diff options
| author | Eli Zaretskii | 2010-10-09 18:37:15 +0200 |
|---|---|---|
| committer | Eli Zaretskii | 2010-10-09 18:37:15 +0200 |
| commit | 2f3f89b323266e4acba71ae0e96acaf78a1584d1 (patch) | |
| tree | 0040e565425a8a592ca060421d42f261736c8e7c /src | |
| parent | e1291a3605edf76f414c7f2919b02d714d41e827 (diff) | |
| download | emacs-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/ChangeLog | 14 | ||||
| -rw-r--r-- | src/xdisp.c | 211 |
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 @@ | |||
| 1 | 2010-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 | |||
| 1 | 2010-10-02 Eli Zaretskii <eliz@gnu.org> | 15 | 2010-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. */ | ||
| 23886 | static void | ||
| 23887 | rows_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 |