From f3014ef5b24ac42ec714b48148b7b604b47f7468 Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Fri, 1 Jul 2011 13:53:29 +0300 Subject: [PATCH] Support bidi reordering of unibyte strings. Fix crash displaying "All" in mode line of an empty buffer. src/dispextern.h (struct bidi_string_data): New member `unibyte'. src/xdisp.c (handle_single_display_spec, next_overlay_string) (get_overlay_strings_1, reseat_1, reseat_to_string) (push_display_prop): Set up the `unibyte' member of bidi_it.string correctly. Don't assume unibyte strings are not bidi-reordered. (compute_display_string_pos) (compute_display_string_end): Fix handling the case of C string. src/bidi.c (bidi_count_bytes, bidi_char_at_pos): Accept an additional argument UNIBYTE, and support unibyte strings. All callers changed. (bidi_fetch_char): Support unibyte strings. --- src/ChangeLog | 16 +++++++++ src/bidi.c | 87 ++++++++++++++++++++++++++++++++++-------------- src/dispextern.h | 1 + src/xdisp.c | 70 +++++++++++++------------------------- 4 files changed, 102 insertions(+), 72 deletions(-) diff --git a/src/ChangeLog b/src/ChangeLog index 8d5275f9702..8cb94b3ff22 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,19 @@ +2011-07-01 Eli Zaretskii + + * dispextern.h (struct bidi_string_data): New member `unibyte'. + + * xdisp.c (handle_single_display_spec, next_overlay_string) + (get_overlay_strings_1, reseat_1, reseat_to_string) + (push_display_prop): Set up the `unibyte' member of bidi_it.string + correctly. Don't assume unibyte strings are not bidi-reordered. + (compute_display_string_pos) + (compute_display_string_end): Fix handling the case of C string. + + * bidi.c (bidi_count_bytes, bidi_char_at_pos): Accept an + additional argument UNIBYTE, and support unibyte strings. All + callers changed. + (bidi_fetch_char): Support unibyte strings. + 2011-06-25 Eli Zaretskii * xdisp.c (set_iterator_to_next, get_visually_first_element): Use diff --git a/src/bidi.c b/src/bidi.c index 5c9239d60f0..87978058a5b 100644 --- a/src/bidi.c +++ b/src/bidi.c @@ -721,23 +721,29 @@ bidi_line_init (struct bidi_it *bidi_it) Fetching characters ***********************************************************************/ -/* Count bytes in multibyte string S between BEG/BEGBYTE and END. BEG - and END are zero-based character positions in S, BEGBYTE is byte - position corresponding to BEG. */ +/* Count bytes in string S between BEG/BEGBYTE and END. BEG and END + are zero-based character positions in S, BEGBYTE is byte position + corresponding to BEG. UNIBYTE, if non-zero, means S is a unibyte + string. */ static inline EMACS_INT bidi_count_bytes (const unsigned char *s, const EMACS_INT beg, - const EMACS_INT begbyte, const EMACS_INT end) + const EMACS_INT begbyte, const EMACS_INT end, int unibyte) { EMACS_INT pos = beg; const unsigned char *p = s + begbyte, *start = p; - if (!CHAR_HEAD_P (*p)) - abort (); - - while (pos < end) + if (unibyte) + p = s + end; + else { - p += BYTES_BY_CHAR_HEAD (*p); - pos++; + if (!CHAR_HEAD_P (*p)) + abort (); + + while (pos < end) + { + p += BYTES_BY_CHAR_HEAD (*p); + pos++; + } } return p - start; @@ -745,12 +751,18 @@ bidi_count_bytes (const unsigned char *s, const EMACS_INT beg, /* Fetch and returns the character at byte position BYTEPOS. If S is non-NULL, fetch the character from string S; otherwise fetch the - character from the current buffer. */ + character from the current buffer. UNIBYTE non-zero means S is a + unibyte string. */ static inline int -bidi_char_at_pos (EMACS_INT bytepos, const unsigned char *s) +bidi_char_at_pos (EMACS_INT bytepos, const unsigned char *s, int unibyte) { if (s) - return STRING_CHAR (s + bytepos); + { + if (unibyte) + return s[bytepos]; + else + return STRING_CHAR (s + bytepos); + } else return FETCH_MULTIBYTE_CHAR (bytepos); } @@ -804,12 +816,14 @@ bidi_fetch_char (EMACS_INT bytepos, EMACS_INT charpos, EMACS_INT *disp_pos, ch = 0xFFFC; disp_end_pos = compute_display_string_end (*disp_pos, string); *nchars = disp_end_pos - *disp_pos; + if (*nchars <= 0) + abort (); if (string->s) *ch_len = bidi_count_bytes (string->s, *disp_pos, bytepos, - disp_end_pos); + disp_end_pos, string->unibyte); else if (STRINGP (string->lstring)) *ch_len = bidi_count_bytes (SDATA (string->lstring), *disp_pos, - bytepos, disp_end_pos); + bytepos, disp_end_pos, string->unibyte); else *ch_len = CHAR_TO_BYTE (disp_end_pos) - bytepos; } @@ -819,15 +833,32 @@ bidi_fetch_char (EMACS_INT bytepos, EMACS_INT charpos, EMACS_INT *disp_pos, { EMACS_INT len; - ch = STRING_CHAR_AND_LENGTH (string->s + bytepos, len); - *ch_len = len; + if (!string->unibyte) + { + ch = STRING_CHAR_AND_LENGTH (string->s + bytepos, len); + *ch_len = len; + } + else + { + ch = UNIBYTE_TO_CHAR (string->s[bytepos]); + *ch_len = 1; + } } else if (STRINGP (string->lstring)) { EMACS_INT len; - ch = STRING_CHAR_AND_LENGTH (SDATA (string->lstring) + bytepos, len); - *ch_len = len; + if (!string->unibyte) + { + ch = STRING_CHAR_AND_LENGTH (SDATA (string->lstring) + bytepos, + len); + *ch_len = len; + } + else + { + ch = UNIBYTE_TO_CHAR (SREF (string->lstring, bytepos)); + *ch_len = 1; + } } else { @@ -971,7 +1002,8 @@ bidi_paragraph_init (bidi_dir_t dir, struct bidi_it *bidi_it, int no_default_p) pos = bidi_it->charpos; s = STRINGP (bidi_it->string.lstring) ? SDATA (bidi_it->string.lstring) : bidi_it->string.s; - if (bytepos > begbyte && bidi_char_at_pos (bytepos, s) == '\n') + if (bytepos > begbyte + && bidi_char_at_pos (bytepos, s, bidi_it->string.unibyte) == '\n') { bytepos++; pos++; @@ -1123,7 +1155,8 @@ bidi_resolve_explicit_1 (struct bidi_it *bidi_it) if (bidi_it->charpos < 0) bidi_it->charpos = 0; - bidi_it->bytepos = bidi_count_bytes (p, 0, 0, bidi_it->charpos); + bidi_it->bytepos = bidi_count_bytes (p, 0, 0, bidi_it->charpos, + bidi_it->string.unibyte); } else { @@ -1308,7 +1341,8 @@ bidi_resolve_explicit (struct bidi_it *bidi_it) && bidi_it->ignore_bn_limit == -1 /* only if not already known */ && bidi_it->charpos < eob /* not already at EOB */ && bidi_explicit_dir_char (bidi_char_at_pos (bidi_it->bytepos - + bidi_it->ch_len, s))) + + bidi_it->ch_len, s, + bidi_it->string.unibyte))) { /* Avoid pushing and popping embedding levels if the level run is empty, as this breaks level runs where it shouldn't. @@ -1321,7 +1355,8 @@ bidi_resolve_explicit (struct bidi_it *bidi_it) bidi_copy_it (&saved_it, bidi_it); while (bidi_explicit_dir_char (bidi_char_at_pos (bidi_it->bytepos - + bidi_it->ch_len, s))) + + bidi_it->ch_len, s, + bidi_it->string.unibyte))) { /* This advances to the next character, skipping any characters covered by display strings. */ @@ -1459,7 +1494,8 @@ bidi_resolve_weak (struct bidi_it *bidi_it) next_char = bidi_it->charpos + bidi_it->nchars >= eob ? BIDI_EOB - : bidi_char_at_pos (bidi_it->bytepos + bidi_it->ch_len, s); + : bidi_char_at_pos (bidi_it->bytepos + bidi_it->ch_len, s, + bidi_it->string.unibyte); type_of_next = bidi_get_type (next_char, override); if (type_of_next == WEAK_BN @@ -1517,7 +1553,8 @@ bidi_resolve_weak (struct bidi_it *bidi_it) next_char = bidi_it->charpos + bidi_it->nchars >= eob ? BIDI_EOB - : bidi_char_at_pos (bidi_it->bytepos + bidi_it->ch_len, s); + : bidi_char_at_pos (bidi_it->bytepos + bidi_it->ch_len, s, + bidi_it->string.unibyte); type_of_next = bidi_get_type (next_char, override); if (type_of_next == WEAK_ET diff --git a/src/dispextern.h b/src/dispextern.h index 16fa3abdd19..9586edab63b 100644 --- a/src/dispextern.h +++ b/src/dispextern.h @@ -1821,6 +1821,7 @@ struct bidi_string_data { EMACS_INT bufpos; /* buffer position of lstring, or 0 if N/A */ unsigned from_disp_str : 1; /* 1 means the string comes from a display property */ + unsigned unibyte : 1; /* 1 means the string is unibyte */ }; /* Data type for reordering bidirectional text. */ diff --git a/src/xdisp.c b/src/xdisp.c index 3b934547471..43913eb886e 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -3113,8 +3113,9 @@ compute_display_string_pos (struct text_pos *position, Lisp_Object object = (string && STRINGP (string->lstring)) ? string->lstring : Qnil; Lisp_Object pos, spec; - EMACS_INT eob = STRINGP (object) ? string->schars : ZV; - EMACS_INT begb = STRINGP (object) ? 0 : BEGV; + int string_p = (string && (STRINGP (string->lstring) || string->s)); + EMACS_INT eob = string_p ? string->schars : ZV; + EMACS_INT begb = string_p ? 0 : BEGV; EMACS_INT bufpos, charpos = CHARPOS (*position); struct text_pos tpos; @@ -3175,7 +3176,8 @@ compute_display_string_end (EMACS_INT charpos, struct bidi_string_data *string) Lisp_Object object = (string && STRINGP (string->lstring)) ? string->lstring : Qnil; Lisp_Object pos = make_number (charpos); - EMACS_INT eob = STRINGP (object) ? string->schars : ZV; + EMACS_INT eob = + (STRINGP (object) || (string && string->s)) ? string->schars : ZV; if (charpos >= eob || (string->s && !STRINGP (object))) return eob; @@ -4496,19 +4498,6 @@ handle_single_display_spec (struct it *it, Lisp_Object spec, Lisp_Object object, it->paragraph_embedding = (it->bidi_p ? it->bidi_it.paragraph_dir : L2R); - /* Do we need to reorder this display string? */ - if (it->multibyte_p) - { - if (BUFFERP (object)) - it->bidi_p = - !NILP (BVAR (XBUFFER (object), bidi_display_reordering)); - else - it->bidi_p = - !NILP (BVAR (&buffer_defaults, bidi_display_reordering)); - } - else - it->bidi_p = 0; - /* Set up the bidi iterator for this display string. */ if (it->bidi_p) { @@ -4517,6 +4506,7 @@ handle_single_display_spec (struct it *it, Lisp_Object spec, Lisp_Object object, it->bidi_it.string.schars = it->end_charpos; it->bidi_it.string.bufpos = bufpos; it->bidi_it.string.from_disp_str = 1; + it->bidi_it.string.unibyte = !it->multibyte_p; bidi_init_it (0, 0, FRAME_WINDOW_P (it->f), &it->bidi_it); } } @@ -4873,11 +4863,6 @@ next_overlay_string (struct it *it) it->prev_stop = 0; it->base_level_stop = 0; - /* Do we need to reorder this overlay string? */ - it->bidi_p = - it->multibyte_p - && !NILP (BVAR (current_buffer, bidi_display_reordering)); - /* Set up the bidi iterator for this overlay string. */ if (it->bidi_p) { @@ -4886,6 +4871,7 @@ next_overlay_string (struct it *it) it->bidi_it.string.schars = SCHARS (it->string); it->bidi_it.string.bufpos = it->overlay_strings_charpos; it->bidi_it.string.from_disp_str = it->string_from_display_prop_p; + it->bidi_it.string.unibyte = !it->multibyte_p; bidi_init_it (0, 0, FRAME_WINDOW_P (it->f), &it->bidi_it); } } @@ -5159,11 +5145,6 @@ get_overlay_strings_1 (struct it *it, EMACS_INT charpos, int compute_stop_p) it->multibyte_p = STRING_MULTIBYTE (it->string); it->method = GET_FROM_STRING; - /* Do we need to reorder this overlay string? */ - it->bidi_p = - it->multibyte_p - && !NILP (BVAR (current_buffer, bidi_display_reordering)); - /* Force paragraph direction to be that of the parent buffer. */ it->paragraph_embedding = (it->bidi_p ? it->bidi_it.paragraph_dir : L2R); @@ -5178,6 +5159,7 @@ get_overlay_strings_1 (struct it *it, EMACS_INT charpos, int compute_stop_p) it->bidi_it.string.schars = SCHARS (it->string); it->bidi_it.string.bufpos = pos; it->bidi_it.string.from_disp_str = it->string_from_display_prop_p; + it->bidi_it.string.unibyte = !it->multibyte_p; bidi_init_it (0, 0, FRAME_WINDOW_P (it->f), &it->bidi_it); } return 1; @@ -5747,6 +5729,7 @@ reseat_1 (struct it *it, struct text_pos pos, int set_stop_p) it->bidi_it.string.s = NULL; it->bidi_it.string.lstring = Qnil; it->bidi_it.string.bufpos = 0; + it->bidi_it.string.unibyte = 0; } if (set_stop_p) @@ -5799,9 +5782,7 @@ reseat_to_string (struct it *it, const char *s, Lisp_Object string, /* Bidirectional reordering of strings is controlled by the default value of bidi-display-reordering. */ - it->bidi_p = - !NILP (BVAR (&buffer_defaults, bidi_display_reordering)) - && it->multibyte_p; + it->bidi_p = !NILP (BVAR (&buffer_defaults, bidi_display_reordering)); if (s == NULL) { @@ -5819,6 +5800,7 @@ reseat_to_string (struct it *it, const char *s, Lisp_Object string, it->bidi_it.string.schars = it->end_charpos; it->bidi_it.string.bufpos = 0; it->bidi_it.string.from_disp_str = 0; + it->bidi_it.string.unibyte = !it->multibyte_p; bidi_init_it (charpos, IT_STRING_BYTEPOS (*it), FRAME_WINDOW_P (it->f), &it->bidi_it); } @@ -5835,25 +5817,24 @@ reseat_to_string (struct it *it, const char *s, Lisp_Object string, { it->current.pos = c_string_pos (charpos, s, 1); it->end_charpos = it->string_nchars = number_of_chars (s, 1); - - if (it->bidi_p) - { - it->bidi_it.string.lstring = Qnil; - it->bidi_it.string.s = s; - it->bidi_it.string.schars = it->end_charpos; - it->bidi_it.string.bufpos = 0; - it->bidi_it.string.from_disp_str = 0; - bidi_init_it (charpos, IT_BYTEPOS (*it), FRAME_WINDOW_P (it->f), - &it->bidi_it); - } } else { - /* Unibyte (a.k.a. ASCII) C strings are never bidi-reordered. */ IT_CHARPOS (*it) = IT_BYTEPOS (*it) = charpos; it->end_charpos = it->string_nchars = strlen (s); } + if (it->bidi_p) + { + it->bidi_it.string.lstring = Qnil; + it->bidi_it.string.s = s; + it->bidi_it.string.schars = it->end_charpos; + it->bidi_it.string.bufpos = 0; + it->bidi_it.string.from_disp_str = 0; + it->bidi_it.string.unibyte = !it->multibyte_p; + bidi_init_it (charpos, IT_BYTEPOS (*it), FRAME_WINDOW_P (it->f), + &it->bidi_it); + } it->method = GET_FROM_C_STRING; } @@ -17788,12 +17769,6 @@ push_display_prop (struct it *it, Lisp_Object prop) buffer. */ it->paragraph_embedding = (it->bidi_p ? it->bidi_it.paragraph_dir : L2R); - /* Do we need to reorder this string? */ - if (it->multibyte_p) - it->bidi_p = !NILP (BVAR (current_buffer, bidi_display_reordering)); - else - it->bidi_p = 0; - /* Set up the bidi iterator for this display string. */ if (it->bidi_p) { @@ -17802,6 +17777,7 @@ push_display_prop (struct it *it, Lisp_Object prop) it->bidi_it.string.schars = it->end_charpos; it->bidi_it.string.bufpos = IT_CHARPOS (*it); it->bidi_it.string.from_disp_str = 1; + it->bidi_it.string.unibyte = !it->multibyte_p; bidi_init_it (0, 0, FRAME_WINDOW_P (it->f), &it->bidi_it); } } -- 2.39.5