aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorEli Zaretskii2010-10-09 18:37:15 +0200
committerEli Zaretskii2010-10-09 18:37:15 +0200
commit2f3f89b323266e4acba71ae0e96acaf78a1584d1 (patch)
tree0040e565425a8a592ca060421d42f261736c8e7c /src
parente1291a3605edf76f414c7f2919b02d714d41e827 (diff)
downloademacs-2f3f89b323266e4acba71ae0e96acaf78a1584d1.tar.gz
emacs-2f3f89b323266e4acba71ae0e96acaf78a1584d1.zip
Finished work on mouse_face_from_buffer_pos for bidi-reordered rows.
Need lots of testing, including bug#1220. Next task: get rid of fast_find_position, call mouse_face_from_buffer_pos instead. xdisp.c (rows_from_pos_range): New function. (mouse_face_from_buffer_pos): Use it instead of calling row_containing_pos for START_CHARPOS and END_CHARPOS. (note_mouse_highlight): When bidi reordering is turned on in a buffer, call next-single-property-change and previous-single-property-change with last argument nil.
Diffstat (limited to 'src')
-rw-r--r--src/ChangeLog14
-rw-r--r--src/xdisp.c211
2 files changed, 178 insertions, 47 deletions
diff --git a/src/ChangeLog b/src/ChangeLog
index 25649a1a83b..3a1e0810d41 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,3 +1,17 @@
12010-10-09 Eli Zaretskii <eliz@gnu.org>
2
3 Finished work on mouse_face_from_buffer_pos for bidi-reordered
4 rows. Need lots of testing, including bug#1220.
5 Next task: get rid of fast_find_position, call
6 mouse_face_from_buffer_pos instead.
7
8 * xdisp.c (rows_from_pos_range): New function.
9 (mouse_face_from_buffer_pos): Use it instead of calling
10 row_containing_pos for START_CHARPOS and END_CHARPOS.
11 (note_mouse_highlight): When bidi reordering is turned on in a
12 buffer, call next-single-property-change and
13 previous-single-property-change with last argument nil.
14
12010-10-02 Eli Zaretskii <eliz@gnu.org> 152010-10-02 Eli Zaretskii <eliz@gnu.org>
2 16
3 * xdisp.c (coords_in_mouse_face_p): Fix the conditions for when 17 * xdisp.c (coords_in_mouse_face_p): Fix the conditions for when
diff --git a/src/xdisp.c b/src/xdisp.c
index eeea4cb4333..9f39046b1f5 100644
--- a/src/xdisp.c
+++ b/src/xdisp.c
@@ -23878,6 +23878,129 @@ cursor_in_mouse_face_p (struct window *w)
23878 23878
23879 23879
23880 23880
23881/* Find the glyph rows START_ROW and END_ROW of window W that display
23882 characters between buffer positions START_CHARPOS and END_CHARPOS
23883 (excluding END_CHARPOS). This is similar to row_containing_pos,
23884 but is more accurate when bidi reordering makes buffer positions
23885 change non-linearly with glyph rows. */
23886static void
23887rows_from_pos_range (struct window *w,
23888 EMACS_INT start_charpos, EMACS_INT end_charpos,
23889 struct glyph_row **start, struct glyph_row **end)
23890{
23891 struct glyph_row *first = MATRIX_FIRST_TEXT_ROW (w->current_matrix);
23892 int last_y = window_text_bottom_y (w);
23893 struct glyph_row *row;
23894
23895 *start = NULL;
23896 *end = NULL;
23897
23898 while (!first->enabled_p
23899 && first < MATRIX_BOTTOM_TEXT_ROW (w->current_matrix, w))
23900 first++;
23901
23902 /* Find the START row. */
23903 for (row = first;
23904 row->enabled_p && MATRIX_ROW_BOTTOM_Y (row) <= last_y;
23905 row++)
23906 {
23907 /* A row can potentially be the START row if the range of the
23908 characters it displays intersects the range
23909 [START_CHARPOS..END_CHARPOS). */
23910 if (! ((start_charpos < MATRIX_ROW_START_CHARPOS (row)
23911 && end_charpos < MATRIX_ROW_START_CHARPOS (row))
23912 /* See the commentary in row_containing_pos, for the
23913 explanation of the complicated way to check whether
23914 some position is beyond the end of the characters
23915 displayed by a row. */
23916 || ((start_charpos > MATRIX_ROW_END_CHARPOS (row)
23917 || (start_charpos == MATRIX_ROW_END_CHARPOS (row)
23918 && !row->ends_at_zv_p
23919 && !MATRIX_ROW_ENDS_IN_MIDDLE_OF_CHAR_P (row)))
23920 && (end_charpos > MATRIX_ROW_END_CHARPOS (row)
23921 || (end_charpos == MATRIX_ROW_END_CHARPOS (row)
23922 && !row->ends_at_zv_p
23923 && !MATRIX_ROW_ENDS_IN_MIDDLE_OF_CHAR_P (row))))))
23924 {
23925 /* Found a candidate row. Now make sure at least one of the
23926 glyphs it displays has a charpos from the range
23927 [START_CHARPOS..END_CHARPOS).
23928
23929 This is not obvious because bidi reordering could have
23930 buffer positions of a row be 1,2,3,102,101,100, and if we
23931 want to highlight characters in [50..60), we don't want
23932 this row, even though [50..60) does intersect [1..103),
23933 the range of character positions given by the row's start
23934 and end positions. */
23935 struct glyph *g = row->glyphs[TEXT_AREA];
23936 struct glyph *e = g + row->used[TEXT_AREA];
23937
23938 while (g < e)
23939 {
23940 if (BUFFERP (g->object)
23941 && start_charpos <= g->charpos && g->charpos < end_charpos)
23942 *start = row;
23943 g++;
23944 }
23945 if (*start)
23946 break;
23947 }
23948 }
23949
23950 /* Find the END row. */
23951 if (!*start
23952 /* If the last row is partially visible, start looking for END
23953 from that row, instead of starting from FIRST. */
23954 && !(row->enabled_p
23955 && row->y < last_y && MATRIX_ROW_BOTTOM_Y (row) > last_y))
23956 row = first;
23957 for ( ; row->enabled_p && MATRIX_ROW_BOTTOM_Y (row) <= last_y; row++)
23958 {
23959 struct glyph_row *next = row + 1;
23960
23961 if (!next->enabled_p
23962 || next >= MATRIX_BOTTOM_TEXT_ROW (w->current_matrix, w)
23963 /* The first row >= START whose range of displayed characters
23964 does NOT intersect the range [START_CHARPOS..END_CHARPOS]
23965 is the row END + 1. */
23966 || (start_charpos < MATRIX_ROW_START_CHARPOS (next)
23967 && end_charpos < MATRIX_ROW_START_CHARPOS (next))
23968 || ((start_charpos > MATRIX_ROW_END_CHARPOS (next)
23969 || (start_charpos == MATRIX_ROW_END_CHARPOS (next)
23970 && !next->ends_at_zv_p
23971 && !MATRIX_ROW_ENDS_IN_MIDDLE_OF_CHAR_P (next)))
23972 && (end_charpos > MATRIX_ROW_END_CHARPOS (next)
23973 || (end_charpos == MATRIX_ROW_END_CHARPOS (next)
23974 && !next->ends_at_zv_p
23975 && !MATRIX_ROW_ENDS_IN_MIDDLE_OF_CHAR_P (next)))))
23976 {
23977 *end = row;
23978 break;
23979 }
23980 else
23981 {
23982 /* If the next row's edges intersect [START_CHARPOS..END_CHARPOS],
23983 but none of the characters it displays are in the range, it is
23984 also END + 1. */
23985 struct glyph *g = next->glyphs[TEXT_AREA];
23986 struct glyph *e = g + next->used[TEXT_AREA];
23987
23988 while (g < e)
23989 {
23990 if (BUFFERP (g->object)
23991 && start_charpos <= g->charpos && g->charpos < end_charpos)
23992 break;
23993 g++;
23994 }
23995 if (g == e)
23996 {
23997 *end = row;
23998 break;
23999 }
24000 }
24001 }
24002}
24003
23881/* This function sets the mouse_face_* elements of DPYINFO, assuming 24004/* This function sets the mouse_face_* elements of DPYINFO, assuming
23882 the mouse cursor is on a glyph with buffer charpos MOUSE_CHARPOS in 24005 the mouse cursor is on a glyph with buffer charpos MOUSE_CHARPOS in
23883 window WINDOW. START_CHARPOS and END_CHARPOS are buffer positions 24006 window WINDOW. START_CHARPOS and END_CHARPOS are buffer positions
@@ -23903,56 +24026,39 @@ mouse_face_from_buffer_pos (Lisp_Object window,
23903 struct glyph *glyph, *end; 24026 struct glyph *glyph, *end;
23904 EMACS_INT ignore, pos; 24027 EMACS_INT ignore, pos;
23905 int x; 24028 int x;
23906 int beg_set = 0;
23907 24029
23908 xassert (NILP (display_string) || STRINGP (display_string)); 24030 xassert (NILP (display_string) || STRINGP (display_string));
23909 xassert (NILP (before_string) || STRINGP (before_string)); 24031 xassert (NILP (before_string) || STRINGP (before_string));
23910 xassert (NILP (after_string) || STRINGP (after_string)); 24032 xassert (NILP (after_string) || STRINGP (after_string));
23911 24033
23912 /* Find the row with START_CHARPOS. */
23913 /* FIXME: Sometimes the caller gets "wise" and gives us the window 24034 /* FIXME: Sometimes the caller gets "wise" and gives us the window
23914 start position instead of the real start of the mouse face 24035 start position instead of the real start of the mouse face
23915 property. This completely messes up the logic of finding the 24036 property. This completely messes up the logic of finding the
23916 beg_row and end_row. */ 24037 beg_row and end_row. */
23917 if (start_charpos < MATRIX_ROW_START_CHARPOS (first)
23918 && (NILP (XBUFFER (w->buffer)->bidi_display_reordering)
23919 || row_containing_pos (w, start_charpos, first, NULL, 0) == NULL))
23920 {
23921 dpyinfo->mouse_face_beg_col = 0;
23922 dpyinfo->mouse_face_beg_row = MATRIX_ROW_VPOS (first, w->current_matrix);
23923 dpyinfo->mouse_face_beg_x = first->x;
23924 dpyinfo->mouse_face_beg_y = first->y;
23925 beg_set = 1;
23926 }
23927 else
23928 {
23929 r1 = row_containing_pos (w, start_charpos, first, NULL, 0);
23930 if (r1 == NULL)
23931 r1 = MATRIX_ROW (w->current_matrix, XFASTINT (w->window_end_vpos));
23932 24038
23933 /* If the before-string or display-string contains newlines, 24039 /* Find the rows corresponding to START_CHARPOS and END_CHARPOS. */
23934 row_containing_pos skips to its last row. Move back. */ 24040 rows_from_pos_range (w, start_charpos, end_charpos, &r1, &r2);
23935 if (!NILP (before_string) || !NILP (display_string)) 24041 if (r1 == NULL)
23936 { 24042 r1 = MATRIX_ROW (w->current_matrix, XFASTINT (w->window_end_vpos));
23937 struct glyph_row *prev; 24043 /* If the before-string or display-string contains newlines,
23938 while ((prev = r1 - 1, prev >= first) 24044 row_containing_pos skips to its last row. Move back. */
23939 && MATRIX_ROW_END_CHARPOS (prev) == start_charpos 24045 if (!NILP (before_string) || !NILP (display_string))
23940 && prev->used[TEXT_AREA] > 0) 24046 {
23941 { 24047 struct glyph_row *prev;
23942 struct glyph *beg = prev->glyphs[TEXT_AREA]; 24048 while ((prev = r1 - 1, prev >= first)
23943 glyph = beg + prev->used[TEXT_AREA]; 24049 && MATRIX_ROW_END_CHARPOS (prev) == start_charpos
23944 while (--glyph >= beg && INTEGERP (glyph->object)); 24050 && prev->used[TEXT_AREA] > 0)
23945 if (glyph < beg 24051 {
23946 || !(EQ (glyph->object, before_string) 24052 struct glyph *beg = prev->glyphs[TEXT_AREA];
23947 || EQ (glyph->object, display_string))) 24053 glyph = beg + prev->used[TEXT_AREA];
23948 break; 24054 while (--glyph >= beg && INTEGERP (glyph->object));
23949 r1 = prev; 24055 if (glyph < beg
23950 } 24056 || !(EQ (glyph->object, before_string)
24057 || EQ (glyph->object, display_string)))
24058 break;
24059 r1 = prev;
23951 } 24060 }
23952 } 24061 }
23953
23954 /* Find the row with END_CHARPOS. */
23955 r2 = row_containing_pos (w, end_charpos, first, NULL, 0);
23956 if (r2 == NULL) 24062 if (r2 == NULL)
23957 { 24063 {
23958 r2 = MATRIX_ROW (w->current_matrix, XFASTINT (w->window_end_vpos)); 24064 r2 = MATRIX_ROW (w->current_matrix, XFASTINT (w->window_end_vpos));
@@ -23972,7 +24078,6 @@ mouse_face_from_buffer_pos (Lisp_Object window,
23972 ++next) 24078 ++next)
23973 r2 = next; 24079 r2 = next;
23974 } 24080 }
23975
23976 /* The rest of the display engine assumes that mouse_face_beg_row is 24081 /* The rest of the display engine assumes that mouse_face_beg_row is
23977 either above below mouse_face_end_row or identical to it. But 24082 either above below mouse_face_end_row or identical to it. But
23978 with bidi-reordered continued lines, the row for START_CHARPOS 24083 with bidi-reordered continued lines, the row for START_CHARPOS
@@ -23985,6 +24090,7 @@ mouse_face_from_buffer_pos (Lisp_Object window,
23985 r2 = r1; 24090 r2 = r1;
23986 r1 = tem; 24091 r1 = tem;
23987 } 24092 }
24093
23988 dpyinfo->mouse_face_beg_y = r1->y; 24094 dpyinfo->mouse_face_beg_y = r1->y;
23989 dpyinfo->mouse_face_beg_row = MATRIX_ROW_VPOS (r1, w->current_matrix); 24095 dpyinfo->mouse_face_beg_row = MATRIX_ROW_VPOS (r1, w->current_matrix);
23990 dpyinfo->mouse_face_end_y = r2->y; 24096 dpyinfo->mouse_face_end_y = r2->y;
@@ -24000,9 +24106,7 @@ mouse_face_from_buffer_pos (Lisp_Object window,
24000 between START_CHARPOS and END_CHARPOS if the range of characters 24106 between START_CHARPOS and END_CHARPOS if the range of characters
24001 strides the bidi level boundary, e.g. if the beginning is in R2L 24107 strides the bidi level boundary, e.g. if the beginning is in R2L
24002 text while the end is in L2R text or vice versa. */ 24108 text while the end is in L2R text or vice versa. */
24003 if (beg_set) 24109 if (!r1->reversed_p)
24004 ;
24005 else if (!r1->reversed_p)
24006 { 24110 {
24007 /* This row is in a left to right paragraph. Scan it left to 24111 /* This row is in a left to right paragraph. Scan it left to
24008 right. */ 24112 right. */
@@ -25027,17 +25131,30 @@ note_mouse_highlight (struct frame *f, int x, int y)
25027 { 25131 {
25028 Lisp_Object before, after; 25132 Lisp_Object before, after;
25029 Lisp_Object before_string, after_string; 25133 Lisp_Object before_string, after_string;
25134 /* To correctly find the limits of mouse highlight
25135 in a bidi-reordered buffer, we must not use the
25136 optimization of limiting the search in
25137 previous-single-property-change and
25138 next-single-property-change, because
25139 rows_from_pos_range needs the real start and end
25140 positions to DTRT in this case. */
25141 Lisp_Object lim1 =
25142 NILP (XBUFFER (buffer)->bidi_display_reordering)
25143 ? Fmarker_position (w->start)
25144 : Qnil;
25145 Lisp_Object lim2 =
25146 NILP (XBUFFER (buffer)->bidi_display_reordering)
25147 ? make_number (BUF_Z (XBUFFER (buffer))
25148 - XFASTINT (w->window_end_pos))
25149 : Qnil;
25030 25150
25031 if (NILP (overlay)) 25151 if (NILP (overlay))
25032 { 25152 {
25033 /* Handle the text property case. */ 25153 /* Handle the text property case. */
25034 before = Fprevious_single_property_change 25154 before = Fprevious_single_property_change
25035 (make_number (pos + 1), Qmouse_face, buffer, 25155 (make_number (pos + 1), Qmouse_face, buffer, lim1);
25036 Fmarker_position (w->start));
25037 after = Fnext_single_property_change 25156 after = Fnext_single_property_change
25038 (make_number (pos), Qmouse_face, buffer, 25157 (make_number (pos), Qmouse_face, buffer, lim2);
25039 make_number (BUF_Z (XBUFFER (buffer))
25040 - XFASTINT (w->window_end_pos)));
25041 before_string = after_string = Qnil; 25158 before_string = after_string = Qnil;
25042 } 25159 }
25043 else 25160 else