Initial reimplementation of calculating line edge positions in bidi lines.
authorEli Zaretskii <eliz@gnu.org>
Tue, 18 May 2010 15:22:15 +0000 (18:22 +0300)
committerEli Zaretskii <eliz@gnu.org>
Tue, 18 May 2010 15:22:15 +0000 (18:22 +0300)
 dispextern.h (struct glyph_row): New members minpos and maxpos.
 (MATRIX_ROW_START_CHARPOS, MATRIX_ROW_START_BYTEPOS)
 (MATRIX_ROW_END_CHARPOS, MATRIX_ROW_END_BYTEPOS): Reference minpos
 and maxpos members instead of start.pos and end.pos, respectively.
 xdisp.c (display_line): Compare IT_CHARPOS with the position in
 row->start.pos, rather than with MATRIX_ROW_START_CHARPOS.
 (cursor_row_p): Use row->end.pos rather than MATRIX_ROW_END_CHARPOS.
 (try_window_reusing_current_matrix, try_window_id): Use
 ROW->minpos rather than ROW->start.pos.
 (init_from_display_pos, init_iterator): Use EMACS_INT for
 character and byte positions.
 (find_row_edges): Renamed from find_row_end.  Accept additional
 arguments for minimum and maximum buffer positions seen by
 display_line for this row.  Don't use iterator to find the
 position following the maximum one; instead, increment the
 position found by display_line directly.
 (display_line): Record minimum and maximum buffer positions for
 glyphs in this row.  Record the position of the newline that
 terminates the line.
 dispnew.c (increment_row_positions, check_matrix_invariants):
 Increment and check row->start.pos and row->end.pos, in addition
 to MATRIX_ROW_START_CHARPOS and MATRIX_ROW_END_CHARPOS.

src/ChangeLog
src/dispextern.h
src/dispnew.c
src/xdisp.c

index b0965f8..fe30d07 100644 (file)
@@ -1,3 +1,30 @@
+2010-05-18  Eli Zaretskii  <eliz@gnu.org>
+
+       * dispextern.h (struct glyph_row): New members minpos and maxpos.
+       (MATRIX_ROW_START_CHARPOS, MATRIX_ROW_START_BYTEPOS)
+       (MATRIX_ROW_END_CHARPOS, MATRIX_ROW_END_BYTEPOS): Reference minpos
+       and maxpos members instead of start.pos and end.pos, respectively.
+
+       * xdisp.c (display_line): Compare IT_CHARPOS with the position in
+       row->start.pos, rather than with MATRIX_ROW_START_CHARPOS.
+       (cursor_row_p): Use row->end.pos rather than MATRIX_ROW_END_CHARPOS.
+       (try_window_reusing_current_matrix, try_window_id): Use
+       ROW->minpos rather than ROW->start.pos.
+       (init_from_display_pos, init_iterator): Use EMACS_INT for
+       character and byte positions.
+       (find_row_edges): Renamed from find_row_end.  Accept additional
+       arguments for minimum and maximum buffer positions seen by
+       display_line for this row.  Don't use iterator to find the
+       position following the maximum one; instead, increment the
+       position found by display_line directly.
+       (display_line): Record minimum and maximum buffer positions for
+       glyphs in this row.  Record the position of the newline that
+       terminates the line.
+
+       * dispnew.c (increment_row_positions, check_matrix_invariants):
+       Increment and check row->start.pos and row->end.pos, in addition
+       to MATRIX_ROW_START_CHARPOS and MATRIX_ROW_END_CHARPOS.
+
 2010-05-18  Juanma Barranquero  <lekktu@gmail.com>
 
        * charset.c (load_charset_map_from_file): Don't call close after fclose.
        * xdisp.c (Fcurrent_bidi_paragraph_direction): New function.
        (syms_of_xdisp): Defsubr it.
 
+       * cmds.c (Fforward_char, Fbackward_char): Doc fix.
+
        * Makefile.in: Fix MSDOS-related comments.
 
 2010-05-15  Glenn Morris  <rgm@gnu.org>
