aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorEli Zaretskii2011-08-02 22:16:32 +0300
committerEli Zaretskii2011-08-02 22:16:32 +0300
commit55439c615b8e04748a66a6d88ec70a9ac5acd672 (patch)
treedf8c9c478b012b4ac25c5be2cf881c9398bfe174 /src
parent0e6a2bd74efe96eb9b171aa8011b1a13db7f80df (diff)
downloademacs-55439c615b8e04748a66a6d88ec70a9ac5acd672.tar.gz
emacs-55439c615b8e04748a66a6d88ec70a9ac5acd672.zip
Fix bug #9218 with slow cursor motion and scrolling Org Mode buffers.
src/dispextern.h (struct bidi_it): New member disp_prop_p. src/xdisp.c: Remove one-slot cache of display string positions. (compute_display_string_pos): Accept an additional argument DISP_PROP_P; callers changed. Scan at most 5K characters forward for a display string or property. If found, set DISP_PROP_P non-zero. src/bidi.c (bidi_fetch_char): Accept an additional argument DISP_PROP_P, and pass it to compute_display_string_pos. Only handle text covered by a display string if DISP_PROP_P is returned non-zero. All callers of bidi_fetch_char changed.
Diffstat (limited to 'src')
-rw-r--r--src/ChangeLog18
-rw-r--r--src/bidi.c44
-rw-r--r--src/dispextern.h5
-rw-r--r--src/xdisp.c67
4 files changed, 70 insertions, 64 deletions
diff --git a/src/ChangeLog b/src/ChangeLog
index 59f09515829..3717924ff68 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,3 +1,21 @@
12011-08-02 Eli Zaretskii <eliz@gnu.org>
2
3 Fix slow cursor motion and scrolling in large buffers with
4 selective display, like Org Mode buffers. (Bug#9218)
5
6 * dispextern.h (struct bidi_it): New member disp_prop_p.
7
8 * xdisp.c: Remove one-slot cache of display string positions.
9 (compute_display_string_pos): Accept an additional argument
10 DISP_PROP_P; callers changed. Scan at most 5K characters forward
11 for a display string or property. If found, set DISP_PROP_P
12 non-zero.
13
14 * bidi.c (bidi_fetch_char): Accept an additional argument
15 DISP_PROP_P, and pass it to compute_display_string_pos. Only
16 handle text covered by a display string if DISP_PROP_P is returned
17 non-zero. All callers of bidi_fetch_char changed.
18
12011-08-02 Stefan Monnier <monnier@iro.umontreal.ca> 192011-08-02 Stefan Monnier <monnier@iro.umontreal.ca>
2 20
3 * keymap.c (Fdefine_key): Fix Lisp_Object/int mixup; apply some CSE. 21 * keymap.c (Fdefine_key): Fix Lisp_Object/int mixup; apply some CSE.
diff --git a/src/bidi.c b/src/bidi.c
index 697ebb92856..ae5143b37e0 100644
--- a/src/bidi.c
+++ b/src/bidi.c
@@ -792,6 +792,7 @@ bidi_init_it (EMACS_INT charpos, EMACS_INT bytepos, int frame_window_p,
792 bidi_it->prev_for_neutral.orig_type = UNKNOWN_BT; 792 bidi_it->prev_for_neutral.orig_type = UNKNOWN_BT;
793 bidi_it->sor = L2R; /* FIXME: should it be user-selectable? */ 793 bidi_it->sor = L2R; /* FIXME: should it be user-selectable? */
794 bidi_it->disp_pos = -1; /* invalid/unknown */ 794 bidi_it->disp_pos = -1; /* invalid/unknown */
795 bidi_it->disp_prop_p = 0;
795 /* We can only shrink the cache if we are at the bottom level of its 796 /* We can only shrink the cache if we are at the bottom level of its
796 "stack". */ 797 "stack". */
797 if (bidi_cache_start == 0) 798 if (bidi_cache_start == 0)
@@ -874,14 +875,16 @@ bidi_char_at_pos (EMACS_INT bytepos, const unsigned char *s, int unibyte)
874 covered characters as a single character u+FFFC, and return their 875 covered characters as a single character u+FFFC, and return their
875 combined length in CH_LEN and NCHARS. DISP_POS specifies the 876 combined length in CH_LEN and NCHARS. DISP_POS specifies the
876 character position of the next display string, or -1 if not yet 877 character position of the next display string, or -1 if not yet
877 computed. When the next character is at or beyond that position, 878 computed. DISP_PROP_P non-zero means that there's really a display
878 the function updates DISP_POS with the position of the next display 879 string at DISP_POS, as opposed to when we searched till DISP_POS
879 string. STRING->s is the C string to iterate, or NULL if iterating 880 without findingone. When the next character is at or beyond that
880 over a buffer or a Lisp string; in the latter case, STRING->lstring 881 position, the function updates DISP_POS with the position of the
881 is the Lisp string. */ 882 next display string. STRING->s is the C string to iterate, or NULL
883 if iterating over a buffer or a Lisp string; in the latter case,
884 STRING->lstring is the Lisp string. */
882static inline int 885static inline int
883bidi_fetch_char (EMACS_INT bytepos, EMACS_INT charpos, EMACS_INT *disp_pos, 886bidi_fetch_char (EMACS_INT bytepos, EMACS_INT charpos, EMACS_INT *disp_pos,
884 struct bidi_string_data *string, 887 int *disp_prop_p, struct bidi_string_data *string,
885 int frame_window_p, EMACS_INT *ch_len, EMACS_INT *nchars) 888 int frame_window_p, EMACS_INT *ch_len, EMACS_INT *nchars)
886{ 889{
887 int ch; 890 int ch;
@@ -894,7 +897,8 @@ bidi_fetch_char (EMACS_INT bytepos, EMACS_INT charpos, EMACS_INT *disp_pos,
894 if (charpos < endpos && charpos > *disp_pos) 897 if (charpos < endpos && charpos > *disp_pos)
895 { 898 {
896 SET_TEXT_POS (pos, charpos, bytepos); 899 SET_TEXT_POS (pos, charpos, bytepos);
897 *disp_pos = compute_display_string_pos (&pos, string, frame_window_p); 900 *disp_pos = compute_display_string_pos (&pos, string, frame_window_p,
901 disp_prop_p);
898 } 902 }
899 903
900 /* Fetch the character at BYTEPOS. */ 904 /* Fetch the character at BYTEPOS. */
@@ -904,8 +908,9 @@ bidi_fetch_char (EMACS_INT bytepos, EMACS_INT charpos, EMACS_INT *disp_pos,
904 *ch_len = 1; 908 *ch_len = 1;
905 *nchars = 1; 909 *nchars = 1;
906 *disp_pos = endpos; 910 *disp_pos = endpos;
911 *disp_prop_p = 0;
907 } 912 }
908 else if (charpos >= *disp_pos) 913 else if (charpos >= *disp_pos && *disp_prop_p)
909 { 914 {
910 EMACS_INT disp_end_pos; 915 EMACS_INT disp_end_pos;
911 916
@@ -972,10 +977,12 @@ bidi_fetch_char (EMACS_INT bytepos, EMACS_INT charpos, EMACS_INT *disp_pos,
972 977
973 /* If we just entered a run of characters covered by a display 978 /* If we just entered a run of characters covered by a display
974 string, compute the position of the next display string. */ 979 string, compute the position of the next display string. */
975 if (charpos + *nchars <= endpos && charpos + *nchars > *disp_pos) 980 if (charpos + *nchars <= endpos && charpos + *nchars > *disp_pos
981 && *disp_prop_p)
976 { 982 {
977 SET_TEXT_POS (pos, charpos + *nchars, bytepos + *ch_len); 983 SET_TEXT_POS (pos, charpos + *nchars, bytepos + *ch_len);
978 *disp_pos = compute_display_string_pos (&pos, string, frame_window_p); 984 *disp_pos = compute_display_string_pos (&pos, string, frame_window_p,
985 disp_prop_p);
979 } 986 }
980 987
981 return ch; 988 return ch;
@@ -1083,6 +1090,7 @@ bidi_paragraph_init (bidi_dir_t dir, struct bidi_it *bidi_it, int no_default_p)
1083 int ch; 1090 int ch;
1084 EMACS_INT ch_len, nchars; 1091 EMACS_INT ch_len, nchars;
1085 EMACS_INT pos, disp_pos = -1; 1092 EMACS_INT pos, disp_pos = -1;
1093 int disp_prop_p = 0;
1086 bidi_type_t type; 1094 bidi_type_t type;
1087 const unsigned char *s; 1095 const unsigned char *s;
1088 1096
@@ -1130,7 +1138,8 @@ bidi_paragraph_init (bidi_dir_t dir, struct bidi_it *bidi_it, int no_default_p)
1130 bytepos = pstartbyte; 1138 bytepos = pstartbyte;
1131 if (!string_p) 1139 if (!string_p)
1132 pos = BYTE_TO_CHAR (bytepos); 1140 pos = BYTE_TO_CHAR (bytepos);
1133 ch = bidi_fetch_char (bytepos, pos, &disp_pos, &bidi_it->string, 1141 ch = bidi_fetch_char (bytepos, pos, &disp_pos, &disp_prop_p,
1142 &bidi_it->string,
1134 bidi_it->frame_window_p, &ch_len, &nchars); 1143 bidi_it->frame_window_p, &ch_len, &nchars);
1135 type = bidi_get_type (ch, NEUTRAL_DIR); 1144 type = bidi_get_type (ch, NEUTRAL_DIR);
1136 1145
@@ -1157,7 +1166,8 @@ bidi_paragraph_init (bidi_dir_t dir, struct bidi_it *bidi_it, int no_default_p)
1157 && bidi_at_paragraph_end (pos, bytepos) >= -1) 1166 && bidi_at_paragraph_end (pos, bytepos) >= -1)
1158 break; 1167 break;
1159 /* Fetch next character and advance to get past it. */ 1168 /* Fetch next character and advance to get past it. */
1160 ch = bidi_fetch_char (bytepos, pos, &disp_pos, &bidi_it->string, 1169 ch = bidi_fetch_char (bytepos, pos, &disp_pos,
1170 &disp_prop_p, &bidi_it->string,
1161 bidi_it->frame_window_p, &ch_len, &nchars); 1171 bidi_it->frame_window_p, &ch_len, &nchars);
1162 pos += nchars; 1172 pos += nchars;
1163 bytepos += ch_len; 1173 bytepos += ch_len;
@@ -1290,6 +1300,7 @@ bidi_resolve_explicit_1 (struct bidi_it *bidi_it)
1290 bidi_it->ch_len = 1; 1300 bidi_it->ch_len = 1;
1291 bidi_it->nchars = 1; 1301 bidi_it->nchars = 1;
1292 bidi_it->disp_pos = (string_p ? bidi_it->string.schars : ZV); 1302 bidi_it->disp_pos = (string_p ? bidi_it->string.schars : ZV);
1303 bidi_it->disp_prop_p = 0;
1293 } 1304 }
1294 else 1305 else
1295 { 1306 {
@@ -1297,8 +1308,8 @@ bidi_resolve_explicit_1 (struct bidi_it *bidi_it)
1297 display string, treat the entire run of covered characters as 1308 display string, treat the entire run of covered characters as
1298 a single character u+FFFC. */ 1309 a single character u+FFFC. */
1299 curchar = bidi_fetch_char (bidi_it->bytepos, bidi_it->charpos, 1310 curchar = bidi_fetch_char (bidi_it->bytepos, bidi_it->charpos,
1300 &bidi_it->disp_pos, &bidi_it->string, 1311 &bidi_it->disp_pos, &bidi_it->disp_prop_p,
1301 bidi_it->frame_window_p, 1312 &bidi_it->string, bidi_it->frame_window_p,
1302 &bidi_it->ch_len, &bidi_it->nchars); 1313 &bidi_it->ch_len, &bidi_it->nchars);
1303 } 1314 }
1304 bidi_it->ch = curchar; 1315 bidi_it->ch = curchar;
@@ -2032,12 +2043,13 @@ bidi_level_of_next_char (struct bidi_it *bidi_it)
2032 struct bidi_string_data bs = bidi_it->string; 2043 struct bidi_string_data bs = bidi_it->string;
2033 bidi_type_t chtype; 2044 bidi_type_t chtype;
2034 int fwp = bidi_it->frame_window_p; 2045 int fwp = bidi_it->frame_window_p;
2046 int dpp = bidi_it->disp_prop_p;
2035 2047
2036 if (bidi_it->nchars <= 0) 2048 if (bidi_it->nchars <= 0)
2037 abort (); 2049 abort ();
2038 do { 2050 do {
2039 ch = bidi_fetch_char (bpos += clen, cpos += nc, &disp_pos, &bs, fwp, 2051 ch = bidi_fetch_char (bpos += clen, cpos += nc, &disp_pos, &dpp, &bs,
2040 &clen, &nc); 2052 fwp, &clen, &nc);
2041 if (ch == '\n' || ch == BIDI_EOB /* || ch == LINESEP_CHAR */) 2053 if (ch == '\n' || ch == BIDI_EOB /* || ch == LINESEP_CHAR */)
2042 chtype = NEUTRAL_B; 2054 chtype = NEUTRAL_B;
2043 else 2055 else
diff --git a/src/dispextern.h b/src/dispextern.h
index dc44c698164..2e245479a81 100644
--- a/src/dispextern.h
+++ b/src/dispextern.h
@@ -1868,6 +1868,8 @@ struct bidi_it {
1868 bidi_dir_t paragraph_dir; /* current paragraph direction */ 1868 bidi_dir_t paragraph_dir; /* current paragraph direction */
1869 EMACS_INT separator_limit; /* where paragraph separator should end */ 1869 EMACS_INT separator_limit; /* where paragraph separator should end */
1870 EMACS_INT disp_pos; /* position of display string after ch */ 1870 EMACS_INT disp_pos; /* position of display string after ch */
1871 int disp_prop_p; /* if non-zero, there really is a
1872 `display' property/string at disp_pos */
1871 unsigned first_elt : 1; /* if non-zero, examine current char first */ 1873 unsigned first_elt : 1; /* if non-zero, examine current char first */
1872 unsigned new_paragraph : 1; /* if non-zero, we expect a new paragraph */ 1874 unsigned new_paragraph : 1; /* if non-zero, we expect a new paragraph */
1873 unsigned frame_window_p : 1; /* non-zero if displaying on a GUI frame */ 1875 unsigned frame_window_p : 1; /* non-zero if displaying on a GUI frame */
@@ -3035,7 +3037,8 @@ extern Lisp_Object lookup_glyphless_char_display (int, struct it *);
3035extern int calc_pixel_width_or_height (double *, struct it *, Lisp_Object, 3037extern int calc_pixel_width_or_height (double *, struct it *, Lisp_Object,
3036 struct font *, int, int *); 3038 struct font *, int, int *);
3037extern EMACS_INT compute_display_string_pos (struct text_pos *, 3039extern EMACS_INT compute_display_string_pos (struct text_pos *,
3038 struct bidi_string_data *, int); 3040 struct bidi_string_data *,
3041 int, int *);
3039extern EMACS_INT compute_display_string_end (EMACS_INT, 3042extern EMACS_INT compute_display_string_end (EMACS_INT,
3040 struct bidi_string_data *); 3043 struct bidi_string_data *);
3041 3044
diff --git a/src/xdisp.c b/src/xdisp.c
index 9d3e501787b..fa4b3c4f9ab 100644
--- a/src/xdisp.c
+++ b/src/xdisp.c
@@ -3134,13 +3134,10 @@ next_overlay_change (EMACS_INT pos)
3134 return endpos; 3134 return endpos;
3135} 3135}
3136 3136
3137/* Record one cached display string position found recently by 3137/* How many characters forward to search for a display property or
3138 compute_display_string_pos. */ 3138 display string. Enough for a screenful of 100 lines x 50
3139static EMACS_INT cached_disp_pos; 3139 characters in a line. */
3140static EMACS_INT cached_prev_pos = -1; 3140#define MAX_DISP_SCAN 5000
3141static struct buffer *cached_disp_buffer;
3142static int cached_disp_modiff;
3143static int cached_disp_overlay_modiff;
3144 3141
3145/* Return the character position of a display string at or after 3142/* Return the character position of a display string at or after
3146 position specified by POSITION. If no display string exists at or 3143 position specified by POSITION. If no display string exists at or
@@ -3152,57 +3149,33 @@ static int cached_disp_overlay_modiff;
3152 on a GUI frame. */ 3149 on a GUI frame. */
3153EMACS_INT 3150EMACS_INT
3154compute_display_string_pos (struct text_pos *position, 3151compute_display_string_pos (struct text_pos *position,
3155 struct bidi_string_data *string, int frame_window_p) 3152 struct bidi_string_data *string,
3153 int frame_window_p, int *disp_prop_p)
3156{ 3154{
3157 /* OBJECT = nil means current buffer. */ 3155 /* OBJECT = nil means current buffer. */
3158 Lisp_Object object = 3156 Lisp_Object object =
3159 (string && STRINGP (string->lstring)) ? string->lstring : Qnil; 3157 (string && STRINGP (string->lstring)) ? string->lstring : Qnil;
3160 Lisp_Object pos, spec; 3158 Lisp_Object pos, spec, limpos;
3161 int string_p = (string && (STRINGP (string->lstring) || string->s)); 3159 int string_p = (string && (STRINGP (string->lstring) || string->s));
3162 EMACS_INT eob = string_p ? string->schars : ZV; 3160 EMACS_INT eob = string_p ? string->schars : ZV;
3163 EMACS_INT begb = string_p ? 0 : BEGV; 3161 EMACS_INT begb = string_p ? 0 : BEGV;
3164 EMACS_INT bufpos, charpos = CHARPOS (*position); 3162 EMACS_INT bufpos, charpos = CHARPOS (*position);
3163 EMACS_INT lim =
3164 (charpos < eob - MAX_DISP_SCAN) ? charpos + MAX_DISP_SCAN : eob;
3165 struct text_pos tpos; 3165 struct text_pos tpos;
3166 struct buffer *b; 3166 struct buffer *b;
3167 3167
3168 *disp_prop_p = 1;
3169
3168 if (charpos >= eob 3170 if (charpos >= eob
3169 /* We don't support display properties whose values are strings 3171 /* We don't support display properties whose values are strings
3170 that have display string properties. */ 3172 that have display string properties. */
3171 || string->from_disp_str 3173 || string->from_disp_str
3172 /* C strings cannot have display properties. */ 3174 /* C strings cannot have display properties. */
3173 || (string->s && !STRINGP (object))) 3175 || (string->s && !STRINGP (object)))
3174 return eob;
3175
3176 /* Check the cached values. */
3177 if (!STRINGP (object))
3178 { 3176 {
3179 if (NILP (object)) 3177 *disp_prop_p = 0;
3180 b = current_buffer; 3178 return eob;
3181 else
3182 b = XBUFFER (object);
3183 if (b == cached_disp_buffer
3184 && BUF_MODIFF (b) == cached_disp_modiff
3185 && BUF_OVERLAY_MODIFF (b) == cached_disp_overlay_modiff
3186 && !b->clip_changed)
3187 {
3188 if (cached_prev_pos >= 0
3189 && cached_prev_pos < charpos && charpos <= cached_disp_pos)
3190 return cached_disp_pos;
3191 /* Handle overstepping either end of the known interval. */
3192 if (charpos > cached_disp_pos)
3193 cached_prev_pos = cached_disp_pos;
3194 else /* charpos <= cached_prev_pos */
3195 cached_prev_pos = max (charpos - 1, 0);
3196 }
3197
3198 /* Record new values in the cache. */
3199 if (b != cached_disp_buffer)
3200 {
3201 cached_disp_buffer = b;
3202 cached_prev_pos = max (charpos - 1, 0);
3203 }
3204 cached_disp_modiff = BUF_MODIFF (b);
3205 cached_disp_overlay_modiff = BUF_OVERLAY_MODIFF (b);
3206 } 3179 }
3207 3180
3208 /* If the character at CHARPOS is where the display string begins, 3181 /* If the character at CHARPOS is where the display string begins,
@@ -3221,22 +3194,24 @@ compute_display_string_pos (struct text_pos *position,
3221 && handle_display_spec (NULL, spec, object, Qnil, &tpos, bufpos, 3194 && handle_display_spec (NULL, spec, object, Qnil, &tpos, bufpos,
3222 frame_window_p)) 3195 frame_window_p))
3223 { 3196 {
3224 if (!STRINGP (object))
3225 cached_disp_pos = charpos;
3226 return charpos; 3197 return charpos;
3227 } 3198 }
3228 3199
3229 /* Look forward for the first character with a `display' property 3200 /* Look forward for the first character with a `display' property
3230 that will replace the underlying text when displayed. */ 3201 that will replace the underlying text when displayed. */
3202 limpos = make_number (lim);
3231 do { 3203 do {
3232 pos = Fnext_single_char_property_change (pos, Qdisplay, object, Qnil); 3204 pos = Fnext_single_char_property_change (pos, Qdisplay, object, limpos);
3233 CHARPOS (tpos) = XFASTINT (pos); 3205 CHARPOS (tpos) = XFASTINT (pos);
3206 if (CHARPOS (tpos) >= lim)
3207 {
3208 *disp_prop_p = 0;
3209 break;
3210 }
3234 if (STRINGP (object)) 3211 if (STRINGP (object))
3235 BYTEPOS (tpos) = string_char_to_byte (object, CHARPOS (tpos)); 3212 BYTEPOS (tpos) = string_char_to_byte (object, CHARPOS (tpos));
3236 else 3213 else
3237 BYTEPOS (tpos) = CHAR_TO_BYTE (CHARPOS (tpos)); 3214 BYTEPOS (tpos) = CHAR_TO_BYTE (CHARPOS (tpos));
3238 if (CHARPOS (tpos) >= eob)
3239 break;
3240 spec = Fget_char_property (pos, Qdisplay, object); 3215 spec = Fget_char_property (pos, Qdisplay, object);
3241 if (!STRINGP (object)) 3216 if (!STRINGP (object))
3242 bufpos = CHARPOS (tpos); 3217 bufpos = CHARPOS (tpos);
@@ -3244,8 +3219,6 @@ compute_display_string_pos (struct text_pos *position,
3244 || !handle_display_spec (NULL, spec, object, Qnil, &tpos, bufpos, 3219 || !handle_display_spec (NULL, spec, object, Qnil, &tpos, bufpos,
3245 frame_window_p)); 3220 frame_window_p));
3246 3221
3247 if (!STRINGP (object))
3248 cached_disp_pos = CHARPOS (tpos);
3249 return CHARPOS (tpos); 3222 return CHARPOS (tpos);
3250} 3223}
3251 3224