#define BIDI_CACHE_CHUNK 200
static struct bidi_it *bidi_cache;
-static size_t bidi_cache_size = 0;
-static size_t elsz = sizeof (struct bidi_it);
-static EMACS_INT bidi_cache_idx; /* next unused cache slot */
-static EMACS_INT bidi_cache_last_idx; /* slot of last cache hit */
-static EMACS_INT bidi_cache_start = 0; /* start of cache for this
+static ptrdiff_t bidi_cache_size = 0;
+enum { elsz = sizeof (struct bidi_it) };
+static ptrdiff_t bidi_cache_idx; /* next unused cache slot */
+static ptrdiff_t bidi_cache_last_idx; /* slot of last cache hit */
+static ptrdiff_t bidi_cache_start = 0; /* start of cache for this
"stack" level */
/* Reset the cache state to the empty state. We only reset the part
}
static inline void
-bidi_cache_fetch_state (EMACS_INT idx, struct bidi_it *bidi_it)
+bidi_cache_fetch_state (ptrdiff_t idx, struct bidi_it *bidi_it)
{
int current_scan_dir = bidi_it->scan_dir;
level less or equal to LEVEL. if LEVEL is -1, disregard the
resolved levels in cached states. DIR, if non-zero, means search
in that direction from the last cache hit. */
-static inline EMACS_INT
+static inline ptrdiff_t
bidi_cache_search (EMACS_INT charpos, int level, int dir)
{
- EMACS_INT i, i_start;
+ ptrdiff_t i, i_start;
if (bidi_cache_idx > bidi_cache_start)
{
C, searching backwards (DIR = -1) for LEVEL = 2 will return the
index of slot B or A, depending whether BEFORE is, respectively,
non-zero or zero. */
-static EMACS_INT
+static ptrdiff_t
bidi_cache_find_level_change (int level, int dir, int before)
{
if (bidi_cache_idx)
{
- EMACS_INT i = dir ? bidi_cache_last_idx : bidi_cache_idx - 1;
+ ptrdiff_t i = dir ? bidi_cache_last_idx : bidi_cache_idx - 1;
int incr = before ? 1 : 0;
xassert (!dir || bidi_cache_last_idx >= 0);
}
static inline void
-bidi_cache_ensure_space (EMACS_INT idx)
+bidi_cache_ensure_space (ptrdiff_t idx)
{
/* Enlarge the cache as needed. */
if (idx >= bidi_cache_size)
{
- while (idx >= bidi_cache_size)
- bidi_cache_size += BIDI_CACHE_CHUNK;
- bidi_cache =
- (struct bidi_it *) xrealloc (bidi_cache, bidi_cache_size * elsz);
+ ptrdiff_t new_size;
+
+ /* The bidi cache cannot be larger than the largest Lisp string
+ or buffer. */
+ ptrdiff_t string_or_buffer_bound =
+ max (BUF_BYTES_MAX, STRING_BYTES_BOUND);
+
+ /* Also, it cannot be larger than what C can represent. */
+ ptrdiff_t c_bound = min (PTRDIFF_MAX, SIZE_MAX) / elsz;
+
+ if (min (string_or_buffer_bound, c_bound) <= idx)
+ memory_full (SIZE_MAX);
+ new_size = idx - idx % BIDI_CACHE_CHUNK + BIDI_CACHE_CHUNK;
+ bidi_cache = (struct bidi_it *) xrealloc (bidi_cache, new_size * elsz);
+ bidi_cache_size = new_size;
}
}
static inline void
bidi_cache_iterator_state (struct bidi_it *bidi_it, int resolved)
{
- EMACS_INT idx;
+ ptrdiff_t idx;
/* We should never cache on backward scans. */
if (bidi_it->scan_dir == -1)
static inline bidi_type_t
bidi_cache_find (EMACS_INT charpos, int level, struct bidi_it *bidi_it)
{
- EMACS_INT i = bidi_cache_search (charpos, level, bidi_it->scan_dir);
+ ptrdiff_t i = bidi_cache_search (charpos, level, bidi_it->scan_dir);
if (i >= bidi_cache_start)
{
/* 5-slot stack for saving the start of the previous level of the
cache. xdisp.c maintains a 5-slot stack for its iterator state,
and we need the same size of our stack. */
-static EMACS_INT bidi_cache_start_stack[IT_STACK_SIZE];
+static ptrdiff_t bidi_cache_start_stack[IT_STACK_SIZE];
static int bidi_cache_sp;
/* Push the bidi iterator state in preparation for reordering a
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)
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;
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. */
*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;
/* 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;
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;
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);
&& 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;
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
{
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;
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
bidi_find_other_level_edge (struct bidi_it *bidi_it, int level, int end_flag)
{
int dir = end_flag ? -bidi_it->scan_dir : bidi_it->scan_dir;
- EMACS_INT idx;
+ ptrdiff_t idx;
/* Try the cache first. */
if ((idx = bidi_cache_find_level_change (level, dir, end_flag))
void
bidi_dump_cached_states (void)
{
- int i;
+ ptrdiff_t i;
int ndigits = 1;
if (bidi_cache_idx == 0)
fprintf (stderr, "The cache is empty.\n");
return;
}
- fprintf (stderr, "Total of %d state%s in cache:\n",
+ fprintf (stderr, "Total of %"pD"d state%s in cache:\n",
bidi_cache_idx, bidi_cache_idx == 1 ? "" : "s");
for (i = bidi_cache[bidi_cache_idx - 1].charpos; i > 0; i /= 10)