changeset 108656:0b28d05fa415

Initial reimplementation of calculating line edge positions in bidi lines. 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.
author Eli Zaretskii <eliz@gnu.org>
date Tue, 18 May 2010 18:22:15 +0300
parents f5b2fcb51f42
children 7e4a23f2f3ea
files src/ChangeLog src/dispextern.h src/dispnew.c src/xdisp.c
diffstat 4 files changed, 212 insertions(+), 141 deletions(-) [+]
line wrap: on
line diff
--- a/src/ChangeLog	Tue May 18 10:33:29 2010 +0200
+++ b/src/ChangeLog	Tue May 18 18:22:15 2010 +0300
@@ -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.
@@ -91,6 +118,8 @@
 	* 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>
--- a/src/dispextern.h	Tue May 18 10:33:29 2010 +0200
+++ b/src/dispextern.h	Tue May 18 18:22:15 2010 +0300
@@ -748,21 +748,29 @@
 
   /* 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 @@
    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 @@
   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
--- a/src/dispnew.c	Tue May 18 10:33:29 2010 +0200
+++ b/src/dispnew.c	Tue May 18 18:22:15 2010 +0300
@@ -1188,6 +1188,10 @@
   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 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 @@
 		   == 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;
     }
--- a/src/xdisp.c	Tue May 18 10:33:29 2010 +0200
+++ b/src/xdisp.c	Tue May 18 18:22:15 2010 +0300
@@ -2598,7 +2598,7 @@
 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 @@
      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 @@
   /* 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 @@
 	    {
 	      /* 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 @@
 	 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 @@
      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 @@
 {
   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 @@
 	{
 	  /* 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 @@
     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++)
-    {
-      if (BUFFERP (g->object))
-	{
-	  if (g->charpos > 0 && g->charpos < min_pos)
-	    min_pos = g->charpos;
-	  if (g->charpos > max_pos)
-	    max_pos = g->charpos;
-	}
-    }
-  /* 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])
-    {
-      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;
-	    }
-	}
-    }
-
-  /* ROW->start is the value of min_pos, the minimal buffer position
+
+  /* ROW->minpos 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));
+      SET_TEXT_POS (row->minpos, min_pos, min_bpos);
       if (max_pos == 0)
-	max_pos = min_pos;
-    }
-
-  /* For ROW->end, we need the position that is _after_ max_pos, in
-     the logical order, unless we are at ZV.  */
+	{
+	  max_pos = min_pos;
+	  max_bpos = 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.  */
+      row->minpos = row->start.pos;
+      max_pos = CHARPOS (it->current.pos);
+      max_bpos = BYTEPOS (it->current.pos);
+    }
+
+  if (!max_pos)
+    abort ();
+
+  /* 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)
-    {
-      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))
-	{
-	  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;
-	  else
-	    {
-	      row_end = it->current;
-	      save_it.eol_pos.charpos = save_it.eol_pos.bytepos = 0;
-	    }
-	}
-      else if (!row->continued_p
-	       && MATRIX_ROW_CONTINUATION_LINE_P (row)
-	       && it->eol_pos.charpos > 0)
-	{
-	  /* 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;
-	}
-      *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;
-    }
-  return row_end;
+    row->maxpos = it->current.pos;
+  else if (row->used[TEXT_AREA])
+    {
+      if (max_pos == min_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
+	    /* A line that is entirely from a string.  */
+	    row->maxpos = row->minpos;
+	}
+      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)
+	{
+	  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);
+	}
+      else if (row->ends_in_newline_from_string_p)
+	SET_TEXT_POS (row->maxpos, max_pos, max_bpos);
+      else
+	abort ();
+    }
+  else
+    row->maxpos = it->current.pos;
 }
 
 /* Construct the glyph row IT->glyph_row in the desired matrix of
@@ -17651,6 +17617,7 @@
   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 @@
 	  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 @@
 				}
 			    }
 			}
+
+		      /* 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 @@
 		  /* 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 @@
 	  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 @@
   /* 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 @@
 
   /* 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 @@
      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