aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorEli Zaretskii2010-05-01 21:11:20 +0300
committerEli Zaretskii2010-05-01 21:11:20 +0300
commitaf7c7572ce8d87f51817d0f518d1b0aced074a41 (patch)
treeff962558f8c48781e6a76883bd429b5ea6be73ba /src
parent502269d6e71e78eaafe2da520d9b14ecf732914d (diff)
parentb47e0dcf2db5d0f754342f0eb13e53974bfbefbe (diff)
downloademacs-af7c7572ce8d87f51817d0f518d1b0aced074a41.tar.gz
emacs-af7c7572ce8d87f51817d0f518d1b0aced074a41.zip
Fix display of R2L lines and cursor motion in bidi buffers.
xdisp.c (find_row_end): New function, refactored from display_line. (display_line): Use it. (extend_face_to_end_of_line): In almost-filled rows, extend only if the row is R2L and not continued. (display_line): Fix prepending of truncation glyphs to R2L rows. Preserve overlay and string info in row->end. (insert_left_trunc_glyphs): Support addition of left truncation glyphs to R2L rows. (set_cursor_from_row): Don't place cursor on the vertical border glyph between adjacent windows. Fix a crash when a display string is continued to the next line. Don't return zero if cursor was found by `cursor' property of a display string. (try_cursor_movement): Don't assume that row->end == (row+1)->start, test for that explicitly.
Diffstat (limited to 'src')
-rw-r--r--src/ChangeLog20
-rw-r--r--src/xdisp.c341
2 files changed, 225 insertions, 136 deletions
diff --git a/src/ChangeLog b/src/ChangeLog
index e5c6a0b23b7..0b4baf64cf4 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,3 +1,23 @@
12010-05-01 Eli Zaretskii <eliz@gnu.org>
2
3 Miscellaneous fixes of bidi display.
4
5 * xdisp.c (find_row_end): New function, refactored from
6 display_line.
7 (display_line): Use it.
8 (extend_face_to_end_of_line): In almost-filled rows, extend only
9 if the row is R2L and not continued.
10 (display_line): Fix prepending of truncation glyphs to R2L rows.
11 Preserve overlay and string info in row->end.
12 (insert_left_trunc_glyphs): Support addition of left truncation
13 glyphs to R2L rows.
14 (set_cursor_from_row): Don't place cursor on the vertical border
15 glyph between adjacent windows. Fix a crash when a display string
16 is continued to the next line. Don't return zero if cursor was
17 found by `cursor' property of a display string.
18 (try_cursor_movement): Don't assume that row->end == (row+1)->start,
19 test for that explicitly.
20
12010-05-01 Glenn Morris <rgm@gnu.org> 212010-05-01 Glenn Morris <rgm@gnu.org>
2 22
3 * Makefile.in (gmallocobj, rallocobj, vmlimitobj): Initialize to null, 23 * Makefile.in (gmallocobj, rallocobj, vmlimitobj): Initialize to null,
diff --git a/src/xdisp.c b/src/xdisp.c
index 4834b61a626..6d906825d1e 100644
--- a/src/xdisp.c
+++ b/src/xdisp.c
@@ -12776,6 +12776,13 @@ set_cursor_from_row (w, row, matrix, delta, delta_bytes, dy, dvpos)
12776 rightmost glyph. Case in point: an empty last line that is 12776 rightmost glyph. Case in point: an empty last line that is
12777 part of an R2L paragraph. */ 12777 part of an R2L paragraph. */
12778 cursor = end - 1; 12778 cursor = end - 1;
12779 /* Avoid placing the cursor on the last glyph of the row, where
12780 on terminal frames we hold the vertical border between
12781 adjacent windows. */
12782 if (!FRAME_WINDOW_P (WINDOW_XFRAME (w))
12783 && !WINDOW_RIGHTMOST_P (w)
12784 && cursor == row->glyphs[LAST_AREA] - 1)
12785 cursor--;
12779 x = -1; /* will be computed below, at label compute_x */ 12786 x = -1; /* will be computed below, at label compute_x */
12780 } 12787 }
12781 12788
@@ -13015,7 +13022,8 @@ set_cursor_from_row (w, row, matrix, delta, delta_bytes, dy, dvpos)
13015 13022
13016 cursor = glyph; 13023 cursor = glyph;
13017 for (glyph += incr; 13024 for (glyph += incr;
13018 EQ (glyph->object, str); 13025 (row->reversed_p ? glyph > stop : glyph < stop)
13026 && EQ (glyph->object, str);
13019 glyph += incr) 13027 glyph += incr)
13020 { 13028 {
13021 Lisp_Object cprop; 13029 Lisp_Object cprop;
@@ -13055,8 +13063,9 @@ set_cursor_from_row (w, row, matrix, delta, delta_bytes, dy, dvpos)
13055 13063
13056 /* If we reached the end of the line, and END was from a string, 13064 /* If we reached the end of the line, and END was from a string,
13057 the cursor is not on this line. */ 13065 the cursor is not on this line. */
13058 if (glyph == end 13066 if (cursor == NULL
13059 && STRINGP ((glyph - incr)->object) 13067 && (row->reversed_p ? glyph <= end : glyph >= end)
13068 && STRINGP (end->object)
13060 && row->continued_p) 13069 && row->continued_p)
13061 return 0; 13070 return 0;
13062 } 13071 }
@@ -13714,11 +13723,14 @@ try_cursor_movement (window, startp, scroll_step)
13714 ++row; 13723 ++row;
13715 } 13724 }
13716 13725
13717 /* The end position of a row equals the start position 13726 /* If the end position of a row equals the start
13718 of the next row. If PT is there, we would rather 13727 position of the next row, and PT is at that position,
13719 display it in the next line. */ 13728 we would rather display cursor in the next line. */
13720 while (MATRIX_ROW_BOTTOM_Y (row) < last_y 13729 while (MATRIX_ROW_BOTTOM_Y (row) < last_y
13721 && MATRIX_ROW_END_CHARPOS (row) == PT 13730 && MATRIX_ROW_END_CHARPOS (row) == PT
13731 && row < w->current_matrix->rows
13732 + w->current_matrix->nrows - 1
13733 && MATRIX_ROW_START_CHARPOS (row+1) == PT
13722 && !cursor_row_p (w, row)) 13734 && !cursor_row_p (w, row))
13723 ++row; 13735 ++row;
13724 13736
@@ -16737,24 +16749,61 @@ insert_left_trunc_glyphs (it)
16737 produce_special_glyphs (&truncate_it, IT_TRUNCATION); 16749 produce_special_glyphs (&truncate_it, IT_TRUNCATION);
16738 16750
16739 /* Overwrite glyphs from IT with truncation glyphs. */ 16751 /* Overwrite glyphs from IT with truncation glyphs. */
16740 from = truncate_it.glyph_row->glyphs[TEXT_AREA]; 16752 if (!it->glyph_row->reversed_p)
16741 end = from + truncate_it.glyph_row->used[TEXT_AREA];
16742 to = it->glyph_row->glyphs[TEXT_AREA];
16743 toend = to + it->glyph_row->used[TEXT_AREA];
16744
16745 while (from < end)
16746 *to++ = *from++;
16747
16748 /* There may be padding glyphs left over. Overwrite them too. */
16749 while (to < toend && CHAR_GLYPH_PADDING_P (*to))
16750 { 16753 {
16751 from = truncate_it.glyph_row->glyphs[TEXT_AREA]; 16754 from = truncate_it.glyph_row->glyphs[TEXT_AREA];
16755 end = from + truncate_it.glyph_row->used[TEXT_AREA];
16756 to = it->glyph_row->glyphs[TEXT_AREA];
16757 toend = to + it->glyph_row->used[TEXT_AREA];
16758
16752 while (from < end) 16759 while (from < end)
16753 *to++ = *from++; 16760 *to++ = *from++;
16761
16762 /* There may be padding glyphs left over. Overwrite them too. */
16763 while (to < toend && CHAR_GLYPH_PADDING_P (*to))
16764 {
16765 from = truncate_it.glyph_row->glyphs[TEXT_AREA];
16766 while (from < end)
16767 *to++ = *from++;
16768 }
16769
16770 if (to > toend)
16771 it->glyph_row->used[TEXT_AREA] = to - it->glyph_row->glyphs[TEXT_AREA];
16754 } 16772 }
16773 else
16774 {
16775 /* In R2L rows, overwrite the last (rightmost) glyphs, and do
16776 that back to front. */
16777 end = truncate_it.glyph_row->glyphs[TEXT_AREA];
16778 from = end + truncate_it.glyph_row->used[TEXT_AREA] - 1;
16779 toend = it->glyph_row->glyphs[TEXT_AREA];
16780 to = toend + it->glyph_row->used[TEXT_AREA] - 1;
16781
16782 while (from >= end && to >= toend)
16783 *to-- = *from--;
16784 while (to >= toend && CHAR_GLYPH_PADDING_P (*to))
16785 {
16786 from =
16787 truncate_it.glyph_row->glyphs[TEXT_AREA]
16788 + truncate_it.glyph_row->used[TEXT_AREA] - 1;
16789 while (from >= end && to >= toend)
16790 *to-- = *from--;
16791 }
16792 if (from >= end)
16793 {
16794 /* Need to free some room before prepending additional
16795 glyphs. */
16796 int move_by = from - end + 1;
16797 struct glyph *g0 = it->glyph_row->glyphs[TEXT_AREA];
16798 struct glyph *g = g0 + it->glyph_row->used[TEXT_AREA] - 1;
16755 16799
16756 if (to > toend) 16800 for ( ; g >= g0; g--)
16757 it->glyph_row->used[TEXT_AREA] = to - it->glyph_row->glyphs[TEXT_AREA]; 16801 g[move_by] = *g;
16802 while (from >= end)
16803 *to-- = *from--;
16804 it->glyph_row->used[TEXT_AREA] += move_by;
16805 }
16806 }
16758} 16807}
16759 16808
16760 16809
@@ -16946,8 +16995,13 @@ extend_face_to_end_of_line (it)
16946 16995
16947 /* If line is already filled, do nothing. Non window-system frames 16996 /* If line is already filled, do nothing. Non window-system frames
16948 get a grace of one more ``pixel'' because their characters are 16997 get a grace of one more ``pixel'' because their characters are
16949 1-``pixel'' wide, so they hit the equality too early. */ 16998 1-``pixel'' wide, so they hit the equality too early. This grace
16950 if (it->current_x >= it->last_visible_x + !FRAME_WINDOW_P (f)) 16999 is needed only for R2L rows that are not continued, to produce
17000 one extra blank where we could display the cursor. */
17001 if (it->current_x >= it->last_visible_x
17002 + (!FRAME_WINDOW_P (f)
17003 && it->glyph_row->reversed_p
17004 && !it->glyph_row->continued_p))
16951 return; 17005 return;
16952 17006
16953 /* Face extension extends the background and box of IT->face_id 17007 /* Face extension extends the background and box of IT->face_id
@@ -17368,6 +17422,123 @@ unproduce_glyphs (it, n)
17368 glyph[-n] = *glyph; 17422 glyph[-n] = *glyph;
17369} 17423}
17370 17424
17425/* Find the positions in a bidi-reordered ROW to serve as ROW->start
17426 and ROW->end. */
17427static struct display_pos
17428find_row_end (it, row)
17429 struct it *it;
17430 struct glyph_row *row;
17431{
17432 /* FIXME: Revisit this when glyph ``spilling'' in continuation
17433 lines' rows is implemented for bidi-reordered rows. */
17434 EMACS_INT min_pos = ZV + 1, max_pos = 0;
17435 struct glyph *g;
17436 struct it save_it;
17437 struct text_pos tpos;
17438 struct display_pos row_end = it->current;
17439
17440 for (g = row->glyphs[TEXT_AREA];
17441 g < row->glyphs[TEXT_AREA] + row->used[TEXT_AREA];
17442 g++)
17443 {
17444 if (BUFFERP (g->object))
17445 {
17446 if (g->charpos > 0 && g->charpos < min_pos)
17447 min_pos = g->charpos;
17448 if (g->charpos > max_pos)
17449 max_pos = g->charpos;
17450 }
17451 }
17452 /* Empty lines have a valid buffer position at their first
17453 glyph, but that glyph's OBJECT is zero, as if it didn't come
17454 from a buffer. If we didn't find any valid buffer positions
17455 in this row, maybe we have such an empty line. */
17456 if (max_pos == 0 && row->used[TEXT_AREA])
17457 {
17458 for (g = row->glyphs[TEXT_AREA];
17459 g < row->glyphs[TEXT_AREA] + row->used[TEXT_AREA];
17460 g++)
17461 {
17462 if (INTEGERP (g->object))
17463 {
17464 if (g->charpos > 0 && g->charpos < min_pos)
17465 min_pos = g->charpos;
17466 if (g->charpos > max_pos)
17467 max_pos = g->charpos;
17468 }
17469 }
17470 }
17471
17472 /* ROW->start is the value of min_pos, the minimal buffer position
17473 we have in ROW. */
17474 if (min_pos <= ZV)
17475 {
17476 /* Avoid calling the costly CHAR_TO_BYTE if possible. */
17477 if (min_pos != row->start.pos.charpos)
17478 SET_TEXT_POS (row->start.pos, min_pos, CHAR_TO_BYTE (min_pos));
17479 if (max_pos == 0)
17480 max_pos = min_pos;
17481 }
17482
17483 /* For ROW->end, we need the position that is _after_ max_pos, in
17484 the logical order, unless we are at ZV. */
17485 if (row->ends_at_zv_p)
17486 {
17487 if (!row->used[TEXT_AREA])
17488 row->start.pos = row_end.pos;
17489 }
17490 else if (row->used[TEXT_AREA] && max_pos)
17491 {
17492 int at_eol_p;
17493
17494 SET_TEXT_POS (tpos, max_pos, CHAR_TO_BYTE (max_pos));
17495 save_it = *it;
17496 it->bidi_p = 0;
17497 reseat (it, tpos, 0);
17498 if (!get_next_display_element (it))
17499 abort (); /* this row cannot be at ZV, see above */
17500 at_eol_p = ITERATOR_AT_END_OF_LINE_P (it);
17501 set_iterator_to_next (it, 1);
17502 row_end = it->current;
17503 /* If the character at max_pos is not a newline and the
17504 characters at max_pos+1 is a newline, skip that newline as
17505 well. Note that this may skip some invisible text. */
17506 if (!at_eol_p
17507 && get_next_display_element (it)
17508 && ITERATOR_AT_END_OF_LINE_P (it))
17509 {
17510 set_iterator_to_next (it, 1);
17511 /* Record the position after the newline of a continued row.
17512 We will need that to set ROW->end of the last row
17513 produced for a continued line. */
17514 if (row->continued_p)
17515 save_it.eol_pos = it->current.pos;
17516 else
17517 {
17518 row_end = it->current;
17519 save_it.eol_pos.charpos = save_it.eol_pos.bytepos = 0;
17520 }
17521 }
17522 else if (!row->continued_p
17523 && MATRIX_ROW_CONTINUATION_LINE_P (row)
17524 && it->eol_pos.charpos > 0)
17525 {
17526 /* Last row of a continued line. Use the position recorded
17527 in IT->eol_pos, to the effect that the newline belongs to
17528 this row, not to the row which displays the character
17529 with the largest buffer position before the newline. */
17530 row_end.pos = it->eol_pos;
17531 it->eol_pos.charpos = it->eol_pos.bytepos = 0;
17532 }
17533 *it = save_it;
17534 /* The members of ROW->end that are not taken from buffer
17535 positions are copied from IT->current. */
17536 row_end.string_pos = it->current.string_pos;
17537 row_end.overlay_string_index = it->current.overlay_string_index;
17538 row_end.dpvec_index = it->current.dpvec_index;
17539 }
17540 return row_end;
17541}
17371 17542
17372/* Construct the glyph row IT->glyph_row in the desired matrix of 17543/* Construct the glyph row IT->glyph_row in the desired matrix of
17373 IT->w from text at the current position of IT. See dispextern.h 17544 IT->w from text at the current position of IT. See dispextern.h
@@ -17386,7 +17557,6 @@ display_line (it)
17386 int wrap_row_used = -1, wrap_row_ascent, wrap_row_height; 17557 int wrap_row_used = -1, wrap_row_ascent, wrap_row_height;
17387 int wrap_row_phys_ascent, wrap_row_phys_height; 17558 int wrap_row_phys_ascent, wrap_row_phys_height;
17388 int wrap_row_extra_line_spacing; 17559 int wrap_row_extra_line_spacing;
17389 struct display_pos row_end;
17390 int cvpos; 17560 int cvpos;
17391 17561
17392 /* We always start displaying at hpos zero even if hscrolled. */ 17562 /* We always start displaying at hpos zero even if hscrolled. */
@@ -17815,10 +17985,14 @@ display_line (it)
17815 for (i = 0; i < row->used[TEXT_AREA]; i++) 17985 for (i = 0; i < row->used[TEXT_AREA]; i++)
17816 if (!CHAR_GLYPH_PADDING_P (row->glyphs[TEXT_AREA][i])) 17986 if (!CHAR_GLYPH_PADDING_P (row->glyphs[TEXT_AREA][i]))
17817 break; 17987 break;
17818 /* Remove padding glyphs at the front of ROW, to 17988 /* Remove any padding glyphs at the front of ROW, to
17819 make room for the truncation glyphs we will be 17989 make room for the truncation glyphs we will be
17820 adding below. */ 17990 adding below. The loop below always inserts at
17821 unproduce_glyphs (it, i); 17991 least one truncation glyph, so also remove the
17992 last glyph added to ROW. */
17993 unproduce_glyphs (it, i + 1);
17994 /* Adjust i for the loop below. */
17995 i = row->used[TEXT_AREA] - (i + 1);
17822 } 17996 }
17823 17997
17824 for (n = row->used[TEXT_AREA]; i < n; ++i) 17998 for (n = row->used[TEXT_AREA]; i < n; ++i)
@@ -17910,118 +18084,13 @@ display_line (it)
17910 compute_line_metrics (it); 18084 compute_line_metrics (it);
17911 18085
17912 /* Remember the position at which this line ends. */ 18086 /* Remember the position at which this line ends. */
17913 row->end = row_end = it->current; 18087 row->end = it->current;
18088 /* ROW->start and ROW->end must be the smallest and the largest
18089 buffer positions in ROW. But if ROW was bidi-reordered, these
18090 two positions can be anywhere in the row, so we must rescan all
18091 of the ROW's glyphs to find them. */
17914 if (it->bidi_p) 18092 if (it->bidi_p)
17915 { 18093 row->end = find_row_end (it, row);
17916 /* ROW->start and ROW->end must be the smallest and largest
17917 buffer positions in ROW. But if ROW was bidi-reordered,
17918 these two positions can be anywhere in the row, so we must
17919 rescan all of the ROW's glyphs to find them. */
17920 /* FIXME: Revisit this when glyph ``spilling'' in continuation
17921 lines' rows is implemented for bidi-reordered rows. */
17922 EMACS_INT min_pos = ZV + 1, max_pos = 0;
17923 struct glyph *g;
17924 struct it save_it;
17925 struct text_pos tpos;
17926
17927 for (g = row->glyphs[TEXT_AREA];
17928 g < row->glyphs[TEXT_AREA] + row->used[TEXT_AREA];
17929 g++)
17930 {
17931 if (BUFFERP (g->object))
17932 {
17933 if (g->charpos > 0 && g->charpos < min_pos)
17934 min_pos = g->charpos;
17935 if (g->charpos > max_pos)
17936 max_pos = g->charpos;
17937 }
17938 }
17939 /* Empty lines have a valid buffer position at their first
17940 glyph, but that glyph's OBJECT is zero, as if it didn't come
17941 from a buffer. If we didn't find any valid buffer positions
17942 in this row, maybe we have such an empty line. */
17943 if (min_pos == ZV + 1 && row->used[TEXT_AREA])
17944 {
17945 for (g = row->glyphs[TEXT_AREA];
17946 g < row->glyphs[TEXT_AREA] + row->used[TEXT_AREA];
17947 g++)
17948 {
17949 if (INTEGERP (g->object))
17950 {
17951 if (g->charpos > 0 && g->charpos < min_pos)
17952 min_pos = g->charpos;
17953 if (g->charpos > max_pos)
17954 max_pos = g->charpos;
17955 }
17956 }
17957 }
17958 if (min_pos <= ZV)
17959 {
17960 if (min_pos != row->start.pos.charpos)
17961 {
17962 row->start.pos.charpos = min_pos;
17963 row->start.pos.bytepos = CHAR_TO_BYTE (min_pos);
17964 }
17965 if (max_pos == 0)
17966 max_pos = min_pos;
17967 }
17968 /* For ROW->end, we need the position that is _after_ max_pos,
17969 in the logical order, unless we are at ZV. */
17970 if (row->ends_at_zv_p)
17971 {
17972 row_end = row->end = it->current;
17973 if (!row->used[TEXT_AREA])
17974 {
17975 row->start.pos.charpos = row_end.pos.charpos;
17976 row->start.pos.bytepos = row_end.pos.bytepos;
17977 }
17978 }
17979 else if (row->used[TEXT_AREA] && max_pos)
17980 {
17981 SET_TEXT_POS (tpos, max_pos, CHAR_TO_BYTE (max_pos));
17982 save_it = *it;
17983 it->bidi_p = 0;
17984 reseat (it, tpos, 0);
17985 if (!get_next_display_element (it))
17986 abort (); /* row at ZV was already handled above */
17987 set_iterator_to_next (it, 1);
17988 row_end = it->current;
17989 /* If the character at max_pos+1 is a newline, skip that as
17990 well. Note that this may skip some invisible text. */
17991 if (get_next_display_element (it)
17992 && ITERATOR_AT_END_OF_LINE_P (it))
17993 {
17994 set_iterator_to_next (it, 1);
17995 /* Record the position after the newline of a continued
17996 row. We will need that to set ROW->end of the last
17997 row produced for a continued line. */
17998 if (row->continued_p)
17999 {
18000 save_it.eol_pos.charpos = IT_CHARPOS (*it);
18001 save_it.eol_pos.bytepos = IT_BYTEPOS (*it);
18002 }
18003 else
18004 {
18005 row_end = it->current;
18006 save_it.eol_pos.charpos = save_it.eol_pos.bytepos = 0;
18007 }
18008 }
18009 else if (!row->continued_p
18010 && MATRIX_ROW_CONTINUATION_LINE_P (row)
18011 && it->eol_pos.charpos > 0)
18012 {
18013 /* Last row of a continued line. Use the position
18014 recorded in ROW->eol_pos, to the effect that the
18015 newline belongs to this row, not to the row which
18016 displays the character with the largest buffer
18017 position. */
18018 row_end.pos = it->eol_pos;
18019 it->eol_pos.charpos = it->eol_pos.bytepos = 0;
18020 }
18021 *it = save_it;
18022 row->end = row_end;
18023 }
18024 }
18025 18094
18026 /* Record whether this row ends inside an ellipsis. */ 18095 /* Record whether this row ends inside an ellipsis. */
18027 row->ends_in_ellipsis_p 18096 row->ends_in_ellipsis_p
@@ -18075,7 +18144,7 @@ display_line (it)
18075 the flag accordingly. */ 18144 the flag accordingly. */
18076 if (it->glyph_row < MATRIX_BOTTOM_TEXT_ROW (it->w->desired_matrix, it->w)) 18145 if (it->glyph_row < MATRIX_BOTTOM_TEXT_ROW (it->w->desired_matrix, it->w))
18077 it->glyph_row->reversed_p = row->reversed_p; 18146 it->glyph_row->reversed_p = row->reversed_p;
18078 it->start = row_end; 18147 it->start = row->end;
18079 return row->displays_text_p; 18148 return row->displays_text_p;
18080} 18149}
18081 18150