diff options
| author | Eli Zaretskii | 2011-09-17 18:18:56 +0300 |
|---|---|---|
| committer | Eli Zaretskii | 2011-09-17 18:18:56 +0300 |
| commit | 1137e8b8eb6fbae76880b814d516377de30eddd3 (patch) | |
| tree | 51e82ce03063d5940d0e9e27fff0f10f2587634b /src | |
| parent | 8d5ed89901195abc4a5d660371ea26e849292ea6 (diff) | |
| download | emacs-1137e8b8eb6fbae76880b814d516377de30eddd3.tar.gz emacs-1137e8b8eb6fbae76880b814d516377de30eddd3.zip | |
Fix bug #9470 with slow redisplay in huge single-paragraph buffers.
src/bidi.c (MAX_PARAGRAPH_SEARCH): New macro.
(bidi_find_paragraph_start): Search back for paragraph beginning
at most MAX_PARAGRAPH_SEARCH lines; if not found, return BEGV_BYTE.
(bidi_move_to_visually_next): Only trigger paragraph-related
computations when the last character is a newline or at EOB, not
just any NEUTRAL_B.
src/xdisp.c (reseat_at_next_visible_line_start): Keep information
about the current paragraph and restore it after the call to
reseat.
Diffstat (limited to 'src')
| -rw-r--r-- | src/ChangeLog | 11 | ||||
| -rw-r--r-- | src/bidi.c | 20 | ||||
| -rw-r--r-- | src/xdisp.c | 42 |
3 files changed, 69 insertions, 4 deletions
diff --git a/src/ChangeLog b/src/ChangeLog index d09c970bc03..a6d890cd149 100644 --- a/src/ChangeLog +++ b/src/ChangeLog | |||
| @@ -1,5 +1,16 @@ | |||
| 1 | 2011-09-17 Eli Zaretskii <eliz@gnu.org> | 1 | 2011-09-17 Eli Zaretskii <eliz@gnu.org> |
| 2 | 2 | ||
| 3 | * xdisp.c (reseat_at_next_visible_line_start): Keep information | ||
| 4 | about the current paragraph and restore it after the call to | ||
| 5 | reseat. | ||
| 6 | |||
| 7 | * bidi.c (MAX_PARAGRAPH_SEARCH): New macro. | ||
| 8 | (bidi_find_paragraph_start): Search back for paragraph beginning | ||
| 9 | at most MAX_PARAGRAPH_SEARCH lines; if not found, return BEGV_BYTE. | ||
| 10 | (bidi_move_to_visually_next): Only trigger paragraph-related | ||
| 11 | computations when the last character is a newline or at EOB, not | ||
| 12 | just any NEUTRAL_B. (Bug#9470) | ||
| 13 | |||
| 3 | * xdisp.c (set_cursor_from_row): Don't invoke special treatment of | 14 | * xdisp.c (set_cursor_from_row): Don't invoke special treatment of |
| 4 | truncated lines if point is covered by a display string. (Bug#9524) | 15 | truncated lines if point is covered by a display string. (Bug#9524) |
| 5 | 16 | ||
diff --git a/src/bidi.c b/src/bidi.c index bb29647ea88..3efdc1590df 100644 --- a/src/bidi.c +++ b/src/bidi.c | |||
| @@ -1071,15 +1071,25 @@ bidi_at_paragraph_end (EMACS_INT charpos, EMACS_INT bytepos) | |||
| 1071 | return val; | 1071 | return val; |
| 1072 | } | 1072 | } |
| 1073 | 1073 | ||
| 1074 | /* On my 2005-vintage machine, searching back for paragraph start | ||
| 1075 | takes ~1 ms per line. And bidi_paragraph_init is called 4 times | ||
| 1076 | when user types C-p. The number below limits each call to | ||
| 1077 | bidi_paragraph_init to about 10 ms. */ | ||
| 1078 | #define MAX_PARAGRAPH_SEARCH 7500 | ||
| 1079 | |||
| 1074 | /* Find the beginning of this paragraph by looking back in the buffer. | 1080 | /* Find the beginning of this paragraph by looking back in the buffer. |
| 1075 | Value is the byte position of the paragraph's beginning. */ | 1081 | Value is the byte position of the paragraph's beginning, or |
| 1082 | BEGV_BYTE if paragraph_start_re is still not found after looking | ||
| 1083 | back MAX_PARAGRAPH_SEARCH lines in the buffer. */ | ||
| 1076 | static EMACS_INT | 1084 | static EMACS_INT |
| 1077 | bidi_find_paragraph_start (EMACS_INT pos, EMACS_INT pos_byte) | 1085 | bidi_find_paragraph_start (EMACS_INT pos, EMACS_INT pos_byte) |
| 1078 | { | 1086 | { |
| 1079 | Lisp_Object re = paragraph_start_re; | 1087 | Lisp_Object re = paragraph_start_re; |
| 1080 | EMACS_INT limit = ZV, limit_byte = ZV_BYTE; | 1088 | EMACS_INT limit = ZV, limit_byte = ZV_BYTE; |
| 1089 | EMACS_INT n = 0; | ||
| 1081 | 1090 | ||
| 1082 | while (pos_byte > BEGV_BYTE | 1091 | while (pos_byte > BEGV_BYTE |
| 1092 | && n++ < MAX_PARAGRAPH_SEARCH | ||
| 1083 | && fast_looking_at (re, pos, pos_byte, limit, limit_byte, Qnil) < 0) | 1093 | && fast_looking_at (re, pos, pos_byte, limit, limit_byte, Qnil) < 0) |
| 1084 | { | 1094 | { |
| 1085 | /* FIXME: What if the paragraph beginning is covered by a | 1095 | /* FIXME: What if the paragraph beginning is covered by a |
| @@ -1089,6 +1099,8 @@ bidi_find_paragraph_start (EMACS_INT pos, EMACS_INT pos_byte) | |||
| 1089 | pos = find_next_newline_no_quit (pos - 1, -1); | 1099 | pos = find_next_newline_no_quit (pos - 1, -1); |
| 1090 | pos_byte = CHAR_TO_BYTE (pos); | 1100 | pos_byte = CHAR_TO_BYTE (pos); |
| 1091 | } | 1101 | } |
| 1102 | if (n >= MAX_PARAGRAPH_SEARCH) | ||
| 1103 | pos_byte = BEGV_BYTE; | ||
| 1092 | return pos_byte; | 1104 | return pos_byte; |
| 1093 | } | 1105 | } |
| 1094 | 1106 | ||
| @@ -2239,7 +2251,8 @@ bidi_move_to_visually_next (struct bidi_it *bidi_it) | |||
| 2239 | GCPRO1 (bidi_it->string.lstring); | 2251 | GCPRO1 (bidi_it->string.lstring); |
| 2240 | 2252 | ||
| 2241 | /* If we just passed a newline, initialize for the next line. */ | 2253 | /* If we just passed a newline, initialize for the next line. */ |
| 2242 | if (!bidi_it->first_elt && bidi_it->orig_type == NEUTRAL_B) | 2254 | if (!bidi_it->first_elt |
| 2255 | && (bidi_it->ch == '\n' || bidi_it->ch == BIDI_EOB)) | ||
| 2243 | bidi_line_init (bidi_it); | 2256 | bidi_line_init (bidi_it); |
| 2244 | 2257 | ||
| 2245 | /* Prepare the sentinel iterator state, and cache it. When we bump | 2258 | /* Prepare the sentinel iterator state, and cache it. When we bump |
| @@ -2320,7 +2333,8 @@ bidi_move_to_visually_next (struct bidi_it *bidi_it) | |||
| 2320 | reordering, whereas we _must_ know the paragraph base direction | 2333 | reordering, whereas we _must_ know the paragraph base direction |
| 2321 | _before_ we process the paragraph's text, since the base | 2334 | _before_ we process the paragraph's text, since the base |
| 2322 | direction affects the reordering. */ | 2335 | direction affects the reordering. */ |
| 2323 | if (bidi_it->scan_dir == 1 && bidi_it->orig_type == NEUTRAL_B) | 2336 | if (bidi_it->scan_dir == 1 |
| 2337 | && (bidi_it->ch == '\n' || bidi_it->ch == BIDI_EOB)) | ||
| 2324 | { | 2338 | { |
| 2325 | /* The paragraph direction of the entire string, once | 2339 | /* The paragraph direction of the entire string, once |
| 2326 | determined, is in effect for the entire string. Setting the | 2340 | determined, is in effect for the entire string. Setting the |
diff --git a/src/xdisp.c b/src/xdisp.c index 864734d4b20..3cb9f301bb2 100644 --- a/src/xdisp.c +++ b/src/xdisp.c | |||
| @@ -5722,6 +5722,9 @@ reseat_at_next_visible_line_start (struct it *it, int on_newline_p) | |||
| 5722 | { | 5722 | { |
| 5723 | int newline_found_p, skipped_p = 0; | 5723 | int newline_found_p, skipped_p = 0; |
| 5724 | struct bidi_it bidi_it_prev; | 5724 | struct bidi_it bidi_it_prev; |
| 5725 | int new_paragraph, first_elt, disp_prop; | ||
| 5726 | EMACS_INT paragraph_end, disp_pos; | ||
| 5727 | bidi_dir_t paragraph_dir; | ||
| 5725 | 5728 | ||
| 5726 | newline_found_p = forward_to_next_line_start (it, &skipped_p, &bidi_it_prev); | 5729 | newline_found_p = forward_to_next_line_start (it, &skipped_p, &bidi_it_prev); |
| 5727 | 5730 | ||
| @@ -5738,6 +5741,23 @@ reseat_at_next_visible_line_start (struct it *it, int on_newline_p) | |||
| 5738 | forward_to_next_line_start (it, &skipped_p, &bidi_it_prev); | 5741 | forward_to_next_line_start (it, &skipped_p, &bidi_it_prev); |
| 5739 | } | 5742 | } |
| 5740 | 5743 | ||
| 5744 | /* Under bidi iteration, save the attributes of the paragraph we are | ||
| 5745 | in, to be restored after the call to `reseat' below. That's | ||
| 5746 | because `reseat' overwrites them, which requires unneeded and | ||
| 5747 | potentially expensive backward search for paragraph beginning. | ||
| 5748 | This search is unnecessary because we will be `reseat'ed to the | ||
| 5749 | same position where we are now, for which we already have all the | ||
| 5750 | information we need in the bidi iterator. */ | ||
| 5751 | if (it->bidi_p && !STRINGP (it->string)) | ||
| 5752 | { | ||
| 5753 | new_paragraph = it->bidi_it.new_paragraph; | ||
| 5754 | first_elt = it->bidi_it.first_elt; | ||
| 5755 | paragraph_end = it->bidi_it.separator_limit; | ||
| 5756 | paragraph_dir = it->bidi_it.paragraph_dir; | ||
| 5757 | disp_pos = it->bidi_it.disp_pos; | ||
| 5758 | disp_prop = it->bidi_it.disp_prop; | ||
| 5759 | } | ||
| 5760 | |||
| 5741 | /* Position on the newline if that's what's requested. */ | 5761 | /* Position on the newline if that's what's requested. */ |
| 5742 | if (on_newline_p && newline_found_p) | 5762 | if (on_newline_p && newline_found_p) |
| 5743 | { | 5763 | { |
| @@ -5777,10 +5797,30 @@ reseat_at_next_visible_line_start (struct it *it, int on_newline_p) | |||
| 5777 | IT_BYTEPOS (*it) = it->bidi_it.bytepos; | 5797 | IT_BYTEPOS (*it) = it->bidi_it.bytepos; |
| 5778 | } | 5798 | } |
| 5779 | reseat (it, it->current.pos, 0); | 5799 | reseat (it, it->current.pos, 0); |
| 5800 | if (it->bidi_p) | ||
| 5801 | { | ||
| 5802 | it->bidi_it.new_paragraph = new_paragraph; | ||
| 5803 | it->bidi_it.first_elt = first_elt; | ||
| 5804 | it->bidi_it.separator_limit = paragraph_end; | ||
| 5805 | it->bidi_it.paragraph_dir = paragraph_dir; | ||
| 5806 | it->bidi_it.disp_pos = disp_pos; | ||
| 5807 | it->bidi_it.disp_prop = disp_prop; | ||
| 5808 | } | ||
| 5780 | } | 5809 | } |
| 5781 | } | 5810 | } |
| 5782 | else if (skipped_p) | 5811 | else if (skipped_p) |
| 5783 | reseat (it, it->current.pos, 0); | 5812 | { |
| 5813 | reseat (it, it->current.pos, 0); | ||
| 5814 | if (it->bidi_p) | ||
| 5815 | { | ||
| 5816 | it->bidi_it.new_paragraph = new_paragraph; | ||
| 5817 | it->bidi_it.first_elt = first_elt; | ||
| 5818 | it->bidi_it.separator_limit = paragraph_end; | ||
| 5819 | it->bidi_it.paragraph_dir = paragraph_dir; | ||
| 5820 | it->bidi_it.disp_pos = disp_pos; | ||
| 5821 | it->bidi_it.disp_prop = disp_prop; | ||
| 5822 | } | ||
| 5823 | } | ||
| 5784 | 5824 | ||
| 5785 | CHECK_IT (it); | 5825 | CHECK_IT (it); |
| 5786 | } | 5826 | } |