]> code.delx.au - gnu-emacs/blobdiff - src/xdisp.c
Fix cursor display (bug#23993)
[gnu-emacs] / src / xdisp.c
index 89385c0e17267f5c2cb64da807d3f482d0d8dbff..efd5f54fa39f57a6b4c0d9cb32bfa2029c52998f 100644 (file)
@@ -7,8 +7,8 @@ This file is part of GNU Emacs.
 
 GNU Emacs is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
+the Free Software Foundation, either version 3 of the License, or (at
+your option) any later version.
 
 GNU Emacs is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -314,13 +314,11 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #include "font.h"
 #include "fontset.h"
 #include "blockinput.h"
+#include "xwidget.h"
 #ifdef HAVE_WINDOW_SYSTEM
 #include TERM_HEADER
 #endif /* HAVE_WINDOW_SYSTEM */
 
-#ifdef HAVE_XWIDGETS
-# include "xwidget.h"
-#endif
 #ifndef FRAME_X_OUTPUT
 #define FRAME_X_OUTPUT(f) ((f)->output_data.x)
 #endif
@@ -827,6 +825,7 @@ static Lisp_Object redisplay_window_1 (Lisp_Object);
 static bool set_cursor_from_row (struct window *, struct glyph_row *,
                                 struct glyph_matrix *, ptrdiff_t, ptrdiff_t,
                                 int, int);
+static bool cursor_row_fully_visible_p (struct window *, bool, bool);
 static bool update_menu_bar (struct frame *, bool, bool);
 static bool try_window_reusing_current_matrix (struct window *);
 static int try_window_id (struct window *);
@@ -857,9 +856,7 @@ static bool next_element_from_buffer (struct it *);
 static bool next_element_from_composition (struct it *);
 static bool next_element_from_image (struct it *);
 static bool next_element_from_stretch (struct it *);
-#ifdef HAVE_XWIDGETS
 static bool next_element_from_xwidget (struct it *);
-#endif
 static void load_overlay_strings (struct it *, ptrdiff_t);
 static bool get_next_display_element (struct it *);
 static enum move_it_result
@@ -1324,6 +1321,11 @@ pos_visible_p (struct window *w, ptrdiff_t charpos, int *x, int *y,
   if (CHARPOS (top) > ZV)
     SET_TEXT_POS (top, BEGV, BEGV_BYTE);
 
+  /* If the top of the window is after CHARPOS, the latter is surely
+     not visible.  */
+  if (charpos >= 0 && CHARPOS (top) > charpos)
+    return visible_p;
+
   /* Compute exact mode line heights.  */
   if (WINDOW_WANTS_MODELINE_P (w))
     w->mode_line_height
@@ -1816,7 +1818,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_FROM_ID_OR_NULL (f, face_id);
          if (face)
            {
              if (face->font)
@@ -2235,7 +2237,7 @@ get_phys_cursor_geometry (struct window *w, struct glyph_row *row,
   ascent = row->ascent;
   if (row->ascent < glyph->ascent)
     {
-      y =- glyph->ascent - row->ascent;
+      y -= glyph->ascent - row->ascent;
       ascent = glyph->ascent;
     }
 
@@ -2921,7 +2923,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_FROM_ID_OR_NULL (it->f, remapped_base_face_id);
       if (face && face->box != FACE_NO_BOX)
        it->start_of_box_run_p = true;
     }
@@ -2949,7 +2951,7 @@ init_iterator (struct it *it, struct window *w,
         character properties needed for reordering are not yet
         available.  */
       it->bidi_p =
-       NILP (Vpurify_flag)
+       !redisplay__inhibit_bidi
        && !NILP (BVAR (current_buffer, bidi_display_reordering))
        && it->multibyte_p;
 
@@ -3880,9 +3882,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
-            is the initial call that gets the face.  */
-         struct face *old_face = FACE_FROM_ID (it->f, it->face_id);
+            the definition of FACE_FROM_ID_OR_NULL.  This will happen
+            if this is the initial call that gets the face.  */
+         struct face *old_face = FACE_FROM_ID_OR_NULL (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
@@ -3891,7 +3893,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_FROM_ID_OR_NULL (it->f, prev_face_id);
            }
 
          /* If the new face has a box, but the old face does not,
@@ -3991,7 +3993,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_FROM_ID_OR_NULL (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
@@ -4850,7 +4852,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)
@@ -4869,6 +4870,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]);
@@ -4890,6 +4892,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);
@@ -5019,8 +5022,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))
@@ -5045,8 +5046,8 @@ handle_single_display_spec (struct it *it, Lisp_Object spec, Lisp_Object object,
 
 #ifdef HAVE_WINDOW_SYSTEM
       value = XCAR (XCDR (spec));
-      if (!SYMBOLP (value)
-         || !(fringe_bitmap = lookup_fringe_bitmap (value)))
+      int fringe_bitmap = SYMBOLP (value) ? lookup_fringe_bitmap (value) : 0;
+      if (! fringe_bitmap)
        /* If we return here, POSITION has been advanced
           across the text with this property.  */
        {
@@ -5147,11 +5148,8 @@ handle_single_display_spec (struct it *it, Lisp_Object spec, Lisp_Object object,
                      && valid_image_p (value))
 #endif /* not HAVE_WINDOW_SYSTEM */
              || (CONSP (value) && EQ (XCAR (value), Qspace))
-#ifdef HAVE_XWIDGETS
              || ((it ? FRAME_WINDOW_P (it->f) : frame_window_p)
-                && valid_xwidget_spec_p (value))
-#endif
-             );
+                && valid_xwidget_spec_p (value)));
 
   if (valid_p && display_replaced == 0)
     {
@@ -5226,17 +5224,15 @@ handle_single_display_spec (struct it *it, Lisp_Object spec, Lisp_Object object,
          *position = it->position = start_pos;
          retval = 1 + (it->area == TEXT_AREA);
        }
-#ifdef HAVE_XWIDGETS
-      else if (valid_xwidget_spec_p(value))
+      else if (valid_xwidget_spec_p (value))
        {
           it->what = IT_XWIDGET;
           it->method = GET_FROM_XWIDGET;
           it->position = start_pos;
          it->object = NILP (object) ? it->w->contents : object;
          *position = start_pos;
-          it->xwidget = lookup_xwidget(value);
+          it->xwidget = lookup_xwidget (value);
        }
-#endif
 #ifdef HAVE_WINDOW_SYSTEM
       else
        {
@@ -5989,11 +5985,9 @@ push_it (struct it *it, struct text_pos *position)
     case GET_FROM_STRETCH:
       p->u.stretch.object = it->object;
       break;
-#ifdef HAVE_XWIDGETS
     case GET_FROM_XWIDGET:
       p->u.xwidget.object = it->object;
       break;
-#endif
     case GET_FROM_BUFFER:
     case GET_FROM_DISPLAY_VECTOR:
     case GET_FROM_STRING:
@@ -6095,11 +6089,9 @@ pop_it (struct it *it)
       it->object = p->u.image.object;
       it->slice = p->u.image.slice;
       break;
-#ifdef HAVE_XWIDGETS
     case GET_FROM_XWIDGET:
       it->object = p->u.xwidget.object;
       break;
-#endif
     case GET_FROM_STRETCH:
       it->object = p->u.stretch.object;
       break;
@@ -6108,7 +6100,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_FROM_ID_OR_NULL (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
@@ -6653,7 +6645,7 @@ reseat_to_string (struct it *it, const char *s, Lisp_Object string,
      loading loadup.el, as the necessary character property tables are
      not yet available.  */
   it->bidi_p =
-    NILP (Vpurify_flag)
+    !redisplay__inhibit_bidi
     && !NILP (BVAR (&buffer_defaults, bidi_display_reordering));
 
   if (s == NULL)
@@ -6775,9 +6767,7 @@ static next_element_function const get_next_element[NUM_IT_METHODS] =
   next_element_from_c_string,
   next_element_from_image,
   next_element_from_stretch,
-#ifdef HAVE_XWIDGETS
   next_element_from_xwidget,
-#endif
 };
 
 #define GET_NEXT_DISPLAY_ELEMENT(it) (*get_next_element[(it)->method]) (it)
@@ -6791,7 +6781,8 @@ 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_FROM_ID_OR_NULL ((IT)->f,         \
+                                                      (IT)->face_id),  \
                                 (IT)->string)))
 
 
@@ -7094,6 +7085,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 \.  */
@@ -7110,15 +7114,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)
@@ -7216,7 +7211,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_FROM_ID_OR_NULL (it->f, face_id);
 
          if (face)
            {
@@ -7243,30 +7238,72 @@ get_next_display_element (struct it *it)
                {
                  ptrdiff_t ignore;
                  int next_face_id;
+                 bool text_from_string = false;
+                 /* Normally, the next buffer location is stored in
+                    IT->current.pos...  */
                  struct text_pos pos = it->current.pos;
 
-                 /* For a string from a display property, the next
-                    buffer position is stored in the 'position'
+                 /* ...but for a string from a display property, the
+                    next buffer position is stored in the 'position'
                     member of the iteration stack slot below the
                     current one, see handle_single_display_spec.  By
-                    contrast, it->current.pos was is not yet updated
-                    to point to that buffer position; that will
-                    happen in pop_it, after we finish displaying the
-                    current string.  Note that we already checked
-                    above that it->sp is positive, so subtracting one
-                    from it is safe.  */
+                    contrast, it->current.pos was not yet updated to
+                    point to that buffer position; that will happen
+                    in pop_it, after we finish displaying the current
+                    string.  Note that we already checked above that
+                    it->sp is positive, so subtracting one from it is
+                    safe.  */
                  if (it->from_disp_prop_p)
-                   pos = (it->stack + it->sp - 1)->position;
+                   {
+                     int stackp = it->sp - 1;
+
+                     /* Find the stack level with data from buffer.  */
+                     while (stackp >= 0
+                            && STRINGP ((it->stack + stackp)->string))
+                       stackp--;
+                     if (stackp < 0)
+                       {
+                         /* If no stack slot was found for iterating
+                            a buffer, we are displaying text from a
+                            string, most probably the mode line or
+                            the header line, and that string has a
+                            display string on some of its
+                            characters.  */
+                         text_from_string = true;
+                         pos = it->stack[it->sp - 1].position;
+                       }
+                     else
+                       pos = (it->stack + stackp)->position;
+                   }
                  else
                    INC_TEXT_POS (pos, it->multibyte_p);
 
-                 if (CHARPOS (pos) >= ZV)
+                 if (text_from_string)
+                   {
+                     Lisp_Object base_string = it->stack[it->sp - 1].string;
+
+                     if (CHARPOS (pos) >= SCHARS (base_string) - 1)
+                       it->end_of_box_run_p = true;
+                     else
+                       {
+                         next_face_id
+                           = face_at_string_position (it->w, base_string,
+                                                      CHARPOS (pos), 0,
+                                                      &ignore, face_id, false);
+                         it->end_of_box_run_p
+                           = (FACE_FROM_ID (it->f, next_face_id)->box
+                              == FACE_NO_BOX);
+                       }
+                   }
+                 else if (CHARPOS (pos) >= ZV)
                    it->end_of_box_run_p = true;
                  else
                    {
-                     next_face_id = face_at_buffer_position
-                       (it->w, CHARPOS (pos), &ignore,
-                        CHARPOS (pos) + TEXT_PROP_DISTANCE_LIMIT, false, -1);
+                     next_face_id =
+                       face_at_buffer_position (it->w, CHARPOS (pos), &ignore,
+                                                CHARPOS (pos)
+                                                + TEXT_PROP_DISTANCE_LIMIT,
+                                                false, -1);
                      it->end_of_box_run_p
                        = (FACE_FROM_ID (it->f, next_face_id)->box
                           == FACE_NO_BOX);
@@ -7638,9 +7675,7 @@ set_iterator_to_next (struct it *it, bool reseat_p)
 
     case GET_FROM_IMAGE:
     case GET_FROM_STRETCH:
-#ifdef HAVE_XWIDGETS
     case GET_FROM_XWIDGET:
-#endif
 
       /* The position etc with which we have to proceed are on
         the stack.  The position may be at the end of a string,
@@ -7709,8 +7744,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_FROM_ID_OR_NULL (it->f, it->face_id);
+      prev_face = FACE_FROM_ID_OR_NULL (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
@@ -7735,7 +7770,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_FROM_ID_OR_NULL (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));
@@ -8103,14 +8138,12 @@ next_element_from_image (struct it *it)
   return true;
 }
 
-#ifdef HAVE_XWIDGETS
 static bool
 next_element_from_xwidget (struct it *it)
 {
   it->what = IT_XWIDGET;
   return true;
 }
-#endif
 
 
 /* Fill iterator IT with next display element from a stretch glyph
@@ -8529,7 +8562,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.  */
@@ -8580,8 +8614,7 @@ move_it_in_display_line_to (struct it *it,
           && it->dpvec + it->current.dpvec_index + 1 >= it->dpend)))
 
   /* If there's a line-/wrap-prefix, handle it.  */
-  if (it->hpos == 0 && it->method == GET_FROM_BUFFER
-      && it->current_y < it->last_visible_y)
+  if (it->hpos == 0 && it->method == GET_FROM_BUFFER)
     handle_line_prefix (it);
 
   if (IT_CHARPOS (*it) < CHARPOS (this_line_min_pos))
@@ -8781,6 +8814,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
@@ -8799,16 +8834,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;
@@ -8851,6 +8907,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))
@@ -8878,7 +8935,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.  */
@@ -8977,6 +9041,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;
        }
 