index 8e8da36..ce8527b 100644 (file)
@@ -748,21 +748,29 @@ struct glyph_row
 
   /* First position in this row.  This is the text position, including
      overlay position information etc, where the display of this row
-     started, and can thus be less the position of the first glyph
-     (e.g. due to invisible text or horizontal scrolling).  BIDI Note:
-     This is the smallest character position in the row, but not
-     necessarily the character that is the leftmost on the display.  */
+     started, and can thus be less than the position of the first
+     glyph (e.g. due to invisible text or horizontal scrolling).
+     BIDI Note: In R2L rows, that have its reversed_p flag set, this
+     position is at or beyond the right edge of the row.  */
   struct display_pos start;
 
   /* Text position at the end of this row.  This is the position after
      the last glyph on this row.  It can be greater than the last
-     glyph position + 1, due to truncation, invisible text etc.  In an
-     up-to-date display, this should always be equal to the start
-     position of the next row.  BIDI Note: this is the character whose
-     buffer position is the largest, but not necessarily the rightmost
-     one on the display.  */
+     glyph position + 1, due to a newline that ends the line,
+     truncation, invisible text etc.  In an up-to-date display, this
+     should always be equal to the start position of the next row.
+     BIDI Note: In R2L rows, this position is at or beyond the left
+     edge of the row.  */
   struct display_pos end;
 
+  /* The smallest and the largest buffer positions that contributed to
+     glyphs in this row.  Note that due to bidi reordering, these are
+     in general different from the text positions stored in `start'
+     and `end' members above, and also different from the buffer
+     positions recorded in the glyphs displayed the leftmost and
+     rightmost on the screen.  */
+  struct text_pos minpos, maxpos;
+
   /* Non-zero means the overlay arrow bitmap is on this line.
      -1 means use default overlay arrow bitmap, else
      it specifies actual fringe bitmap number.  */
@@ -947,16 +955,16 @@ struct glyph_row *matrix_row P_ ((struct glyph_matrix *, int));
    displayed by ROW, which is not necessarily the smallest horizontal
    position.  */
 
-#define MATRIX_ROW_START_CHARPOS(ROW) ((ROW)->start.pos.charpos)
-#define MATRIX_ROW_START_BYTEPOS(ROW) ((ROW)->start.pos.bytepos)
+#define MATRIX_ROW_START_CHARPOS(ROW) ((ROW)->minpos.charpos)
+#define MATRIX_ROW_START_BYTEPOS(ROW) ((ROW)->minpos.bytepos)
 
 /* Return the character/ byte position at which ROW ends.  BIDI Note:
    this is the largest character/byte position among characters in
    ROW, i.e. the last logical-order character displayed by ROW, which
    is not necessarily the largest horizontal position.  */
 
-#define MATRIX_ROW_END_CHARPOS(ROW) ((ROW)->end.pos.charpos)
-#define MATRIX_ROW_END_BYTEPOS(ROW) ((ROW)->end.pos.bytepos)
+#define MATRIX_ROW_END_CHARPOS(ROW) ((ROW)->maxpos.charpos)
+#define MATRIX_ROW_END_BYTEPOS(ROW) ((ROW)->maxpos.bytepos)
 
 /* Return the vertical position of ROW in MATRIX.  */
 
@@ -1789,7 +1797,7 @@ struct bidi_it {
   EMACS_INT next_en_pos;       /* position of next EN char for ET */
   EMACS_INT ignore_bn_limit;   /* position until which to ignore BNs */
   bidi_dir_t sor;              /* direction of start-of-run in effect */
-  int scan_dir;                        /* direction of text scan */
+  int scan_dir;                        /* direction of text scan, 1: forw, -1: back */
   int stack_idx;               /* index of current data on the stack */
   /* Note: Everything from here on is not copied/saved when the bidi
      iterator state is saved, pushed, or popped.  So only put here
index 7ab2bf3..476b58a 100644 (file)
@@ -1188,6 +1188,10 @@ increment_row_positions (row, delta, delta_bytes)
   MATRIX_ROW_START_BYTEPOS (row) += delta_bytes;
   MATRIX_ROW_END_CHARPOS (row) += delta;
   MATRIX_ROW_END_BYTEPOS (row) += delta_bytes;
+  CHARPOS (row->start.pos) += delta;
+  BYTEPOS (row->start.pos) += delta_bytes;
+  CHARPOS (row->end.pos) += delta;
+  BYTEPOS (row->end.pos) += delta_bytes;
 
   if (!row->enabled_p)
     return;
@@ -1748,13 +1752,19 @@ check_matrix_invariants (w)
       /* Check that character and byte positions are in sync.  */
       xassert (MATRIX_ROW_START_BYTEPOS (row)
               == CHAR_TO_BYTE (MATRIX_ROW_START_CHARPOS (row)));
+      xassert (BYTEPOS (row->start.pos)
+              == CHAR_TO_BYTE (CHARPOS (row->start.pos)));
 
       /* CHAR_TO_BYTE aborts when invoked for a position > Z.  We can
         have such a position temporarily in case of a minibuffer
         displaying something like `[Sole completion]' at its end.  */
       if (MATRIX_ROW_END_CHARPOS (row) < BUF_ZV (current_buffer))
-       xassert (MATRIX_ROW_END_BYTEPOS (row)
-                == CHAR_TO_BYTE (MATRIX_ROW_END_CHARPOS (row)));
+       {
+         xassert (MATRIX_ROW_END_BYTEPOS (row)
+                  == CHAR_TO_BYTE (MATRIX_ROW_END_CHARPOS (row)));
+         xassert (BYTEPOS (row->end.pos)
+                  == CHAR_TO_BYTE (CHARPOS (row->end.pos)));
+       }
 
       /* Check that end position of `row' is equal to start position
         of next row.  */
@@ -1764,6 +1774,8 @@ check_matrix_invariants (w)
                   == MATRIX_ROW_START_CHARPOS (next));
          xassert (MATRIX_ROW_END_BYTEPOS (row)
                   == MATRIX_ROW_START_BYTEPOS (next));
