aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEli Zaretskii2011-07-03 21:36:56 +0300
committerEli Zaretskii2011-07-03 21:36:56 +0300
commited94e6d7bf6751592ff3dadb2b87f03ffaab3bfa (patch)
tree0d06ed1743bb484cac818ef7ff75d68f107a6332
parent6eec759623c7d77e01370c504543a29887c28034 (diff)
downloademacs-ed94e6d7bf6751592ff3dadb2b87f03ffaab3bfa.tar.gz
emacs-ed94e6d7bf6751592ff3dadb2b87f03ffaab3bfa.zip
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.
-rw-r--r--src/ChangeLog15
-rw-r--r--src/bidi.c80
-rw-r--r--src/dispextern.h2
-rw-r--r--src/xdisp.c152
4 files changed, 204 insertions, 45 deletions
diff --git a/src/ChangeLog b/src/ChangeLog
index 1a443e848a7..fdb6657e135 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,3 +1,18 @@
12011-07-03 Eli Zaretskii <eliz@gnu.org>
2
3 * bidi.c (bidi_shelve_cache, bidi_unshelve_cache): New functions.
4
5 * dispextern.h (bidi_shelve_cache, bidi_unshelve_cache): Declare
6 prototypes.
7
8 * xdisp.c (SAVE_IT, RESTORE_IT): New macros.
9 (pos_visible_p, face_before_or_after_it_pos)
10 (back_to_previous_visible_line_start)
11 (move_it_in_display_line_to, move_it_in_display_line)
12 (move_it_to, move_it_vertically_backward, move_it_by_lines)
13 (try_scrolling, redisplay_window, display_line): Use them when
14 saving a temporary copy of the iterator and restoring it back.
15
12011-07-02 Eli Zaretskii <eliz@gnu.org> 162011-07-02 Eli Zaretskii <eliz@gnu.org>
2 17
3 * xdisp.c (reseat_1): Call bidi_init_it to resync the bidi 18 * xdisp.c (reseat_1): Call bidi_init_it to resync the bidi
diff --git a/src/bidi.c b/src/bidi.c
index 05c16a70f94..be34f0352de 100644
--- a/src/bidi.c
+++ b/src/bidi.c
@@ -603,6 +603,86 @@ bidi_pop_it (struct bidi_it *bidi_it)
603 bidi_cache_last_idx = -1; 603 bidi_cache_last_idx = -1;
604} 604}
605 605
606/* Stash away a copy of the cache and its control variables. */
607void *
608bidi_shelve_cache (void)
609{
610 unsigned char *databuf;
611
612 if (bidi_cache_idx == 0)
613 return NULL;
614
615 databuf = xmalloc (sizeof (bidi_cache_idx)
616 + bidi_cache_idx * sizeof (struct bidi_it)
617 + sizeof (bidi_cache_start_stack)
618 + sizeof (bidi_cache_sp) + sizeof (bidi_cache_start)
619 + sizeof (bidi_cache_last_idx));
620 memcpy (databuf, &bidi_cache_idx, sizeof (bidi_cache_idx));
621 memcpy (databuf + sizeof (bidi_cache_idx),
622 bidi_cache, bidi_cache_idx * sizeof (struct bidi_it));
623 memcpy (databuf + sizeof (bidi_cache_idx)
624 + bidi_cache_idx * sizeof (struct bidi_it),
625 bidi_cache_start_stack, sizeof (bidi_cache_start_stack));
626 memcpy (databuf + sizeof (bidi_cache_idx)
627 + bidi_cache_idx * sizeof (struct bidi_it)
628 + sizeof (bidi_cache_start_stack),
629 &bidi_cache_sp, sizeof (bidi_cache_sp));
630 memcpy (databuf + sizeof (bidi_cache_idx)
631 + bidi_cache_idx * sizeof (struct bidi_it)
632 + sizeof (bidi_cache_start_stack) + sizeof (bidi_cache_sp),
633 &bidi_cache_start, sizeof (bidi_cache_start));
634 memcpy (databuf + sizeof (bidi_cache_idx)
635 + bidi_cache_idx * sizeof (struct bidi_it)
636 + sizeof (bidi_cache_start_stack) + sizeof (bidi_cache_sp)
637 + sizeof (bidi_cache_start),
638 &bidi_cache_last_idx, sizeof (bidi_cache_last_idx));
639
640 return databuf;
641}
642
643/* Restore the cache state from a copy stashed away by bidi_shelve_cache. */
644void
645bidi_unshelve_cache (void *databuf)
646{
647 unsigned char *p = databuf;
648
649 if (!p)
650 {
651 /* A NULL pointer means an empty cache. */
652 bidi_cache_start = 0;
653 bidi_cache_sp = 0;
654 bidi_cache_reset ();
655 }
656 else
657 {
658 memcpy (&bidi_cache_idx, p, sizeof (bidi_cache_idx));
659 memcpy (bidi_cache, p + sizeof (bidi_cache_idx),
660 bidi_cache_idx * sizeof (struct bidi_it));
661 memcpy (bidi_cache_start_stack,
662 p + sizeof (bidi_cache_idx)
663 + bidi_cache_idx * sizeof (struct bidi_it),
664 sizeof (bidi_cache_start_stack));
665 memcpy (&bidi_cache_sp,
666 p + sizeof (bidi_cache_idx)
667 + bidi_cache_idx * sizeof (struct bidi_it)
668 + sizeof (bidi_cache_start_stack),
669 sizeof (bidi_cache_sp));
670 memcpy (&bidi_cache_start,
671 p + sizeof (bidi_cache_idx)
672 + bidi_cache_idx * sizeof (struct bidi_it)
673 + sizeof (bidi_cache_start_stack) + sizeof (bidi_cache_sp),
674 sizeof (bidi_cache_start));
675 memcpy (&bidi_cache_last_idx,
676 p + sizeof (bidi_cache_idx)
677 + bidi_cache_idx * sizeof (struct bidi_it)
678 + sizeof (bidi_cache_start_stack) + sizeof (bidi_cache_sp)
679 + sizeof (bidi_cache_start),
680 sizeof (bidi_cache_last_idx));
681
682 xfree (p);
683 }
684}
685
606 686
607/*********************************************************************** 687/***********************************************************************
608 Initialization 688 Initialization
diff --git a/src/dispextern.h b/src/dispextern.h
index 997ef6df088..5bb72ff7600 100644
--- a/src/dispextern.h
+++ b/src/dispextern.h
@@ -2974,6 +2974,8 @@ extern void bidi_paragraph_init (bidi_dir_t, struct bidi_it *, int);
2974extern int bidi_mirror_char (int); 2974extern int bidi_mirror_char (int);
2975extern void bidi_push_it (struct bidi_it *); 2975extern void bidi_push_it (struct bidi_it *);
2976extern void bidi_pop_it (struct bidi_it *); 2976extern void bidi_pop_it (struct bidi_it *);
2977extern void *bidi_shelve_cache (void);
2978extern void bidi_unshelve_cache (void *);
2977 2979
2978/* Defined in xdisp.c */ 2980/* Defined in xdisp.c */
2979 2981
diff --git a/src/xdisp.c b/src/xdisp.c
index c3d5fd9479b..c1f4d44dbc5 100644
--- a/src/xdisp.c
+++ b/src/xdisp.c
@@ -594,6 +594,29 @@ int current_mode_line_height, current_header_line_height;
594 594
595#define TEXT_PROP_DISTANCE_LIMIT 100 595#define TEXT_PROP_DISTANCE_LIMIT 100
596 596
597/* SAVE_IT and RESTORE_IT are called when we save a snapshot of the
598 iterator state and later restore it. This is needed because the
599 bidi iterator on bidi.c keeps a stacked cache of its states, which
600 is really a singleton. When we use scratch iterator objects to
601 move around the buffer, we can cause the bidi cache to be pushed or
602 popped, and therefore we need to restore the cache state when we
603 return to the original iterator. */
604#define SAVE_IT(ITCOPY,ITORIG,CACHE) \
605 do { \
606 if (CACHE) \
607 xfree (CACHE); \
608 ITCOPY = ITORIG; \
609 CACHE = bidi_shelve_cache(); \
610 } while (0)
611
612#define RESTORE_IT(pITORIG,pITCOPY,CACHE) \
613 do { \
614 if (pITORIG != pITCOPY) \
615 *(pITORIG) = *(pITCOPY); \
616 bidi_unshelve_cache (CACHE); \
617 CACHE = NULL; \
618 } while (0)
619
597#if GLYPH_DEBUG 620#if GLYPH_DEBUG
598 621
599/* Non-zero means print traces of redisplay if compiled with 622/* 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 else 1308 else
1286 { 1309 {
1287 struct it it2; 1310 struct it it2;
1311 void *it2data = NULL;
1288 1312
1289 it2 = it; 1313 SAVE_IT (it2, it, it2data);
1290 if (IT_CHARPOS (it) < ZV && FETCH_BYTE (IT_BYTEPOS (it)) != '\n') 1314 if (IT_CHARPOS (it) < ZV && FETCH_BYTE (IT_BYTEPOS (it)) != '\n')
1291 move_it_by_lines (&it, 1); 1315 move_it_by_lines (&it, 1);
1292 if (charpos < IT_CHARPOS (it) 1316 if (charpos < IT_CHARPOS (it)
1293 || (it.what == IT_EOB && charpos == IT_CHARPOS (it))) 1317 || (it.what == IT_EOB && charpos == IT_CHARPOS (it)))
1294 { 1318 {
1295 visible_p = 1; 1319 visible_p = 1;
1320 RESTORE_IT (&it2, &it2, it2data);
1296 move_it_to (&it2, charpos, -1, -1, -1, MOVE_TO_POS); 1321 move_it_to (&it2, charpos, -1, -1, -1, MOVE_TO_POS);
1297 *x = it2.current_x; 1322 *x = it2.current_x;
1298 *y = it2.current_y + it2.max_ascent - it2.ascent; 1323 *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 WINDOW_HEADER_LINE_HEIGHT (w)))); 1330 WINDOW_HEADER_LINE_HEIGHT (w))));
1306 *vpos = it2.vpos; 1331 *vpos = it2.vpos;
1307 } 1332 }
1333 else
1334 xfree (it2data);
1308 } 1335 }
1309 1336
1310 if (old_buffer) 1337 if (old_buffer)
@@ -3484,6 +3511,7 @@ face_before_or_after_it_pos (struct it *it, int before_p)
3484 int face_id, limit; 3511 int face_id, limit;
3485 EMACS_INT next_check_charpos; 3512 EMACS_INT next_check_charpos;
3486 struct it it_copy; 3513 struct it it_copy;
3514 void *it_copy_data = NULL;
3487 3515
3488 xassert (it->s == NULL); 3516 xassert (it->s == NULL);
3489 3517
@@ -3526,7 +3554,7 @@ face_before_or_after_it_pos (struct it *it, int before_p)
3526 character on this display line. */ 3554 character on this display line. */
3527 if (it->current_x <= it->first_visible_x) 3555 if (it->current_x <= it->first_visible_x)
3528 return it->face_id; 3556 return it->face_id;
3529 it_copy = *it; 3557 SAVE_IT (it_copy, *it, it_copy_data);
3530 /* Implementation note: Since move_it_in_display_line 3558 /* Implementation note: Since move_it_in_display_line
3531 works in the iterator geometry, and thinks the first 3559 works in the iterator geometry, and thinks the first
3532 character is always the leftmost, even in R2L lines, 3560 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 move_it_in_display_line (&it_copy, SCHARS (it_copy.string), 3563 move_it_in_display_line (&it_copy, SCHARS (it_copy.string),
3536 it_copy.current_x - 1, MOVE_TO_X); 3564 it_copy.current_x - 1, MOVE_TO_X);
3537 charpos = IT_STRING_CHARPOS (it_copy); 3565 charpos = IT_STRING_CHARPOS (it_copy);
3566 RESTORE_IT (it, it, it_copy_data);
3538 } 3567 }
3539 else 3568 else
3540 { 3569 {
@@ -3624,7 +3653,7 @@ face_before_or_after_it_pos (struct it *it, int before_p)
3624 character on this display line. */ 3653 character on this display line. */
3625 if (it->current_x <= it->first_visible_x) 3654 if (it->current_x <= it->first_visible_x)
3626 return it->face_id; 3655 return it->face_id;
3627 it_copy = *it; 3656 SAVE_IT (it_copy, *it, it_copy_data);
3628 /* Implementation note: Since move_it_in_display_line 3657 /* Implementation note: Since move_it_in_display_line
3629 works in the iterator geometry, and thinks the first 3658 works in the iterator geometry, and thinks the first
3630 character is always the leftmost, even in R2L lines, 3659 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 move_it_in_display_line (&it_copy, ZV, 3662 move_it_in_display_line (&it_copy, ZV,
3634 it_copy.current_x - 1, MOVE_TO_X); 3663 it_copy.current_x - 1, MOVE_TO_X);
3635 pos = it_copy.current.pos; 3664 pos = it_copy.current.pos;
3665 RESTORE_IT (it, it, it_copy_data);
3636 } 3666 }
3637 else 3667 else
3638 { 3668 {
@@ -5527,6 +5557,7 @@ back_to_previous_visible_line_start (struct it *it)
5527 5557
5528 { 5558 {
5529 struct it it2; 5559 struct it it2;
5560 void *it2data = NULL;
5530 EMACS_INT pos; 5561 EMACS_INT pos;
5531 EMACS_INT beg, end; 5562 EMACS_INT beg, end;
5532 Lisp_Object val, overlay; 5563 Lisp_Object val, overlay;
@@ -5538,7 +5569,7 @@ back_to_previous_visible_line_start (struct it *it)
5538 5569
5539 /* If newline is replaced by a display property, find start of overlay 5570 /* If newline is replaced by a display property, find start of overlay
5540 or interval and continue search from that point. */ 5571 or interval and continue search from that point. */
5541 it2 = *it; 5572 SAVE_IT (it2, *it, it2data);
5542 pos = --IT_CHARPOS (it2); 5573 pos = --IT_CHARPOS (it2);
5543 --IT_BYTEPOS (it2); 5574 --IT_BYTEPOS (it2);
5544 it2.sp = 0; 5575 it2.sp = 0;
@@ -5551,21 +5582,12 @@ back_to_previous_visible_line_start (struct it *it)
5551 ? (beg = OVERLAY_POSITION (OVERLAY_START (overlay))) 5582 ? (beg = OVERLAY_POSITION (OVERLAY_START (overlay)))
5552 : get_property_and_range (pos, Qdisplay, &val, &beg, &end, Qnil))) 5583 : get_property_and_range (pos, Qdisplay, &val, &beg, &end, Qnil)))
5553 { 5584 {
5554 /* If the call to handle_display_prop above pushed the 5585 RESTORE_IT (it, it, it2data);
5555 iterator state, that causes side effects for the bidi
5556 iterator by calling bidi_push_it. Undo those side
5557 effects. */
5558 while (it2.sp > 0)
5559 {
5560 /* push_it calls bidi_push_it only if the bidi_p flag
5561 is set in the iterator being pushed. */
5562 if (it2.stack[--it2.sp].bidi_p)
5563 bidi_pop_it (&it2.bidi_it);
5564 }
5565 goto replaced; 5586 goto replaced;
5566 } 5587 }
5567 5588
5568 /* Newline is not replaced by anything -- so we are done. */ 5589 /* Newline is not replaced by anything -- so we are done. */
5590 RESTORE_IT (it, it, it2data);
5569 break; 5591 break;
5570 5592
5571 replaced: 5593 replaced:
@@ -7495,6 +7517,7 @@ move_it_in_display_line_to (struct it *it,
7495 enum move_it_result result = MOVE_UNDEFINED; 7517 enum move_it_result result = MOVE_UNDEFINED;
7496 struct glyph_row *saved_glyph_row; 7518 struct glyph_row *saved_glyph_row;
7497 struct it wrap_it, atpos_it, atx_it; 7519 struct it wrap_it, atpos_it, atx_it;
7520 void *wrap_data = NULL, *atpos_data = NULL, *atx_data = NULL;
7498 int may_wrap = 0; 7521 int may_wrap = 0;
7499 enum it_method prev_method = it->method; 7522 enum it_method prev_method = it->method;
7500 EMACS_INT prev_pos = IT_CHARPOS (*it); 7523 EMACS_INT prev_pos = IT_CHARPOS (*it);
@@ -7563,7 +7586,7 @@ move_it_in_display_line_to (struct it *it,
7563 /* If wrap_it is valid, the current position might be in a 7586 /* If wrap_it is valid, the current position might be in a
7564 word that is wrapped. So, save the iterator in 7587 word that is wrapped. So, save the iterator in
7565 atpos_it and continue to see if wrapping happens. */ 7588 atpos_it and continue to see if wrapping happens. */
7566 atpos_it = *it; 7589 SAVE_IT (atpos_it, *it, atpos_data);
7567 } 7590 }
7568 7591
7569 prev_method = it->method; 7592 prev_method = it->method;
@@ -7600,18 +7623,18 @@ move_it_in_display_line_to (struct it *it,
7600 already found, we are done. */ 7623 already found, we are done. */
7601 if (atpos_it.sp >= 0) 7624 if (atpos_it.sp >= 0)
7602 { 7625 {
7603 *it = atpos_it; 7626 RESTORE_IT (it, &atpos_it, atpos_data);
7604 result = MOVE_POS_MATCH_OR_ZV; 7627 result = MOVE_POS_MATCH_OR_ZV;
7605 goto done; 7628 goto done;
7606 } 7629 }
7607 if (atx_it.sp >= 0) 7630 if (atx_it.sp >= 0)
7608 { 7631 {
7609 *it = atx_it; 7632 RESTORE_IT (it, &atx_it, atx_data);
7610 result = MOVE_X_REACHED; 7633 result = MOVE_X_REACHED;
7611 goto done; 7634 goto done;
7612 } 7635 }
7613 /* Otherwise, we can wrap here. */ 7636 /* Otherwise, we can wrap here. */
7614 wrap_it = *it; 7637 SAVE_IT (wrap_it, *it, wrap_data);
7615 may_wrap = 0; 7638 may_wrap = 0;
7616 } 7639 }
7617 } 7640 }
@@ -7679,7 +7702,7 @@ move_it_in_display_line_to (struct it *it,
7679 goto buffer_pos_reached; 7702 goto buffer_pos_reached;
7680 if (atpos_it.sp < 0) 7703 if (atpos_it.sp < 0)
7681 { 7704 {
7682 atpos_it = *it; 7705 SAVE_IT (atpos_it, *it, atpos_data);
7683 IT_RESET_X_ASCENT_DESCENT (&atpos_it); 7706 IT_RESET_X_ASCENT_DESCENT (&atpos_it);
7684 } 7707 }
7685 } 7708 }
@@ -7693,7 +7716,7 @@ move_it_in_display_line_to (struct it *it,
7693 } 7716 }
7694 if (atx_it.sp < 0) 7717 if (atx_it.sp < 0)
7695 { 7718 {
7696 atx_it = *it; 7719 SAVE_IT (atx_it, *it, atx_data);
7697 IT_RESET_X_ASCENT_DESCENT (&atx_it); 7720 IT_RESET_X_ASCENT_DESCENT (&atx_it);
7698 } 7721 }
7699 } 7722 }
@@ -7737,7 +7760,7 @@ move_it_in_display_line_to (struct it *it,
7737 if (it->line_wrap == WORD_WRAP 7760 if (it->line_wrap == WORD_WRAP
7738 && atpos_it.sp < 0) 7761 && atpos_it.sp < 0)
7739 { 7762 {
7740 atpos_it = *it; 7763 SAVE_IT (atpos_it, *it, atpos_data);
7741 atpos_it.current_x = x_before_this_char; 7764 atpos_it.current_x = x_before_this_char;
7742 atpos_it.hpos = hpos_before_this_char; 7765 atpos_it.hpos = hpos_before_this_char;
7743 } 7766 }
@@ -7782,7 +7805,7 @@ move_it_in_display_line_to (struct it *it,
7782 7805
7783 if (wrap_it.sp >= 0) 7806 if (wrap_it.sp >= 0)
7784 { 7807 {
7785 *it = wrap_it; 7808 RESTORE_IT (it, &wrap_it, wrap_data);
7786 atpos_it.sp = -1; 7809 atpos_it.sp = -1;
7787 atx_it.sp = -1; 7810 atx_it.sp = -1;
7788 } 7811 }
@@ -7799,7 +7822,7 @@ move_it_in_display_line_to (struct it *it,
7799 goto buffer_pos_reached; 7822 goto buffer_pos_reached;
7800 if (it->line_wrap == WORD_WRAP && atpos_it.sp < 0) 7823 if (it->line_wrap == WORD_WRAP && atpos_it.sp < 0)
7801 { 7824 {
7802 atpos_it = *it; 7825 SAVE_IT (atpos_it, *it, atpos_data);
7803 IT_RESET_X_ASCENT_DESCENT (&atpos_it); 7826 IT_RESET_X_ASCENT_DESCENT (&atpos_it);
7804 } 7827 }
7805 } 7828 }
@@ -7879,12 +7902,19 @@ move_it_in_display_line_to (struct it *it,
7879 /* If we scanned beyond to_pos and didn't find a point to wrap at, 7902 /* If we scanned beyond to_pos and didn't find a point to wrap at,
7880 restore the saved iterator. */ 7903 restore the saved iterator. */
7881 if (atpos_it.sp >= 0) 7904 if (atpos_it.sp >= 0)
7882 *it = atpos_it; 7905 RESTORE_IT (it, &atpos_it, atpos_data);
7883 else if (atx_it.sp >= 0) 7906 else if (atx_it.sp >= 0)
7884 *it = atx_it; 7907 RESTORE_IT (it, &atx_it, atx_data);
7885 7908
7886 done: 7909 done:
7887 7910
7911 if (atpos_data)
7912 xfree (atpos_data);
7913 if (atx_data)
7914 xfree (atx_data);
7915 if (wrap_data)
7916 xfree (wrap_data);
7917
7888 /* Restore the iterator settings altered at the beginning of this 7918 /* Restore the iterator settings altered at the beginning of this
7889 function. */ 7919 function. */
7890 it->glyph_row = saved_glyph_row; 7920 it->glyph_row = saved_glyph_row;
@@ -7900,8 +7930,12 @@ move_it_in_display_line (struct it *it,
7900 if (it->line_wrap == WORD_WRAP 7930 if (it->line_wrap == WORD_WRAP
7901 && (op & MOVE_TO_X)) 7931 && (op & MOVE_TO_X))
7902 { 7932 {
7903 struct it save_it = *it; 7933 struct it save_it;
7904 int skip = move_it_in_display_line_to (it, to_charpos, to_x, op); 7934 void *save_data = NULL;
7935 int skip;
7936
7937 SAVE_IT (save_it, *it, save_data);
7938 skip = move_it_in_display_line_to (it, to_charpos, to_x, op);
7905 /* When word-wrap is on, TO_X may lie past the end 7939 /* When word-wrap is on, TO_X may lie past the end
7906 of a wrapped line. Then it->current is the 7940 of a wrapped line. Then it->current is the
7907 character on the next line, so backtrack to the 7941 character on the next line, so backtrack to the
@@ -7909,10 +7943,12 @@ move_it_in_display_line (struct it *it,
7909 if (skip == MOVE_LINE_CONTINUED) 7943 if (skip == MOVE_LINE_CONTINUED)
7910 { 7944 {
7911 int prev_x = max (it->current_x - 1, 0); 7945 int prev_x = max (it->current_x - 1, 0);
7912 *it = save_it; 7946 RESTORE_IT (it, &save_it, save_data);
7913 move_it_in_display_line_to 7947 move_it_in_display_line_to
7914 (it, -1, prev_x, MOVE_TO_X); 7948 (it, -1, prev_x, MOVE_TO_X);
7915 } 7949 }
7950 else
7951 xfree (save_data);
7916 } 7952 }
7917 else 7953 else
7918 move_it_in_display_line_to (it, to_charpos, to_x, op); 7954 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{ 7971{
7936 enum move_it_result skip, skip2 = MOVE_X_REACHED; 7972 enum move_it_result skip, skip2 = MOVE_X_REACHED;
7937 int line_height, line_start_x = 0, reached = 0; 7973 int line_height, line_start_x = 0, reached = 0;
7974 void *backup_data = NULL;
7938 7975
7939 for (;;) 7976 for (;;)
7940 { 7977 {
@@ -7987,7 +8024,7 @@ move_it_to (struct it *it, EMACS_INT to_charpos, int to_x, int to_y, int to_vpos
7987 struct it it_backup; 8024 struct it it_backup;
7988 8025
7989 if (it->line_wrap == WORD_WRAP) 8026 if (it->line_wrap == WORD_WRAP)
7990 it_backup = *it; 8027 SAVE_IT (it_backup, *it, backup_data);
7991 8028
7992 /* TO_Y specified means stop at TO_X in the line containing 8029 /* TO_Y specified means stop at TO_X in the line containing
7993 TO_Y---or at TO_CHARPOS if this is reached first. The 8030 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 reached = 6; 8058 reached = 6;
8022 break; 8059 break;
8023 } 8060 }
8024 it_backup = *it; 8061 SAVE_IT (it_backup, *it, backup_data);
8025 TRACE_MOVE ((stderr, "move_it: from %d\n", IT_CHARPOS (*it))); 8062 TRACE_MOVE ((stderr, "move_it: from %d\n", IT_CHARPOS (*it)));
8026 skip2 = move_it_in_display_line_to (it, to_charpos, -1, 8063 skip2 = move_it_in_display_line_to (it, to_charpos, -1,
8027 op & MOVE_TO_POS); 8064 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 /* If TO_Y is in this line and TO_X was reached 8072 /* If TO_Y is in this line and TO_X was reached
8036 above, we scanned too far. We have to restore 8073 above, we scanned too far. We have to restore
8037 IT's settings to the ones before skipping. */ 8074 IT's settings to the ones before skipping. */
8038 *it = it_backup; 8075 RESTORE_IT (it, &it_backup, backup_data);
8039 reached = 6; 8076 reached = 6;
8040 } 8077 }
8041 else 8078 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 && it->line_wrap == WORD_WRAP) 8099 && it->line_wrap == WORD_WRAP)
8063 { 8100 {
8064 int prev_x = max (it->current_x - 1, 0); 8101 int prev_x = max (it->current_x - 1, 0);
8065 *it = it_backup; 8102 RESTORE_IT (it, &it_backup, backup_data);
8066 skip = move_it_in_display_line_to 8103 skip = move_it_in_display_line_to
8067 (it, -1, prev_x, MOVE_TO_X); 8104 (it, -1, prev_x, MOVE_TO_X);
8068 } 8105 }
@@ -8169,6 +8206,9 @@ move_it_to (struct it *it, EMACS_INT to_charpos, int to_x, int to_y, int to_vpos
8169 last_max_ascent = it->max_ascent; 8206 last_max_ascent = it->max_ascent;
8170 } 8207 }
8171 8208
8209 if (backup_data)
8210 xfree (backup_data);
8211
8172 TRACE_MOVE ((stderr, "move_it_to: reached %d\n", reached)); 8212 TRACE_MOVE ((stderr, "move_it_to: reached %d\n", reached));
8173} 8213}
8174 8214
@@ -8186,6 +8226,7 @@ move_it_vertically_backward (struct it *it, int dy)
8186{ 8226{
8187 int nlines, h; 8227 int nlines, h;
8188 struct it it2, it3; 8228 struct it it2, it3;
8229 void *it2data = NULL, *it3data = NULL;
8189 EMACS_INT start_pos; 8230 EMACS_INT start_pos;
8190 8231
8191 move_further_back: 8232 move_further_back:
@@ -8214,7 +8255,7 @@ move_it_vertically_backward (struct it *it, int dy)
8214 start of the next line so that we get its height. We need this 8255 start of the next line so that we get its height. We need this
8215 height to be able to tell whether we reached the specified 8256 height to be able to tell whether we reached the specified
8216 y-distance. */ 8257 y-distance. */
8217 it2 = *it; 8258 SAVE_IT (it2, *it, it2data);
8218 it2.max_ascent = it2.max_descent = 0; 8259 it2.max_ascent = it2.max_descent = 0;
8219 do 8260 do
8220 { 8261 {
@@ -8223,7 +8264,7 @@ move_it_vertically_backward (struct it *it, int dy)
8223 } 8264 }
8224 while (!IT_POS_VALID_AFTER_MOVE_P (&it2)); 8265 while (!IT_POS_VALID_AFTER_MOVE_P (&it2));
8225 xassert (IT_CHARPOS (*it) >= BEGV); 8266 xassert (IT_CHARPOS (*it) >= BEGV);
8226 it3 = it2; 8267 SAVE_IT (it3, it2, it3data);
8227 8268
8228 move_it_to (&it2, start_pos, -1, -1, -1, MOVE_TO_POS); 8269 move_it_to (&it2, start_pos, -1, -1, -1, MOVE_TO_POS);
8229 xassert (IT_CHARPOS (*it) >= BEGV); 8270 xassert (IT_CHARPOS (*it) >= BEGV);
@@ -8242,8 +8283,10 @@ move_it_vertically_backward (struct it *it, int dy)
8242 { 8283 {
8243 /* DY == 0 means move to the start of the screen line. The 8284 /* DY == 0 means move to the start of the screen line. The
8244 value of nlines is > 0 if continuation lines were involved. */ 8285 value of nlines is > 0 if continuation lines were involved. */
8286 RESTORE_IT (it, it, it2data);
8245 if (nlines > 0) 8287 if (nlines > 0)
8246 move_it_by_lines (it, nlines); 8288 move_it_by_lines (it, nlines);
8289 xfree (it3data);
8247 } 8290 }
8248 else 8291 else
8249 { 8292 {
@@ -8251,9 +8294,13 @@ move_it_vertically_backward (struct it *it, int dy)
8251 Note that H has been subtracted in front of the if-statement. */ 8294 Note that H has been subtracted in front of the if-statement. */
8252 int target_y = it->current_y + h - dy; 8295 int target_y = it->current_y + h - dy;
8253 int y0 = it3.current_y; 8296 int y0 = it3.current_y;
8254 int y1 = line_bottom_y (&it3); 8297 int y1;
8255 int line_height = y1 - y0; 8298 int line_height;
8256 8299
8300 RESTORE_IT (&it3, &it3, it3data);
8301 y1 = line_bottom_y (&it3);
8302 line_height = y1 - y0;
8303 RESTORE_IT (it, it, it2data);
8257 /* If we did not reach target_y, try to move further backward if 8304 /* If we did not reach target_y, try to move further backward if
8258 we can. If we moved too far backward, try to move forward. */ 8305 we can. If we moved too far backward, try to move forward. */
8259 if (target_y < it->current_y 8306 if (target_y < it->current_y
@@ -8380,6 +8427,7 @@ move_it_by_lines (struct it *it, int dvpos)
8380 else 8427 else
8381 { 8428 {
8382 struct it it2; 8429 struct it it2;
8430 void *it2data = NULL;
8383 EMACS_INT start_charpos, i; 8431 EMACS_INT start_charpos, i;
8384 8432
8385 /* Start at the beginning of the screen line containing IT's 8433 /* Start at the beginning of the screen line containing IT's
@@ -8415,7 +8463,7 @@ move_it_by_lines (struct it *it, int dvpos)
8415 8463
8416 /* Above call may have moved too far if continuation lines 8464 /* Above call may have moved too far if continuation lines
8417 are involved. Scan forward and see if it did. */ 8465 are involved. Scan forward and see if it did. */
8418 it2 = *it; 8466 SAVE_IT (it2, *it, it2data);
8419 it2.vpos = it2.current_y = 0; 8467 it2.vpos = it2.current_y = 0;
8420 move_it_to (&it2, start_charpos, -1, -1, -1, MOVE_TO_POS); 8468 move_it_to (&it2, start_charpos, -1, -1, -1, MOVE_TO_POS);
8421 it->vpos -= it2.vpos; 8469 it->vpos -= it2.vpos;
@@ -8426,12 +8474,18 @@ move_it_by_lines (struct it *it, int dvpos)
8426 if (it2.vpos > -dvpos) 8474 if (it2.vpos > -dvpos)
8427 { 8475 {
8428 int delta = it2.vpos + dvpos; 8476 int delta = it2.vpos + dvpos;
8429 it2 = *it; 8477
8478 RESTORE_IT (&it2, &it2, it2data);
8479 SAVE_IT (it2, *it, it2data);
8430 move_it_to (it, -1, -1, -1, it->vpos + delta, MOVE_TO_VPOS); 8480 move_it_to (it, -1, -1, -1, it->vpos + delta, MOVE_TO_VPOS);
8431 /* Move back again if we got too far ahead. */ 8481 /* Move back again if we got too far ahead. */
8432 if (IT_CHARPOS (*it) >= start_charpos) 8482 if (IT_CHARPOS (*it) >= start_charpos)
8433 *it = it2; 8483 RESTORE_IT (it, &it2, it2data);
8484 else
8485 xfree (it2data);
8434 } 8486 }
8487 else
8488 RESTORE_IT (it, it, it2data);
8435 } 8489 }
8436} 8490}
8437 8491
@@ -13776,14 +13830,18 @@ try_scrolling (Lisp_Object window, int just_this_one_p,
13776 which was computed as distance from window bottom to 13830 which was computed as distance from window bottom to
13777 point. This matters when lines at window top and lines 13831 point. This matters when lines at window top and lines
13778 below window bottom have different height. */ 13832 below window bottom have different height. */
13779 struct it it1 = it; 13833 struct it it1;
13834 void *it1data = NULL;
13780 /* We use a temporary it1 because line_bottom_y can modify 13835 /* We use a temporary it1 because line_bottom_y can modify
13781 its argument, if it moves one line down; see there. */ 13836 its argument, if it moves one line down; see there. */
13782 int start_y = line_bottom_y (&it1); 13837 int start_y;
13783 13838
13839 SAVE_IT (it1, it, it1data);
13840 start_y = line_bottom_y (&it1);
13784 do { 13841 do {
13842 RESTORE_IT (&it, &it, it1data);
13785 move_it_by_lines (&it, 1); 13843 move_it_by_lines (&it, 1);
13786 it1 = it; 13844 SAVE_IT (it1, it, it1data);
13787 } while (line_bottom_y (&it1) - start_y < amount_to_scroll); 13845 } while (line_bottom_y (&it1) - start_y < amount_to_scroll);
13788 } 13846 }
13789 13847
@@ -14891,10 +14949,13 @@ redisplay_window (Lisp_Object window, int just_this_one_p)
14891 && BEGV <= CHARPOS (startp) && CHARPOS (startp) <= ZV) 14949 && BEGV <= CHARPOS (startp) && CHARPOS (startp) <= ZV)
14892 { 14950 {
14893 struct it it1; 14951 struct it it1;
14952 void *it1data = NULL;
14894 14953
14954 SAVE_IT (it1, it, it1data);
14895 start_display (&it1, w, startp); 14955 start_display (&it1, w, startp);
14896 move_it_vertically (&it1, margin); 14956 move_it_vertically (&it1, margin);
14897 margin_pos = IT_CHARPOS (it1); 14957 margin_pos = IT_CHARPOS (it1);
14958 RESTORE_IT (&it, &it, it1data);
14898 } 14959 }
14899 scrolling_up = PT > margin_pos; 14960 scrolling_up = PT > margin_pos;
14900 aggressive = 14961 aggressive =
@@ -17991,6 +18052,7 @@ display_line (struct it *it)
17991 struct glyph_row *row = it->glyph_row; 18052 struct glyph_row *row = it->glyph_row;
17992 Lisp_Object overlay_arrow_string; 18053 Lisp_Object overlay_arrow_string;
17993 struct it wrap_it; 18054 struct it wrap_it;
18055 void *wrap_data = NULL;
17994 int may_wrap = 0, wrap_x IF_LINT (= 0); 18056 int may_wrap = 0, wrap_x IF_LINT (= 0);
17995 int wrap_row_used = -1; 18057 int wrap_row_used = -1;
17996 int wrap_row_ascent IF_LINT (= 0), wrap_row_height IF_LINT (= 0); 18058 int wrap_row_ascent IF_LINT (= 0), wrap_row_height IF_LINT (= 0);
@@ -18145,7 +18207,7 @@ display_line (struct it *it)
18145 may_wrap = 1; 18207 may_wrap = 1;
18146 else if (may_wrap) 18208 else if (may_wrap)
18147 { 18209 {
18148 wrap_it = *it; 18210 SAVE_IT (wrap_it, *it, wrap_data);
18149 wrap_x = x; 18211 wrap_x = x;
18150 wrap_row_used = row->used[TEXT_AREA]; 18212 wrap_row_used = row->used[TEXT_AREA];
18151 wrap_row_ascent = row->ascent; 18213 wrap_row_ascent = row->ascent;
@@ -18315,7 +18377,7 @@ display_line (struct it *it)
18315 if (row->reversed_p) 18377 if (row->reversed_p)
18316 unproduce_glyphs (it, 18378 unproduce_glyphs (it,
18317 row->used[TEXT_AREA] - wrap_row_used); 18379 row->used[TEXT_AREA] - wrap_row_used);
18318 *it = wrap_it; 18380 RESTORE_IT (it, &wrap_it, wrap_data);
18319 it->continuation_lines_width += wrap_x; 18381 it->continuation_lines_width += wrap_x;
18320 row->used[TEXT_AREA] = wrap_row_used; 18382 row->used[TEXT_AREA] = wrap_row_used;
18321 row->ascent = wrap_row_ascent; 18383 row->ascent = wrap_row_ascent;