Merge from trunk.
[bpt/emacs.git] / src / xdisp.c
index 7c1b205..d44e677 100644 (file)
@@ -258,7 +258,7 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
    still left to right, i.e. the iterator "thinks" the first character
    is at the leftmost pixel position.  The iterator does not know that
    PRODUCE_GLYPHS reverses the order of the glyphs that the iterator
-   delivers.  This is important when functions from the the move_it_*
+   delivers.  This is important when functions from the move_it_*
    family are used to get to certain screen position or to match
    screen coordinates with buffer coordinates: these functions use the
    iterator geometry, which is left to right even in R2L paragraphs.
@@ -594,6 +594,29 @@ int current_mode_line_height, current_header_line_height;
 
 #define TEXT_PROP_DISTANCE_LIMIT 100
 
+/* SAVE_IT and RESTORE_IT are called when we save a snapshot of the
+   iterator state and later restore it.  This is needed because the
+   bidi iterator on bidi.c keeps a stacked cache of its states, which
+   is really a singleton.  When we use scratch iterator objects to
+   move around the buffer, we can cause the bidi cache to be pushed or
+   popped, and therefore we need to restore the cache state when we
+   return to the original iterator.  */
+#define SAVE_IT(ITCOPY,ITORIG,CACHE)           \
+  do {                                         \
+    if (CACHE)                                 \
+      xfree (CACHE);                           \
+    ITCOPY = ITORIG;                           \
+    CACHE = bidi_shelve_cache();               \
+  } while (0)
+
+#define RESTORE_IT(pITORIG,pITCOPY,CACHE)      \
+  do {                                         \
+    if (pITORIG != pITCOPY)                    \
+      *(pITORIG) = *(pITCOPY);                 \
+    bidi_unshelve_cache (CACHE);               \
+    CACHE = NULL;                              \
+  } while (0)
+
 #if GLYPH_DEBUG
 
 /* Non-zero means print traces of redisplay if compiled with
@@ -814,7 +837,7 @@ static int cursor_row_fully_visible_p (struct window *, int, int);
 static int try_scrolling (Lisp_Object, int, EMACS_INT, EMACS_INT, int, int);
 static int try_cursor_movement (Lisp_Object, struct text_pos, int *);
 static int trailing_whitespace_p (EMACS_INT);
-static unsigned long int message_log_check_duplicate (EMACS_INT, EMACS_INT);
+static intmax_t message_log_check_duplicate (EMACS_INT, EMACS_INT);
 static void push_it (struct it *, struct text_pos *);
 static void pop_it (struct it *);
 static void sync_frame_with_window_matrix_rows (struct window *);
@@ -931,7 +954,7 @@ static int coords_in_mouse_face_p (struct window *, int, int);
 
    This is the height of W minus the height of a mode line, if any.  */
 