@@ -9059,9 +9128,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);
@@ -9803,26 +9881,28 @@ the maximum pixel-height of all text lines.
 
 The optional argument FROM, if non-nil, specifies the first text
 position and defaults to the minimum accessible position of the buffer.
-If FROM is t, use the minimum accessible position that is not a newline
-character.  TO, if non-nil, specifies the last text position and
+If FROM is t, use the minimum accessible position that starts a
+non-empty line.  TO, if non-nil, specifies the last text position and
 defaults to the maximum accessible position of the buffer.  If TO is t,
-use the maximum accessible position that is not a newline character.
+use the maximum accessible position that ends a non-empty line.
 
 The optional argument X-LIMIT, if non-nil, specifies the maximum text
 width that can be returned.  X-LIMIT nil or omitted, means to use the
-pixel-width of WINDOW's body; use this if you do not intend to change
-the width of WINDOW.  Use the maximum width WINDOW may assume if you
-intend to change WINDOW's width.  In any case, text whose x-coordinate
-is beyond X-LIMIT is ignored.  Since calculating the width of long lines
-can take some time, it's always a good idea to make this argument as
-small as possible; in particular, if the buffer contains long lines that
-shall be truncated anyway.
+pixel-width of WINDOW's body; use this if you want to know how high
+WINDOW should be become in order to fit all of its buffer's text with
+the width of WINDOW unaltered.  Use the maximum width WINDOW may assume
+if you intend to change WINDOW's width.  In any case, text whose
+x-coordinate is beyond X-LIMIT is ignored.  Since calculating the width
+of long lines can take some time, it's always a good idea to make this
+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 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 buffer is unknown.
+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
+buffer is large or unknown.
 
 Optional argument MODE-AND-HEADER-LINE nil or omitted means do not
 include the height of the mode- or header-line of WINDOW in the return
