Commit d36fe237 authored by Eli Zaretskii's avatar Eli Zaretskii

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.
parent 560bb7ae
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>
......
......@@ -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
......
......@@ -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;
}
......
......@@ -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
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment