Commit ed94e6d7 authored by Eli Zaretskii's avatar Eli Zaretskii
Browse files

Save and restore bidi cache when saving and restoring the iterator.

Not tested, just compiled.

 src/bidi.c (bidi_shelve_cache, bidi_unshelve_cache): New functions.
 src/dispextern.h (bidi_shelve_cache, bidi_unshelve_cache): Declare
 prototypes.
 src/xdisp.c (SAVE_IT, RESTORE_IT): New macros.
 (pos_visible_p, face_before_or_after_it_pos)
 (back_to_previous_visible_line_start)
 (move_it_in_display_line_to, move_it_in_display_line)
 (move_it_to, move_it_vertically_backward, move_it_by_lines)
 (try_scrolling, redisplay_window, display_line): Use them when
 saving a temporary copy of the iterator and restoring it back.
parent 6eec7596
2011-07-03 Eli Zaretskii <eliz@gnu.org>
* bidi.c (bidi_shelve_cache, bidi_unshelve_cache): New functions.
* dispextern.h (bidi_shelve_cache, bidi_unshelve_cache): Declare
prototypes.
* xdisp.c (SAVE_IT, RESTORE_IT): New macros.
(pos_visible_p, face_before_or_after_it_pos)
(back_to_previous_visible_line_start)
(move_it_in_display_line_to, move_it_in_display_line)
(move_it_to, move_it_vertically_backward, move_it_by_lines)
(try_scrolling, redisplay_window, display_line): Use them when
saving a temporary copy of the iterator and restoring it back.
2011-07-02 Eli Zaretskii <eliz@gnu.org> 2011-07-02 Eli Zaretskii <eliz@gnu.org>
* xdisp.c (reseat_1): Call bidi_init_it to resync the bidi * xdisp.c (reseat_1): Call bidi_init_it to resync the bidi
......
...@@ -603,6 +603,86 @@ bidi_pop_it (struct bidi_it *bidi_it) ...@@ -603,6 +603,86 @@ bidi_pop_it (struct bidi_it *bidi_it)
bidi_cache_last_idx = -1; bidi_cache_last_idx = -1;
} }
/* Stash away a copy of the cache and its control variables. */
void *
bidi_shelve_cache (void)
{
unsigned char *databuf;
if (bidi_cache_idx == 0)
return NULL;
databuf = xmalloc (sizeof (bidi_cache_idx)
+ bidi_cache_idx * sizeof (struct bidi_it)
+ sizeof (bidi_cache_start_stack)
+ sizeof (bidi_cache_sp) + sizeof (bidi_cache_start)
+ sizeof (bidi_cache_last_idx));
memcpy (databuf, &bidi_cache_idx, sizeof (bidi_cache_idx));
memcpy (databuf + sizeof (bidi_cache_idx),
bidi_cache, bidi_cache_idx * sizeof (struct bidi_it));
memcpy (databuf + sizeof (bidi_cache_idx)
+ bidi_cache_idx * sizeof (struct bidi_it),
bidi_cache_start_stack, sizeof (bidi_cache_start_stack));
memcpy (databuf + sizeof (bidi_cache_idx)
+ bidi_cache_idx * sizeof (struct bidi_it)
+ sizeof (bidi_cache_start_stack),
&bidi_cache_sp, sizeof (bidi_cache_sp));
memcpy (databuf + sizeof (bidi_cache_idx)
+ bidi_cache_idx * sizeof (struct bidi_it)
+ sizeof (bidi_cache_start_stack) + sizeof (bidi_cache_sp),
&bidi_cache_start, sizeof (bidi_cache_start));
memcpy (databuf + sizeof (bidi_cache_idx)
+ bidi_cache_idx * sizeof (struct bidi_it)
+ sizeof (bidi_cache_start_stack) + sizeof (bidi_cache_sp)
+ sizeof (bidi_cache_start),
&bidi_cache_last_idx, sizeof (bidi_cache_last_idx));
return databuf;
}
/* Restore the cache state from a copy stashed away by bidi_shelve_cache. */
void
bidi_unshelve_cache (void *databuf)
{
unsigned char *p = databuf;
if (!p)
{
/* A NULL pointer means an empty cache. */
bidi_cache_start = 0;
bidi_cache_sp = 0;
bidi_cache_reset ();
}
else
{
memcpy (&bidi_cache_idx, p, sizeof (bidi_cache_idx));
memcpy (bidi_cache, p + sizeof (bidi_cache_idx),
bidi_cache_idx * sizeof (struct bidi_it));
memcpy (bidi_cache_start_stack,
p + sizeof (bidi_cache_idx)
+ bidi_cache_idx * sizeof (struct bidi_it),
sizeof (bidi_cache_start_stack));
memcpy (&bidi_cache_sp,
p + sizeof (bidi_cache_idx)
+ bidi_cache_idx * sizeof (struct bidi_it)
+ sizeof (bidi_cache_start_stack),
sizeof (bidi_cache_sp));
memcpy (&bidi_cache_start,
p + sizeof (bidi_cache_idx)
+ bidi_cache_idx * sizeof (struct bidi_it)
+ sizeof (bidi_cache_start_stack) + sizeof (bidi_cache_sp),
sizeof (bidi_cache_start));
memcpy (&bidi_cache_last_idx,
p + sizeof (bidi_cache_idx)
+ bidi_cache_idx * sizeof (struct bidi_it)
+ sizeof (bidi_cache_start_stack) + sizeof (bidi_cache_sp)
+ sizeof (bidi_cache_start),
sizeof (bidi_cache_last_idx));
xfree (p);
}
}
/*********************************************************************** /***********************************************************************
Initialization Initialization
......
...@@ -2974,6 +2974,8 @@ extern void bidi_paragraph_init (bidi_dir_t, struct bidi_it *, int); ...@@ -2974,6 +2974,8 @@ extern void bidi_paragraph_init (bidi_dir_t, struct bidi_it *, int);
extern int bidi_mirror_char (int); extern int bidi_mirror_char (int);
extern void bidi_push_it (struct bidi_it *); extern void bidi_push_it (struct bidi_it *);
extern void bidi_pop_it (struct bidi_it *); extern void bidi_pop_it (struct bidi_it *);
extern void *bidi_shelve_cache (void);
extern void bidi_unshelve_cache (void *);
/* Defined in xdisp.c */ /* Defined in xdisp.c */
......
...@@ -594,6 +594,29 @@ int current_mode_line_height, current_header_line_height; ...@@ -594,6 +594,29 @@ int current_mode_line_height, current_header_line_height;
   
