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:
parent
0e6a2bd74e
commit
55439c615b
4 changed files with 70 additions and 64 deletions
|
@ -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.
|
||||
|
|
44
src/bidi.c
44
src/bidi.c
|
@ -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
|
||||
|
|
|
@ -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 *);
|
||||
|
||||
|
|
67
src/xdisp.c
67
src/xdisp.c
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue