#define SAVE_IT(ITCOPY,ITORIG,CACHE) \
do { \
if (CACHE) \
- xfree (CACHE); \
+ bidi_unshelve_cache (CACHE, 1); \
ITCOPY = ITORIG; \
CACHE = bidi_shelve_cache(); \
} while (0)
do { \
if (pITORIG != pITCOPY) \
*(pITORIG) = *(pITCOPY); \
- bidi_unshelve_cache (CACHE); \
+ bidi_unshelve_cache (CACHE, 0); \
CACHE = NULL; \
} while (0)
*vpos = it2.vpos;
}
else
- xfree (it2data);
+ bidi_unshelve_cache (it2data, 1);
}
- bidi_unshelve_cache (itdata);
+ bidi_unshelve_cache (itdata, 0);
if (old_buffer)
set_buffer_internal_1 (old_buffer);
it->paragraph_embedding = R2L;
else
it->paragraph_embedding = NEUTRAL_DIR;
- bidi_unshelve_cache (NULL);
+ bidi_unshelve_cache (NULL, 0);
bidi_init_it (charpos, IT_BYTEPOS (*it), FRAME_WINDOW_P (it->f),
&it->bidi_it);
}
EMACS_INT lim =
(charpos < eob - MAX_DISP_SCAN) ? charpos + MAX_DISP_SCAN : eob;
struct text_pos tpos;
- struct buffer *b;
*disp_prop_p = 1;
EMACS_INT eob = (buffer_p ? ZV : it->end_charpos);
EMACS_INT bob = (buffer_p ? BEGV : 0);
+ xassert (eob >= CHARPOS (it->position) && CHARPOS (it->position) >= bob);
+
/* 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. */
/* prev_stop can be zero, so check against BEGV as well. */
while (it->bidi_it.charpos >= bob
&& it->prev_stop <= it->bidi_it.charpos
- && it->bidi_it.charpos < CHARPOS (it->position))
+ && it->bidi_it.charpos < CHARPOS (it->position)
+ && it->bidi_it.charpos < eob)
bidi_move_to_visually_next (&it->bidi_it);
/* Record the stop_pos we just crossed, for when we cross it
back, maybe. */
/* If we ended up not where pop_it put us, resync IT's
positional members with the bidi iterator. */
if (it->bidi_it.charpos != CHARPOS (it->position))
- {
- SET_TEXT_POS (it->position,
- it->bidi_it.charpos, it->bidi_it.bytepos);
- if (buffer_p)
- it->current.pos = it->position;
- else
- it->current.string_pos = it->position;
- }
+ SET_TEXT_POS (it->position, it->bidi_it.charpos, it->bidi_it.bytepos);
+ if (buffer_p)
+ it->current.pos = it->position;
+ else
+ it->current.string_pos = it->position;
}
/* Restore IT's settings from IT->stack. Called, for example, when no
xassert (!STRINGP (it->string));
- /* 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);
+ /* 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 (!it->bidi_p)
+ {
+ IT_CHARPOS (*it) = limit;
+ IT_BYTEPOS (*it) = CHAR_TO_BYTE (limit);
+ }
+ else
+ {
+ struct bidi_it bprev;
+
+ /* Help bidi.c avoid expensive searches for display
+ properties and overlays, by telling it that there are
+ none up to `limit'. */
+ if (it->bidi_it.disp_pos < limit)
+ {
+ it->bidi_it.disp_pos = limit;
+ it->bidi_it.disp_prop_p = 0;
+ }
+ do {
+ bprev = it->bidi_it;
+ bidi_move_to_visually_next (&it->bidi_it);
+ } while (it->bidi_it.charpos != limit);
+ IT_CHARPOS (*it) = limit;
+ IT_BYTEPOS (*it) = it->bidi_it.bytepos;
+ if (bidi_it_prev)
+ *bidi_it_prev = bprev;
+ }
*skipped_p = newline_found_p = 1;
}
else
pos = --IT_CHARPOS (it2);
--IT_BYTEPOS (it2);
it2.sp = 0;
- bidi_unshelve_cache (NULL);
+ bidi_unshelve_cache (NULL, 0);
it2.string_from_display_prop_p = 0;
it2.from_disp_prop_p = 0;
if (handle_display_prop (&it2) == HANDLED_RETURN
{
bidi_init_it (IT_CHARPOS (*it), IT_BYTEPOS (*it), FRAME_WINDOW_P (it->f),
&it->bidi_it);
- bidi_unshelve_cache (NULL);
+ bidi_unshelve_cache (NULL, 0);
it->bidi_it.paragraph_dir = NEUTRAL_DIR;
it->bidi_it.string.s = NULL;
it->bidi_it.string.lstring = Qnil;
((op & MOVE_TO_POS) != 0 \
&& BUFFERP (it->object) \
&& (IT_CHARPOS (*it) == to_charpos \
- || (!it->bidi_p && IT_CHARPOS (*it) > to_charpos)) \
+ || (!it->bidi_p && IT_CHARPOS (*it) > to_charpos) \
+ || (it->what == IT_COMPOSITION \
+ && ((IT_CHARPOS (*it) > to_charpos \
+ && to_charpos >= it->cmp_it.charpos) \
+ || (IT_CHARPOS (*it) < to_charpos \
+ && to_charpos <= it->cmp_it.charpos)))) \
&& (it->method == GET_FROM_BUFFER \
|| (it->method == GET_FROM_DISPLAY_VECTOR \
&& it->dpvec + it->current.dpvec_index + 1 >= it->dpend)))
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)
+ if (it->bidi_p && (op & MOVE_TO_POS) != 0)
{
- result = MOVE_POS_MATCH_OR_ZV;
- if (it->bidi_p && IT_CHARPOS (ppos_it) < ZV)
- RESTORE_IT (it, &ppos_it, ppos_data);
+ if (!saw_smaller_pos && IT_CHARPOS (*it) > to_charpos)
+ {
+ if (IT_CHARPOS (ppos_it) < ZV)
+ {
+ RESTORE_IT (it, &ppos_it, ppos_data);
+ result = MOVE_POS_MATCH_OR_ZV;
+ }
+ else
+ goto buffer_pos_reached;
+ }
+ else if (it->line_wrap == WORD_WRAP && atpos_it.sp >= 0
+ && IT_CHARPOS (*it) > to_charpos)
+ goto buffer_pos_reached;
+ else
+ result = MOVE_NEWLINE_OR_CR;
}
else
result = MOVE_NEWLINE_OR_CR;
character positions smaller than TO_CHARPOS,
return MOVE_POS_MATCH_OR_ZV, like the
unidirectional display did. */
- || ((op & MOVE_TO_POS) != 0
+ || (it->bidi_p && (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)
+ if (!at_eob_p && IT_CHARPOS (ppos_it) < ZV)
RESTORE_IT (it, &ppos_it, ppos_data);
+ result = MOVE_POS_MATCH_OR_ZV;
break;
}
if (ITERATOR_AT_END_OF_LINE_P (it))
break;
}
}
- else if ((op & MOVE_TO_POS) != 0
+ else if (it->bidi_p && (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)
+ if (IT_CHARPOS (ppos_it) < ZV)
RESTORE_IT (it, &ppos_it, ppos_data);
+ result = MOVE_POS_MATCH_OR_ZV;
break;
}
result = MOVE_LINE_TRUNCATED;
done:
if (atpos_data)
- xfree (atpos_data);
+ bidi_unshelve_cache (atpos_data, 1);
if (atx_data)
- xfree (atx_data);
+ bidi_unshelve_cache (atx_data, 1);
if (wrap_data)
- xfree (wrap_data);
+ bidi_unshelve_cache (wrap_data, 1);
if (ppos_data)
- xfree (ppos_data);
+ bidi_unshelve_cache (ppos_data, 1);
/* Restore the iterator settings altered at the beginning of this
function. */
(it, -1, prev_x, MOVE_TO_X);
}
else
- xfree (save_data);
+ bidi_unshelve_cache (save_data, 1);
}
else
move_it_in_display_line_to (it, to_charpos, to_x, op);
}
if (backup_data)
- xfree (backup_data);
+ bidi_unshelve_cache (backup_data, 1);
TRACE_MOVE ((stderr, "move_it_to: reached %d\n", reached));
}
RESTORE_IT (it, it, it2data);
if (nlines > 0)
move_it_by_lines (it, nlines);
- xfree (it3data);
+ bidi_unshelve_cache (it3data, 1);
}
else
{
if (IT_CHARPOS (*it) >= start_charpos)
RESTORE_IT (it, &it2, it2data);
else
- xfree (it2data);
+ bidi_unshelve_cache (it2data, 1);
}
else
RESTORE_IT (it, it, it2data);
/* Last buffer position covered by an overlay string with an integer
`cursor' property. */
EMACS_INT bpos_covered = 0;
+ /* Non-zero means the display string on which to display the cursor
+ comes from a text property, not from an overlay. */
+ int string_from_text_prop = 0;
/* Skip over glyphs not having an object at the start and the end of
the row. These are special glyphs like truncation marks on
{
Lisp_Object str;
EMACS_INT tem;
+ /* If the display property covers the newline, we
+ need to search for it one position farther. */
+ EMACS_INT lim = pos_after
+ + (pos_after == MATRIX_ROW_END_CHARPOS (row) + delta);
+ string_from_text_prop = 0;
str = glyph->object;
- tem = string_buffer_position_lim (str, pos, pos_after, 0);
+ tem = string_buffer_position_lim (str, pos, lim, 0);
if (tem == 0 /* from overlay */
|| pos <= tem)
{
EMACS_INT strpos = glyph->charpos;
if (tem)
- cursor = glyph;
+ {
+ cursor = glyph;
+ string_from_text_prop = 1;
+ }
for ( ;
(row->reversed_p ? glyph > stop : glyph < stop)
&& EQ (glyph->object, str);
w->cursor.vpos >= 0
/* that candidate is not the row we are processing */
&& MATRIX_ROW (matrix, w->cursor.vpos) != row
- /* the row we are processing is part of a continued line */
- && (row->continued_p || MATRIX_ROW_CONTINUATION_LINE_P (row))
/* Make sure cursor.vpos specifies a row whose start and end
- charpos occlude point. This is because some callers of this
- function leave cursor.vpos at the row where the cursor was
- displayed during the last redisplay cycle. */
+ charpos occlude point, and it is valid candidate for being a
+ cursor-row. This is because some callers of this function
+ leave cursor.vpos at the row where the cursor was displayed
+ during the last redisplay cycle. */
&& MATRIX_ROW_START_CHARPOS (MATRIX_ROW (matrix, w->cursor.vpos)) <= pt_old
- && pt_old < MATRIX_ROW_END_CHARPOS (MATRIX_ROW (matrix, w->cursor.vpos)))
+ && pt_old <= MATRIX_ROW_END_CHARPOS (MATRIX_ROW (matrix, w->cursor.vpos))
+ && cursor_row_p (MATRIX_ROW (matrix, w->cursor.vpos)))
{
struct glyph *g1 =
MATRIX_ROW_GLYPH_START (matrix, w->cursor.vpos) + w->cursor.hpos;
if (!(row->reversed_p ? glyph > glyphs_end : glyph < glyphs_end))
return 0;
/* Keep the candidate whose buffer position is the closest to
- point. */
+ point or has the `cursor' property. */
if (/* previous candidate is a glyph in TEXT_AREA of that row */
w->cursor.hpos >= 0
&& w->cursor.hpos < MATRIX_ROW_USED (matrix, w->cursor.vpos)
- && BUFFERP (g1->object)
- && (g1->charpos == pt_old /* an exact match always wins */
- || (BUFFERP (glyph->object)
- && eabs (g1->charpos - pt_old)
- < eabs (glyph->charpos - pt_old))))
+ && ((BUFFERP (g1->object)
+ && (g1->charpos == pt_old /* an exact match always wins */
+ || (BUFFERP (glyph->object)
+ && eabs (g1->charpos - pt_old)
+ < eabs (glyph->charpos - pt_old))))
+ /* previous candidate is a glyph from a string that has
+ a non-nil `cursor' property */
+ || (STRINGP (g1->object)
+ && (!NILP (Fget_char_property (make_number (g1->charpos),
+ Qcursor, g1->object))
+ /* pevious candidate is from the same display
+ string as this one, and the display string
+ came from a text property */
+ || (EQ (g1->object, glyph->object)
+ && string_from_text_prop)
+ /* this candidate is from newline and its
+ position is not an exact match */
+ || (INTEGERP (glyph->object)
+ && glyph->charpos != pt_old)))))
return 0;
/* If this candidate gives an exact match, use that. */
- if (!(BUFFERP (glyph->object) && glyph->charpos == pt_old)
+ if (!((BUFFERP (glyph->object) && glyph->charpos == pt_old)
+ /* If this candidate is a glyph created for the
+ terminating newline of a line, and point is on that
+ newline, it wins because it's an exact match. */
+ || (!row->continued_p
+ && INTEGERP (glyph->object)
+ && glyph->charpos == 0
+ && pt_old == MATRIX_ROW_END_CHARPOS (row) - 1))
/* Otherwise, keep the candidate that comes from a row
spanning less buffer positions. This may win when one or
both candidate positions are on glyphs that came from
}
++row;
}
- while ((MATRIX_ROW_CONTINUATION_LINE_P (row)
+ while (((MATRIX_ROW_CONTINUATION_LINE_P (row)
+ || row->continued_p)
&& MATRIX_ROW_BOTTOM_Y (row) <= last_y)
|| (MATRIX_ROW_START_CHARPOS (row) == PT
&& MATRIX_ROW_BOTTOM_Y (row) < last_y));
if (pt_offset)
centering_position -= pt_offset;
centering_position -=
- FRAME_LINE_HEIGHT (f) * (1 + margin + (last_line_misfit != 0));
+ FRAME_LINE_HEIGHT (f) * (1 + margin + (last_line_misfit != 0))
+ + WINDOW_HEADER_LINE_HEIGHT (w);
/* Don't let point enter the scroll margin near top of
the window. */
if (centering_position < margin * FRAME_LINE_HEIGHT (f))
{
int result = 1;
- if (PT == CHARPOS (row->end.pos))
+ if (PT == CHARPOS (row->end.pos)
+ || PT == MATRIX_ROW_END_CHARPOS (row))
{
/* Suppose the row ends on a string.
Unless the row is continued, that means it ends on a newline
\f
-/* Push the display property PROP so that it will be rendered at the
- current position in IT. Return 1 if PROP was successfully pushed,
- 0 otherwise. */
+/* Push the property PROP so that it will be rendered at the current
+ position in IT. Return 1 if PROP was successfully pushed, 0
+ otherwise. Called from handle_line_prefix to handle the
+ `line-prefix' and `wrap-prefix' properties. */
static int
push_display_prop (struct it *it, Lisp_Object prop)
{
- xassert (it->method == GET_FROM_BUFFER);
+ struct text_pos pos =
+ (it->method == GET_FROM_STRING) ? it->current.string_pos : it->current.pos;
- push_it (it, NULL);
+ xassert (it->method == GET_FROM_BUFFER
+ || it->method == GET_FROM_STRING);
+
+ /* We need to save the current buffer/string position, so it will be
+ restored by pop_it, because iterate_out_of_display_property
+ depends on that being set correctly, but some situations leave
+ it->position not yet set when this function is called. */
+ push_it (it, &pos);
if (STRINGP (prop))
{
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. */
+ buffer/string. */
if (it->bidi_p && it->bidi_it.paragraph_dir == R2L)
it->paragraph_embedding = it->bidi_it.paragraph_dir;
else
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.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);
}
#define RECORD_MAX_MIN_POS(IT) \
do \
{ \
- if (IT_CHARPOS (*(IT)) < min_pos) \
+ int composition_p = (IT)->what == IT_COMPOSITION; \
+ EMACS_INT current_pos = \
+ composition_p ? (IT)->cmp_it.charpos \
+ : IT_CHARPOS (*(IT)); \
+ EMACS_INT current_bpos = \
+ composition_p ? CHAR_TO_BYTE (current_pos) \
+ : IT_BYTEPOS (*(IT)); \
+ if (current_pos < min_pos) \
{ \
- min_pos = IT_CHARPOS (*(IT)); \
- min_bpos = IT_BYTEPOS (*(IT)); \
+ min_pos = current_pos; \
+ min_bpos = current_bpos; \
} \
- if (IT_CHARPOS (*(IT)) > max_pos) \
+ if (IT_CHARPOS (*it) > max_pos) \
{ \
- max_pos = IT_CHARPOS (*(IT)); \
- max_bpos = IT_BYTEPOS (*(IT)); \
+ max_pos = IT_CHARPOS (*it); \
+ max_bpos = IT_BYTEPOS (*it); \
} \
} \
while (0)
}
}
+ if (wrap_data)
+ bidi_unshelve_cache (wrap_data, 1);
+
/* If line is not empty and hscrolled, maybe insert truncation glyphs
at the left window margin. */
if (it->first_visible_x
buf = XBUFFER (buffer);
}
- if (NILP (BVAR (buf, bidi_display_reordering)))
+ if (NILP (BVAR (buf, bidi_display_reordering))
+ || NILP (BVAR (buf, enable_multibyte_characters)))
return Qleft_to_right;
else if (!NILP (BVAR (buf, bidi_paragraph_direction)))
return BVAR (buf, bidi_paragraph_direction);
Lisp_Object gstring;
struct font_metrics metrics;
+ it->nglyphs = 1;
+
gstring = composition_gstring_from_id (it->cmp_it.id);
it->pixel_width
= composition_gstring_width (gstring, it->cmp_it.from, it->cmp_it.to,