#define TEXT_PROP_DISTANCE_LIMIT 100 #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 #if GLYPH_DEBUG
   
/* Non-zero means print traces of redisplay if compiled with /* Non-zero means print traces of redisplay if compiled with
...@@ -1285,14 +1308,16 @@ pos_visible_p (struct window *w, EMACS_INT charpos, int *x, int *y, ...@@ -1285,14 +1308,16 @@ pos_visible_p (struct window *w, EMACS_INT charpos, int *x, int *y,
else else
{ {
struct it it2; struct it it2;
void *it2data = NULL;
   
it2 = it; SAVE_IT (it2, it, it2data);
if (IT_CHARPOS (it) < ZV && FETCH_BYTE (IT_BYTEPOS (it)) != '\n') if (IT_CHARPOS (it) < ZV && FETCH_BYTE (IT_BYTEPOS (it)) != '\n')
move_it_by_lines (&it, 1); move_it_by_lines (&it, 1);
if (charpos < IT_CHARPOS (it) if (charpos < IT_CHARPOS (it)
|| (it.what == IT_EOB && charpos == IT_CHARPOS (it))) || (it.what == IT_EOB && charpos == IT_CHARPOS (it)))
{ {
visible_p = 1; visible_p = 1;
RESTORE_IT (&it2, &it2, it2data);
move_it_to (&it2, charpos, -1, -1, -1, MOVE_TO_POS); move_it_to (&it2, charpos, -1, -1, -1, MOVE_TO_POS);
*x = it2.current_x; *x = it2.current_x;
*y = it2.current_y + it2.max_ascent - it2.ascent; *y = it2.current_y + it2.max_ascent - it2.ascent;
...@@ -1305,6 +1330,8 @@ pos_visible_p (struct window *w, EMACS_INT charpos, int *x, int *y, ...@@ -1305,6 +1330,8 @@ pos_visible_p (struct window *w, EMACS_INT charpos, int *x, int *y,
WINDOW_HEADER_LINE_HEIGHT (w)))); WINDOW_HEADER_LINE_HEIGHT (w))));
*vpos = it2.vpos; *vpos = it2.vpos;
} }
else
xfree (it2data);
} }
   
if (old_buffer) if (old_buffer)
...@@ -3484,6 +3511,7 @@ face_before_or_after_it_pos (struct it *it, int before_p) ...@@ -3484,6 +3511,7 @@ face_before_or_after_it_pos (struct it *it, int before_p)
int face_id, limit; int face_id, limit;
EMACS_INT next_check_charpos; EMACS_INT next_check_charpos;
struct it it_copy; struct it it_copy;
void *it_copy_data = NULL;
   
xassert (it->s == NULL); xassert (it->s == NULL);
   
...@@ -3526,7 +3554,7 @@ face_before_or_after_it_pos (struct it *it, int before_p) ...@@ -3526,7 +3554,7 @@ face_before_or_after_it_pos (struct it *it, int before_p)
character on this display line. */ character on this display line. */
if (it->current_x <= it->first_visible_x) if (it->current_x <= it->first_visible_x)
return it->face_id; return it->face_id;
it_copy = *it; SAVE_IT (it_copy, *it, it_copy_data);
/* Implementation note: Since move_it_in_display_line /* Implementation note: Since move_it_in_display_line
works in the iterator geometry, and thinks the first works in the iterator geometry, and thinks the first
character is always the leftmost, even in R2L lines, character is always the leftmost, even in R2L lines,
...@@ -3535,6 +3563,7 @@ face_before_or_after_it_pos (struct it *it, int before_p) ...@@ -3535,6 +3563,7 @@ face_before_or_after_it_pos (struct it *it, int before_p)
move_it_in_display_line (&it_copy, SCHARS (it_copy.string), move_it_in_display_line (&it_copy, SCHARS (it_copy.string),
it_copy.current_x - 1, MOVE_TO_X); it_copy.current_x - 1, MOVE_TO_X);
charpos = IT_STRING_CHARPOS (it_copy); charpos = IT_STRING_CHARPOS (it_copy);
RESTORE_IT (it, it, it_copy_data);
} }
else else
{ {
...@@ -3624,7 +3653,7 @@ face_before_or_after_it_pos (struct it *it, int before_p) ...@@ -3624,7 +3653,7 @@ face_before_or_after_it_pos (struct it *it, int before_p)
character on this display line. */ character on this display line. */
if (it->current_x <= it->first_visible_x) if (it->current_x <= it->first_visible_x)
return it->face_id; return it->face_id;
it_copy = *it; SAVE_IT (it_copy, *it, it_copy_data);
/* Implementation note: Since move_it_in_display_line /* Implementation note: Since move_it_in_display_line
works in the iterator geometry, and thinks the first works in the iterator geometry, and thinks the first
character is always the leftmost, even in R2L lines, character is always the leftmost, even in R2L lines,
...@@ -3633,6 +3662,7 @@ face_before_or_after_it_pos (struct it *it, int before_p) ...@@ -3633,6 +3662,7 @@ face_before_or_after_it_pos (struct it *it, int before_p)
move_it_in_display_line (&it_copy, ZV, move_it_in_display_line (&it_copy, ZV,
it_copy.current_x - 1, MOVE_TO_X); it_copy.current_x - 1, MOVE_TO_X);
pos = it_copy.current.pos; pos = it_copy.current.pos;
RESTORE_IT (it, it, it_copy_data);
} }
else else
{ {
...@@ -5527,6 +5557,7 @@ back_to_previous_visible_line_start (struct it *it) ...@@ -5527,6 +5557,7 @@ back_to_previous_visible_line_start (struct it *it)
   
{ {
struct it it2; struct it it2;
void *it2data = NULL;
EMACS_INT pos; EMACS_INT pos;
EMACS_INT beg, end; EMACS_INT beg, end;
Lisp_Object val, overlay; Lisp_Object val, overlay;
...@@ -5538,7 +5569,7 @@ back_to_previous_visible_line_start (struct it *it) ...@@ -5538,7 +5569,7 @@ back_to_previous_visible_line_start (struct it *it)
   
/* If newline is replaced by a display property, find start of overlay /* If newline is replaced by a display property, find start of overlay
or interval and continue search from that point. */ or interval and continue search from that point. */
it2 = *it; SAVE_IT (it2, *it, it2data);
pos = --IT_CHARPOS (it2); pos = --IT_CHARPOS (it2);
--IT_BYTEPOS (it2); --IT_BYTEPOS (it2);
it2.sp = 0; it2.sp = 0;
...@@ -5551,21 +5582,12 @@ back_to_previous_visible_line_start (struct it *it) ...@@ -5551,21 +5582,12 @@ back_to_previous_visible_line_start (struct it *it)
? (beg = OVERLAY_POSITION (OVERLAY_START (overlay))) ? (beg = OVERLAY_POSITION (OVERLAY_START (overlay)))
: get_property_and_range (pos, Qdisplay, &val, &beg, &end, Qnil))) : get_property_and_range (pos, Qdisplay, &val, &beg, &end, Qnil)))
{ {
/* If the call to handle_display_prop above pushed the RESTORE_IT (it, it, it2data);
iterator state, that causes side effects for the bidi
iterator by calling bidi_push_it. Undo those side
effects. */
while (it2.sp > 0)
{
/* push_it calls bidi_push_it only if the bidi_p flag
is set in the iterator being pushed. */
if (it2.stack[--it2.sp].bidi_p)
bidi_pop_it (&it2.bidi_it);
}
goto replaced; goto replaced;
} }
   
