Mercurial > emacs
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