From 595eddd848740bc132ae2bbdf630876114364f98 Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Sun, 18 Jul 2021 17:27:23 +0300 Subject: [PATCH] Fix display of mode-line with bidi formatting controls * src/xdisp.c (face_before_or_after_it_pos): Reimplement the bidi iteration to find the character after the current in visual order. (Bug#49562) --- src/xdisp.c | 66 ++++++++++++++++++++++++++--------------------------- 1 file changed, 32 insertions(+), 34 deletions(-) diff --git a/src/xdisp.c b/src/xdisp.c index 8f4dfa5430c..50ab2f8e051 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -4557,11 +4557,13 @@ face_before_or_after_it_pos (struct it *it, bool before_p) ptrdiff_t bufpos, charpos; int base_face_id; - /* No face change past the end of the string (for the case - we are padding with spaces). No face change before the - string start. */ + /* No face change past the end of the string (for the case we + are padding with spaces). No face change before the string + start. Ignore face changes before the first visible + character on this display line. */ if (IT_STRING_CHARPOS (*it) >= SCHARS (it->string) - || (IT_STRING_CHARPOS (*it) == 0 && before_p)) + || (IT_STRING_CHARPOS (*it) == 0 && before_p) + || it->current_x <= it->first_visible_x) return it->face_id; if (!it->bidi_p) @@ -4580,51 +4582,47 @@ face_before_or_after_it_pos (struct it *it, bool before_p) } else { - if (before_p) - { - /* With bidi iteration, the character before the current - in the visual order cannot be found by simple - iteration, because "reverse" reordering is not - supported. Instead, we need to start from the string - beginning and go all the way to the current string - position, remembering the previous position. */ - /* Ignore face changes before the first visible - character on this display line. */ - if (it->current_x <= it->first_visible_x) - return it->face_id; - SAVE_IT (it_copy, *it, it_copy_data); - IT_STRING_CHARPOS (it_copy) = 0; - bidi_init_it (0, 0, FRAME_WINDOW_P (it_copy.f), &it_copy.bidi_it); + /* With bidi iteration, the character before the current in + the visual order cannot be found by simple iteration, + because "reverse" reordering is not supported. Instead, + we need to start from the string beginning and go all the + way to the current string position, remembering the + visually-previous position. We need to start from the + string beginning for the character after the current as + well, since the iterator state in IT may have been + pushed, and the bidi cache is no longer coherent with the + string's text. */ + SAVE_IT (it_copy, *it, it_copy_data); + IT_STRING_CHARPOS (it_copy) = 0; + bidi_init_it (0, 0, FRAME_WINDOW_P (it_copy.f), &it_copy.bidi_it); - do - { - charpos = IT_STRING_CHARPOS (it_copy); - if (charpos >= SCHARS (it->string)) - break; - bidi_move_to_visually_next (&it_copy.bidi_it); - } - while (IT_STRING_CHARPOS (it_copy) != IT_STRING_CHARPOS (*it)); - - RESTORE_IT (it, it, it_copy_data); + do + { + charpos = it_copy.bidi_it.charpos; + if (charpos >= SCHARS (it->string)) + break; + bidi_move_to_visually_next (&it_copy.bidi_it); } - else + while (it_copy.bidi_it.charpos != IT_STRING_CHARPOS (*it)); + + if (!before_p) { /* Set charpos to the string position of the character that comes after IT's current position in the visual order. */ int n = (it->what == IT_COMPOSITION ? it->cmp_it.nchars : 1); - - it_copy = *it; - /* If this is the first display element, + /* If this is the first string character, bidi_move_to_visually_next will deliver character at current position without moving, so we need to enlarge N. */ - if (it->bidi_it.first_elt) + if (it_copy.bidi_it.first_elt) n++; while (n--) bidi_move_to_visually_next (&it_copy.bidi_it); charpos = it_copy.bidi_it.charpos; } + + RESTORE_IT (it, it, it_copy_data); } eassert (0 <= charpos && charpos <= SCHARS (it->string)); -- 2.39.2