@@ -9840,7 +9920,7 @@ include the height of both, if present, in the return value.  */)
   ptrdiff_t start, end, pos;
   struct text_pos startp;
   void *itdata = NULL;
-  int c, max_y = -1, x = 0, y = 0;
+  int c, max_x = 0, max_y = 0, x = 0, y = 0;
 
   CHECK_BUFFER (buffer);
   b = XBUFFER (buffer);
@@ -9885,11 +9965,13 @@ include the height of both, if present, in the return value.  */)
       end = max (start, min (XINT (to), ZV));
     }
 
-  if (!NILP (y_limit))
-    {
-      CHECK_NUMBER (y_limit);
-      max_y = min (XINT (y_limit), INT_MAX);
-    }
+  if (!NILP (x_limit) && RANGED_INTEGERP (0, x_limit, INT_MAX))
+    max_x = XINT (x_limit);
+
+  if (NILP (y_limit))
+    max_y = INT_MAX;
+  else if (RANGED_INTEGERP (0, y_limit, INT_MAX))
+    max_y = XINT (y_limit);
 
   itdata = bidi_shelve_cache ();
   SET_TEXT_POS (startp, start, CHAR_TO_BYTE (start));
@@ -9899,27 +9981,33 @@ include the height of both, if present, in the return value.  */)
     x = move_it_to (&it, end, -1, max_y, -1, MOVE_TO_POS | MOVE_TO_Y);
   else
     {
-      CHECK_NUMBER (x_limit);
-      it.last_visible_x = min (XINT (x_limit), INFINITY);
+      it.last_visible_x = max_x;
       /* Actually, we never want move_it_to stop at to_x.  But to make
         sure that move_it_in_display_line_to always moves far enough,
         we set it to INT_MAX and specify MOVE_TO_X.  */
       x = move_it_to (&it, end, INT_MAX, max_y, -1,
                      MOVE_TO_POS | MOVE_TO_X | MOVE_TO_Y);
+      /* Don't return more than X-LIMIT.  */
+      if (x > max_x)
+        x = max_x;
     }
 
-  y = it.current_y + it.max_ascent + it.max_descent;
+  /* Subtract height of header-line which was counted automatically by
+     start_display.  */
+  y = it.current_y + it.max_ascent + it.max_descent
+    - WINDOW_HEADER_LINE_HEIGHT (w);
+  /* Don't return more than Y-LIMIT.  */
+  if (y > max_y)
+    y = max_y;
 
-  if (!EQ (mode_and_header_line, Qheader_line)
-      && !EQ (mode_and_header_line, Qt))
-    /* Do not count the header-line which was counted automatically by
-       start_display.  */
-    y = y - WINDOW_HEADER_LINE_HEIGHT (w);
+  if (EQ (mode_and_header_line, Qheader_line)
+      || EQ (mode_and_header_line, Qt))
+    /* Re-add height of header-line as requested.  */
+    y = y + WINDOW_HEADER_LINE_HEIGHT (w);
 
   if (EQ (mode_and_header_line, Qmode_line)
       || EQ (mode_and_header_line, Qt))
-    /* Do count the mode-line which is not included automatically by
-       start_display.  */
+    /* Add height of mode-line as requested.  */
     y = y + WINDOW_MODE_LINE_HEIGHT (w);
 
   bidi_unshelve_cache (itdata, false);
@@ -10497,25 +10585,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];
       }
@@ -10533,8 +10617,8 @@ ensure_echo_area_buffers (void)
    suitable buffer from echo_buffer[] and clear it.
 
    If WHICH < 0, set echo_area_buffer[1] to echo_area_buffer[0], so
-   that the current message becomes the last displayed one, make
-   choose a suitable buffer for echo_area_buffer[0], and clear it.
+   that the current message becomes the last displayed one, choose a
+   suitable buffer for echo_area_buffer[0], and clear it.
 
    Value is what FN returns.  */
 
