]> code.delx.au - gnu-emacs/blobdiff - src/xdisp.c
Fix vertical layout calculations when newline has line-height property
[gnu-emacs] / src / xdisp.c
index 290f69878da6496553ac005b00dec4206f91b61b..da0e84f00432247cee74fd5e108e24403bc56de6 100644 (file)
@@ -1813,7 +1813,7 @@ estimate_mode_line_height (struct frame *f, enum face_id face_id)
         cache and mode line face are not yet initialized.  */
       if (FRAME_FACE_CACHE (f))
        {
-         struct face *face = FACE_FROM_ID (f, face_id);
+         struct face *face = FACE_OPT_FROM_ID (f, face_id);
          if (face)
            {
              if (face->font)
@@ -2918,7 +2918,7 @@ init_iterator (struct it *it, struct window *w,
 
       /* If we have a boxed mode line, make the first character appear
         with a left box line.  */
-      face = FACE_FROM_ID (it->f, remapped_base_face_id);
+      face = FACE_OPT_FROM_ID (it->f, remapped_base_face_id);
       if (face && face->box != FACE_NO_BOX)
        it->start_of_box_run_p = true;
     }
@@ -3877,9 +3877,9 @@ handle_face_prop (struct it *it)
        {
          struct face *new_face = FACE_FROM_ID (it->f, new_face_id);
          /* If it->face_id is -1, old_face below will be NULL, see
-            the definition of FACE_FROM_ID.  This will happen if this
+            the definition of FACE_OPT_FROM_ID.  This will happen if this
             is the initial call that gets the face.  */
-         struct face *old_face = FACE_FROM_ID (it->f, it->face_id);
+         struct face *old_face = FACE_OPT_FROM_ID (it->f, it->face_id);
 
          /* If the value of face_id of the iterator is -1, we have to
             look in front of IT's position and see whether there is a
@@ -3888,7 +3888,7 @@ handle_face_prop (struct it *it)
            {
              int prev_face_id = face_before_it_pos (it);
 
-             old_face = FACE_FROM_ID (it->f, prev_face_id);
+             old_face = FACE_OPT_FROM_ID (it->f, prev_face_id);
            }
 
          /* If the new face has a box, but the old face does not,
@@ -3988,7 +3988,7 @@ handle_face_prop (struct it *it)
       if (new_face_id != it->face_id)
        {
          struct face *new_face = FACE_FROM_ID (it->f, new_face_id);
-         struct face *old_face = FACE_FROM_ID (it->f, it->face_id);
+         struct face *old_face = FACE_OPT_FROM_ID (it->f, it->face_id);
 
          /* If new face has a box but old face hasn't, this is the
             start of a run of characters with box, i.e. it has a
@@ -4847,7 +4847,6 @@ handle_single_display_spec (struct it *it, Lisp_Object spec, Lisp_Object object,
          it->font_height = XCAR (XCDR (spec));
          if (!NILP (it->font_height))
            {
-             struct face *face = FACE_FROM_ID (it->f, it->face_id);
              int new_height = -1;
 
              if (CONSP (it->font_height)
@@ -4866,6 +4865,7 @@ handle_single_display_spec (struct it *it, Lisp_Object spec, Lisp_Object object,
                {
                  /* Call function with current height as argument.
                     Value is the new height.  */
+                 struct face *face = FACE_FROM_ID (it->f, it->face_id);
                  Lisp_Object height;
                  height = safe_call1 (it->font_height,
                                       face->lface[LFACE_HEIGHT_INDEX]);
@@ -4887,6 +4887,7 @@ handle_single_display_spec (struct it *it, Lisp_Object spec, Lisp_Object object,
                  /* Evaluate IT->font_height with `height' bound to the
                     current specified height to get the new height.  */
                  ptrdiff_t count = SPECPDL_INDEX ();
+                 struct face *face = FACE_FROM_ID (it->f, it->face_id);
 
                  specbind (Qheight, face->lface[LFACE_HEIGHT_INDEX]);
                  value = safe_eval (it->font_height);
@@ -5016,8 +5017,6 @@ handle_single_display_spec (struct it *it, Lisp_Object spec, Lisp_Object object,
          || EQ (XCAR (spec), Qright_fringe))
       && CONSP (XCDR (spec)))
     {
-      int fringe_bitmap;
-
       if (it)
        {
          if (!FRAME_WINDOW_P (it->f))
@@ -5041,6 +5040,8 @@ handle_single_display_spec (struct it *it, Lisp_Object spec, Lisp_Object object,
        return 1;
 
 #ifdef HAVE_WINDOW_SYSTEM
+      int fringe_bitmap;
+
       value = XCAR (XCDR (spec));
       if (!SYMBOLP (value)
          || !(fringe_bitmap = lookup_fringe_bitmap (value)))
@@ -6096,7 +6097,7 @@ pop_it (struct it *it)
       break;
     case GET_FROM_STRING:
       {
-       struct face *face = FACE_FROM_ID (it->f, it->face_id);
+       struct face *face = FACE_OPT_FROM_ID (it->f, it->face_id);
 
        /* Restore the face_box_p flag, since it could have been
           overwritten by the face of the object that we just finished
@@ -6777,7 +6778,7 @@ static next_element_function const get_next_element[NUM_IT_METHODS] =
    || ((IT)->cmp_it.stop_pos == (CHARPOS)                              \
        && composition_reseat_it (&(IT)->cmp_it, CHARPOS, BYTEPOS,      \
                                 END_CHARPOS, (IT)->w,                  \
-                                FACE_FROM_ID ((IT)->f, (IT)->face_id), \
+                                FACE_OPT_FROM_ID ((IT)->f, (IT)->face_id),     \
                                 (IT)->string)))
 
 
@@ -7080,6 +7081,19 @@ get_next_display_element (struct it *it)
                  goto display_control;
                }
 
+             /* Handle non-ascii hyphens in the mode where it only
+                gets highlighting.  */
+
+             if (nonascii_hyphen_p && EQ (Vnobreak_char_display, Qt))
+               {
+                 /* Merge `nobreak-space' into the current face.  */
+                 face_id = merge_faces (it->f, Qnobreak_hyphen, 0,
+                                        it->face_id);
+                 XSETINT (it->ctl_chars[0], '-');
+                 ctl_len = 1;
+                 goto display_control;
+               }
+
              /* Handle sequences that start with the "escape glyph".  */
 
              /* the default escape glyph is \.  */
@@ -7096,15 +7110,6 @@ get_next_display_element (struct it *it)
                         ? merge_faces (it->f, Qt, lface_id, it->face_id)
                         : merge_escape_glyph_face (it));
 
-             /* Draw non-ASCII hyphen with just highlighting: */
-
-             if (nonascii_hyphen_p && EQ (Vnobreak_char_display, Qt))
-               {
-                 XSETINT (it->ctl_chars[0], '-');
-                 ctl_len = 1;
-                 goto display_control;
-               }
-
              /* Draw non-ASCII space/hyphen with escape glyph: */
 
              if (nonascii_space_p || nonascii_hyphen_p)
@@ -7202,7 +7207,7 @@ get_next_display_element (struct it *it)
       if (it->method == GET_FROM_STRING && it->sp)
        {
          int face_id = underlying_face_id (it);
-         struct face *face = FACE_FROM_ID (it->f, face_id);
+         struct face *face = FACE_OPT_FROM_ID (it->f, face_id);
 
          if (face)
            {
@@ -7735,8 +7740,8 @@ next_element_from_display_vector (struct it *it)
       /* Glyphs in the display vector could have the box face, so we
         need to set the related flags in the iterator, as
         appropriate.  */
-      this_face = FACE_FROM_ID (it->f, it->face_id);
-      prev_face = FACE_FROM_ID (it->f, prev_face_id);
+      this_face = FACE_OPT_FROM_ID (it->f, it->face_id);
+      prev_face = FACE_OPT_FROM_ID (it->f, prev_face_id);
 
       /* Is this character the first character of a box-face run?  */
       it->start_of_box_run_p = (this_face && this_face->box != FACE_NO_BOX
@@ -7761,7 +7766,7 @@ next_element_from_display_vector (struct it *it)
                                            it->saved_face_id);
            }
        }
-      next_face = FACE_FROM_ID (it->f, next_face_id);
+      next_face = FACE_OPT_FROM_ID (it->f, next_face_id);
       it->end_of_box_run_p = (this_face && this_face->box != FACE_NO_BOX
                              && (!next_face
                                  || next_face->box == FACE_NO_BOX));
@@ -8553,7 +8558,8 @@ move_it_in_display_line_to (struct it *it,
   void *ppos_data = NULL;
   bool may_wrap = false;
   enum it_method prev_method = it->method;
-  ptrdiff_t closest_pos IF_LINT (= 0), prev_pos = IT_CHARPOS (*it);
+  ptrdiff_t closest_pos UNINIT;
+  ptrdiff_t prev_pos = IT_CHARPOS (*it);
   bool saw_smaller_pos = prev_pos < to_charpos;
 
   /* Don't produce glyphs in produce_glyphs.  */
@@ -8805,6 +8811,8 @@ move_it_in_display_line_to (struct it *it,
                              ? WINDOW_LEFT_FRINGE_WIDTH (it->w)
                              : WINDOW_RIGHT_FRINGE_WIDTH (it->w)))))
                {
+                 bool moved_forward = false;
+
                  if (/* IT->hpos == 0 means the very first glyph
                         doesn't fit on the line, e.g. a wide image.  */
                      it->hpos == 0
@@ -8823,16 +8831,37 @@ move_it_in_display_line_to (struct it *it,
                             now that we know it fits in this row.  */
                          if (BUFFER_POS_REACHED_P ())
                            {
+                             bool can_wrap = true;
+
+                             /* If we are at a whitespace character
+                                that barely fits on this screen line,
+                                but the next character is also
+                                whitespace, we cannot wrap here.  */
+                             if (it->line_wrap == WORD_WRAP
+                                 && wrap_it.sp >= 0
+                                 && may_wrap
+                                 && IT_OVERFLOW_NEWLINE_INTO_FRINGE (it))
+                               {
+                                 struct it tem_it;
+                                 void *tem_data = NULL;
+
+                                 SAVE_IT (tem_it, *it, tem_data);
+                                 set_iterator_to_next (it, true);
+                                 if (get_next_display_element (it)
+                                     && IT_DISPLAYING_WHITESPACE (it))
+                                   can_wrap = false;
+                                 RESTORE_IT (it, &tem_it, tem_data);
+                               }
                              if (it->line_wrap != WORD_WRAP
                                  || wrap_it.sp < 0
-                                 /* If we've just found whitespace to
-                                    wrap, effectively ignore the
-                                    previous wrap point -- it is no
-                                    longer relevant, but we won't
-                                    have an opportunity to update it,
-                                    since we've reached the edge of
-                                    this screen line.  */
-                                 || (may_wrap
+                                 /* If we've just found whitespace
+                                    where we can wrap, effectively
+                                    ignore the previous wrap point --
+                                    it is no longer relevant, but we
+                                    won't have an opportunity to
+                                    update it, since we've reached
+                                    the edge of this screen line.  */
+                                 || (may_wrap && can_wrap
                                      && IT_OVERFLOW_NEWLINE_INTO_FRINGE (it)))
                                {
                                  it->hpos = hpos_before_this_char;
@@ -8875,6 +8904,7 @@ move_it_in_display_line_to (struct it *it,
                                  result = MOVE_POS_MATCH_OR_ZV;
                                  break;
                                }
+                             moved_forward = true;
                              if (BUFFER_POS_REACHED_P ())
                                {
                                  if (ITERATOR_AT_END_OF_LINE_P (it))
@@ -8902,7 +8932,14 @@ move_it_in_display_line_to (struct it *it,
                     longer relevant, but we won't have an opportunity
                     to update it, since we are done with this screen
                     line.  */
-                 if (may_wrap && IT_OVERFLOW_NEWLINE_INTO_FRINGE (it))
+                 if (may_wrap && IT_OVERFLOW_NEWLINE_INTO_FRINGE (it)
+                     /* If the character after the one which set the
+                        may_wrap flag is also whitespace, we can't
+                        wrap here, since the screen line cannot be
+                        wrapped in the middle of whitespace.
+                        Therefore, wrap_it _is_ relevant in that
+                        case.  */
+                     && !(moved_forward && IT_DISPLAYING_WHITESPACE (it)))
                    {
                      /* If we've found TO_X, go back there, as we now
                         know the last word fits on this screen line.  */
@@ -9001,6 +9038,11 @@ move_it_in_display_line_to (struct it *it,
            }
          else
            result = MOVE_NEWLINE_OR_CR;
+         /* If we've processed the newline, make sure this flag is
+            reset, as it must only be set when the newline itself is
+            processed.  */
+         if (result == MOVE_NEWLINE_OR_CR)
+           it->constrain_row_ascent_descent_p = false;
          break;
        }
 
@@ -9083,9 +9125,18 @@ move_it_in_display_line_to (struct it *it,
 
 #undef BUFFER_POS_REACHED_P
 
-  /* If we scanned beyond to_pos and didn't find a point to wrap at,
-     restore the saved iterator.  */
-  if (atpos_it.sp >= 0)
+  /* If we scanned beyond TO_POS, restore the saved iterator either to
+     the wrap point (if found), or to atpos/atx location.  We decide which
+     data to use to restore the saved iterator state by their X coordinates,
+     since buffer positions might increase non-monotonically with screen
+     coordinates due to bidi reordering.  */
+  if (result == MOVE_LINE_CONTINUED
+      && it->line_wrap == WORD_WRAP
+      && wrap_it.sp >= 0
+      && ((atpos_it.sp >= 0 && wrap_it.current_x < atpos_it.current_x)
+         || (atx_it.sp >= 0 && wrap_it.current_x < atx_it.current_x)))
+    RESTORE_IT (it, &wrap_it, wrap_data);
+  else if (atpos_it.sp >= 0)
     RESTORE_IT (it, &atpos_it, atpos_data);
   else if (atx_it.sp >= 0)
     RESTORE_IT (it, &atx_it, atx_data);
@@ -9844,7 +9895,7 @@ argument as small as possible; in particular, if the buffer contains
 long lines that shall be truncated anyway.
 
 The optional argument Y-LIMIT, if non-nil, specifies the maximum text
-height (exluding the height of the mode- or header-line, if any) that
+height (excluding the height of the mode- or header-line, if any) that
 can be returned.  Text lines whose y-coordinate is beyond Y-LIMIT are
 ignored.  Since calculating the text height of a large buffer can take
 some time, it makes sense to specify this argument if the size of the
@@ -10528,25 +10579,21 @@ update_echo_area (void)
 static void
 ensure_echo_area_buffers (void)
 {
-  int i;
-
-  for (i = 0; i < 2; ++i)
+  for (int i = 0; i < 2; i++)
     if (!BUFFERP (echo_buffer[i])
        || !BUFFER_LIVE_P (XBUFFER (echo_buffer[i])))
       {
-       char name[30];
-       Lisp_Object old_buffer;
-       int j;
-
-       old_buffer = echo_buffer[i];
-       echo_buffer[i] = Fget_buffer_create
-         (make_formatted_string (name, " *Echo Area %d*", i));
+       Lisp_Object old_buffer = echo_buffer[i];
+       static char const name_fmt[] = " *Echo Area %d*";
+       char name[sizeof name_fmt + INT_STRLEN_BOUND (int)];
+       AUTO_STRING_WITH_LEN (lname, name, sprintf (name, name_fmt, i));
+       echo_buffer[i] = Fget_buffer_create (lname);
        bset_truncate_lines (XBUFFER (echo_buffer[i]), Qnil);
        /* to force word wrap in echo area -
           it was decided to postpone this*/
        /* XBUFFER (echo_buffer[i])->word_wrap = Qt; */
 
-       for (j = 0; j < 2; ++j)
+       for (int j = 0; j < 2; j++)
          if (EQ (old_buffer, echo_area_buffer[j]))
            echo_area_buffer[j] = echo_buffer[i];
       }
@@ -17046,7 +17093,16 @@ redisplay_window (Lisp_Object window, bool just_this_one_p)
            ignore_mouse_drag_p = true;
 #endif
         }
+      ptrdiff_t count1 = SPECPDL_INDEX ();
+      /* x_consider_frame_title calls select-frame, which calls
+        resize_mini_window, which could resize the mini-window and by
+        that undo the effect of this redisplay cycle wrt minibuffer
+        and echo-area display.  Binding inhibit-redisplay to t makes
+        the call to resize_mini_window a no-op, thus avoiding the
+        adverse side effects.  */
+      specbind (Qinhibit_redisplay, Qt);
       x_consider_frame_title (w->frame);
+      unbind_to (count1, Qnil);
 #endif
     }
 
@@ -18653,7 +18709,7 @@ try_window_id (struct window *w)
       eassert (MATRIX_ROW_DISPLAYS_TEXT_P (first_unchanged_at_end_row));
       row = find_last_row_displaying_text (w->current_matrix, &it,
                                           first_unchanged_at_end_row);
-      eassert (row && MATRIX_ROW_DISPLAYS_TEXT_P (row));
+      eassume (row && MATRIX_ROW_DISPLAYS_TEXT_P (row));
       adjust_window_ends (w, row, true);
       eassert (w->window_end_bytepos >= 0);
       IF_DEBUG (debug_method_add (w, "A"));
@@ -18683,10 +18739,9 @@ try_window_id (struct window *w)
       struct glyph_row *current_row = current_matrix->rows + vpos;
       struct glyph_row *desired_row = desired_matrix->rows + vpos;
 
-      for (row = NULL;
-          row == NULL && vpos >= first_vpos;
-          --vpos, --current_row, --desired_row)
+      for (row = NULL; !row; --vpos, --current_row, --desired_row)
        {
+         eassert (first_vpos <= vpos);
          if (desired_row->enabled_p)
            {
              if (MATRIX_ROW_DISPLAYS_TEXT_P (desired_row))
@@ -18696,7 +18751,6 @@ try_window_id (struct window *w)
            row  = current_row;
        }
 
-      eassert (row != NULL);
       w->window_end_vpos = vpos + 1;
       w->window_end_pos = Z - MATRIX_ROW_END_CHARPOS (row);
       w->window_end_bytepos = Z_BYTE - MATRIX_ROW_END_BYTEPOS (row);
@@ -19460,7 +19514,6 @@ append_space_for_newline (struct it *it, bool default_face_p)
          struct text_pos saved_pos;
          Lisp_Object saved_object;
          struct face *face;
-         struct glyph *g;
 
          saved_object = it->object;
          saved_pos = it->position;
@@ -19496,7 +19549,7 @@ append_space_for_newline (struct it *it, bool default_face_p)
          /* Make sure this space glyph has the right ascent and
             descent values, or else cursor at end of line will look
             funny, and height of empty lines will be incorrect.  */
-         g = it->glyph_row->glyphs[TEXT_AREA] + n;
+         struct glyph *g = it->glyph_row->glyphs[TEXT_AREA] + n;
          struct font *font = face->font ? face->font : FRAME_FONT (it->f);
          if (n == 0)
            {
@@ -19621,15 +19674,14 @@ extend_face_to_end_of_line (struct it *it)
     return;
 
   /* The default face, possibly remapped. */
-  default_face = FACE_FROM_ID (f, lookup_basic_face (f, DEFAULT_FACE_ID));
+  default_face = FACE_OPT_FROM_ID (f, lookup_basic_face (f, DEFAULT_FACE_ID));
 
   /* Face extension extends the background and box of IT->face_id
      to the end of the line.  If the background equals the background
      of the frame, we don't have to do anything.  */
-  if (it->face_before_selective_p)
-    face = FACE_FROM_ID (f, it->saved_face_id);
-  else
-    face = FACE_FROM_ID (f, it->face_id);
+  face = FACE_OPT_FROM_ID (f, (it->face_before_selective_p
+                              ? it->saved_face_id
+                              : it->face_id));
 
   if (FRAME_WINDOW_P (f)
       && MATRIX_ROW_DISPLAYS_TEXT_P (it->glyph_row)
@@ -20369,16 +20421,16 @@ display_line (struct it *it)
   struct it wrap_it;
   void *wrap_data = NULL;
   bool may_wrap = false;
-  int wrap_x IF_LINT (= 0);
+  int wrap_x UNINIT;
   int wrap_row_used = -1;
-  int wrap_row_ascent IF_LINT (= 0), wrap_row_height IF_LINT (= 0);
-  int wrap_row_phys_ascent IF_LINT (= 0), wrap_row_phys_height IF_LINT (= 0);
-  int wrap_row_extra_line_spacing IF_LINT (= 0);
-  ptrdiff_t wrap_row_min_pos IF_LINT (= 0), wrap_row_min_bpos IF_LINT (= 0);
-  ptrdiff_t wrap_row_max_pos IF_LINT (= 0), wrap_row_max_bpos IF_LINT (= 0);
+  int wrap_row_ascent UNINIT, wrap_row_height UNINIT;
+  int wrap_row_phys_ascent UNINIT, wrap_row_phys_height UNINIT;
+  int wrap_row_extra_line_spacing UNINIT;
+  ptrdiff_t wrap_row_min_pos UNINIT, wrap_row_min_bpos UNINIT;
+  ptrdiff_t wrap_row_max_pos UNINIT, wrap_row_max_bpos UNINIT;
   int cvpos;
   ptrdiff_t min_pos = ZV + 1, max_pos = 0;
-  ptrdiff_t min_bpos IF_LINT (= 0), max_bpos IF_LINT (= 0);
+  ptrdiff_t min_bpos UNINIT, max_bpos UNINIT;
   bool pending_handle_line_prefix = false;
 
   /* We always start displaying at hpos zero even if hscrolled.  */
@@ -21639,7 +21691,9 @@ Value is the new character position of point.  */)
       int pt_x, target_x, pixel_width, pt_vpos;
       bool at_eol_p;
       bool overshoot_expected = false;
+#ifdef HAVE_WINDOW_SYSTEM
       bool target_is_eol_p = false;
+#endif
 
       /* Setup the arena.  */
       SET_TEXT_POS (pt, PT, PT_BYTE);
@@ -21754,7 +21808,9 @@ Value is the new character position of point.  */)
            {
              move_it_by_lines (&it, -1);
              target_x = it.last_visible_x - !FRAME_WINDOW_P (it.f);
+#ifdef HAVE_WINDOW_SYSTEM
              target_is_eol_p = true;
+#endif
              /* Under word-wrap, we don't know the x coordinate of
                 the last character displayed on the previous line,
                 which immediately precedes the wrap point.  To find
@@ -24603,7 +24659,6 @@ get_glyph_face_and_encoding (struct frame *f, struct glyph *glyph,
   face = FACE_FROM_ID (f, glyph->face_id);
 
   /* Make sure X resources of the face are allocated.  */
-  eassert (face != NULL);
   prepare_face_for_display (f, face);
 
   if (face->font)
@@ -24735,7 +24790,7 @@ fill_gstring_glyph_string (struct glyph_string *s, int face_id,
   s->cmp_id = glyph->u.cmp.id;
   s->cmp_from = glyph->slice.cmp.from;
   s->cmp_to = glyph->slice.cmp.to + 1;
-  s->face = FACE_FROM_ID (s->f, face_id);
+  s->face = FACE_OPT_FROM_ID (s->f, face_id);
   lgstring = composition_gstring_from_id (s->cmp_id);
   s->font = XFONT_OBJECT (LGSTRING_FONT (lgstring));
   glyph++;
@@ -25328,7 +25383,7 @@ compute_overhangs_and_x (struct glyph_string *s, int x, bool backward_p)
 #define BUILD_COMPOSITE_GLYPH_STRING(START, END, HEAD, TAIL, HL, X, LAST_X) \
   do {                                                                     \
     int face_id = (row)->glyphs[area][START].face_id;                      \
-    struct face *base_face = FACE_FROM_ID (f, face_id);                            \
+    struct face *base_face = FACE_OPT_FROM_ID (f, face_id);                \
     ptrdiff_t cmp_id = (row)->glyphs[area][START].u.cmp.id;                \
     struct composition *cmp = composition_table[cmp_id];                   \
     XChar2b *char2b;                                                       \
@@ -25549,7 +25604,7 @@ draw_glyphs (struct window *w, int x, struct glyph_row *row,
     {
       struct glyph_string *h, *t;
       Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
-      int mouse_beg_col IF_LINT (= 0), mouse_end_col IF_LINT (= 0);
+      int mouse_beg_col UNINIT, mouse_end_col UNINIT;
       bool check_mouse_face = false;
       int dummy_x = 0;
 
@@ -25783,6 +25838,7 @@ append_glyph (struct it *it)
       glyph->object = it->object;
       if (it->pixel_width > 0)
        {
+         eassert (it->pixel_width <= SHRT_MAX);
          glyph->pixel_width = it->pixel_width;
          glyph->padding_p = false;
        }
@@ -25863,6 +25919,7 @@ append_composite_glyph (struct it *it)
        }
       glyph->charpos = it->cmp_it.charpos;
       glyph->object = it->object;
+      eassert (it->pixel_width <= SHRT_MAX);
       glyph->pixel_width = it->pixel_width;
       glyph->ascent = it->ascent;
       glyph->descent = it->descent;
@@ -25949,7 +26006,6 @@ produce_image_glyph (struct it *it)
   eassert (it->what == IT_IMAGE);
 
   face = FACE_FROM_ID (it->f, it->face_id);
-  eassert (face);
   /* Make sure X resources of the face is loaded.  */
   prepare_face_for_display (it->f, face);
 
@@ -25964,7 +26020,6 @@ produce_image_glyph (struct it *it)
     }
 
   img = IMAGE_FROM_ID (it->f, it->image_id);
-  eassert (img);
   /* Make sure X resources of the image is loaded.  */
   prepare_image_for_display (it->f, img);
 
@@ -26072,7 +26127,7 @@ produce_image_glyph (struct it *it)
        {
          glyph->charpos = CHARPOS (it->position);
          glyph->object = it->object;
-         glyph->pixel_width = it->pixel_width;
+         glyph->pixel_width = clip_to_bounds (-1, it->pixel_width, SHRT_MAX);
          glyph->ascent = glyph_ascent;
          glyph->descent = it->descent;
          glyph->voffset = it->voffset;
@@ -26120,7 +26175,6 @@ produce_xwidget_glyph (struct it *it)
   eassert (it->what == IT_XWIDGET);
 
   struct face *face = FACE_FROM_ID (it->f, it->face_id);
-  eassert (face);
   /* Make sure X resources of the face is loaded.  */
   prepare_face_for_display (it->f, face);
 
@@ -26176,7 +26230,7 @@ produce_xwidget_glyph (struct it *it)
        {
          glyph->charpos = CHARPOS (it->position);
          glyph->object = it->object;
-         glyph->pixel_width = it->pixel_width;
+         glyph->pixel_width = clip_to_bounds (-1, it->pixel_width, SHRT_MAX);
          glyph->ascent = glyph_ascent;
          glyph->descent = it->descent;
          glyph->voffset = it->voffset;
@@ -26262,7 +26316,9 @@ append_stretch_glyph (struct it *it, Lisp_Object object,
        }
       glyph->charpos = CHARPOS (it->position);
       glyph->object = object;
-      glyph->pixel_width = width;
+      /* FIXME: It would be better to use TYPE_MAX here, but
+        __typeof__ is not portable enough...  */
+      glyph->pixel_width = clip_to_bounds (-1, width, SHRT_MAX);
       glyph->ascent = ascent;
       glyph->descent = height - ascent;
       glyph->voffset = it->voffset;
@@ -26713,6 +26769,7 @@ append_glyphless_glyph (struct it *it, int face_id, bool for_no_font, int len,
        }
       glyph->charpos = CHARPOS (it->position);
       glyph->object = it->object;
+      eassert (it->pixel_width <= SHRT_MAX);
       glyph->pixel_width = it->pixel_width;
       glyph->ascent = it->ascent;
       glyph->descent = it->descent;
@@ -27294,18 +27351,21 @@ x_produce_glyphs (struct it *it)
          int leftmost, rightmost, lowest, highest;
          int lbearing, rbearing;
          int i, width, ascent, descent;
-         int c IF_LINT (= 0); /* cmp->glyph_len can't be zero; see Bug#8512 */
+         int c;
          XChar2b char2b;
          struct font_metrics *pcm;
          ptrdiff_t pos;
 
-         for (glyph_len = cmp->glyph_len; glyph_len > 0; glyph_len--)
-           if ((c = COMPOSITION_GLYPH (cmp, glyph_len - 1)) != '\t')
-             break;
+         eassume (0 < glyph_len); /* See Bug#8512.  */
+         do
+           c = COMPOSITION_GLYPH (cmp, --glyph_len);
+         while (c == '\t' && 0 < glyph_len);
+
          bool right_padded = glyph_len < cmp->glyph_len;
          for (i = 0; i < glyph_len; i++)
            {
-             if ((c = COMPOSITION_GLYPH (cmp, i)) != '\t')
+             c = COMPOSITION_GLYPH (cmp, i);
+             if (c != '\t')
                break;
              cmp->offsets[i * 2] = cmp->offsets[i * 2 + 1] = 0;
            }
@@ -28004,7 +28064,7 @@ get_window_cursor_type (struct window *w, struct glyph *glyph, int *width,
              /* Using a block cursor on large images can be very annoying.
                 So use a hollow cursor for "large" images.
                 If image is not transparent (no mask), also use hollow cursor.  */
-             struct image *img = IMAGE_FROM_ID (f, glyph->u.img_id);
+             struct image *img = IMAGE_OPT_FROM_ID (f, glyph->u.img_id);
              if (img != NULL && IMAGEP (img->spec))
                {
                  /* Arbitrarily, interpret "Large" as >32x32 and >NxN
@@ -28542,7 +28602,11 @@ static void
 show_mouse_face (Mouse_HLInfo *hlinfo, enum draw_glyphs_face draw)
 {
   struct window *w = XWINDOW (hlinfo->mouse_face_window);
+#ifdef HAVE_WINDOW_SYSTEM
   struct frame *f = XFRAME (WINDOW_FRAME (w));
+#else
+  (void) XFRAME (WINDOW_FRAME (w));
+#endif
 
   if (/* If window is in the process of being destroyed, don't bother
         to do anything.  */
@@ -28553,7 +28617,9 @@ show_mouse_face (Mouse_HLInfo *hlinfo, enum draw_glyphs_face draw)
         anymore.  This can happen when a window is split.  */
       && hlinfo->mouse_face_end_row < w->current_matrix->nrows)
     {
+#ifdef HAVE_WINDOW_SYSTEM
       bool phys_cursor_on_p = w->phys_cursor_on_p;
+#endif
       struct glyph_row *row, *first, *last;
 
       first = MATRIX_ROW (w->current_matrix, hlinfo->mouse_face_beg_row);
@@ -29645,18 +29711,17 @@ note_mode_line_or_margin_highlight (Lisp_Object window, int x, int y,
   Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
 #ifdef HAVE_WINDOW_SYSTEM
   Display_Info *dpyinfo;
-#endif
   Cursor cursor = No_Cursor;
   Lisp_Object pointer = Qnil;
+#endif
   int dx, dy, width, height;
   ptrdiff_t charpos;
   Lisp_Object string, object = Qnil;
-  Lisp_Object pos IF_LINT (= Qnil), help;
-
+  Lisp_Object pos UNINIT;
   Lisp_Object mouse_face;
   int original_x_pixel = x;
   struct glyph * glyph = NULL, * row_start_glyph = NULL;
-  struct glyph_row *row IF_LINT (= 0);
+  struct glyph_row *row UNINIT;
 
   if (area == ON_MODE_LINE || area == ON_HEADER_LINE)
     {
@@ -29696,7 +29761,7 @@ note_mode_line_or_margin_highlight (Lisp_Object window, int x, int y,
                                     &object, &dx, &dy, &width, &height);
     }
 
-  help = Qnil;
+  Lisp_Object help = Qnil;
 
 #ifdef HAVE_WINDOW_SYSTEM
   if (IMAGEP (object))
@@ -29899,8 +29964,12 @@ note_mode_line_or_margin_highlight (Lisp_Object window, int x, int y,
               && hlinfo->mouse_face_beg_row == vpos )
            return;
 
+#ifdef HAVE_WINDOW_SYSTEM
          if (clear_mouse_face (hlinfo))
            cursor = No_Cursor;
+#else
+         (void) clear_mouse_face (hlinfo);
+#endif
 
          if (!row->reversed_p)
            {
@@ -29934,8 +30003,10 @@ note_mode_line_or_margin_highlight (Lisp_Object window, int x, int y,
          show_mouse_face (hlinfo, DRAW_MOUSE_FACE);
          mouse_face_shown = true;
 
+#ifdef HAVE_WINDOW_SYSTEM
          if (NILP (pointer))
            pointer = Qhand;
+#endif
        }
     }
 
@@ -29966,8 +30037,10 @@ note_mouse_highlight (struct frame *f, int x, int y)
   enum window_part part = ON_NOTHING;
   Lisp_Object window;
   struct window *w;
+#ifdef HAVE_WINDOW_SYSTEM
   Cursor cursor = No_Cursor;
   Lisp_Object pointer = Qnil;  /* Takes precedence over cursor!  */
+#endif
   struct buffer *b;
 
   /* When a menu is active, don't highlight because this looks odd.  */
@@ -30091,7 +30164,7 @@ note_mouse_highlight (struct frame *f, int x, int y)
       /* Look for :pointer property on image.  */
       if (glyph != NULL && glyph->type == IMAGE_GLYPH)
        {
-         struct image *img = IMAGE_FROM_ID (f, glyph->u.img_id);
+         struct image *img = IMAGE_OPT_FROM_ID (f, glyph->u.img_id);
          if (img != NULL && IMAGEP (img->spec))
            {
              Lisp_Object image_map, hotspot;
@@ -30150,9 +30223,11 @@ note_mouse_highlight (struct frame *f, int x, int y)
              && glyph->type == STRETCH_GLYPH
              && glyph->avoid_cursor_p))
        {
+#ifndef HAVE_WINDOW_SYSTEM
+         (void) clear_mouse_face (hlinfo);
+#else  /* HAVE_WINDOW_SYSTEM */
          if (clear_mouse_face (hlinfo))
            cursor = No_Cursor;
-#ifdef HAVE_WINDOW_SYSTEM
          if (FRAME_WINDOW_P (f) && NILP (pointer))
            {
              if (area != TEXT_AREA)
@@ -30160,7 +30235,7 @@ note_mouse_highlight (struct frame *f, int x, int y)
              else
                pointer = Vvoid_text_area_pointer;
            }
-#endif
+#endif /* HAVE_WINDOW_SYSTEM */
          goto set_cursor;
        }
 
@@ -30205,8 +30280,10 @@ note_mouse_highlight (struct frame *f, int x, int y)
 
       same_region = coords_in_mouse_face_p (w, hpos, vpos);
 
+#ifdef HAVE_WINDOW_SYSTEM
       if (same_region)
        cursor = No_Cursor;
+#endif
 
       /* Check mouse-face highlighting.  */
       if (! same_region
@@ -30233,8 +30310,12 @@ note_mouse_highlight (struct frame *f, int x, int y)
          hlinfo->mouse_face_overlay = overlay;
 
          /* Clear the display of the old active region, if any.  */
+#ifdef HAVE_WINDOW_SYSTEM
          if (clear_mouse_face (hlinfo))
            cursor = No_Cursor;
+#else
+         (void) clear_mouse_face (hlinfo);
+#endif
 
          /* If no overlay applies, get a text property.  */
          if (NILP (overlay))
@@ -30265,14 +30346,16 @@ note_mouse_highlight (struct frame *f, int x, int y)
                = face_at_string_position (w, object, pos, 0, &ignore,
                                           glyph->face_id, true);
              show_mouse_face (hlinfo, DRAW_MOUSE_FACE);
+#ifdef HAVE_WINDOW_SYSTEM
              cursor = No_Cursor;
+#endif
            }
          else
            {
              /* The mouse-highlighting, if any, comes from an overlay
                 or text property in the buffer.  */
-             Lisp_Object buffer IF_LINT (= Qnil);
-             Lisp_Object disp_string IF_LINT (= Qnil);
+             Lisp_Object buffer UNINIT;
+             Lisp_Object disp_string UNINIT;
 
              if (STRINGP (object))
                {
@@ -30349,7 +30432,9 @@ note_mouse_highlight (struct frame *f, int x, int y)
                                              : XFASTINT (after),
                                              before_string, after_string,
                                              disp_string);
+#ifdef HAVE_WINDOW_SYSTEM
                  cursor = No_Cursor;
+#endif
                }
            }
        }
@@ -31188,8 +31273,10 @@ They are still logged to the *Messages* buffer.  */);
   /* Name and number of the face used to highlight escape glyphs.  */
   DEFSYM (Qescape_glyph, "escape-glyph");
 
-  /* Name and number of the face used to highlight non-breaking spaces.  */
+  /* Name and number of the face used to highlight non-breaking
+     spaces/hyphens.  */
   DEFSYM (Qnobreak_space, "nobreak-space");
+  DEFSYM (Qnobreak_hyphen, "nobreak-hyphen");
 
   /* The symbol 'image' which is the car of the lists used to represent
      images in Lisp.  Also a tool bar style.  */
@@ -31301,7 +31388,7 @@ The face used for trailing whitespace is `trailing-whitespace'.  */);
     doc: /* Control highlighting of non-ASCII space and hyphen chars.
 If the value is t, Emacs highlights non-ASCII chars which have the
 same appearance as an ASCII space or hyphen, using the `nobreak-space'
-or `escape-glyph' face respectively.
+or `nobreak-hyphen' face respectively.
 
 U+00A0 (no-break space), U+00AD (soft hyphen), U+2010 (hyphen), and
 U+2011 (non-breaking hyphen) are affected.