Mercurial > emacs
changeset 108750:3339da3cfeb3
Redesign bidi-aware edge positions of glyph rows, fix bug #6036.
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. Fix logic; eol_pos
should be tested before the rest. Handle the case of characters
delivered from display vector (bug#6036). Fix tests related to
it->method. Handle the truncated_on_right_p rows.
(RECORD_MAX_MIN_POS): New macro.
(display_line): Use it to record the minimum and maximum buffer
positions for glyphs in the row being assembled. Record the
position of the newline that terminates the line. If word wrap is
in effect, restore minimum and maximum positions seen up to the
wrap point, when iterator returns to it.
(try_window_reusing_current_matrix): Give up if in bidi-reordered
row and cursor not already at point. Restore original pre-bidi
code for unidirectional buffers.
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.
.gdbinit (prowlims): Display row->minpos and row->maxpos.
Display truncated_on_left_p and truncated_on_right_p flags.
Formatting fixes.
(pmtxrows): Display the ordinal number of each row. Don't display
rows beyond the last one.
bidi.c (bidi_cache_iterator_state): Don't zero out new_paragraph:
it is not copied by bidi_copy_it.
author | Eli Zaretskii <eliz@gnu.org> |
---|---|
date | Sat, 22 May 2010 22:32:21 +0300 |
parents | 48378bcd6c35 (current diff) ab4686221ccf (diff) |
children | c40b9bfe9167 0aaff477ec9f |
files | src/ChangeLog src/bidi.c src/xdisp.c |
diffstat | 6 files changed, 261 insertions(+), 181 deletions(-) [+] |
line wrap: on
line diff
--- a/src/.gdbinit Sat May 22 22:09:51 2010 +0300 +++ b/src/.gdbinit Sat May 22 22:32:21 2010 +0300 @@ -616,7 +616,7 @@ end define prowlims - printf "start=%d,end=%d,reversed=%d,cont=%d,at_zv=%d\n", $arg0->start.pos.charpos, $arg0->end.pos.charpos, $arg0->reversed_p, $arg0->continued_p, $arg0->ends_at_zv_p + printf "edges=(%d,%d),r2l=%d,cont=%d,trunc=(%d,%d),at_zv=%d\n", $arg0->minpos.charpos, $arg0->maxpos.charpos, $arg0->reversed_p, $arg0->continued_p, $arg0->truncated_on_left_p, $arg0->truncated_on_right_p, $arg0->ends_at_zv_p end document prowlims Print important attributes of a glyph_row structure. @@ -626,10 +626,13 @@ define pmtxrows set $mtx = $arg0 set $gl = $mtx->rows - set $glend = $mtx->rows + $mtx->nrows + set $glend = $mtx->rows + $mtx->nrows - 1 + set $i = 0 while ($gl < $glend) + printf "%d: ", $i prowlims $gl set $gl = $gl + 1 + set $i = $i + 1 end end document pmtxrows
--- a/src/ChangeLog Sat May 22 22:09:51 2010 +0300 +++ b/src/ChangeLog Sat May 22 22:32:21 2010 +0300 @@ -1,3 +1,50 @@ +2010-05-19 Eli Zaretskii <eliz@gnu.org> + + Redesign and reimplement bidi-aware edge positions of glyph rows. + + * 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. Fix logic; eol_pos + should be tested before the rest. Handle the case of characters + delivered from display vector (bug#6036). Fix tests related to + it->method. Handle the truncated_on_right_p rows. + (RECORD_MAX_MIN_POS): New macro. + (display_line): Use it to record the minimum and maximum buffer + positions for glyphs in the row being assembled. Record the + position of the newline that terminates the line. If word wrap is + in effect, restore minimum and maximum positions seen up to the + wrap point, when iterator returns to it. + (try_window_reusing_current_matrix): Give up if in bidi-reordered + row and cursor not already at point. Restore original pre-bidi + code for unidirectional buffers. + + * 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. + + * .gdbinit (prowlims): Display row->minpos and row->maxpos. + Display truncated_on_left_p and truncated_on_right_p flags. + Formatting fixes. + (pmtxrows): Display the ordinal number of each row. Don't display + rows beyond the last one. + + * bidi.c (bidi_cache_iterator_state): Don't zero out new_paragraph: + it is not copied by bidi_copy_it. + 2010-05-22 Eli Zaretskii <eliz@gnu.org> * w32.c (sys_write): Break writes into chunks smaller than 32MB. @@ -51,8 +98,6 @@ Move static/dynamic dependency stuff to deps.mk/autodeps.mk. * deps.mk, autodeps.mk: New files, extracted from Makefile.in. -2010-05-19 Eli Zaretskii <eliz@gnu.org> - * bidi.c (bidi_cache_shrink, bidi_cache_iterator_state): Fix reallocation of the cache. (Bug#6210) @@ -175,6 +220,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/bidi.c Sat May 22 22:09:51 2010 +0300 +++ b/src/bidi.c Sat May 22 22:32:21 2010 +0300 @@ -707,7 +707,6 @@ bidi_copy_it (&bidi_cache[idx], bidi_it); if (!resolved) bidi_cache[idx].resolved_level = -1; - bidi_cache[idx].new_paragraph = 0; } else {
--- a/src/dispextern.h Sat May 22 22:09:51 2010 +0300 +++ b/src/dispextern.h Sat May 22 22:32:21 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 Sat May 22 22:09:51 2010 +0300 +++ b/src/dispnew.c Sat May 22 22:32:21 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 Sat May 22 22:09:51 2010 +0300 +++ b/src/xdisp.c Sat May 22 22:32:21 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 @@ -14975,7 +14975,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. */ @@ -15014,7 +15014,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) @@ -15296,39 +15296,26 @@ { struct glyph *glyph = row->glyphs[TEXT_AREA] + w->cursor.hpos; struct glyph *end = glyph + row->used[TEXT_AREA]; - struct glyph *orig_glyph = glyph; - struct cursor_pos orig_cursor = w->cursor; - - for (; glyph < end - && (!BUFFERP (glyph->object) - || glyph->charpos != PT); - glyph++) - { - w->cursor.hpos++; - w->cursor.x += glyph->pixel_width; - } - /* With bidi reordering, charpos changes non-linearly - with hpos, so the right glyph could be to the - left. */ - if (!NILP (XBUFFER (w->buffer)->bidi_display_reordering) - && (!BUFFERP (glyph->object) || glyph->charpos != PT)) - { - struct glyph *start_glyph = row->glyphs[TEXT_AREA]; - - glyph = orig_glyph - 1; - orig_cursor.hpos--; - orig_cursor.x -= glyph->pixel_width; - for (; glyph >= start_glyph - && (!BUFFERP (glyph->object) - || glyph->charpos != PT); - glyph--) - { - w->cursor.hpos--; - w->cursor.x -= glyph->pixel_width; - } - if (BUFFERP (glyph->object) && glyph->charpos == PT) - w->cursor = orig_cursor; - } + + /* Can't use this optimization with bidi-reordered glyph + rows, unless cursor is already at point. */ + if (!NILP (XBUFFER (w->buffer)->bidi_display_reordering)) + { + if (!(w->cursor.hpos >= 0 + && w->cursor.hpos < row->used[TEXT_AREA] + && BUFFERP (glyph->object) + && glyph->charpos == PT)) + return 0; + } + else + for (; glyph < end + && (!BUFFERP (glyph->object) + || glyph->charpos < PT); + glyph++) + { + w->cursor.hpos++; + w->cursor.x += glyph->pixel_width; + } } } @@ -15908,13 +15895,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 @@ -15946,7 +15933,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 @@ -17338,7 +17325,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 @@ -17375,14 +17362,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 @@ -17518,122 +17506,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)); - 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. */ + 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. */ + 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: + + Line ends in a newline from buffer eol_pos + 1 + Line is continued from buffer max_pos + 1 + Line is truncated on right it->current.pos + Line ends in a newline from string max_pos + Line is continued from string max_pos + Line is continued from display vector max_pos + Line is entirely from a string min_pos == max_pos + Line is entirely from a display vector min_pos == max_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 (row->ends_in_newline_from_string_p) + SET_TEXT_POS (row->maxpos, max_pos, max_bpos); + 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 max_pos is different from IT's current position, it + means IT->method does not belong to the display element + at max_pos. However, it also means that the display + element at max_pos was displayed in its entirety on this + line, which is equivalent to saying that the next line + starts at the next buffer position. */ + if (IT_CHARPOS (*it) == max_pos && it->method != GET_FROM_BUFFER) + SET_TEXT_POS (row->maxpos, max_pos, max_bpos); + else + { + INC_BOTH (max_pos, max_bpos); + SET_TEXT_POS (row->maxpos, max_pos, max_bpos); + } + } + else if (row->truncated_on_right_p) + /* display_line already called reseat_at_next_visible_line_start, + which puts the iterator at the beginning of the next line, in + the logical order. */ + row->maxpos = it->current.pos; + else if (max_pos == min_pos && it->method != GET_FROM_BUFFER) + /* A line that is entirely from a string/image/stretch... */ + row->maxpos = row->minpos; + else + abort (); + } + else + row->maxpos = it->current.pos; } /* Construct the glyph row IT->glyph_row in the desired matrix of @@ -17653,7 +17606,10 @@ int wrap_row_used = -1, wrap_row_ascent, wrap_row_height; int wrap_row_phys_ascent, wrap_row_phys_height; int wrap_row_extra_line_spacing; + EMACS_INT wrap_row_min_pos, wrap_row_min_bpos; + EMACS_INT wrap_row_max_pos, wrap_row_max_bpos; 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); @@ -17710,6 +17666,23 @@ row->phys_height = it->max_phys_ascent + it->max_phys_descent; row->extra_line_spacing = it->max_extra_line_spacing; +/* Utility macro to record max and min buffer positions seen until now. */ +#define RECORD_MAX_MIN_POS(IT) \ + do \ + { \ + 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)); \ + } \ + } \ + while (0) + /* Loop generating characters. The loop is left with IT on the next character to display. */ while (1) @@ -17744,7 +17717,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; @@ -17778,6 +17752,10 @@ wrap_row_phys_ascent = row->phys_ascent; wrap_row_phys_height = row->phys_height; wrap_row_extra_line_spacing = row->extra_line_spacing; + wrap_row_min_pos = min_pos; + wrap_row_min_bpos = min_bpos; + wrap_row_max_pos = max_pos; + wrap_row_max_bpos = max_bpos; may_wrap = 0; } } @@ -17828,6 +17806,10 @@ it->max_extra_line_spacing); if (it->current_x - it->pixel_width < it->first_visible_x) row->x = x - it->first_visible_x; + /* Record the maximum and minimum buffer positions seen so + far in glyphs that will be displayed by this row. */ + if (it->bidi_p) + RECORD_MAX_MIN_POS (it); } else { @@ -17861,6 +17843,11 @@ it->current_x = new_x; it->continuation_lines_width += new_x; ++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) + RECORD_MAX_MIN_POS (it); if (i == nglyphs - 1) { /* If line-wrap is on, check if a previous @@ -17935,6 +17922,10 @@ row->phys_ascent = wrap_row_phys_ascent; row->phys_height = wrap_row_phys_height; row->extra_line_spacing = wrap_row_extra_line_spacing; + min_pos = wrap_row_min_pos; + min_bpos = wrap_row_min_bpos; + max_pos = wrap_row_max_pos; + max_bpos = wrap_row_max_bpos; row->continued_p = 1; row->ends_at_zv_p = 0; row->exact_window_width_line_p = 0; @@ -17997,6 +17988,12 @@ /* 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) + RECORD_MAX_MIN_POS (it); + if (x < it->first_visible_x) /* Glyph is partially visible, i.e. row starts at negative X position. */ @@ -18048,6 +18045,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; @@ -18127,7 +18128,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); @@ -18181,12 +18182,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 @@ -18232,6 +18240,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 @@ -18242,6 +18251,8 @@ it->glyph_row->reversed_p = row->reversed_p; it->start = row->end; return row->displays_text_p; + +#undef RECORD_MAX_MIN_POS } DEFUN ("current-bidi-paragraph-direction", Fcurrent_bidi_paragraph_direction,