-INLINE int
+inline int
 window_text_bottom_y (struct window *w)
 {
   int height = WINDOW_TOTAL_HEIGHT (w);
@@ -945,7 +968,7 @@ window_text_bottom_y (struct window *w)
    means return the total width of W, not including fringes to
    the left and right of the window.  */
 
-INLINE int
+inline int
 window_box_width (struct window *w, int area)
 {
   int cols = XFASTINT (w->total_cols);
@@ -984,7 +1007,7 @@ window_box_width (struct window *w, int area)
 /* Return the pixel height of the display area of window W, not
    including mode lines of W, if any.  */
 
-INLINE int
+inline int
 window_box_height (struct window *w)
 {
   struct frame *f = XFRAME (w->frame);
@@ -1031,7 +1054,7 @@ window_box_height (struct window *w)
    area AREA of window W.  AREA < 0 means return the left edge of the
    whole window, to the right of the left fringe of W.  */
 
-INLINE int
+inline int
 window_box_left_offset (struct window *w, int area)
 {
   int x;
@@ -1063,7 +1086,7 @@ window_box_left_offset (struct window *w, int area)
    area AREA of window W.  AREA < 0 means return the right edge of the
    whole window, to the left of the right fringe of W.  */
 
-INLINE int
+inline int
 window_box_right_offset (struct window *w, int area)
 {
   return window_box_left_offset (w, area) + window_box_width (w, area);
@@ -1073,7 +1096,7 @@ window_box_right_offset (struct window *w, int area)
    area AREA of window W.  AREA < 0 means return the left edge of the
    whole window, to the right of the left fringe of W.  */
 
-INLINE int
+inline int
 window_box_left (struct window *w, int area)
 {
   struct frame *f = XFRAME (w->frame);
@@ -1093,7 +1116,7 @@ window_box_left (struct window *w, int area)
    area AREA of window W.  AREA < 0 means return the right edge of the
    whole window, to the left of the right fringe of W.  */
 
-INLINE int
+inline int
 window_box_right (struct window *w, int area)
 {
   return window_box_left (w, area) + window_box_width (w, area);
@@ -1106,7 +1129,7 @@ window_box_right (struct window *w, int area)
    coordinates of the upper-left corner of the box.  Return in
    *BOX_WIDTH, and *BOX_HEIGHT the pixel width and height of the box.  */
 
-INLINE void
+inline void
 window_box (struct window *w, int area, int *box_x, int *box_y,
            int *box_width, int *box_height)
 {
@@ -1133,7 +1156,7 @@ window_box (struct window *w, int area, int *box_x, int *box_y,
    *BOTTOM_RIGHT_Y the coordinates of the bottom-right corner of the
    box.  */
 
-static INLINE void
+static inline void
 window_box_edges (struct window *w, int area, int *top_left_x, int *top_left_y,
                   int *bottom_right_x, int *bottom_right_y)
 {
@@ -1199,6 +1222,7 @@ pos_visible_p (struct window *w, EMACS_INT charpos, int *x, int *y,
               int *rtop, int *rbot, int *rowh, int *vpos)
 {
   struct it it;
+  void *itdata = bidi_shelve_cache ();
   struct text_pos top;
   int visible_p = 0;
   struct buffer *old_buffer = NULL;
@@ -1229,13 +1253,21 @@ pos_visible_p (struct window *w, EMACS_INT charpos, int *x, int *y,
   move_it_to (&it, charpos, -1, it.last_visible_y-1, -1,
              (charpos >= 0 ? MOVE_TO_POS : 0) | MOVE_TO_Y);
 
-  if (charpos >= 0 && IT_CHARPOS (it) >= charpos)
+  if (charpos >= 0
+      && (((!it.bidi_p || it.bidi_it.scan_dir == 1)
+          && IT_CHARPOS (it) >= charpos)
+         /* When scanning backwards under bidi iteration, move_it_to
+            stops at or _before_ CHARPOS, because it stops at or to
+            the _right_ of the character at CHARPOS. */
+         || (it.bidi_p && it.bidi_it.scan_dir == -1
+             && IT_CHARPOS (it) <= charpos)))
     {
       /* We have reached CHARPOS, or passed it.  How the call to
-        move_it_to can overshoot: (i) If CHARPOS is on invisible
-        text, move_it_to stops at the end of the invisible text,
-        after CHARPOS.  (ii) If CHARPOS is in a display vector,
-        move_it_to stops on its last glyph.  */
+        move_it_to can overshoot: (i) If CHARPOS is on invisible text
+        or covered by a display property, move_it_to stops at the end
+        of the invisible text, to the right of CHARPOS.  (ii) If
+        CHARPOS is in a display vector, move_it_to stops on its last
+        glyph.  */
       int top_x = it.current_x;
       int top_y = it.current_y;
       enum it_method it_method = it.method;
@@ -1284,15 +1316,18 @@ pos_visible_p (struct window *w, EMACS_INT charpos, int *x, int *y,
     }
   else
     {
+      /* We were asked to provide info about WINDOW_END.  */
       struct it it2;
+      void *it2data = NULL;
 
-      it2 = it;
+      SAVE_IT (it2, it, it2data);
       if (IT_CHARPOS (it) < ZV && FETCH_BYTE (IT_BYTEPOS (it)) != '\n')
        move_it_by_lines (&it, 1);
       if (charpos < IT_CHARPOS (it)
          || (it.what == IT_EOB && charpos == IT_CHARPOS (it)))
        {
          visible_p = 1;
+         RESTORE_IT (&it2, &it2, it2data);
          move_it_to (&it2, charpos, -1, -1, -1, MOVE_TO_POS);
          *x = it2.current_x;
          *y = it2.current_y + it2.max_ascent - it2.ascent;
@@ -1305,7 +1340,10 @@ pos_visible_p (struct window *w, EMACS_INT charpos, int *x, int *y,
                                  WINDOW_HEADER_LINE_HEIGHT (w))));
          *vpos = it2.vpos;
        }
+      else
+       xfree (it2data);
     }
+  bidi_unshelve_cache (itdata);
 
   if (old_buffer)
     set_buffer_internal_1 (old_buffer);
@@ -1333,13 +1371,13 @@ pos_visible_p (struct window *w, EMACS_INT charpos, int *x, int *y,
    returns an invalid character.  If we find one, we return a `?', but
    with the length of the invalid character.  */
 
-static INLINE int
+static inline int
 string_char_and_length (const unsigned char *str, int *len)
 {
   int c;
 
   c = STRING_CHAR_AND_LENGTH (str, *len);
-  if (!CHAR_VALID_P (c, 1))
+  if (!CHAR_VALID_P (c))
     /* We may not change the length here because other places in Emacs
        don't use this function, i.e. they silently accept invalid
        characters.  */
@@ -1381,7 +1419,7 @@ string_pos_nchars_ahead (struct text_pos pos, Lisp_Object string, EMACS_INT ncha
 /* Value is the text position, i.e. character and byte position,
    for character position CHARPOS in STRING.  */
 
-static INLINE struct text_pos
+static inline struct text_pos
 string_pos (EMACS_INT charpos, Lisp_Object string)
 {
   struct text_pos pos;
@@ -2142,7 +2180,7 @@ safe_eval_handler (Lisp_Object arg)
    redisplay during the evaluation.  */
 
 Lisp_Object
-safe_call (size_t nargs, Lisp_Object *args)
+safe_call (ptrdiff_t nargs, Lisp_Object *args)
 {
   Lisp_Object val;
 
@@ -2213,8 +2251,7 @@ safe_call2 (Lisp_Object fn, Lisp_Object arg1, Lisp_Object arg2)
    This is for debugging.  It is too slow to do unconditionally.  */
 
 static void
-check_it (it)
-     struct it *it;
+check_it (struct it *it)
 {
   if (it->method == GET_FROM_STRING)
     {
@@ -2246,14 +2283,13 @@ check_it (it)
 #endif /* not 0 */
 
 
-#if GLYPH_DEBUG
+#if GLYPH_DEBUG && XASSERTS
 
 /* Check that the window end of window W is what we expect it
    to be---the last row in the current matrix displaying text.  */
 
 static void
-check_window_end (w)
-     struct window *w;
+check_window_end (struct window *w)
 {
   if (!MINI_WINDOW_P (w)
       && !NILP (w->window_end_valid))
@@ -2269,11 +2305,11 @@ check_window_end (w)
 
 #define CHECK_WINDOW_END(W)    check_window_end ((W))
 
-#else /* not GLYPH_DEBUG */
+#else
 
 #define CHECK_WINDOW_END(W)    (void) 0
 
-#endif /* not GLYPH_DEBUG */
+#endif
 
 
 \f
@@ -2393,7 +2429,7 @@ init_iterator (struct it *it, struct window *w,
      is invisible.  >0 means lines indented more than this value are
      invisible.  */
   it->selective = (INTEGERP (BVAR (current_buffer, selective_display))
-                  ? XFASTINT (BVAR (current_buffer, selective_display))
+                  ? XINT (BVAR (current_buffer, selective_display))
                   : (!NILP (BVAR (current_buffer, selective_display))
                      ? -1 : 0));
   it->selective_display_ellipsis_p
@@ -2442,10 +2478,7 @@ init_iterator (struct it *it, struct window *w,
   else if (INTEGERP (w->redisplay_end_trigger))
     it->redisplay_end_trigger_charpos = XINT (w->redisplay_end_trigger);
 
-  /* Correct bogus values of tab_width.  */
-  it->tab_width = XINT (BVAR (current_buffer, tab_width));
-  if (it->tab_width <= 0 || it->tab_width > 1000)
-    it->tab_width = 8;
+  it->tab_width = SANE_TAB_WIDTH (current_buffer);
 
   /* Are lines in the display truncated?  */
   if (base_face_id != DEFAULT_FACE_ID
@@ -2591,6 +2624,7 @@ init_iterator (struct it *it, struct window *w,
            it->paragraph_embedding = R2L;
          else
            it->paragraph_embedding = NEUTRAL_DIR;
+         bidi_unshelve_cache (NULL);
          bidi_init_it (charpos, IT_BYTEPOS (*it), FRAME_WINDOW_P (it->f),
                        &it->bidi_it);
        }
@@ -2915,6 +2949,7 @@ handle_stop (struct it *it)
                {
                  it->ignore_overlay_strings_at_pos_p = 1;
                  it->string_from_display_prop_p = 0;
+                 it->from_disp_prop_p = 0;
                  handle_overlay_change_p = 0;
                }
              handled = HANDLED_RECOMPUTE_PROPS;
@@ -3074,10 +3109,9 @@ compute_stop_pos (struct it *it)
 static EMACS_INT
 next_overlay_change (EMACS_INT pos)
 {
-  int noverlays;
+  ptrdiff_t i, noverlays;
   EMACS_INT endpos;
   Lisp_Object *overlays;
-  int i;
 
   /* Get all overlays at the given position.  */
   GET_OVERLAYS_AT (pos, overlays, noverlays, &endpos, 1);
@@ -3097,6 +3131,14 @@ next_overlay_change (EMACS_INT pos)
   return endpos;
 }
 
+/* Record one cached display string position found recently by
+   compute_display_string_pos.  */
+static EMACS_INT cached_disp_pos;
+static EMACS_INT cached_prev_pos = -1;
+static struct buffer *cached_disp_buffer;
+static int cached_disp_modiff;
+static int cached_disp_overlay_modiff;
+
 /* Return the character position of a display string at or after
    position specified by POSITION.  If no display string exists at or
    after POSITION, return ZV.  A display string is either an overlay
@@ -3118,6 +3160,7 @@ compute_display_string_pos (struct text_pos *position,
   EMACS_INT begb = string_p ? 0 : BEGV;
   EMACS_INT bufpos, charpos = CHARPOS (*position);
   struct text_pos tpos;
+  struct buffer *b;
 
   if (charpos >= eob
       /* We don't support display properties whose values are strings
@@ -3127,6 +3170,38 @@ compute_display_string_pos (struct text_pos *position,
       || (string->s && !STRINGP (object)))
     return eob;
 
+  /* Check the cached values.  */
+  if (!STRINGP (object))
+    {
+      if (NILP (object))
+       b = current_buffer;
+      else
+       b = XBUFFER (object);
+      if (b == cached_disp_buffer
+         && BUF_MODIFF (b) == cached_disp_modiff
+         && BUF_OVERLAY_MODIFF (b) == cached_disp_overlay_modiff
+         && !b->clip_changed)
+       {
+         if (cached_prev_pos >= 0
+             && cached_prev_pos < charpos && charpos <= cached_disp_pos)
+           return cached_disp_pos;
+         /* Handle overstepping either end of the known interval.  */
+         if (charpos > cached_disp_pos)
+           cached_prev_pos = cached_disp_pos;
+         else  /* charpos <= cached_prev_pos */
+           cached_prev_pos = max (charpos - 1, 0);
+       }
+
+      /* Record new values in the cache.  */
+      if (b != cached_disp_buffer)
+       {
+         cached_disp_buffer = b;
+         cached_prev_pos = max (charpos - 1, 0);
+       }
+      cached_disp_modiff = BUF_MODIFF (b);
+      cached_disp_overlay_modiff = BUF_OVERLAY_MODIFF (b);
+    }
+
   /* If the character at CHARPOS is where the display string begins,
      return CHARPOS.  */
   pos = make_number (charpos);
@@ -3142,7 +3217,11 @@ compute_display_string_pos (struct text_pos *position,
                  spec))
       && handle_display_spec (NULL, spec, object, Qnil, &tpos, bufpos,
                              frame_window_p))
-    return charpos;
+    {
+      if (!STRINGP (object))
+       cached_disp_pos = charpos;
+      return charpos;
+    }
 
   /* Look forward for the first character with a `display' property
      that will replace the underlying text when displayed.  */
@@ -3162,6 +3241,8 @@ compute_display_string_pos (struct text_pos *position,
           || !handle_display_spec (NULL, spec, object, Qnil, &tpos, bufpos,
                                    frame_window_p));
 
+  if (!STRINGP (object))
+    cached_disp_pos = CHARPOS (tpos);
   return CHARPOS (tpos);
 }
 
@@ -3483,6 +3564,7 @@ face_before_or_after_it_pos (struct it *it, int before_p)
   int face_id, limit;
   EMACS_INT next_check_charpos;
   struct it it_copy;
+  void *it_copy_data = NULL;
 
   xassert (it->s == NULL);
 
@@ -3525,7 +3607,7 @@ face_before_or_after_it_pos (struct it *it, int before_p)
                 character on this display line.  */
              if (it->current_x <= it->first_visible_x)
                return it->face_id;
-             it_copy = *it;
+             SAVE_IT (it_copy, *it, it_copy_data);
              /* Implementation note: Since move_it_in_display_line
                 works in the iterator geometry, and thinks the first
                 character is always the leftmost, even in R2L lines,
@@ -3534,6 +3616,7 @@ face_before_or_after_it_pos (struct it *it, int before_p)
              move_it_in_display_line (&it_copy, SCHARS (it_copy.string),
                                       it_copy.current_x - 1, MOVE_TO_X);
              charpos = IT_STRING_CHARPOS (it_copy);
+             RESTORE_IT (it, it, it_copy_data);
            }
          else
            {
@@ -3623,7 +3706,7 @@ face_before_or_after_it_pos (struct it *it, int before_p)
                 character on this display line.  */
              if (it->current_x <= it->first_visible_x)
                return it->face_id;
-             it_copy = *it;
+             SAVE_IT (it_copy, *it, it_copy_data);
              /* Implementation note: Since move_it_in_display_line
                 works in the iterator geometry, and thinks the first
                 character is always the leftmost, even in R2L lines,
@@ -3632,6 +3715,7 @@ face_before_or_after_it_pos (struct it *it, int before_p)
              move_it_in_display_line (&it_copy, ZV,
                                       it_copy.current_x - 1, MOVE_TO_X);
              pos = it_copy.current.pos;
+             RESTORE_IT (it, it, it_copy_data);
            }
          else
            {
@@ -4757,6 +4841,11 @@ handle_composition_prop (struct it *it)
       && COMPOSITION_VALID_P (start, end, prop)
       && (STRINGP (it->string) || (PT <= start || PT >= end)))
     {
+      if (start < pos)
+       /* As we can't handle this situation (perhaps font-lock added
+          a new composition), we just return here hoping that next
+          redisplay will detect this composition much earlier.  */
+       return HANDLED_NORMALLY;
       if (start != pos)
        {
          if (STRINGP (it->string))
@@ -5416,7 +5505,8 @@ back_to_previous_line_start (struct it *it)
 static int
 forward_to_next_line_start (struct it *it, int *skipped_p)
 {
-  int old_selective, newline_found_p, n;
+  EMACS_INT old_selective;
+  int newline_found_p, n;
   const int MAX_NEWLINE_DISTANCE = 500;
 
   /* If already on a newline, just consume it to avoid unintended
@@ -5509,7 +5599,7 @@ back_to_previous_visible_line_start (struct it *it)
         invisible.  */
       if (it->selective > 0
          && indented_beyond_p (IT_CHARPOS (*it), IT_BYTEPOS (*it),
-                               (double) it->selective)) /* iftc */
+                               it->selective))
        continue;
 
       /* Check the newline before point for invisibility.  */
@@ -5526,10 +5616,13 @@ back_to_previous_visible_line_start (struct it *it)
 
       {
        struct it it2;
+       void *it2data = NULL;
        EMACS_INT pos;
        EMACS_INT beg, end;
        Lisp_Object val, overlay;
 
+       SAVE_IT (it2, *it, it2data);
+
        /* If newline is part of a composition, continue from start of composition */
        if (find_composition (IT_CHARPOS (*it), -1, &beg, &end, &val, Qnil)
            && beg < IT_CHARPOS (*it))
@@ -5537,11 +5630,12 @@ back_to_previous_visible_line_start (struct it *it)
 
        /* If newline is replaced by a display property, find start of overlay
           or interval and continue search from that point.  */
-       it2 = *it;
        pos = --IT_CHARPOS (it2);
        --IT_BYTEPOS (it2);
        it2.sp = 0;
+       bidi_unshelve_cache (NULL);
        it2.string_from_display_prop_p = 0;
+       it2.from_disp_prop_p = 0;
        if (handle_display_prop (&it2) == HANDLED_RETURN
            && !NILP (val = get_char_property_and_overlay
                      (make_number (pos), Qdisplay, Qnil, &overlay))
@@ -5549,21 +5643,12 @@ back_to_previous_visible_line_start (struct it *it)
                ? (beg = OVERLAY_POSITION (OVERLAY_START (overlay)))
                : get_property_and_range (pos, Qdisplay, &val, &beg, &end, Qnil)))
          {
-           /* If the call to handle_display_prop above pushed the
-              iterator state, that causes side effects for the bidi
-              iterator by calling bidi_push_it.  Undo those side
-              effects.  */
-           while (it2.sp > 0)
-             {
-               /* push_it calls bidi_push_it only if the bidi_p flag
-                  is set in the iterator being pushed.  */
-               if (it2.stack[--it2.sp].bidi_p)
-                 bidi_pop_it (&it2.bidi_it);
-             }
+           RESTORE_IT (it, it, it2data);
            goto replaced;
          }
 
        /* Newline is not replaced by anything -- so we are done.  */
+       RESTORE_IT (it, it, it2data);
        break;
 
       replaced:
@@ -5616,7 +5701,7 @@ reseat_at_next_visible_line_start (struct it *it, int on_newline_p)
   if (it->selective > 0)
     while (IT_CHARPOS (*it) < ZV
           && indented_beyond_p (IT_CHARPOS (*it), IT_BYTEPOS (*it),
-                                (double) it->selective)) /* iftc */
+                                it->selective))
       {
        xassert (IT_BYTEPOS (*it) == BEGV
                 || FETCH_BYTE (IT_BYTEPOS (*it) - 1) == '\n');
@@ -5690,17 +5775,19 @@ reseat (struct it *it, struct text_pos pos, int force_p)
        {
          /* For bidi iteration, we need to prime prev_stop and
             base_level_stop with our best estimations.  */
-         if (CHARPOS (pos) < it->prev_stop)
-           {
-             handle_stop_backwards (it, BEGV);
-             if (CHARPOS (pos) < it->base_level_stop)
-               it->base_level_stop = 0;
-           }
-         else if (CHARPOS (pos) > it->stop_charpos
-                  && it->stop_charpos >= BEGV)
-           handle_stop_backwards (it, it->stop_charpos);
-         else  /* force_p */
-           handle_stop (it);
+         /* Implementation note: Of course, POS is not necessarily a
+            stop position, so assigning prev_pos to it is a lie; we
+            should have called compute_stop_backwards.  However, if
+            the current buffer does not include any R2L characters,
+            that call would be a waste of cycles, because the
+            iterator will never move back, and thus never cross this
+            "fake" stop position.  So we delay that backward search
+            until the time we really need it, in next_element_from_buffer.  */
+         if (CHARPOS (pos) != it->prev_stop)
+           it->prev_stop = CHARPOS (pos);
+         if (CHARPOS (pos) < it->base_level_stop)
+           it->base_level_stop = 0; /* meaning it's unknown */
+         handle_stop (it);
        }
       else
        {
@@ -5740,12 +5827,14 @@ reseat_1 (struct it *it, struct text_pos pos, int set_stop_p)
   it->multibyte_p = !NILP (BVAR (current_buffer, enable_multibyte_characters));
   it->sp = 0;
   it->string_from_display_prop_p = 0;
+  it->from_disp_prop_p = 0;
   it->face_before_selective_p = 0;
   if (it->bidi_p)
     {
-      it->bidi_it.first_elt = 1;
+      bidi_init_it (IT_CHARPOS (*it), IT_BYTEPOS (*it), FRAME_WINDOW_P (it->f),
+                   &it->bidi_it);
+      bidi_unshelve_cache (NULL);
       it->bidi_it.paragraph_dir = NEUTRAL_DIR;
-      it->bidi_it.disp_pos = -1;
       it->bidi_it.string.s = NULL;
       it->bidi_it.string.lstring = Qnil;
       it->bidi_it.string.bufpos = 0;
@@ -5847,7 +5936,7 @@ reseat_to_string (struct it *it, const char *s, Lisp_Object string,
       if (it->bidi_p)
        {
          it->bidi_it.string.lstring = Qnil;
-         it->bidi_it.string.s = s;
+         it->bidi_it.string.s = (const unsigned char *) s;
          it->bidi_it.string.schars = it->end_charpos;
          it->bidi_it.string.bufpos = 0;
          it->bidi_it.string.from_disp_str = 0;
@@ -6130,7 +6219,8 @@ get_next_display_element (struct it *it)
                 display.  Then, set IT->dpvec to these glyphs.  */
              Lisp_Object gc;
              int ctl_len;
-             int face_id, lface_id = 0 ;
+             int face_id;
+             EMACS_INT lface_id = 0;
              int escape_glyph;
 
              /* Handle control characters with ^.  */
@@ -6300,11 +6390,23 @@ get_next_display_element (struct it *it)
       else
        {
          EMACS_INT pos = (it->s ? -1
-                          : STRINGP (it->string) ? IT_STRING_CHARPOS (*it)
-                          : IT_CHARPOS (*it));
+                    : STRINGP (it->string) ? IT_STRING_CHARPOS (*it)
+                    : IT_CHARPOS (*it));
+         int c;
+
+         if (it->what == IT_CHARACTER)
+           c = it->char_to_display;
+         else
+           {
+             struct composition *cmp = composition_table[it->cmp_it.id];
+             int i;
 
-         it->face_id = FACE_FOR_CHAR (it->f, face, it->char_to_display, pos,
-                                      it->string);
+             c = ' ';
+             for (i = 0; i < cmp->glyph_len; i++)
+               if ((c = COMPOSITION_GLYPH (cmp, i)) != '\t')
+                 break;
+           }
+         it->face_id = FACE_FOR_CHAR (it->f, face, c, pos, it->string);
        }
     }
 
@@ -6759,7 +6861,7 @@ next_element_from_display_vector (struct it *it)
        it->face_id = it->dpvec_face_id;
       else
        {
-         int lface_id = GLYPH_CODE_FACE (gc);
+         EMACS_INT lface_id = GLYPH_CODE_FACE (gc);
          if (lface_id > 0)
            it->face_id = merge_faces (it->f, Qt, lface_id,
                                       it->saved_face_id);
@@ -6889,7 +6991,7 @@ next_element_from_string (struct it *it)
   struct text_pos position;
 
   xassert (STRINGP (it->string));
-  xassert (!it->bidi_p || it->string == it->bidi_it.string.lstring);
+  xassert (!it->bidi_p || EQ (it->string, it->bidi_it.string.lstring));
   xassert (IT_STRING_CHARPOS (*it) >= 0);
   position = it->current.string_pos;
 
@@ -6952,10 +7054,10 @@ next_element_from_string (struct it *it)
                  embedding level, so test for that explicitly.  */
               && !BIDI_AT_BASE_LEVEL (it->bidi_it))
        {
-         /* If we lost track of base_level_stop, we have no better place
-            for handle_stop_backwards to start from than BEGV.  This
-            happens, e.g., when we were reseated to the previous
-            screenful of text by vertical-motion.  */
+         /* If we lost track of base_level_stop, we have no better
+            place for handle_stop_backwards to start from than string
+            beginning.  This happens, e.g., when we were reseated to
+            the previous screenful of text by vertical-motion.  */
          if (it->base_level_stop <= 0
              || IT_STRING_CHARPOS (*it) < it->base_level_stop)
            it->base_level_stop = 0;
@@ -7143,6 +7245,50 @@ next_element_from_stretch (struct it *it)
   return 1;
 }
 
+/* Scan backwards from IT's current position until we find a stop
+   position, or until BEGV.  This is called when we find ourself
+   before both the last known prev_stop and base_level_stop while
+   reordering bidirectional text.  */
+
+static void
+compute_stop_pos_backwards (struct it *it)
+{
+  const int SCAN_BACK_LIMIT = 1000;
+  struct text_pos pos;
+  struct display_pos save_current = it->current;
+  struct text_pos save_position = it->position;
+  EMACS_INT charpos = IT_CHARPOS (*it);
+  EMACS_INT where_we_are = charpos;
+  EMACS_INT save_stop_pos = it->stop_charpos;
+  EMACS_INT save_end_pos = it->end_charpos;
+
+  xassert (NILP (it->string) && !it->s);
+  xassert (it->bidi_p);
+  it->bidi_p = 0;
+  do
+    {
+      it->end_charpos = min (charpos + 1, ZV);
+      charpos = max (charpos - SCAN_BACK_LIMIT, BEGV);
+      SET_TEXT_POS (pos, charpos, BYTE_TO_CHAR (charpos));
+      reseat_1 (it, pos, 0);
+      compute_stop_pos (it);
+      /* We must advance forward, right?  */
+      if (it->stop_charpos <= charpos)
+       abort ();
+    }
+  while (charpos > BEGV && it->stop_charpos >= it->end_charpos);
+
+  if (it->stop_charpos <= where_we_are)
+    it->prev_stop = it->stop_charpos;
+  else
+    it->prev_stop = BEGV;
+  it->bidi_p = 1;
+  it->current = save_current;
+  it->position = save_position;
+  it->stop_charpos = save_stop_pos;
+  it->end_charpos = save_end_pos;
+}
+
 /* Scan forward from CHARPOS in the current buffer/string, until we
    find a stop position > current IT's position.  Then handle the stop
    position before that.  This is called when we bump into a stop
@@ -7162,6 +7308,7 @@ handle_stop_backwards (struct it *it, EMACS_INT charpos)
   EMACS_INT next_stop;
 
   /* Scan in strict logical order.  */
+  xassert (it->bidi_p);
   it->bidi_p = 0;
   do
     {
@@ -7181,11 +7328,11 @@ handle_stop_backwards (struct it *it, EMACS_INT charpos)
     }
   while (charpos <= where_we_are);
 
-  next_stop = it->stop_charpos;
-  it->stop_charpos = it->prev_stop;
   it->bidi_p = 1;
   it->current = save_current;
   it->position = save_position;
+  next_stop = it->stop_charpos;
+  it->stop_charpos = it->prev_stop;
   handle_stop (it);
   it->stop_charpos = next_stop;
 }
@@ -7203,7 +7350,7 @@ next_element_from_buffer (struct it *it)
   xassert (IT_CHARPOS (*it) >= BEGV);
   xassert (NILP (it->string) && !it->s);
   xassert (!it->bidi_p
-          || (it->bidi_it.string.lstring == Qnil
+          || (EQ (it->bidi_it.string.lstring, Qnil)
               && it->bidi_it.string.s == NULL));
 
   /* With bidi reordering, the character to display might not be the
@@ -7282,14 +7429,19 @@ next_element_from_buffer (struct it *it)
              embedding level, so test for that explicitly.  */
           && !BIDI_AT_BASE_LEVEL (it->bidi_it))
     {
-      /* If we lost track of base_level_stop, we have no better place
-        for handle_stop_backwards to start from than BEGV.  This
-        happens, e.g., when we were reseated to the previous
-        screenful of text by vertical-motion.  */
       if (it->base_level_stop <= 0
          || IT_CHARPOS (*it) < it->base_level_stop)
-       it->base_level_stop = BEGV;
-      handle_stop_backwards (it, it->base_level_stop);
+       {
+         /* If we lost track of base_level_stop, we need to find
+            prev_stop by looking backwards.  This happens, e.g., when
+            we were reseated to the previous screenful of text by
+            vertical-motion.  */
+         it->base_level_stop = BEGV;
+         compute_stop_pos_backwards (it);
+         handle_stop_backwards (it, it->prev_stop);
+       }
+      else
+       handle_stop_backwards (it, it->base_level_stop);
       return GET_NEXT_DISPLAY_ELEMENT (it);
     }
   else
@@ -7338,7 +7490,7 @@ next_element_from_buffer (struct it *it)
                  && IT_CHARPOS (*it) + 1 < ZV
                  && indented_beyond_p (IT_CHARPOS (*it) + 1,
                                        IT_BYTEPOS (*it) + 1,
-                                       (double) it->selective)) /* iftc */
+                                       it->selective))
                {
                  success_p = next_element_from_ellipsis (it);
                  it->dpvec_char_len = -1;
@@ -7491,10 +7643,13 @@ move_it_in_display_line_to (struct it *it,
 {
   enum move_it_result result = MOVE_UNDEFINED;
   struct glyph_row *saved_glyph_row;
-  struct it wrap_it, atpos_it, atx_it;
+  struct it wrap_it, atpos_it, atx_it, ppos_it;
+  void *wrap_data = NULL, *atpos_data = NULL, *atx_data = NULL;
+  void *ppos_data = NULL;
   int may_wrap = 0;
   enum it_method prev_method = it->method;
   EMACS_INT prev_pos = IT_CHARPOS (*it);
+  int saw_smaller_pos = prev_pos < to_charpos;
 
   /* Don't produce glyphs in produce_glyphs.  */
   saved_glyph_row = it->glyph_row;
@@ -7509,6 +7664,19 @@ move_it_in_display_line_to (struct it *it,
   atpos_it.sp = -1;
   atx_it.sp = -1;
 
+  /* Use ppos_it under bidi reordering to save a copy of IT for the
+     position > CHARPOS that is the closest to CHARPOS.  We restore
+     that position in IT when we have scanned the entire display line
+     without finding a match for CHARPOS and all the character
+     positions are greater than CHARPOS.  */
+  if (it->bidi_p)
+    {
+      SAVE_IT (ppos_it, *it, ppos_data);
+      SET_TEXT_POS (ppos_it.current.pos, ZV, ZV_BYTE);
+      if ((op & MOVE_TO_POS) && IT_CHARPOS (*it) >= to_charpos)
+       SAVE_IT (ppos_it, *it, ppos_data);
+    }
+
 #define BUFFER_POS_REACHED_P()                                 \
   ((op & MOVE_TO_POS) != 0                                     \
    && BUFFERP (it->object)                                     \
@@ -7535,15 +7703,16 @@ move_it_in_display_line_to (struct it *it,
   ((IT)->current_x = x, (IT)->max_ascent = ascent,     \
    (IT)->max_descent = descent)
 
-      /* Stop if we move beyond TO_CHARPOS (after an image or stretch
-        glyph).  */
+      /* Stop if we move beyond TO_CHARPOS (after an image or a
+        display string or stretch glyph).  */
       if ((op & MOVE_TO_POS) != 0
          && BUFFERP (it->object)
          && it->method == GET_FROM_BUFFER
          && ((!it->bidi_p && IT_CHARPOS (*it) > to_charpos)
              || (it->bidi_p
                  && (prev_method == GET_FROM_IMAGE
-                     || prev_method == GET_FROM_STRETCH)
+                     || prev_method == GET_FROM_STRETCH
+                     || prev_method == GET_FROM_STRING)
                  /* Passed TO_CHARPOS from left to right.  */
                  && ((prev_pos < to_charpos
                       && IT_CHARPOS (*it) > to_charpos)
@@ -7560,12 +7729,9 @@ move_it_in_display_line_to (struct it *it,
            /* If wrap_it is valid, the current position might be in a
               word that is wrapped.  So, save the iterator in
               atpos_it and continue to see if wrapping happens.  */
-           atpos_it = *it;
+           SAVE_IT (atpos_it, *it, atpos_data);
        }
 
-      prev_method = it->method;
-      if (it->method == GET_FROM_BUFFER)
-       prev_pos = IT_CHARPOS (*it);
       /* Stop when ZV reached.
          We used to stop here when TO_CHARPOS reached as well, but that is
          too soon if this glyph does not fit on this line.  So we handle it
@@ -7597,18 +7763,18 @@ move_it_in_display_line_to (struct it *it,
                     already found, we are done.  */
                  if (atpos_it.sp >= 0)
                    {
-                     *it = atpos_it;
+                     RESTORE_IT (it, &atpos_it, atpos_data);
                      result = MOVE_POS_MATCH_OR_ZV;
                      goto done;
                    }
                  if (atx_it.sp >= 0)
                    {
-                     *it = atx_it;
+                     RESTORE_IT (it, &atx_it, atx_data);
                      result = MOVE_X_REACHED;
                      goto done;
                    }
                  /* Otherwise, we can wrap here.  */
-                 wrap_it = *it;
+                 SAVE_IT (wrap_it, *it, wrap_data);
                  may_wrap = 0;
                }
            }
@@ -7629,10 +7795,18 @@ move_it_in_display_line_to (struct it *it,
 
       if (it->area != TEXT_AREA)
        {
+         prev_method = it->method;
+         if (it->method == GET_FROM_BUFFER)
+           prev_pos = IT_CHARPOS (*it);
          set_iterator_to_next (it, 1);
          if (IT_CHARPOS (*it) < CHARPOS (this_line_min_pos))
            SET_TEXT_POS (this_line_min_pos,
                          IT_CHARPOS (*it), IT_BYTEPOS (*it));
+         if (it->bidi_p
+             && (op & MOVE_TO_POS)
+             && IT_CHARPOS (*it) > to_charpos
+             && IT_CHARPOS (*it) < IT_CHARPOS (ppos_it))
+           SAVE_IT (ppos_it, *it, ppos_data);
          continue;
        }
 
@@ -7676,7 +7850,7 @@ move_it_in_display_line_to (struct it *it,
                        goto buffer_pos_reached;
                      if (atpos_it.sp < 0)
                        {
-                         atpos_it = *it;
+                         SAVE_IT (atpos_it, *it, atpos_data);
                          IT_RESET_X_ASCENT_DESCENT (&atpos_it);
                        }
                    }
@@ -7690,7 +7864,7 @@ move_it_in_display_line_to (struct it *it,
                        }
                      if (atx_it.sp < 0)
                        {
-                         atx_it = *it;
+                         SAVE_IT (atx_it, *it, atx_data);
                          IT_RESET_X_ASCENT_DESCENT (&atx_it);
                        }
                    }
@@ -7734,12 +7908,15 @@ move_it_in_display_line_to (struct it *it,
                              if (it->line_wrap == WORD_WRAP
                                  && atpos_it.sp < 0)
                                {
-                                 atpos_it = *it;
+                                 SAVE_IT (atpos_it, *it, atpos_data);
                                  atpos_it.current_x = x_before_this_char;
                                  atpos_it.hpos = hpos_before_this_char;
                                }
                            }
 
+                         prev_method = it->method;
+                         if (it->method == GET_FROM_BUFFER)
+                           prev_pos = IT_CHARPOS (*it);
                          set_iterator_to_next (it, 1);
                          if (IT_CHARPOS (*it) < CHARPOS (this_line_min_pos))
                            SET_TEXT_POS (this_line_min_pos,
@@ -7779,7 +7956,7 @@ move_it_in_display_line_to (struct it *it,
 
                  if (wrap_it.sp >= 0)
                    {
-                     *it = wrap_it;
+                     RESTORE_IT (it, &wrap_it, wrap_data);
                      atpos_it.sp = -1;
                      atx_it.sp = -1;
                    }
@@ -7796,7 +7973,7 @@ move_it_in_display_line_to (struct it *it,
                    goto buffer_pos_reached;
                  if (it->line_wrap == WORD_WRAP && atpos_it.sp < 0)
                    {
-                     atpos_it = *it;
+                     SAVE_IT (atpos_it, *it, atpos_data);
                      IT_RESET_X_ASCENT_DESCENT (&atpos_it);
                    }
                }
@@ -7833,10 +8010,24 @@ move_it_in_display_line_to (struct it *it,
       /* Is this a line end?  If yes, we're done.  */
       if (ITERATOR_AT_END_OF_LINE_P (it))
        {
-         result = MOVE_NEWLINE_OR_CR;
+         /* If we are past TO_CHARPOS, but never saw any character
+            positions smaller than TO_CHARPOS, return
+            MOVE_POS_MATCH_OR_ZV, like the unidirectional display
+            did.  */
+         if ((op & MOVE_TO_POS) != 0
+             && !saw_smaller_pos
+             && IT_CHARPOS (*it) > to_charpos)
+           {
+             result = MOVE_POS_MATCH_OR_ZV;
+             if (it->bidi_p && IT_CHARPOS (ppos_it) < ZV)
+               RESTORE_IT (it, &ppos_it, ppos_data);
+           }
+         else
+           result = MOVE_NEWLINE_OR_CR;
          break;
        }
 
+      prev_method = it->method;
       if (it->method == GET_FROM_BUFFER)
        prev_pos = IT_CHARPOS (*it);
       /* The current display element has been consumed.  Advance
@@ -7844,6 +8035,13 @@ move_it_in_display_line_to (struct it *it,
       set_iterator_to_next (it, 1);
       if (IT_CHARPOS (*it) < CHARPOS (this_line_min_pos))
        SET_TEXT_POS (this_line_min_pos, IT_CHARPOS (*it), IT_BYTEPOS (*it));
+      if (IT_CHARPOS (*it) < to_charpos)
+       saw_smaller_pos = 1;
+      if (it->bidi_p
+         && (op & MOVE_TO_POS)
+         && IT_CHARPOS (*it) >= to_charpos
+         && IT_CHARPOS (*it) < IT_CHARPOS (ppos_it))
+       SAVE_IT (ppos_it, *it, ppos_data);
 
       /* Stop if lines are truncated and IT's current x-position is
         past the right edge of the window now.  */
@@ -7853,10 +8051,21 @@ move_it_in_display_line_to (struct it *it,
          if (!FRAME_WINDOW_P (it->f)
              || IT_OVERFLOW_NEWLINE_INTO_FRINGE (it))
            {
-             if (!get_next_display_element (it)
-                 || BUFFER_POS_REACHED_P ())
+             int at_eob_p = 0;
+
+             if ((at_eob_p = !get_next_display_element (it))
+                 || BUFFER_POS_REACHED_P ()
+                 /* If we are past TO_CHARPOS, but never saw any
+                    character positions smaller than TO_CHARPOS,
+                    return MOVE_POS_MATCH_OR_ZV, like the
+                    unidirectional display did.  */
+                 || ((op & MOVE_TO_POS) != 0
+                     && !saw_smaller_pos
+                     && IT_CHARPOS (*it) > to_charpos))
                {
                  result = MOVE_POS_MATCH_OR_ZV;
+                 if (it->bidi_p && !at_eob_p && IT_CHARPOS (ppos_it) < ZV)
+                   RESTORE_IT (it, &ppos_it, ppos_data);
                  break;
                }
              if (ITERATOR_AT_END_OF_LINE_P (it))
@@ -7865,6 +8074,15 @@ move_it_in_display_line_to (struct it *it,
                  break;
                }
            }
+         else if ((op & MOVE_TO_POS) != 0
+                  && !saw_smaller_pos
+                  && IT_CHARPOS (*it) > to_charpos)
+           {
+             result = MOVE_POS_MATCH_OR_ZV;
+             if (it->bidi_p && IT_CHARPOS (ppos_it) < ZV)
+               RESTORE_IT (it, &ppos_it, ppos_data);
+             break;
+           }
          result = MOVE_LINE_TRUNCATED;
          break;
        }
@@ -7876,12 +8094,21 @@ move_it_in_display_line_to (struct it *it,
   /* If we scanned beyond to_pos and didn't find a point to wrap at,
      restore the saved iterator.  */
   if (atpos_it.sp >= 0)
-    *it = atpos_it;
+    RESTORE_IT (it, &atpos_it, atpos_data);
   else if (atx_it.sp >= 0)
-    *it = atx_it;
+    RESTORE_IT (it, &atx_it, atx_data);
 
  done:
 
+  if (atpos_data)
+    xfree (atpos_data);
+  if (atx_data)
+    xfree (atx_data);
+  if (wrap_data)
+    xfree (wrap_data);
+  if (ppos_data)
+    xfree (ppos_data);
+
   /* Restore the iterator settings altered at the beginning of this
      function.  */
   it->glyph_row = saved_glyph_row;
@@ -7897,8 +8124,12 @@ move_it_in_display_line (struct it *it,
   if (it->line_wrap == WORD_WRAP
       && (op & MOVE_TO_X))
     {
-      struct it save_it = *it;
-      int skip = move_it_in_display_line_to (it, to_charpos, to_x, op);
+      struct it save_it;
+      void *save_data = NULL;
+      int skip;
+
+      SAVE_IT (save_it, *it, save_data);
+      skip = move_it_in_display_line_to (it, to_charpos, to_x, op);
       /* When word-wrap is on, TO_X may lie past the end
         of a wrapped line.  Then it->current is the
         character on the next line, so backtrack to the
@@ -7906,10 +8137,12 @@ move_it_in_display_line (struct it *it,
       if (skip == MOVE_LINE_CONTINUED)
        {
          int prev_x = max (it->current_x - 1, 0);
-         *it = save_it;
+         RESTORE_IT (it, &save_it, save_data);
          move_it_in_display_line_to
            (it, -1, prev_x, MOVE_TO_X);
        }
+      else
+       xfree (save_data);
     }
   else
     move_it_in_display_line_to (it, to_charpos, to_x, op);
@@ -7924,14 +8157,15 @@ move_it_in_display_line (struct it *it,
    description of enum move_operation_enum.
 
    If TO_CHARPOS is in invisible text, e.g. a truncated part of a
-   screen line, this function will set IT to the next position >
-   TO_CHARPOS.  */
+   screen line, this function will set IT to the next position that is
+   displayed to the right of TO_CHARPOS on the screen.  */
 
 void
 move_it_to (struct it *it, EMACS_INT to_charpos, int to_x, int to_y, int to_vpos, int op)
 {
   enum move_it_result skip, skip2 = MOVE_X_REACHED;
   int line_height, line_start_x = 0, reached = 0;
+  void *backup_data = NULL;
 
   for (;;)
     {
@@ -7984,7 +8218,7 @@ move_it_to (struct it *it, EMACS_INT to_charpos, int to_x, int to_y, int to_vpos
          struct it it_backup;
 
          if (it->line_wrap == WORD_WRAP)
-           it_backup = *it;
+           SAVE_IT (it_backup, *it, backup_data);
 
          /* TO_Y specified means stop at TO_X in the line containing
             TO_Y---or at TO_CHARPOS if this is reached first.  The
@@ -8018,7 +8252,7 @@ move_it_to (struct it *it, EMACS_INT to_charpos, int to_x, int to_y, int to_vpos
                  reached = 6;
                  break;
                }
-             it_backup = *it;
+             SAVE_IT (it_backup, *it, backup_data);
              TRACE_MOVE ((stderr, "move_it: from %d\n", IT_CHARPOS (*it)));
              skip2 = move_it_in_display_line_to (it, to_charpos, -1,
                                                  op & MOVE_TO_POS);
@@ -8032,7 +8266,7 @@ move_it_to (struct it *it, EMACS_INT to_charpos, int to_x, int to_y, int to_vpos
                  /* If TO_Y is in this line and TO_X was reached
                     above, we scanned too far.  We have to restore
                     IT's settings to the ones before skipping.  */
-                 *it = it_backup;
+                 RESTORE_IT (it, &it_backup, backup_data);
                  reached = 6;
                }
              else
@@ -8059,7 +8293,7 @@ move_it_to (struct it *it, EMACS_INT to_charpos, int to_x, int to_y, int to_vpos
                      && it->line_wrap == WORD_WRAP)
                    {
                      int prev_x = max (it->current_x - 1, 0);
-                     *it = it_backup;
+                     RESTORE_IT (it, &it_backup, backup_data);
                      skip = move_it_in_display_line_to
                        (it, -1, prev_x, MOVE_TO_X);
                    }
@@ -8166,6 +8400,9 @@ move_it_to (struct it *it, EMACS_INT to_charpos, int to_x, int to_y, int to_vpos
       last_max_ascent = it->max_ascent;
     }
 
+  if (backup_data)
+    xfree (backup_data);
+
   TRACE_MOVE ((stderr, "move_it_to: reached %d\n", reached));
 }
 
@@ -8183,6 +8420,7 @@ move_it_vertically_backward (struct it *it, int dy)
 {
   int nlines, h;
   struct it it2, it3;
+  void *it2data = NULL, *it3data = NULL;
   EMACS_INT start_pos;
 
  move_further_back:
@@ -8211,7 +8449,7 @@ move_it_vertically_backward (struct it *it, int dy)
      start of the next line so that we get its height.  We need this
      height to be able to tell whether we reached the specified
      y-distance.  */
-  it2 = *it;
+  SAVE_IT (it2, *it, it2data);
   it2.max_ascent = it2.max_descent = 0;
   do
     {
@@ -8220,7 +8458,7 @@ move_it_vertically_backward (struct it *it, int dy)
     }
   while (!IT_POS_VALID_AFTER_MOVE_P (&it2));
   xassert (IT_CHARPOS (*it) >= BEGV);
-  it3 = it2;
+  SAVE_IT (it3, it2, it3data);
 
   move_it_to (&it2, start_pos, -1, -1, -1, MOVE_TO_POS);
   xassert (IT_CHARPOS (*it) >= BEGV);
@@ -8239,8 +8477,10 @@ move_it_vertically_backward (struct it *it, int dy)
     {
       /* DY == 0 means move to the start of the screen line.  The
         value of nlines is > 0 if continuation lines were involved.  */
+      RESTORE_IT (it, it, it2data);
       if (nlines > 0)
        move_it_by_lines (it, nlines);
+      xfree (it3data);
     }
   else
     {
@@ -8248,9 +8488,13 @@ move_it_vertically_backward (struct it *it, int dy)
         Note that H has been subtracted in front of the if-statement.  */
       int target_y = it->current_y + h - dy;
       int y0 = it3.current_y;
-      int y1 = line_bottom_y (&it3);
-      int line_height = y1 - y0;
+      int y1;
+      int line_height;
 
+      RESTORE_IT (&it3, &it3, it3data);
+      y1 = line_bottom_y (&it3);
+      line_height = y1 - y0;
+      RESTORE_IT (it, it, it2data);
       /* If we did not reach target_y, try to move further backward if
         we can.  If we moved too far backward, try to move forward.  */
       if (target_y < it->current_y
@@ -8377,6 +8621,7 @@ move_it_by_lines (struct it *it, int dvpos)
   else
     {
       struct it it2;
+      void *it2data = NULL;
       EMACS_INT start_charpos, i;
 
       /* Start at the beginning of the screen line containing IT's
@@ -8412,7 +8657,7 @@ move_it_by_lines (struct it *it, int dvpos)
 
       /* Above call may have moved too far if continuation lines
         are involved.  Scan forward and see if it did.  */
-      it2 = *it;
+      SAVE_IT (it2, *it, it2data);
       it2.vpos = it2.current_y = 0;
       move_it_to (&it2, start_charpos, -1, -1, -1, MOVE_TO_POS);
       it->vpos -= it2.vpos;
@@ -8423,12 +8668,18 @@ move_it_by_lines (struct it *it, int dvpos)
       if (it2.vpos > -dvpos)
        {
          int delta = it2.vpos + dvpos;
-         it2 = *it;
+
+         RESTORE_IT (&it2, &it2, it2data);
+         SAVE_IT (it2, *it, it2data);
          move_it_to (it, -1, -1, -1, it->vpos + delta, MOVE_TO_VPOS);
          /* Move back again if we got too far ahead.  */
          if (IT_CHARPOS (*it) >= start_charpos)
-           *it = it2;
+           RESTORE_IT (it, &it2, it2data);
+         else
+           xfree (it2data);
        }
+      else
+       RESTORE_IT (it, it, it2data);
     }
 }
 
@@ -8589,7 +8840,7 @@ message_dolog (const char *m, EMACS_INT nbytes, int nlflag, int multibyte)
       if (nlflag)
        {
          EMACS_INT this_bol, this_bol_byte, prev_bol, prev_bol_byte;
-         unsigned long int dups;
+         printmax_t dups;
          insert_1 ("\n", 1, 1, 0, 0);
 
          scan_newline (Z, Z_BYTE, BEG, BEG_BYTE, -2, 0);
@@ -8612,12 +8863,13 @@ message_dolog (const char *m, EMACS_INT nbytes, int nlflag, int multibyte)
                                  this_bol, this_bol_byte, 0);
                  if (dups > 1)
                    {
-                     char dupstr[40];
+                     char dupstr[sizeof " [ times]"
+                                 + INT_STRLEN_BOUND (printmax_t)];
                      int duplen;
 
                      /* If you change this format, don't forget to also
                         change message_log_check_duplicate.  */
-                     sprintf (dupstr, " [%lu times]", dups);
+                     sprintf (dupstr, " [%"pMd" times]", dups);
                      duplen = strlen (dupstr);
                      TEMP_SET_PT_BOTH (Z - 1, Z_BYTE - 1);
                      insert_1 (dupstr, duplen, 1, 0, 1);
@@ -8679,7 +8931,7 @@ message_dolog (const char *m, EMACS_INT nbytes, int nlflag, int multibyte)
    Return 0 if different, 1 if the new one should just replace it, or a
    value N > 1 if we should also append " [N times]".  */
 
-static unsigned long int
+static intmax_t
 message_log_check_duplicate (EMACS_INT prev_bol_byte, EMACS_INT this_bol_byte)
 {
   EMACS_INT i;
@@ -8701,8 +8953,8 @@ message_log_check_duplicate (EMACS_INT prev_bol_byte, EMACS_INT this_bol_byte)
   if (*p1++ == ' ' && *p1++ == '[')
     {
       char *pend;
-      unsigned long int n = strtoul ((char *) p1, &pend, 10);
-      if (strncmp (pend, " times]\n", 8) == 0)
+      intmax_t n = strtoimax ((char *) p1, &pend, 10);
+      if (0 < n && n < INTMAX_MAX && strncmp (pend, " times]\n", 8) == 0)
        return n+1;
     }
   return 0;
@@ -9010,7 +9262,7 @@ vmessage (const char *m, va_list ap)
        {
          if (m)
            {
-             size_t len;
+             ptrdiff_t len;
 
              len = doprnt (FRAME_MESSAGE_BUF (f),
                            FRAME_MESSAGE_BUF_SIZE (f), m, (char *)0, ap);
@@ -10135,8 +10387,12 @@ store_mode_line_noprop_char (char c)
      double the buffer's size.  */
   if (mode_line_noprop_ptr == mode_line_noprop_buf_end)
     {
-      int len = MODE_LINE_NOPROP_LEN (0);
-      int new_size = 2 * len * sizeof *mode_line_noprop_buf;
+      ptrdiff_t len = MODE_LINE_NOPROP_LEN (0);
+      ptrdiff_t new_size;
+
+      if (STRING_BYTES_BOUND / 2 < len)
+       memory_full (SIZE_MAX);
+      new_size = 2 * len;
       mode_line_noprop_buf = (char *) xrealloc (mode_line_noprop_buf, new_size);
       mode_line_noprop_buf_end = mode_line_noprop_buf + new_size;
       mode_line_noprop_ptr = mode_line_noprop_buf + len;
@@ -10200,9 +10456,9 @@ x_consider_frame_title (Lisp_Object frame)
       /* Do we have more than one visible frame on this X display?  */
       Lisp_Object tail;
       Lisp_Object fmt;
-      int title_start;
+      ptrdiff_t title_start;
       char *title;
-      int len;
+      ptrdiff_t len;
       struct it it;
       int count = SPECPDL_INDEX ();
 
@@ -11031,7 +11287,7 @@ DEFUN ("tool-bar-lines-needed", Ftool_bar_lines_needed, Stool_bar_lines_needed,
   f = XFRAME (frame);
 
   if (WINDOWP (f->tool_bar_window)
-      || (w = XWINDOW (f->tool_bar_window),
+      && (w = XWINDOW (f->tool_bar_window),
          WINDOW_TOTAL_LINES (w) > 0))
     {
       update_tool_bar (f, 1);
@@ -11635,40 +11891,42 @@ hscroll_windows (Lisp_Object window)
 
 /* First and last unchanged row for try_window_id.  */
 
-int debug_first_unchanged_at_end_vpos;
-int debug_last_unchanged_at_beg_vpos;
+static int debug_first_unchanged_at_end_vpos;
+static int debug_last_unchanged_at_beg_vpos;
 
 /* Delta vpos and y.  */
 
-int debug_dvpos, debug_dy;
+static int debug_dvpos, debug_dy;
 
 /* Delta in characters and bytes for try_window_id.  */
 
-EMACS_INT debug_delta, debug_delta_bytes;
+static EMACS_INT debug_delta, debug_delta_bytes;
 
 /* Values of window_end_pos and window_end_vpos at the end of
    try_window_id.  */
 
-EMACS_INT debug_end_vpos;
+static EMACS_INT debug_end_vpos;
 
 /* Append a string to W->desired_matrix->method.  FMT is a printf
-   format string.  A1...A9 are a supplement for a variable-length
-   argument list.  If trace_redisplay_p is non-zero also printf the
+   format string.  If trace_redisplay_p is non-zero also printf the
    resulting string to stderr.  */
 
+static void debug_method_add (struct window *, char const *, ...)
+  ATTRIBUTE_FORMAT_PRINTF (2, 3);
+
 static void
-debug_method_add (w, fmt, a1, a2, a3, a4, a5, a6, a7, a8, a9)
-     struct window *w;
-     char *fmt;
-     int a1, a2, a3, a4, a5, a6, a7, a8, a9;
+debug_method_add (struct window *w, char const *fmt, ...)
 {
   char buffer[512];
   char *method = w->desired_matrix->method;
   int len = strlen (method);
   int size = sizeof w->desired_matrix->method;
   int remaining = size - len - 1;
+  va_list ap;
 
-  sprintf (buffer, fmt, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+  va_start (ap, fmt);
+  vsprintf (buffer, fmt, ap);
+  va_end (ap);
   if (len && remaining)
     {
       method[len] = '|';
@@ -11681,8 +11939,8 @@ debug_method_add (w, fmt, a1, a2, a3, a4, a5, a6, a7, a8, a9)
     fprintf (stderr, "%p (%s): %s\n",
             w,
             ((BUFFERP (w->buffer)
-              && STRINGP (XBUFFER (w->buffer)->name))
-             ? SSDATA (XBUFFER (w->buffer)->name)
+              && STRINGP (BVAR (XBUFFER (w->buffer), name)))
+             ? SSDATA (BVAR (XBUFFER (w->buffer), name))
              : "no buffer"),
             buffer);
 }
@@ -11695,7 +11953,7 @@ debug_method_add (w, fmt, a1, a2, a3, a4, a5, a6, a7, a8, a9)
    buffer position, END is given as a distance from Z.  Used in
    redisplay_internal for display optimization.  */
 
-static INLINE int
+static inline int
 text_outside_line_unchanged_p (struct window *w,
                               EMACS_INT start, EMACS_INT end)
 {
@@ -11956,7 +12214,7 @@ check_point_in_composition (struct buffer *prev_buf, EMACS_INT prev_pt,
 /* Reconsider the setting of B->clip_changed which is displayed
    in window W.  */
 
-static INLINE void
+static inline void
 reconsider_clip_changes (struct window *w, struct buffer *b)
 {
   if (b->clip_changed
@@ -13536,7 +13794,7 @@ set_cursor_from_row (struct window *w, struct glyph_row *row,
 
    We assume that the window's buffer is really current.  */
 
-static INLINE struct text_pos
+static inline struct text_pos
 run_window_scroll_functions (Lisp_Object window, struct text_pos startp)
 {
   struct window *w = XWINDOW (window);
@@ -13773,14 +14031,18 @@ try_scrolling (Lisp_Object window, int just_this_one_p,
             which was computed as distance from window bottom to
             point.  This matters when lines at window top and lines
             below window bottom have different height.  */
-         struct it it1 = it;
+         struct it it1;
+         void *it1data = NULL;
          /* We use a temporary it1 because line_bottom_y can modify
             its argument, if it moves one line down; see there.  */
-         int start_y = line_bottom_y (&it1);
+         int start_y;
 
+         SAVE_IT (it1, it, it1data);
+         start_y = line_bottom_y (&it1);
          do {
+           RESTORE_IT (&it, &it, it1data);
            move_it_by_lines (&it, 1);
-           it1 = it;
+           SAVE_IT (it1, it, it1data);
          } while (line_bottom_y (&it1) - start_y < amount_to_scroll);
        }
 
@@ -14888,10 +15150,13 @@ redisplay_window (Lisp_Object window, int just_this_one_p)
          && BEGV <= CHARPOS (startp) && CHARPOS (startp) <= ZV)
        {
          struct it it1;
+         void *it1data = NULL;
 
+         SAVE_IT (it1, it, it1data);
          start_display (&it1, w, startp);
          move_it_vertically (&it1, margin);
          margin_pos = IT_CHARPOS (it1);
+         RESTORE_IT (&it, &it, it1data);
        }
       scrolling_up = PT > margin_pos;
       aggressive =
@@ -15482,7 +15747,8 @@ try_window_reusing_current_matrix (struct window *w)
                row->visible_height -= min_y - row->y;
              if (row->y + row->height > max_y)
                row->visible_height -= row->y + row->height - max_y;
-             row->redraw_fringe_bitmaps_p = 1;
+             if (row->fringe_bitmap_periodic_p)
+               row->redraw_fringe_bitmaps_p = 1;
 
              it.current_y += row->height;
 
@@ -15644,7 +15910,8 @@ try_window_reusing_current_matrix (struct window *w)
            row->visible_height -= min_y - row->y;
          if (row->y + row->height > max_y)
            row->visible_height -= row->y + row->height - max_y;
-         row->redraw_fringe_bitmaps_p = 1;
+         if (row->fringe_bitmap_periodic_p)
+           row->redraw_fringe_bitmaps_p = 1;
        }
 
       /* Scroll the current matrix.  */
@@ -16797,9 +17064,9 @@ try_window_id (struct window *w)
 
 #if GLYPH_DEBUG
 
-void dump_glyph_row (struct glyph_row *, int, int);
-void dump_glyph_matrix (struct glyph_matrix *, int);
-void dump_glyph (struct glyph_row *, struct glyph *, int);
+void dump_glyph_row (struct glyph_row *, int, int) EXTERNALLY_VISIBLE;
+void dump_glyph_matrix (struct glyph_matrix *, int) EXTERNALLY_VISIBLE;
+void dump_glyph (struct glyph_row *, struct glyph *, int) EXTERNALLY_VISIBLE;
 
 
 /* Dump the contents of glyph matrix MATRIX on stderr.
@@ -16809,9 +17076,7 @@ void dump_glyph (struct glyph_row *, struct glyph *, int);
    GLYPHS > 1 means show glyphs in long form.  */
 
 void
-dump_glyph_matrix (matrix, glyphs)
-     struct glyph_matrix *matrix;
-     int glyphs;
+dump_glyph_matrix (struct glyph_matrix *matrix, int glyphs)
 {
   int i;
   for (i = 0; i < matrix->nrows; ++i)
@@ -16823,15 +17088,12 @@ dump_glyph_matrix (matrix, glyphs)
    the glyph row and area where the glyph comes from.  */
 
 void
-dump_glyph (row, glyph, area)
-     struct glyph_row *row;
-     struct glyph *glyph;
-     int area;
+dump_glyph (struct glyph_row *row, struct glyph *glyph, int area)
 {
   if (glyph->type == CHAR_GLYPH)
     {
       fprintf (stderr,
-              "  %5d %4c %6d %c %3d 0x%05x %c %4d %1.1d%1.1d\n",
+              "  %5td %4c %6"pI"d %c %3d 0x%05x %c %4d %1.1d%1.1d\n",
               glyph - row->glyphs[TEXT_AREA],
               'C',
               glyph->charpos,
@@ -16852,7 +17114,7 @@ dump_glyph (row, glyph, area)
   else if (glyph->type == STRETCH_GLYPH)
     {
       fprintf (stderr,
-              "  %5d %4c %6d %c %3d 0x%05x %c %4d %1.1d%1.1d\n",
+              "  %5td %4c %6"pI"d %c %3d 0x%05x %c %4d %1.1d%1.1d\n",
               glyph - row->glyphs[TEXT_AREA],
               'S',
               glyph->charpos,
@@ -16871,7 +17133,7 @@ dump_glyph (row, glyph, area)
   else if (glyph->type == IMAGE_GLYPH)
     {
       fprintf (stderr,
-              "  %5d %4c %6d %c %3d 0x%05x %c %4d %1.1d%1.1d\n",
+              "  %5td %4c %6"pI"d %c %3d 0x%05x %c %4d %1.1d%1.1d\n",
               glyph - row->glyphs[TEXT_AREA],
               'I',
               glyph->charpos,
@@ -16890,7 +17152,7 @@ dump_glyph (row, glyph, area)
   else if (glyph->type == COMPOSITE_GLYPH)
     {
       fprintf (stderr,
-              "  %5d %4c %6d %c %3d 0x%05x",
+              "  %5td %4c %6"pI"d %c %3d 0x%05x",
               glyph - row->glyphs[TEXT_AREA],
               '+',
               glyph->charpos,
@@ -16919,16 +17181,14 @@ dump_glyph (row, glyph, area)
    GLYPHS > 1 means show glyphs in long form.  */
 
 void
-dump_glyph_row (row, vpos, glyphs)
-     struct glyph_row *row;
-     int vpos, glyphs;
+dump_glyph_row (struct glyph_row *row, int vpos, int glyphs)
 {
   if (glyphs != 1)
     {
       fprintf (stderr, "Row Start   End Used oE><\\CTZFesm     X    Y    W    H    V    A    P\n");
       fprintf (stderr, "======================================================================\n");
 
-      fprintf (stderr, "%3d %5d %5d %4d %1.1d%1.1d%1.1d%1.1d\
+      fprintf (stderr, "%3d %5"pI"d %5"pI"d %4d %1.1d%1.1d%1.1d%1.1d\
 %1.1d%1.1d%1.1d%1.1d%1.1d%1.1d%1.1d%1.1d  %4d %4d %4d %4d %4d %4d %4d\n",
               vpos,
               MATRIX_ROW_START_CHARPOS (row),
@@ -16956,7 +17216,7 @@ dump_glyph_row (row, vpos, glyphs)
       fprintf (stderr, "%9d %5d\t%5d\n", row->start.overlay_string_index,
               row->end.overlay_string_index,
               row->continuation_lines_width);
-      fprintf (stderr, "%9d %5d\n",
+      fprintf (stderr, "%9"pI"d %5"pI"d\n",
               CHARPOS (row->start.string_pos),
               CHARPOS (row->end.string_pos));
       fprintf (stderr, "%9d %5d\n", row->start.dpvec_index,
@@ -17021,7 +17281,7 @@ glyphs in short form, otherwise show glyphs in long form.  */)
   struct window *w = XWINDOW (selected_window);
   struct buffer *buffer = XBUFFER (w->buffer);
 
-  fprintf (stderr, "PT = %d, BEGV = %d. ZV = %d\n",
+  fprintf (stderr, "PT = %"pI"d, BEGV = %"pI"d. ZV = %"pI"d\n",
           BUF_PT (buffer), BUF_BEGV (buffer), BUF_ZV (buffer));
   fprintf (stderr, "Cursor x = %d, y = %d, hpos = %d, vpos = %d\n",
           w->cursor.x, w->cursor.y, w->cursor.hpos, w->cursor.vpos);
@@ -17103,7 +17363,7 @@ With ARG, turn tracing on if and only if ARG is positive.  */)
 DEFUN ("trace-to-stderr", Ftrace_to_stderr, Strace_to_stderr, 1, MANY, "",
        doc: /* Like `format', but print result to stderr.
 usage: (trace-to-stderr STRING &rest OBJECTS)  */)
-  (size_t nargs, Lisp_Object *args)
+  (ptrdiff_t nargs, Lisp_Object *args)
 {
   Lisp_Object s = Fformat (nargs, args);
   fprintf (stderr, "%s", SDATA (s));
@@ -17908,12 +18168,13 @@ find_row_edges (struct it *it, struct glyph_row *row,
      lines' rows is implemented for bidi-reordered rows.  */
 
   /* ROW->minpos is the value of min_pos, the minimal buffer position
-     we have in ROW.  */
-  if (min_pos <= ZV)
+     we have in ROW, or ROW->start.pos if that is smaller.  */
+  if (min_pos <= ZV && min_pos < row->start.pos.charpos)
     SET_TEXT_POS (row->minpos, min_pos, min_bpos);
   else
-    /* We didn't find _any_ valid buffer positions in any of the
-       glyphs, so we must trust the iterator's computed positions.  */
+    /* We didn't find buffer positions smaller than ROW->start, or
+       didn't find _any_ valid buffer positions in any of the glyphs,
+       so we must trust the iterator's computed positions.  */
       row->minpos = row->start.pos;
   if (max_pos <= 0)
     {
@@ -17988,6 +18249,7 @@ display_line (struct it *it)
   struct glyph_row *row = it->glyph_row;
   Lisp_Object overlay_arrow_string;
   struct it wrap_it;
+  void *wrap_data = NULL;
   int may_wrap = 0, wrap_x IF_LINT (= 0);
   int wrap_row_used = -1;
   int wrap_row_ascent IF_LINT (= 0), wrap_row_height IF_LINT (= 0);
@@ -18142,7 +18404,7 @@ display_line (struct it *it)
                may_wrap = 1;
              else if (may_wrap)
                {
-                 wrap_it = *it;
+                 SAVE_IT (wrap_it, *it, wrap_data);
                  wrap_x = x;
                  wrap_row_used = row->used[TEXT_AREA];
                  wrap_row_ascent = row->ascent;
@@ -18312,7 +18574,7 @@ display_line (struct it *it)
                      if (row->reversed_p)
                        unproduce_glyphs (it,
                                          row->used[TEXT_AREA] - wrap_row_used);
-                     *it = wrap_it;
+                     RESTORE_IT (it, &wrap_it, wrap_data);
                      it->continuation_lines_width += wrap_x;
                      row->used[TEXT_AREA] = wrap_row_used;
                      row->ascent = wrap_row_ascent;
@@ -19306,8 +19568,7 @@ display_mode_element (struct it *it, int depth, int field_width, int precision,
                        break;
                      case MODE_LINE_STRING:
                        {
-                         int len = strlen (spec);
-                         Lisp_Object tem = make_string (spec, len);
+                         Lisp_Object tem = build_string (spec);
                          props = Ftext_properties_at (make_number (charpos), elt);
                          /* Should only keep face property in props */
                          n += store_mode_line_string (NULL, tem, 0, field, prec, props);
@@ -19950,7 +20211,8 @@ decode_mode_spec_coding (Lisp_Object coding_system, register char *buf, int eol_
       else if (CHARACTERP (eoltype))
        {
          unsigned char *tmp = (unsigned char *) alloca (MAX_MULTIBYTE_LENGTH);
-         eol_str_len = CHAR_STRING (XINT (eoltype), tmp);
+         int c = XFASTINT (eoltype);
+         eol_str_len = CHAR_STRING (c, tmp);
          eol_str = tmp;
        }
       else
@@ -21007,7 +21269,7 @@ calc_pixel_width_or_height (double *res, struct it *it, Lisp_Object prop,
          if (FRAME_WINDOW_P (it->f)
              && valid_image_p (prop))
            {
-             int id = lookup_image (it->f, prop);
+             ptrdiff_t id = lookup_image (it->f, prop);
              struct image *img = IMAGE_FROM_ID (it->f, id);
 
              return OK_PIXELS (width_p ? img->width : img->height);
@@ -21066,8 +21328,7 @@ calc_pixel_width_or_height (double *res, struct it *it, Lisp_Object prop,
 #if GLYPH_DEBUG
 
 void
-dump_glyph_string (s)
-     struct glyph_string *s;
+dump_glyph_string (struct glyph_string *s)
 {
   fprintf (stderr, "glyph string\n");
   fprintf (stderr, "  x, y, w, h = %d, %d, %d, %d\n",
@@ -21135,7 +21396,7 @@ init_glyph_string (struct glyph_string *s,
 /* Append the list of glyph strings with head H and tail T to the list
    with head *HEAD and tail *TAIL.  Set *HEAD and *TAIL to the result.  */
 
-static INLINE void
+static inline void
 append_glyph_string_lists (struct glyph_string **head, struct glyph_string **tail,
                           struct glyph_string *h, struct glyph_string *t)
 {
@@ -21155,7 +21416,7 @@ append_glyph_string_lists (struct glyph_string **head, struct glyph_string **tai
    list with head *HEAD and tail *TAIL.  Set *HEAD and *TAIL to the
    result.  */
 
-static INLINE void
+static inline void
 prepend_glyph_string_lists (struct glyph_string **head, struct glyph_string **tail,
                            struct glyph_string *h, struct glyph_string *t)
 {
@@ -21174,7 +21435,7 @@ prepend_glyph_string_lists (struct glyph_string **head, struct glyph_string **ta
 /* Append glyph string S to the list with head *HEAD and tail *TAIL.
    Set *HEAD and *TAIL to the resulting list.  */
 
-static INLINE void
+static inline void
 append_glyph_string (struct glyph_string **head, struct glyph_string **tail,
                     struct glyph_string *s)
 {
@@ -21189,7 +21450,7 @@ append_glyph_string (struct glyph_string **head, struct glyph_string **tail,
    Value is a pointer to a realized face that is ready for display if
    DISPLAY_P is non-zero.  */
 
-static INLINE struct face *
+static inline struct face *
 get_char_face_and_encoding (struct frame *f, int c, int face_id,
                            XChar2b *char2b, int display_p)
 {
@@ -21222,7 +21483,7 @@ get_char_face_and_encoding (struct frame *f, int c, int face_id,
    The encoding of GLYPH->u.ch is returned in *CHAR2B.  Value is
    a pointer to a realized face that is ready for display.  */
 
-static INLINE struct face *
+static inline struct face *
 get_glyph_face_and_encoding (struct frame *f, struct glyph *glyph,
                             XChar2b *char2b, int *two_byte_p)
 {
@@ -21259,7 +21520,7 @@ get_glyph_face_and_encoding (struct frame *f, struct glyph *glyph,
 /* Get glyph code of character C in FONT in the two-byte form CHAR2B.
    Retunr 1 if FONT has a glyph for C, otherwise return 0.  */
 
-static INLINE int
+static inline int
 get_char_glyph_code (int c, struct font *font, XChar2b *char2b)
 {
   unsigned code;
@@ -21723,7 +21984,7 @@ right_overwriting (struct glyph_string *s)
    first glyph following S.  LAST_X is the right-most x-position + 1
    in the drawing area.  */
 
-static INLINE void
+static inline void
 set_glyph_string_background_width (struct glyph_string *s, int start, int last_x)
 {
   /* If the face of this glyph string has to be drawn to the end of
@@ -21880,7 +22141,7 @@ compute_overhangs_and_x (struct glyph_string *s, int x, int backward_p)
   do {                                                                     \
     int face_id = (row)->glyphs[area][START].face_id;                      \
     struct face *base_face = FACE_FROM_ID (f, face_id);                            \
-    int cmp_id = (row)->glyphs[area][START].u.cmp.id;                      \
+    ptrdiff_t cmp_id = (row)->glyphs[area][START].u.cmp.id;                \
     struct composition *cmp = composition_table[cmp_id];                   \
     XChar2b *char2b;                                                       \
     struct glyph_string *first_s IF_LINT (= NULL);                         \
@@ -22285,7 +22546,7 @@ draw_glyphs (struct window *w, int x, struct glyph_row *row,
 /* Store one glyph for IT->char_to_display in IT->glyph_row.
    Called from x_produce_glyphs when IT->glyph_row is non-null.  */
 
-static INLINE void
+static inline void
 append_glyph (struct it *it)
 {
   struct glyph *glyph;
@@ -22359,7 +22620,7 @@ append_glyph (struct it *it)
    IT->glyph_row.  Called from x_produce_glyphs when IT->glyph_row is
    non-null.  */
 
-static INLINE void
+static inline void
 append_composite_glyph (struct it *it)
 {
   struct glyph *glyph;
@@ -22428,7 +22689,7 @@ append_composite_glyph (struct it *it)
 /* Change IT->ascent and IT->height according to the setting of
    IT->voffset.  */
 
-static INLINE void
+static inline void
 take_vertical_position_into_account (struct it *it)
 {
   if (it->voffset)
@@ -23001,7 +23262,7 @@ produce_glyphless_glyph (struct it *it, int for_no_font, Lisp_Object acronym)
   base_width = font->average_width;
 
   /* Get a face ID for the glyph by utilizing a cache (the same way as
-     doen for `escape-glyph' in get_next_display_element).  */
+     done for `escape-glyph' in get_next_display_element).  */
   if (it->f == last_glyphless_glyph_frame
       && it->face_id == last_glyphless_glyph_face_id)
     {
@@ -24904,7 +25165,7 @@ rows_from_pos_range (struct window *w,
 
          while (g < e)
            {
-             if (BUFFERP (g->object)
+             if ((BUFFERP (g->object) || INTEGERP (g->object))
                  && start_charpos <= g->charpos && g->charpos < end_charpos)
                *start = row;
              g++;
@@ -24954,7 +25215,7 @@ rows_from_pos_range (struct window *w,
 
          while (g < e)
            {
-             if (BUFFERP (g->object)
+             if ((BUFFERP (g->object) || INTEGERP (g->object))
                  && start_charpos <= g->charpos && g->charpos < end_charpos)
                break;
              g++;
@@ -26057,13 +26318,13 @@ note_mouse_highlight (struct frame *f, int x, int y)
       && XFASTINT (w->last_modified) == BUF_MODIFF (b)
       && XFASTINT (w->last_overlay_modified) == BUF_OVERLAY_MODIFF (b))
     {
-      int hpos, vpos, i, dx, dy, area;
+      int hpos, vpos, dx, dy, area;
       EMACS_INT pos;
       struct glyph *glyph;
       Lisp_Object object;
       Lisp_Object mouse_face = Qnil, position;
       Lisp_Object *overlay_vec = NULL;
-      int noverlays;
+      ptrdiff_t i, noverlays;
       struct buffer *obuf;
       EMACS_INT obegv, ozv;
       int same_region;
@@ -26986,7 +27247,7 @@ x_intersect_rectangles (XRectangle *r1, XRectangle *r2, XRectangle *result)
     {
       result->x = right->x;
 
-      /* The right end of the intersection is the minimum of the
+      /* The right end of the intersection is the minimum of
         the right ends of left and right.  */
       result->width = (min (left->x + left->width, right->x + right->width)
                       - result->x);
@@ -27031,8 +27292,7 @@ syms_of_xdisp (void)
   Vmessage_stack = Qnil;
   staticpro (&Vmessage_stack);
 
-  Qinhibit_redisplay = intern_c_string ("inhibit-redisplay");
-  staticpro (&Qinhibit_redisplay);
+  DEFSYM (Qinhibit_redisplay, "inhibit-redisplay");
 
   message_dolog_marker1 = Fmake_marker ();
   staticpro (&message_dolog_marker1);
@@ -27057,141 +27317,72 @@ syms_of_xdisp (void)
   defsubr (&Sinvisible_p);
   defsubr (&Scurrent_bidi_paragraph_direction);
 
-  staticpro (&Qmenu_bar_update_hook);
-  Qmenu_bar_update_hook = intern_c_string ("menu-bar-update-hook");
-
-  staticpro (&Qoverriding_terminal_local_map);
-  Qoverriding_terminal_local_map = intern_c_string ("overriding-terminal-local-map");
-
-  staticpro (&Qoverriding_local_map);
-  Qoverriding_local_map = intern_c_string ("overriding-local-map");
-
-  staticpro (&Qwindow_scroll_functions);
-  Qwindow_scroll_functions = intern_c_string ("window-scroll-functions");
-
-  staticpro (&Qwindow_text_change_functions);
-  Qwindow_text_change_functions = intern_c_string ("window-text-change-functions");
-
-  staticpro (&Qredisplay_end_trigger_functions);
-  Qredisplay_end_trigger_functions = intern_c_string ("redisplay-end-trigger-functions");
-
-  staticpro (&Qinhibit_point_motion_hooks);
-  Qinhibit_point_motion_hooks = intern_c_string ("inhibit-point-motion-hooks");
-
-  Qeval = intern_c_string ("eval");
-  staticpro (&Qeval);
-
-  QCdata = intern_c_string (":data");
-  staticpro (&QCdata);
-  Qdisplay = intern_c_string ("display");
-  staticpro (&Qdisplay);
-  Qspace_width = intern_c_string ("space-width");
-  staticpro (&Qspace_width);
-  Qraise = intern_c_string ("raise");
-  staticpro (&Qraise);
-  Qslice = intern_c_string ("slice");
-  staticpro (&Qslice);
-  Qspace = intern_c_string ("space");
-  staticpro (&Qspace);
-  Qmargin = intern_c_string ("margin");
-  staticpro (&Qmargin);
-  Qpointer = intern_c_string ("pointer");
-  staticpro (&Qpointer);
-  Qleft_margin = intern_c_string ("left-margin");
-  staticpro (&Qleft_margin);
-  Qright_margin = intern_c_string ("right-margin");
-  staticpro (&Qright_margin);
-  Qcenter = intern_c_string ("center");
-  staticpro (&Qcenter);
-  Qline_height = intern_c_string ("line-height");
-  staticpro (&Qline_height);
-  QCalign_to = intern_c_string (":align-to");
-  staticpro (&QCalign_to);
-  QCrelative_width = intern_c_string (":relative-width");
-  staticpro (&QCrelative_width);
-  QCrelative_height = intern_c_string (":relative-height");
-  staticpro (&QCrelative_height);
-  QCeval = intern_c_string (":eval");
-  staticpro (&QCeval);
-  QCpropertize = intern_c_string (":propertize");
-  staticpro (&QCpropertize);
-  QCfile = intern_c_string (":file");
-  staticpro (&QCfile);
-  Qfontified = intern_c_string ("fontified");
-  staticpro (&Qfontified);
-  Qfontification_functions = intern_c_string ("fontification-functions");
-  staticpro (&Qfontification_functions);
-  Qtrailing_whitespace = intern_c_string ("trailing-whitespace");
-  staticpro (&Qtrailing_whitespace);
-  Qescape_glyph = intern_c_string ("escape-glyph");
-  staticpro (&Qescape_glyph);
-  Qnobreak_space = intern_c_string ("nobreak-space");
-  staticpro (&Qnobreak_space);
-  Qimage = intern_c_string ("image");
-  staticpro (&Qimage);
-  Qtext = intern_c_string ("text");
-  staticpro (&Qtext);
-  Qboth = intern_c_string ("both");
-  staticpro (&Qboth);
-  Qboth_horiz = intern_c_string ("both-horiz");
-  staticpro (&Qboth_horiz);
-  Qtext_image_horiz = intern_c_string ("text-image-horiz");
-  staticpro (&Qtext_image_horiz);
-  QCmap = intern_c_string (":map");
-  staticpro (&QCmap);
-  QCpointer = intern_c_string (":pointer");
-  staticpro (&QCpointer);
-  Qrect = intern_c_string ("rect");
-  staticpro (&Qrect);
-  Qcircle = intern_c_string ("circle");
-  staticpro (&Qcircle);
-  Qpoly = intern_c_string ("poly");
-  staticpro (&Qpoly);
-  Qmessage_truncate_lines = intern_c_string ("message-truncate-lines");
-  staticpro (&Qmessage_truncate_lines);
-  Qgrow_only = intern_c_string ("grow-only");
-  staticpro (&Qgrow_only);
-  Qinhibit_menubar_update = intern_c_string ("inhibit-menubar-update");
-  staticpro (&Qinhibit_menubar_update);
-  Qinhibit_eval_during_redisplay = intern_c_string ("inhibit-eval-during-redisplay");
-  staticpro (&Qinhibit_eval_during_redisplay);
-  Qposition = intern_c_string ("position");
-  staticpro (&Qposition);
-  Qbuffer_position = intern_c_string ("buffer-position");
-  staticpro (&Qbuffer_position);
-  Qobject = intern_c_string ("object");
-  staticpro (&Qobject);
-  Qbar = intern_c_string ("bar");
-  staticpro (&Qbar);
-  Qhbar = intern_c_string ("hbar");
-  staticpro (&Qhbar);
-  Qbox = intern_c_string ("box");
-  staticpro (&Qbox);
-  Qhollow = intern_c_string ("hollow");
-  staticpro (&Qhollow);
-  Qhand = intern_c_string ("hand");
-  staticpro (&Qhand);
-  Qarrow = intern_c_string ("arrow");
-  staticpro (&Qarrow);
-  Qtext = intern_c_string ("text");
-  staticpro (&Qtext);
-  Qinhibit_free_realized_faces = intern_c_string ("inhibit-free-realized-faces");
-  staticpro (&Qinhibit_free_realized_faces);
+  DEFSYM (Qmenu_bar_update_hook, "menu-bar-update-hook");
+  DEFSYM (Qoverriding_terminal_local_map, "overriding-terminal-local-map");
+  DEFSYM (Qoverriding_local_map, "overriding-local-map");
+  DEFSYM (Qwindow_scroll_functions, "window-scroll-functions");
+  DEFSYM (Qwindow_text_change_functions, "window-text-change-functions");
+  DEFSYM (Qredisplay_end_trigger_functions, "redisplay-end-trigger-functions");
+  DEFSYM (Qinhibit_point_motion_hooks, "inhibit-point-motion-hooks");
+  DEFSYM (Qeval, "eval");
+  DEFSYM (QCdata, ":data");
+  DEFSYM (Qdisplay, "display");
+  DEFSYM (Qspace_width, "space-width");
+  DEFSYM (Qraise, "raise");
+  DEFSYM (Qslice, "slice");
+  DEFSYM (Qspace, "space");
+  DEFSYM (Qmargin, "margin");
+  DEFSYM (Qpointer, "pointer");
+  DEFSYM (Qleft_margin, "left-margin");
+  DEFSYM (Qright_margin, "right-margin");
+  DEFSYM (Qcenter, "center");
+  DEFSYM (Qline_height, "line-height");
+  DEFSYM (QCalign_to, ":align-to");
+  DEFSYM (QCrelative_width, ":relative-width");
+  DEFSYM (QCrelative_height, ":relative-height");
+  DEFSYM (QCeval, ":eval");
+  DEFSYM (QCpropertize, ":propertize");
+  DEFSYM (QCfile, ":file");
+  DEFSYM (Qfontified, "fontified");
+  DEFSYM (Qfontification_functions, "fontification-functions");
+  DEFSYM (Qtrailing_whitespace, "trailing-whitespace");
+  DEFSYM (Qescape_glyph, "escape-glyph");
+  DEFSYM (Qnobreak_space, "nobreak-space");
+  DEFSYM (Qimage, "image");
+  DEFSYM (Qtext, "text");
+  DEFSYM (Qboth, "both");
+  DEFSYM (Qboth_horiz, "both-horiz");
+  DEFSYM (Qtext_image_horiz, "text-image-horiz");
+  DEFSYM (QCmap, ":map");
+  DEFSYM (QCpointer, ":pointer");
+  DEFSYM (Qrect, "rect");
+  DEFSYM (Qcircle, "circle");
+  DEFSYM (Qpoly, "poly");
+  DEFSYM (Qmessage_truncate_lines, "message-truncate-lines");
+  DEFSYM (Qgrow_only, "grow-only");
+  DEFSYM (Qinhibit_menubar_update, "inhibit-menubar-update");
+  DEFSYM (Qinhibit_eval_during_redisplay, "inhibit-eval-during-redisplay");
+  DEFSYM (Qposition, "position");
+  DEFSYM (Qbuffer_position, "buffer-position");
+  DEFSYM (Qobject, "object");
+  DEFSYM (Qbar, "bar");
+  DEFSYM (Qhbar, "hbar");
+  DEFSYM (Qbox, "box");
+  DEFSYM (Qhollow, "hollow");
+  DEFSYM (Qhand, "hand");
+  DEFSYM (Qarrow, "arrow");
+  DEFSYM (Qtext, "text");
+  DEFSYM (Qinhibit_free_realized_faces, "inhibit-free-realized-faces");
 
   list_of_error = Fcons (Fcons (intern_c_string ("error"),
                                Fcons (intern_c_string ("void-variable"), Qnil)),
                         Qnil);
   staticpro (&list_of_error);
 
-  Qlast_arrow_position = intern_c_string ("last-arrow-position");
-  staticpro (&Qlast_arrow_position);
-  Qlast_arrow_string = intern_c_string ("last-arrow-string");
-  staticpro (&Qlast_arrow_string);
-
-  Qoverlay_arrow_string = intern_c_string ("overlay-arrow-string");
-  staticpro (&Qoverlay_arrow_string);
-  Qoverlay_arrow_bitmap = intern_c_string ("overlay-arrow-bitmap");
-  staticpro (&Qoverlay_arrow_bitmap);
+  DEFSYM (Qlast_arrow_position, "last-arrow-position");
+  DEFSYM (Qlast_arrow_string, "last-arrow-string");
+  DEFSYM (Qoverlay_arrow_string, "overlay-arrow-string");
+  DEFSYM (Qoverlay_arrow_bitmap, "overlay-arrow-bitmap");
 
   echo_buffer[0] = echo_buffer[1] = Qnil;
   staticpro (&echo_buffer[0]);
@@ -27225,10 +27416,8 @@ syms_of_xdisp (void)
   staticpro (&previous_help_echo_string);
   help_echo_pos = -1;
 
-  Qright_to_left = intern_c_string ("right-to-left");
-  staticpro (&Qright_to_left);
-  Qleft_to_right = intern_c_string ("left-to-right");
-  staticpro (&Qleft_to_right);
+  DEFSYM (Qright_to_left, "right-to-left");
+  DEFSYM (Qleft_to_right, "left-to-right");
 
 #ifdef HAVE_WINDOW_SYSTEM
   DEFVAR_BOOL ("x-stretch-cursor", x_stretch_cursor_p,
@@ -27517,18 +27706,18 @@ but does not change the fact they are interpreted as raw bytes.  */);
   unibyte_display_via_language_environment = 0;
 
   DEFVAR_LISP ("max-mini-window-height", Vmax_mini_window_height,
-    doc: /* *Maximum height for resizing mini-windows.
+    doc: /* *Maximum height for resizing mini-windows (the minibuffer and the echo area).
 If a float, it specifies a fraction of the mini-window frame's height.
 If an integer, it specifies a number of lines.  */);
   Vmax_mini_window_height = make_float (0.25);
 
   DEFVAR_LISP ("resize-mini-windows", Vresize_mini_windows,
-    doc: /* *How to resize mini-windows.
+    doc: /* How to resize mini-windows (the minibuffer and the echo area).
 A value of nil means don't automatically resize mini-windows.
 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, until their display becomes empty, at which point the windows
-go back to their normal size.  */);
+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;
 
   DEFVAR_LISP ("blink-cursor-alist", Vblink_cursor_alist,
@@ -27548,8 +27737,7 @@ the frame's other specifications determine how to blink the cursor off.  */);
 If non-nil, windows are automatically scrolled horizontally to make
 point visible.  */);
   automatic_hscrolling_p = 1;
-  Qauto_hscroll_mode = intern_c_string ("auto-hscroll-mode");
-  staticpro (&Qauto_hscroll_mode);
+  DEFSYM (Qauto_hscroll_mode, "auto-hscroll-mode");
 
   DEFVAR_INT ("hscroll-margin", hscroll_margin,
     doc: /* *How many columns away from the window edge point is allowed to get
@@ -27605,8 +27793,7 @@ property.
 
 To add a prefix to non-continuation lines, use `line-prefix'.  */);
   Vwrap_prefix = Qnil;
-  staticpro (&Qwrap_prefix);
-  Qwrap_prefix = intern_c_string ("wrap-prefix");
+  DEFSYM (Qwrap_prefix, "wrap-prefix");
   Fmake_variable_buffer_local (Qwrap_prefix);
 
   DEFVAR_LISP ("line-prefix", Vline_prefix,
@@ -27619,8 +27806,7 @@ property.
 
 To add a prefix to continuation lines, use `wrap-prefix'.  */);
   Vline_prefix = Qnil;
-  staticpro (&Qline_prefix);
-  Qline_prefix = intern_c_string ("line-prefix");
+  DEFSYM (Qline_prefix, "line-prefix");
   Fmake_variable_buffer_local (Qline_prefix);
 
   DEFVAR_BOOL ("inhibit-eval-during-redisplay", inhibit_eval_during_redisplay,
@@ -27713,31 +27899,27 @@ Its value should be an ASCII acronym string, `hex-code', `empty-box', or
 void
 init_xdisp (void)
 {
-  Lisp_Object root_window;
-  struct window *mini_w;
-
   current_header_line_height = current_mode_line_height = -1;
 
   CHARPOS (this_line_start_pos) = 0;
 
-  mini_w = XWINDOW (minibuf_window);
-  root_window = FRAME_ROOT_WINDOW (XFRAME (WINDOW_FRAME (mini_w)));
-  echo_area_window = minibuf_window;
-
   if (!noninteractive)
     {
-      struct frame *f = XFRAME (WINDOW_FRAME (XWINDOW (root_window)));
+      struct window *m = XWINDOW (minibuf_window);
+      Lisp_Object frame = m->frame;
+      struct frame *f = XFRAME (frame);
+      Lisp_Object root = FRAME_ROOT_WINDOW (f);
+      struct window *r = XWINDOW (root);
       int i;
 
-      XWINDOW (root_window)->top_line = make_number (FRAME_TOP_MARGIN (f));
-      set_window_height (root_window,
-                        FRAME_LINES (f) - 1 - FRAME_TOP_MARGIN (f),
-                        0);
-      mini_w->top_line = make_number (FRAME_LINES (f) - 1);
-      set_window_height (minibuf_window, 1, 0);
+      echo_area_window = minibuf_window;
 
-      XWINDOW (root_window)->total_cols = make_number (FRAME_COLS (f));
-      mini_w->total_cols = make_number (FRAME_COLS (f));
+      XSETFASTINT (r->top_line, FRAME_TOP_MARGIN (f));
+      XSETFASTINT (r->total_lines, FRAME_LINES (f) - 1 - FRAME_TOP_MARGIN (f));
+      XSETFASTINT (r->total_cols, FRAME_COLS (f));
+      XSETFASTINT (m->top_line, FRAME_LINES (f) - 1);
+      XSETFASTINT (m->total_lines, 1);
+      XSETFASTINT (m->total_cols, FRAME_COLS (f));
 
       scratch_glyph_row.glyphs[TEXT_AREA] = scratch_glyphs;
       scratch_glyph_row.glyphs[TEXT_AREA + 1]