aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorEli Zaretskii2014-10-22 19:09:57 +0300
committerEli Zaretskii2014-10-22 19:09:57 +0300
commit6a7884caf2a6f4a7fb7faa9ba275163d40f6bd96 (patch)
treed069f3b26e0a621dffb1747bea2b55f13af3ca16 /src
parent36749d80256f49ac10860405b95fe319012c3b91 (diff)
downloademacs-6a7884caf2a6f4a7fb7faa9ba275163d40f6bd96.tar.gz
emacs-6a7884caf2a6f4a7fb7faa9ba275163d40f6bd96.zip
Fix bug #18778 with slow redisplay of bracketed L2R text with long lines.
src/bidi.c (bidi_cache_reset_to): New function. (bidi_cache_reset): Call it. (bidi_init_it, bidi_line_init): Initialize the bracket_pairing_pos member to -1. (bidi_resolve_explicit): Reset bracket_pairing_pos and bracket_enclosed_type only if bracket_pairing_pos's value is not ZV. (MAX_BPA_STACK): Make sure the value is signed. (PUSH_BPA_STACK): If the BPA stack overflows, don't bail out, but stop pushing values onto the stack. (bidi_find_bracket_pairs): If the bracketed text is only on the base embedding level, remove all the states cached by this function from the cache, and return zero, so that the brackets in this segment of text are processed as normal neutrals. (bidi_resolve_brackets): Detect the brackets that are to be processed as neutrals, and don't call bidi_find_bracket_pairs on them.
Diffstat (limited to 'src')
-rw-r--r--src/ChangeLog21
-rw-r--r--src/bidi.c134
2 files changed, 135 insertions, 20 deletions
diff --git a/src/ChangeLog b/src/ChangeLog
index daa11d7f5c7..91f910aa6f9 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,3 +1,24 @@
12014-10-22 Eli Zaretskii <eliz@gnu.org>
2
3 Optimize redisplay of simple bracketed text.
4 * bidi.c (bidi_cache_reset_to): New function.
5 (bidi_cache_reset): Call it.
6 (bidi_init_it, bidi_line_init): Initialize the bracket_pairing_pos
7 member to -1.
8 (bidi_resolve_explicit): Reset bracket_pairing_pos and
9 bracket_enclosed_type only if bracket_pairing_pos's value is not
10 ZV.
11 (MAX_BPA_STACK): Make sure the value is signed.
12 (PUSH_BPA_STACK): If the BPA stack overflows, don't bail out, but
13 stop pushing values onto the stack.
14 (bidi_find_bracket_pairs): If the bracketed text is only on the
15 base embedding level, remove all the states cached by this
16 function from the cache, and return zero, so that the brackets in
17 this segment of text are processed as normal neutrals.
18 (bidi_resolve_brackets): Detect the brackets that are to be
19 processed as neutrals, and don't call bidi_find_bracket_pairs on
20 them. (Bug#18778)
21
12014-10-21 Stefan Monnier <monnier@iro.umontreal.ca> 222014-10-21 Stefan Monnier <monnier@iro.umontreal.ca>
2 23
3 * w32select.c (Fw32_selection_exists_p): Rename from 24 * w32select.c (Fw32_selection_exists_p): Rename from
diff --git a/src/bidi.c b/src/bidi.c
index d354aa796ae..84341cb1456 100644
--- a/src/bidi.c
+++ b/src/bidi.c
@@ -565,6 +565,16 @@ enum
565 + sizeof (bidi_cache_last_idx)) 565 + sizeof (bidi_cache_last_idx))
566 }; 566 };
567 567
568/* Effectively remove the cached states beyond the Nth state from the
569 part of the cache relevant to iteration of the current object
570 (buffer or string). */
571static void
572bidi_cache_reset_to (int n)
573{
574 bidi_cache_idx = bidi_cache_start + n;
575 bidi_cache_last_idx = n - 1;
576}
577
568/* Reset the cache state to the empty state. We only reset the part 578/* Reset the cache state to the empty state. We only reset the part
569 of the cache relevant to iteration of the current object. Previous 579 of the cache relevant to iteration of the current object. Previous
570 objects, which are pushed on the display iterator's stack, are left 580 objects, which are pushed on the display iterator's stack, are left
@@ -574,8 +584,7 @@ enum
574static void 584static void
575bidi_cache_reset (void) 585bidi_cache_reset (void)
576{ 586{
577 bidi_cache_idx = bidi_cache_start; 587 bidi_cache_reset_to (0);
578 bidi_cache_last_idx = -1;
579} 588}
580 589
581/* Shrink the cache to its minimal size. Called when we init the bidi 590/* Shrink the cache to its minimal size. Called when we init the bidi
@@ -1076,6 +1085,7 @@ bidi_init_it (ptrdiff_t charpos, ptrdiff_t bytepos, bool frame_window_p,
1076 bidi_it->prev_for_neutral.charpos = -1; 1085 bidi_it->prev_for_neutral.charpos = -1;
1077 bidi_it->prev_for_neutral.type 1086 bidi_it->prev_for_neutral.type
1078 = bidi_it->prev_for_neutral.orig_type = UNKNOWN_BT; 1087 = bidi_it->prev_for_neutral.orig_type = UNKNOWN_BT;
1088 bidi_it->bracket_pairing_pos = -1;
1079 bidi_it->sos = L2R; /* FIXME: should it be user-selectable? */ 1089 bidi_it->sos = L2R; /* FIXME: should it be user-selectable? */
1080 bidi_it->disp_pos = -1; /* invalid/unknown */ 1090 bidi_it->disp_pos = -1; /* invalid/unknown */
1081 bidi_it->disp_prop = 0; 1091 bidi_it->disp_prop = 0;
@@ -1105,6 +1115,7 @@ bidi_line_init (struct bidi_it *bidi_it)
1105 bidi_it->next_en_type = UNKNOWN_BT; 1115 bidi_it->next_en_type = UNKNOWN_BT;
1106 bidi_it->next_for_ws.charpos = -1; 1116 bidi_it->next_for_ws.charpos = -1;
1107 bidi_it->next_for_ws.type = UNKNOWN_BT; 1117 bidi_it->next_for_ws.type = UNKNOWN_BT;
1118 bidi_it->bracket_pairing_pos = -1;
1108 bidi_set_sos_type (bidi_it, 1119 bidi_set_sos_type (bidi_it,
1109 (bidi_it->paragraph_dir == R2L ? 1 : 0), 1120 (bidi_it->paragraph_dir == R2L ? 1 : 0),
1110 bidi_it->level_stack[0].level); /* X10 */ 1121 bidi_it->level_stack[0].level); /* X10 */
@@ -1758,7 +1769,14 @@ bidi_resolve_explicit (struct bidi_it *bidi_it)
1758 /* If we overstepped the characters used for resolving neutrals 1769 /* If we overstepped the characters used for resolving neutrals
1759 and whitespace, invalidate their info in the iterator. */ 1770 and whitespace, invalidate their info in the iterator. */
1760 if (bidi_it->charpos >= bidi_it->next_for_neutral.charpos) 1771 if (bidi_it->charpos >= bidi_it->next_for_neutral.charpos)
1761 bidi_it->next_for_neutral.type = UNKNOWN_BT; 1772 {
1773 bidi_it->next_for_neutral.type = UNKNOWN_BT;
1774 /* If needed, reset the "magical" value of pairing bracket
1775 position, so that bidi_resolve_brackets will resume
1776 resolution of brackets according to BPA. */
1777 if (bidi_it->bracket_pairing_pos == ZV)
1778 bidi_it->bracket_pairing_pos = -1;
1779 }
1762 if (bidi_it->next_en_pos >= 0 1780 if (bidi_it->next_en_pos >= 0
1763 && bidi_it->charpos >= bidi_it->next_en_pos) 1781 && bidi_it->charpos >= bidi_it->next_en_pos)
1764 { 1782 {
@@ -1766,9 +1784,14 @@ bidi_resolve_explicit (struct bidi_it *bidi_it)
1766 bidi_it->next_en_type = UNKNOWN_BT; 1784 bidi_it->next_en_type = UNKNOWN_BT;
1767 } 1785 }
1768 1786
1769 /* Reset the bracket resolution info. */ 1787 /* Reset the bracket resolution info, unless we previously decided
1770 bidi_it->bracket_pairing_pos = -1; 1788 (in bidi_find_bracket_pairs) that brackets in this level run
1771 bidi_it->bracket_enclosed_type = UNKNOWN_BT; 1789 should be resolved as neutrals. */
1790 if (bidi_it->bracket_pairing_pos != ZV)
1791 {
1792 bidi_it->bracket_pairing_pos = -1;
1793 bidi_it->bracket_enclosed_type = UNKNOWN_BT;
1794 }
1772 1795
1773 /* If reseat()'ed, don't advance, so as to start iteration from the 1796 /* If reseat()'ed, don't advance, so as to start iteration from the
1774 position where we were reseated. bidi_it->bytepos can be less 1797 position where we were reseated. bidi_it->bytepos can be less
@@ -2336,7 +2359,7 @@ typedef struct bpa_stack_entry {
2336 2359
2337/* With MAX_ALLOCA of 16KB, this should allow at least 1K slots in the 2360/* With MAX_ALLOCA of 16KB, this should allow at least 1K slots in the
2338 BPA stack, which should be more than enough for actual bidi text. */ 2361 BPA stack, which should be more than enough for actual bidi text. */
2339#define MAX_BPA_STACK (max (MAX_ALLOCA / sizeof (bpa_stack_entry), 1)) 2362#define MAX_BPA_STACK ((int)max (MAX_ALLOCA / sizeof (bpa_stack_entry), 1))
2340 2363
2341/* UAX#9 says to match opening brackets with the matching closing 2364/* UAX#9 says to match opening brackets with the matching closing
2342 brackets or their canonical equivalents. As of Unicode 7.0, there 2365 brackets or their canonical equivalents. As of Unicode 7.0, there
@@ -2383,17 +2406,15 @@ typedef struct bpa_stack_entry {
2383#define PUSH_BPA_STACK \ 2406#define PUSH_BPA_STACK \
2384 do { \ 2407 do { \
2385 int ch; \ 2408 int ch; \
2386 bpa_sp++; \ 2409 if (bpa_sp < MAX_BPA_STACK - 1) \
2387 if (bpa_sp >= MAX_BPA_STACK) \
2388 { \ 2410 { \
2389 bpa_sp = MAX_BPA_STACK - 1; \ 2411 bpa_sp++; \
2390 goto bpa_give_up; \ 2412 ch = CANONICAL_EQU (bidi_it->ch); \
2413 bpa_stack[bpa_sp].close_bracket_char = bidi_mirror_char (ch); \
2414 bpa_stack[bpa_sp].open_bracket_idx = bidi_cache_last_idx; \
2415 bpa_stack[bpa_sp].flags = 0; \
2416 STORE_BRACKET_CHARPOS; \
2391 } \ 2417 } \
2392 ch = CANONICAL_EQU (bidi_it->ch); \
2393 bpa_stack[bpa_sp].close_bracket_char = bidi_mirror_char (ch); \
2394 bpa_stack[bpa_sp].open_bracket_idx = bidi_cache_last_idx; \
2395 bpa_stack[bpa_sp].flags = 0; \
2396 STORE_BRACKET_CHARPOS; \
2397 } while (0) 2418 } while (0)
2398 2419
2399 2420
@@ -2422,9 +2443,13 @@ bidi_find_bracket_pairs (struct bidi_it *bidi_it)
2422 bpa_stack_entry bpa_stack[MAX_BPA_STACK]; 2443 bpa_stack_entry bpa_stack[MAX_BPA_STACK];
2423 int bpa_sp = -1; 2444 int bpa_sp = -1;
2424 struct bidi_it saved_it; 2445 struct bidi_it saved_it;
2446 int base_level = bidi_it->level_stack[0].level;
2425 int embedding_level = bidi_it->level_stack[bidi_it->stack_idx].level; 2447 int embedding_level = bidi_it->level_stack[bidi_it->stack_idx].level;
2448 int maxlevel = embedding_level;
2426 bidi_type_t embedding_type = (embedding_level & 1) ? STRONG_R : STRONG_L; 2449 bidi_type_t embedding_type = (embedding_level & 1) ? STRONG_R : STRONG_L;
2427 struct bidi_it tem_it; 2450 struct bidi_it tem_it;
2451 bool l2r_seen = false, r2l_seen = false;
2452 ptrdiff_t pairing_pos;
2428 2453
2429 eassert (MAX_BPA_STACK >= 100); 2454 eassert (MAX_BPA_STACK >= 100);
2430 bidi_copy_it (&saved_it, bidi_it); 2455 bidi_copy_it (&saved_it, bidi_it);
@@ -2438,6 +2463,8 @@ bidi_find_bracket_pairs (struct bidi_it *bidi_it)
2438 int old_sidx, new_sidx; 2463 int old_sidx, new_sidx;
2439 int current_level = bidi_it->level_stack[bidi_it->stack_idx].level; 2464 int current_level = bidi_it->level_stack[bidi_it->stack_idx].level;
2440 2465
2466 if (maxlevel < current_level)
2467 maxlevel = current_level;
2441 /* Mark every opening bracket character we've traversed by 2468 /* Mark every opening bracket character we've traversed by
2442 putting its own position into bracket_pairing_pos. This 2469 putting its own position into bracket_pairing_pos. This
2443 is examined in bidi_resolve_brackets to distinguish 2470 is examined in bidi_resolve_brackets to distinguish
@@ -2503,6 +2530,7 @@ bidi_find_bracket_pairs (struct bidi_it *bidi_it)
2503 flag = ((embedding_level & 1) == 0 2530 flag = ((embedding_level & 1) == 0
2504 ? FLAG_EMBEDDING_INSIDE 2531 ? FLAG_EMBEDDING_INSIDE
2505 : FLAG_OPPOSITE_INSIDE); 2532 : FLAG_OPPOSITE_INSIDE);
2533 l2r_seen = true;
2506 break; 2534 break;
2507 case STRONG_R: 2535 case STRONG_R:
2508 case WEAK_EN: 2536 case WEAK_EN:
@@ -2510,6 +2538,7 @@ bidi_find_bracket_pairs (struct bidi_it *bidi_it)
2510 flag = ((embedding_level & 1) == 1 2538 flag = ((embedding_level & 1) == 1
2511 ? FLAG_EMBEDDING_INSIDE 2539 ? FLAG_EMBEDDING_INSIDE
2512 : FLAG_OPPOSITE_INSIDE); 2540 : FLAG_OPPOSITE_INSIDE);
2541 r2l_seen = true;
2513 break; 2542 break;
2514 default: 2543 default:
2515 break; 2544 break;
@@ -2532,6 +2561,8 @@ bidi_find_bracket_pairs (struct bidi_it *bidi_it)
2532 while (bidi_it->level_stack[bidi_it->stack_idx].level 2561 while (bidi_it->level_stack[bidi_it->stack_idx].level
2533 > current_level) 2562 > current_level)
2534 { 2563 {
2564 if (maxlevel < bidi_it->level_stack[bidi_it->stack_idx].level)
2565 maxlevel = bidi_it->level_stack[bidi_it->stack_idx].level;
2535 bidi_cache_iterator_state (bidi_it, type == NEUTRAL_B, 0); 2566 bidi_cache_iterator_state (bidi_it, type == NEUTRAL_B, 0);
2536 type = bidi_resolve_weak (bidi_it); 2567 type = bidi_resolve_weak (bidi_it);
2537 } 2568 }
@@ -2540,11 +2571,11 @@ bidi_find_bracket_pairs (struct bidi_it *bidi_it)
2540 || (bidi_it->level_stack[bidi_it->stack_idx].level 2571 || (bidi_it->level_stack[bidi_it->stack_idx].level
2541 != current_level)) 2572 != current_level))
2542 { 2573 {
2543 bpa_give_up:
2544 /* We've marched all the way to the end of this 2574 /* We've marched all the way to the end of this
2545 isolating run sequence, and didn't find matching 2575 isolating run sequence, and didn't find matching
2546 closing brackets for some opening brackets. Leave 2576 closing brackets for some opening brackets. Leave
2547 their type unchanged. */ 2577 their type unchanged. */
2578 pairing_pos = bidi_it->charpos;
2548 break; 2579 break;
2549 } 2580 }
2550 if (bidi_it->type_after_wn == NEUTRAL_ON) /* Unicode 8.0 correction */ 2581 if (bidi_it->type_after_wn == NEUTRAL_ON) /* Unicode 8.0 correction */
@@ -2557,6 +2588,52 @@ bidi_find_bracket_pairs (struct bidi_it *bidi_it)
2557 resolution members set as determined by the above loop. */ 2588 resolution members set as determined by the above loop. */
2558 type = bidi_cache_find (saved_it.charpos, 0, bidi_it); 2589 type = bidi_cache_find (saved_it.charpos, 0, bidi_it);
2559 eassert (type == NEUTRAL_ON); 2590 eassert (type == NEUTRAL_ON);
2591
2592 /* The following is an optimization for bracketed text that has
2593 only one level which is equal to the paragraph's base
2594 embedding level. That is, only L2R and weak/neutral
2595 characters in a L2R paragraph, or only R2L and weak/neutral
2596 characters in a R2L paragraph. Such brackets can be resolved
2597 by bidi_resolve_neutral, which has a further shortcut for
2598 this case. So we pretend we did not resolve the brackets in
2599 this case, set up next_for_neutral for the entire bracketed
2600 text, and reset the cache to the character before the opening
2601 bracket. The upshot is to allow bidi_move_to_visually_next
2602 reset the cache when it returns this opening bracket, thus
2603 cutting significantly on the size of the cache, which is
2604 important with long lines, especially if word-wrap is non-nil
2605 (which requires the display engine to copy the cache back and
2606 forth many times). */
2607 if (maxlevel == base_level
2608 && ((base_level == 0 && !r2l_seen)
2609 || (base_level == 1 && !l2r_seen)))
2610 {
2611 if (retval)
2612 pairing_pos = bidi_it->bracket_pairing_pos;
2613
2614 /* This special value (which cannot possibly happen when
2615 brackets are resolved, since there's no character at ZV)
2616 will be noticed by bidi_resolve_explicit, and will be
2617 copied to the following iterator states, instead of being
2618 reset to -1. */
2619 bidi_it->bracket_pairing_pos = ZV;
2620 /* This type value will be used for resolving the outermost
2621 closing bracket in bidi_resolve_brackets. */
2622 bidi_it->bracket_enclosed_type = embedding_type;
2623 /* bidi_cache_last_idx is set to the index of the current
2624 state, because we just called bidi_cache_find above.
2625 Force the cache to "forget" all the cached states
2626 starting from the one corresponding to the outermost
2627 opening bracket, which is what the current state
2628 describes. */
2629 bidi_cache_reset_to (bidi_cache_last_idx);
2630 /* Set up the next_for_neutral member, to help
2631 bidi_resolve_neutral. */
2632 bidi_it->next_for_neutral.type = embedding_type;
2633 bidi_it->next_for_neutral.charpos = pairing_pos;
2634 /* Pretend we didn't resolve this bracket. */
2635 retval = false;
2636 }
2560 } 2637 }
2561 2638
2562 return retval; 2639 return retval;
@@ -2614,10 +2691,27 @@ bidi_resolve_brackets (struct bidi_it *bidi_it)
2614 if (type == UNKNOWN_BT) 2691 if (type == UNKNOWN_BT)
2615 { 2692 {
2616 type = bidi_resolve_weak (bidi_it); 2693 type = bidi_resolve_weak (bidi_it);
2617 if (type == NEUTRAL_ON && bidi_find_bracket_pairs (bidi_it)) 2694 if (type == NEUTRAL_ON)
2618 resolve_bracket = true; 2695 {
2696 /* bracket_pairing_pos == ZV means this bracket does not
2697 need to be resolved as a bracket, but as a neutral, see
2698 the optimization trick we play near the end of
2699 bidi_find_bracket_pairs. */
2700 if (bidi_it->bracket_pairing_pos == ZV)
2701 {
2702 /* If this is the outermost closing bracket of a run of
2703 characters in which we decided to resolve brackets as
2704 neutrals, use the embedding level's type, recorded in
2705 bracket_enclosed_type, to resolve the bracket. */
2706 if (bidi_it->next_for_neutral.charpos == bidi_it->charpos
2707 && bidi_paired_bracket_type (bidi_it->ch) == BIDI_BRACKET_CLOSE)
2708 type = bidi_it->bracket_enclosed_type;
2709 }
2710 else if (bidi_find_bracket_pairs (bidi_it))
2711 resolve_bracket = true;
2712 }
2619 } 2713 }
2620 else 2714 else if (bidi_it->bracket_pairing_pos != ZV)
2621 { 2715 {
2622 eassert (bidi_it->resolved_level == -1); 2716 eassert (bidi_it->resolved_level == -1);
2623 /* If the cached state shows an increase of embedding level due 2717 /* If the cached state shows an increase of embedding level due