/* Newline is not replaced by anything -- so we are done. */ /* Newline is not replaced by anything -- so we are done. */
RESTORE_IT (it, it, it2data);
break; break;
   
replaced: replaced:
...@@ -7495,6 +7517,7 @@ move_it_in_display_line_to (struct it *it, ...@@ -7495,6 +7517,7 @@ move_it_in_display_line_to (struct it *it,
enum move_it_result result = MOVE_UNDEFINED; enum move_it_result result = MOVE_UNDEFINED;
struct glyph_row *saved_glyph_row; struct glyph_row *saved_glyph_row;
struct it wrap_it, atpos_it, atx_it; struct it wrap_it, atpos_it, atx_it;
void *wrap_data = NULL, *atpos_data = NULL, *atx_data = NULL;
int may_wrap = 0; int may_wrap = 0;
enum it_method prev_method = it->method; enum it_method prev_method = it->method;
EMACS_INT prev_pos = IT_CHARPOS (*it); EMACS_INT prev_pos = IT_CHARPOS (*it);
...@@ -7563,7 +7586,7 @@ move_it_in_display_line_to (struct it *it, ...@@ -7563,7 +7586,7 @@ move_it_in_display_line_to (struct it *it,
/* If wrap_it is valid, the current position might be in a /* If wrap_it is valid, the current position might be in a
word that is wrapped. So, save the iterator in word that is wrapped. So, save the iterator in
atpos_it and continue to see if wrapping happens. */ atpos_it and continue to see if wrapping happens. */
atpos_it = *it; SAVE_IT (atpos_it, *it, atpos_data);
} }
   
prev_method = it->method; prev_method = it->method;
...@@ -7600,18 +7623,18 @@ move_it_in_display_line_to (struct it *it, ...@@ -7600,18 +7623,18 @@ move_it_in_display_line_to (struct it *it,
already found, we are done. */ already found, we are done. */
if (atpos_it.sp >= 0) if (atpos_it.sp >= 0)
{ {
*it = atpos_it; RESTORE_IT (it, &atpos_it, atpos_data);
result = MOVE_POS_MATCH_OR_ZV; result = MOVE_POS_MATCH_OR_ZV;
goto done; goto done;
} }
if (atx_it.sp >= 0) if (atx_it.sp >= 0)
{ {
*it = atx_it; RESTORE_IT (it, &atx_it, atx_data);
result = MOVE_X_REACHED; result = MOVE_X_REACHED;
goto done; goto done;
} }
/* Otherwise, we can wrap here. */ /* Otherwise, we can wrap here. */
wrap_it = *it; SAVE_IT (wrap_it, *it, wrap_data);
may_wrap = 0; may_wrap = 0;
} }
} }
...@@ -7679,7 +7702,7 @@ move_it_in_display_line_to (struct it *it, ...@@ -7679,7 +7702,7 @@ move_it_in_display_line_to (struct it *it,
goto buffer_pos_reached; goto buffer_pos_reached;
if (atpos_it.sp < 0) if (atpos_it.sp < 0)
{ {
atpos_it = *it; SAVE_IT (atpos_it, *it, atpos_data);
IT_RESET_X_ASCENT_DESCENT (&atpos_it); IT_RESET_X_ASCENT_DESCENT (&atpos_it);
} }
} }
...@@ -7693,7 +7716,7 @@ move_it_in_display_line_to (struct it *it, ...@@ -7693,7 +7716,7 @@ move_it_in_display_line_to (struct it *it,
} }
if (atx_it.sp < 0) if (atx_it.sp < 0)
{ {
atx_it = *it; SAVE_IT (atx_it, *it, atx_data);
IT_RESET_X_ASCENT_DESCENT (&atx_it); IT_RESET_X_ASCENT_DESCENT (&atx_it);
} }
} }
...@@ -7737,7 +7760,7 @@ move_it_in_display_line_to (struct it *it, ...@@ -7737,7 +7760,7 @@ move_it_in_display_line_to (struct it *it,
if (it->line_wrap == WORD_WRAP if (it->line_wrap == WORD_WRAP
&& atpos_it.sp < 0) && atpos_it.sp < 0)
{ {
atpos_it = *it; SAVE_IT (atpos_it, *it, atpos_data);
atpos_it.current_x = x_before_this_char; atpos_it.current_x = x_before_this_char;
atpos_it.hpos = hpos_before_this_char; atpos_it.hpos = hpos_before_this_char;
} }
...@@ -7782,7 +7805,7 @@ move_it_in_display_line_to (struct it *it, ...@@ -7782,7 +7805,7 @@ move_it_in_display_line_to (struct it *it,
   
if (wrap_it.sp >= 0) if (wrap_it.sp >= 0)
{ {
*it = wrap_it; RESTORE_IT (it, &wrap_it, wrap_data);
atpos_it.sp = -1; atpos_it.sp = -1;
atx_it.sp = -1; atx_it.sp = -1;
} }
...@@ -7799,7 +7822,7 @@ move_it_in_display_line_to (struct it *it, ...@@ -7799,7 +7822,7 @@ move_it_in_display_line_to (struct it *it,
goto buffer_pos_reached; goto buffer_pos_reached;
if (it->line_wrap == WORD_WRAP && atpos_it.sp < 0) 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); IT_RESET_X_ASCENT_DESCENT (&atpos_it);
} }
} }
...@@ -7879,12 +7902,19 @@ move_it_in_display_line_to (struct it *it, ...@@ -7879,12 +7902,19 @@ move_it_in_display_line_to (struct it *it,
/* If we scanned beyond to_pos and didn't find a point to wrap at, /* If we scanned beyond to_pos and didn't find a point to wrap at,
restore the saved iterator. */ restore the saved iterator. */
if (atpos_it.sp >= 0) if (atpos_it.sp >= 0)
*it = atpos_it; RESTORE_IT (it, &atpos_it, atpos_data);
else if (atx_it.sp >= 0) else if (atx_it.sp >= 0)
*it = atx_it; RESTORE_IT (it, &atx_it, atx_data);
   
done: done:
   
if (atpos_data)
xfree (atpos_data);
if (atx_data)
xfree (atx_data);
if (wrap_data)
xfree (wrap_data);
/* Restore the iterator settings altered at the beginning of this /* Restore the iterator settings altered at the beginning of this
function. */ function. */
it->glyph_row = saved_glyph_row; it->glyph_row = saved_glyph_row;
...@@ -7900,8 +7930,12 @@ move_it_in_display_line (struct it *it, ...@@ -7900,8 +7930,12 @@ move_it_in_display_line (struct it *it,
if (it->line_wrap == WORD_WRAP if (it->line_wrap == WORD_WRAP
&& (op & MOVE_TO_X)) && (op & MOVE_TO_X))
{ {
struct it save_it = *it; struct it save_it;
int skip = move_it_in_display_line_to (it, to_charpos, to_x, op); 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 /* When word-wrap is on, TO_X may lie past the end
of a wrapped line. Then it->current is the of a wrapped line. Then it->current is the
character on the next line, so backtrack to the character on the next line, so backtrack to the
...@@ -7909,10 +7943,12 @@ move_it_in_display_line (struct it *it, ...@@ -7909,10 +7943,12 @@ move_it_in_display_line (struct it *it,
if (skip == MOVE_LINE_CONTINUED) if (skip == MOVE_LINE_CONTINUED)
{ {
int prev_x = max (it->current_x - 1, 0); 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 move_it_in_display_line_to
(it, -1, prev_x, MOVE_TO_X); (it, -1, prev_x, MOVE_TO_X);
} }
else
xfree (save_data);
} }
else else
move_it_in_display_line_to (it, to_charpos, to_x, op); move_it_in_display_line_to (it, to_charpos, to_x, op);
...@@ -7935,6 +7971,7 @@ move_it_to (struct it *it, EMACS_INT to_charpos, int to_x, int to_y, int to_vpos ...@@ -7935,6 +7971,7 @@ move_it_to (struct it *it, EMACS_INT to_charpos, int to_x, int to_y, int to_vpos
{ {
enum move_it_result skip, skip2 = MOVE_X_REACHED; enum move_it_result skip, skip2 = MOVE_X_REACHED;
int line_height, line_start_x = 0, reached = 0; int line_height, line_start_x = 0, reached = 0;
void *backup_data = NULL;
   
for (;;) for (;;)
{ {
...@@ -7987,7 +8024,7 @@ move_it_to (struct it *it, EMACS_INT to_charpos, int to_x, int to_y, int to_vpos ...@@ -7987,7 +8024,7 @@ move_it_to (struct it *it, EMACS_INT to_charpos, int to_x, int to_y, int to_vpos
struct it it_backup; struct it it_backup;
   
if (it->line_wrap == WORD_WRAP) 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 specified means stop at TO_X in the line containing
TO_Y---or at TO_CHARPOS if this is reached first. The TO_Y---or at TO_CHARPOS if this is reached first. The
...@@ -8021,7 +8058,7 @@ move_it_to (struct it *it, EMACS_INT to_charpos, int to_x, int to_y, int to_vpos ...@@ -8021,7 +8058,7 @@ move_it_to (struct it *it, EMACS_INT to_charpos, int to_x, int to_y, int to_vpos
reached = 6; reached = 6;
break; break;
} }
it_backup = *it; SAVE_IT (it_backup, *it, backup_data);
TRACE_MOVE ((stderr, "move_it: from %d\n", IT_CHARPOS (*it))); TRACE_MOVE ((stderr, "move_it: from %d\n", IT_CHARPOS (*it)));
skip2 = move_it_in_display_line_to (it, to_charpos, -1, skip2 = move_it_in_display_line_to (it, to_charpos, -1,
op & MOVE_TO_POS); op & MOVE_TO_POS);
...@@ -8035,7 +8072,7 @@ move_it_to (struct it *it, EMACS_INT to_charpos, int to_x, int to_y, int to_vpos ...@@ -8035,7 +8072,7 @@ move_it_to (struct it *it, EMACS_INT to_charpos, int to_x, int to_y, int to_vpos
/* If TO_Y is in this line and TO_X was reached /* If TO_Y is in this line and TO_X was reached
above, we scanned too far. We have to restore above, we scanned too far. We have to restore
IT's settings to the ones before skipping. */ IT's settings to the ones before skipping. */
*it = it_backup; RESTORE_IT (it, &it_backup, backup_data);
reached = 6; reached = 6;
} }
else else
...@@ -8062,7 +8099,7 @@ move_it_to (struct it *it, EMACS_INT to_charpos, int to_x, int to_y, int to_vpos ...@@ -8062,7 +8099,7 @@ move_it_to (struct it *it, EMACS_INT to_charpos, int to_x, int to_y, int to_vpos
&& it->line_wrap == WORD_WRAP) && it->line_wrap == WORD_WRAP)
{ {
int prev_x = max (it->current_x - 1, 0); 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 skip = move_it_in_display_line_to
(it, -1, prev_x, MOVE_TO_X); (it, -1, prev_x, MOVE_TO_X);
} }
...@@ -8169,6 +8206,9 @@ move_it_to (struct it *it, EMACS_INT to_charpos, int to_x, int to_y, int to_vpos ...@@ -8169,6 +8206,9 @@ move_it_to (struct it *it, EMACS_INT to_charpos, int to_x, int to_y, int to_vpos
last_max_ascent = it->max_ascent; last_max_ascent = it->max_ascent;
} }
   
if (backup_data)
xfree (backup_data);
TRACE_MOVE ((stderr, "move_it_to: reached %d\n", reached)); TRACE_MOVE ((stderr, "move_it_to: reached %d\n", reached));
} }
   
...@@ -8186,6 +8226,7 @@ move_it_vertically_backward (struct it *it, int dy) ...@@ -8186,6 +8226,7 @@ move_it_vertically_backward (struct it *it, int dy)
{ {
int nlines, h; int nlines, h;
struct it it2, it3; struct it it2, it3;
void *it2data = NULL, *it3data = NULL;
EMACS_INT start_pos; EMACS_INT start_pos;
   
move_further_back: move_further_back:
...@@ -8214,7 +8255,7 @@ move_it_vertically_backward (struct it *it, int dy) ...@@ -8214,7 +8255,7 @@ move_it_vertically_backward (struct it *it, int dy)
start of the next line so that we get its height. We need this 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 height to be able to tell whether we reached the specified
y-distance. */ y-distance. */
it2 = *it; SAVE_IT (it2, *it, it2data);
it2.max_ascent = it2.max_descent = 0; it2.max_ascent = it2.max_descent = 0;
do do
{ {
...@@ -8223,7 +8264,7 @@ move_it_vertically_backward (struct it *it, int dy) ...@@ -8223,7 +8264,7 @@ move_it_vertically_backward (struct it *it, int dy)
} }
while (!IT_POS_VALID_AFTER_MOVE_P (&it2)); while (!IT_POS_VALID_AFTER_MOVE_P (&it2));
xassert (IT_CHARPOS (*it) >= BEGV); xassert (IT_CHARPOS (*it) >= BEGV);
it3 = it2; SAVE_IT (it3, it2, it3data);
   
move_it_to (&it2, start_pos, -1, -1, -1, MOVE_TO_POS); move_it_to (&it2, start_pos, -1, -1, -1, MOVE_TO_POS);
xassert (IT_CHARPOS (*it) >= BEGV); xassert (IT_CHARPOS (*it) >= BEGV);
...@@ -8242,8 +8283,10 @@ move_it_vertically_backward (struct it *it, int dy) ...@@ -8242,8 +8283,10 @@ move_it_vertically_backward (struct it *it, int dy)
{ {
/* DY == 0 means move to the start of the screen line. The /* DY == 0 means move to the start of the screen line. The
value of nlines is > 0 if continuation lines were involved. */ value of nlines is > 0 if continuation lines were involved. */
RESTORE_IT (it, it, it2data);
if (nlines > 0) if (nlines > 0)
move_it_by_lines (it, nlines); move_it_by_lines (it, nlines);
xfree (it3data);
} }
else else
{ {
...@@ -8251,9 +8294,13 @@ move_it_vertically_backward (struct it *it, int dy) ...@@ -8251,9 +8294,13 @@ move_it_vertically_backward (struct it *it, int dy)
Note that H has been subtracted in front of the if-statement. */ Note that H has been subtracted in front of the if-statement. */
int target_y = it->current_y + h - dy; int target_y = it->current_y + h - dy;
int y0 = it3.current_y; int y0 = it3.current_y;
int y1 = line_bottom_y (&it3); int y1;
int line_height = y1 - y0; 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 /* If we did not reach target_y, try to move further backward if