@@ -10568,7 +10652,7 @@ with_echo_area_buffer (struct window *w, int which,
        echo_area_buffer[this_one] = Qnil;
     }
 
-  /* Choose a suitable buffer from echo_buffer[] is we don't
+  /* Choose a suitable buffer from echo_buffer[] if we don't
      have one.  */
   if (NILP (echo_area_buffer[this_one]))
     {
@@ -11241,6 +11325,7 @@ clear_garbaged_frames (void)
   if (frame_garbaged)
     {
       Lisp_Object tail, frame;
+      struct frame *sf = SELECTED_FRAME ();
 
       FOR_EACH_FRAME (tail, frame)
        {
@@ -11248,7 +11333,13 @@ clear_garbaged_frames (void)
 
          if (FRAME_VISIBLE_P (f) && FRAME_GARBAGED_P (f))
            {
-             if (f->resized_p)
+             if (f->resized_p
+                 /* It makes no sense to redraw a non-selected TTY
+                    frame, since that will actually clear the
+                    selected frame, and might leave the selected
+                    frame with corrupted display, if it happens not
+                    to be marked garbaged.  */
+                 && !(f != sf && (FRAME_TERMCAP_P (f) || FRAME_MSDOS_P (f))))
                redraw_frame (f);
              else
                clear_current_matrices (f);
@@ -11795,24 +11886,7 @@ prepare_menu_bars (void)
              && !XBUFFER (w->contents)->text->redisplay)
            continue;
 
-         /* If a window on this frame changed size, report that to
-            the user and clear the size-change flag.  */
-         if (FRAME_WINDOW_SIZES_CHANGED (f))
-           {
-             Lisp_Object functions;
-
-             /* Clear flag first in case we get an error below.  */
-             FRAME_WINDOW_SIZES_CHANGED (f) = false;
-             functions = Vwindow_size_change_functions;
-
-             while (CONSP (functions))
-               {
-                 if (!EQ (XCAR (functions), Qt))
-                   call1 (XCAR (functions), frame);
-                 functions = XCDR (functions);
-               }
-           }
-
+         run_window_size_change_functions (frame);
          menu_bar_hooks_run = update_menu_bar (f, false, menu_bar_hooks_run);
 #ifdef HAVE_WINDOW_SYSTEM
          update_tool_bar (f, false);
@@ -13158,7 +13232,7 @@ text_outside_line_unchanged_p (struct window *w,
         beginning of a paragraph, before the first strong directional
         character, can change the base direction of the paragraph (unless
         the buffer specifies a fixed paragraph direction), which will
-        require to redisplay the whole paragraph.  It might be worthwhile
+        require redisplaying the whole paragraph.  It might be worthwhile
         to find the paragraph limits and widen the range of redisplayed
         lines to that, but for now just give up this optimization.  */
       if (!NILP (BVAR (XBUFFER (w->contents), bidi_display_reordering))
@@ -13487,7 +13561,7 @@ redisplay_internal (void)
   specbind (Qinhibit_free_realized_faces, Qnil);
 
   /* Record this function, so it appears on the profiler's backtraces.  */
-  record_in_backtrace (Qredisplay_internal, 0, 0);
+  record_in_backtrace (Qredisplay_internal_xC_functionx, 0, 0);
 
   FOR_EACH_FRAME (tail, frame)
     XFRAME (frame)->already_hscrolled_p = false;
@@ -13608,24 +13682,12 @@ redisplay_internal (void)
         it's too late for the hooks in window-size-change-functions,
         which have been examined already in prepare_menu_bars.  So in
         that case we call the hooks here only for the selected frame.  */
-      if (sf->redisplay && FRAME_WINDOW_SIZES_CHANGED (sf))
+      if (sf->redisplay)
        {
-         Lisp_Object functions;
          ptrdiff_t count1 = SPECPDL_INDEX ();
 
          record_unwind_save_match_data ();
-
-         /* Clear flag first in case we get an error below.  */
-         FRAME_WINDOW_SIZES_CHANGED (sf) = false;
-         functions = Vwindow_size_change_functions;
-
-         while (CONSP (functions))
-           {
-             if (!EQ (XCAR (functions), Qt))
-               call1 (XCAR (functions), selected_frame);
-             functions = XCDR (functions);
-           }
-
+         run_window_size_change_functions (selected_frame);
          unbind_to (count1, Qnil);
        }
 
@@ -13647,22 +13709,10 @@ redisplay_internal (void)
     {
       if (sf->redisplay)
        {
-         Lisp_Object functions;
          ptrdiff_t count1 = SPECPDL_INDEX ();
 
          record_unwind_save_match_data ();
-
-         /* Clear flag first in case we get an error below.  */
-         FRAME_WINDOW_SIZES_CHANGED (sf) = false;
-         functions = Vwindow_size_change_functions;
-
-         while (CONSP (functions))
-           {
-             if (!EQ (XCAR (functions), Qt))
-               call1 (XCAR (functions), selected_frame);
-             functions = XCDR (functions);
-           }
-
+         run_window_size_change_functions (selected_frame);
          unbind_to (count1, Qnil);
        }
 
@@ -13891,11 +13941,16 @@ redisplay_internal (void)
              eassert (this_line_vpos == it.vpos);
              eassert (this_line_y == it.current_y);
              set_cursor_from_row (w, row, w->current_matrix, 0, 0, 0, 0);
+             if (cursor_row_fully_visible_p (w, false, true))
+               {
 #ifdef GLYPH_DEBUG
-             *w->desired_matrix->method = 0;
-             debug_method_add (w, "optimization 3");
+                 *w->desired_matrix->method = 0;
+                 debug_method_add (w, "optimization 3");
 #endif
-             goto update;
+                 goto update;
+               }
+             else
+               goto cancel;
            }
          else
            goto cancel;
@@ -14034,9 +14089,6 @@ redisplay_internal (void)
     }
   else if (FRAME_VISIBLE_P (sf) && !FRAME_OBSCURED_P (sf))
     {
-      Lisp_Object mini_window = FRAME_MINIBUF_WINDOW (sf);
-      struct frame *mini_frame;
-
       displayed_buffer = XBUFFER (XWINDOW (selected_window)->contents);
       /* Use list_of_error, not Qerror, so that
         we catch only errors and don't run the debugger.  */
@@ -14044,8 +14096,8 @@ redisplay_internal (void)
                                 list_of_error,
                                 redisplay_window_error);
       if (update_miniwindow_p)
-       internal_condition_case_1 (redisplay_window_1, mini_window,
-                                  list_of_error,
+       internal_condition_case_1 (redisplay_window_1,
+                                  FRAME_MINIBUF_WINDOW (sf), list_of_error,
                                   redisplay_window_error);
 
       /* Compare desired and current matrices, perform output.  */
@@ -14095,8 +14147,8 @@ redisplay_internal (void)
         have put text on a frame other than the selected one, so the
         above call to update_frame would not have caught it.  Catch
         it here.  */
-      mini_window = FRAME_MINIBUF_WINDOW (sf);
-      mini_frame = XFRAME (WINDOW_FRAME (XWINDOW (mini_window)));
+      Lisp_Object mini_window = FRAME_MINIBUF_WINDOW (sf);
+      struct frame *mini_frame = XFRAME (WINDOW_FRAME (XWINDOW (mini_window)));
 
       if (mini_frame != sf && FRAME_WINDOW_P (mini_frame))
        {
@@ -15465,12 +15517,14 @@ try_scrolling (Lisp_Object window, bool just_this_one_p,
 
    The new window start will be computed, based on W's width, starting
    from the start of the continued line.  It is the start of the
-   screen line with the minimum distance from the old start W->start.  */
+   screen line with the minimum distance from the old start W->start,
+   which is still before point (otherwise point will definitely not
+   be visible in the window).  */
 
 static bool
 compute_window_start_on_continuation_line (struct window *w)
 {
-  struct text_pos pos, start_pos;
+  struct text_pos pos, start_pos, pos_before_pt;
   bool window_start_changed_p = false;
 
   SET_TEXT_POS_FROM_MARKER (start_pos, w->start);
@@ -15498,10 +15552,14 @@ compute_window_start_on_continuation_line (struct window *w)
       reseat_at_previous_visible_line_start (&it);
 
       /* If the line start is "too far" away from the window start,
-         say it takes too much time to compute a new window start.  */
-      if (CHARPOS (start_pos) - IT_CHARPOS (it)
-         /* PXW: Do we need upper bounds here?  */
-         < WINDOW_TOTAL_LINES (w) * WINDOW_TOTAL_COLS (w))
+         say it takes too much time to compute a new window start.
+         Also, give up if the line start is after point, as in that
+         case point will not be visible with any window start we
+         compute.  */
+      if (IT_CHARPOS (it) <= PT
+         || (CHARPOS (start_pos) - IT_CHARPOS (it)
+             /* PXW: Do we need upper bounds here?  */
+             < WINDOW_TOTAL_LINES (w) * WINDOW_TOTAL_COLS (w)))
        {
          int min_distance, distance;
 
@@ -15511,12 +15569,14 @@ compute_window_start_on_continuation_line (struct window *w)
             decreased, the new window start will be < the old start.
             So, we're looking for the display line start with the
             minimum distance from the old window start.  */
-         pos = it.current.pos;
+         pos_before_pt = pos = it.current.pos;
          min_distance = INFINITY;
          while ((distance = eabs (CHARPOS (start_pos) - IT_CHARPOS (it))),
                 distance < min_distance)
            {
              min_distance = distance;
+             if (CHARPOS (pos) <= PT)
+               pos_before_pt = pos;
              pos = it.current.pos;
              if (it.line_wrap == WORD_WRAP)
                {
@@ -15539,6 +15599,13 @@ compute_window_start_on_continuation_line (struct window *w)
                move_it_by_lines (&it, 1);
            }
 
+         /* It makes very little sense to make the new window start
+            after point, as point won't be visible.  If that's what
+            the loop above finds, fall back on the candidate before
+            or at point that is closest to the old window start.  */
+         if (CHARPOS (pos) > PT)
+           pos = pos_before_pt;
+
          /* Set the window start there.  */
          SET_MARKER_FROM_TEXT_POS (w->start, pos);
          window_start_changed_p = true;
@@ -16086,6 +16153,7 @@ redisplay_window (Lisp_Object window, bool just_this_one_p)
   bool last_line_misfit = false;
   ptrdiff_t beg_unchanged, end_unchanged;
   int frame_line_height;
+  bool use_desired_matrix;
 
   SET_TEXT_POS (lpoint, PT, PT_BYTE);
   opoint = lpoint;
@@ -16808,7 +16876,7 @@ redisplay_window (Lisp_Object window, bool just_this_one_p)
   startp = run_window_scroll_functions (window, it.current.pos);
 
   /* Redisplay the window.  */
-  bool use_desired_matrix = false;
+  use_desired_matrix = false;
   if (!current_matrix_up_to_date_p
       || windows_or_buffers_changed
       || f->cursor_type_changed
@@ -16924,7 +16992,7 @@ redisplay_window (Lisp_Object window, bool just_this_one_p)
       if (scroll_conservatively > SCROLL_LIMIT)
        {
          int window_total_lines
-           = WINDOW_TOTAL_LINES (w) * FRAME_LINE_HEIGHT (f) * frame_line_height;
+           = WINDOW_TOTAL_LINES (w) * FRAME_LINE_HEIGHT (f) / frame_line_height;
          int margin =
            scroll_margin > 0
            ? min (scroll_margin, window_total_lines / 4)
@@ -17046,7 +17114,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
     }
 
@@ -18086,7 +18163,7 @@ try_window_id (struct window *w)
      beginning of a paragraph, before the first strong directional
      character, can change the base direction of the paragraph (unless
      the buffer specifies a fixed paragraph direction), which will
-     require to redisplay the whole paragraph.  It might be worthwhile
+     require redisplaying the whole paragraph.  It might be worthwhile
      to find the paragraph limits and widen the range of redisplayed
      lines to that, but for now just give up this optimization and
      redisplay from scratch.  */
@@ -18653,7 +18730,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 +18760,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 +18772,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);
@@ -18844,9 +18919,11 @@ dump_glyph (struct glyph_row *row, struct glyph *glyph, int area)
               glyph->left_box_line_p,
               glyph->right_box_line_p);
     }
-#ifdef HAVE_XWIDGETS
   else if (glyph->type == XWIDGET_GLYPH)
     {
+#ifndef HAVE_XWIDGETS
+      eassume (false);
+#else
       fprintf (stderr,
               "  %5d %4c %6d %c %3d 0x%05x %c %4d %1.1d%1.1d\n",
               glyph - row->glyphs[TEXT_AREA],
@@ -18863,9 +18940,8 @@ dump_glyph (struct glyph_row *row, struct glyph *glyph, int area)
               glyph->face_id,
               glyph->left_box_line_p,
               glyph->right_box_line_p);
-
-    }
 #endif
+    }
 }
 
 
@@ -19459,7 +19535,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;
@@ -19495,7 +19570,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)
            {
@@ -19620,15 +19695,15 @@ 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_FROM_ID_OR_NULL (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_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)
@@ -20368,16 +20443,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.  */
@@ -21226,7 +21301,7 @@ See also `bidi-paragraph-direction'.  */)
       || NILP (BVAR (buf, enable_multibyte_characters))
       /* When we are loading loadup.el, the character property tables
         needed for bidi iteration are not yet available.  */
-      || !NILP (Vpurify_flag))
+      || redisplay__inhibit_bidi)
     return Qleft_to_right;
   else if (!NILP (BVAR (buf, bidi_paragraph_direction)))
     return BVAR (buf, bidi_paragraph_direction);
@@ -21350,7 +21425,7 @@ the `bidi-class' property of a character.  */)
          /* When we are loading loadup.el, the character property
             tables needed for bidi iteration are not yet
             available.  */
-         || !NILP (Vpurify_flag))
+         || redisplay__inhibit_bidi)
        return Qnil;
 
       validate_subarray (object, from, to, SCHARS (object), &from_pos, &to_pos);
@@ -21378,7 +21453,7 @@ the `bidi-class' property of a character.  */)
          /* When we are loading loadup.el, the character property
             tables needed for bidi iteration are not yet
             available.  */
-         || !NILP (Vpurify_flag))
+         || redisplay__inhibit_bidi)
        return Qnil;
 
       set_buffer_temp (buf);
@@ -21794,7 +21869,6 @@ Value is the new character position of point.  */)
        }
 
       /* Move to the target X coordinate.  */
-#ifdef HAVE_WINDOW_SYSTEM
       /* On GUI frames, as we don't know the X coordinate of the
         character to the left of point, moving point to the left
         requires walking, one grapheme cluster at a time, until we
@@ -21851,9 +21925,7 @@ Value is the new character position of point.  */)
            new_pos.bytepos = CHAR_TO_BYTE (new_pos.charpos);
          it.current.pos = new_pos;
        }
-      else
-#endif
-      if (it.current_x != target_x)
+      else if (it.current_x != target_x)
        move_it_in_display_line_to (&it, ZV, target_x, MOVE_TO_POS | MOVE_TO_X);
 
       /* If we ended up in a display string that covers point, move to
@@ -24364,13 +24436,11 @@ calc_pixel_width_or_height (double *res, struct it *it, Lisp_Object prop,
 
              return OK_PIXELS (width_p ? img->width : img->height);
            }
-# ifdef HAVE_XWIDGETS
          if (FRAME_WINDOW_P (it->f) && valid_xwidget_spec_p (prop))
            {
               // TODO: Don't return dummy size.
               return OK_PIXELS (100);
             }
-# endif
 #endif
          if (EQ (car, Qplus) || EQ (car, Qminus))
            {
@@ -24604,7 +24674,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)
@@ -25273,8 +25342,11 @@ compute_overhangs_and_x (struct glyph_string *s, int x, bool backward_p)
        }                                                               \
      while (false)
 
-#ifdef HAVE_XWIDGETS
-#define BUILD_XWIDGET_GLYPH_STRING(START, END, HEAD, TAIL, HL, X, LAST_X) \
+#ifndef HAVE_XWIDGETS
+# define BUILD_XWIDGET_GLYPH_STRING(START, END, HEAD, TAIL, HL, X, LAST_X) \
+     eassume (false)
+#else
+# define BUILD_XWIDGET_GLYPH_STRING(START, END, HEAD, TAIL, HL, X, LAST_X) \
      do                                                                        \
        {                                                               \
         s = alloca (sizeof *s);                                        \
@@ -25287,7 +25359,6 @@ compute_overhangs_and_x (struct glyph_string *s, int x, bool backward_p)
      while (false)
 #endif
 
-
 /* Add a glyph string for a sequence of character glyphs to the list
    of strings between HEAD and TAIL.  START is the index of the first
    glyph in row area AREA of glyph row ROW that is part of the new
@@ -25327,7 +25398,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_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;                                                       \
@@ -25441,13 +25512,11 @@ compute_overhangs_and_x (struct glyph_string *s, int x, bool backward_p)
                                        HL, X, LAST_X);                 \
              break;
 
-#ifdef HAVE_XWIDGETS
-# define BUILD_GLYPH_STRINGS_XW(START, END, HEAD, TAIL, HL, X, LAST_X) \
+#define BUILD_GLYPH_STRINGS_XW(START, END, HEAD, TAIL, HL, X, LAST_X)  \
             case XWIDGET_GLYPH:                                         \
               BUILD_XWIDGET_GLYPH_STRING (START, END, HEAD, TAIL,       \
                                           HL, X, LAST_X);               \
               break;
-#endif
 
 #define BUILD_GLYPH_STRINGS_2(START, END, HEAD, TAIL, HL, X, LAST_X)   \
            case GLYPHLESS_GLYPH:                                       \
@@ -25456,7 +25525,7 @@ compute_overhangs_and_x (struct glyph_string *s, int x, bool backward_p)
              break;                                                    \
                                                                        \
            default:                                                    \
-             emacs_abort ();                                                   \
+             emacs_abort ();                                           \
            }                                                           \
                                                                        \
          if (s)                                                        \
@@ -25468,16 +25537,10 @@ compute_overhangs_and_x (struct glyph_string *s, int x, bool backward_p)
     } while (false)
 
 
-#ifdef HAVE_XWIDGETS
-# define BUILD_GLYPH_STRINGS(START, END, HEAD, TAIL, HL, X, LAST_X)    \
+#define BUILD_GLYPH_STRINGS(START, END, HEAD, TAIL, HL, X, LAST_X)     \
     BUILD_GLYPH_STRINGS_1(START, END, HEAD, TAIL, HL, X, LAST_X)       \
     BUILD_GLYPH_STRINGS_XW(START, END, HEAD, TAIL, HL, X, LAST_X)      \
     BUILD_GLYPH_STRINGS_2(START, END, HEAD, TAIL, HL, X, LAST_X)
-#else
-# define BUILD_GLYPH_STRINGS(START, END, HEAD, TAIL, HL, X, LAST_X)    \
-    BUILD_GLYPH_STRINGS_1(START, END, HEAD, TAIL, HL, X, LAST_X)       \
-    BUILD_GLYPH_STRINGS_2(START, END, HEAD, TAIL, HL, X, LAST_X)
-#endif
 
 
 /* Draw glyphs between START and END in AREA of ROW on window W,
@@ -25556,7 +25619,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;
 
@@ -25790,6 +25853,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;
        }
@@ -25870,6 +25934,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;
@@ -25956,7 +26021,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);
 
@@ -25971,7 +26035,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);
 
@@ -26079,7 +26142,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;
@@ -26118,16 +26181,15 @@ produce_image_glyph (struct it *it)
     }
 }
 
-#ifdef HAVE_XWIDGETS
 static void
 produce_xwidget_glyph (struct it *it)
 {
+#ifdef HAVE_XWIDGETS
   struct xwidget *xw;
   int glyph_ascent, crop;
   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);
 
@@ -26183,7 +26245,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;
@@ -26219,8 +26281,8 @@ produce_xwidget_glyph (struct it *it)
       else
        IT_EXPAND_MATRIX_WIDTH (it, area);
     }
-}
 #endif
+}
 
 /* Append a stretch glyph to IT->glyph_row.  OBJECT is the source
    of the glyph, WIDTH and HEIGHT are the width and height of the
@@ -26269,7 +26331,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;
@@ -26651,12 +26715,8 @@ calc_line_height_property (struct it *it, Lisp_Object val, struct font *font,
       struct face *face;
 
       face_id = lookup_named_face (it->f, face_name, false);
-      if (face_id < 0)
-       return make_number (-1);
-
-      face = FACE_FROM_ID (it->f, face_id);
-      font = face->font;
-      if (font == NULL)
+      face = FACE_FROM_ID_OR_NULL (it->f, face_id);
+      if (face == NULL || ((font = face->font) == NULL))
        return make_number (-1);
       boff = font->baseline_offset;
       if (font->vertical_centering)
@@ -26720,6 +26780,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;
@@ -27301,18 +27362,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 - 1);
+         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;
            }
@@ -27631,10 +27695,8 @@ x_produce_glyphs (struct it *it)
     produce_image_glyph (it);
   else if (it->what == IT_STRETCH)
     produce_stretch_glyph (it);
-#ifdef HAVE_XWIDGETS
   else if (it->what == IT_XWIDGET)
     produce_xwidget_glyph (it);
-#endif
 
  done:
   /* Accumulate dimensions.  Note: can't assume that it->descent > 0
@@ -28004,10 +28066,8 @@ get_window_cursor_type (struct window *w, struct glyph *glyph, int *width,
   /* Use normal cursor if not blinked off.  */
   if (!w->cursor_off_p)
     {
-#ifdef HAVE_XWIDGETS
       if (glyph != NULL && glyph->type == XWIDGET_GLYPH)
         return NO_CURSOR;
-#endif
       if (glyph != NULL && glyph->type == IMAGE_GLYPH)
        {
          if (cursor_type == FILLED_BOX_CURSOR)
@@ -28015,7 +28075,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
@@ -28640,12 +28700,12 @@ show_mouse_face (Mouse_HLInfo *hlinfo, enum draw_glyphs_face draw)
            }
        }
 
-#ifdef HAVE_WINDOW_SYSTEM
       /* When we've written over the cursor, arrange for it to
         be displayed again.  */
       if (FRAME_WINDOW_P (f)
          && phys_cursor_on_p && !w->phys_cursor_on_p)
        {
+#ifdef HAVE_WINDOW_SYSTEM
          int hpos = w->phys_cursor.hpos;
 
          /* When the window is hscrolled, cursor hpos can legitimately be
@@ -28660,8 +28720,8 @@ show_mouse_face (Mouse_HLInfo *hlinfo, enum draw_glyphs_face draw)
          display_and_set_cursor (w, true, hpos, w->phys_cursor.vpos,
                                  w->phys_cursor.x, w->phys_cursor.y);
          unblock_input ();
-       }
 #endif /* HAVE_WINDOW_SYSTEM */
+       }
     }
 
 #ifdef HAVE_WINDOW_SYSTEM
@@ -29601,12 +29661,17 @@ Returns the alist element for the first matching AREA in MAP.  */)
                        clip_to_bounds (INT_MIN, XINT (x), INT_MAX),
                        clip_to_bounds (INT_MIN, XINT (y), INT_MAX));
 }
+#endif /* HAVE_WINDOW_SYSTEM */
 
 
 /* Display frame CURSOR, optionally using shape defined by POINTER.  */
 static void
 define_frame_cursor1 (struct frame *f, Cursor cursor, Lisp_Object pointer)
 {
+#ifdef HAVE_WINDOW_SYSTEM
+  if (!FRAME_WINDOW_P (f))
+    return;
+
   /* Do not change cursor shape while dragging mouse.  */
   if (EQ (do_mouse_tracking, Qdragging))
     return;
@@ -29623,10 +29688,10 @@ define_frame_cursor1 (struct frame *f, Cursor cursor, Lisp_Object pointer)
        cursor = FRAME_X_OUTPUT (f)->horizontal_drag_cursor;
       else if (EQ (pointer, intern ("nhdrag")))
        cursor = FRAME_X_OUTPUT (f)->vertical_drag_cursor;
-#ifdef HAVE_X_WINDOWS
+# ifdef HAVE_X_WINDOWS
       else if (EQ (pointer, intern ("vdrag")))
        cursor = FRAME_DISPLAY_INFO (f)->vertical_scroll_bar_cursor;
-#endif
+# endif
       else if (EQ (pointer, intern ("hourglass")))
        cursor = FRAME_X_OUTPUT (f)->hourglass_cursor;
       else if (EQ (pointer, Qmodeline))
@@ -29637,10 +29702,9 @@ define_frame_cursor1 (struct frame *f, Cursor cursor, Lisp_Object pointer)
 
   if (cursor != No_Cursor)
     FRAME_RIF (f)->define_frame_cursor (f, cursor);
+#endif
 }
 
-#endif /* HAVE_WINDOW_SYSTEM */
-
 /* Take proper action when mouse has moved to the mode or header line
    or marginal area AREA of window W, x-position X and y-position Y.
    X is relative to the start of the text display area of W, so the
@@ -29662,12 +29726,11 @@ note_mode_line_or_margin_highlight (Lisp_Object window, int x, int y,
   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)
     {
@@ -29707,7 +29770,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))
@@ -29955,10 +30018,7 @@ note_mode_line_or_margin_highlight (Lisp_Object window, int x, int y,
   if ((area == ON_MODE_LINE || area == ON_HEADER_LINE) && !mouse_face_shown)
     clear_mouse_face (hlinfo);
 
-#ifdef HAVE_WINDOW_SYSTEM
-  if (FRAME_WINDOW_P (f))
-    define_frame_cursor1 (f, cursor, pointer);
-#endif
+  define_frame_cursor1 (f, cursor, pointer);
 }
 
 
@@ -30102,7 +30162,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;
@@ -30163,15 +30223,15 @@ note_mouse_highlight (struct frame *f, int x, int y)
        {
          if (clear_mouse_face (hlinfo))
            cursor = No_Cursor;
-#ifdef HAVE_WINDOW_SYSTEM
          if (FRAME_WINDOW_P (f) && NILP (pointer))
            {
+#ifdef HAVE_WINDOW_SYSTEM
              if (area != TEXT_AREA)
                cursor = FRAME_X_OUTPUT (f)->nontext_cursor;
              else
                pointer = Vvoid_text_area_pointer;
-           }
 #endif
+           }
          goto set_cursor;
        }
 
@@ -30282,8 +30342,8 @@ note_mouse_highlight (struct frame *f, int x, int y)
            {
              /* 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))
                {
@@ -30483,15 +30543,7 @@ note_mouse_highlight (struct frame *f, int x, int y)
     }
 
  set_cursor:
-
-#ifdef HAVE_WINDOW_SYSTEM
-  if (FRAME_WINDOW_P (f))
-    define_frame_cursor1 (f, cursor, pointer);
-#else
-  /* This is here to prevent a compiler error, about "label at end of
-     compound statement".  */
-  return;
-#endif
+  define_frame_cursor1 (f, cursor, pointer);
 }
 
 
@@ -31128,7 +31180,7 @@ syms_of_xdisp (void)
   /* Non-nil means don't actually do any redisplay.  */
   DEFSYM (Qinhibit_redisplay, "inhibit-redisplay");
 
-  DEFSYM (Qredisplay_internal, "redisplay_internal (C function)");
+  DEFSYM (Qredisplay_internal_xC_functionx, "redisplay_internal (C function)");
 
   DEFVAR_BOOL("inhibit-message", inhibit_message,
               doc:  /* Non-nil means calls to `message' are not displayed.
@@ -31199,8 +31251,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.  */
@@ -31312,7 +31366,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.
@@ -31397,8 +31451,11 @@ Value is a number or a cons (WIDTH-DPI . HEIGHT-DPI).  */);
               Vtruncate_partial_width_windows,
     doc: /* Non-nil means truncate lines in windows narrower than the frame.
 For an integer value, truncate lines in each window narrower than the
-full frame width, provided the window width is less than that integer;
-otherwise, respect the value of `truncate-lines'.
+full frame width, provided the total window width in column units is less
+than that integer; otherwise, respect the value of `truncate-lines'.
+The total width of the window is as returned by `window-total-width', it
+includes the fringes, the continuation and truncation glyphs, the
+display margins (if any), and the scroll bar
 
 For any other non-nil value, truncate lines in all windows that do
 not span the full frame width.
@@ -31433,7 +31490,7 @@ This variable is not guaranteed to be accurate except while processing
 
   DEFVAR_LISP ("frame-title-format", Vframe_title_format,
     doc: /* Template for displaying the title bar of visible frames.
-(Assuming the window manager supports this feature.)
+\(Assuming the window manager supports this feature.)
 
 This variable has the same structure as `mode-line-format', except that
 the %c and %l constructs are ignored.  It is used only on frames for
@@ -31441,10 +31498,10 @@ which no explicit name has been set (see `modify-frame-parameters').  */);
 
   DEFVAR_LISP ("icon-title-format", Vicon_title_format,
     doc: /* Template for displaying the title bar of an iconified frame.
-(Assuming the window manager supports this feature.)
+\(Assuming the window manager supports this feature.)
 This variable has the same structure as `mode-line-format' (which see),
 and is used only on frames for which no explicit name has been set
-(see `modify-frame-parameters').  */);
+\(see `modify-frame-parameters').  */);
   Vicon_title_format
     = Vframe_title_format
     = listn (CONSTYPE_PURE, 3,
@@ -31462,16 +31519,6 @@ If nil, disable message logging.  If t, log messages but don't truncate
 the buffer when it becomes large.  */);
   Vmessage_log_max = make_number (1000);
 
-  DEFVAR_LISP ("window-size-change-functions", Vwindow_size_change_functions,
-    doc: /* Functions called during redisplay, if window sizes have changed.
-The value should be a list of functions that take one argument.
-During the first part of redisplay, for each frame, if any of its windows
-have changed size since the last redisplay, or have been split or deleted,
-all the functions in the list are called, with the frame as argument.
-If redisplay decides to resize the minibuffer window, it calls these
-functions on behalf of that as well.  */);
-  Vwindow_size_change_functions = Qnil;
-
   DEFVAR_LISP ("window-scroll-functions", Vwindow_scroll_functions,
     doc: /* List of functions to call before redisplaying a window with scrolling.
 Each function is called with two arguments, the window and its new
@@ -31606,7 +31653,12 @@ A value of t means resize them to fit the text displayed in them.
 A value of `grow-only', the default, means let mini-windows grow only;
 they return to their normal size when the minibuffer is closed, or the
 echo area becomes empty.  */);
-  Vresize_mini_windows = Qgrow_only;
+  /* Contrary to the doc string, we initialize this to nil, so that
+     loading loadup.el won't try to resize windows before loading
+     window.el, where some functions we need to call for this live.
+     We assign the 'grow-only' value right after loading window.el
+     during loadup.  */
+  Vresize_mini_windows = Qnil;
 
   DEFVAR_LISP ("blink-cursor-alist", Vblink_cursor_alist,
     doc: /* Alist specifying how to blink the cursor off.
@@ -31814,6 +31866,12 @@ display table takes effect; in this case, Emacs does not consult
   DEFVAR_LISP ("redisplay--variables", Vredisplay__variables,
      doc: /* A hash-table of variables changing which triggers a thorough redisplay.  */);
   Vredisplay__variables = Qnil;
+
+  DEFVAR_BOOL ("redisplay--inhibit-bidi", redisplay__inhibit_bidi,
+     doc: /* Non-nil means it is not safe to attempt bidi reordering for display.  */);
+  /* Initialize to t, since we need to disable reordering until
+     loadup.el successfully loads charprop.el.  */
+  redisplay__inhibit_bidi = true;
 }