+         xassert (CHARPOS (row->end.pos) == CHARPOS (next->start.pos));
+         xassert (BYTEPOS (row->end.pos) == BYTEPOS (next->start.pos));
        }
       row = next;
     }
index 6b3097c..9cd562e 100644 (file)
@@ -2598,7 +2598,7 @@ void
 init_iterator (it, w, charpos, bytepos, row, base_face_id)
      struct it *it;
      struct window *w;
-     int charpos, bytepos;
+     EMACS_INT charpos, bytepos;
      struct glyph_row *row;
      enum face_id base_face_id;
 {
@@ -3012,7 +3012,7 @@ init_from_display_pos (it, w, pos)
      struct window *w;
      struct display_pos *pos;
 {
-  int charpos = CHARPOS (pos->pos), bytepos = BYTEPOS (pos->pos);
+  EMACS_INT charpos = CHARPOS (pos->pos), bytepos = BYTEPOS (pos->pos);
   int i, overlay_strings_with_newlines = 0;
 
   /* If POS specifies a position in a display vector, this might
@@ -14972,7 +14972,7 @@ try_window_reusing_current_matrix (w)
   /* The variable new_start now holds the new window start.  The old
      start `start' can be determined from the current matrix.  */
   SET_TEXT_POS_FROM_MARKER (new_start, w->start);
-  start = start_row->start.pos;
+  start = start_row->minpos;
   start_vpos = MATRIX_ROW_VPOS (start_row, w->current_matrix);
 
   /* Clear the desired matrix for the display below.  */
@@ -15011,7 +15011,7 @@ try_window_reusing_current_matrix (w)
            {
              /* Advance to the next row as the "start".  */
              start_row++;
-             start = start_row->start.pos;
+             start = start_row->minpos;
              /* If there are no more rows to try, or just one, give up.  */
              if (start_row == MATRIX_MODE_LINE_ROW (w->current_matrix) - 1
                  || w->vscroll || MATRIX_ROW_PARTIALLY_VISIBLE_P (w, start_row)
@@ -15905,13 +15905,13 @@ try_window_id (w)
         as is, without changing glyph positions since no text has
         been added/removed in front of the window end.  */
       r0 = MATRIX_FIRST_TEXT_ROW (current_matrix);
-      if (TEXT_POS_EQUAL_P (start, r0->start.pos)
+      if (TEXT_POS_EQUAL_P (start, r0->minpos)
          /* PT must not be in a partially visible line.  */
          && !(PT >= MATRIX_ROW_START_CHARPOS (row)
               && MATRIX_ROW_BOTTOM_Y (row) > window_text_bottom_y (w)))
        {
          /* We have to compute the window end anew since text
-            can have been added/removed after it.  */
+            could have been added/removed after it.  */
          w->window_end_pos
            = make_number (Z - MATRIX_ROW_END_CHARPOS (row));
          w->window_end_bytepos
@@ -15943,7 +15943,7 @@ try_window_id (w)
      start is not in changed text, otherwise positions would not be
      comparable.  */
   row = MATRIX_FIRST_TEXT_ROW (current_matrix);
-  if (!TEXT_POS_EQUAL_P (start, row->start.pos))
+  if (!TEXT_POS_EQUAL_P (start, row->minpos))
     GIVE_UP (16);
 
   /* Give up if the window ends in strings.  Overlay strings
@@ -17335,7 +17335,7 @@ cursor_row_p (w, row)
 {
   int cursor_row_p = 1;
 
-  if (PT == MATRIX_ROW_END_CHARPOS (row))
+  if (PT == CHARPOS (row->end.pos))
     {
       /* Suppose the row ends on a string.
         Unless the row is continued, that means it ends on a newline
@@ -17372,14 +17372,15 @@ cursor_row_p (w, row)
        {
          /* If the row ends in middle of a real character,
             and the line is continued, we want the cursor here.
-            That's because MATRIX_ROW_END_CHARPOS would equal
+            That's because CHARPOS (ROW->end.pos) would equal
             PT if PT is before the character.  */
          if (!row->ends_in_ellipsis_p)
            cursor_row_p = row->continued_p;
          else
          /* If the row ends in an ellipsis, then
-            MATRIX_ROW_END_CHARPOS will equal point after the invisible text.
-            We want that position to be displayed after the ellipsis.  */
+            CHARPOS (ROW->end.pos) will equal point after the
+            invisible text.  We want that position to be displayed
+            after the ellipsis.  */
            cursor_row_p = 0;
        }
       /* If the row ends at ZV, display the cursor at the end of that
@@ -17515,122 +17516,87 @@ unproduce_glyphs (it, n)
     glyph[-n] = *glyph;
 }
 
-/* Find the positions in a bidi-reordered ROW to serve as ROW->start
-   and ROW->end.  */
-static struct display_pos
-find_row_end (it, row)
+/* Find the positions in a bidi-reordered ROW to serve as ROW->minpos
+   and ROW->maxpos.  */
+static void
+find_row_edges (it, row, min_pos, min_bpos, max_pos, max_bpos)
      struct it *it;
      struct glyph_row *row;
+     EMACS_INT min_pos, min_bpos, max_pos, max_bpos;
 {
   /* FIXME: Revisit this when glyph ``spilling'' in continuation
      lines' rows is implemented for bidi-reordered rows.  */
-  EMACS_INT min_pos = ZV + 1, max_pos = 0;
-  struct glyph *g;
-  struct it save_it;
-  struct text_pos tpos;
-  struct display_pos row_end = it->current;
 
-  for (g = row->glyphs[TEXT_AREA];
-       g < row->glyphs[TEXT_AREA] + row->used[TEXT_AREA];
-       g++)
+  /* ROW->minpos is the value of min_pos, the minimal buffer position
+     we have in ROW.  */
+  if (min_pos <= ZV)
     {
-      if (BUFFERP (g->object))
+      SET_TEXT_POS (row->minpos, min_pos, min_bpos);
+      if (max_pos == 0)
        {
-         if (g->charpos > 0 && g->charpos < min_pos)
-           min_pos = g->charpos;
-         if (g->charpos > max_pos)
-           max_pos = g->charpos;
+         max_pos = min_pos;
+         max_bpos = min_bpos;
        }
     }
-  /* Empty lines have a valid buffer position at their first
-     glyph, but that glyph's OBJECT is zero, as if it didn't come
-     from a buffer.  If we didn't find any valid buffer positions
-     in this row, maybe we have such an empty line.  */
-  if (max_pos == 0 && row->used[TEXT_AREA])
+  else
     {
-      for (g = row->glyphs[TEXT_AREA];
-          g < row->glyphs[TEXT_AREA] + row->used[TEXT_AREA];
-          g++)
-       {
-         if (INTEGERP (g->object))
-           {
-             if (g->charpos > 0 && g->charpos < min_pos)
-               min_pos = g->charpos;
-             if (g->charpos > max_pos)
-               max_pos = g->charpos;
-           }
-       }
+      /* We 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;
+      max_pos = CHARPOS (it->current.pos);
+      max_bpos = BYTEPOS (it->current.pos);
     }
 
-  /* ROW->start is the value of min_pos, the minimal buffer position
-     we have in ROW.  */
-  if (min_pos <= ZV)
-    {
-      /* Avoid calling the costly CHAR_TO_BYTE if possible.  */
-      if (min_pos != row->start.pos.charpos)
-       SET_TEXT_POS (row->start.pos, min_pos, CHAR_TO_BYTE (min_pos));
-      if (max_pos == 0)
-       max_pos = min_pos;
-    }
+  if (!max_pos)
+    abort ();
 
-  /* For ROW->end, we need the position that is _after_ max_pos, in
-     the logical order, unless we are at ZV.  */
+  /* Here are the various use-cases for ending the row, and the
+     corresponding values for ROW->maxpos:
+
+     Empty line                               min_pos + 1
+     Line ends in a newline from buffer       eol_pos + 1
+     Line is continued from buffer            max_pos + 1
+     Line ends in a newline from string       max_pos
+     Line is continued from string            max_pos
+     Line is entirely from a string           min_pos
+     Line that ends at ZV                     ZV
+
+     If you discover other use-cases, please add them here as
+     appropriate.  */
   if (row->ends_at_zv_p)
+    row->maxpos = it->current.pos;
+  else if (row->used[TEXT_AREA])
     {
-      if (!row->used[TEXT_AREA])
-       row->start.pos = row_end.pos;
-    }
-  else if (row->used[TEXT_AREA] && max_pos)
-    {
-      int at_eol_p;
-
-      SET_TEXT_POS (tpos, max_pos, CHAR_TO_BYTE (max_pos));
-      save_it = *it;
-      it->bidi_p = 0;
-      reseat (it, tpos, 0);
-      if (!get_next_display_element (it))
-       abort ();       /* this row cannot be at ZV, see above */
-      at_eol_p = ITERATOR_AT_END_OF_LINE_P (it);
-      set_iterator_to_next (it, 1);
-      row_end = it->current;
-      /* If the character at max_pos is not a newline and the
-        characters at max_pos+1 is a newline, skip that newline as
-        well.  Note that this may skip some invisible text.  */
-      if (!at_eol_p
-         && get_next_display_element (it)
-         && ITERATOR_AT_END_OF_LINE_P (it))
+      if (max_pos == min_pos)
        {
-         set_iterator_to_next (it, 1);
-         /* Record the position after the newline of a continued row.
-            We will need that to set ROW->end of the last row
-            produced for a continued line.  */
-         if (row->continued_p)
-           save_it.eol_pos = it->current.pos;
+         if (it->method == GET_FROM_BUFFER)
+           /* Empty line, which stands for a newline.  */
+           SET_TEXT_POS (row->maxpos, min_pos + 1, min_bpos + 1);
          else
-           {
-             row_end = it->current;
-             save_it.eol_pos.charpos = save_it.eol_pos.bytepos = 0;
-           }
+           /* A line that is entirely from a string.  */
+           row->maxpos = row->minpos;
        }
-      else if (!row->continued_p
-              && MATRIX_ROW_CONTINUATION_LINE_P (row)
-              && it->eol_pos.charpos > 0)
+      else if (CHARPOS (it->eol_pos) > 0)
+       SET_TEXT_POS (row->maxpos,
+                     CHARPOS (it->eol_pos) + 1, BYTEPOS (it->eol_pos) + 1);
+      else if (row->continued_p)
        {
-         /* Last row of a continued line.  Use the position recorded
-            in IT->eol_pos, to the effect that the newline belongs to
-            this row, not to the row which displays the character
-            with the largest buffer position before the newline.  */
-         row_end.pos = it->eol_pos;
-         it->eol_pos.charpos = it->eol_pos.bytepos = 0;
+         if (it->method == GET_FROM_BUFFER)
+           {
+             INC_BOTH (max_pos, max_bpos);
+             SET_TEXT_POS (row->maxpos, max_pos, max_bpos);
+           }
+         else
+           SET_TEXT_POS (row->maxpos, max_pos, max_bpos);
        }
-      *it = save_it;
-      /* The members of ROW->end that are not taken from buffer
-        positions are copied from IT->current.  */
-      row_end.string_pos = it->current.string_pos;
-      row_end.overlay_string_index = it->current.overlay_string_index;
-      row_end.dpvec_index = it->current.dpvec_index;
+      else if (row->ends_in_newline_from_string_p)
+       SET_TEXT_POS (row->maxpos, max_pos, max_bpos);
+      else
+       abort ();
     }
-  return row_end;
+  else
+    row->maxpos = it->current.pos;
 }
 
 /* Construct the glyph row IT->glyph_row in the desired matrix of
@@ -17651,6 +17617,7 @@ display_line (it)
   int wrap_row_phys_ascent, wrap_row_phys_height;
   int wrap_row_extra_line_spacing;
   int cvpos;
+  EMACS_INT min_pos = ZV + 1, min_bpos, max_pos = 0, max_bpos;
 
   /* We always start displaying at hpos zero even if hscrolled.  */
   xassert (it->hpos == 0 && it->current_x == 0);
@@ -17741,7 +17708,8 @@ display_line (it)
          row->ends_at_zv_p = 1;
          /* A row that displays right-to-left text must always have
             its last face extended all the way to the end of line,
-            even if this row ends in ZV.  */
+            even if this row ends in ZV, because we still write to th
+            screen left to right.  */
          if (row->reversed_p)
            extend_face_to_end_of_line (it);
          break;
@@ -17889,6 +17857,27 @@ display_line (it)
                                }
                            }
                        }
+
+                     /* Record the maximum and minimum buffer
+                        positions seen so far in glyphs that will be
+                        displayed by this row.  */
+                     if (it->bidi_p)
+                       {
+                         if (BUFFERP (glyph->object)
+                             || INTEGERP (glyph->object))
+                           {
+                             if (IT_CHARPOS (*it) < min_pos)
+                               {
+                                 min_pos = IT_CHARPOS (*it);
+                                 min_bpos = IT_BYTEPOS (*it);
+                               }
+                             if (IT_CHARPOS (*it) > max_pos)
+                               {
+                                 max_pos = IT_CHARPOS (*it);
+                                 max_bpos = IT_BYTEPOS (*it);
+                               }
+                           }
+                       }
                    }
                  else if (CHAR_GLYPH_PADDING_P (*glyph)
                           && !FRAME_WINDOW_P (it->f))
@@ -17994,6 +17983,27 @@ display_line (it)
                  /* Increment number of glyphs actually displayed.  */
                  ++it->hpos;
 
+                 /* Record the maximum and minimum buffer positions
+                    seen so far in glyphs that will be displayed by
+                    this row.  */
+                 if (it->bidi_p)
+                   {
+                     if (BUFFERP (glyph->object)
+                         || INTEGERP (glyph->object))
+                       {
+                         if (IT_CHARPOS (*it) < min_pos)
+                           {
+                             min_pos = IT_CHARPOS (*it);
+                             min_bpos = IT_BYTEPOS (*it);
+                           }
+                         if (IT_CHARPOS (*it) > max_pos)
+                           {
+                             max_pos = IT_CHARPOS (*it);
+                             max_bpos = IT_BYTEPOS (*it);
+                           }
+                       }
+                   }
+
                  if (x < it->first_visible_x)
                    /* Glyph is partially visible, i.e. row starts at
                       negative X position.  */
@@ -18045,6 +18055,10 @@ display_line (it)
          if (used_before == 0)
            row->glyphs[TEXT_AREA]->charpos = CHARPOS (it->position);
 
+         /* Record the position of the newline, for use in
+            find_row_edges.  */
+         it->eol_pos = it->current.pos;
+
          /* Consume the line end.  This skips over invisible lines.  */
          set_iterator_to_next (it, 1);
          it->continuation_lines_width = 0;
@@ -18124,7 +18138,7 @@ display_line (it)
   /* If line is not empty and hscrolled, maybe insert truncation glyphs
      at the left window margin.  */
   if (it->first_visible_x
-      && IT_CHARPOS (*it) != MATRIX_ROW_START_CHARPOS (row))
+      && IT_CHARPOS (*it) != CHARPOS (row->start.pos))
     {
       if (!FRAME_WINDOW_P (it->f))
        insert_left_trunc_glyphs (it);
@@ -18178,12 +18192,19 @@ display_line (it)
 
   /* Remember the position at which this line ends.  */
   row->end = it->current;
-  /* ROW->start and ROW->end must be the smallest and the largest
-     buffer positions in ROW.  But if ROW was bidi-reordered, these
-     two positions can be anywhere in the row, so we must rescan all
-     of the ROW's glyphs to find them.  */
-  if (it->bidi_p)
-    row->end = find_row_end (it, row);
+  if (!it->bidi_p)
+    {
+      row->minpos = row->start.pos;
+      row->maxpos = row->end.pos;
+    }
+  else
+    {
+      /* ROW->minpos and ROW->maxpos must be the smallest and
+        `1 + the largest' buffer positions in ROW.  But if ROW was
+        bidi-reordered, these two positions can be anywhere in the
+        row, so we must determine them now.  */
+      find_row_edges (it, row, min_pos, min_bpos, max_pos, max_bpos);
+    }
 
   /* Record whether this row ends inside an ellipsis.  */
   row->ends_in_ellipsis_p
@@ -18229,6 +18250,7 @@ display_line (it)
      row to be used.  */
   it->current_x = it->hpos = 0;
   it->current_y += row->height;
+  SET_TEXT_POS (it->eol_pos, 0, 0);
   ++it->vpos;
   ++it->glyph_row;
   /* The next row should by default use the same value of the