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.
This commit is contained in:
Eli Zaretskii 2011-08-02 22:16:32 +03:00
parent 0e6a2bd74e
commit 55439c615b
4 changed files with 70 additions and 64 deletions

View file

@ -1,3 +1,21 @@
2011-08-02 Eli Zaretskii <eliz@gnu.org>
Fix slow cursor motion and scrolling in large buffers with
selective display, like Org Mode buffers. (Bug#9218)
* dispextern.h (struct bidi_it): New member disp_prop_p.
* 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.
* 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.
2011-08-02 Stefan Monnier <monnier@iro.umontreal.ca>
* keymap.c (Fdefine_key): Fix Lisp_Object/int mixup; apply some CSE.

View file

@ -792,6 +792,7 @@ bidi_init_it (EMACS_INT charpos, EMACS_INT bytepos, int frame_window_p,
bidi_it->prev_for_neutral.orig_type = UNKNOWN_BT;
bidi_it->sor = L2R; /* FIXME: should it be user-selectable? */
bidi_it->disp_pos = -1; /* invalid/unknown */
bidi_it->disp_prop_p = 0;
/* We can only shrink the cache if we are at the bottom level of its
"stack". */
if (bidi_cache_start == 0)
@ -874,14 +875,16 @@ bidi_char_at_pos (EMACS_INT bytepos, const unsigned char *s, int unibyte)
covered characters as a single character u+FFFC, and return their
combined length in CH_LEN and NCHARS. DISP_POS specifies the
character position of the next display string, or -1 if not yet
computed. When the next character is at or beyond that position,
the function updates DISP_POS with the position of the next display
string. STRING->s is the C string to iterate, or NULL if iterating
over a buffer or a Lisp string; in the latter case, STRING->lstring
is the Lisp string. */
computed. DISP_PROP_P non-zero means that there's really a display
string at DISP_POS, as opposed to when we searched till DISP_POS
without findingone. When the next character is at or beyond that
position, the function updates DISP_POS with the position of the
next display string. STRING->s is the C string to iterate, or NULL
if iterating over a buffer or a Lisp string; in the latter case,
STRING->lstring is the Lisp string. */
static inline int
bidi_fetch_char (EMACS_INT bytepos, EMACS_INT charpos, EMACS_INT *disp_pos,
struct bidi_string_data *string,
int *disp_prop_p, struct bidi_string_data *string,
int frame_window_p, EMACS_INT *ch_len, EMACS_INT *nchars)
{
int ch;
@ -894,7 +897,8 @@ bidi_fetch_char (EMACS_INT bytepos, EMACS_INT charpos, EMACS_INT *disp_pos,
if (charpos < endpos && charpos > *disp_pos)
{
SET_TEXT_POS (pos, charpos, bytepos);
*disp_pos = compute_display_string_pos (&pos, string, frame_window_p);
*disp_pos = compute_display_string_pos (&pos, string, frame_window_p,
disp_prop_p);
}
/* Fetch the character at BYTEPOS. */
@ -904,8 +908,9 @@ bidi_fetch_char (EMACS_INT bytepos, EMACS_INT charpos, EMACS_INT *disp_pos,
*ch_len = 1;
*nchars = 1;
*disp_pos = endpos;
*disp_prop_p = 0;
}
else if (charpos >= *disp_pos)
else if (charpos >= *disp_pos && *disp_prop_p)
{
EMACS_INT disp_end_pos;
@ -972,10 +977,12 @@ bidi_fetch_char (EMACS_INT bytepos, EMACS_INT charpos, EMACS_INT *disp_pos,
/* If we just entered a run of characters covered by a display
string, compute the position of the next display string. */
if (charpos + *nchars <= endpos && charpos + *nchars > *disp_pos)
if (charpos + *nchars <= endpos && charpos + *nchars > *disp_pos
&& *disp_prop_p)
{
SET_TEXT_POS (pos, charpos + *nchars, bytepos + *ch_len);
*disp_pos = compute_display_string_pos (&pos, string, frame_window_p);
*disp_pos = compute_display_string_pos (&pos, string, frame_window_p,
disp_prop_p);
}
return ch;
@ -1083,6 +1090,7 @@ bidi_paragraph_init (bidi_dir_t dir, struct bidi_it *bidi_it, int no_default_p)
int ch;
EMACS_INT ch_len, nchars;
EMACS_INT pos, disp_pos = -1;
int disp_prop_p = 0;
bidi_type_t type;
const unsigned char *s;
@ -1130,7 +1138,8 @@ bidi_paragraph_init (bidi_dir_t dir, struct bidi_it *bidi_it, int no_default_p)
bytepos = pstartbyte;
if (!string_p)
pos = BYTE_TO_CHAR (bytepos);
ch = bidi_fetch_char (bytepos, pos, &disp_pos, &bidi_it->string,
ch = bidi_fetch_char (bytepos, pos, &disp_pos, &disp_prop_p,
&bidi_it->string,
bidi_it->frame_window_p, &ch_len, &nchars);
type = bidi_get_type (ch, NEUTRAL_DIR);
@ -1157,7 +1166,8 @@ bidi_paragraph_init (bidi_dir_t dir, struct bidi_it *bidi_it, int no_default_p)
&& bidi_at_paragraph_end (pos, bytepos) >= -1)
break;
/* Fetch next character and advance to get past it. */
ch = bidi_fetch_char (bytepos, pos, &disp_pos, &bidi_it->string,
ch = bidi_fetch_char (bytepos, pos, &disp_pos,
&disp_prop_p, &bidi_it->string,
bidi_it->frame_window_p, &ch_len, &nchars);
pos += nchars;
bytepos += ch_len;
@ -1290,6 +1300,7 @@ bidi_resolve_explicit_1 (struct bidi_it *bidi_it)
bidi_it->ch_len = 1;
bidi_it->nchars = 1;
bidi_it->disp_pos = (string_p ? bidi_it->string.schars : ZV);
bidi_it->disp_prop_p = 0;
}
else
{
@ -1297,8 +1308,8 @@ bidi_resolve_explicit_1 (struct bidi_it *bidi_it)
display string, treat the entire run of covered characters as
a single character u+FFFC. */
curchar = bidi_fetch_char (bidi_it->bytepos, bidi_it->charpos,
&bidi_it->disp_pos, &bidi_it->string,
bidi_it->frame_window_p,
&bidi_it->disp_pos, &bidi_it->disp_prop_p,
&bidi_it->string, bidi_it->frame_window_p,
&bidi_it->ch_len, &bidi_it->nchars);
}
bidi_it->ch = curchar;
@ -2032,12 +2043,13 @@ bidi_level_of_next_char (struct bidi_it *bidi_it)
struct bidi_string_data bs = bidi_it->string;
bidi_type_t chtype;
int fwp = bidi_it->frame_window_p;
int dpp = bidi_it->disp_prop_p;
if (bidi_it->nchars <= 0)
abort ();
do {
ch = bidi_fetch_char (bpos += clen, cpos += nc, &disp_pos, &bs, fwp,
&clen, &nc);
ch = bidi_fetch_char (bpos += clen, cpos += nc, &disp_pos, &dpp, &bs,
fwp, &clen, &nc);
if (ch == '\n' || ch == BIDI_EOB /* || ch == LINESEP_CHAR */)
chtype = NEUTRAL_B;
else

View file

@ -1868,6 +1868,8 @@ struct bidi_it {
bidi_dir_t paragraph_dir; /* current paragraph direction */
EMACS_INT separator_limit; /* where paragraph separator should end */
EMACS_INT disp_pos; /* position of display string after ch */
int disp_prop_p; /* if non-zero, there really is a
`display' property/string at disp_pos */
unsigned first_elt : 1; /* if non-zero, examine current char first */
unsigned new_paragraph : 1; /* if non-zero, we expect a new paragraph */
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 *);
extern int calc_pixel_width_or_height (double *, struct it *, Lisp_Object,
struct font *, int, int *);
extern EMACS_INT compute_display_string_pos (struct text_pos *,
struct bidi_string_data *, int);
struct bidi_string_data *,
int, int *);
extern EMACS_INT compute_display_string_end (EMACS_INT,
struct bidi_string_data *);

View file

@ -3134,13 +3134,10 @@ next_overlay_change (EMACS_INT pos)
return endpos;
}
/* Record one cached display string position found recently by
compute_display_string_pos. */
static EMACS_INT cached_disp_pos;
static EMACS_INT cached_prev_pos = -1;
static struct buffer *cached_disp_buffer;
static int cached_disp_modiff;
static int cached_disp_overlay_modiff;
/* How many characters forward to search for a display property or
display string. Enough for a screenful of 100 lines x 50
characters in a line. */
#define MAX_DISP_SCAN 5000
/* Return the character position of a display string at or after
position specified by POSITION. If no display string exists at or
@ -3152,57 +3149,33 @@ static int cached_disp_overlay_modiff;
on a GUI frame. */
EMACS_INT
compute_display_string_pos (struct text_pos *position,
struct bidi_string_data *string, int frame_window_p)
struct bidi_string_data *string,
int frame_window_p, int *disp_prop_p)
{
/* OBJECT = nil means current buffer. */
Lisp_Object object =
(string && STRINGP (string->lstring)) ? string->lstring : Qnil;
Lisp_Object pos, spec;
Lisp_Object pos, spec, limpos;
int string_p = (string && (STRINGP (string->lstring) || string->s));
EMACS_INT eob = string_p ? string->schars : ZV;
EMACS_INT begb = string_p ? 0 : BEGV;
EMACS_INT bufpos, charpos = CHARPOS (*position);
EMACS_INT lim =
(charpos < eob - MAX_DISP_SCAN) ? charpos + MAX_DISP_SCAN : eob;
struct text_pos tpos;
struct buffer *b;
*disp_prop_p = 1;
if (charpos >= eob
/* We don't support display properties whose values are strings
that have display string properties. */
|| string->from_disp_str
/* C strings cannot have display properties. */
|| (string->s && !STRINGP (object)))
return eob;
/* Check the cached values. */
if (!STRINGP (object))
{
if (NILP (object))
b = current_buffer;
else
b = XBUFFER (object);
if (b == cached_disp_buffer
&& BUF_MODIFF (b) == cached_disp_modiff
&& BUF_OVERLAY_MODIFF (b) == cached_disp_overlay_modiff
&& !b->clip_changed)
{
if (cached_prev_pos >= 0
&& cached_prev_pos < charpos && charpos <= cached_disp_pos)
return cached_disp_pos;
/* Handle overstepping either end of the known interval. */
if (charpos > cached_disp_pos)
cached_prev_pos = cached_disp_pos;
else /* charpos <= cached_prev_pos */
cached_prev_pos = max (charpos - 1, 0);
}
/* Record new values in the cache. */
if (b != cached_disp_buffer)
{
cached_disp_buffer = b;
cached_prev_pos = max (charpos - 1, 0);
}
cached_disp_modiff = BUF_MODIFF (b);
cached_disp_overlay_modiff = BUF_OVERLAY_MODIFF (b);
*disp_prop_p = 0;
return eob;
}
/* If the character at CHARPOS is where the display string begins,
@ -3221,22 +3194,24 @@ compute_display_string_pos (struct text_pos *position,
&& handle_display_spec (NULL, spec, object, Qnil, &tpos, bufpos,
frame_window_p))
{
if (!STRINGP (object))
cached_disp_pos = charpos;
return charpos;
}
/* Look forward for the first character with a `display' property
that will replace the underlying text when displayed. */
limpos = make_number (lim);
do {
pos = Fnext_single_char_property_change (pos, Qdisplay, object, Qnil);
pos = Fnext_single_char_property_change (pos, Qdisplay, object, limpos);
CHARPOS (tpos) = XFASTINT (pos);
if (CHARPOS (tpos) >= lim)
{
*disp_prop_p = 0;
break;
}
if (STRINGP (object))
BYTEPOS (tpos) = string_char_to_byte (object, CHARPOS (tpos));
else
BYTEPOS (tpos) = CHAR_TO_BYTE (CHARPOS (tpos));
if (CHARPOS (tpos) >= eob)
break;
spec = Fget_char_property (pos, Qdisplay, object);
if (!STRINGP (object))
bufpos = CHARPOS (tpos);
@ -3244,8 +3219,6 @@ compute_display_string_pos (struct text_pos *position,
|| !handle_display_spec (NULL, spec, object, Qnil, &tpos, bufpos,
frame_window_p));
if (!STRINGP (object))
cached_disp_pos = CHARPOS (tpos);
return CHARPOS (tpos);
}