argument.
Iteration over things to be displayed is then simple. It is
- started by initializing an iterator with a call to init_iterator.
- Calls to get_next_display_element fill the iterator structure with
- relevant information about the next thing to display. Calls to
+ started by initializing an iterator with a call to init_iterator,
+ passing it the buffer position where to start iteration. For
+ iteration over strings, pass -1 as the position to init_iterator,
+ and call reseat_to_string when the string is ready, to initialize
+ the iterator for that string. Thereafter, calls to
+ get_next_display_element fill the iterator structure with relevant
+ information about the next thing to display. Calls to
set_iterator_to_next move the iterator to the next thing.
Besides this, an iterator also contains information about the
#define TEXT_PROP_DISTANCE_LIMIT 100
+/* SAVE_IT and RESTORE_IT are called when we save a snapshot of the
+ iterator state and later restore it. This is needed because the
+ bidi iterator on bidi.c keeps a stacked cache of its states, which
+ is really a singleton. When we use scratch iterator objects to
+ move around the buffer, we can cause the bidi cache to be pushed or
+ popped, and therefore we need to restore the cache state when we
+ return to the original iterator. */
+#define SAVE_IT(ITCOPY,ITORIG,CACHE) \
+ do { \
+ if (CACHE) \
+ xfree (CACHE); \
+ ITCOPY = ITORIG; \
+ CACHE = bidi_shelve_cache(); \
+ } while (0)
+
+#define RESTORE_IT(pITORIG,pITCOPY,CACHE) \
+ do { \
+ if (pITORIG != pITCOPY) \
+ *(pITORIG) = *(pITCOPY); \
+ bidi_unshelve_cache (CACHE); \
+ CACHE = NULL; \
+ } while (0)
+
#if GLYPH_DEBUG
/* Non-zero means print traces of redisplay if compiled with
static int try_scrolling (Lisp_Object, int, EMACS_INT, EMACS_INT, int, int);
static int try_cursor_movement (Lisp_Object, struct text_pos, int *);
static int trailing_whitespace_p (EMACS_INT);
-static unsigned long int message_log_check_duplicate (EMACS_INT, EMACS_INT);
+static intmax_t message_log_check_duplicate (EMACS_INT, EMACS_INT);
static void push_it (struct it *, struct text_pos *);
static void pop_it (struct it *);
static void sync_frame_with_window_matrix_rows (struct window *);
int *rtop, int *rbot, int *rowh, int *vpos)
{
struct it it;
+ void *itdata = bidi_shelve_cache ();
struct text_pos top;
int visible_p = 0;
struct buffer *old_buffer = NULL;
move_it_to (&it, charpos, -1, it.last_visible_y-1, -1,
(charpos >= 0 ? MOVE_TO_POS : 0) | MOVE_TO_Y);
- if (charpos >= 0 && IT_CHARPOS (it) >= charpos)
+ if (charpos >= 0
+ && (((!it.bidi_p || it.bidi_it.scan_dir == 1)
+ && IT_CHARPOS (it) >= charpos)
+ /* When scanning backwards under bidi iteration, move_it_to
+ stops at or _before_ CHARPOS, because it stops at or to
+ the _right_ of the character at CHARPOS. */
+ || (it.bidi_p && it.bidi_it.scan_dir == -1
+ && IT_CHARPOS (it) <= charpos)))
{
/* We have reached CHARPOS, or passed it. How the call to
- move_it_to can overshoot: (i) If CHARPOS is on invisible
- text, move_it_to stops at the end of the invisible text,
- after CHARPOS. (ii) If CHARPOS is in a display vector,
- move_it_to stops on its last glyph. */
+ move_it_to can overshoot: (i) If CHARPOS is on invisible text
+ or covered by a display property, move_it_to stops at the end
+ of the invisible text, to the right of CHARPOS. (ii) If
+ CHARPOS is in a display vector, move_it_to stops on its last
+ glyph. */
int top_x = it.current_x;
int top_y = it.current_y;
enum it_method it_method = it.method;
}
else
{
+ /* We were asked to provide info about WINDOW_END. */
struct it it2;
+ void *it2data = NULL;
- it2 = it;
+ SAVE_IT (it2, it, it2data);
if (IT_CHARPOS (it) < ZV && FETCH_BYTE (IT_BYTEPOS (it)) != '\n')
move_it_by_lines (&it, 1);
if (charpos < IT_CHARPOS (it)
|| (it.what == IT_EOB && charpos == IT_CHARPOS (it)))
{
visible_p = 1;
+ RESTORE_IT (&it2, &it2, it2data);
move_it_to (&it2, charpos, -1, -1, -1, MOVE_TO_POS);
*x = it2.current_x;
*y = it2.current_y + it2.max_ascent - it2.ascent;
WINDOW_HEADER_LINE_HEIGHT (w))));
*vpos = it2.vpos;
}
+ else
+ xfree (it2data);
}
+ bidi_unshelve_cache (itdata);
if (old_buffer)
set_buffer_internal_1 (old_buffer);
This is for debugging. It is too slow to do unconditionally. */
static void
-check_it (it)
- struct it *it;
+check_it (struct it *it)
{
if (it->method == GET_FROM_STRING)
{
#endif /* not 0 */
-#if GLYPH_DEBUG
+#if GLYPH_DEBUG && XASSERTS
/* Check that the window end of window W is what we expect it
to be---the last row in the current matrix displaying text. */
static void
-check_window_end (w)
- struct window *w;
+check_window_end (struct window *w)
{
if (!MINI_WINDOW_P (w)
&& !NILP (w->window_end_valid))
#define CHECK_WINDOW_END(W) check_window_end ((W))
-#else /* not GLYPH_DEBUG */
+#else
#define CHECK_WINDOW_END(W) (void) 0
-#endif /* not GLYPH_DEBUG */
+#endif
\f
it->base_face_id = remapped_base_face_id;
it->string = Qnil;
IT_STRING_CHARPOS (*it) = IT_STRING_BYTEPOS (*it) = -1;
+ it->paragraph_embedding = L2R;
+ it->bidi_it.string.lstring = Qnil;
+ it->bidi_it.string.s = NULL;
+ it->bidi_it.string.bufpos = 0;
/* The window in which we iterate over current_buffer: */
XSETWINDOW (it->window, w);
is invisible. >0 means lines indented more than this value are
invisible. */
it->selective = (INTEGERP (BVAR (current_buffer, selective_display))
- ? XFASTINT (BVAR (current_buffer, selective_display))
+ ? XINT (BVAR (current_buffer, selective_display))
: (!NILP (BVAR (current_buffer, selective_display))
? -1 : 0));
it->selective_display_ellipsis_p
/* Are multibyte characters enabled in current_buffer? */
it->multibyte_p = !NILP (BVAR (current_buffer, enable_multibyte_characters));
- /* Do we need to reorder bidirectional text? Not if this is a
- unibyte buffer: by definition, none of the single-byte characters
- are strong R2L, so no reordering is needed. And bidi.c doesn't
- support unibyte buffers anyway. */
- it->bidi_p
- = !NILP (BVAR (current_buffer, bidi_display_reordering)) && it->multibyte_p;
-
/* Non-zero if we should highlight the region. */
highlight_region_p
= (!NILP (Vtransient_mark_mode)
else if (INTEGERP (w->redisplay_end_trigger))
it->redisplay_end_trigger_charpos = XINT (w->redisplay_end_trigger);
- /* Correct bogus values of tab_width. */
- it->tab_width = XINT (BVAR (current_buffer, tab_width));
- if (it->tab_width <= 0 || it->tab_width > 1000)
- it->tab_width = 8;
+ it->tab_width = SANE_TAB_WIDTH (current_buffer);
/* Are lines in the display truncated? */
if (base_face_id != DEFAULT_FACE_ID
it->start_of_box_run_p = 1;
}
- /* If we are to reorder bidirectional text, init the bidi
- iterator. */
- if (it->bidi_p)
- {
- /* Note the paragraph direction that this buffer wants to
- use. */
- if (EQ (BVAR (current_buffer, bidi_paragraph_direction), Qleft_to_right))
- it->paragraph_embedding = L2R;
- else if (EQ (BVAR (current_buffer, bidi_paragraph_direction), Qright_to_left))
- it->paragraph_embedding = R2L;
- else
- it->paragraph_embedding = NEUTRAL_DIR;
- bidi_init_it (charpos, bytepos, FRAME_WINDOW_P (it->f), &it->bidi_it);
- }
-
/* If a buffer position was specified, set the iterator there,
getting overlays and face properties from that position. */
if (charpos >= BUF_BEG (current_buffer))
IT_BYTEPOS (*it) = bytepos;
it->start = it->current;
+ /* Do we need to reorder bidirectional text? Not if this is a
+ unibyte buffer: by definition, none of the single-byte
+ characters are strong R2L, so no reordering is needed. And
+ bidi.c doesn't support unibyte buffers anyway. */
+ it->bidi_p =
+ !NILP (BVAR (current_buffer, bidi_display_reordering))
+ && it->multibyte_p;
+
+ /* If we are to reorder bidirectional text, init the bidi
+ iterator. */
+ if (it->bidi_p)
+ {
+ /* Note the paragraph direction that this buffer wants to
+ use. */
+ if (EQ (BVAR (current_buffer, bidi_paragraph_direction),
+ Qleft_to_right))
+ it->paragraph_embedding = L2R;
+ else if (EQ (BVAR (current_buffer, bidi_paragraph_direction),
+ Qright_to_left))
+ it->paragraph_embedding = R2L;
+ else
+ it->paragraph_embedding = NEUTRAL_DIR;
+ bidi_unshelve_cache (NULL);
+ bidi_init_it (charpos, IT_BYTEPOS (*it), FRAME_WINDOW_P (it->f),
+ &it->bidi_it);
+ }
/* Compute faces etc. */
reseat (it, it->current.pos, 1);
{
it->ignore_overlay_strings_at_pos_p = 1;
it->string_from_display_prop_p = 0;
+ it->from_disp_prop_p = 0;
handle_overlay_change_p = 0;
}
handled = HANDLED_RECOMPUTE_PROPS;
static EMACS_INT
next_overlay_change (EMACS_INT pos)
{
- int noverlays;
+ ptrdiff_t i, noverlays;
EMACS_INT endpos;
Lisp_Object *overlays;
- int i;
/* Get all overlays at the given position. */
GET_OVERLAYS_AT (pos, overlays, noverlays, &endpos, 1);
return endpos;
}
-/* Return the character position of a display string at or after CHARPOS.
- If no display string exists at or after CHARPOS, return ZV. A
- display string is either an overlay with `display' property whose
- value is a string, or a `display' text property whose value is a
- string. FRAME_WINDOW_P is non-zero when we are displaying a window
+/* 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;
+
+/* Return the character position of a display string at or after
+ position specified by POSITION. If no display string exists at or
+ after POSITION, return ZV. A display string is either an overlay
+ with `display' property whose value is a string, or a `display'
+ text property whose value is a string. STRING is data about the
+ string to iterate; if STRING->lstring is nil, we are iterating a
+ buffer. FRAME_WINDOW_P is non-zero when we are displaying a window
on a GUI frame. */
EMACS_INT
-compute_display_string_pos (EMACS_INT charpos, int frame_window_p)
+compute_display_string_pos (struct text_pos *position,
+ struct bidi_string_data *string, int frame_window_p)
{
- /* FIXME: Support display properties on strings (object = Qnil means
- current buffer). */
- Lisp_Object object = Qnil;
+ /* OBJECT = nil means current buffer. */
+ Lisp_Object object =
+ (string && STRINGP (string->lstring)) ? string->lstring : Qnil;
Lisp_Object pos, spec;
- struct text_pos position;
- EMACS_INT bufpos;
+ 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);
+ struct text_pos tpos;
+ struct buffer *b;
+
+ 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;
- if (charpos >= ZV)
- return ZV;
+ /* 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);
+ }
/* If the character at CHARPOS is where the display string begins,
return CHARPOS. */
pos = make_number (charpos);
- CHARPOS (position) = charpos;
- BYTEPOS (position) = CHAR_TO_BYTE (charpos);
- bufpos = charpos; /* FIXME! support strings as well */
+ if (STRINGP (object))
+ bufpos = string->bufpos;
+ else
+ bufpos = charpos;
+ tpos = *position;
if (!NILP (spec = Fget_char_property (pos, Qdisplay, object))
- && (charpos <= BEGV
+ && (charpos <= begb
|| !EQ (Fget_char_property (make_number (charpos - 1), Qdisplay,
object),
spec))
- && handle_display_spec (NULL, spec, object, Qnil, &position, bufpos,
+ && handle_display_spec (NULL, spec, object, Qnil, &tpos, bufpos,
frame_window_p))
- return charpos;
+ {
+ 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. */
do {
pos = Fnext_single_char_property_change (pos, Qdisplay, object, Qnil);
- CHARPOS (position) = XFASTINT (pos);
- BYTEPOS (position) = CHAR_TO_BYTE (CHARPOS (position));
- if (CHARPOS (position) >= ZV)
+ CHARPOS (tpos) = XFASTINT (pos);
+ 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);
- bufpos = CHARPOS (position); /* FIXME! support strings as well */
+ if (!STRINGP (object))
+ bufpos = CHARPOS (tpos);
} while (NILP (spec)
- || !handle_display_spec (NULL, spec, object, Qnil, &position, bufpos,
+ || !handle_display_spec (NULL, spec, object, Qnil, &tpos, bufpos,
frame_window_p));
- return CHARPOS (position);
+ if (!STRINGP (object))
+ cached_disp_pos = CHARPOS (tpos);
+ return CHARPOS (tpos);
}
/* Return the character position of the end of the display string that
`display' property whose value is a string or a `display' text
property whose value is a string. */
EMACS_INT
-compute_display_string_end (EMACS_INT charpos)
+compute_display_string_end (EMACS_INT charpos, struct bidi_string_data *string)
{
- /* FIXME: Support display properties on strings (object = Qnil means
- current buffer). */
- Lisp_Object object = Qnil;
+ /* OBJECT = nil means current buffer. */
+ Lisp_Object object =
+ (string && STRINGP (string->lstring)) ? string->lstring : Qnil;
Lisp_Object pos = make_number (charpos);
+ EMACS_INT eob =
+ (STRINGP (object) || (string && string->s)) ? string->schars : ZV;
- if (charpos >= ZV)
- return ZV;
+ if (charpos >= eob || (string->s && !STRINGP (object)))
+ return eob;
if (NILP (Fget_char_property (pos, Qdisplay, object)))
abort ();
/* Compute the face one character before or after the current position
- of IT. BEFORE_P non-zero means get the face in front of IT's
- position. Value is the id of the face. */
+ of IT, in the visual order. BEFORE_P non-zero means get the face
+ in front (to the left in L2R paragraphs, to the right in R2L
+ paragraphs) of IT's screen position. Value is the ID of the face. */
static int
face_before_or_after_it_pos (struct it *it, int before_p)
{
int face_id, limit;
EMACS_INT next_check_charpos;
- struct text_pos pos;
+ struct it it_copy;
+ void *it_copy_data = NULL;
xassert (it->s == NULL);
if (STRINGP (it->string))
{
- EMACS_INT bufpos;
+ EMACS_INT bufpos, charpos;
int base_face_id;
/* No face change past the end of the string (for the case
|| (IT_STRING_CHARPOS (*it) == 0 && before_p))
return it->face_id;
- /* Set pos to the position before or after IT's current position. */
- if (before_p)
- pos = string_pos (IT_STRING_CHARPOS (*it) - 1, it->string);
+ if (!it->bidi_p)
+ {
+ /* Set charpos to the position before or after IT's current
+ position, in the logical order, which in the non-bidi
+ case is the same as the visual order. */
+ if (before_p)
+ charpos = IT_STRING_CHARPOS (*it) - 1;
+ else if (it->what == IT_COMPOSITION)
+ /* For composition, we must check the character after the
+ composition. */
+ charpos = IT_STRING_CHARPOS (*it) + it->cmp_it.nchars;
+ else
+ charpos = IT_STRING_CHARPOS (*it) + 1;
+ }
else
- /* For composition, we must check the character after the
- composition. */
- pos = (it->what == IT_COMPOSITION
- ? string_pos (IT_STRING_CHARPOS (*it)
- + it->cmp_it.nchars, it->string)
- : string_pos (IT_STRING_CHARPOS (*it) + 1, it->string));
+ {
+ if (before_p)
+ {
+ /* With bidi iteration, the character before the current
+ in the visual order cannot be found by simple
+ iteration, because "reverse" reordering is not
+ supported. Instead, we need to use the move_it_*
+ family of functions. */
+ /* Ignore face changes before the first visible
+ character on this display line. */
+ if (it->current_x <= it->first_visible_x)
+ return it->face_id;
+ SAVE_IT (it_copy, *it, it_copy_data);
+ /* Implementation note: Since move_it_in_display_line
+ works in the iterator geometry, and thinks the first
+ character is always the leftmost, even in R2L lines,
+ we don't need to distinguish between the R2L and L2R
+ cases here. */
+ move_it_in_display_line (&it_copy, SCHARS (it_copy.string),
+ it_copy.current_x - 1, MOVE_TO_X);
+ charpos = IT_STRING_CHARPOS (it_copy);
+ RESTORE_IT (it, it, it_copy_data);
+ }
+ else
+ {
+ /* Set charpos to the string position of the character
+ that comes after IT's current position in the visual
+ order. */
+ int n = (it->what == IT_COMPOSITION ? it->cmp_it.nchars : 1);
+
+ it_copy = *it;
+ while (n--)
+ bidi_move_to_visually_next (&it_copy.bidi_it);
+
+ charpos = it_copy.bidi_it.charpos;
+ }
+ }
+ xassert (0 <= charpos && charpos <= SCHARS (it->string));
if (it->current.overlay_string_index >= 0)
bufpos = IT_CHARPOS (*it);
/* Get the face for ASCII, or unibyte. */
face_id = face_at_string_position (it->w,
it->string,
- CHARPOS (pos),
+ charpos,
bufpos,
it->region_beg_charpos,
it->region_end_charpos,
suitable for unibyte text if IT->string is unibyte. */
if (STRING_MULTIBYTE (it->string))
{
- const unsigned char *p = SDATA (it->string) + BYTEPOS (pos);
+ struct text_pos pos1 = string_pos (charpos, it->string);
+ const unsigned char *p = SDATA (it->string) + BYTEPOS (pos1);
int c, len;
struct face *face = FACE_FROM_ID (it->f, face_id);
c = string_char_and_length (p, &len);
- face_id = FACE_FOR_CHAR (it->f, face, c, CHARPOS (pos), it->string);
+ face_id = FACE_FOR_CHAR (it->f, face, c, charpos, it->string);
}
}
else
{
+ struct text_pos pos;
+
if ((IT_CHARPOS (*it) >= ZV && !before_p)
|| (IT_CHARPOS (*it) <= BEGV && before_p))
return it->face_id;
limit = IT_CHARPOS (*it) + TEXT_PROP_DISTANCE_LIMIT;
pos = it->current.pos;
- if (before_p)
- DEC_TEXT_POS (pos, it->multibyte_p);
+ if (!it->bidi_p)
+ {
+ if (before_p)
+ DEC_TEXT_POS (pos, it->multibyte_p);
+ else
+ {
+ if (it->what == IT_COMPOSITION)
+ {
+ /* For composition, we must check the position after
+ the composition. */
+ pos.charpos += it->cmp_it.nchars;
+ pos.bytepos += it->len;
+ }
+ else
+ INC_TEXT_POS (pos, it->multibyte_p);
+ }
+ }
else
{
- if (it->what == IT_COMPOSITION)
- /* For composition, we must check the position after the
- composition. */
- pos.charpos += it->cmp_it.nchars, pos.bytepos += it->len;
+ if (before_p)
+ {
+ /* With bidi iteration, the character before the current
+ in the visual order cannot be found by simple
+ iteration, because "reverse" reordering is not
+ supported. Instead, we need to use the move_it_*
+ family of functions. */
+ /* Ignore face changes before the first visible
+ character on this display line. */
+ if (it->current_x <= it->first_visible_x)
+ return it->face_id;
+ SAVE_IT (it_copy, *it, it_copy_data);
+ /* Implementation note: Since move_it_in_display_line
+ works in the iterator geometry, and thinks the first
+ character is always the leftmost, even in R2L lines,
+ we don't need to distinguish between the R2L and L2R
+ cases here. */
+ move_it_in_display_line (&it_copy, ZV,
+ it_copy.current_x - 1, MOVE_TO_X);
+ pos = it_copy.current.pos;
+ RESTORE_IT (it, it, it_copy_data);
+ }
else
- INC_TEXT_POS (pos, it->multibyte_p);
+ {
+ /* Set charpos to the buffer position of the character
+ that comes after IT's current position in the visual
+ order. */
+ int n = (it->what == IT_COMPOSITION ? it->cmp_it.nchars : 1);
+
+ it_copy = *it;
+ while (n--)
+ bidi_move_to_visually_next (&it_copy.bidi_it);
+
+ SET_TEXT_POS (pos,
+ it_copy.bidi_it.charpos, it_copy.bidi_it.bytepos);
+ }
}
+ xassert (BEGV <= CHARPOS (pos) && CHARPOS (pos) <= ZV);
/* Determine face for CHARSET_ASCII, or unibyte. */
face_id = face_at_buffer_position (it->w,
if (!NILP (prop)
&& IT_STRING_CHARPOS (*it) < it->end_charpos)
{
+ EMACS_INT endpos;
+
handled = HANDLED_RECOMPUTE_PROPS;
/* Get the position at which the next change of the
change in the property is at position end_charpos.
Move IT's current position to that position. */
if (INTEGERP (end_charpos)
- && XFASTINT (end_charpos) < XFASTINT (limit))
+ && (endpos = XFASTINT (end_charpos)) < XFASTINT (limit))
{
struct text_pos old;
+ EMACS_INT oldpos;
+
old = it->current.string_pos;
- IT_STRING_CHARPOS (*it) = XFASTINT (end_charpos);
- compute_string_pos (&it->current.string_pos, old, it->string);
+ oldpos = CHARPOS (old);
+ if (it->bidi_p)
+ {
+ if (it->bidi_it.first_elt
+ && it->bidi_it.charpos < SCHARS (it->string))
+ bidi_paragraph_init (it->paragraph_embedding,
+ &it->bidi_it, 1);
+ /* Bidi-iterate out of the invisible text. */
+ do
+ {
+ bidi_move_to_visually_next (&it->bidi_it);
+ }
+ while (oldpos <= it->bidi_it.charpos
+ && it->bidi_it.charpos < endpos);
+
+ IT_STRING_CHARPOS (*it) = it->bidi_it.charpos;
+ IT_STRING_BYTEPOS (*it) = it->bidi_it.bytepos;
+ if (IT_CHARPOS (*it) >= endpos)
+ it->prev_stop = endpos;
+ }
+ else
+ {
+ IT_STRING_CHARPOS (*it) = XFASTINT (end_charpos);
+ compute_string_pos (&it->current.string_pos, old, it->string);
+ }
}
else
{
it->method = GET_FROM_IMAGE;
it->from_overlay = Qnil;
it->face_id = face_id;
+ it->from_disp_prop_p = 1;
/* Say that we haven't consumed the characters with
`display' property yet. The call to pop_it in
when we are finished with the glyph property value. */
push_it (it, position);
it->from_overlay = overlay;
+ it->from_disp_prop_p = 1;
if (NILP (location))
it->area = TEXT_AREA;
it->end_charpos = it->string_nchars = SCHARS (it->string);
it->method = GET_FROM_STRING;
it->stop_charpos = 0;
+ it->prev_stop = 0;
+ it->base_level_stop = 0;
it->string_from_display_prop_p = 1;
/* Say that we haven't consumed the characters with
`display' property yet. The call to pop_it in
set_iterator_to_next will clean this up. */
if (BUFFERP (object))
*position = start_pos;
+
+ /* Force paragraph direction to be that of the parent
+ object. If the parent object's paragraph direction is
+ not yet determined, default to L2R. */
+ if (it->bidi_p && it->bidi_it.paragraph_dir == R2L)
+ it->paragraph_embedding = it->bidi_it.paragraph_dir;
+ else
+ it->paragraph_embedding = L2R;
+
+ /* Set up the bidi iterator for this display string. */
+ if (it->bidi_p)
+ {
+ it->bidi_it.string.lstring = it->string;
+ it->bidi_it.string.s = NULL;
+ it->bidi_it.string.schars = it->end_charpos;
+ it->bidi_it.string.bufpos = bufpos;
+ it->bidi_it.string.from_disp_str = 1;
+ it->bidi_it.string.unibyte = !it->multibyte_p;
+ bidi_init_it (0, 0, FRAME_WINDOW_P (it->f), &it->bidi_it);
+ }
}
else if (CONSP (value) && EQ (XCAR (value), Qspace))
{
&& COMPOSITION_VALID_P (start, end, prop)
&& (STRINGP (it->string) || (PT <= start || PT >= end)))
{
+ if (start < pos)
+ /* As we can't handle this situation (perhaps font-lock added
+ a new composition), we just return here hoping that next
+ redisplay will detect this composition much earlier. */
+ return HANDLED_NORMALLY;
if (start != pos)
{
if (STRINGP (it->string))
it->stop_charpos = 0;
if (it->cmp_it.stop_pos >= 0)
it->cmp_it.stop_pos = 0;
+ it->prev_stop = 0;
+ it->base_level_stop = 0;
+
+ /* Set up the bidi iterator for this overlay string. */
+ if (it->bidi_p)
+ {
+ it->bidi_it.string.lstring = it->string;
+ it->bidi_it.string.s = NULL;
+ it->bidi_it.string.schars = SCHARS (it->string);
+ it->bidi_it.string.bufpos = it->overlay_strings_charpos;
+ it->bidi_it.string.from_disp_str = it->string_from_display_prop_p;
+ it->bidi_it.string.unibyte = !it->multibyte_p;
+ bidi_init_it (0, 0, FRAME_WINDOW_P (it->f), &it->bidi_it);
+ }
}
CHECK_IT (it);
it->stop_charpos = 0;
xassert (STRINGP (it->string));
it->end_charpos = SCHARS (it->string);
+ it->prev_stop = 0;
+ it->base_level_stop = 0;
it->multibyte_p = STRING_MULTIBYTE (it->string);
it->method = GET_FROM_STRING;
+ it->from_disp_prop_p = 0;
+
+ /* Force paragraph direction to be that of the parent
+ buffer. */
+ if (it->bidi_p && it->bidi_it.paragraph_dir == R2L)
+ it->paragraph_embedding = it->bidi_it.paragraph_dir;
+ else
+ it->paragraph_embedding = L2R;
+
+ /* Set up the bidi iterator for this overlay string. */
+ if (it->bidi_p)
+ {
+ EMACS_INT pos = (charpos > 0 ? charpos : IT_CHARPOS (*it));
+
+ it->bidi_it.string.lstring = it->string;
+ it->bidi_it.string.s = NULL;
+ it->bidi_it.string.schars = SCHARS (it->string);
+ it->bidi_it.string.bufpos = pos;
+ it->bidi_it.string.from_disp_str = it->string_from_display_prop_p;
+ it->bidi_it.string.unibyte = !it->multibyte_p;
+ bidi_init_it (0, 0, FRAME_WINDOW_P (it->f), &it->bidi_it);
+ }
return 1;
}
p->string_from_display_prop_p = it->string_from_display_prop_p;
p->display_ellipsis_p = 0;
p->line_wrap = it->line_wrap;
+ p->bidi_p = it->bidi_p;
+ p->paragraph_embedding = it->paragraph_embedding;
+ p->from_disp_prop_p = it->from_disp_prop_p;
++it->sp;
+
+ /* Save the state of the bidi iterator as well. */
+ if (it->bidi_p)
+ bidi_push_it (&it->bidi_it);
}
static void
iterate_out_of_display_property (struct it *it)
{
+ int buffer_p = BUFFERP (it->object);
+ EMACS_INT eob = (buffer_p ? ZV : it->end_charpos);
+ EMACS_INT bob = (buffer_p ? BEGV : 0);
+
/* Maybe initialize paragraph direction. If we are at the beginning
of a new paragraph, next_element_from_buffer may not have a
chance to do that. */
- if (it->bidi_it.first_elt && it->bidi_it.charpos < ZV)
+ if (it->bidi_it.first_elt && it->bidi_it.charpos < eob)
bidi_paragraph_init (it->paragraph_embedding, &it->bidi_it, 1);
/* prev_stop can be zero, so check against BEGV as well. */
- while (it->bidi_it.charpos >= BEGV
+ while (it->bidi_it.charpos >= bob
&& it->prev_stop <= it->bidi_it.charpos
&& it->bidi_it.charpos < CHARPOS (it->position))
bidi_move_to_visually_next (&it->bidi_it);
{
SET_TEXT_POS (it->position,
it->bidi_it.charpos, it->bidi_it.bytepos);
- it->current.pos = it->position;
+ if (buffer_p)
+ it->current.pos = it->position;
+ else
+ it->current.string_pos = it->position;
}
}
pop_it (struct it *it)
{
struct iterator_stack_entry *p;
+ int from_display_prop = it->from_disp_prop_p;
xassert (it->sp > 0);
--it->sp;
it->slice = p->u.image.slice;
break;
case GET_FROM_STRETCH:
- it->object = p->u.comp.object;
+ it->object = p->u.stretch.object;
break;
case GET_FROM_BUFFER:
it->object = it->w->buffer;
- if (it->bidi_p)
- {
- /* Bidi-iterate until we get out of the portion of text, if
- any, covered by a `display' text property or an overlay
- with `display' property. (We cannot just jump there,
- because the internal coherency of the bidi iterator state
- can not be preserved across such jumps.) We also must
- determine the paragraph base direction if the overlay we
- just processed is at the beginning of a new
- paragraph. */
- iterate_out_of_display_property (it);
- }
break;
case GET_FROM_STRING:
it->object = it->string;
it->voffset = p->voffset;
it->string_from_display_prop_p = p->string_from_display_prop_p;
it->line_wrap = p->line_wrap;
+ it->bidi_p = p->bidi_p;
+ it->paragraph_embedding = p->paragraph_embedding;
+ it->from_disp_prop_p = p->from_disp_prop_p;
+ if (it->bidi_p)
+ {
+ bidi_pop_it (&it->bidi_it);
+ /* Bidi-iterate until we get out of the portion of text, if any,
+ covered by a `display' text property or by an overlay with
+ `display' property. (We cannot just jump there, because the
+ internal coherency of the bidi iterator state can not be
+ preserved across such jumps.) We also must determine the
+ paragraph base direction if the overlay we just processed is
+ at the beginning of a new paragraph. */
+ if (from_display_prop
+ && (it->method == GET_FROM_BUFFER || it->method == GET_FROM_STRING))
+ iterate_out_of_display_property (it);
+
+ xassert ((BUFFERP (it->object)
+ && IT_CHARPOS (*it) == it->bidi_it.charpos
+ && IT_BYTEPOS (*it) == it->bidi_it.bytepos)
+ || (STRINGP (it->object)
+ && IT_STRING_CHARPOS (*it) == it->bidi_it.charpos
+ && IT_STRING_BYTEPOS (*it) == it->bidi_it.bytepos));
+ }
}
static int
forward_to_next_line_start (struct it *it, int *skipped_p)
{
- int old_selective, newline_found_p, n;
+ EMACS_INT old_selective;
+ int newline_found_p, n;
const int MAX_NEWLINE_DISTANCE = 500;
/* If already on a newline, just consume it to avoid unintended
xassert (!STRINGP (it->string));
- /* If there isn't any `display' property in sight, and no
- overlays, we can just use the position of the newline in
- buffer text. */
- if (it->stop_charpos >= limit
- || ((pos = Fnext_single_property_change (make_number (start),
- Qdisplay,
- Qnil, make_number (limit)),
- NILP (pos))
- && next_overlay_change (start) == ZV))
+ /* If we are not bidi-reordering, and there isn't any `display'
+ property in sight, and no overlays, we can just use the
+ position of the newline in buffer text. */
+ if (!it->bidi_p
+ && (it->stop_charpos >= limit
+ || ((pos = Fnext_single_property_change (make_number (start),
+ Qdisplay, Qnil,
+ make_number (limit)),
+ NILP (pos))
+ && next_overlay_change (start) == ZV)))
{
IT_CHARPOS (*it) = limit;
IT_BYTEPOS (*it) = CHAR_TO_BYTE (limit);
invisible. */
if (it->selective > 0
&& indented_beyond_p (IT_CHARPOS (*it), IT_BYTEPOS (*it),
- (double) it->selective)) /* iftc */
+ it->selective))
continue;
/* Check the newline before point for invisibility. */
{
struct it it2;
+ void *it2data = NULL;
EMACS_INT pos;
EMACS_INT beg, end;
Lisp_Object val, overlay;
+ SAVE_IT (it2, *it, it2data);
+
/* If newline is part of a composition, continue from start of composition */
if (find_composition (IT_CHARPOS (*it), -1, &beg, &end, &val, Qnil)
&& beg < IT_CHARPOS (*it))
/* If newline is replaced by a display property, find start of overlay
or interval and continue search from that point. */
- it2 = *it;
pos = --IT_CHARPOS (it2);
--IT_BYTEPOS (it2);
it2.sp = 0;
+ bidi_unshelve_cache (NULL);
it2.string_from_display_prop_p = 0;
+ it2.from_disp_prop_p = 0;
if (handle_display_prop (&it2) == HANDLED_RETURN
&& !NILP (val = get_char_property_and_overlay
(make_number (pos), Qdisplay, Qnil, &overlay))
&& (OVERLAYP (overlay)
? (beg = OVERLAY_POSITION (OVERLAY_START (overlay)))
: get_property_and_range (pos, Qdisplay, &val, &beg, &end, Qnil)))
- goto replaced;
+ {
+ RESTORE_IT (it, it, it2data);
+ goto replaced;
+ }
/* Newline is not replaced by anything -- so we are done. */
+ RESTORE_IT (it, it, it2data);
break;
replaced:
if (it->selective > 0)
while (IT_CHARPOS (*it) < ZV
&& indented_beyond_p (IT_CHARPOS (*it), IT_BYTEPOS (*it),
- (double) it->selective)) /* iftc */
+ it->selective))
{
xassert (IT_BYTEPOS (*it) == BEGV
|| FETCH_BYTE (IT_BYTEPOS (*it) - 1) == '\n');
{
if (IT_STRING_CHARPOS (*it) > 0)
{
- --IT_STRING_CHARPOS (*it);
- --IT_STRING_BYTEPOS (*it);
+ if (!it->bidi_p)
+ {
+ --IT_STRING_CHARPOS (*it);
+ --IT_STRING_BYTEPOS (*it);
+ }
+ else
+ /* Setting this flag will cause
+ bidi_move_to_visually_next not to advance, but
+ instead deliver the current character (newline),
+ which is what the ON_NEWLINE_P flag wants. */
+ it->bidi_it.first_elt = 1;
}
}
else if (IT_CHARPOS (*it) > BEGV)
{
- --IT_CHARPOS (*it);
- --IT_BYTEPOS (*it);
+ if (!it->bidi_p)
+ {
+ --IT_CHARPOS (*it);
+ --IT_BYTEPOS (*it);
+ }
+ /* With bidi iteration, the call to `reseat' will cause
+ bidi_move_to_visually_next deliver the current character,
+ the newline, instead of advancing. */
reseat (it, it->current.pos, 0);
}
}
{
/* For bidi iteration, we need to prime prev_stop and
base_level_stop with our best estimations. */
- if (CHARPOS (pos) < it->prev_stop)
- {
- handle_stop_backwards (it, BEGV);
- if (CHARPOS (pos) < it->base_level_stop)
- it->base_level_stop = 0;
- }
- else if (CHARPOS (pos) > it->stop_charpos
- && it->stop_charpos >= BEGV)
- handle_stop_backwards (it, it->stop_charpos);
- else /* force_p */
- handle_stop (it);
+ /* Implementation note: Of course, POS is not necessarily a
+ stop position, so assigning prev_pos to it is a lie; we
+ should have called compute_stop_backwards. However, if
+ the current buffer does not include any R2L characters,
+ that call would be a waste of cycles, because the
+ iterator will never move back, and thus never cross this
+ "fake" stop position. So we delay that backward search
+ until the time we really need it, in next_element_from_buffer. */
+ if (CHARPOS (pos) != it->prev_stop)
+ it->prev_stop = CHARPOS (pos);
+ if (CHARPOS (pos) < it->base_level_stop)
+ it->base_level_stop = 0; /* meaning it's unknown */
+ handle_stop (it);
}
else
{
IT_STRING_CHARPOS (*it) = -1;
IT_STRING_BYTEPOS (*it) = -1;
it->string = Qnil;
- it->string_from_display_prop_p = 0;
it->method = GET_FROM_BUFFER;
it->object = it->w->buffer;
it->area = TEXT_AREA;
it->multibyte_p = !NILP (BVAR (current_buffer, enable_multibyte_characters));
it->sp = 0;
it->string_from_display_prop_p = 0;
+ it->from_disp_prop_p = 0;
it->face_before_selective_p = 0;
if (it->bidi_p)
{
- it->bidi_it.first_elt = 1;
+ bidi_init_it (IT_CHARPOS (*it), IT_BYTEPOS (*it), FRAME_WINDOW_P (it->f),
+ &it->bidi_it);
+ bidi_unshelve_cache (NULL);
it->bidi_it.paragraph_dir = NEUTRAL_DIR;
- it->bidi_it.disp_pos = -1;
+ it->bidi_it.string.s = NULL;
+ it->bidi_it.string.lstring = Qnil;
+ it->bidi_it.string.bufpos = 0;
+ it->bidi_it.string.unibyte = 0;
}
if (set_stop_p)
if (multibyte >= 0)
it->multibyte_p = multibyte > 0;
+ /* Bidirectional reordering of strings is controlled by the default
+ value of bidi-display-reordering. */
+ it->bidi_p = !NILP (BVAR (&buffer_defaults, bidi_display_reordering));
+
if (s == NULL)
{
xassert (STRINGP (string));
it->end_charpos = it->string_nchars = SCHARS (string);
it->method = GET_FROM_STRING;
it->current.string_pos = string_pos (charpos, string);
+
+ if (it->bidi_p)
+ {
+ it->bidi_it.string.lstring = string;
+ it->bidi_it.string.s = NULL;
+ it->bidi_it.string.schars = it->end_charpos;
+ it->bidi_it.string.bufpos = 0;
+ it->bidi_it.string.from_disp_str = 0;
+ it->bidi_it.string.unibyte = !it->multibyte_p;
+ bidi_init_it (charpos, IT_STRING_BYTEPOS (*it),
+ FRAME_WINDOW_P (it->f), &it->bidi_it);
+ }
}
else
{
it->end_charpos = it->string_nchars = strlen (s);
}
+ if (it->bidi_p)
+ {
+ it->bidi_it.string.lstring = Qnil;
+ it->bidi_it.string.s = (const unsigned char *) s;
+ it->bidi_it.string.schars = it->end_charpos;
+ it->bidi_it.string.bufpos = 0;
+ it->bidi_it.string.from_disp_str = 0;
+ it->bidi_it.string.unibyte = !it->multibyte_p;
+ bidi_init_it (charpos, IT_BYTEPOS (*it), FRAME_WINDOW_P (it->f),
+ &it->bidi_it);
+ }
it->method = GET_FROM_C_STRING;
}
/* PRECISION > 0 means don't return more than PRECISION characters
from the string. */
if (precision > 0 && it->end_charpos - charpos > precision)
- it->end_charpos = it->string_nchars = charpos + precision;
+ {
+ it->end_charpos = it->string_nchars = charpos + precision;
+ if (it->bidi_p)
+ it->bidi_it.string.schars = it->end_charpos;
+ }
/* FIELD_WIDTH > 0 means pad with spaces until FIELD_WIDTH
characters have been returned. FIELD_WIDTH == 0 means don't pad,
padding with `-' at the end of a mode line. */
if (field_width < 0)
field_width = INFINITY;
+ /* Implementation note: We deliberately don't enlarge
+ it->bidi_it.string.schars here to fit it->end_charpos, because
+ the bidi iterator cannot produce characters out of thin air. */
if (field_width > it->end_charpos - charpos)
it->end_charpos = charpos + field_width;
it->dp = XCHAR_TABLE (Vstandard_display_table);
it->stop_charpos = charpos;
+ it->prev_stop = charpos;
+ it->base_level_stop = 0;
+ if (it->bidi_p)
+ {
+ it->bidi_it.first_elt = 1;
+ it->bidi_it.paragraph_dir = NEUTRAL_DIR;
+ it->bidi_it.disp_pos = -1;
+ }
if (s == NULL && it->multibyte_p)
{
EMACS_INT endpos = SCHARS (it->string);
case GET_FROM_C_STRING:
/* Current display element of IT is from a C string. */
- IT_BYTEPOS (*it) += it->len;
- IT_CHARPOS (*it) += 1;
+ if (!it->bidi_p
+ /* If the string position is beyond string's end, it means
+ next_element_from_c_string is padding the string with
+ blanks, in which case we bypass the bidi iterator,
+ because it cannot deal with such virtual characters. */
+ || IT_CHARPOS (*it) >= it->bidi_it.string.schars)
+ {
+ IT_BYTEPOS (*it) += it->len;
+ IT_CHARPOS (*it) += 1;
+ }
+ else
+ {
+ bidi_move_to_visually_next (&it->bidi_it);
+ IT_BYTEPOS (*it) = it->bidi_it.bytepos;
+ IT_CHARPOS (*it) = it->bidi_it.charpos;
+ }
break;
case GET_FROM_DISPLAY_VECTOR:
xassert (it->s == NULL && STRINGP (it->string));
if (it->cmp_it.id >= 0)
{
- IT_STRING_CHARPOS (*it) += it->cmp_it.nchars;
- IT_STRING_BYTEPOS (*it) += it->cmp_it.nbytes;
- if (it->cmp_it.to < it->cmp_it.nglyphs)
- it->cmp_it.from = it->cmp_it.to;
+ int i;
+
+ if (! it->bidi_p)
+ {
+ IT_STRING_CHARPOS (*it) += it->cmp_it.nchars;
+ IT_STRING_BYTEPOS (*it) += it->cmp_it.nbytes;
+ if (it->cmp_it.to < it->cmp_it.nglyphs)
+ it->cmp_it.from = it->cmp_it.to;
+ else
+ {
+ it->cmp_it.id = -1;
+ composition_compute_stop_pos (&it->cmp_it,
+ IT_STRING_CHARPOS (*it),
+ IT_STRING_BYTEPOS (*it),
+ it->end_charpos, it->string);
+ }
+ }
+ else if (! it->cmp_it.reversed_p)
+ {
+ for (i = 0; i < it->cmp_it.nchars; i++)
+ bidi_move_to_visually_next (&it->bidi_it);
+ IT_STRING_BYTEPOS (*it) = it->bidi_it.bytepos;
+ IT_STRING_CHARPOS (*it) = it->bidi_it.charpos;
+
+ if (it->cmp_it.to < it->cmp_it.nglyphs)
+ it->cmp_it.from = it->cmp_it.to;
+ else
+ {
+ EMACS_INT stop = it->end_charpos;
+ if (it->bidi_it.scan_dir < 0)
+ stop = -1;
+ composition_compute_stop_pos (&it->cmp_it,
+ IT_STRING_CHARPOS (*it),
+ IT_STRING_BYTEPOS (*it), stop,
+ it->string);
+ }
+ }
else
{
- it->cmp_it.id = -1;
- composition_compute_stop_pos (&it->cmp_it,
- IT_STRING_CHARPOS (*it),
- IT_STRING_BYTEPOS (*it),
- it->end_charpos, it->string);
+ for (i = 0; i < it->cmp_it.nchars; i++)
+ bidi_move_to_visually_next (&it->bidi_it);
+ IT_STRING_BYTEPOS (*it) = it->bidi_it.bytepos;
+ IT_STRING_CHARPOS (*it) = it->bidi_it.charpos;
+ if (it->cmp_it.from > 0)
+ it->cmp_it.to = it->cmp_it.from;
+ else
+ {
+ EMACS_INT stop = it->end_charpos;
+ if (it->bidi_it.scan_dir < 0)
+ stop = -1;
+ composition_compute_stop_pos (&it->cmp_it,
+ IT_STRING_CHARPOS (*it),
+ IT_STRING_BYTEPOS (*it), stop,
+ it->string);
+ }
}
}
else
{
- IT_STRING_BYTEPOS (*it) += it->len;
- IT_STRING_CHARPOS (*it) += 1;
+ if (!it->bidi_p
+ /* If the string position is beyond string's end, it
+ means next_element_from_string is padding the string
+ with blanks, in which case we bypass the bidi
+ iterator, because it cannot deal with such virtual
+ characters. */
+ || IT_STRING_CHARPOS (*it) >= it->bidi_it.string.schars)
+ {
+ IT_STRING_BYTEPOS (*it) += it->len;
+ IT_STRING_CHARPOS (*it) += 1;
+ }
+ else
+ {
+ int prev_scan_dir = it->bidi_it.scan_dir;
+
+ bidi_move_to_visually_next (&it->bidi_it);
+ IT_STRING_BYTEPOS (*it) = it->bidi_it.bytepos;
+ IT_STRING_CHARPOS (*it) = it->bidi_it.charpos;
+ if (prev_scan_dir != it->bidi_it.scan_dir)
+ {
+ EMACS_INT stop = it->end_charpos;
+
+ if (it->bidi_it.scan_dir < 0)
+ stop = -1;
+ composition_compute_stop_pos (&it->cmp_it,
+ IT_STRING_CHARPOS (*it),
+ IT_STRING_BYTEPOS (*it), stop,
+ it->string);
+ }
+ }
}
consider_string_end:
return 1;
}
+/* Get the first element of string/buffer in the visual order, after
+ being reseated to a new position in a string or a buffer. */
+static void
+get_visually_first_element (struct it *it)
+{
+ int string_p = STRINGP (it->string) || it->s;
+ EMACS_INT eob = (string_p ? it->bidi_it.string.schars : ZV);
+ EMACS_INT bob = (string_p ? 0 : BEGV);
+
+ if (STRINGP (it->string))
+ {
+ it->bidi_it.charpos = IT_STRING_CHARPOS (*it);
+ it->bidi_it.bytepos = IT_STRING_BYTEPOS (*it);
+ }
+ else
+ {
+ it->bidi_it.charpos = IT_CHARPOS (*it);
+ it->bidi_it.bytepos = IT_BYTEPOS (*it);
+ }
+
+ if (it->bidi_it.charpos == eob)
+ {
+ /* Nothing to do, but reset the FIRST_ELT flag, like
+ bidi_paragraph_init does, because we are not going to
+ call it. */
+ it->bidi_it.first_elt = 0;
+ }
+ else if (it->bidi_it.charpos == bob
+ || (!string_p
+ /* FIXME: Should support all Unicode line separators. */
+ && (FETCH_CHAR (it->bidi_it.bytepos - 1) == '\n'
+ || FETCH_CHAR (it->bidi_it.bytepos) == '\n')))
+ {
+ /* If we are at the beginning of a line/string, we can produce
+ the next element right away. */
+ bidi_paragraph_init (it->paragraph_embedding, &it->bidi_it, 1);
+ bidi_move_to_visually_next (&it->bidi_it);
+ }
+ else
+ {
+ EMACS_INT orig_bytepos = it->bidi_it.bytepos;
+
+ /* We need to prime the bidi iterator starting at the line's or
+ string's beginning, before we will be able to produce the
+ next element. */
+ if (string_p)
+ it->bidi_it.charpos = it->bidi_it.bytepos = 0;
+ else
+ {
+ it->bidi_it.charpos = find_next_newline_no_quit (IT_CHARPOS (*it),
+ -1);
+ it->bidi_it.bytepos = CHAR_TO_BYTE (it->bidi_it.charpos);
+ }
+ bidi_paragraph_init (it->paragraph_embedding, &it->bidi_it, 1);
+ do
+ {
+ /* Now return to buffer/string position where we were asked
+ to get the next display element, and produce that. */
+ bidi_move_to_visually_next (&it->bidi_it);
+ }
+ while (it->bidi_it.bytepos != orig_bytepos
+ && it->bidi_it.charpos < eob);
+ }
+
+ /* Adjust IT's position information to where we ended up. */
+ if (STRINGP (it->string))
+ {
+ IT_STRING_CHARPOS (*it) = it->bidi_it.charpos;
+ IT_STRING_BYTEPOS (*it) = it->bidi_it.bytepos;
+ }
+ else
+ {
+ IT_CHARPOS (*it) = it->bidi_it.charpos;
+ IT_BYTEPOS (*it) = it->bidi_it.bytepos;
+ }
+
+ if (STRINGP (it->string) || !it->s)
+ {
+ EMACS_INT stop, charpos, bytepos;
+
+ if (STRINGP (it->string))
+ {
+ xassert (!it->s);
+ stop = SCHARS (it->string);
+ if (stop > it->end_charpos)
+ stop = it->end_charpos;
+ charpos = IT_STRING_CHARPOS (*it);
+ bytepos = IT_STRING_BYTEPOS (*it);
+ }
+ else
+ {
+ stop = it->end_charpos;
+ charpos = IT_CHARPOS (*it);
+ bytepos = IT_BYTEPOS (*it);
+ }
+ if (it->bidi_it.scan_dir < 0)
+ stop = -1;
+ composition_compute_stop_pos (&it->cmp_it, charpos, bytepos, stop,
+ it->string);
+ }
+}
/* Load IT with the next display element from Lisp string IT->string.
IT->current.string_pos is the current position within the string.
struct text_pos position;
xassert (STRINGP (it->string));
+ xassert (!it->bidi_p || EQ (it->string, it->bidi_it.string.lstring));
xassert (IT_STRING_CHARPOS (*it) >= 0);
position = it->current.string_pos;
+ /* With bidi reordering, the character to display might not be the
+ character at IT_STRING_CHARPOS. BIDI_IT.FIRST_ELT non-zero means
+ that we were reseat()ed to a new string, whose paragraph
+ direction is not known. */
+ if (it->bidi_p && it->bidi_it.first_elt)
+ {
+ get_visually_first_element (it);
+ SET_TEXT_POS (position, IT_STRING_CHARPOS (*it), IT_STRING_BYTEPOS (*it));
+ }
+
/* Time to check for invisible text? */
- if (IT_STRING_CHARPOS (*it) < it->end_charpos
- && IT_STRING_CHARPOS (*it) == it->stop_charpos)
+ if (IT_STRING_CHARPOS (*it) < it->end_charpos)
{
- handle_stop (it);
+ if (IT_STRING_CHARPOS (*it) >= it->stop_charpos)
+ {
+ if (!(!it->bidi_p
+ || BIDI_AT_BASE_LEVEL (it->bidi_it)
+ || IT_STRING_CHARPOS (*it) == it->stop_charpos))
+ {
+ /* With bidi non-linear iteration, we could find
+ ourselves far beyond the last computed stop_charpos,
+ with several other stop positions in between that we
+ missed. Scan them all now, in buffer's logical
+ order, until we find and handle the last stop_charpos
+ that precedes our current position. */
+ handle_stop_backwards (it, it->stop_charpos);
+ return GET_NEXT_DISPLAY_ELEMENT (it);
+ }
+ else
+ {
+ if (it->bidi_p)
+ {
+ /* Take note of the stop position we just moved
+ across, for when we will move back across it. */
+ it->prev_stop = it->stop_charpos;
+ /* If we are at base paragraph embedding level, take
+ note of the last stop position seen at this
+ level. */
+ if (BIDI_AT_BASE_LEVEL (it->bidi_it))
+ it->base_level_stop = it->stop_charpos;
+ }
+ handle_stop (it);
- /* Since a handler may have changed IT->method, we must
- recurse here. */
- return GET_NEXT_DISPLAY_ELEMENT (it);
+ /* Since a handler may have changed IT->method, we must
+ recurse here. */
+ return GET_NEXT_DISPLAY_ELEMENT (it);
+ }
+ }
+ else if (it->bidi_p
+ /* If we are before prev_stop, we may have overstepped
+ on our way backwards a stop_pos, and if so, we need
+ to handle that stop_pos. */
+ && IT_STRING_CHARPOS (*it) < it->prev_stop
+ /* We can sometimes back up for reasons that have nothing
+ to do with bidi reordering. E.g., compositions. The
+ code below is only needed when we are above the base
+ embedding level, so test for that explicitly. */
+ && !BIDI_AT_BASE_LEVEL (it->bidi_it))
+ {
+ /* If we lost track of base_level_stop, we have no better
+ place for handle_stop_backwards to start from than string
+ beginning. This happens, e.g., when we were reseated to
+ the previous screenful of text by vertical-motion. */
+ if (it->base_level_stop <= 0
+ || IT_STRING_CHARPOS (*it) < it->base_level_stop)
+ it->base_level_stop = 0;
+ handle_stop_backwards (it, it->base_level_stop);
+ return GET_NEXT_DISPLAY_ELEMENT (it);
+ }
}
if (it->current.overlay_string_index >= 0)
return 0;
}
else if (CHAR_COMPOSED_P (it, IT_STRING_CHARPOS (*it),
- IT_STRING_BYTEPOS (*it), SCHARS (it->string))
+ IT_STRING_BYTEPOS (*it),
+ it->bidi_it.scan_dir < 0
+ ? -1
+ : SCHARS (it->string))
&& next_element_from_composition (it))
{
return 1;
CHARPOS (position) = BYTEPOS (position) = -1;
}
else if (CHAR_COMPOSED_P (it, IT_STRING_CHARPOS (*it),
- IT_STRING_BYTEPOS (*it), it->string_nchars)
+ IT_STRING_BYTEPOS (*it),
+ it->bidi_it.scan_dir < 0
+ ? -1
+ : it->string_nchars)
&& next_element_from_composition (it))
{
return 1;
int success_p = 1;
xassert (it->s);
+ xassert (!it->bidi_p || it->s == it->bidi_it.string.s);
it->what = IT_CHARACTER;
BYTEPOS (it->position) = CHARPOS (it->position) = 0;
it->object = Qnil;
- /* IT's position can be greater IT->string_nchars in case a field
- width or precision has been specified when the iterator was
+ /* With bidi reordering, the character to display might not be the
+ character at IT_CHARPOS. BIDI_IT.FIRST_ELT non-zero means that
+ we were reseated to a new string, whose paragraph direction is
+ not known. */
+ if (it->bidi_p && it->bidi_it.first_elt)
+ get_visually_first_element (it);
+
+ /* IT's position can be greater than IT->string_nchars in case a
+ field width or precision has been specified when the iterator was
initialized. */
if (IT_CHARPOS (*it) >= it->end_charpos)
{
return 1;
}
-/* Scan forward from CHARPOS in the current buffer, until we find a
- stop position > current IT's position. Then handle the stop
+/* Scan backwards from IT's current position until we find a stop
+ position, or until BEGV. This is called when we find ourself
+ before both the last known prev_stop and base_level_stop while
+ reordering bidirectional text. */
+
+static void
+compute_stop_pos_backwards (struct it *it)
+{
+ const int SCAN_BACK_LIMIT = 1000;
+ struct text_pos pos;
+ struct display_pos save_current = it->current;
+ struct text_pos save_position = it->position;
+ EMACS_INT charpos = IT_CHARPOS (*it);
+ EMACS_INT where_we_are = charpos;
+ EMACS_INT save_stop_pos = it->stop_charpos;
+ EMACS_INT save_end_pos = it->end_charpos;
+
+ xassert (NILP (it->string) && !it->s);
+ xassert (it->bidi_p);
+ it->bidi_p = 0;
+ do
+ {
+ it->end_charpos = min (charpos + 1, ZV);
+ charpos = max (charpos - SCAN_BACK_LIMIT, BEGV);
+ SET_TEXT_POS (pos, charpos, BYTE_TO_CHAR (charpos));
+ reseat_1 (it, pos, 0);
+ compute_stop_pos (it);
+ /* We must advance forward, right? */
+ if (it->stop_charpos <= charpos)
+ abort ();
+ }
+ while (charpos > BEGV && it->stop_charpos >= it->end_charpos);
+
+ if (it->stop_charpos <= where_we_are)
+ it->prev_stop = it->stop_charpos;
+ else
+ it->prev_stop = BEGV;
+ it->bidi_p = 1;
+ it->current = save_current;
+ it->position = save_position;
+ it->stop_charpos = save_stop_pos;
+ it->end_charpos = save_end_pos;
+}
+
+/* Scan forward from CHARPOS in the current buffer/string, until we
+ find a stop position > current IT's position. Then handle the stop
position before that. This is called when we bump into a stop
position while reordering bidirectional text. CHARPOS should be
- the last previously processed stop_pos (or BEGV, if none were
+ the last previously processed stop_pos (or BEGV/0, if none were
processed yet) whose position is less that IT's current
position. */
static void
handle_stop_backwards (struct it *it, EMACS_INT charpos)
{
- EMACS_INT where_we_are = IT_CHARPOS (*it);
+ int bufp = !STRINGP (it->string);
+ EMACS_INT where_we_are = (bufp ? IT_CHARPOS (*it) : IT_STRING_CHARPOS (*it));
struct display_pos save_current = it->current;
struct text_pos save_position = it->position;
struct text_pos pos1;
EMACS_INT next_stop;
/* Scan in strict logical order. */
+ xassert (it->bidi_p);
it->bidi_p = 0;
do
{
it->prev_stop = charpos;
- SET_TEXT_POS (pos1, charpos, CHAR_TO_BYTE (charpos));
- reseat_1 (it, pos1, 0);
+ if (bufp)
+ {
+ SET_TEXT_POS (pos1, charpos, CHAR_TO_BYTE (charpos));
+ reseat_1 (it, pos1, 0);
+ }
+ else
+ it->current.string_pos = string_pos (charpos, it->string);
compute_stop_pos (it);
/* We must advance forward, right? */
if (it->stop_charpos <= it->prev_stop)
}
while (charpos <= where_we_are);
- next_stop = it->stop_charpos;
- it->stop_charpos = it->prev_stop;
it->bidi_p = 1;
it->current = save_current;
it->position = save_position;
+ next_stop = it->stop_charpos;
+ it->stop_charpos = it->prev_stop;
handle_stop (it);
it->stop_charpos = next_stop;
}
int success_p = 1;
xassert (IT_CHARPOS (*it) >= BEGV);
+ xassert (NILP (it->string) && !it->s);
+ xassert (!it->bidi_p
+ || (EQ (it->bidi_it.string.lstring, Qnil)
+ && it->bidi_it.string.s == NULL));
/* With bidi reordering, the character to display might not be the
character at IT_CHARPOS. BIDI_IT.FIRST_ELT non-zero means that
a different paragraph. */
if (it->bidi_p && it->bidi_it.first_elt)
{
- it->bidi_it.charpos = IT_CHARPOS (*it);
- it->bidi_it.bytepos = IT_BYTEPOS (*it);
- if (it->bidi_it.bytepos == ZV_BYTE)
- {
- /* Nothing to do, but reset the FIRST_ELT flag, like
- bidi_paragraph_init does, because we are not going to
- call it. */
- it->bidi_it.first_elt = 0;
- }
- else if (it->bidi_it.bytepos == BEGV_BYTE
- /* FIXME: Should support all Unicode line separators. */
- || FETCH_CHAR (it->bidi_it.bytepos - 1) == '\n'
- || FETCH_CHAR (it->bidi_it.bytepos) == '\n')
- {
- /* If we are at the beginning of a line, we can produce the
- next element right away. */
- bidi_paragraph_init (it->paragraph_embedding, &it->bidi_it, 1);
- bidi_move_to_visually_next (&it->bidi_it);
- }
- else
- {
- EMACS_INT orig_bytepos = IT_BYTEPOS (*it);
-
- /* We need to prime the bidi iterator starting at the line's
- beginning, before we will be able to produce the next
- element. */
- IT_CHARPOS (*it) = find_next_newline_no_quit (IT_CHARPOS (*it), -1);
- IT_BYTEPOS (*it) = CHAR_TO_BYTE (IT_CHARPOS (*it));
- it->bidi_it.charpos = IT_CHARPOS (*it);
- it->bidi_it.bytepos = IT_BYTEPOS (*it);
- bidi_paragraph_init (it->paragraph_embedding, &it->bidi_it, 1);
- do
- {
- /* Now return to buffer position where we were asked to
- get the next display element, and produce that. */
- bidi_move_to_visually_next (&it->bidi_it);
- }
- while (it->bidi_it.bytepos != orig_bytepos
- && it->bidi_it.bytepos < ZV_BYTE);
- }
-
- it->bidi_it.first_elt = 0; /* paranoia: bidi.c does this */
- /* Adjust IT's position information to where we ended up. */
- IT_CHARPOS (*it) = it->bidi_it.charpos;
- IT_BYTEPOS (*it) = it->bidi_it.bytepos;
+ get_visually_first_element (it);
SET_TEXT_POS (it->position, IT_CHARPOS (*it), IT_BYTEPOS (*it));
- {
- EMACS_INT stop = it->end_charpos;
- if (it->bidi_it.scan_dir < 0)
- stop = -1;
- composition_compute_stop_pos (&it->cmp_it, IT_CHARPOS (*it),
- IT_BYTEPOS (*it), stop, Qnil);
- }
}
if (IT_CHARPOS (*it) >= it->stop_charpos)
}
}
else if (it->bidi_p
+ /* If we are before prev_stop, we may have overstepped on
+ our way backwards a stop_pos, and if so, we need to
+ handle that stop_pos. */
+ && IT_CHARPOS (*it) < it->prev_stop
/* We can sometimes back up for reasons that have nothing
to do with bidi reordering. E.g., compositions. The
code below is only needed when we are above the base
embedding level, so test for that explicitly. */
- && !BIDI_AT_BASE_LEVEL (it->bidi_it)
- && IT_CHARPOS (*it) < it->prev_stop)
+ && !BIDI_AT_BASE_LEVEL (it->bidi_it))
{
- if (it->base_level_stop <= 0)
- it->base_level_stop = BEGV;
- if (IT_CHARPOS (*it) < it->base_level_stop)
- abort ();
- handle_stop_backwards (it, it->base_level_stop);
+ if (it->base_level_stop <= 0
+ || IT_CHARPOS (*it) < it->base_level_stop)
+ {
+ /* If we lost track of base_level_stop, we need to find
+ prev_stop by looking backwards. This happens, e.g., when
+ we were reseated to the previous screenful of text by
+ vertical-motion. */
+ it->base_level_stop = BEGV;
+ compute_stop_pos_backwards (it);
+ handle_stop_backwards (it, it->prev_stop);
+ }
+ else
+ handle_stop_backwards (it, it->base_level_stop);
return GET_NEXT_DISPLAY_ELEMENT (it);
}
else
&& IT_CHARPOS (*it) + 1 < ZV
&& indented_beyond_p (IT_CHARPOS (*it) + 1,
IT_BYTEPOS (*it) + 1,
- (double) it->selective)) /* iftc */
+ it->selective))
{
success_p = next_element_from_ellipsis (it);
it->dpvec_char_len = -1;
{
enum move_it_result result = MOVE_UNDEFINED;
struct glyph_row *saved_glyph_row;
- struct it wrap_it, atpos_it, atx_it;
+ struct it wrap_it, atpos_it, atx_it, ppos_it;
+ void *wrap_data = NULL, *atpos_data = NULL, *atx_data = NULL;
+ void *ppos_data = NULL;
int may_wrap = 0;
enum it_method prev_method = it->method;
EMACS_INT prev_pos = IT_CHARPOS (*it);
+ int saw_smaller_pos = prev_pos < to_charpos;
/* Don't produce glyphs in produce_glyphs. */
saved_glyph_row = it->glyph_row;
atpos_it.sp = -1;
atx_it.sp = -1;
+ /* Use ppos_it under bidi reordering to save a copy of IT for the
+ position > CHARPOS that is the closest to CHARPOS. We restore
+ that position in IT when we have scanned the entire display line
+ without finding a match for CHARPOS and all the character
+ positions are greater than CHARPOS. */
+ if (it->bidi_p)
+ {
+ SAVE_IT (ppos_it, *it, ppos_data);
+ SET_TEXT_POS (ppos_it.current.pos, ZV, ZV_BYTE);
+ if ((op & MOVE_TO_POS) && IT_CHARPOS (*it) >= to_charpos)
+ SAVE_IT (ppos_it, *it, ppos_data);
+ }
+
#define BUFFER_POS_REACHED_P() \
((op & MOVE_TO_POS) != 0 \
&& BUFFERP (it->object) \
((IT)->current_x = x, (IT)->max_ascent = ascent, \
(IT)->max_descent = descent)
- /* Stop if we move beyond TO_CHARPOS (after an image or stretch
- glyph). */
+ /* Stop if we move beyond TO_CHARPOS (after an image or a
+ display string or stretch glyph). */
if ((op & MOVE_TO_POS) != 0
&& BUFFERP (it->object)
&& it->method == GET_FROM_BUFFER
&& ((!it->bidi_p && IT_CHARPOS (*it) > to_charpos)
|| (it->bidi_p
&& (prev_method == GET_FROM_IMAGE
- || prev_method == GET_FROM_STRETCH)
+ || prev_method == GET_FROM_STRETCH
+ || prev_method == GET_FROM_STRING)
/* Passed TO_CHARPOS from left to right. */
&& ((prev_pos < to_charpos
&& IT_CHARPOS (*it) > to_charpos)
/* If wrap_it is valid, the current position might be in a
word that is wrapped. So, save the iterator in
atpos_it and continue to see if wrapping happens. */
- atpos_it = *it;
+ SAVE_IT (atpos_it, *it, atpos_data);
}
- prev_method = it->method;
- if (it->method == GET_FROM_BUFFER)
- prev_pos = IT_CHARPOS (*it);
/* Stop when ZV reached.
We used to stop here when TO_CHARPOS reached as well, but that is
too soon if this glyph does not fit on this line. So we handle it
already found, we are done. */
if (atpos_it.sp >= 0)
{
- *it = atpos_it;
+ RESTORE_IT (it, &atpos_it, atpos_data);
result = MOVE_POS_MATCH_OR_ZV;
goto done;
}
if (atx_it.sp >= 0)
{
- *it = atx_it;
+ RESTORE_IT (it, &atx_it, atx_data);
result = MOVE_X_REACHED;
goto done;
}
/* Otherwise, we can wrap here. */
- wrap_it = *it;
+ SAVE_IT (wrap_it, *it, wrap_data);
may_wrap = 0;
}
}
if (it->area != TEXT_AREA)
{
+ prev_method = it->method;
+ if (it->method == GET_FROM_BUFFER)
+ prev_pos = IT_CHARPOS (*it);
set_iterator_to_next (it, 1);
if (IT_CHARPOS (*it) < CHARPOS (this_line_min_pos))
SET_TEXT_POS (this_line_min_pos,
IT_CHARPOS (*it), IT_BYTEPOS (*it));
+ if (it->bidi_p
+ && (op & MOVE_TO_POS)
+ && IT_CHARPOS (*it) > to_charpos
+ && IT_CHARPOS (*it) < IT_CHARPOS (ppos_it))
+ SAVE_IT (ppos_it, *it, ppos_data);
continue;
}
goto buffer_pos_reached;
if (atpos_it.sp < 0)
{
- atpos_it = *it;
+ SAVE_IT (atpos_it, *it, atpos_data);
IT_RESET_X_ASCENT_DESCENT (&atpos_it);
}
}
}
if (atx_it.sp < 0)
{
- atx_it = *it;
+ SAVE_IT (atx_it, *it, atx_data);
IT_RESET_X_ASCENT_DESCENT (&atx_it);
}
}
if (it->line_wrap == WORD_WRAP
&& atpos_it.sp < 0)
{
- atpos_it = *it;
+ SAVE_IT (atpos_it, *it, atpos_data);
atpos_it.current_x = x_before_this_char;
atpos_it.hpos = hpos_before_this_char;
}
}
+ prev_method = it->method;
+ if (it->method == GET_FROM_BUFFER)
+ prev_pos = IT_CHARPOS (*it);
set_iterator_to_next (it, 1);
if (IT_CHARPOS (*it) < CHARPOS (this_line_min_pos))
SET_TEXT_POS (this_line_min_pos,
if (wrap_it.sp >= 0)
{
- *it = wrap_it;
+ RESTORE_IT (it, &wrap_it, wrap_data);
atpos_it.sp = -1;
atx_it.sp = -1;
}
goto buffer_pos_reached;
if (it->line_wrap == WORD_WRAP && atpos_it.sp < 0)
{
- atpos_it = *it;
+ SAVE_IT (atpos_it, *it, atpos_data);
IT_RESET_X_ASCENT_DESCENT (&atpos_it);
}
}
/* Is this a line end? If yes, we're done. */
if (ITERATOR_AT_END_OF_LINE_P (it))
{
- result = MOVE_NEWLINE_OR_CR;
+ /* If we are past TO_CHARPOS, but never saw any character
+ positions smaller than TO_CHARPOS, return
+ MOVE_POS_MATCH_OR_ZV, like the unidirectional display
+ did. */
+ if ((op & MOVE_TO_POS) != 0
+ && !saw_smaller_pos
+ && IT_CHARPOS (*it) > to_charpos)
+ {
+ result = MOVE_POS_MATCH_OR_ZV;
+ if (it->bidi_p && IT_CHARPOS (ppos_it) < ZV)
+ RESTORE_IT (it, &ppos_it, ppos_data);
+ }
+ else
+ result = MOVE_NEWLINE_OR_CR;
break;
}
+ prev_method = it->method;
if (it->method == GET_FROM_BUFFER)
prev_pos = IT_CHARPOS (*it);
/* The current display element has been consumed. Advance
set_iterator_to_next (it, 1);
if (IT_CHARPOS (*it) < CHARPOS (this_line_min_pos))
SET_TEXT_POS (this_line_min_pos, IT_CHARPOS (*it), IT_BYTEPOS (*it));
+ if (IT_CHARPOS (*it) < to_charpos)
+ saw_smaller_pos = 1;
+ if (it->bidi_p
+ && (op & MOVE_TO_POS)
+ && IT_CHARPOS (*it) >= to_charpos
+ && IT_CHARPOS (*it) < IT_CHARPOS (ppos_it))
+ SAVE_IT (ppos_it, *it, ppos_data);
/* Stop if lines are truncated and IT's current x-position is
past the right edge of the window now. */
if (!FRAME_WINDOW_P (it->f)
|| IT_OVERFLOW_NEWLINE_INTO_FRINGE (it))
{
- if (!get_next_display_element (it)
- || BUFFER_POS_REACHED_P ())
+ int at_eob_p = 0;
+
+ if ((at_eob_p = !get_next_display_element (it))
+ || BUFFER_POS_REACHED_P ()
+ /* If we are past TO_CHARPOS, but never saw any
+ character positions smaller than TO_CHARPOS,
+ return MOVE_POS_MATCH_OR_ZV, like the
+ unidirectional display did. */
+ || ((op & MOVE_TO_POS) != 0
+ && !saw_smaller_pos
+ && IT_CHARPOS (*it) > to_charpos))
{
result = MOVE_POS_MATCH_OR_ZV;
+ if (it->bidi_p && !at_eob_p && IT_CHARPOS (ppos_it) < ZV)
+ RESTORE_IT (it, &ppos_it, ppos_data);
break;
}
if (ITERATOR_AT_END_OF_LINE_P (it))
break;
}
}
+ else if ((op & MOVE_TO_POS) != 0
+ && !saw_smaller_pos
+ && IT_CHARPOS (*it) > to_charpos)
+ {
+ result = MOVE_POS_MATCH_OR_ZV;
+ if (it->bidi_p && IT_CHARPOS (ppos_it) < ZV)
+ RESTORE_IT (it, &ppos_it, ppos_data);
+ break;
+ }
result = MOVE_LINE_TRUNCATED;
break;
}
/* If we scanned beyond to_pos and didn't find a point to wrap at,
restore the saved iterator. */
if (atpos_it.sp >= 0)
- *it = atpos_it;
+ RESTORE_IT (it, &atpos_it, atpos_data);
else if (atx_it.sp >= 0)
- *it = atx_it;
+ RESTORE_IT (it, &atx_it, atx_data);
done:
+ if (atpos_data)
+ xfree (atpos_data);
+ if (atx_data)
+ xfree (atx_data);
+ if (wrap_data)
+ xfree (wrap_data);
+ if (ppos_data)
+ xfree (ppos_data);
+
/* Restore the iterator settings altered at the beginning of this
function. */
it->glyph_row = saved_glyph_row;
if (it->line_wrap == WORD_WRAP
&& (op & MOVE_TO_X))
{
- struct it save_it = *it;
- int skip = move_it_in_display_line_to (it, to_charpos, to_x, op);
+ struct it save_it;
+ void *save_data = NULL;
+ int skip;
+
+ SAVE_IT (save_it, *it, save_data);
+ skip = move_it_in_display_line_to (it, to_charpos, to_x, op);
/* When word-wrap is on, TO_X may lie past the end
of a wrapped line. Then it->current is the
character on the next line, so backtrack to the
if (skip == MOVE_LINE_CONTINUED)
{
int prev_x = max (it->current_x - 1, 0);
- *it = save_it;
+ RESTORE_IT (it, &save_it, save_data);
move_it_in_display_line_to
(it, -1, prev_x, MOVE_TO_X);
}
+ else
+ xfree (save_data);
}
else
move_it_in_display_line_to (it, to_charpos, to_x, op);
description of enum move_operation_enum.
If TO_CHARPOS is in invisible text, e.g. a truncated part of a
- screen line, this function will set IT to the next position >
- TO_CHARPOS. */
+ screen line, this function will set IT to the next position that is
+ displayed to the right of TO_CHARPOS on the screen. */
void
move_it_to (struct it *it, EMACS_INT to_charpos, int to_x, int to_y, int to_vpos, int op)
{
enum move_it_result skip, skip2 = MOVE_X_REACHED;
int line_height, line_start_x = 0, reached = 0;
+ void *backup_data = NULL;
for (;;)
{
struct it it_backup;
if (it->line_wrap == WORD_WRAP)
- it_backup = *it;
+ SAVE_IT (it_backup, *it, backup_data);
/* TO_Y specified means stop at TO_X in the line containing
TO_Y---or at TO_CHARPOS if this is reached first. The
reached = 6;
break;
}
- it_backup = *it;
+ SAVE_IT (it_backup, *it, backup_data);
TRACE_MOVE ((stderr, "move_it: from %d\n", IT_CHARPOS (*it)));
skip2 = move_it_in_display_line_to (it, to_charpos, -1,
op & MOVE_TO_POS);
/* If TO_Y is in this line and TO_X was reached
above, we scanned too far. We have to restore
IT's settings to the ones before skipping. */
- *it = it_backup;
+ RESTORE_IT (it, &it_backup, backup_data);
reached = 6;
}
else
&& it->line_wrap == WORD_WRAP)
{
int prev_x = max (it->current_x - 1, 0);
- *it = it_backup;
+ RESTORE_IT (it, &it_backup, backup_data);
skip = move_it_in_display_line_to
(it, -1, prev_x, MOVE_TO_X);
}
last_max_ascent = it->max_ascent;
}
+ if (backup_data)
+ xfree (backup_data);
+
TRACE_MOVE ((stderr, "move_it_to: reached %d\n", reached));
}
{
int nlines, h;
struct it it2, it3;
+ void *it2data = NULL, *it3data = NULL;
EMACS_INT start_pos;
move_further_back:
start of the next line so that we get its height. We need this
height to be able to tell whether we reached the specified
y-distance. */
- it2 = *it;
+ SAVE_IT (it2, *it, it2data);
it2.max_ascent = it2.max_descent = 0;
do
{
}
while (!IT_POS_VALID_AFTER_MOVE_P (&it2));
xassert (IT_CHARPOS (*it) >= BEGV);
- it3 = it2;
+ SAVE_IT (it3, it2, it3data);
move_it_to (&it2, start_pos, -1, -1, -1, MOVE_TO_POS);
xassert (IT_CHARPOS (*it) >= BEGV);
{
/* DY == 0 means move to the start of the screen line. The
value of nlines is > 0 if continuation lines were involved. */
+ RESTORE_IT (it, it, it2data);
if (nlines > 0)
move_it_by_lines (it, nlines);
+ xfree (it3data);
}
else
{
Note that H has been subtracted in front of the if-statement. */
int target_y = it->current_y + h - dy;
int y0 = it3.current_y;
- int y1 = line_bottom_y (&it3);
- int line_height = y1 - y0;
+ int y1;
+ int line_height;
+ RESTORE_IT (&it3, &it3, it3data);
+ y1 = line_bottom_y (&it3);
+ line_height = y1 - y0;
+ RESTORE_IT (it, it, it2data);
/* If we did not reach target_y, try to move further backward if
we can. If we moved too far backward, try to move forward. */
if (target_y < it->current_y
else
{
struct it it2;
+ void *it2data = NULL;
EMACS_INT start_charpos, i;
/* Start at the beginning of the screen line containing IT's
/* Above call may have moved too far if continuation lines
are involved. Scan forward and see if it did. */
- it2 = *it;
+ SAVE_IT (it2, *it, it2data);
it2.vpos = it2.current_y = 0;
move_it_to (&it2, start_charpos, -1, -1, -1, MOVE_TO_POS);
it->vpos -= it2.vpos;
if (it2.vpos > -dvpos)
{
int delta = it2.vpos + dvpos;
- it2 = *it;
+
+ RESTORE_IT (&it2, &it2, it2data);
+ SAVE_IT (it2, *it, it2data);
move_it_to (it, -1, -1, -1, it->vpos + delta, MOVE_TO_VPOS);
/* Move back again if we got too far ahead. */
if (IT_CHARPOS (*it) >= start_charpos)
- *it = it2;
+ RESTORE_IT (it, &it2, it2data);
+ else
+ xfree (it2data);
}
+ else
+ RESTORE_IT (it, it, it2data);
}
}
if (nlflag)
{
EMACS_INT this_bol, this_bol_byte, prev_bol, prev_bol_byte;
- unsigned long int dups;
+ printmax_t dups;
insert_1 ("\n", 1, 1, 0, 0);
scan_newline (Z, Z_BYTE, BEG, BEG_BYTE, -2, 0);
this_bol, this_bol_byte, 0);
if (dups > 1)
{
- char dupstr[40];
+ char dupstr[sizeof " [ times]"
+ + INT_STRLEN_BOUND (printmax_t)];
int duplen;
/* If you change this format, don't forget to also
change message_log_check_duplicate. */
- sprintf (dupstr, " [%lu times]", dups);
+ sprintf (dupstr, " [%"pMd" times]", dups);
duplen = strlen (dupstr);
TEMP_SET_PT_BOTH (Z - 1, Z_BYTE - 1);
insert_1 (dupstr, duplen, 1, 0, 1);
Return 0 if different, 1 if the new one should just replace it, or a
value N > 1 if we should also append " [N times]". */
-static unsigned long int
+static intmax_t
message_log_check_duplicate (EMACS_INT prev_bol_byte, EMACS_INT this_bol_byte)
{
EMACS_INT i;
if (*p1++ == ' ' && *p1++ == '[')
{
char *pend;
- unsigned long int n = strtoul ((char *) p1, &pend, 10);
- if (strncmp (pend, " times]\n", 8) == 0)
+ intmax_t n = strtoimax ((char *) p1, &pend, 10);
+ if (0 < n && n < INTMAX_MAX && strncmp (pend, " times]\n", 8) == 0)
return n+1;
}
return 0;
{
if (m)
{
- size_t len;
+ ptrdiff_t len;
len = doprnt (FRAME_MESSAGE_BUF (f),
FRAME_MESSAGE_BUF_SIZE (f), m, (char *)0, ap);
double the buffer's size. */
if (mode_line_noprop_ptr == mode_line_noprop_buf_end)
{
- int len = MODE_LINE_NOPROP_LEN (0);
- int new_size = 2 * len * sizeof *mode_line_noprop_buf;
+ ptrdiff_t len = MODE_LINE_NOPROP_LEN (0);
+ ptrdiff_t new_size;
+
+ if (STRING_BYTES_BOUND / 2 < len)
+ memory_full (SIZE_MAX);
+ new_size = 2 * len;
mode_line_noprop_buf = (char *) xrealloc (mode_line_noprop_buf, new_size);
mode_line_noprop_buf_end = mode_line_noprop_buf + new_size;
mode_line_noprop_ptr = mode_line_noprop_buf + len;
/* Do we have more than one visible frame on this X display? */
Lisp_Object tail;
Lisp_Object fmt;
- int title_start;
+ ptrdiff_t title_start;
char *title;
- int len;
+ ptrdiff_t len;
struct it it;
int count = SPECPDL_INDEX ();
++i;
}
- /* Stop at line ends. */
+ /* Stop at line end. */
if (ITERATOR_AT_END_OF_LINE_P (it))
break;
it.first_visible_x = 0;
it.last_visible_x = FRAME_TOTAL_COLS (f) * FRAME_COLUMN_WIDTH (f);
reseat_to_string (&it, NULL, f->desired_tool_bar_string, 0, 0, 0, -1);
+ it.paragraph_embedding = L2R;
while (!ITERATOR_AT_END_P (&it))
{
f = XFRAME (frame);
if (WINDOWP (f->tool_bar_window)
- || (w = XWINDOW (f->tool_bar_window),
+ && (w = XWINDOW (f->tool_bar_window),
WINDOW_TOTAL_LINES (w) > 0))
{
update_tool_bar (f, 1);
/* Build a string that represents the contents of the tool-bar. */
build_desired_tool_bar_string (f);
reseat_to_string (&it, NULL, f->desired_tool_bar_string, 0, 0, 0, -1);
+ /* FIXME: This should be controlled by a user option. But it
+ doesn't make sense to have an R2L tool bar if the menu bar cannot
+ be drawn also R2L, and making the menu bar R2L is tricky due
+ toolkit-specific code that implements it. If an R2L tool bar is
+ ever supported, display_tool_bar_line should also be augmented to
+ call unproduce_glyphs like display_line and display_string
+ do. */
+ it.paragraph_embedding = L2R;
if (f->n_tool_bar_rows == 0)
{
/* First and last unchanged row for try_window_id. */
-int debug_first_unchanged_at_end_vpos;
-int debug_last_unchanged_at_beg_vpos;
+static int debug_first_unchanged_at_end_vpos;
+static int debug_last_unchanged_at_beg_vpos;
/* Delta vpos and y. */
-int debug_dvpos, debug_dy;
+static int debug_dvpos, debug_dy;
/* Delta in characters and bytes for try_window_id. */
-EMACS_INT debug_delta, debug_delta_bytes;
+static EMACS_INT debug_delta, debug_delta_bytes;
/* Values of window_end_pos and window_end_vpos at the end of
try_window_id. */
-EMACS_INT debug_end_vpos;
+static EMACS_INT debug_end_vpos;
/* Append a string to W->desired_matrix->method. FMT is a printf
- format string. A1...A9 are a supplement for a variable-length
- argument list. If trace_redisplay_p is non-zero also printf the
+ format string. If trace_redisplay_p is non-zero also printf the
resulting string to stderr. */
+static void debug_method_add (struct window *, char const *, ...)
+ ATTRIBUTE_FORMAT_PRINTF (2, 3);
+
static void
-debug_method_add (w, fmt, a1, a2, a3, a4, a5, a6, a7, a8, a9)
- struct window *w;
- char *fmt;
- int a1, a2, a3, a4, a5, a6, a7, a8, a9;
+debug_method_add (struct window *w, char const *fmt, ...)
{
char buffer[512];
char *method = w->desired_matrix->method;
int len = strlen (method);
int size = sizeof w->desired_matrix->method;
int remaining = size - len - 1;
+ va_list ap;
- sprintf (buffer, fmt, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+ va_start (ap, fmt);
+ vsprintf (buffer, fmt, ap);
+ va_end (ap);
if (len && remaining)
{
method[len] = '|';
fprintf (stderr, "%p (%s): %s\n",
w,
((BUFFERP (w->buffer)
- && STRINGP (XBUFFER (w->buffer)->name))
- ? SSDATA (XBUFFER (w->buffer)->name)
+ && STRINGP (BVAR (XBUFFER (w->buffer), name)))
+ ? SSDATA (BVAR (XBUFFER (w->buffer), name))
: "no buffer"),
buffer);
}
which was computed as distance from window bottom to
point. This matters when lines at window top and lines
below window bottom have different height. */
- struct it it1 = it;
+ struct it it1;
+ void *it1data = NULL;
/* We use a temporary it1 because line_bottom_y can modify
its argument, if it moves one line down; see there. */
- int start_y = line_bottom_y (&it1);
+ int start_y;
+ SAVE_IT (it1, it, it1data);
+ start_y = line_bottom_y (&it1);
do {
+ RESTORE_IT (&it, &it, it1data);
move_it_by_lines (&it, 1);
- it1 = it;
+ SAVE_IT (it1, it, it1data);
} while (line_bottom_y (&it1) - start_y < amount_to_scroll);
}
&& BEGV <= CHARPOS (startp) && CHARPOS (startp) <= ZV)
{
struct it it1;
+ void *it1data = NULL;
+ SAVE_IT (it1, it, it1data);
start_display (&it1, w, startp);
move_it_vertically (&it1, margin);
margin_pos = IT_CHARPOS (it1);
+ RESTORE_IT (&it, &it, it1data);
}
scrolling_up = PT > margin_pos;
aggressive =
#if GLYPH_DEBUG
-void dump_glyph_row (struct glyph_row *, int, int);
-void dump_glyph_matrix (struct glyph_matrix *, int);
-void dump_glyph (struct glyph_row *, struct glyph *, int);
+void dump_glyph_row (struct glyph_row *, int, int) EXTERNALLY_VISIBLE;
+void dump_glyph_matrix (struct glyph_matrix *, int) EXTERNALLY_VISIBLE;
+void dump_glyph (struct glyph_row *, struct glyph *, int) EXTERNALLY_VISIBLE;
/* Dump the contents of glyph matrix MATRIX on stderr.
GLYPHS > 1 means show glyphs in long form. */
void
-dump_glyph_matrix (matrix, glyphs)
- struct glyph_matrix *matrix;
- int glyphs;
+dump_glyph_matrix (struct glyph_matrix *matrix, int glyphs)
{
int i;
for (i = 0; i < matrix->nrows; ++i)
the glyph row and area where the glyph comes from. */
void
-dump_glyph (row, glyph, area)
- struct glyph_row *row;
- struct glyph *glyph;
- int area;
+dump_glyph (struct glyph_row *row, struct glyph *glyph, int area)
{
if (glyph->type == CHAR_GLYPH)
{
fprintf (stderr,
- " %5d %4c %6d %c %3d 0x%05x %c %4d %1.1d%1.1d\n",
+ " %5td %4c %6"pI"d %c %3d 0x%05x %c %4d %1.1d%1.1d\n",
glyph - row->glyphs[TEXT_AREA],
'C',
glyph->charpos,
else if (glyph->type == STRETCH_GLYPH)
{
fprintf (stderr,
- " %5d %4c %6d %c %3d 0x%05x %c %4d %1.1d%1.1d\n",
+ " %5td %4c %6"pI"d %c %3d 0x%05x %c %4d %1.1d%1.1d\n",
glyph - row->glyphs[TEXT_AREA],
'S',
glyph->charpos,
else if (glyph->type == IMAGE_GLYPH)
{
fprintf (stderr,
- " %5d %4c %6d %c %3d 0x%05x %c %4d %1.1d%1.1d\n",
+ " %5td %4c %6"pI"d %c %3d 0x%05x %c %4d %1.1d%1.1d\n",
glyph - row->glyphs[TEXT_AREA],
'I',
glyph->charpos,
else if (glyph->type == COMPOSITE_GLYPH)
{
fprintf (stderr,
- " %5d %4c %6d %c %3d 0x%05x",
+ " %5td %4c %6"pI"d %c %3d 0x%05x",
glyph - row->glyphs[TEXT_AREA],
'+',
glyph->charpos,
GLYPHS > 1 means show glyphs in long form. */
void
-dump_glyph_row (row, vpos, glyphs)
- struct glyph_row *row;
- int vpos, glyphs;
+dump_glyph_row (struct glyph_row *row, int vpos, int glyphs)
{
if (glyphs != 1)
{
fprintf (stderr, "Row Start End Used oE><\\CTZFesm X Y W H V A P\n");
fprintf (stderr, "======================================================================\n");
- fprintf (stderr, "%3d %5d %5d %4d %1.1d%1.1d%1.1d%1.1d\
+ fprintf (stderr, "%3d %5"pI"d %5"pI"d %4d %1.1d%1.1d%1.1d%1.1d\
%1.1d%1.1d%1.1d%1.1d%1.1d%1.1d%1.1d%1.1d %4d %4d %4d %4d %4d %4d %4d\n",
vpos,
MATRIX_ROW_START_CHARPOS (row),
fprintf (stderr, "%9d %5d\t%5d\n", row->start.overlay_string_index,
row->end.overlay_string_index,
row->continuation_lines_width);
- fprintf (stderr, "%9d %5d\n",
+ fprintf (stderr, "%9"pI"d %5"pI"d\n",
CHARPOS (row->start.string_pos),
CHARPOS (row->end.string_pos));
fprintf (stderr, "%9d %5d\n", row->start.dpvec_index,
struct window *w = XWINDOW (selected_window);
struct buffer *buffer = XBUFFER (w->buffer);
- fprintf (stderr, "PT = %d, BEGV = %d. ZV = %d\n",
+ fprintf (stderr, "PT = %"pI"d, BEGV = %"pI"d. ZV = %"pI"d\n",
BUF_PT (buffer), BUF_BEGV (buffer), BUF_ZV (buffer));
fprintf (stderr, "Cursor x = %d, y = %d, hpos = %d, vpos = %d\n",
w->cursor.x, w->cursor.y, w->cursor.hpos, w->cursor.vpos);
static int
push_display_prop (struct it *it, Lisp_Object prop)
{
+ xassert (it->method == GET_FROM_BUFFER);
+
push_it (it, NULL);
if (STRINGP (prop))
it->end_charpos = it->string_nchars = SCHARS (it->string);
it->method = GET_FROM_STRING;
it->stop_charpos = 0;
+ it->prev_stop = 0;
+ it->base_level_stop = 0;
+ it->string_from_display_prop_p = 1;
+ it->from_disp_prop_p = 1;
+
+ /* Force paragraph direction to be that of the parent
+ buffer. */
+ if (it->bidi_p && it->bidi_it.paragraph_dir == R2L)
+ it->paragraph_embedding = it->bidi_it.paragraph_dir;
+ else
+ it->paragraph_embedding = L2R;
+
+ /* Set up the bidi iterator for this display string. */
+ if (it->bidi_p)
+ {
+ it->bidi_it.string.lstring = it->string;
+ it->bidi_it.string.s = NULL;
+ it->bidi_it.string.schars = it->end_charpos;
+ it->bidi_it.string.bufpos = IT_CHARPOS (*it);
+ it->bidi_it.string.from_disp_str = 1;
+ it->bidi_it.string.unibyte = !it->multibyte_p;
+ bidi_init_it (0, 0, FRAME_WINDOW_P (it->f), &it->bidi_it);
+ }
}
else if (CONSP (prop) && EQ (XCAR (prop), Qspace))
{
handle_line_prefix (struct it *it)
{
Lisp_Object prefix;
+
if (it->continuation_lines_width > 0)
{
prefix = get_it_property (it, Qwrap_prefix);
\f
/* Remove N glyphs at the start of a reversed IT->glyph_row. Called
- only for R2L lines from display_line, when it decides that too many
- glyphs were produced by PRODUCE_GLYPHS, and the line needs to be
- continued. */
+ only for R2L lines from display_line and display_string, when they
+ decide that too many glyphs were produced by PRODUCE_GLYPHS, and
+ the line/string needs to be continued on the next glyph row. */
static void
unproduce_glyphs (struct it *it, int n)
{
lines' rows is implemented for bidi-reordered rows. */
/* ROW->minpos is the value of min_pos, the minimal buffer position
- we have in ROW. */
- if (min_pos <= ZV)
+ we have in ROW, or ROW->start.pos if that is smaller. */
+ if (min_pos <= ZV && min_pos < row->start.pos.charpos)
SET_TEXT_POS (row->minpos, min_pos, min_bpos);
else
- /* We didn't find _any_ valid buffer positions in any of the
- glyphs, so we must trust the iterator's computed positions. */
+ /* We didn't find buffer positions smaller than ROW->start, or
+ didn't find _any_ valid buffer positions in any of the glyphs,
+ so we must trust the iterator's computed positions. */
row->minpos = row->start.pos;
if (max_pos <= 0)
{
struct glyph_row *row = it->glyph_row;
Lisp_Object overlay_arrow_string;
struct it wrap_it;
+ void *wrap_data = NULL;
int may_wrap = 0, wrap_x IF_LINT (= 0);
int wrap_row_used = -1;
int wrap_row_ascent IF_LINT (= 0), wrap_row_height IF_LINT (= 0);
may_wrap = 1;
else if (may_wrap)
{
- wrap_it = *it;
+ SAVE_IT (wrap_it, *it, wrap_data);
wrap_x = x;
wrap_row_used = row->used[TEXT_AREA];
wrap_row_ascent = row->ascent;
if (row->reversed_p)
unproduce_glyphs (it,
row->used[TEXT_AREA] - wrap_row_used);
- *it = wrap_it;
+ RESTORE_IT (it, &wrap_it, wrap_data);
it->continuation_lines_width += wrap_x;
row->used[TEXT_AREA] = wrap_row_used;
row->ascent = wrap_row_ascent;
itb.charpos = pos;
itb.bytepos = bytepos;
itb.nchars = -1;
+ itb.string.s = NULL;
+ itb.string.lstring = Qnil;
itb.frame_window_p = FRAME_WINDOW_P (SELECTED_FRAME ()); /* guesswork */
itb.first_elt = 1;
itb.separator_limit = -1;
}
#endif /* not USE_X_TOOLKIT */
+ /* FIXME: This should be controlled by a user option. See the
+ comments in redisplay_tool_bar and display_mode_line about
+ this. */
+ it.paragraph_embedding = L2R;
+
if (! mode_line_inverse_video)
/* Force the menu-bar to be displayed in the default face. */
it.base_face_id = it.face_id = DEFAULT_FACE_ID;
/* Force the mode-line to be displayed in the default face. */
it.base_face_id = it.face_id = DEFAULT_FACE_ID;
+ /* FIXME: This should be controlled by a user option. But
+ supporting such an option is not trivial, since the mode line is
+ made up of many separate strings. */
+ it.paragraph_embedding = L2R;
+
record_unwind_protect (unwind_format_mode_line,
format_mode_line_unwind_data (NULL, Qnil, 0));
break;
case MODE_LINE_STRING:
{
- int len = strlen (spec);
- Lisp_Object tem = make_string (spec, len);
+ Lisp_Object tem = build_string (spec);
props = Ftext_properties_at (make_number (charpos), elt);
/* Should only keep face property in props */
n += store_mode_line_string (NULL, tem, 0, field, prec, props);
int hpos_at_start = it->hpos;
int saved_face_id = it->face_id;
struct glyph_row *row = it->glyph_row;
+ EMACS_INT it_charpos;
/* Initialize the iterator IT for iteration over STRING beginning
with index START. */
if (string && STRINGP (lisp_string))
/* LISP_STRING is the one returned by decode_mode_spec. We should
ignore its text properties. */
- it->stop_charpos = -1;
+ it->stop_charpos = it->end_charpos;
- /* If displaying STRING, set up the face of the iterator
- from LISP_STRING, if that's given. */
+ /* If displaying STRING, set up the face of the iterator from
+ FACE_STRING, if that's given. */
if (STRINGP (face_string))
{
EMACS_INT endptr;
row->phys_height = it->max_phys_ascent + it->max_phys_descent;
row->extra_line_spacing = it->max_extra_line_spacing;
+ if (STRINGP (it->string))
+ it_charpos = IT_STRING_CHARPOS (*it);
+ else
+ it_charpos = IT_CHARPOS (*it);
+
/* This condition is for the case that we are called with current_x
past last_visible_x. */
while (it->current_x < max_x)
/* Produce glyphs. */
x_before = it->current_x;
- n_glyphs_before = it->glyph_row->used[TEXT_AREA];
+ n_glyphs_before = row->used[TEXT_AREA];
PRODUCE_GLYPHS (it);
- nglyphs = it->glyph_row->used[TEXT_AREA] - n_glyphs_before;
+ nglyphs = row->used[TEXT_AREA] - n_glyphs_before;
i = 0;
x = x_before;
while (i < nglyphs)
if (CHAR_GLYPH_PADDING_P (*glyph))
{
/* A wide character is unbreakable. */
- it->glyph_row->used[TEXT_AREA] = n_glyphs_before;
+ if (row->reversed_p)
+ unproduce_glyphs (it, row->used[TEXT_AREA]
+ - n_glyphs_before);
+ row->used[TEXT_AREA] = n_glyphs_before;
it->current_x = x_before;
}
else
{
- it->glyph_row->used[TEXT_AREA] = n_glyphs_before + i;
+ if (row->reversed_p)
+ unproduce_glyphs (it, row->used[TEXT_AREA]
+ - (n_glyphs_before + i));
+ row->used[TEXT_AREA] = n_glyphs_before + i;
it->current_x = x;
}
break;
/* Glyph is at least partially visible. */
++it->hpos;
if (x < it->first_visible_x)
- it->glyph_row->x = x - it->first_visible_x;
+ row->x = x - it->first_visible_x;
}
else
{
}
set_iterator_to_next (it, 1);
+ if (STRINGP (it->string))
+ it_charpos = IT_STRING_CHARPOS (*it);
+ else
+ it_charpos = IT_CHARPOS (*it);
/* Stop if truncating at the right edge. */
if (it->line_wrap == TRUNCATE
{
/* Add truncation mark, but don't do it if the line is
truncated at a padding space. */
- if (IT_CHARPOS (*it) < it->string_nchars)
+ if (it_charpos < it->string_nchars)
{
if (!FRAME_WINDOW_P (it->f))
{
if (it->current_x > it->last_visible_x)
{
- for (ii = row->used[TEXT_AREA] - 1; ii > 0; --ii)
- if (!CHAR_GLYPH_PADDING_P (row->glyphs[TEXT_AREA][ii]))
- break;
+ if (!row->reversed_p)
+ {
+ for (ii = row->used[TEXT_AREA] - 1; ii > 0; --ii)
+ if (!CHAR_GLYPH_PADDING_P (row->glyphs[TEXT_AREA][ii]))
+ break;
+ }
+ else
+ {
+ for (ii = 0; ii < row->used[TEXT_AREA]; ii++)
+ if (!CHAR_GLYPH_PADDING_P (row->glyphs[TEXT_AREA][ii]))
+ break;
+ unproduce_glyphs (it, ii + 1);
+ ii = row->used[TEXT_AREA] - (ii + 1);
+ }
for (n = row->used[TEXT_AREA]; ii < n; ++ii)
{
row->used[TEXT_AREA] = ii;
}
produce_special_glyphs (it, IT_TRUNCATION);
}
- it->glyph_row->truncated_on_right_p = 1;
+ row->truncated_on_right_p = 1;
}
break;
}
/* Maybe insert a truncation at the left. */
if (it->first_visible_x
- && IT_CHARPOS (*it) > 0)
+ && it_charpos > 0)
{
if (!FRAME_WINDOW_P (it->f))
insert_left_trunc_glyphs (it);
- it->glyph_row->truncated_on_left_p = 1;
+ row->truncated_on_left_p = 1;
}
it->face_id = saved_face_id;
if (FRAME_WINDOW_P (it->f)
&& valid_image_p (prop))
{
- int id = lookup_image (it->f, prop);
+ ptrdiff_t id = lookup_image (it->f, prop);
struct image *img = IMAGE_FROM_ID (it->f, id);
return OK_PIXELS (width_p ? img->width : img->height);
#if GLYPH_DEBUG
void
-dump_glyph_string (s)
- struct glyph_string *s;
+dump_glyph_string (struct glyph_string *s)
{
fprintf (stderr, "glyph string\n");
fprintf (stderr, " x, y, w, h = %d, %d, %d, %d\n",
do { \
int face_id = (row)->glyphs[area][START].face_id; \
struct face *base_face = FACE_FROM_ID (f, face_id); \
- int cmp_id = (row)->glyphs[area][START].u.cmp.id; \
+ ptrdiff_t cmp_id = (row)->glyphs[area][START].u.cmp.id; \
struct composition *cmp = composition_table[cmp_id]; \
XChar2b *char2b; \
struct glyph_string *first_s IF_LINT (= NULL); \
base_width = font->average_width;
/* Get a face ID for the glyph by utilizing a cache (the same way as
- doen for `escape-glyph' in get_next_display_element). */
+ done for `escape-glyph' in get_next_display_element). */
if (it->f == last_glyphless_glyph_frame
&& it->face_id == last_glyphless_glyph_face_id)
{
while (g < e)
{
- if (BUFFERP (g->object)
+ if ((BUFFERP (g->object) || INTEGERP (g->object))
&& start_charpos <= g->charpos && g->charpos < end_charpos)
*start = row;
g++;
while (g < e)
{
- if (BUFFERP (g->object)
+ if ((BUFFERP (g->object) || INTEGERP (g->object))
&& start_charpos <= g->charpos && g->charpos < end_charpos)
break;
g++;
&& XFASTINT (w->last_modified) == BUF_MODIFF (b)
&& XFASTINT (w->last_overlay_modified) == BUF_OVERLAY_MODIFF (b))
{
- int hpos, vpos, i, dx, dy, area;
+ int hpos, vpos, dx, dy, area;
EMACS_INT pos;
struct glyph *glyph;
Lisp_Object object;
Lisp_Object mouse_face = Qnil, position;
Lisp_Object *overlay_vec = NULL;
- int noverlays;
+ ptrdiff_t i, noverlays;
struct buffer *obuf;
EMACS_INT obegv, ozv;
int same_region;
Vmessage_stack = Qnil;
staticpro (&Vmessage_stack);
- Qinhibit_redisplay = intern_c_string ("inhibit-redisplay");
- staticpro (&Qinhibit_redisplay);
+ DEFSYM (Qinhibit_redisplay, "inhibit-redisplay");
message_dolog_marker1 = Fmake_marker ();
staticpro (&message_dolog_marker1);
defsubr (&Sinvisible_p);
defsubr (&Scurrent_bidi_paragraph_direction);
- staticpro (&Qmenu_bar_update_hook);
- Qmenu_bar_update_hook = intern_c_string ("menu-bar-update-hook");
-
- staticpro (&Qoverriding_terminal_local_map);
- Qoverriding_terminal_local_map = intern_c_string ("overriding-terminal-local-map");
-
- staticpro (&Qoverriding_local_map);
- Qoverriding_local_map = intern_c_string ("overriding-local-map");
-
- staticpro (&Qwindow_scroll_functions);
- Qwindow_scroll_functions = intern_c_string ("window-scroll-functions");
-
- staticpro (&Qwindow_text_change_functions);
- Qwindow_text_change_functions = intern_c_string ("window-text-change-functions");
-
- staticpro (&Qredisplay_end_trigger_functions);
- Qredisplay_end_trigger_functions = intern_c_string ("redisplay-end-trigger-functions");
-
- staticpro (&Qinhibit_point_motion_hooks);
- Qinhibit_point_motion_hooks = intern_c_string ("inhibit-point-motion-hooks");
-
- Qeval = intern_c_string ("eval");
- staticpro (&Qeval);
-
- QCdata = intern_c_string (":data");
- staticpro (&QCdata);
- Qdisplay = intern_c_string ("display");
- staticpro (&Qdisplay);
- Qspace_width = intern_c_string ("space-width");
- staticpro (&Qspace_width);
- Qraise = intern_c_string ("raise");
- staticpro (&Qraise);
- Qslice = intern_c_string ("slice");
- staticpro (&Qslice);
- Qspace = intern_c_string ("space");
- staticpro (&Qspace);
- Qmargin = intern_c_string ("margin");
- staticpro (&Qmargin);
- Qpointer = intern_c_string ("pointer");
- staticpro (&Qpointer);
- Qleft_margin = intern_c_string ("left-margin");
- staticpro (&Qleft_margin);
- Qright_margin = intern_c_string ("right-margin");
- staticpro (&Qright_margin);
- Qcenter = intern_c_string ("center");
- staticpro (&Qcenter);
- Qline_height = intern_c_string ("line-height");
- staticpro (&Qline_height);
- QCalign_to = intern_c_string (":align-to");
- staticpro (&QCalign_to);
- QCrelative_width = intern_c_string (":relative-width");
- staticpro (&QCrelative_width);
- QCrelative_height = intern_c_string (":relative-height");
- staticpro (&QCrelative_height);
- QCeval = intern_c_string (":eval");
- staticpro (&QCeval);
- QCpropertize = intern_c_string (":propertize");
- staticpro (&QCpropertize);
- QCfile = intern_c_string (":file");
- staticpro (&QCfile);
- Qfontified = intern_c_string ("fontified");
- staticpro (&Qfontified);
- Qfontification_functions = intern_c_string ("fontification-functions");
- staticpro (&Qfontification_functions);
- Qtrailing_whitespace = intern_c_string ("trailing-whitespace");
- staticpro (&Qtrailing_whitespace);
- Qescape_glyph = intern_c_string ("escape-glyph");
- staticpro (&Qescape_glyph);
- Qnobreak_space = intern_c_string ("nobreak-space");
- staticpro (&Qnobreak_space);
- Qimage = intern_c_string ("image");
- staticpro (&Qimage);
- Qtext = intern_c_string ("text");
- staticpro (&Qtext);
- Qboth = intern_c_string ("both");
- staticpro (&Qboth);
- Qboth_horiz = intern_c_string ("both-horiz");
- staticpro (&Qboth_horiz);
- Qtext_image_horiz = intern_c_string ("text-image-horiz");
- staticpro (&Qtext_image_horiz);
- QCmap = intern_c_string (":map");
- staticpro (&QCmap);
- QCpointer = intern_c_string (":pointer");
- staticpro (&QCpointer);
- Qrect = intern_c_string ("rect");
- staticpro (&Qrect);
- Qcircle = intern_c_string ("circle");
- staticpro (&Qcircle);
- Qpoly = intern_c_string ("poly");
- staticpro (&Qpoly);
- Qmessage_truncate_lines = intern_c_string ("message-truncate-lines");
- staticpro (&Qmessage_truncate_lines);
- Qgrow_only = intern_c_string ("grow-only");
- staticpro (&Qgrow_only);
- Qinhibit_menubar_update = intern_c_string ("inhibit-menubar-update");
- staticpro (&Qinhibit_menubar_update);
- Qinhibit_eval_during_redisplay = intern_c_string ("inhibit-eval-during-redisplay");
- staticpro (&Qinhibit_eval_during_redisplay);
- Qposition = intern_c_string ("position");
- staticpro (&Qposition);
- Qbuffer_position = intern_c_string ("buffer-position");
- staticpro (&Qbuffer_position);
- Qobject = intern_c_string ("object");
- staticpro (&Qobject);
- Qbar = intern_c_string ("bar");
- staticpro (&Qbar);
- Qhbar = intern_c_string ("hbar");
- staticpro (&Qhbar);
- Qbox = intern_c_string ("box");
- staticpro (&Qbox);
- Qhollow = intern_c_string ("hollow");
- staticpro (&Qhollow);
- Qhand = intern_c_string ("hand");
- staticpro (&Qhand);
- Qarrow = intern_c_string ("arrow");
- staticpro (&Qarrow);
- Qtext = intern_c_string ("text");
- staticpro (&Qtext);
- Qinhibit_free_realized_faces = intern_c_string ("inhibit-free-realized-faces");
- staticpro (&Qinhibit_free_realized_faces);
+ DEFSYM (Qmenu_bar_update_hook, "menu-bar-update-hook");
+ DEFSYM (Qoverriding_terminal_local_map, "overriding-terminal-local-map");
+ DEFSYM (Qoverriding_local_map, "overriding-local-map");
+ DEFSYM (Qwindow_scroll_functions, "window-scroll-functions");
+ DEFSYM (Qwindow_text_change_functions, "window-text-change-functions");
+ DEFSYM (Qredisplay_end_trigger_functions, "redisplay-end-trigger-functions");
+ DEFSYM (Qinhibit_point_motion_hooks, "inhibit-point-motion-hooks");
+ DEFSYM (Qeval, "eval");
+ DEFSYM (QCdata, ":data");
+ DEFSYM (Qdisplay, "display");
+ DEFSYM (Qspace_width, "space-width");
+ DEFSYM (Qraise, "raise");
+ DEFSYM (Qslice, "slice");
+ DEFSYM (Qspace, "space");
+ DEFSYM (Qmargin, "margin");
+ DEFSYM (Qpointer, "pointer");
+ DEFSYM (Qleft_margin, "left-margin");
+ DEFSYM (Qright_margin, "right-margin");
+ DEFSYM (Qcenter, "center");
+ DEFSYM (Qline_height, "line-height");
+ DEFSYM (QCalign_to, ":align-to");
+ DEFSYM (QCrelative_width, ":relative-width");
+ DEFSYM (QCrelative_height, ":relative-height");
+ DEFSYM (QCeval, ":eval");
+ DEFSYM (QCpropertize, ":propertize");
+ DEFSYM (QCfile, ":file");
+ DEFSYM (Qfontified, "fontified");
+ DEFSYM (Qfontification_functions, "fontification-functions");
+ DEFSYM (Qtrailing_whitespace, "trailing-whitespace");
+ DEFSYM (Qescape_glyph, "escape-glyph");
+ DEFSYM (Qnobreak_space, "nobreak-space");
+ DEFSYM (Qimage, "image");
+ DEFSYM (Qtext, "text");
+ DEFSYM (Qboth, "both");
+ DEFSYM (Qboth_horiz, "both-horiz");
+ DEFSYM (Qtext_image_horiz, "text-image-horiz");
+ DEFSYM (QCmap, ":map");
+ DEFSYM (QCpointer, ":pointer");
+ DEFSYM (Qrect, "rect");
+ DEFSYM (Qcircle, "circle");
+ DEFSYM (Qpoly, "poly");
+ DEFSYM (Qmessage_truncate_lines, "message-truncate-lines");
+ DEFSYM (Qgrow_only, "grow-only");
+ DEFSYM (Qinhibit_menubar_update, "inhibit-menubar-update");
+ DEFSYM (Qinhibit_eval_during_redisplay, "inhibit-eval-during-redisplay");
+ DEFSYM (Qposition, "position");
+ DEFSYM (Qbuffer_position, "buffer-position");
+ DEFSYM (Qobject, "object");
+ DEFSYM (Qbar, "bar");
+ DEFSYM (Qhbar, "hbar");
+ DEFSYM (Qbox, "box");
+ DEFSYM (Qhollow, "hollow");
+ DEFSYM (Qhand, "hand");
+ DEFSYM (Qarrow, "arrow");
+ DEFSYM (Qtext, "text");
+ DEFSYM (Qinhibit_free_realized_faces, "inhibit-free-realized-faces");
list_of_error = Fcons (Fcons (intern_c_string ("error"),
Fcons (intern_c_string ("void-variable"), Qnil)),
Qnil);
staticpro (&list_of_error);
- Qlast_arrow_position = intern_c_string ("last-arrow-position");
- staticpro (&Qlast_arrow_position);
- Qlast_arrow_string = intern_c_string ("last-arrow-string");
- staticpro (&Qlast_arrow_string);
-
- Qoverlay_arrow_string = intern_c_string ("overlay-arrow-string");
- staticpro (&Qoverlay_arrow_string);
- Qoverlay_arrow_bitmap = intern_c_string ("overlay-arrow-bitmap");
- staticpro (&Qoverlay_arrow_bitmap);
+ DEFSYM (Qlast_arrow_position, "last-arrow-position");
+ DEFSYM (Qlast_arrow_string, "last-arrow-string");
+ DEFSYM (Qoverlay_arrow_string, "overlay-arrow-string");
+ DEFSYM (Qoverlay_arrow_bitmap, "overlay-arrow-bitmap");
echo_buffer[0] = echo_buffer[1] = Qnil;
staticpro (&echo_buffer[0]);
staticpro (&previous_help_echo_string);
help_echo_pos = -1;
- Qright_to_left = intern_c_string ("right-to-left");
- staticpro (&Qright_to_left);
- Qleft_to_right = intern_c_string ("left-to-right");
- staticpro (&Qleft_to_right);
+ DEFSYM (Qright_to_left, "right-to-left");
+ DEFSYM (Qleft_to_right, "left-to-right");
#ifdef HAVE_WINDOW_SYSTEM
DEFVAR_BOOL ("x-stretch-cursor", x_stretch_cursor_p,
unibyte_display_via_language_environment = 0;
DEFVAR_LISP ("max-mini-window-height", Vmax_mini_window_height,
- doc: /* *Maximum height for resizing mini-windows.
+ doc: /* *Maximum height for resizing mini-windows (the minibuffer and the echo area).
If a float, it specifies a fraction of the mini-window frame's height.
If an integer, it specifies a number of lines. */);
Vmax_mini_window_height = make_float (0.25);
DEFVAR_LISP ("resize-mini-windows", Vresize_mini_windows,
- doc: /* *How to resize mini-windows.
+ doc: /* How to resize mini-windows (the minibuffer and the echo area).
A value of nil means don't automatically resize mini-windows.
A value of t means resize them to fit the text displayed in them.
-A value of `grow-only', the default, means let mini-windows grow
-only, until their display becomes empty, at which point the windows
-go back to their normal size. */);
+A value of `grow-only', the default, means let mini-windows grow only;
+they return to their normal size when the minibuffer is closed, or the
+echo area becomes empty. */);
Vresize_mini_windows = Qgrow_only;
DEFVAR_LISP ("blink-cursor-alist", Vblink_cursor_alist,
If non-nil, windows are automatically scrolled horizontally to make
point visible. */);
automatic_hscrolling_p = 1;
- Qauto_hscroll_mode = intern_c_string ("auto-hscroll-mode");
- staticpro (&Qauto_hscroll_mode);
+ DEFSYM (Qauto_hscroll_mode, "auto-hscroll-mode");
DEFVAR_INT ("hscroll-margin", hscroll_margin,
doc: /* *How many columns away from the window edge point is allowed to get
To add a prefix to non-continuation lines, use `line-prefix'. */);
Vwrap_prefix = Qnil;
- staticpro (&Qwrap_prefix);
- Qwrap_prefix = intern_c_string ("wrap-prefix");
+ DEFSYM (Qwrap_prefix, "wrap-prefix");
Fmake_variable_buffer_local (Qwrap_prefix);
DEFVAR_LISP ("line-prefix", Vline_prefix,
To add a prefix to continuation lines, use `wrap-prefix'. */);
Vline_prefix = Qnil;
- staticpro (&Qline_prefix);
- Qline_prefix = intern_c_string ("line-prefix");
+ DEFSYM (Qline_prefix, "line-prefix");
Fmake_variable_buffer_local (Qline_prefix);
DEFVAR_BOOL ("inhibit-eval-during-redisplay", inhibit_eval_during_redisplay,