aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorEli Zaretskii2011-06-08 21:01:56 +0300
committerEli Zaretskii2011-06-08 21:01:56 +0300
commit87e67904f15fda542426c9159c95a19142aecbad (patch)
treee5ccb1ee1fdb9e135f2f8a7f3e09a382cdd2beef /src
parent9d68c2a9abaddbed86a1b2f166625c93e8f88326 (diff)
downloademacs-87e67904f15fda542426c9159c95a19142aecbad.tar.gz
emacs-87e67904f15fda542426c9159c95a19142aecbad.zip
Started work on string reordering. Just compiled, not yet tested.
src/bidi.c (bidi_paragraph_info): Delete unused struct. (bidi_cache_idx, bidi_cache_last_idx): Declare EMACS_INT. (bidi_cache_start): New variable. (bidi_cache_reset): Reset bidi_cache_idx to bidi_cache_start, not to zero. (bidi_cache_fetch_state, bidi_cache_search) (bidi_cache_find_level_change, bidi_cache_iterator_state) (bidi_cache_find, bidi_peek_at_next_level) (bidi_level_of_next_char, bidi_find_other_level_edge) (bidi_move_to_visually_next): Compare cache index with bidi_cache_start rather than with zero. (bidi_fetch_char): Accept new argument STRING; all callers changed. Support iteration over a string. (bidi_paragraph_init, bidi_resolve_explicit_1) (bidi_resolve_explicit, bidi_resolve_weak) (bidi_level_of_next_char, bidi_move_to_visually_next): Support iteration over a string. (bidi_set_sor_type, bidi_resolve_explicit_1) (bidi_resolve_explicit, bidi_type_of_next_char): ignore_bn_limit can now be zero (for strings); special values 0 and -1 were changed to -1 and -2, respectively. (bidi_char_at_pos): New function. (bidi_paragraph_init, bidi_resolve_explicit, bidi_resolve_weak): Call it instead of FETCH_MULTIBYTE_CHAR. (bidi_move_to_visually_next): Abort if charpos or bytepos were not initialized to valid values. (bidi_init_it): Don't initialize charpos and bytepos with invalid values. src/xdisp.c (compute_display_string_pos) (compute_display_string_end): Accept additional argument STRING. (init_iterator, reseat_1): Initialize bidi_it->string.s to NULL. (reseat_to_string): Initialize bidi_it->string.s and bidi_it->string.schars. src/dispextern.h (struct bidi_string_data): New structure. (struct bidi_it): New member `string'. Make flag members be 1-bit fields, and put them last in the struct. (compute_display_string_pos, compute_display_string_end): Update prototypes.
Diffstat (limited to 'src')
-rw-r--r--src/ChangeLog43
-rw-r--r--src/bidi.c328
-rw-r--r--src/dispextern.h24
-rw-r--r--src/xdisp.c39
4 files changed, 312 insertions, 122 deletions
diff --git a/src/ChangeLog b/src/ChangeLog
index 63353b31d4d..c303839b14d 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,3 +1,46 @@
12011-06-08 Eli Zaretskii <eliz@gnu.org>
2
3 * bidi.c (bidi_paragraph_info): Delete unused struct.
4 (bidi_cache_idx, bidi_cache_last_idx): Declare EMACS_INT.
5 (bidi_cache_start): New variable.
6 (bidi_cache_reset): Reset bidi_cache_idx to bidi_cache_start, not
7 to zero.
8 (bidi_cache_fetch_state, bidi_cache_search)
9 (bidi_cache_find_level_change, bidi_cache_iterator_state)
10 (bidi_cache_find, bidi_peek_at_next_level)
11 (bidi_level_of_next_char, bidi_find_other_level_edge)
12 (bidi_move_to_visually_next): Compare cache index with
13 bidi_cache_start rather than with zero.
14 (bidi_fetch_char): Accept new argument STRING; all callers
15 changed. Support iteration over a string.
16 (bidi_paragraph_init, bidi_resolve_explicit_1)
17 (bidi_resolve_explicit, bidi_resolve_weak)
18 (bidi_level_of_next_char, bidi_move_to_visually_next): Support
19 iteration over a string.
20 (bidi_set_sor_type, bidi_resolve_explicit_1)
21 (bidi_resolve_explicit, bidi_type_of_next_char): ignore_bn_limit
22 can now be zero (for strings); special values 0 and -1 were
23 changed to -1 and -2, respectively.
24 (bidi_char_at_pos): New function.
25 (bidi_paragraph_init, bidi_resolve_explicit, bidi_resolve_weak):
26 Call it instead of FETCH_MULTIBYTE_CHAR.
27 (bidi_move_to_visually_next): Abort if charpos or bytepos were not
28 initialized to valid values.
29 (bidi_init_it): Don't initialize charpos and bytepos with invalid
30 values.
31
32 * xdisp.c (compute_display_string_pos)
33 (compute_display_string_end): Accept additional argument STRING.
34 (init_iterator, reseat_1): Initialize bidi_it->string.s to NULL.
35 (reseat_to_string): Initialize bidi_it->string.s and
36 bidi_it->string.schars.
37
38 * dispextern.h (struct bidi_string_data): New structure.
39 (struct bidi_it): New member `string'. Make flag members be 1-bit
40 fields, and put them last in the struct.
41 (compute_display_string_pos, compute_display_string_end): Update
42 prototypes.
43
12011-06-04 Eli Zaretskii <eliz@gnu.org> 442011-06-04 Eli Zaretskii <eliz@gnu.org>
2 45
3 * bidi.c (bidi_level_of_next_char): clen should be EMACS_NT, not int. 46 * bidi.c (bidi_level_of_next_char): clen should be EMACS_NT, not int.
diff --git a/src/bidi.c b/src/bidi.c
index ccf21827fc1..ac950a9000a 100644
--- a/src/bidi.c
+++ b/src/bidi.c
@@ -66,16 +66,6 @@ static Lisp_Object bidi_type_table, bidi_mirror_table;
66#define RLM_CHAR 0x200F 66#define RLM_CHAR 0x200F
67#define BIDI_EOB -1 67#define BIDI_EOB -1
68 68
69/* Local data structures. (Look in dispextern.h for the rest.) */
70
71/* What we need to know about the current paragraph. */
72struct bidi_paragraph_info {
73 EMACS_INT start_bytepos; /* byte position where it begins */
74 EMACS_INT end_bytepos; /* byte position where it ends */
75 int embedding_level; /* its basic embedding level */
76 bidi_dir_t base_dir; /* its base direction */
77};
78
79/* Data type for describing the bidirectional character categories. */ 69/* Data type for describing the bidirectional character categories. */
80typedef enum { 70typedef enum {
81 UNKNOWN_BC, 71 UNKNOWN_BC,
@@ -265,16 +255,28 @@ bidi_copy_it (struct bidi_it *to, struct bidi_it *from)
265static struct bidi_it *bidi_cache; 255static struct bidi_it *bidi_cache;
266static size_t bidi_cache_size = 0; 256static size_t bidi_cache_size = 0;
267static size_t elsz = sizeof (struct bidi_it); 257static size_t elsz = sizeof (struct bidi_it);
268static int bidi_cache_idx; /* next unused cache slot */ 258static EMACS_INT bidi_cache_idx; /* next unused cache slot */
269static int bidi_cache_last_idx; /* slot of last cache hit */ 259static EMACS_INT bidi_cache_last_idx; /* slot of last cache hit */
270 260static EMACS_INT bidi_cache_start = 0; /* start of cache for this
261 "stack" level */
262
263/* Reset the cache state to the empty state. We only reset the part
264 of the cache relevant to iteration of the current object. Previous
265 objects, which are pushed on the display iterator's stack, are left
266 intact. This is called when the cached information is no more
267 useful for the current iteration, e.g. when we were reseated to a
268 new position on the same object. */
271static INLINE void 269static INLINE void
272bidi_cache_reset (void) 270bidi_cache_reset (void)
273{ 271{
274 bidi_cache_idx = 0; 272 bidi_cache_idx = bidi_cache_start;
275 bidi_cache_last_idx = -1; 273 bidi_cache_last_idx = -1;
276} 274}
277 275
276/* Shrink the cache to its minimal size. Called when we init the bidi
277 iterator for reordering a buffer or a string that does not come
278 from display properties, because that means all the previously
279 cached info is of no further use. */
278static INLINE void 280static INLINE void
279bidi_cache_shrink (void) 281bidi_cache_shrink (void)
280{ 282{
@@ -292,7 +294,7 @@ bidi_cache_fetch_state (int idx, struct bidi_it *bidi_it)
292{ 294{
293 int current_scan_dir = bidi_it->scan_dir; 295 int current_scan_dir = bidi_it->scan_dir;
294 296
295 if (idx < 0 || idx >= bidi_cache_idx) 297 if (idx < bidi_cache_start || idx >= bidi_cache_idx)
296 abort (); 298 abort ();
297 299
298 bidi_copy_it (bidi_it, &bidi_cache[idx]); 300 bidi_copy_it (bidi_it, &bidi_cache[idx]);
@@ -333,7 +335,7 @@ bidi_cache_search (EMACS_INT charpos, int level, int dir)
333 if (dir < 0) 335 if (dir < 0)
334 { 336 {
335 /* Linear search for now; FIXME! */ 337 /* Linear search for now; FIXME! */
336 for (i = i_start; i >= 0; i--) 338 for (i = i_start; i >= bidi_cache_start; i--)
337 if (bidi_cache[i].charpos <= charpos 339 if (bidi_cache[i].charpos <= charpos
338 && charpos < bidi_cache[i].charpos + bidi_cache[i].nchars 340 && charpos < bidi_cache[i].charpos + bidi_cache[i].nchars
339 && (level == -1 || bidi_cache[i].resolved_level <= level)) 341 && (level == -1 || bidi_cache[i].resolved_level <= level))
@@ -355,8 +357,9 @@ bidi_cache_search (EMACS_INT charpos, int level, int dir)
355/* Find a cached state where the resolved level changes to a value 357/* Find a cached state where the resolved level changes to a value
356 that is lower than LEVEL, and return its cache slot index. DIR is 358 that is lower than LEVEL, and return its cache slot index. DIR is
357 the direction to search, starting with the last used cache slot. 359 the direction to search, starting with the last used cache slot.
358 BEFORE, if non-zero, means return the index of the slot that is 360 If DIR is zero, we search backwards from the last occupied cache
359 ``before'' the level change in the search direction. That is, 361 slot. BEFORE, if non-zero, means return the index of the slot that
362 is ``before'' the level change in the search direction. That is,
360 given the cached levels like this: 363 given the cached levels like this:
361 364
362 1122333442211 365 1122333442211
@@ -381,7 +384,7 @@ bidi_cache_find_level_change (int level, int dir, int before)
381 384
382 if (dir < 0) 385 if (dir < 0)
383 { 386 {
384 while (i >= incr) 387 while (i >= bidi_cache_start + incr)
385 { 388 {
386 if (bidi_cache[i - incr].resolved_level >= 0 389 if (bidi_cache[i - incr].resolved_level >= 0
387 && bidi_cache[i - incr].resolved_level < level) 390 && bidi_cache[i - incr].resolved_level < level)
@@ -427,13 +430,13 @@ bidi_cache_iterator_state (struct bidi_it *bidi_it, int resolved)
427 /* Character positions should correspond to cache positions 1:1. 430 /* Character positions should correspond to cache positions 1:1.
428 If we are outside the range of cached positions, the cache is 431 If we are outside the range of cached positions, the cache is
429 useless and must be reset. */ 432 useless and must be reset. */
430 if (idx > 0 && 433 if (idx > bidi_cache_start &&
431 (bidi_it->charpos > (bidi_cache[idx - 1].charpos 434 (bidi_it->charpos > (bidi_cache[idx - 1].charpos
432 + bidi_cache[idx - 1].nchars) 435 + bidi_cache[idx - 1].nchars)
433 || bidi_it->charpos < bidi_cache[0].charpos)) 436 || bidi_it->charpos < bidi_cache[0].charpos))
434 { 437 {
435 bidi_cache_reset (); 438 bidi_cache_reset ();
436 idx = 0; 439 idx = bidi_cache_start;
437 } 440 }
438 if (bidi_it->nchars <= 0) 441 if (bidi_it->nchars <= 0)
439 abort (); 442 abort ();
@@ -470,7 +473,7 @@ bidi_cache_find (EMACS_INT charpos, int level, struct bidi_it *bidi_it)
470{ 473{
471 int i = bidi_cache_search (charpos, level, bidi_it->scan_dir); 474 int i = bidi_cache_search (charpos, level, bidi_it->scan_dir);
472 475
473 if (i >= 0) 476 if (i >= bidi_cache_start)
474 { 477 {
475 bidi_dir_t current_scan_dir = bidi_it->scan_dir; 478 bidi_dir_t current_scan_dir = bidi_it->scan_dir;
476 479
@@ -488,7 +491,7 @@ bidi_cache_find (EMACS_INT charpos, int level, struct bidi_it *bidi_it)
488static INLINE int 491static INLINE int
489bidi_peek_at_next_level (struct bidi_it *bidi_it) 492bidi_peek_at_next_level (struct bidi_it *bidi_it)
490{ 493{
491 if (bidi_cache_idx == 0 || bidi_cache_last_idx == -1) 494 if (bidi_cache_idx == bidi_cache_start || bidi_cache_last_idx == -1)
492 abort (); 495 abort ();
493 return bidi_cache[bidi_cache_last_idx + bidi_it->scan_dir].resolved_level; 496 return bidi_cache[bidi_cache_last_idx + bidi_it->scan_dir].resolved_level;
494} 497}
@@ -550,7 +553,7 @@ bidi_set_sor_type (struct bidi_it *bidi_it, int level_before, int level_after)
550 bidi_it->prev_for_neutral.bytepos = bidi_it->bytepos; 553 bidi_it->prev_for_neutral.bytepos = bidi_it->bytepos;
551 bidi_it->next_for_neutral.type = bidi_it->next_for_neutral.type_after_w1 = 554 bidi_it->next_for_neutral.type = bidi_it->next_for_neutral.type_after_w1 =
552 bidi_it->next_for_neutral.orig_type = UNKNOWN_BT; 555 bidi_it->next_for_neutral.orig_type = UNKNOWN_BT;
553 bidi_it->ignore_bn_limit = 0; /* meaning it's unknown */ 556 bidi_it->ignore_bn_limit = -1; /* meaning it's unknown */
554} 557}
555 558
556/* Perform initializations for reordering a new line of bidi text. */ 559/* Perform initializations for reordering a new line of bidi text. */
@@ -571,6 +574,40 @@ bidi_line_init (struct bidi_it *bidi_it)
571 bidi_cache_reset (); 574 bidi_cache_reset ();
572} 575}
573 576
577/* Count bytes in multibyte string S between BEG/BEGBYTE and END. BEG
578 and END are zero-based character positions in S, BEGBYTE is byte
579 position corresponding to BEG. */
580static inline EMACS_INT
581bidi_count_bytes (const unsigned char *s, const EMACS_INT beg,
582 const EMACS_INT begbyte, const EMACS_INT end)
583{
584 EMACS_INT pos = beg;
585 const unsigned char *p = s + begbyte, *start = p;
586
587 if (!CHAR_HEAD_P (*p))
588 abort ();
589
590 while (pos < end)
591 {
592 p += BYTES_BY_CHAR_HEAD (*p);
593 pos++;
594 }
595
596 return p - start;
597}
598
599/* Fetch and returns the character at byte position BYTEPOS. If S is
600 non-NULL, fetch the character from string S; otherwise fetch the
601 character from the current buffer. */
602static inline int
603bidi_char_at_pos (EMACS_INT bytepos, const unsigned char *s)
604{
605 if (s)
606 return STRING_CHAR (s + bytepos);
607 else
608 return FETCH_MULTIBYTE_CHAR (bytepos);
609}
610
574/* Fetch and return the character at BYTEPOS/CHARPOS. If that 611/* Fetch and return the character at BYTEPOS/CHARPOS. If that
575 character is covered by a display string, treat the entire run of 612 character is covered by a display string, treat the entire run of
576 covered characters as a single character u+FFFC, and return their 613 covered characters as a single character u+FFFC, and return their
@@ -578,26 +615,28 @@ bidi_line_init (struct bidi_it *bidi_it)
578 character position of the next display string, or -1 if not yet 615 character position of the next display string, or -1 if not yet
579 computed. When the next character is at or beyond that position, 616 computed. When the next character is at or beyond that position,
580 the function updates DISP_POS with the position of the next display 617 the function updates DISP_POS with the position of the next display
581 string. */ 618 string. STRING->s is the string to iterate, or NULL if iterating over
582static INLINE int 619 a buffer. */
620static inline int
583bidi_fetch_char (EMACS_INT bytepos, EMACS_INT charpos, EMACS_INT *disp_pos, 621bidi_fetch_char (EMACS_INT bytepos, EMACS_INT charpos, EMACS_INT *disp_pos,
622 struct bidi_string_data *string,
584 int frame_window_p, EMACS_INT *ch_len, EMACS_INT *nchars) 623 int frame_window_p, EMACS_INT *ch_len, EMACS_INT *nchars)
585{ 624{
586 int ch; 625 int ch;
626 EMACS_INT endpos = string->s ? string->schars : ZV;
587 627
588 /* FIXME: Support strings in addition to buffers. */
589 /* If we got past the last known position of display string, compute 628 /* If we got past the last known position of display string, compute
590 the position of the next one. That position could be at BYTEPOS. */ 629 the position of the next one. That position could be at CHARPOS. */
591 if (charpos < ZV && charpos > *disp_pos) 630 if (charpos < endpos && charpos > *disp_pos)
592 *disp_pos = compute_display_string_pos (charpos, frame_window_p); 631 *disp_pos = compute_display_string_pos (charpos, string, frame_window_p);
593 632
594 /* Fetch the character at BYTEPOS. */ 633 /* Fetch the character at BYTEPOS. */
595 if (bytepos >= ZV_BYTE) 634 if (charpos >= endpos)
596 { 635 {
597 ch = BIDI_EOB; 636 ch = BIDI_EOB;
598 *ch_len = 1; 637 *ch_len = 1;
599 *nchars = 1; 638 *nchars = 1;
600 *disp_pos = ZV; 639 *disp_pos = endpos;
601 } 640 }
602 else if (charpos >= *disp_pos) 641 else if (charpos >= *disp_pos)
603 { 642 {
@@ -608,24 +647,38 @@ bidi_fetch_char (EMACS_INT bytepos, EMACS_INT charpos, EMACS_INT *disp_pos,
608 if (charpos > *disp_pos) 647 if (charpos > *disp_pos)
609 abort (); 648 abort ();
610 /* Return the Unicode Object Replacement Character to represent 649 /* Return the Unicode Object Replacement Character to represent
611 the entire run of characters covered by the display 650 the entire run of characters covered by the display string. */
612 string. */
613 ch = 0xFFFC; 651 ch = 0xFFFC;
614 disp_end_pos = compute_display_string_end (*disp_pos); 652 disp_end_pos = compute_display_string_end (*disp_pos, string);
615 *nchars = disp_end_pos - *disp_pos; 653 *nchars = disp_end_pos - *disp_pos;
616 *ch_len = CHAR_TO_BYTE (disp_end_pos) - bytepos; 654 if (string->s)
655 *ch_len = bidi_count_bytes (string->s, *disp_pos, bytepos,
656 disp_end_pos);
657 else
658 *ch_len = CHAR_TO_BYTE (disp_end_pos) - bytepos;
617 } 659 }
618 else 660 else
619 { 661 {
620 ch = FETCH_MULTIBYTE_CHAR (bytepos); 662 if (string->s)
663 {
664 EMACS_INT len;
665
666 ch = STRING_CHAR_AND_LENGTH (string->s + bytepos, len);
667 *ch_len = len;
668 }
669 else
670 {
671 ch = FETCH_MULTIBYTE_CHAR (bytepos);
672 *ch_len = CHAR_BYTES (ch);
673 }
621 *nchars = 1; 674 *nchars = 1;
622 *ch_len = CHAR_BYTES (ch);
623 } 675 }
624 676
625 /* If we just entered a run of characters covered by a display 677 /* If we just entered a run of characters covered by a display
626 string, compute the position of the next display string. */ 678 string, compute the position of the next display string. */
627 if (charpos + *nchars <= ZV && charpos + *nchars > *disp_pos) 679 if (charpos + *nchars <= endpos && charpos + *nchars > *disp_pos)
628 *disp_pos = compute_display_string_pos (charpos + *nchars, frame_window_p); 680 *disp_pos = compute_display_string_pos (charpos + *nchars, string,
681 frame_window_p);
629 682
630 return ch; 683 return ch;
631} 684}
@@ -670,13 +723,19 @@ void
670bidi_paragraph_init (bidi_dir_t dir, struct bidi_it *bidi_it, int no_default_p) 723bidi_paragraph_init (bidi_dir_t dir, struct bidi_it *bidi_it, int no_default_p)
671{ 724{
672 EMACS_INT bytepos = bidi_it->bytepos; 725 EMACS_INT bytepos = bidi_it->bytepos;
726 int string_p = bidi_it->string.s != NULL;
673 EMACS_INT pstartbyte; 727 EMACS_INT pstartbyte;
728 /* Note that begbyte is a byte position, while end is a character
729 position. Yes, this is ugly, but we are trying to avoid costly
730 calls to BYTE_TO_CHAR and its ilk. */
731 EMACS_INT begbyte = string_p ? 0 : BEGV_BYTE;
732 EMACS_INT end = string_p ? bidi_it->string.schars : ZV;
674 733
675 /* Special case for an empty buffer. */ 734 /* Special case for an empty buffer. */
676 if (bytepos == BEGV_BYTE && bytepos == ZV_BYTE) 735 if (bytepos == begbyte && bidi_it->charpos == end)
677 dir = L2R; 736 dir = L2R;
678 /* We should never be called at EOB or before BEGV. */ 737 /* We should never be called at EOB or before BEGV. */
679 else if (bytepos >= ZV_BYTE || bytepos < BEGV_BYTE) 738 else if (bidi_it->charpos >= end || bytepos < begbyte)
680 abort (); 739 abort ();
681 740
682 if (dir == L2R) 741 if (dir == L2R)
@@ -712,7 +771,8 @@ bidi_paragraph_init (bidi_dir_t dir, struct bidi_it *bidi_it, int no_default_p)
712 we are potentially in a new paragraph that doesn't yet 771 we are potentially in a new paragraph that doesn't yet
713 exist. */ 772 exist. */
714 pos = bidi_it->charpos; 773 pos = bidi_it->charpos;
715 if (bytepos > BEGV_BYTE && FETCH_CHAR (bytepos) == '\n') 774 if (bytepos > begbyte
775 && bidi_char_at_pos (bytepos, bidi_it->string.s) == '\n')
716 { 776 {
717 bytepos++; 777 bytepos++;
718 pos++; 778 pos++;
@@ -720,17 +780,25 @@ bidi_paragraph_init (bidi_dir_t dir, struct bidi_it *bidi_it, int no_default_p)
720 780
721 /* We are either at the beginning of a paragraph or in the 781 /* We are either at the beginning of a paragraph or in the
722 middle of it. Find where this paragraph starts. */ 782 middle of it. Find where this paragraph starts. */
723 pstartbyte = bidi_find_paragraph_start (pos, bytepos); 783 if (string_p)
784 {
785 /* We don't support changes of paragraph direction inside a
786 string. It is treated as a single paragraph. */
787 pstartbyte = 0;
788 }
789 else
790 pstartbyte = bidi_find_paragraph_start (pos, bytepos);
724 bidi_it->separator_limit = -1; 791 bidi_it->separator_limit = -1;
725 bidi_it->new_paragraph = 0; 792 bidi_it->new_paragraph = 0;
726 793
727 /* The following loop is run more than once only if NO_DEFAULT_P 794 /* The following loop is run more than once only if NO_DEFAULT_P
728 is non-zero. */ 795 is non-zero, and only if we are iterating on a buffer. */
729 do { 796 do {
730 bytepos = pstartbyte; 797 bytepos = pstartbyte;
731 pos = BYTE_TO_CHAR (bytepos); 798 if (!string_p)
732 ch = bidi_fetch_char (bytepos, pos, &disp_pos, bidi_it->frame_window_p, 799 pos = BYTE_TO_CHAR (bytepos);
733 &ch_len, &nchars); 800 ch = bidi_fetch_char (bytepos, pos, &disp_pos, &bidi_it->string,
801 bidi_it->frame_window_p, &ch_len, &nchars);
734 type = bidi_get_type (ch, NEUTRAL_DIR); 802 type = bidi_get_type (ch, NEUTRAL_DIR);
735 803
736 for (pos += nchars, bytepos += ch_len; 804 for (pos += nchars, bytepos += ch_len;
@@ -744,17 +812,19 @@ bidi_paragraph_init (bidi_dir_t dir, struct bidi_it *bidi_it, int no_default_p)
744 || type == LRE || type == LRO)); 812 || type == LRE || type == LRO));
745 type = bidi_get_type (ch, NEUTRAL_DIR)) 813 type = bidi_get_type (ch, NEUTRAL_DIR))
746 { 814 {
747 if (type == NEUTRAL_B && bidi_at_paragraph_end (pos, bytepos) >= -1) 815 if (!string_p
816 && type == NEUTRAL_B
817 && bidi_at_paragraph_end (pos, bytepos) >= -1)
748 break; 818 break;
749 if (bytepos >= ZV_BYTE) 819 if (pos >= end)
750 { 820 {
751 /* Pretend there's a paragraph separator at end of 821 /* Pretend there's a paragraph separator at end of
752 buffer. */ 822 buffer/string. */
753 type = NEUTRAL_B; 823 type = NEUTRAL_B;
754 break; 824 break;
755 } 825 }
756 /* Fetch next character and advance to get past it. */ 826 /* Fetch next character and advance to get past it. */
757 ch = bidi_fetch_char (bytepos, pos, &disp_pos, 827 ch = bidi_fetch_char (bytepos, pos, &disp_pos, &bidi_it->string,
758 bidi_it->frame_window_p, &ch_len, &nchars); 828 bidi_it->frame_window_p, &ch_len, &nchars);
759 pos += nchars; 829 pos += nchars;
760 bytepos += ch_len; 830 bytepos += ch_len;
@@ -763,7 +833,8 @@ bidi_paragraph_init (bidi_dir_t dir, struct bidi_it *bidi_it, int no_default_p)
763 bidi_it->paragraph_dir = R2L; 833 bidi_it->paragraph_dir = R2L;
764 else if (type == STRONG_L) 834 else if (type == STRONG_L)
765 bidi_it->paragraph_dir = L2R; 835 bidi_it->paragraph_dir = L2R;
766 if (no_default_p && bidi_it->paragraph_dir == NEUTRAL_DIR) 836 if (!string_p
837 && no_default_p && bidi_it->paragraph_dir == NEUTRAL_DIR)
767 { 838 {
768 /* If this paragraph is at BEGV, default to L2R. */ 839 /* If this paragraph is at BEGV, default to L2R. */
769 if (pstartbyte == BEGV_BYTE) 840 if (pstartbyte == BEGV_BYTE)
@@ -786,7 +857,8 @@ bidi_paragraph_init (bidi_dir_t dir, struct bidi_it *bidi_it, int no_default_p)
786 pstartbyte = prevpbyte; 857 pstartbyte = prevpbyte;
787 } 858 }
788 } 859 }
789 } while (no_default_p && bidi_it->paragraph_dir == NEUTRAL_DIR); 860 } while (!string_p
861 && no_default_p && bidi_it->paragraph_dir == NEUTRAL_DIR);
790 } 862 }
791 else 863 else
792 abort (); 864 abort ();
@@ -822,8 +894,10 @@ bidi_init_it (EMACS_INT charpos, EMACS_INT bytepos, int frame_window_p,
822{ 894{
823 if (! bidi_initialized) 895 if (! bidi_initialized)
824 bidi_initialize (); 896 bidi_initialize ();
825 bidi_it->charpos = charpos; 897 if (charpos >= 0)
826 bidi_it->bytepos = bytepos; 898 bidi_it->charpos = charpos;
899 if (bytepos >= 0)
900 bidi_it->bytepos = bytepos;
827 bidi_it->frame_window_p = frame_window_p; 901 bidi_it->frame_window_p = frame_window_p;
828 bidi_it->nchars = -1; /* to be computed in bidi_resolve_explicit_1 */ 902 bidi_it->nchars = -1; /* to be computed in bidi_resolve_explicit_1 */
829 bidi_it->first_elt = 1; 903 bidi_it->first_elt = 1;
@@ -848,7 +922,10 @@ bidi_init_it (EMACS_INT charpos, EMACS_INT bytepos, int frame_window_p,
848 bidi_it->prev_for_neutral.orig_type = UNKNOWN_BT; 922 bidi_it->prev_for_neutral.orig_type = UNKNOWN_BT;
849 bidi_it->sor = L2R; /* FIXME: should it be user-selectable? */ 923 bidi_it->sor = L2R; /* FIXME: should it be user-selectable? */
850 bidi_it->disp_pos = -1; /* invalid/unknown */ 924 bidi_it->disp_pos = -1; /* invalid/unknown */
851 bidi_cache_shrink (); 925 /* We can only shrink the cache if we are at the bottom level of its
926 "stack". */
927 if (bidi_cache_start == 0)
928 bidi_cache_shrink ();
852} 929}
853 930
854/* Push the current embedding level and override status; reset the 931/* Push the current embedding level and override status; reset the
@@ -934,19 +1011,31 @@ bidi_resolve_explicit_1 (struct bidi_it *bidi_it)
934 int current_level; 1011 int current_level;
935 int new_level; 1012 int new_level;
936 bidi_dir_t override; 1013 bidi_dir_t override;
1014 int string_p = bidi_it->string.s != NULL;
937 1015
938 /* If reseat()'ed, don't advance, so as to start iteration from the 1016 /* If reseat()'ed, don't advance, so as to start iteration from the
939 position where we were reseated. bidi_it->bytepos can be less 1017 position where we were reseated. bidi_it->bytepos can be less
940 than BEGV_BYTE after reseat to BEGV. */ 1018 than BEGV_BYTE after reseat to BEGV. */
941 if (bidi_it->bytepos < BEGV_BYTE 1019 if (bidi_it->bytepos < (string_p ? 0 : BEGV_BYTE)
942 || bidi_it->first_elt) 1020 || bidi_it->first_elt)
943 { 1021 {
944 bidi_it->first_elt = 0; 1022 bidi_it->first_elt = 0;
945 if (bidi_it->charpos < BEGV) 1023 if (string_p)
946 bidi_it->charpos = BEGV; 1024 {
947 bidi_it->bytepos = CHAR_TO_BYTE (bidi_it->charpos); 1025 if (bidi_it->charpos < 0)
1026 bidi_it->charpos = 0;
1027 bidi_it->bytepos = bidi_count_bytes (bidi_it->string.s, 0, 0,
1028 bidi_it->charpos);
1029 }
1030 else
1031 {
1032 if (bidi_it->charpos < BEGV)
1033 bidi_it->charpos = BEGV;
1034 bidi_it->bytepos = CHAR_TO_BYTE (bidi_it->charpos);
1035 }
948 } 1036 }
949 else if (bidi_it->bytepos < ZV_BYTE) /* don't move at ZV */ 1037 /* Don't move at end of buffer/string. */
1038 else if (bidi_it->charpos < (string_p ? bidi_it->string.schars : ZV))
950 { 1039 {
951 /* Advance to the next character, skipping characters covered by 1040 /* Advance to the next character, skipping characters covered by
952 display strings (nchars > 1). */ 1041 display strings (nchars > 1). */
@@ -962,12 +1051,12 @@ bidi_resolve_explicit_1 (struct bidi_it *bidi_it)
962 override = bidi_it->level_stack[bidi_it->stack_idx].override; 1051 override = bidi_it->level_stack[bidi_it->stack_idx].override;
963 new_level = current_level; 1052 new_level = current_level;
964 1053
965 if (bidi_it->bytepos >= ZV_BYTE) 1054 if (bidi_it->charpos >= (string_p ? bidi_it->string.schars : ZV))
966 { 1055 {
967 curchar = BIDI_EOB; 1056 curchar = BIDI_EOB;
968 bidi_it->ch_len = 1; 1057 bidi_it->ch_len = 1;
969 bidi_it->nchars = 1; 1058 bidi_it->nchars = 1;
970 bidi_it->disp_pos = ZV; 1059 bidi_it->disp_pos = (string_p ? bidi_it->string.schars : ZV);
971 } 1060 }
972 else 1061 else
973 { 1062 {
@@ -975,7 +1064,8 @@ bidi_resolve_explicit_1 (struct bidi_it *bidi_it)
975 display string, treat the entire run of covered characters as 1064 display string, treat the entire run of covered characters as
976 a single character u+FFFC. */ 1065 a single character u+FFFC. */
977 curchar = bidi_fetch_char (bidi_it->bytepos, bidi_it->charpos, 1066 curchar = bidi_fetch_char (bidi_it->bytepos, bidi_it->charpos,
978 &bidi_it->disp_pos, bidi_it->frame_window_p, 1067 &bidi_it->disp_pos, &bidi_it->string,
1068 bidi_it->frame_window_p,
979 &bidi_it->ch_len, &bidi_it->nchars); 1069 &bidi_it->ch_len, &bidi_it->nchars);
980 } 1070 }
981 bidi_it->ch = curchar; 1071 bidi_it->ch = curchar;
@@ -1000,7 +1090,7 @@ bidi_resolve_explicit_1 (struct bidi_it *bidi_it)
1000 bidi_it->type_after_w1 = type; 1090 bidi_it->type_after_w1 = type;
1001 bidi_check_type (bidi_it->type_after_w1); 1091 bidi_check_type (bidi_it->type_after_w1);
1002 type = WEAK_BN; /* X9/Retaining */ 1092 type = WEAK_BN; /* X9/Retaining */
1003 if (bidi_it->ignore_bn_limit <= 0) 1093 if (bidi_it->ignore_bn_limit <= -1)
1004 { 1094 {
1005 if (current_level <= BIDI_MAXLEVEL - 4) 1095 if (current_level <= BIDI_MAXLEVEL - 4)
1006 { 1096 {
@@ -1033,7 +1123,7 @@ bidi_resolve_explicit_1 (struct bidi_it *bidi_it)
1033 bidi_it->type_after_w1 = type; 1123 bidi_it->type_after_w1 = type;
1034 bidi_check_type (bidi_it->type_after_w1); 1124 bidi_check_type (bidi_it->type_after_w1);
1035 type = WEAK_BN; /* X9/Retaining */ 1125 type = WEAK_BN; /* X9/Retaining */
1036 if (bidi_it->ignore_bn_limit <= 0) 1126 if (bidi_it->ignore_bn_limit <= -1)
1037 { 1127 {
1038 if (current_level <= BIDI_MAXLEVEL - 5) 1128 if (current_level <= BIDI_MAXLEVEL - 5)
1039 { 1129 {
@@ -1068,7 +1158,7 @@ bidi_resolve_explicit_1 (struct bidi_it *bidi_it)
1068 bidi_it->type_after_w1 = type; 1158 bidi_it->type_after_w1 = type;
1069 bidi_check_type (bidi_it->type_after_w1); 1159 bidi_check_type (bidi_it->type_after_w1);
1070 type = WEAK_BN; /* X9/Retaining */ 1160 type = WEAK_BN; /* X9/Retaining */
1071 if (bidi_it->ignore_bn_limit <= 0) 1161 if (bidi_it->ignore_bn_limit <= -1)
1072 { 1162 {
1073 if (!bidi_it->invalid_rl_levels) 1163 if (!bidi_it->invalid_rl_levels)
1074 { 1164 {
@@ -1111,13 +1201,15 @@ bidi_resolve_explicit (struct bidi_it *bidi_it)
1111{ 1201{
1112 int prev_level = bidi_it->level_stack[bidi_it->stack_idx].level; 1202 int prev_level = bidi_it->level_stack[bidi_it->stack_idx].level;
1113 int new_level = bidi_resolve_explicit_1 (bidi_it); 1203 int new_level = bidi_resolve_explicit_1 (bidi_it);
1204 EMACS_INT eob = bidi_it->string.s ? bidi_it->string.schars : ZV;
1114 1205
1115 if (prev_level < new_level 1206 if (prev_level < new_level
1116 && bidi_it->type == WEAK_BN 1207 && bidi_it->type == WEAK_BN
1117 && bidi_it->ignore_bn_limit == 0 /* only if not already known */ 1208 && bidi_it->ignore_bn_limit == -1 /* only if not already known */
1118 && bidi_it->bytepos < ZV_BYTE /* not already at EOB */ 1209 && bidi_it->charpos < eob /* not already at EOB */
1119 && bidi_explicit_dir_char (FETCH_MULTIBYTE_CHAR (bidi_it->bytepos 1210 && bidi_explicit_dir_char (bidi_char_at_pos (bidi_it->bytepos
1120 + bidi_it->ch_len))) 1211 + bidi_it->ch_len,
1212 bidi_it->string.s)))
1121 { 1213 {
1122 /* Avoid pushing and popping embedding levels if the level run 1214 /* Avoid pushing and popping embedding levels if the level run
1123 is empty, as this breaks level runs where it shouldn't. 1215 is empty, as this breaks level runs where it shouldn't.
@@ -1129,8 +1221,9 @@ bidi_resolve_explicit (struct bidi_it *bidi_it)
1129 1221
1130 bidi_copy_it (&saved_it, bidi_it); 1222 bidi_copy_it (&saved_it, bidi_it);
1131 1223
1132 while (bidi_explicit_dir_char (FETCH_MULTIBYTE_CHAR (bidi_it->bytepos 1224 while (bidi_explicit_dir_char (bidi_char_at_pos (bidi_it->bytepos
1133 + bidi_it->ch_len))) 1225 + bidi_it->ch_len,
1226 bidi_it->string.s)))
1134 { 1227 {
1135 /* This advances to the next character, skipping any 1228 /* This advances to the next character, skipping any
1136 characters covered by display strings. */ 1229 characters covered by display strings. */
@@ -1142,10 +1235,10 @@ bidi_resolve_explicit (struct bidi_it *bidi_it)
1142 if (level == prev_level) /* empty embedding */ 1235 if (level == prev_level) /* empty embedding */
1143 saved_it.ignore_bn_limit = bidi_it->charpos + bidi_it->nchars; 1236 saved_it.ignore_bn_limit = bidi_it->charpos + bidi_it->nchars;
1144 else /* this embedding is non-empty */ 1237 else /* this embedding is non-empty */
1145 saved_it.ignore_bn_limit = -1; 1238 saved_it.ignore_bn_limit = -2;
1146 1239
1147 bidi_copy_it (bidi_it, &saved_it); 1240 bidi_copy_it (bidi_it, &saved_it);
1148 if (bidi_it->ignore_bn_limit > 0) 1241 if (bidi_it->ignore_bn_limit > -1)
1149 { 1242 {
1150 /* We pushed a level, but we shouldn't have. Undo that. */ 1243 /* We pushed a level, but we shouldn't have. Undo that. */
1151 if (!bidi_it->invalid_rl_levels) 1244 if (!bidi_it->invalid_rl_levels)
@@ -1188,6 +1281,7 @@ bidi_resolve_weak (struct bidi_it *bidi_it)
1188 int next_char; 1281 int next_char;
1189 bidi_type_t type_of_next; 1282 bidi_type_t type_of_next;
1190 struct bidi_it saved_it; 1283 struct bidi_it saved_it;
1284 EMACS_INT eob = bidi_it->string.s ? bidi_it->string.schars : ZV;
1191 1285
1192 type = bidi_it->type; 1286 type = bidi_it->type;
1193 override = bidi_it->level_stack[bidi_it->stack_idx].override; 1287 override = bidi_it->level_stack[bidi_it->stack_idx].override;
@@ -1255,9 +1349,10 @@ bidi_resolve_weak (struct bidi_it *bidi_it)
1255 || bidi_it->prev.type_after_w1 == WEAK_AN))) 1349 || bidi_it->prev.type_after_w1 == WEAK_AN)))
1256 { 1350 {
1257 next_char = 1351 next_char =
1258 bidi_it->bytepos + bidi_it->ch_len >= ZV_BYTE 1352 bidi_it->charpos + bidi_it->nchars >= eob
1259 ? BIDI_EOB : FETCH_MULTIBYTE_CHAR (bidi_it->bytepos 1353 ? BIDI_EOB
1260 + bidi_it->ch_len); 1354 : bidi_char_at_pos (bidi_it->bytepos + bidi_it->ch_len,
1355 bidi_it->string.s);
1261 type_of_next = bidi_get_type (next_char, override); 1356 type_of_next = bidi_get_type (next_char, override);
1262 1357
1263 if (type_of_next == WEAK_BN 1358 if (type_of_next == WEAK_BN
@@ -1310,9 +1405,10 @@ bidi_resolve_weak (struct bidi_it *bidi_it)
1310 if (bidi_it->nchars <= 0) 1405 if (bidi_it->nchars <= 0)
1311 abort (); 1406 abort ();
1312 next_char = 1407 next_char =
1313 bidi_it->bytepos + bidi_it->ch_len >= ZV_BYTE 1408 bidi_it->charpos + bidi_it->nchars >= eob
1314 ? BIDI_EOB : FETCH_MULTIBYTE_CHAR (bidi_it->bytepos 1409 ? BIDI_EOB
1315 + bidi_it->ch_len); 1410 : bidi_char_at_pos (bidi_it->bytepos + bidi_it->ch_len,
1411 bidi_it->string.s);
1316 type_of_next = bidi_get_type (next_char, override); 1412 type_of_next = bidi_get_type (next_char, override);
1317 1413
1318 if (type_of_next == WEAK_ET 1414 if (type_of_next == WEAK_ET
@@ -1509,11 +1605,11 @@ bidi_type_of_next_char (struct bidi_it *bidi_it)
1509 1605
1510 /* Reset the limit until which to ignore BNs if we step out of the 1606 /* Reset the limit until which to ignore BNs if we step out of the
1511 area where we found only empty levels. */ 1607 area where we found only empty levels. */
1512 if ((bidi_it->ignore_bn_limit > 0 1608 if ((bidi_it->ignore_bn_limit > -1
1513 && bidi_it->ignore_bn_limit <= bidi_it->charpos) 1609 && bidi_it->ignore_bn_limit <= bidi_it->charpos)
1514 || (bidi_it->ignore_bn_limit == -1 1610 || (bidi_it->ignore_bn_limit == -2
1515 && !bidi_explicit_dir_char (bidi_it->ch))) 1611 && !bidi_explicit_dir_char (bidi_it->ch)))
1516 bidi_it->ignore_bn_limit = 0; 1612 bidi_it->ignore_bn_limit = -1;
1517 1613
1518 type = bidi_resolve_neutral (bidi_it); 1614 type = bidi_resolve_neutral (bidi_it);
1519 1615
@@ -1530,12 +1626,12 @@ bidi_level_of_next_char (struct bidi_it *bidi_it)
1530 bidi_type_t type; 1626 bidi_type_t type;
1531 int level, prev_level = -1; 1627 int level, prev_level = -1;
1532 struct bidi_saved_info next_for_neutral; 1628 struct bidi_saved_info next_for_neutral;
1533 EMACS_INT next_char_pos; 1629 EMACS_INT next_char_pos = -1;
1534 1630
1535 if (bidi_it->scan_dir == 1) 1631 if (bidi_it->scan_dir == 1)
1536 { 1632 {
1537 /* There's no sense in trying to advance if we hit end of text. */ 1633 /* There's no sense in trying to advance if we hit end of text. */
1538 if (bidi_it->bytepos >= ZV_BYTE) 1634 if (bidi_it->charpos >= (bidi_it->string.s ? bidi_it->string.schars : ZV))
1539 return bidi_it->resolved_level; 1635 return bidi_it->resolved_level;
1540 1636
1541 /* Record the info about the previous character. */ 1637 /* Record the info about the previous character. */
@@ -1575,7 +1671,7 @@ bidi_level_of_next_char (struct bidi_it *bidi_it)
1575 /* Perhaps the character we want is already cached. If it is, the 1671 /* Perhaps the character we want is already cached. If it is, the
1576 call to bidi_cache_find below will return a type other than 1672 call to bidi_cache_find below will return a type other than
1577 UNKNOWN_BT. */ 1673 UNKNOWN_BT. */
1578 if (bidi_cache_idx && !bidi_it->first_elt) 1674 if (bidi_cache_idx > bidi_cache_start && !bidi_it->first_elt)
1579 { 1675 {
1580 if (bidi_it->scan_dir > 0) 1676 if (bidi_it->scan_dir > 0)
1581 { 1677 {
@@ -1583,9 +1679,12 @@ bidi_level_of_next_char (struct bidi_it *bidi_it)
1583 abort (); 1679 abort ();
1584 next_char_pos = bidi_it->charpos + bidi_it->nchars; 1680 next_char_pos = bidi_it->charpos + bidi_it->nchars;
1585 } 1681 }
1586 else 1682 else if (bidi_it->charpos > (bidi_it->string.s ? 0 : 1))
1587 next_char_pos = bidi_it->charpos - 1; 1683 next_char_pos = bidi_it->charpos - 1;
1588 type = bidi_cache_find (next_char_pos, -1, bidi_it); 1684 if (next_char_pos >= 0)
1685 type = bidi_cache_find (next_char_pos, -1, bidi_it);
1686 else
1687 type = UNKNOWN_BT;
1589 } 1688 }
1590 else 1689 else
1591 type = UNKNOWN_BT; 1690 type = UNKNOWN_BT;
@@ -1652,13 +1751,14 @@ bidi_level_of_next_char (struct bidi_it *bidi_it)
1652 EMACS_INT cpos = bidi_it->charpos; 1751 EMACS_INT cpos = bidi_it->charpos;
1653 EMACS_INT disp_pos = bidi_it->disp_pos; 1752 EMACS_INT disp_pos = bidi_it->disp_pos;
1654 EMACS_INT nc = bidi_it->nchars; 1753 EMACS_INT nc = bidi_it->nchars;
1754 struct bidi_string_data bs = bidi_it->string;
1655 bidi_type_t chtype; 1755 bidi_type_t chtype;
1656 int fwp = bidi_it->frame_window_p; 1756 int fwp = bidi_it->frame_window_p;
1657 1757
1658 if (bidi_it->nchars <= 0) 1758 if (bidi_it->nchars <= 0)
1659 abort (); 1759 abort ();
1660 do { 1760 do {
1661 ch = bidi_fetch_char (bpos += clen, cpos += nc, &disp_pos, fwp, 1761 ch = bidi_fetch_char (bpos += clen, cpos += nc, &disp_pos, &bs, fwp,
1662 &clen, &nc); 1762 &clen, &nc);
1663 if (ch == '\n' || ch == BIDI_EOB /* || ch == LINESEP_CHAR */) 1763 if (ch == '\n' || ch == BIDI_EOB /* || ch == LINESEP_CHAR */)
1664 chtype = NEUTRAL_B; 1764 chtype = NEUTRAL_B;
@@ -1759,7 +1859,8 @@ bidi_find_other_level_edge (struct bidi_it *bidi_it, int level, int end_flag)
1759 int idx; 1859 int idx;
1760 1860
1761 /* Try the cache first. */ 1861 /* Try the cache first. */
1762 if ((idx = bidi_cache_find_level_change (level, dir, end_flag)) >= 0) 1862 if ((idx = bidi_cache_find_level_change (level, dir, end_flag))
1863 >= bidi_cache_start)
1763 bidi_cache_fetch_state (idx, bidi_it); 1864 bidi_cache_fetch_state (idx, bidi_it);
1764 else 1865 else
1765 { 1866 {
@@ -1782,6 +1883,9 @@ bidi_move_to_visually_next (struct bidi_it *bidi_it)
1782 int old_level, new_level, next_level; 1883 int old_level, new_level, next_level;
1783 struct bidi_it sentinel; 1884 struct bidi_it sentinel;
1784 1885
1886 if (bidi_it->charpos < 0 || bidi_it->bytepos < 0)
1887 abort ();
1888
1785 if (bidi_it->scan_dir == 0) 1889 if (bidi_it->scan_dir == 0)
1786 { 1890 {
1787 bidi_it->scan_dir = 1; /* default to logical order */ 1891 bidi_it->scan_dir = 1; /* default to logical order */
@@ -1794,7 +1898,7 @@ bidi_move_to_visually_next (struct bidi_it *bidi_it)
1794 /* Prepare the sentinel iterator state, and cache it. When we bump 1898 /* Prepare the sentinel iterator state, and cache it. When we bump
1795 into it, scanning backwards, we'll know that the last non-base 1899 into it, scanning backwards, we'll know that the last non-base
1796 level is exhausted. */ 1900 level is exhausted. */
1797 if (bidi_cache_idx == 0) 1901 if (bidi_cache_idx == bidi_cache_start)
1798 { 1902 {
1799 bidi_copy_it (&sentinel, bidi_it); 1903 bidi_copy_it (&sentinel, bidi_it);
1800 if (bidi_it->first_elt) 1904 if (bidi_it->first_elt)
@@ -1869,26 +1973,34 @@ bidi_move_to_visually_next (struct bidi_it *bidi_it)
1869 reordering, whereas we _must_ know the paragraph base direction 1973 reordering, whereas we _must_ know the paragraph base direction
1870 _before_ we process the paragraph's text, since the base 1974 _before_ we process the paragraph's text, since the base
1871 direction affects the reordering. */ 1975 direction affects the reordering. */
1872 if (bidi_it->scan_dir == 1 1976 if (bidi_it->scan_dir == 1 && bidi_it->orig_type == NEUTRAL_B)
1873 && bidi_it->orig_type == NEUTRAL_B
1874 && bidi_it->bytepos < ZV_BYTE)
1875 { 1977 {
1876 EMACS_INT sep_len = 1978 /* The paragraph direction of the entire string, once
1877 bidi_at_paragraph_end (bidi_it->charpos + bidi_it->nchars, 1979 determined, is in effect for the entire string. Setting the
1878 bidi_it->bytepos + bidi_it->ch_len); 1980 separator limit to the end of the string prevents
1879 if (bidi_it->nchars <= 0) 1981 bidi_paragraph_init from being called automatically on this
1880 abort (); 1982 string. */
1881 if (sep_len >= 0) 1983 if (bidi_it->string.s)
1984 bidi_it->separator_limit = bidi_it->string.schars;
1985 else if (bidi_it->bytepos < ZV_BYTE)
1882 { 1986 {
1883 bidi_it->new_paragraph = 1; 1987 EMACS_INT sep_len =
1884 /* Record the buffer position of the last character of the 1988 bidi_at_paragraph_end (bidi_it->charpos + bidi_it->nchars,
1885 paragraph separator. */ 1989 bidi_it->bytepos + bidi_it->ch_len);
1886 bidi_it->separator_limit = 1990 if (bidi_it->nchars <= 0)
1887 bidi_it->charpos + bidi_it->nchars + sep_len; 1991 abort ();
1992 if (sep_len >= 0)
1993 {
1994 bidi_it->new_paragraph = 1;
1995 /* Record the buffer position of the last character of the
1996 paragraph separator. */
1997 bidi_it->separator_limit =
1998 bidi_it->charpos + bidi_it->nchars + sep_len;
1999 }
1888 } 2000 }
1889 } 2001 }
1890 2002
1891 if (bidi_it->scan_dir == 1 && bidi_cache_idx) 2003 if (bidi_it->scan_dir == 1 && bidi_cache_idx > bidi_cache_start)
1892 { 2004 {
1893 /* If we are at paragraph's base embedding level and beyond the 2005 /* If we are at paragraph's base embedding level and beyond the
1894 last cached position, the cache's job is done and we can 2006 last cached position, the cache's job is done and we can
diff --git a/src/dispextern.h b/src/dispextern.h
index 7138c2225e8..0f7089d7916 100644
--- a/src/dispextern.h
+++ b/src/dispextern.h
@@ -1812,9 +1812,18 @@ struct bidi_stack {
1812 bidi_dir_t override; 1812 bidi_dir_t override;
1813}; 1813};
1814 1814
1815/* Data type for storing information about a string being iterated on. */
1816struct bidi_string_data {
1817 const unsigned char *s; /* the string, or NULL if reordering buffer */
1818 EMACS_INT schars; /* the number of characters in the string,
1819 excluding the terminating null */
1820 unsigned from_disp_str : 1; /* 1 means the string comes from a
1821 display property */
1822};
1823
1815/* Data type for reordering bidirectional text. */ 1824/* Data type for reordering bidirectional text. */
1816struct bidi_it { 1825struct bidi_it {
1817 EMACS_INT bytepos; /* iterator's position in buffer */ 1826 EMACS_INT bytepos; /* iterator's position in buffer/string */
1818 EMACS_INT charpos; 1827 EMACS_INT charpos;
1819 int ch; /* character at that position, or u+FFFC 1828 int ch; /* character at that position, or u+FFFC
1820 ("object replacement character") for a run 1829 ("object replacement character") for a run
@@ -1844,12 +1853,13 @@ struct bidi_it {
1844 iterator state is saved, pushed, or popped. So only put here 1853 iterator state is saved, pushed, or popped. So only put here
1845 stuff that is not part of the bidi iterator's state! */ 1854 stuff that is not part of the bidi iterator's state! */
1846 struct bidi_stack level_stack[BIDI_MAXLEVEL]; /* stack of embedding levels */ 1855 struct bidi_stack level_stack[BIDI_MAXLEVEL]; /* stack of embedding levels */
1847 int first_elt; /* if non-zero, examine current char first */ 1856 struct bidi_string_data string; /* string to reorder */
1848 bidi_dir_t paragraph_dir; /* current paragraph direction */ 1857 bidi_dir_t paragraph_dir; /* current paragraph direction */
1849 int new_paragraph; /* if non-zero, we expect a new paragraph */
1850 int frame_window_p; /* non-zero if displaying on a GUI frame */
1851 EMACS_INT separator_limit; /* where paragraph separator should end */ 1858 EMACS_INT separator_limit; /* where paragraph separator should end */
1852 EMACS_INT disp_pos; /* position of display string after ch */ 1859 EMACS_INT disp_pos; /* position of display string after ch */
1860 unsigned first_elt : 1; /* if non-zero, examine current char first */
1861 unsigned new_paragraph : 1; /* if non-zero, we expect a new paragraph */
1862 unsigned frame_window_p : 1; /* non-zero if displaying on a GUI frame */
1853}; 1863};
1854 1864
1855/* Value is non-zero when the bidi iterator is at base paragraph 1865/* Value is non-zero when the bidi iterator is at base paragraph
@@ -3007,8 +3017,10 @@ extern void reseat_at_previous_visible_line_start (struct it *);
3007extern Lisp_Object lookup_glyphless_char_display (int, struct it *); 3017extern Lisp_Object lookup_glyphless_char_display (int, struct it *);
3008extern int calc_pixel_width_or_height (double *, struct it *, Lisp_Object, 3018extern int calc_pixel_width_or_height (double *, struct it *, Lisp_Object,
3009 struct font *, int, int *); 3019 struct font *, int, int *);
3010extern EMACS_INT compute_display_string_pos (EMACS_INT, int); 3020extern EMACS_INT compute_display_string_pos (EMACS_INT,
3011extern EMACS_INT compute_display_string_end (EMACS_INT); 3021 struct bidi_string_data *, int);
3022extern EMACS_INT compute_display_string_end (EMACS_INT,
3023 struct bidi_string_data *);
3012 3024
3013#ifdef HAVE_WINDOW_SYSTEM 3025#ifdef HAVE_WINDOW_SYSTEM
3014 3026
diff --git a/src/xdisp.c b/src/xdisp.c
index 23667388b56..cd62989d994 100644
--- a/src/xdisp.c
+++ b/src/xdisp.c
@@ -2342,6 +2342,7 @@ init_iterator (struct it *it, struct window *w,
2342 it->base_face_id = remapped_base_face_id; 2342 it->base_face_id = remapped_base_face_id;
2343 it->string = Qnil; 2343 it->string = Qnil;
2344 IT_STRING_CHARPOS (*it) = IT_STRING_BYTEPOS (*it) = -1; 2344 IT_STRING_CHARPOS (*it) = IT_STRING_BYTEPOS (*it) = -1;
2345 it->bidi_it.string.s = NULL;
2345 2346
2346 /* The window in which we iterate over current_buffer: */ 2347 /* The window in which we iterate over current_buffer: */
2347 XSETWINDOW (it->window, w); 2348 XSETWINDOW (it->window, w);
@@ -3087,14 +3088,16 @@ next_overlay_change (EMACS_INT pos)
3087 return endpos; 3088 return endpos;
3088} 3089}
3089 3090
3090/* Return the character position of a display string at or after CHARPOS. 3091/* Return the character position of a display string at or after
3091 If no display string exists at or after CHARPOS, return ZV. A 3092 CHARPOS. If no display string exists at or after CHARPOS, return
3092 display string is either an overlay with `display' property whose 3093 ZV. A display string is either an overlay with `display' property
3093 value is a string, or a `display' text property whose value is a 3094 whose value is a string, or a `display' text property whose value
3094 string. FRAME_WINDOW_P is non-zero when we are displaying a window 3095 is a string. STRING is the string to iterate; if STRING->s is
3095 on a GUI frame. */ 3096 NULL, we are iterating a buffer. FRAME_WINDOW_P is non-zero when
3097 we are displaying a window on a GUI frame. */
3096EMACS_INT 3098EMACS_INT
3097compute_display_string_pos (EMACS_INT charpos, int frame_window_p) 3099compute_display_string_pos (EMACS_INT charpos, struct bidi_string_data *string,
3100 int frame_window_p)
3098{ 3101{
3099 /* FIXME: Support display properties on strings (object = Qnil means 3102 /* FIXME: Support display properties on strings (object = Qnil means
3100 current buffer). */ 3103 current buffer). */
@@ -3143,7 +3146,7 @@ compute_display_string_pos (EMACS_INT charpos, int frame_window_p)
3143 `display' property whose value is a string or a `display' text 3146 `display' property whose value is a string or a `display' text
3144 property whose value is a string. */ 3147 property whose value is a string. */
3145EMACS_INT 3148EMACS_INT
3146compute_display_string_end (EMACS_INT charpos) 3149compute_display_string_end (EMACS_INT charpos, struct bidi_string_data *string)
3147{ 3150{
3148 /* FIXME: Support display properties on strings (object = Qnil means 3151 /* FIXME: Support display properties on strings (object = Qnil means
3149 current buffer). */ 3152 current buffer). */
@@ -5482,6 +5485,7 @@ reseat_1 (struct it *it, struct text_pos pos, int set_stop_p)
5482 it->bidi_it.first_elt = 1; 5485 it->bidi_it.first_elt = 1;
5483 it->bidi_it.paragraph_dir = NEUTRAL_DIR; 5486 it->bidi_it.paragraph_dir = NEUTRAL_DIR;
5484 it->bidi_it.disp_pos = -1; 5487 it->bidi_it.disp_pos = -1;
5488 it->bidi_it.string.s = NULL;
5485 } 5489 }
5486 5490
5487 if (set_stop_p) 5491 if (set_stop_p)
@@ -5531,6 +5535,10 @@ reseat_to_string (struct it *it, const char *s, Lisp_Object string,
5531 setting of MULTIBYTE, if specified. */ 5535 setting of MULTIBYTE, if specified. */
5532 if (multibyte >= 0) 5536 if (multibyte >= 0)
5533 it->multibyte_p = multibyte > 0; 5537 it->multibyte_p = multibyte > 0;
5538#if 0
5539 it->bidi_p =
5540 it->multibyte_p && BVAR (&buffer_defaults, bidi_display_reordering);
5541#endif
5534 5542
5535 if (s == NULL) 5543 if (s == NULL)
5536 { 5544 {
@@ -5540,6 +5548,12 @@ reseat_to_string (struct it *it, const char *s, Lisp_Object string,
5540 it->end_charpos = it->string_nchars = SCHARS (string); 5548 it->end_charpos = it->string_nchars = SCHARS (string);
5541 it->method = GET_FROM_STRING; 5549 it->method = GET_FROM_STRING;
5542 it->current.string_pos = string_pos (charpos, string); 5550 it->current.string_pos = string_pos (charpos, string);
5551#if 0
5552 if (it->bidi_p)
5553 bidi_init_it ();
5554 it->bidi_it.string.s = SDATA (string);
5555 it->bidi_it.string.schars = it->end_charpos;
5556#endif
5543 } 5557 }
5544 else 5558 else
5545 { 5559 {
@@ -5553,11 +5567,20 @@ reseat_to_string (struct it *it, const char *s, Lisp_Object string,
5553 { 5567 {
5554 it->current.pos = c_string_pos (charpos, s, 1); 5568 it->current.pos = c_string_pos (charpos, s, 1);
5555 it->end_charpos = it->string_nchars = number_of_chars (s, 1); 5569 it->end_charpos = it->string_nchars = number_of_chars (s, 1);
5570#if 0
5571 if (it->bidi_p)
5572 bidi_init_it ();
5573 it->bidi_it.string.s = s;
5574 it->bidi_it.string.schars = it->end_charpos;
5575#endif
5556 } 5576 }
5557 else 5577 else
5558 { 5578 {
5559 IT_CHARPOS (*it) = IT_BYTEPOS (*it) = charpos; 5579 IT_CHARPOS (*it) = IT_BYTEPOS (*it) = charpos;
5560 it->end_charpos = it->string_nchars = strlen (s); 5580 it->end_charpos = it->string_nchars = strlen (s);
5581#if 0
5582 it->bidi_p = 0;
5583#endif
5561 } 5584 }
5562 5585
5563 it->method = GET_FROM_C_STRING; 5586 it->method = GET_FROM_C_STRING;