X-Git-Url: https://code.delx.au/gnu-emacs/blobdiff_plain/1ace72676cb6749c45c5dd6462457fc2cea2988c..8610fe8b84e22f5d962f5e480001748a6687a3b2:/src/xdisp.c diff --git a/src/xdisp.c b/src/xdisp.c index ea55cdcc3d..4ed08e72e1 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -258,7 +258,7 @@ along with GNU Emacs. If not, see . */ still left to right, i.e. the iterator "thinks" the first character is at the leftmost pixel position. The iterator does not know that PRODUCE_GLYPHS reverses the order of the glyphs that the iterator - delivers. This is important when functions from the the move_it_* + delivers. This is important when functions from the move_it_* family are used to get to certain screen position or to match screen coordinates with buffer coordinates: these functions use the iterator geometry, which is left to right even in R2L paragraphs. @@ -594,6 +594,29 @@ int current_mode_line_height, current_header_line_height; #define TEXT_PROP_DISTANCE_LIMIT 100 +/* SAVE_IT and RESTORE_IT are called when we save a snapshot of the + iterator state and later restore it. This is needed because the + bidi iterator on bidi.c keeps a stacked cache of its states, which + is really a singleton. When we use scratch iterator objects to + move around the buffer, we can cause the bidi cache to be pushed or + popped, and therefore we need to restore the cache state when we + return to the original iterator. */ +#define SAVE_IT(ITCOPY,ITORIG,CACHE) \ + do { \ + if (CACHE) \ + bidi_unshelve_cache (CACHE, 1); \ + ITCOPY = ITORIG; \ + CACHE = bidi_shelve_cache(); \ + } while (0) + +#define RESTORE_IT(pITORIG,pITCOPY,CACHE) \ + do { \ + if (pITORIG != pITCOPY) \ + *(pITORIG) = *(pITCOPY); \ + bidi_unshelve_cache (CACHE, 0); \ + CACHE = NULL; \ + } while (0) + #if GLYPH_DEBUG /* Non-zero means print traces of redisplay if compiled with @@ -814,7 +837,7 @@ static int cursor_row_fully_visible_p (struct window *, int, int); static int try_scrolling (Lisp_Object, int, EMACS_INT, EMACS_INT, int, int); static int try_cursor_movement (Lisp_Object, struct text_pos, int *); static int trailing_whitespace_p (EMACS_INT); -static unsigned long int message_log_check_duplicate (EMACS_INT, EMACS_INT); +static intmax_t message_log_check_duplicate (EMACS_INT, EMACS_INT); static void push_it (struct it *, struct text_pos *); static void pop_it (struct it *); static void sync_frame_with_window_matrix_rows (struct window *); @@ -876,7 +899,7 @@ static void init_to_row_start (struct it *, struct window *, static int init_to_row_end (struct it *, struct window *, struct glyph_row *); static void back_to_previous_line_start (struct it *); -static int forward_to_next_line_start (struct it *, int *); +static int forward_to_next_line_start (struct it *, int *, struct bidi_it *); static struct text_pos string_pos_nchars_ahead (struct text_pos, Lisp_Object, EMACS_INT); static struct text_pos string_pos (EMACS_INT, Lisp_Object); @@ -931,7 +954,7 @@ static int coords_in_mouse_face_p (struct window *, int, int); This is the height of W minus the height of a mode line, if any. */ -INLINE int +inline int window_text_bottom_y (struct window *w) { int height = WINDOW_TOTAL_HEIGHT (w); @@ -945,7 +968,7 @@ window_text_bottom_y (struct window *w) means return the total width of W, not including fringes to the left and right of the window. */ -INLINE int +inline int window_box_width (struct window *w, int area) { int cols = XFASTINT (w->total_cols); @@ -984,7 +1007,7 @@ window_box_width (struct window *w, int area) /* Return the pixel height of the display area of window W, not including mode lines of W, if any. */ -INLINE int +inline int window_box_height (struct window *w) { struct frame *f = XFRAME (w->frame); @@ -1031,7 +1054,7 @@ window_box_height (struct window *w) area AREA of window W. AREA < 0 means return the left edge of the whole window, to the right of the left fringe of W. */ -INLINE int +inline int window_box_left_offset (struct window *w, int area) { int x; @@ -1063,7 +1086,7 @@ window_box_left_offset (struct window *w, int area) area AREA of window W. AREA < 0 means return the right edge of the whole window, to the left of the right fringe of W. */ -INLINE int +inline int window_box_right_offset (struct window *w, int area) { return window_box_left_offset (w, area) + window_box_width (w, area); @@ -1073,7 +1096,7 @@ window_box_right_offset (struct window *w, int area) area AREA of window W. AREA < 0 means return the left edge of the whole window, to the right of the left fringe of W. */ -INLINE int +inline int window_box_left (struct window *w, int area) { struct frame *f = XFRAME (w->frame); @@ -1093,7 +1116,7 @@ window_box_left (struct window *w, int area) area AREA of window W. AREA < 0 means return the right edge of the whole window, to the left of the right fringe of W. */ -INLINE int +inline int window_box_right (struct window *w, int area) { return window_box_left (w, area) + window_box_width (w, area); @@ -1106,7 +1129,7 @@ window_box_right (struct window *w, int area) coordinates of the upper-left corner of the box. Return in *BOX_WIDTH, and *BOX_HEIGHT the pixel width and height of the box. */ -INLINE void +inline void window_box (struct window *w, int area, int *box_x, int *box_y, int *box_width, int *box_height) { @@ -1133,7 +1156,7 @@ window_box (struct window *w, int area, int *box_x, int *box_y, *BOTTOM_RIGHT_Y the coordinates of the bottom-right corner of the box. */ -static INLINE void +static inline void window_box_edges (struct window *w, int area, int *top_left_x, int *top_left_y, int *bottom_right_x, int *bottom_right_y) { @@ -1199,6 +1222,7 @@ pos_visible_p (struct window *w, EMACS_INT charpos, int *x, int *y, int *rtop, int *rbot, int *rowh, int *vpos) { struct it it; + void *itdata = bidi_shelve_cache (); struct text_pos top; int visible_p = 0; struct buffer *old_buffer = NULL; @@ -1229,13 +1253,21 @@ pos_visible_p (struct window *w, EMACS_INT charpos, int *x, int *y, move_it_to (&it, charpos, -1, it.last_visible_y-1, -1, (charpos >= 0 ? MOVE_TO_POS : 0) | MOVE_TO_Y); - if (charpos >= 0 && IT_CHARPOS (it) >= charpos) + if (charpos >= 0 + && (((!it.bidi_p || it.bidi_it.scan_dir == 1) + && IT_CHARPOS (it) >= charpos) + /* When scanning backwards under bidi iteration, move_it_to + stops at or _before_ CHARPOS, because it stops at or to + the _right_ of the character at CHARPOS. */ + || (it.bidi_p && it.bidi_it.scan_dir == -1 + && IT_CHARPOS (it) <= charpos))) { /* We have reached CHARPOS, or passed it. How the call to - move_it_to can overshoot: (i) If CHARPOS is on invisible - text, move_it_to stops at the end of the invisible text, - after CHARPOS. (ii) If CHARPOS is in a display vector, - move_it_to stops on its last glyph. */ + move_it_to can overshoot: (i) If CHARPOS is on invisible text + or covered by a display property, move_it_to stops at the end + of the invisible text, to the right of CHARPOS. (ii) If + CHARPOS is in a display vector, move_it_to stops on its last + glyph. */ int top_x = it.current_x; int top_y = it.current_y; enum it_method it_method = it.method; @@ -1284,15 +1316,18 @@ pos_visible_p (struct window *w, EMACS_INT charpos, int *x, int *y, } else { + /* We were asked to provide info about WINDOW_END. */ struct it it2; + void *it2data = NULL; - it2 = it; + SAVE_IT (it2, it, it2data); if (IT_CHARPOS (it) < ZV && FETCH_BYTE (IT_BYTEPOS (it)) != '\n') move_it_by_lines (&it, 1); if (charpos < IT_CHARPOS (it) || (it.what == IT_EOB && charpos == IT_CHARPOS (it))) { visible_p = 1; + RESTORE_IT (&it2, &it2, it2data); move_it_to (&it2, charpos, -1, -1, -1, MOVE_TO_POS); *x = it2.current_x; *y = it2.current_y + it2.max_ascent - it2.ascent; @@ -1305,7 +1340,10 @@ pos_visible_p (struct window *w, EMACS_INT charpos, int *x, int *y, WINDOW_HEADER_LINE_HEIGHT (w)))); *vpos = it2.vpos; } + else + bidi_unshelve_cache (it2data, 1); } + bidi_unshelve_cache (itdata, 0); if (old_buffer) set_buffer_internal_1 (old_buffer); @@ -1333,13 +1371,13 @@ pos_visible_p (struct window *w, EMACS_INT charpos, int *x, int *y, returns an invalid character. If we find one, we return a `?', but with the length of the invalid character. */ -static INLINE int +static inline int string_char_and_length (const unsigned char *str, int *len) { int c; c = STRING_CHAR_AND_LENGTH (str, *len); - if (!CHAR_VALID_P (c, 1)) + if (!CHAR_VALID_P (c)) /* We may not change the length here because other places in Emacs don't use this function, i.e. they silently accept invalid characters. */ @@ -1381,7 +1419,7 @@ string_pos_nchars_ahead (struct text_pos pos, Lisp_Object string, EMACS_INT ncha /* Value is the text position, i.e. character and byte position, for character position CHARPOS in STRING. */ -static INLINE struct text_pos +static inline struct text_pos string_pos (EMACS_INT charpos, Lisp_Object string) { struct text_pos pos; @@ -2142,7 +2180,7 @@ safe_eval_handler (Lisp_Object arg) redisplay during the evaluation. */ Lisp_Object -safe_call (size_t nargs, Lisp_Object *args) +safe_call (ptrdiff_t nargs, Lisp_Object *args) { Lisp_Object val; @@ -2213,8 +2251,7 @@ safe_call2 (Lisp_Object fn, Lisp_Object arg1, Lisp_Object arg2) This is for debugging. It is too slow to do unconditionally. */ static void -check_it (it) - struct it *it; +check_it (struct it *it) { if (it->method == GET_FROM_STRING) { @@ -2246,14 +2283,13 @@ check_it (it) #endif /* not 0 */ -#if GLYPH_DEBUG +#if GLYPH_DEBUG && XASSERTS /* Check that the window end of window W is what we expect it to be---the last row in the current matrix displaying text. */ static void -check_window_end (w) - struct window *w; +check_window_end (struct window *w) { if (!MINI_WINDOW_P (w) && !NILP (w->window_end_valid)) @@ -2269,11 +2305,11 @@ check_window_end (w) #define CHECK_WINDOW_END(W) check_window_end ((W)) -#else /* not GLYPH_DEBUG */ +#else #define CHECK_WINDOW_END(W) (void) 0 -#endif /* not GLYPH_DEBUG */ +#endif @@ -2393,7 +2429,7 @@ init_iterator (struct it *it, struct window *w, is invisible. >0 means lines indented more than this value are invisible. */ it->selective = (INTEGERP (BVAR (current_buffer, selective_display)) - ? XFASTINT (BVAR (current_buffer, selective_display)) + ? XINT (BVAR (current_buffer, selective_display)) : (!NILP (BVAR (current_buffer, selective_display)) ? -1 : 0)); it->selective_display_ellipsis_p @@ -2591,6 +2627,7 @@ init_iterator (struct it *it, struct window *w, it->paragraph_embedding = R2L; else it->paragraph_embedding = NEUTRAL_DIR; + bidi_unshelve_cache (NULL, 0); bidi_init_it (charpos, IT_BYTEPOS (*it), FRAME_WINDOW_P (it->f), &it->bidi_it); } @@ -2915,6 +2952,7 @@ handle_stop (struct it *it) { it->ignore_overlay_strings_at_pos_p = 1; it->string_from_display_prop_p = 0; + it->from_disp_prop_p = 0; handle_overlay_change_p = 0; } handled = HANDLED_RECOMPUTE_PROPS; @@ -3074,10 +3112,9 @@ compute_stop_pos (struct it *it) static EMACS_INT next_overlay_change (EMACS_INT pos) { - int noverlays; + ptrdiff_t i, noverlays; EMACS_INT endpos; Lisp_Object *overlays; - int i; /* Get all overlays at the given position. */ GET_OVERLAYS_AT (pos, overlays, noverlays, &endpos, 1); @@ -3097,6 +3134,11 @@ next_overlay_change (EMACS_INT pos) return endpos; } +/* How many characters forward to search for a display property or + display string. Enough for a screenful of 100 lines x 50 + characters in a line. */ +#define MAX_DISP_SCAN 5000 + /* Return the character position of a display string at or after position specified by POSITION. If no display string exists at or after POSITION, return ZV. A display string is either an overlay @@ -3107,24 +3149,33 @@ next_overlay_change (EMACS_INT pos) on a GUI frame. */ EMACS_INT compute_display_string_pos (struct text_pos *position, - struct bidi_string_data *string, int frame_window_p) + struct bidi_string_data *string, + int frame_window_p, int *disp_prop_p) { /* OBJECT = nil means current buffer. */ 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; + Lisp_Object pos, spec, limpos; + 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); + EMACS_INT lim = + (charpos < eob - MAX_DISP_SCAN) ? charpos + MAX_DISP_SCAN : eob; struct text_pos tpos; + *disp_prop_p = 1; + if (charpos >= eob /* We don't support display properties whose values are strings that have display string properties. */ || string->from_disp_str /* C strings cannot have display properties. */ || (string->s && !STRINGP (object))) - return eob; + { + *disp_prop_p = 0; + return eob; + } /* If the character at CHARPOS is where the display string begins, return CHARPOS. */ @@ -3141,19 +3192,25 @@ compute_display_string_pos (struct text_pos *position, spec)) && handle_display_spec (NULL, spec, object, Qnil, &tpos, bufpos, frame_window_p)) - return charpos; + { + return charpos; + } /* Look forward for the first character with a `display' property that will replace the underlying text when displayed. */ + limpos = make_number (lim); do { - pos = Fnext_single_char_property_change (pos, Qdisplay, object, Qnil); + pos = Fnext_single_char_property_change (pos, Qdisplay, object, limpos); CHARPOS (tpos) = XFASTINT (pos); + if (CHARPOS (tpos) >= lim) + { + *disp_prop_p = 0; + break; + } if (STRINGP (object)) BYTEPOS (tpos) = string_char_to_byte (object, CHARPOS (tpos)); else BYTEPOS (tpos) = CHAR_TO_BYTE (CHARPOS (tpos)); - if (CHARPOS (tpos) >= eob) - break; spec = Fget_char_property (pos, Qdisplay, object); if (!STRINGP (object)) bufpos = CHARPOS (tpos); @@ -3175,7 +3232,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; @@ -3481,6 +3539,7 @@ face_before_or_after_it_pos (struct it *it, int before_p) int face_id, limit; EMACS_INT next_check_charpos; struct it it_copy; + void *it_copy_data = NULL; xassert (it->s == NULL); @@ -3523,7 +3582,7 @@ face_before_or_after_it_pos (struct it *it, int before_p) character on this display line. */ if (it->current_x <= it->first_visible_x) return it->face_id; - it_copy = *it; + SAVE_IT (it_copy, *it, it_copy_data); /* Implementation note: Since move_it_in_display_line works in the iterator geometry, and thinks the first character is always the leftmost, even in R2L lines, @@ -3532,6 +3591,7 @@ face_before_or_after_it_pos (struct it *it, int before_p) move_it_in_display_line (&it_copy, SCHARS (it_copy.string), it_copy.current_x - 1, MOVE_TO_X); charpos = IT_STRING_CHARPOS (it_copy); + RESTORE_IT (it, it, it_copy_data); } else { @@ -3621,7 +3681,7 @@ face_before_or_after_it_pos (struct it *it, int before_p) character on this display line. */ if (it->current_x <= it->first_visible_x) return it->face_id; - it_copy = *it; + SAVE_IT (it_copy, *it, it_copy_data); /* Implementation note: Since move_it_in_display_line works in the iterator geometry, and thinks the first character is always the leftmost, even in R2L lines, @@ -3630,6 +3690,7 @@ face_before_or_after_it_pos (struct it *it, int before_p) move_it_in_display_line (&it_copy, ZV, it_copy.current_x - 1, MOVE_TO_X); pos = it_copy.current.pos; + RESTORE_IT (it, it, it_copy_data); } else { @@ -4393,6 +4454,7 @@ handle_single_display_spec (struct it *it, Lisp_Object spec, Lisp_Object object, it->method = GET_FROM_IMAGE; it->from_overlay = Qnil; it->face_id = face_id; + it->from_disp_prop_p = 1; /* Say that we haven't consumed the characters with `display' property yet. The call to pop_it in @@ -4465,6 +4527,7 @@ handle_single_display_spec (struct it *it, Lisp_Object spec, Lisp_Object object, when we are finished with the glyph property value. */ push_it (it, position); it->from_overlay = overlay; + it->from_disp_prop_p = 1; if (NILP (location)) it->area = TEXT_AREA; @@ -4482,12 +4545,34 @@ handle_single_display_spec (struct it *it, Lisp_Object spec, Lisp_Object object, it->end_charpos = it->string_nchars = SCHARS (it->string); it->method = GET_FROM_STRING; it->stop_charpos = 0; + it->prev_stop = 0; + it->base_level_stop = 0; it->string_from_display_prop_p = 1; /* Say that we haven't consumed the characters with `display' property yet. The call to pop_it in set_iterator_to_next will clean this up. */ if (BUFFERP (object)) *position = start_pos; + + /* Force paragraph direction to be that of the parent + object. If the parent object's paragraph direction is + not yet determined, default to L2R. */ + if (it->bidi_p && it->bidi_it.paragraph_dir == R2L) + it->paragraph_embedding = it->bidi_it.paragraph_dir; + else + it->paragraph_embedding = L2R; + + /* Set up the bidi iterator for this display string. */ + if (it->bidi_p) + { + it->bidi_it.string.lstring = it->string; + it->bidi_it.string.s = NULL; + 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); + } } else if (CONSP (value) && EQ (XCAR (value), Qspace)) { @@ -4731,6 +4816,11 @@ handle_composition_prop (struct it *it) && COMPOSITION_VALID_P (start, end, prop) && (STRINGP (it->string) || (PT <= start || PT >= end))) { + if (start < pos) + /* As we can't handle this situation (perhaps font-lock added + a new composition), we just return here hoping that next + redisplay will detect this composition much earlier. */ + return HANDLED_NORMALLY; if (start != pos) { if (STRINGP (it->string)) @@ -4839,6 +4929,20 @@ next_overlay_string (struct it *it) it->stop_charpos = 0; if (it->cmp_it.stop_pos >= 0) it->cmp_it.stop_pos = 0; + it->prev_stop = 0; + it->base_level_stop = 0; + + /* Set up the bidi iterator for this overlay string. */ + if (it->bidi_p) + { + it->bidi_it.string.lstring = it->string; + it->bidi_it.string.s = NULL; + 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); + } } CHECK_IT (it); @@ -5105,8 +5209,32 @@ get_overlay_strings_1 (struct it *it, EMACS_INT charpos, int compute_stop_p) it->stop_charpos = 0; xassert (STRINGP (it->string)); it->end_charpos = SCHARS (it->string); + it->prev_stop = 0; + it->base_level_stop = 0; it->multibyte_p = STRING_MULTIBYTE (it->string); it->method = GET_FROM_STRING; + it->from_disp_prop_p = 0; + + /* Force paragraph direction to be that of the parent + buffer. */ + if (it->bidi_p && it->bidi_it.paragraph_dir == R2L) + it->paragraph_embedding = it->bidi_it.paragraph_dir; + else + it->paragraph_embedding = L2R; + + /* Set up the bidi iterator for this overlay string. */ + if (it->bidi_p) + { + EMACS_INT pos = (charpos > 0 ? charpos : IT_CHARPOS (*it)); + + it->bidi_it.string.lstring = it->string; + it->bidi_it.string.s = NULL; + 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; } @@ -5181,21 +5309,35 @@ push_it (struct it *it, struct text_pos *position) p->string_from_display_prop_p = it->string_from_display_prop_p; p->display_ellipsis_p = 0; p->line_wrap = it->line_wrap; + p->bidi_p = it->bidi_p; + p->paragraph_embedding = it->paragraph_embedding; + p->from_disp_prop_p = it->from_disp_prop_p; ++it->sp; + + /* Save the state of the bidi iterator as well. */ + if (it->bidi_p) + bidi_push_it (&it->bidi_it); } static void iterate_out_of_display_property (struct it *it) { + int buffer_p = BUFFERP (it->object); + EMACS_INT eob = (buffer_p ? ZV : it->end_charpos); + EMACS_INT bob = (buffer_p ? BEGV : 0); + + xassert (eob >= CHARPOS (it->position) && CHARPOS (it->position) >= bob); + /* Maybe initialize paragraph direction. If we are at the beginning of a new paragraph, next_element_from_buffer may not have a chance to do that. */ - if (it->bidi_it.first_elt && it->bidi_it.charpos < ZV) + if (it->bidi_it.first_elt && it->bidi_it.charpos < eob) bidi_paragraph_init (it->paragraph_embedding, &it->bidi_it, 1); /* prev_stop can be zero, so check against BEGV as well. */ - while (it->bidi_it.charpos >= BEGV + while (it->bidi_it.charpos >= bob && it->prev_stop <= it->bidi_it.charpos - && it->bidi_it.charpos < CHARPOS (it->position)) + && it->bidi_it.charpos < CHARPOS (it->position) + && it->bidi_it.charpos < eob) bidi_move_to_visually_next (&it->bidi_it); /* Record the stop_pos we just crossed, for when we cross it back, maybe. */ @@ -5204,11 +5346,11 @@ iterate_out_of_display_property (struct it *it) /* If we ended up not where pop_it put us, resync IT's positional members with the bidi iterator. */ if (it->bidi_it.charpos != CHARPOS (it->position)) - { - SET_TEXT_POS (it->position, - it->bidi_it.charpos, it->bidi_it.bytepos); - it->current.pos = it->position; - } + SET_TEXT_POS (it->position, it->bidi_it.charpos, it->bidi_it.bytepos); + if (buffer_p) + it->current.pos = it->position; + else + it->current.string_pos = it->position; } /* Restore IT's settings from IT->stack. Called, for example, when no @@ -5221,6 +5363,7 @@ static void pop_it (struct it *it) { struct iterator_stack_entry *p; + int from_display_prop = it->from_disp_prop_p; xassert (it->sp > 0); --it->sp; @@ -5245,22 +5388,10 @@ pop_it (struct it *it) it->slice = p->u.image.slice; break; case GET_FROM_STRETCH: - it->object = p->u.comp.object; + it->object = p->u.stretch.object; break; case GET_FROM_BUFFER: it->object = it->w->buffer; - if (it->bidi_p) - { - /* Bidi-iterate until we get out of the portion of text, if - any, covered by a `display' text property or an overlay - with `display' property. (We cannot just jump there, - because the internal coherency of the bidi iterator state - can not be preserved across such jumps.) We also must - determine the paragraph base direction if the overlay we - just processed is at the beginning of a new - paragraph. */ - iterate_out_of_display_property (it); - } break; case GET_FROM_STRING: it->object = it->string; @@ -5286,6 +5417,30 @@ pop_it (struct it *it) it->voffset = p->voffset; it->string_from_display_prop_p = p->string_from_display_prop_p; it->line_wrap = p->line_wrap; + it->bidi_p = p->bidi_p; + it->paragraph_embedding = p->paragraph_embedding; + it->from_disp_prop_p = p->from_disp_prop_p; + if (it->bidi_p) + { + bidi_pop_it (&it->bidi_it); + /* Bidi-iterate until we get out of the portion of text, if any, + covered by a `display' text property or by an overlay with + `display' property. (We cannot just jump there, because the + internal coherency of the bidi iterator state can not be + preserved across such jumps.) We also must determine the + paragraph base direction if the overlay we just processed is + at the beginning of a new paragraph. */ + if (from_display_prop + && (it->method == GET_FROM_BUFFER || it->method == GET_FROM_STRING)) + iterate_out_of_display_property (it); + + xassert ((BUFFERP (it->object) + && IT_CHARPOS (*it) == it->bidi_it.charpos + && IT_BYTEPOS (*it) == it->bidi_it.bytepos) + || (STRINGP (it->object) + && IT_STRING_CHARPOS (*it) == it->bidi_it.charpos + && IT_STRING_BYTEPOS (*it) == it->bidi_it.bytepos)); + } } @@ -5311,6 +5466,9 @@ back_to_previous_line_start (struct it *it) continuously over the text). Otherwise, don't change the value of *SKIPPED_P. + If BIDI_IT_PREV is non-NULL, store into it the state of the bidi + iterator on the newline, if it was found. + Newlines may come from buffer text, overlay strings, or strings displayed via the `display' property. That's the reason we can't simply use find_next_newline_no_quit. @@ -5323,9 +5481,11 @@ back_to_previous_line_start (struct it *it) leads to wrong cursor motion. */ static int -forward_to_next_line_start (struct it *it, int *skipped_p) +forward_to_next_line_start (struct it *it, int *skipped_p, + struct bidi_it *bidi_it_prev) { - int old_selective, newline_found_p, n; + EMACS_INT old_selective; + int newline_found_p, n; const int MAX_NEWLINE_DISTANCE = 500; /* If already on a newline, just consume it to avoid unintended @@ -5334,6 +5494,8 @@ forward_to_next_line_start (struct it *it, int *skipped_p) && it->c == '\n' && CHARPOS (it->position) == IT_CHARPOS (*it)) { + if (it->bidi_p && bidi_it_prev) + *bidi_it_prev = it->bidi_it; set_iterator_to_next (it, 0); it->c = 0; return 1; @@ -5355,6 +5517,8 @@ forward_to_next_line_start (struct it *it, int *skipped_p) if (!get_next_display_element (it)) return 0; newline_found_p = it->what == IT_CHARACTER && it->c == '\n'; + if (newline_found_p && it->bidi_p && bidi_it_prev) + *bidi_it_prev = it->bidi_it; set_iterator_to_next (it, 0); } @@ -5373,13 +5537,37 @@ forward_to_next_line_start (struct it *it, int *skipped_p) buffer text. */ if (it->stop_charpos >= limit || ((pos = Fnext_single_property_change (make_number (start), - Qdisplay, - Qnil, make_number (limit)), + Qdisplay, Qnil, + make_number (limit)), NILP (pos)) && next_overlay_change (start) == ZV)) { - IT_CHARPOS (*it) = limit; - IT_BYTEPOS (*it) = CHAR_TO_BYTE (limit); + if (!it->bidi_p) + { + IT_CHARPOS (*it) = limit; + IT_BYTEPOS (*it) = CHAR_TO_BYTE (limit); + } + else + { + struct bidi_it bprev; + + /* Help bidi.c avoid expensive searches for display + properties and overlays, by telling it that there are + none up to `limit'. */ + if (it->bidi_it.disp_pos < limit) + { + it->bidi_it.disp_pos = limit; + it->bidi_it.disp_prop_p = 0; + } + do { + bprev = it->bidi_it; + bidi_move_to_visually_next (&it->bidi_it); + } while (it->bidi_it.charpos != limit); + IT_CHARPOS (*it) = limit; + IT_BYTEPOS (*it) = it->bidi_it.bytepos; + if (bidi_it_prev) + *bidi_it_prev = bprev; + } *skipped_p = newline_found_p = 1; } else @@ -5388,6 +5576,8 @@ forward_to_next_line_start (struct it *it, int *skipped_p) && !newline_found_p) { newline_found_p = ITERATOR_AT_END_OF_LINE_P (it); + if (newline_found_p && it->bidi_p && bidi_it_prev) + *bidi_it_prev = it->bidi_it; set_iterator_to_next (it, 0); } } @@ -5417,7 +5607,7 @@ back_to_previous_visible_line_start (struct it *it) invisible. */ if (it->selective > 0 && indented_beyond_p (IT_CHARPOS (*it), IT_BYTEPOS (*it), - (double) it->selective)) /* iftc */ + it->selective)) continue; /* Check the newline before point for invisibility. */ @@ -5434,10 +5624,13 @@ back_to_previous_visible_line_start (struct it *it) { struct it it2; + void *it2data = NULL; EMACS_INT pos; EMACS_INT beg, end; Lisp_Object val, overlay; + SAVE_IT (it2, *it, it2data); + /* If newline is part of a composition, continue from start of composition */ if (find_composition (IT_CHARPOS (*it), -1, &beg, &end, &val, Qnil) && beg < IT_CHARPOS (*it)) @@ -5445,20 +5638,25 @@ back_to_previous_visible_line_start (struct it *it) /* If newline is replaced by a display property, find start of overlay or interval and continue search from that point. */ - it2 = *it; pos = --IT_CHARPOS (it2); --IT_BYTEPOS (it2); it2.sp = 0; + bidi_unshelve_cache (NULL, 0); it2.string_from_display_prop_p = 0; + it2.from_disp_prop_p = 0; if (handle_display_prop (&it2) == HANDLED_RETURN && !NILP (val = get_char_property_and_overlay (make_number (pos), Qdisplay, Qnil, &overlay)) && (OVERLAYP (overlay) ? (beg = OVERLAY_POSITION (OVERLAY_START (overlay))) : get_property_and_range (pos, Qdisplay, &val, &beg, &end, Qnil))) - goto replaced; + { + RESTORE_IT (it, it, it2data); + goto replaced; + } /* Newline is not replaced by anything -- so we are done. */ + RESTORE_IT (it, it, it2data); break; replaced: @@ -5503,19 +5701,21 @@ static void reseat_at_next_visible_line_start (struct it *it, int on_newline_p) { int newline_found_p, skipped_p = 0; + struct bidi_it bidi_it_prev; - newline_found_p = forward_to_next_line_start (it, &skipped_p); + newline_found_p = forward_to_next_line_start (it, &skipped_p, &bidi_it_prev); /* Skip over lines that are invisible because they are indented more than the value of IT->selective. */ if (it->selective > 0) while (IT_CHARPOS (*it) < ZV && indented_beyond_p (IT_CHARPOS (*it), IT_BYTEPOS (*it), - (double) it->selective)) /* iftc */ + it->selective)) { xassert (IT_BYTEPOS (*it) == BEGV || FETCH_BYTE (IT_BYTEPOS (*it) - 1) == '\n'); - newline_found_p = forward_to_next_line_start (it, &skipped_p); + newline_found_p = + forward_to_next_line_start (it, &skipped_p, &bidi_it_prev); } /* Position on the newline if that's what's requested. */ @@ -5525,14 +5725,37 @@ reseat_at_next_visible_line_start (struct it *it, int on_newline_p) { if (IT_STRING_CHARPOS (*it) > 0) { - --IT_STRING_CHARPOS (*it); - --IT_STRING_BYTEPOS (*it); + if (!it->bidi_p) + { + --IT_STRING_CHARPOS (*it); + --IT_STRING_BYTEPOS (*it); + } + else + { + /* We need to restore the bidi iterator to the state + it had on the newline, and resync the IT's + position with that. */ + it->bidi_it = bidi_it_prev; + IT_STRING_CHARPOS (*it) = it->bidi_it.charpos; + IT_STRING_BYTEPOS (*it) = it->bidi_it.bytepos; + } } } else if (IT_CHARPOS (*it) > BEGV) { - --IT_CHARPOS (*it); - --IT_BYTEPOS (*it); + if (!it->bidi_p) + { + --IT_CHARPOS (*it); + --IT_BYTEPOS (*it); + } + else + { + /* We need to restore the bidi iterator to the state it + had on the newline and resync IT with that. */ + it->bidi_it = bidi_it_prev; + IT_CHARPOS (*it) = it->bidi_it.charpos; + IT_BYTEPOS (*it) = it->bidi_it.bytepos; + } reseat (it, it->current.pos, 0); } } @@ -5570,17 +5793,19 @@ reseat (struct it *it, struct text_pos pos, int force_p) { /* For bidi iteration, we need to prime prev_stop and base_level_stop with our best estimations. */ - if (CHARPOS (pos) < it->prev_stop) - { - handle_stop_backwards (it, BEGV); - if (CHARPOS (pos) < it->base_level_stop) - it->base_level_stop = 0; - } - else if (CHARPOS (pos) > it->stop_charpos - && it->stop_charpos >= BEGV) - handle_stop_backwards (it, it->stop_charpos); - else /* force_p */ - handle_stop (it); + /* Implementation note: Of course, POS is not necessarily a + stop position, so assigning prev_pos to it is a lie; we + should have called compute_stop_backwards. However, if + the current buffer does not include any R2L characters, + that call would be a waste of cycles, because the + iterator will never move back, and thus never cross this + "fake" stop position. So we delay that backward search + until the time we really need it, in next_element_from_buffer. */ + if (CHARPOS (pos) != it->prev_stop) + it->prev_stop = CHARPOS (pos); + if (CHARPOS (pos) < it->base_level_stop) + it->base_level_stop = 0; /* meaning it's unknown */ + handle_stop (it); } else { @@ -5614,22 +5839,24 @@ reseat_1 (struct it *it, struct text_pos pos, int set_stop_p) IT_STRING_CHARPOS (*it) = -1; IT_STRING_BYTEPOS (*it) = -1; it->string = Qnil; - it->string_from_display_prop_p = 0; it->method = GET_FROM_BUFFER; it->object = it->w->buffer; it->area = TEXT_AREA; it->multibyte_p = !NILP (BVAR (current_buffer, enable_multibyte_characters)); it->sp = 0; it->string_from_display_prop_p = 0; + it->from_disp_prop_p = 0; it->face_before_selective_p = 0; if (it->bidi_p) { - it->bidi_it.first_elt = 1; + bidi_init_it (IT_CHARPOS (*it), IT_BYTEPOS (*it), FRAME_WINDOW_P (it->f), + &it->bidi_it); + bidi_unshelve_cache (NULL, 0); it->bidi_it.paragraph_dir = NEUTRAL_DIR; - it->bidi_it.disp_pos = -1; 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) @@ -5682,9 +5909,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) { @@ -5702,6 +5927,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); } @@ -5718,25 +5944,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 = (const unsigned char *) 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; } @@ -6012,7 +6237,8 @@ get_next_display_element (struct it *it) display. Then, set IT->dpvec to these glyphs. */ Lisp_Object gc; int ctl_len; - int face_id, lface_id = 0 ; + int face_id; + EMACS_INT lface_id = 0; int escape_glyph; /* Handle control characters with ^. */ @@ -6182,11 +6408,23 @@ get_next_display_element (struct it *it) else { EMACS_INT pos = (it->s ? -1 - : STRINGP (it->string) ? IT_STRING_CHARPOS (*it) - : IT_CHARPOS (*it)); + : STRINGP (it->string) ? IT_STRING_CHARPOS (*it) + : IT_CHARPOS (*it)); + int c; - it->face_id = FACE_FOR_CHAR (it->f, face, it->char_to_display, pos, - it->string); + if (it->what == IT_CHARACTER) + c = it->char_to_display; + else + { + struct composition *cmp = composition_table[it->cmp_it.id]; + int i; + + c = ' '; + for (i = 0; i < cmp->glyph_len; i++) + if ((c = COMPOSITION_GLYPH (cmp, i)) != '\t') + break; + } + it->face_id = FACE_FOR_CHAR (it->f, face, c, pos, it->string); } } @@ -6396,11 +6634,11 @@ set_iterator_to_next (struct it *it, int reseat_p) case GET_FROM_C_STRING: /* Current display element of IT is from a C string. */ if (!it->bidi_p - /* If the string position is beyond string_nchars, it means + /* If the string position is beyond string's end, it means next_element_from_c_string is padding the string with blanks, in which case we bypass the bidi iterator, because it cannot deal with such virtual characters. */ - || IT_CHARPOS (*it) >= it->string_nchars) + || IT_CHARPOS (*it) >= it->bidi_it.string.schars) { IT_BYTEPOS (*it) += it->len; IT_CHARPOS (*it) += 1; @@ -6524,12 +6762,12 @@ set_iterator_to_next (struct it *it, int reseat_p) else { if (!it->bidi_p - /* If the string position is beyond string_nchars, it + /* If the string position is beyond string's end, it means next_element_from_string is padding the string with blanks, in which case we bypass the bidi iterator, because it cannot deal with such virtual characters. */ - || IT_STRING_CHARPOS (*it) >= it->string_nchars) + || IT_STRING_CHARPOS (*it) >= it->bidi_it.string.schars) { IT_STRING_BYTEPOS (*it) += it->len; IT_STRING_CHARPOS (*it) += 1; @@ -6641,7 +6879,7 @@ next_element_from_display_vector (struct it *it) it->face_id = it->dpvec_face_id; else { - int lface_id = GLYPH_CODE_FACE (gc); + EMACS_INT lface_id = GLYPH_CODE_FACE (gc); if (lface_id > 0) it->face_id = merge_faces (it->f, Qt, lface_id, it->saved_face_id); @@ -6664,7 +6902,7 @@ static void get_visually_first_element (struct it *it) { int string_p = STRINGP (it->string) || it->s; - EMACS_INT eob = (string_p ? it->string_nchars : ZV); + EMACS_INT eob = (string_p ? it->bidi_it.string.schars : ZV); EMACS_INT bob = (string_p ? 0 : BEGV); if (STRINGP (it->string)) @@ -6771,7 +7009,7 @@ next_element_from_string (struct it *it) struct text_pos position; xassert (STRINGP (it->string)); - xassert (!it->bidi_p || it->string == it->bidi_it.string.lstring); + xassert (!it->bidi_p || EQ (it->string, it->bidi_it.string.lstring)); xassert (IT_STRING_CHARPOS (*it) >= 0); position = it->current.string_pos; @@ -6834,10 +7072,10 @@ next_element_from_string (struct it *it) embedding level, so test for that explicitly. */ && !BIDI_AT_BASE_LEVEL (it->bidi_it)) { - /* If we lost track of base_level_stop, we have no better place - for handle_stop_backwards to start from than BEGV. This - happens, e.g., when we were reseated to the previous - screenful of text by vertical-motion. */ + /* If we lost track of base_level_stop, we have no better + place for handle_stop_backwards to start from than string + beginning. This happens, e.g., when we were reseated to + the previous screenful of text by vertical-motion. */ if (it->base_level_stop <= 0 || IT_STRING_CHARPOS (*it) < it->base_level_stop) it->base_level_stop = 0; @@ -7025,6 +7263,50 @@ next_element_from_stretch (struct it *it) return 1; } +/* Scan backwards from IT's current position until we find a stop + position, or until BEGV. This is called when we find ourself + before both the last known prev_stop and base_level_stop while + reordering bidirectional text. */ + +static void +compute_stop_pos_backwards (struct it *it) +{ + const int SCAN_BACK_LIMIT = 1000; + struct text_pos pos; + struct display_pos save_current = it->current; + struct text_pos save_position = it->position; + EMACS_INT charpos = IT_CHARPOS (*it); + EMACS_INT where_we_are = charpos; + EMACS_INT save_stop_pos = it->stop_charpos; + EMACS_INT save_end_pos = it->end_charpos; + + xassert (NILP (it->string) && !it->s); + xassert (it->bidi_p); + it->bidi_p = 0; + do + { + it->end_charpos = min (charpos + 1, ZV); + charpos = max (charpos - SCAN_BACK_LIMIT, BEGV); + SET_TEXT_POS (pos, charpos, BYTE_TO_CHAR (charpos)); + reseat_1 (it, pos, 0); + compute_stop_pos (it); + /* We must advance forward, right? */ + if (it->stop_charpos <= charpos) + abort (); + } + while (charpos > BEGV && it->stop_charpos >= it->end_charpos); + + if (it->stop_charpos <= where_we_are) + it->prev_stop = it->stop_charpos; + else + it->prev_stop = BEGV; + it->bidi_p = 1; + it->current = save_current; + it->position = save_position; + it->stop_charpos = save_stop_pos; + it->end_charpos = save_end_pos; +} + /* Scan forward from CHARPOS in the current buffer/string, until we find a stop position > current IT's position. Then handle the stop position before that. This is called when we bump into a stop @@ -7044,6 +7326,7 @@ handle_stop_backwards (struct it *it, EMACS_INT charpos) EMACS_INT next_stop; /* Scan in strict logical order. */ + xassert (it->bidi_p); it->bidi_p = 0; do { @@ -7063,11 +7346,11 @@ handle_stop_backwards (struct it *it, EMACS_INT charpos) } while (charpos <= where_we_are); - next_stop = it->stop_charpos; - it->stop_charpos = it->prev_stop; it->bidi_p = 1; it->current = save_current; it->position = save_position; + next_stop = it->stop_charpos; + it->stop_charpos = it->prev_stop; handle_stop (it); it->stop_charpos = next_stop; } @@ -7085,7 +7368,7 @@ next_element_from_buffer (struct it *it) xassert (IT_CHARPOS (*it) >= BEGV); xassert (NILP (it->string) && !it->s); xassert (!it->bidi_p - || (it->bidi_it.string.lstring == Qnil + || (EQ (it->bidi_it.string.lstring, Qnil) && it->bidi_it.string.s == NULL)); /* With bidi reordering, the character to display might not be the @@ -7164,14 +7447,19 @@ next_element_from_buffer (struct it *it) embedding level, so test for that explicitly. */ && !BIDI_AT_BASE_LEVEL (it->bidi_it)) { - /* If we lost track of base_level_stop, we have no better place - for handle_stop_backwards to start from than BEGV. This - happens, e.g., when we were reseated to the previous - screenful of text by vertical-motion. */ if (it->base_level_stop <= 0 || IT_CHARPOS (*it) < it->base_level_stop) - it->base_level_stop = BEGV; - handle_stop_backwards (it, it->base_level_stop); + { + /* If we lost track of base_level_stop, we need to find + prev_stop by looking backwards. This happens, e.g., when + we were reseated to the previous screenful of text by + vertical-motion. */ + it->base_level_stop = BEGV; + compute_stop_pos_backwards (it); + handle_stop_backwards (it, it->prev_stop); + } + else + handle_stop_backwards (it, it->base_level_stop); return GET_NEXT_DISPLAY_ELEMENT (it); } else @@ -7220,7 +7508,7 @@ next_element_from_buffer (struct it *it) && IT_CHARPOS (*it) + 1 < ZV && indented_beyond_p (IT_CHARPOS (*it) + 1, IT_BYTEPOS (*it) + 1, - (double) it->selective)) /* iftc */ + it->selective)) { success_p = next_element_from_ellipsis (it); it->dpvec_char_len = -1; @@ -7373,10 +7661,13 @@ move_it_in_display_line_to (struct it *it, { enum move_it_result result = MOVE_UNDEFINED; struct glyph_row *saved_glyph_row; - struct it wrap_it, atpos_it, atx_it; + struct it wrap_it, atpos_it, atx_it, ppos_it; + void *wrap_data = NULL, *atpos_data = NULL, *atx_data = NULL; + void *ppos_data = NULL; int may_wrap = 0; enum it_method prev_method = it->method; EMACS_INT prev_pos = IT_CHARPOS (*it); + int saw_smaller_pos = prev_pos < to_charpos; /* Don't produce glyphs in produce_glyphs. */ saved_glyph_row = it->glyph_row; @@ -7391,11 +7682,29 @@ move_it_in_display_line_to (struct it *it, atpos_it.sp = -1; atx_it.sp = -1; + /* Use ppos_it under bidi reordering to save a copy of IT for the + position > CHARPOS that is the closest to CHARPOS. We restore + that position in IT when we have scanned the entire display line + without finding a match for CHARPOS and all the character + positions are greater than CHARPOS. */ + if (it->bidi_p) + { + SAVE_IT (ppos_it, *it, ppos_data); + SET_TEXT_POS (ppos_it.current.pos, ZV, ZV_BYTE); + if ((op & MOVE_TO_POS) && IT_CHARPOS (*it) >= to_charpos) + SAVE_IT (ppos_it, *it, ppos_data); + } + #define BUFFER_POS_REACHED_P() \ ((op & MOVE_TO_POS) != 0 \ && BUFFERP (it->object) \ && (IT_CHARPOS (*it) == to_charpos \ - || (!it->bidi_p && IT_CHARPOS (*it) > to_charpos)) \ + || (!it->bidi_p && IT_CHARPOS (*it) > to_charpos) \ + || (it->what == IT_COMPOSITION \ + && ((IT_CHARPOS (*it) > to_charpos \ + && to_charpos >= it->cmp_it.charpos) \ + || (IT_CHARPOS (*it) < to_charpos \ + && to_charpos <= it->cmp_it.charpos)))) \ && (it->method == GET_FROM_BUFFER \ || (it->method == GET_FROM_DISPLAY_VECTOR \ && it->dpvec + it->current.dpvec_index + 1 >= it->dpend))) @@ -7417,15 +7726,16 @@ move_it_in_display_line_to (struct it *it, ((IT)->current_x = x, (IT)->max_ascent = ascent, \ (IT)->max_descent = descent) - /* Stop if we move beyond TO_CHARPOS (after an image or stretch - glyph). */ + /* Stop if we move beyond TO_CHARPOS (after an image or a + display string or stretch glyph). */ if ((op & MOVE_TO_POS) != 0 && BUFFERP (it->object) && it->method == GET_FROM_BUFFER && ((!it->bidi_p && IT_CHARPOS (*it) > to_charpos) || (it->bidi_p && (prev_method == GET_FROM_IMAGE - || prev_method == GET_FROM_STRETCH) + || prev_method == GET_FROM_STRETCH + || prev_method == GET_FROM_STRING) /* Passed TO_CHARPOS from left to right. */ && ((prev_pos < to_charpos && IT_CHARPOS (*it) > to_charpos) @@ -7442,12 +7752,9 @@ move_it_in_display_line_to (struct it *it, /* If wrap_it is valid, the current position might be in a word that is wrapped. So, save the iterator in atpos_it and continue to see if wrapping happens. */ - atpos_it = *it; + SAVE_IT (atpos_it, *it, atpos_data); } - prev_method = it->method; - if (it->method == GET_FROM_BUFFER) - prev_pos = IT_CHARPOS (*it); /* Stop when ZV reached. We used to stop here when TO_CHARPOS reached as well, but that is too soon if this glyph does not fit on this line. So we handle it @@ -7479,18 +7786,18 @@ move_it_in_display_line_to (struct it *it, already found, we are done. */ if (atpos_it.sp >= 0) { - *it = atpos_it; + RESTORE_IT (it, &atpos_it, atpos_data); result = MOVE_POS_MATCH_OR_ZV; goto done; } if (atx_it.sp >= 0) { - *it = atx_it; + RESTORE_IT (it, &atx_it, atx_data); result = MOVE_X_REACHED; goto done; } /* Otherwise, we can wrap here. */ - wrap_it = *it; + SAVE_IT (wrap_it, *it, wrap_data); may_wrap = 0; } } @@ -7511,10 +7818,18 @@ move_it_in_display_line_to (struct it *it, if (it->area != TEXT_AREA) { + prev_method = it->method; + if (it->method == GET_FROM_BUFFER) + prev_pos = IT_CHARPOS (*it); set_iterator_to_next (it, 1); if (IT_CHARPOS (*it) < CHARPOS (this_line_min_pos)) SET_TEXT_POS (this_line_min_pos, IT_CHARPOS (*it), IT_BYTEPOS (*it)); + if (it->bidi_p + && (op & MOVE_TO_POS) + && IT_CHARPOS (*it) > to_charpos + && IT_CHARPOS (*it) < IT_CHARPOS (ppos_it)) + SAVE_IT (ppos_it, *it, ppos_data); continue; } @@ -7558,7 +7873,7 @@ move_it_in_display_line_to (struct it *it, goto buffer_pos_reached; if (atpos_it.sp < 0) { - atpos_it = *it; + SAVE_IT (atpos_it, *it, atpos_data); IT_RESET_X_ASCENT_DESCENT (&atpos_it); } } @@ -7572,7 +7887,7 @@ move_it_in_display_line_to (struct it *it, } if (atx_it.sp < 0) { - atx_it = *it; + SAVE_IT (atx_it, *it, atx_data); IT_RESET_X_ASCENT_DESCENT (&atx_it); } } @@ -7616,12 +7931,15 @@ move_it_in_display_line_to (struct it *it, if (it->line_wrap == WORD_WRAP && atpos_it.sp < 0) { - atpos_it = *it; + SAVE_IT (atpos_it, *it, atpos_data); atpos_it.current_x = x_before_this_char; atpos_it.hpos = hpos_before_this_char; } } + prev_method = it->method; + if (it->method == GET_FROM_BUFFER) + prev_pos = IT_CHARPOS (*it); set_iterator_to_next (it, 1); if (IT_CHARPOS (*it) < CHARPOS (this_line_min_pos)) SET_TEXT_POS (this_line_min_pos, @@ -7661,7 +7979,7 @@ move_it_in_display_line_to (struct it *it, if (wrap_it.sp >= 0) { - *it = wrap_it; + RESTORE_IT (it, &wrap_it, wrap_data); atpos_it.sp = -1; atx_it.sp = -1; } @@ -7678,7 +7996,7 @@ move_it_in_display_line_to (struct it *it, goto buffer_pos_reached; if (it->line_wrap == WORD_WRAP && atpos_it.sp < 0) { - atpos_it = *it; + SAVE_IT (atpos_it, *it, atpos_data); IT_RESET_X_ASCENT_DESCENT (&atpos_it); } } @@ -7715,10 +8033,34 @@ move_it_in_display_line_to (struct it *it, /* Is this a line end? If yes, we're done. */ if (ITERATOR_AT_END_OF_LINE_P (it)) { - result = MOVE_NEWLINE_OR_CR; + /* If we are past TO_CHARPOS, but never saw any character + positions smaller than TO_CHARPOS, return + MOVE_POS_MATCH_OR_ZV, like the unidirectional display + did. */ + if (it->bidi_p && (op & MOVE_TO_POS) != 0) + { + if (!saw_smaller_pos && IT_CHARPOS (*it) > to_charpos) + { + if (IT_CHARPOS (ppos_it) < ZV) + { + RESTORE_IT (it, &ppos_it, ppos_data); + result = MOVE_POS_MATCH_OR_ZV; + } + else + goto buffer_pos_reached; + } + else if (it->line_wrap == WORD_WRAP && atpos_it.sp >= 0 + && IT_CHARPOS (*it) > to_charpos) + goto buffer_pos_reached; + else + result = MOVE_NEWLINE_OR_CR; + } + else + result = MOVE_NEWLINE_OR_CR; break; } + prev_method = it->method; if (it->method == GET_FROM_BUFFER) prev_pos = IT_CHARPOS (*it); /* The current display element has been consumed. Advance @@ -7726,6 +8068,13 @@ move_it_in_display_line_to (struct it *it, set_iterator_to_next (it, 1); if (IT_CHARPOS (*it) < CHARPOS (this_line_min_pos)) SET_TEXT_POS (this_line_min_pos, IT_CHARPOS (*it), IT_BYTEPOS (*it)); + if (IT_CHARPOS (*it) < to_charpos) + saw_smaller_pos = 1; + if (it->bidi_p + && (op & MOVE_TO_POS) + && IT_CHARPOS (*it) >= to_charpos + && IT_CHARPOS (*it) < IT_CHARPOS (ppos_it)) + SAVE_IT (ppos_it, *it, ppos_data); /* Stop if lines are truncated and IT's current x-position is past the right edge of the window now. */ @@ -7735,9 +8084,20 @@ move_it_in_display_line_to (struct it *it, if (!FRAME_WINDOW_P (it->f) || IT_OVERFLOW_NEWLINE_INTO_FRINGE (it)) { - if (!get_next_display_element (it) - || BUFFER_POS_REACHED_P ()) + int at_eob_p = 0; + + if ((at_eob_p = !get_next_display_element (it)) + || BUFFER_POS_REACHED_P () + /* If we are past TO_CHARPOS, but never saw any + character positions smaller than TO_CHARPOS, + return MOVE_POS_MATCH_OR_ZV, like the + unidirectional display did. */ + || (it->bidi_p && (op & MOVE_TO_POS) != 0 + && !saw_smaller_pos + && IT_CHARPOS (*it) > to_charpos)) { + if (!at_eob_p && IT_CHARPOS (ppos_it) < ZV) + RESTORE_IT (it, &ppos_it, ppos_data); result = MOVE_POS_MATCH_OR_ZV; break; } @@ -7747,6 +8107,15 @@ move_it_in_display_line_to (struct it *it, break; } } + else if (it->bidi_p && (op & MOVE_TO_POS) != 0 + && !saw_smaller_pos + && IT_CHARPOS (*it) > to_charpos) + { + if (IT_CHARPOS (ppos_it) < ZV) + RESTORE_IT (it, &ppos_it, ppos_data); + result = MOVE_POS_MATCH_OR_ZV; + break; + } result = MOVE_LINE_TRUNCATED; break; } @@ -7758,12 +8127,21 @@ move_it_in_display_line_to (struct it *it, /* If we scanned beyond to_pos and didn't find a point to wrap at, restore the saved iterator. */ if (atpos_it.sp >= 0) - *it = atpos_it; + RESTORE_IT (it, &atpos_it, atpos_data); else if (atx_it.sp >= 0) - *it = atx_it; + RESTORE_IT (it, &atx_it, atx_data); done: + if (atpos_data) + bidi_unshelve_cache (atpos_data, 1); + if (atx_data) + bidi_unshelve_cache (atx_data, 1); + if (wrap_data) + bidi_unshelve_cache (wrap_data, 1); + if (ppos_data) + bidi_unshelve_cache (ppos_data, 1); + /* Restore the iterator settings altered at the beginning of this function. */ it->glyph_row = saved_glyph_row; @@ -7779,8 +8157,12 @@ move_it_in_display_line (struct it *it, if (it->line_wrap == WORD_WRAP && (op & MOVE_TO_X)) { - struct it save_it = *it; - int skip = move_it_in_display_line_to (it, to_charpos, to_x, op); + struct it save_it; + void *save_data = NULL; + int skip; + + SAVE_IT (save_it, *it, save_data); + skip = move_it_in_display_line_to (it, to_charpos, to_x, op); /* When word-wrap is on, TO_X may lie past the end of a wrapped line. Then it->current is the character on the next line, so backtrack to the @@ -7788,10 +8170,12 @@ move_it_in_display_line (struct it *it, if (skip == MOVE_LINE_CONTINUED) { int prev_x = max (it->current_x - 1, 0); - *it = save_it; + RESTORE_IT (it, &save_it, save_data); move_it_in_display_line_to (it, -1, prev_x, MOVE_TO_X); } + else + bidi_unshelve_cache (save_data, 1); } else move_it_in_display_line_to (it, to_charpos, to_x, op); @@ -7806,14 +8190,15 @@ move_it_in_display_line (struct it *it, description of enum move_operation_enum. If TO_CHARPOS is in invisible text, e.g. a truncated part of a - screen line, this function will set IT to the next position > - TO_CHARPOS. */ + screen line, this function will set IT to the next position that is + displayed to the right of TO_CHARPOS on the screen. */ void move_it_to (struct it *it, EMACS_INT to_charpos, int to_x, int to_y, int to_vpos, int op) { enum move_it_result skip, skip2 = MOVE_X_REACHED; int line_height, line_start_x = 0, reached = 0; + void *backup_data = NULL; for (;;) { @@ -7866,7 +8251,7 @@ move_it_to (struct it *it, EMACS_INT to_charpos, int to_x, int to_y, int to_vpos struct it it_backup; if (it->line_wrap == WORD_WRAP) - it_backup = *it; + SAVE_IT (it_backup, *it, backup_data); /* TO_Y specified means stop at TO_X in the line containing TO_Y---or at TO_CHARPOS if this is reached first. The @@ -7900,7 +8285,7 @@ move_it_to (struct it *it, EMACS_INT to_charpos, int to_x, int to_y, int to_vpos reached = 6; break; } - it_backup = *it; + SAVE_IT (it_backup, *it, backup_data); TRACE_MOVE ((stderr, "move_it: from %d\n", IT_CHARPOS (*it))); skip2 = move_it_in_display_line_to (it, to_charpos, -1, op & MOVE_TO_POS); @@ -7914,7 +8299,7 @@ move_it_to (struct it *it, EMACS_INT to_charpos, int to_x, int to_y, int to_vpos /* If TO_Y is in this line and TO_X was reached above, we scanned too far. We have to restore IT's settings to the ones before skipping. */ - *it = it_backup; + RESTORE_IT (it, &it_backup, backup_data); reached = 6; } else @@ -7941,7 +8326,7 @@ move_it_to (struct it *it, EMACS_INT to_charpos, int to_x, int to_y, int to_vpos && it->line_wrap == WORD_WRAP) { int prev_x = max (it->current_x - 1, 0); - *it = it_backup; + RESTORE_IT (it, &it_backup, backup_data); skip = move_it_in_display_line_to (it, -1, prev_x, MOVE_TO_X); } @@ -8048,6 +8433,9 @@ move_it_to (struct it *it, EMACS_INT to_charpos, int to_x, int to_y, int to_vpos last_max_ascent = it->max_ascent; } + if (backup_data) + bidi_unshelve_cache (backup_data, 1); + TRACE_MOVE ((stderr, "move_it_to: reached %d\n", reached)); } @@ -8065,6 +8453,7 @@ move_it_vertically_backward (struct it *it, int dy) { int nlines, h; struct it it2, it3; + void *it2data = NULL, *it3data = NULL; EMACS_INT start_pos; move_further_back: @@ -8093,7 +8482,7 @@ move_it_vertically_backward (struct it *it, int dy) start of the next line so that we get its height. We need this height to be able to tell whether we reached the specified y-distance. */ - it2 = *it; + SAVE_IT (it2, *it, it2data); it2.max_ascent = it2.max_descent = 0; do { @@ -8102,7 +8491,7 @@ move_it_vertically_backward (struct it *it, int dy) } while (!IT_POS_VALID_AFTER_MOVE_P (&it2)); xassert (IT_CHARPOS (*it) >= BEGV); - it3 = it2; + SAVE_IT (it3, it2, it3data); move_it_to (&it2, start_pos, -1, -1, -1, MOVE_TO_POS); xassert (IT_CHARPOS (*it) >= BEGV); @@ -8121,8 +8510,10 @@ move_it_vertically_backward (struct it *it, int dy) { /* DY == 0 means move to the start of the screen line. The value of nlines is > 0 if continuation lines were involved. */ + RESTORE_IT (it, it, it2data); if (nlines > 0) move_it_by_lines (it, nlines); + bidi_unshelve_cache (it3data, 1); } else { @@ -8130,9 +8521,13 @@ move_it_vertically_backward (struct it *it, int dy) Note that H has been subtracted in front of the if-statement. */ int target_y = it->current_y + h - dy; int y0 = it3.current_y; - int y1 = line_bottom_y (&it3); - int line_height = y1 - y0; + int y1; + int line_height; + RESTORE_IT (&it3, &it3, it3data); + y1 = line_bottom_y (&it3); + line_height = y1 - y0; + RESTORE_IT (it, it, it2data); /* If we did not reach target_y, try to move further backward if we can. If we moved too far backward, try to move forward. */ if (target_y < it->current_y @@ -8259,6 +8654,7 @@ move_it_by_lines (struct it *it, int dvpos) else { struct it it2; + void *it2data = NULL; EMACS_INT start_charpos, i; /* Start at the beginning of the screen line containing IT's @@ -8294,7 +8690,7 @@ move_it_by_lines (struct it *it, int dvpos) /* Above call may have moved too far if continuation lines are involved. Scan forward and see if it did. */ - it2 = *it; + SAVE_IT (it2, *it, it2data); it2.vpos = it2.current_y = 0; move_it_to (&it2, start_charpos, -1, -1, -1, MOVE_TO_POS); it->vpos -= it2.vpos; @@ -8305,12 +8701,18 @@ move_it_by_lines (struct it *it, int dvpos) if (it2.vpos > -dvpos) { int delta = it2.vpos + dvpos; - it2 = *it; + + RESTORE_IT (&it2, &it2, it2data); + SAVE_IT (it2, *it, it2data); move_it_to (it, -1, -1, -1, it->vpos + delta, MOVE_TO_VPOS); /* Move back again if we got too far ahead. */ if (IT_CHARPOS (*it) >= start_charpos) - *it = it2; + RESTORE_IT (it, &it2, it2data); + else + bidi_unshelve_cache (it2data, 1); } + else + RESTORE_IT (it, it, it2data); } } @@ -8471,7 +8873,7 @@ message_dolog (const char *m, EMACS_INT nbytes, int nlflag, int multibyte) if (nlflag) { EMACS_INT this_bol, this_bol_byte, prev_bol, prev_bol_byte; - unsigned long int dups; + printmax_t dups; insert_1 ("\n", 1, 1, 0, 0); scan_newline (Z, Z_BYTE, BEG, BEG_BYTE, -2, 0); @@ -8494,12 +8896,13 @@ message_dolog (const char *m, EMACS_INT nbytes, int nlflag, int multibyte) this_bol, this_bol_byte, 0); if (dups > 1) { - char dupstr[40]; + char dupstr[sizeof " [ times]" + + INT_STRLEN_BOUND (printmax_t)]; int duplen; /* If you change this format, don't forget to also change message_log_check_duplicate. */ - sprintf (dupstr, " [%lu times]", dups); + sprintf (dupstr, " [%"pMd" times]", dups); duplen = strlen (dupstr); TEMP_SET_PT_BOTH (Z - 1, Z_BYTE - 1); insert_1 (dupstr, duplen, 1, 0, 1); @@ -8561,7 +8964,7 @@ message_dolog (const char *m, EMACS_INT nbytes, int nlflag, int multibyte) Return 0 if different, 1 if the new one should just replace it, or a value N > 1 if we should also append " [N times]". */ -static unsigned long int +static intmax_t message_log_check_duplicate (EMACS_INT prev_bol_byte, EMACS_INT this_bol_byte) { EMACS_INT i; @@ -8583,8 +8986,8 @@ message_log_check_duplicate (EMACS_INT prev_bol_byte, EMACS_INT this_bol_byte) if (*p1++ == ' ' && *p1++ == '[') { char *pend; - unsigned long int n = strtoul ((char *) p1, &pend, 10); - if (strncmp (pend, " times]\n", 8) == 0) + intmax_t n = strtoimax ((char *) p1, &pend, 10); + if (0 < n && n < INTMAX_MAX && strncmp (pend, " times]\n", 8) == 0) return n+1; } return 0; @@ -8892,7 +9295,7 @@ vmessage (const char *m, va_list ap) { if (m) { - size_t len; + ptrdiff_t len; len = doprnt (FRAME_MESSAGE_BUF (f), FRAME_MESSAGE_BUF_SIZE (f), m, (char *)0, ap); @@ -10796,7 +11199,7 @@ display_tool_bar_line (struct it *it, int height) ++i; } - /* Stop at line ends. */ + /* Stop at line end. */ if (ITERATOR_AT_END_OF_LINE_P (it)) break; @@ -10879,6 +11282,7 @@ tool_bar_lines_needed (struct frame *f, int *n_rows) it.first_visible_x = 0; it.last_visible_x = FRAME_TOTAL_COLS (f) * FRAME_COLUMN_WIDTH (f); reseat_to_string (&it, NULL, f->desired_tool_bar_string, 0, 0, 0, -1); + it.paragraph_embedding = L2R; while (!ITERATOR_AT_END_P (&it)) { @@ -10912,7 +11316,7 @@ DEFUN ("tool-bar-lines-needed", Ftool_bar_lines_needed, Stool_bar_lines_needed, f = XFRAME (frame); if (WINDOWP (f->tool_bar_window) - || (w = XWINDOW (f->tool_bar_window), + && (w = XWINDOW (f->tool_bar_window), WINDOW_TOTAL_LINES (w) > 0)) { update_tool_bar (f, 1); @@ -10961,6 +11365,14 @@ redisplay_tool_bar (struct frame *f) /* Build a string that represents the contents of the tool-bar. */ build_desired_tool_bar_string (f); reseat_to_string (&it, NULL, f->desired_tool_bar_string, 0, 0, 0, -1); + /* FIXME: This should be controlled by a user option. But it + doesn't make sense to have an R2L tool bar if the menu bar cannot + be drawn also R2L, and making the menu bar R2L is tricky due + toolkit-specific code that implements it. If an R2L tool bar is + ever supported, display_tool_bar_line should also be augmented to + call unproduce_glyphs like display_line and display_string + do. */ + it.paragraph_embedding = L2R; if (f->n_tool_bar_rows == 0) { @@ -11508,40 +11920,42 @@ hscroll_windows (Lisp_Object window) /* First and last unchanged row for try_window_id. */ -int debug_first_unchanged_at_end_vpos; -int debug_last_unchanged_at_beg_vpos; +static int debug_first_unchanged_at_end_vpos; +static int debug_last_unchanged_at_beg_vpos; /* Delta vpos and y. */ -int debug_dvpos, debug_dy; +static int debug_dvpos, debug_dy; /* Delta in characters and bytes for try_window_id. */ -EMACS_INT debug_delta, debug_delta_bytes; +static EMACS_INT debug_delta, debug_delta_bytes; /* Values of window_end_pos and window_end_vpos at the end of try_window_id. */ -EMACS_INT debug_end_vpos; +static EMACS_INT debug_end_vpos; /* Append a string to W->desired_matrix->method. FMT is a printf - format string. A1...A9 are a supplement for a variable-length - argument list. If trace_redisplay_p is non-zero also printf the + format string. If trace_redisplay_p is non-zero also printf the resulting string to stderr. */ +static void debug_method_add (struct window *, char const *, ...) + ATTRIBUTE_FORMAT_PRINTF (2, 3); + static void -debug_method_add (w, fmt, a1, a2, a3, a4, a5, a6, a7, a8, a9) - struct window *w; - char *fmt; - int a1, a2, a3, a4, a5, a6, a7, a8, a9; +debug_method_add (struct window *w, char const *fmt, ...) { char buffer[512]; char *method = w->desired_matrix->method; int len = strlen (method); int size = sizeof w->desired_matrix->method; int remaining = size - len - 1; + va_list ap; - sprintf (buffer, fmt, a1, a2, a3, a4, a5, a6, a7, a8, a9); + va_start (ap, fmt); + vsprintf (buffer, fmt, ap); + va_end (ap); if (len && remaining) { method[len] = '|'; @@ -11554,8 +11968,8 @@ debug_method_add (w, fmt, a1, a2, a3, a4, a5, a6, a7, a8, a9) fprintf (stderr, "%p (%s): %s\n", w, ((BUFFERP (w->buffer) - && STRINGP (XBUFFER (w->buffer)->name)) - ? SSDATA (XBUFFER (w->buffer)->name) + && STRINGP (BVAR (XBUFFER (w->buffer), name))) + ? SSDATA (BVAR (XBUFFER (w->buffer), name)) : "no buffer"), buffer); } @@ -11568,7 +11982,7 @@ debug_method_add (w, fmt, a1, a2, a3, a4, a5, a6, a7, a8, a9) buffer position, END is given as a distance from Z. Used in redisplay_internal for display optimization. */ -static INLINE int +static inline int text_outside_line_unchanged_p (struct window *w, EMACS_INT start, EMACS_INT end) { @@ -11829,7 +12243,7 @@ check_point_in_composition (struct buffer *prev_buf, EMACS_INT prev_pt, /* Reconsider the setting of B->clip_changed which is displayed in window W. */ -static INLINE void +static inline void reconsider_clip_changes (struct window *w, struct buffer *b) { if (b->clip_changed @@ -12911,6 +13325,9 @@ set_cursor_from_row (struct window *w, struct glyph_row *row, /* Last buffer position covered by an overlay string with an integer `cursor' property. */ EMACS_INT bpos_covered = 0; + /* Non-zero means the display string on which to display the cursor + comes from a text property, not from an overlay. */ + int string_from_text_prop = 0; /* Skip over glyphs not having an object at the start and the end of the row. These are special glyphs like truncation marks on @@ -13229,9 +13646,14 @@ set_cursor_from_row (struct window *w, struct glyph_row *row, { Lisp_Object str; EMACS_INT tem; + /* If the display property covers the newline, we + need to search for it one position farther. */ + EMACS_INT lim = pos_after + + (pos_after == MATRIX_ROW_END_CHARPOS (row) + delta); + string_from_text_prop = 0; str = glyph->object; - tem = string_buffer_position_lim (str, pos, pos_after, 0); + tem = string_buffer_position_lim (str, pos, lim, 0); if (tem == 0 /* from overlay */ || pos <= tem) { @@ -13255,7 +13677,10 @@ set_cursor_from_row (struct window *w, struct glyph_row *row, EMACS_INT strpos = glyph->charpos; if (tem) - cursor = glyph; + { + cursor = glyph; + string_from_text_prop = 1; + } for ( ; (row->reversed_p ? glyph > stop : glyph < stop) && EQ (glyph->object, str); @@ -13330,14 +13755,14 @@ set_cursor_from_row (struct window *w, struct glyph_row *row, w->cursor.vpos >= 0 /* that candidate is not the row we are processing */ && MATRIX_ROW (matrix, w->cursor.vpos) != row - /* the row we are processing is part of a continued line */ - && (row->continued_p || MATRIX_ROW_CONTINUATION_LINE_P (row)) /* Make sure cursor.vpos specifies a row whose start and end - charpos occlude point. This is because some callers of this - function leave cursor.vpos at the row where the cursor was - displayed during the last redisplay cycle. */ + charpos occlude point, and it is valid candidate for being a + cursor-row. This is because some callers of this function + leave cursor.vpos at the row where the cursor was displayed + during the last redisplay cycle. */ && MATRIX_ROW_START_CHARPOS (MATRIX_ROW (matrix, w->cursor.vpos)) <= pt_old - && pt_old < MATRIX_ROW_END_CHARPOS (MATRIX_ROW (matrix, w->cursor.vpos))) + && pt_old <= MATRIX_ROW_END_CHARPOS (MATRIX_ROW (matrix, w->cursor.vpos)) + && cursor_row_p (MATRIX_ROW (matrix, w->cursor.vpos))) { struct glyph *g1 = MATRIX_ROW_GLYPH_START (matrix, w->cursor.vpos) + w->cursor.hpos; @@ -13346,18 +13771,39 @@ set_cursor_from_row (struct window *w, struct glyph_row *row, if (!(row->reversed_p ? glyph > glyphs_end : glyph < glyphs_end)) return 0; /* Keep the candidate whose buffer position is the closest to - point. */ + point or has the `cursor' property. */ if (/* previous candidate is a glyph in TEXT_AREA of that row */ w->cursor.hpos >= 0 && w->cursor.hpos < MATRIX_ROW_USED (matrix, w->cursor.vpos) - && BUFFERP (g1->object) - && (g1->charpos == pt_old /* an exact match always wins */ - || (BUFFERP (glyph->object) - && eabs (g1->charpos - pt_old) - < eabs (glyph->charpos - pt_old)))) + && ((BUFFERP (g1->object) + && (g1->charpos == pt_old /* an exact match always wins */ + || (BUFFERP (glyph->object) + && eabs (g1->charpos - pt_old) + < eabs (glyph->charpos - pt_old)))) + /* previous candidate is a glyph from a string that has + a non-nil `cursor' property */ + || (STRINGP (g1->object) + && (!NILP (Fget_char_property (make_number (g1->charpos), + Qcursor, g1->object)) + /* pevious candidate is from the same display + string as this one, and the display string + came from a text property */ + || (EQ (g1->object, glyph->object) + && string_from_text_prop) + /* this candidate is from newline and its + position is not an exact match */ + || (INTEGERP (glyph->object) + && glyph->charpos != pt_old))))) return 0; /* If this candidate gives an exact match, use that. */ - if (!(BUFFERP (glyph->object) && glyph->charpos == pt_old) + if (!((BUFFERP (glyph->object) && glyph->charpos == pt_old) + /* If this candidate is a glyph created for the + terminating newline of a line, and point is on that + newline, it wins because it's an exact match. */ + || (!row->continued_p + && INTEGERP (glyph->object) + && glyph->charpos == 0 + && pt_old == MATRIX_ROW_END_CHARPOS (row) - 1)) /* Otherwise, keep the candidate that comes from a row spanning less buffer positions. This may win when one or both candidate positions are on glyphs that came from @@ -13409,7 +13855,7 @@ set_cursor_from_row (struct window *w, struct glyph_row *row, We assume that the window's buffer is really current. */ -static INLINE struct text_pos +static inline struct text_pos run_window_scroll_functions (Lisp_Object window, struct text_pos startp) { struct window *w = XWINDOW (window); @@ -13646,14 +14092,18 @@ try_scrolling (Lisp_Object window, int just_this_one_p, which was computed as distance from window bottom to point. This matters when lines at window top and lines below window bottom have different height. */ - struct it it1 = it; + struct it it1; + void *it1data = NULL; /* We use a temporary it1 because line_bottom_y can modify its argument, if it moves one line down; see there. */ - int start_y = line_bottom_y (&it1); + int start_y; + SAVE_IT (it1, it, it1data); + start_y = line_bottom_y (&it1); do { + RESTORE_IT (&it, &it, it1data); move_it_by_lines (&it, 1); - it1 = it; + SAVE_IT (it1, it, it1data); } while (line_bottom_y (&it1) - start_y < amount_to_scroll); } @@ -14135,7 +14585,8 @@ try_cursor_movement (Lisp_Object window, struct text_pos startp, int *scroll_ste } ++row; } - while ((MATRIX_ROW_CONTINUATION_LINE_P (row) + while (((MATRIX_ROW_CONTINUATION_LINE_P (row) + || row->continued_p) && MATRIX_ROW_BOTTOM_Y (row) <= last_y) || (MATRIX_ROW_START_CHARPOS (row) == PT && MATRIX_ROW_BOTTOM_Y (row) < last_y)); @@ -14761,10 +15212,13 @@ redisplay_window (Lisp_Object window, int just_this_one_p) && BEGV <= CHARPOS (startp) && CHARPOS (startp) <= ZV) { struct it it1; + void *it1data = NULL; + SAVE_IT (it1, it, it1data); start_display (&it1, w, startp); move_it_vertically (&it1, margin); margin_pos = IT_CHARPOS (it1); + RESTORE_IT (&it, &it, it1data); } scrolling_up = PT > margin_pos; aggressive = @@ -14798,7 +15252,8 @@ redisplay_window (Lisp_Object window, int just_this_one_p) if (pt_offset) centering_position -= pt_offset; centering_position -= - FRAME_LINE_HEIGHT (f) * (1 + margin + (last_line_misfit != 0)); + FRAME_LINE_HEIGHT (f) * (1 + margin + (last_line_misfit != 0)) + + WINDOW_HEADER_LINE_HEIGHT (w); /* Don't let point enter the scroll margin near top of the window. */ if (centering_position < margin * FRAME_LINE_HEIGHT (f)) @@ -15355,7 +15810,8 @@ try_window_reusing_current_matrix (struct window *w) row->visible_height -= min_y - row->y; if (row->y + row->height > max_y) row->visible_height -= row->y + row->height - max_y; - row->redraw_fringe_bitmaps_p = 1; + if (row->fringe_bitmap_periodic_p) + row->redraw_fringe_bitmaps_p = 1; it.current_y += row->height; @@ -15517,7 +15973,8 @@ try_window_reusing_current_matrix (struct window *w) row->visible_height -= min_y - row->y; if (row->y + row->height > max_y) row->visible_height -= row->y + row->height - max_y; - row->redraw_fringe_bitmaps_p = 1; + if (row->fringe_bitmap_periodic_p) + row->redraw_fringe_bitmaps_p = 1; } /* Scroll the current matrix. */ @@ -16670,9 +17127,9 @@ try_window_id (struct window *w) #if GLYPH_DEBUG -void dump_glyph_row (struct glyph_row *, int, int); -void dump_glyph_matrix (struct glyph_matrix *, int); -void dump_glyph (struct glyph_row *, struct glyph *, int); +void dump_glyph_row (struct glyph_row *, int, int) EXTERNALLY_VISIBLE; +void dump_glyph_matrix (struct glyph_matrix *, int) EXTERNALLY_VISIBLE; +void dump_glyph (struct glyph_row *, struct glyph *, int) EXTERNALLY_VISIBLE; /* Dump the contents of glyph matrix MATRIX on stderr. @@ -16682,9 +17139,7 @@ void dump_glyph (struct glyph_row *, struct glyph *, int); GLYPHS > 1 means show glyphs in long form. */ void -dump_glyph_matrix (matrix, glyphs) - struct glyph_matrix *matrix; - int glyphs; +dump_glyph_matrix (struct glyph_matrix *matrix, int glyphs) { int i; for (i = 0; i < matrix->nrows; ++i) @@ -16696,15 +17151,12 @@ dump_glyph_matrix (matrix, glyphs) the glyph row and area where the glyph comes from. */ void -dump_glyph (row, glyph, area) - struct glyph_row *row; - struct glyph *glyph; - int area; +dump_glyph (struct glyph_row *row, struct glyph *glyph, int area) { if (glyph->type == CHAR_GLYPH) { fprintf (stderr, - " %5d %4c %6d %c %3d 0x%05x %c %4d %1.1d%1.1d\n", + " %5td %4c %6"pI"d %c %3d 0x%05x %c %4d %1.1d%1.1d\n", glyph - row->glyphs[TEXT_AREA], 'C', glyph->charpos, @@ -16725,7 +17177,7 @@ dump_glyph (row, glyph, area) else if (glyph->type == STRETCH_GLYPH) { fprintf (stderr, - " %5d %4c %6d %c %3d 0x%05x %c %4d %1.1d%1.1d\n", + " %5td %4c %6"pI"d %c %3d 0x%05x %c %4d %1.1d%1.1d\n", glyph - row->glyphs[TEXT_AREA], 'S', glyph->charpos, @@ -16744,7 +17196,7 @@ dump_glyph (row, glyph, area) else if (glyph->type == IMAGE_GLYPH) { fprintf (stderr, - " %5d %4c %6d %c %3d 0x%05x %c %4d %1.1d%1.1d\n", + " %5td %4c %6"pI"d %c %3d 0x%05x %c %4d %1.1d%1.1d\n", glyph - row->glyphs[TEXT_AREA], 'I', glyph->charpos, @@ -16763,7 +17215,7 @@ dump_glyph (row, glyph, area) else if (glyph->type == COMPOSITE_GLYPH) { fprintf (stderr, - " %5d %4c %6d %c %3d 0x%05x", + " %5td %4c %6"pI"d %c %3d 0x%05x", glyph - row->glyphs[TEXT_AREA], '+', glyph->charpos, @@ -16792,16 +17244,14 @@ dump_glyph (row, glyph, area) GLYPHS > 1 means show glyphs in long form. */ void -dump_glyph_row (row, vpos, glyphs) - struct glyph_row *row; - int vpos, glyphs; +dump_glyph_row (struct glyph_row *row, int vpos, int glyphs) { if (glyphs != 1) { fprintf (stderr, "Row Start End Used oE><\\CTZFesm X Y W H V A P\n"); fprintf (stderr, "======================================================================\n"); - fprintf (stderr, "%3d %5d %5d %4d %1.1d%1.1d%1.1d%1.1d\ + fprintf (stderr, "%3d %5"pI"d %5"pI"d %4d %1.1d%1.1d%1.1d%1.1d\ %1.1d%1.1d%1.1d%1.1d%1.1d%1.1d%1.1d%1.1d %4d %4d %4d %4d %4d %4d %4d\n", vpos, MATRIX_ROW_START_CHARPOS (row), @@ -16829,7 +17279,7 @@ dump_glyph_row (row, vpos, glyphs) fprintf (stderr, "%9d %5d\t%5d\n", row->start.overlay_string_index, row->end.overlay_string_index, row->continuation_lines_width); - fprintf (stderr, "%9d %5d\n", + fprintf (stderr, "%9"pI"d %5"pI"d\n", CHARPOS (row->start.string_pos), CHARPOS (row->end.string_pos)); fprintf (stderr, "%9d %5d\n", row->start.dpvec_index, @@ -16894,7 +17344,7 @@ glyphs in short form, otherwise show glyphs in long form. */) struct window *w = XWINDOW (selected_window); struct buffer *buffer = XBUFFER (w->buffer); - fprintf (stderr, "PT = %d, BEGV = %d. ZV = %d\n", + fprintf (stderr, "PT = %"pI"d, BEGV = %"pI"d. ZV = %"pI"d\n", BUF_PT (buffer), BUF_BEGV (buffer), BUF_ZV (buffer)); fprintf (stderr, "Cursor x = %d, y = %d, hpos = %d, vpos = %d\n", w->cursor.x, w->cursor.y, w->cursor.hpos, w->cursor.vpos); @@ -16976,7 +17426,7 @@ With ARG, turn tracing on if and only if ARG is positive. */) DEFUN ("trace-to-stderr", Ftrace_to_stderr, Strace_to_stderr, 1, MANY, "", doc: /* Like `format', but print result to stderr. usage: (trace-to-stderr STRING &rest OBJECTS) */) - (size_t nargs, Lisp_Object *args) + (ptrdiff_t nargs, Lisp_Object *args) { Lisp_Object s = Fformat (nargs, args); fprintf (stderr, "%s", SDATA (s)); @@ -17567,7 +18017,8 @@ cursor_row_p (struct glyph_row *row) { int result = 1; - if (PT == CHARPOS (row->end.pos)) + if (PT == CHARPOS (row->end.pos) + || PT == MATRIX_ROW_END_CHARPOS (row)) { /* Suppose the row ends on a string. Unless the row is continued, that means it ends on a newline @@ -17628,14 +18079,25 @@ cursor_row_p (struct glyph_row *row) -/* Push the display property PROP so that it will be rendered at the - current position in IT. Return 1 if PROP was successfully pushed, - 0 otherwise. */ +/* Push the property PROP so that it will be rendered at the current + position in IT. Return 1 if PROP was successfully pushed, 0 + otherwise. Called from handle_line_prefix to handle the + `line-prefix' and `wrap-prefix' properties. */ static int push_display_prop (struct it *it, Lisp_Object prop) { - push_it (it, NULL); + struct text_pos pos = + (it->method == GET_FROM_STRING) ? it->current.string_pos : it->current.pos; + + xassert (it->method == GET_FROM_BUFFER + || it->method == GET_FROM_STRING); + + /* We need to save the current buffer/string position, so it will be + restored by pop_it, because iterate_out_of_display_property + depends on that being set correctly, but some situations leave + it->position not yet set when this function is called. */ + push_it (it, &pos); if (STRINGP (prop)) { @@ -17652,6 +18114,27 @@ push_display_prop (struct it *it, Lisp_Object prop) it->end_charpos = it->string_nchars = SCHARS (it->string); it->method = GET_FROM_STRING; it->stop_charpos = 0; + it->prev_stop = 0; + it->base_level_stop = 0; + + /* Force paragraph direction to be that of the parent + buffer/string. */ + if (it->bidi_p && it->bidi_it.paragraph_dir == R2L) + it->paragraph_embedding = it->bidi_it.paragraph_dir; + else + it->paragraph_embedding = L2R; + + /* Set up the bidi iterator for this display string. */ + if (it->bidi_p) + { + it->bidi_it.string.lstring = it->string; + it->bidi_it.string.s = NULL; + it->bidi_it.string.schars = it->end_charpos; + it->bidi_it.string.bufpos = IT_CHARPOS (*it); + 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); + } } else if (CONSP (prop) && EQ (XCAR (prop), Qspace)) { @@ -17698,6 +18181,7 @@ static void handle_line_prefix (struct it *it) { Lisp_Object prefix; + if (it->continuation_lines_width > 0) { prefix = get_it_property (it, Qwrap_prefix); @@ -17755,12 +18239,13 @@ find_row_edges (struct it *it, struct glyph_row *row, lines' rows is implemented for bidi-reordered rows. */ /* ROW->minpos is the value of min_pos, the minimal buffer position - we have in ROW. */ - if (min_pos <= ZV) + we have in ROW, or ROW->start.pos if that is smaller. */ + if (min_pos <= ZV && min_pos < row->start.pos.charpos) SET_TEXT_POS (row->minpos, min_pos, min_bpos); else - /* We didn't find _any_ valid buffer positions in any of the - glyphs, so we must trust the iterator's computed positions. */ + /* We didn't find buffer positions smaller than ROW->start, or + didn't find _any_ valid buffer positions in any of the glyphs, + so we must trust the iterator's computed positions. */ row->minpos = row->start.pos; if (max_pos <= 0) { @@ -17835,6 +18320,7 @@ display_line (struct it *it) struct glyph_row *row = it->glyph_row; Lisp_Object overlay_arrow_string; struct it wrap_it; + void *wrap_data = NULL; int may_wrap = 0, wrap_x IF_LINT (= 0); int wrap_row_used = -1; int wrap_row_ascent IF_LINT (= 0), wrap_row_height IF_LINT (= 0); @@ -17915,15 +18401,22 @@ display_line (struct it *it) #define RECORD_MAX_MIN_POS(IT) \ do \ { \ - if (IT_CHARPOS (*(IT)) < min_pos) \ + int composition_p = (IT)->what == IT_COMPOSITION; \ + EMACS_INT current_pos = \ + composition_p ? (IT)->cmp_it.charpos \ + : IT_CHARPOS (*(IT)); \ + EMACS_INT current_bpos = \ + composition_p ? CHAR_TO_BYTE (current_pos) \ + : IT_BYTEPOS (*(IT)); \ + if (current_pos < min_pos) \ { \ - min_pos = IT_CHARPOS (*(IT)); \ - min_bpos = IT_BYTEPOS (*(IT)); \ + min_pos = current_pos; \ + min_bpos = current_bpos; \ } \ - if (IT_CHARPOS (*(IT)) > max_pos) \ + if (IT_CHARPOS (*it) > max_pos) \ { \ - max_pos = IT_CHARPOS (*(IT)); \ - max_bpos = IT_BYTEPOS (*(IT)); \ + max_pos = IT_CHARPOS (*it); \ + max_bpos = IT_BYTEPOS (*it); \ } \ } \ while (0) @@ -17989,7 +18482,7 @@ display_line (struct it *it) may_wrap = 1; else if (may_wrap) { - wrap_it = *it; + SAVE_IT (wrap_it, *it, wrap_data); wrap_x = x; wrap_row_used = row->used[TEXT_AREA]; wrap_row_ascent = row->ascent; @@ -18159,7 +18652,7 @@ display_line (struct it *it) if (row->reversed_p) unproduce_glyphs (it, row->used[TEXT_AREA] - wrap_row_used); - *it = wrap_it; + RESTORE_IT (it, &wrap_it, wrap_data); it->continuation_lines_width += wrap_x; row->used[TEXT_AREA] = wrap_row_used; row->ascent = wrap_row_ascent; @@ -18370,6 +18863,9 @@ display_line (struct it *it) } } + if (wrap_data) + bidi_unshelve_cache (wrap_data, 1); + /* If line is not empty and hscrolled, maybe insert truncation glyphs at the left window margin. */ if (it->first_visible_x @@ -18527,7 +19023,8 @@ See also `bidi-paragraph-direction'. */) buf = XBUFFER (buffer); } - if (NILP (BVAR (buf, bidi_display_reordering))) + if (NILP (BVAR (buf, bidi_display_reordering)) + || NILP (BVAR (buf, enable_multibyte_characters))) return Qleft_to_right; else if (!NILP (BVAR (buf, bidi_paragraph_direction))) return BVAR (buf, bidi_paragraph_direction); @@ -18656,6 +19153,11 @@ display_menu_bar (struct window *w) } #endif /* not USE_X_TOOLKIT */ + /* FIXME: This should be controlled by a user option. See the + comments in redisplay_tool_bar and display_mode_line about + this. */ + it.paragraph_embedding = L2R; + if (! mode_line_inverse_video) /* Force the menu-bar to be displayed in the default face. */ it.base_face_id = it.face_id = DEFAULT_FACE_ID; @@ -18833,7 +19335,9 @@ display_mode_line (struct window *w, enum face_id face_id, Lisp_Object format) /* Force the mode-line to be displayed in the default face. */ it.base_face_id = it.face_id = DEFAULT_FACE_ID; - /* FIXME: This should take its value from a user option. */ + /* FIXME: This should be controlled by a user option. But + supporting such an option is not trivial, since the mode line is + made up of many separate strings. */ it.paragraph_embedding = L2R; record_unwind_protect (unwind_format_mode_line, @@ -18941,8 +19445,6 @@ display_mode_element (struct it *it, int depth, int field_width, int precision, int n = 0, field, prec; int literal = 0; - it->paragraph_embedding = L2R; - tail_recurse: if (depth > 100) elt = build_string ("*too-deep*"); @@ -19148,8 +19650,7 @@ display_mode_element (struct it *it, int depth, int field_width, int precision, break; case MODE_LINE_STRING: { - int len = strlen (spec); - Lisp_Object tem = make_string (spec, len); + Lisp_Object tem = build_string (spec); props = Ftext_properties_at (make_number (charpos), elt); /* Should only keep face property in props */ n += store_mode_line_string (NULL, tem, 0, field, prec, props); @@ -19792,7 +20293,8 @@ decode_mode_spec_coding (Lisp_Object coding_system, register char *buf, int eol_ else if (CHARACTERP (eoltype)) { unsigned char *tmp = (unsigned char *) alloca (MAX_MULTIBYTE_LENGTH); - eol_str_len = CHAR_STRING (XINT (eoltype), tmp); + int c = XFASTINT (eoltype); + eol_str_len = CHAR_STRING (c, tmp); eol_str = tmp; } else @@ -20908,8 +21410,7 @@ calc_pixel_width_or_height (double *res, struct it *it, Lisp_Object prop, #if GLYPH_DEBUG void -dump_glyph_string (s) - struct glyph_string *s; +dump_glyph_string (struct glyph_string *s) { fprintf (stderr, "glyph string\n"); fprintf (stderr, " x, y, w, h = %d, %d, %d, %d\n", @@ -20977,7 +21478,7 @@ init_glyph_string (struct glyph_string *s, /* Append the list of glyph strings with head H and tail T to the list with head *HEAD and tail *TAIL. Set *HEAD and *TAIL to the result. */ -static INLINE void +static inline void append_glyph_string_lists (struct glyph_string **head, struct glyph_string **tail, struct glyph_string *h, struct glyph_string *t) { @@ -20997,7 +21498,7 @@ append_glyph_string_lists (struct glyph_string **head, struct glyph_string **tai list with head *HEAD and tail *TAIL. Set *HEAD and *TAIL to the result. */ -static INLINE void +static inline void prepend_glyph_string_lists (struct glyph_string **head, struct glyph_string **tail, struct glyph_string *h, struct glyph_string *t) { @@ -21016,7 +21517,7 @@ prepend_glyph_string_lists (struct glyph_string **head, struct glyph_string **ta /* Append glyph string S to the list with head *HEAD and tail *TAIL. Set *HEAD and *TAIL to the resulting list. */ -static INLINE void +static inline void append_glyph_string (struct glyph_string **head, struct glyph_string **tail, struct glyph_string *s) { @@ -21031,7 +21532,7 @@ append_glyph_string (struct glyph_string **head, struct glyph_string **tail, Value is a pointer to a realized face that is ready for display if DISPLAY_P is non-zero. */ -static INLINE struct face * +static inline struct face * get_char_face_and_encoding (struct frame *f, int c, int face_id, XChar2b *char2b, int display_p) { @@ -21064,7 +21565,7 @@ get_char_face_and_encoding (struct frame *f, int c, int face_id, The encoding of GLYPH->u.ch is returned in *CHAR2B. Value is a pointer to a realized face that is ready for display. */ -static INLINE struct face * +static inline struct face * get_glyph_face_and_encoding (struct frame *f, struct glyph *glyph, XChar2b *char2b, int *two_byte_p) { @@ -21101,7 +21602,7 @@ get_glyph_face_and_encoding (struct frame *f, struct glyph *glyph, /* Get glyph code of character C in FONT in the two-byte form CHAR2B. Retunr 1 if FONT has a glyph for C, otherwise return 0. */ -static INLINE int +static inline int get_char_glyph_code (int c, struct font *font, XChar2b *char2b) { unsigned code; @@ -21565,7 +22066,7 @@ right_overwriting (struct glyph_string *s) first glyph following S. LAST_X is the right-most x-position + 1 in the drawing area. */ -static INLINE void +static inline void set_glyph_string_background_width (struct glyph_string *s, int start, int last_x) { /* If the face of this glyph string has to be drawn to the end of @@ -22127,7 +22628,7 @@ draw_glyphs (struct window *w, int x, struct glyph_row *row, /* Store one glyph for IT->char_to_display in IT->glyph_row. Called from x_produce_glyphs when IT->glyph_row is non-null. */ -static INLINE void +static inline void append_glyph (struct it *it) { struct glyph *glyph; @@ -22201,7 +22702,7 @@ append_glyph (struct it *it) IT->glyph_row. Called from x_produce_glyphs when IT->glyph_row is non-null. */ -static INLINE void +static inline void append_composite_glyph (struct it *it) { struct glyph *glyph; @@ -22270,7 +22771,7 @@ append_composite_glyph (struct it *it) /* Change IT->ascent and IT->height according to the setting of IT->voffset. */ -static INLINE void +static inline void take_vertical_position_into_account (struct it *it) { if (it->voffset) @@ -22843,7 +23344,7 @@ produce_glyphless_glyph (struct it *it, int for_no_font, Lisp_Object acronym) base_width = font->average_width; /* Get a face ID for the glyph by utilizing a cache (the same way as - doen for `escape-glyph' in get_next_display_element). */ + done for `escape-glyph' in get_next_display_element). */ if (it->f == last_glyphless_glyph_frame && it->face_id == last_glyphless_glyph_face_id) { @@ -23574,6 +24075,8 @@ x_produce_glyphs (struct it *it) Lisp_Object gstring; struct font_metrics metrics; + it->nglyphs = 1; + gstring = composition_gstring_from_id (it->cmp_it.id); it->pixel_width = composition_gstring_width (gstring, it->cmp_it.from, it->cmp_it.to, @@ -24746,7 +25249,7 @@ rows_from_pos_range (struct window *w, while (g < e) { - if (BUFFERP (g->object) + if ((BUFFERP (g->object) || INTEGERP (g->object)) && start_charpos <= g->charpos && g->charpos < end_charpos) *start = row; g++; @@ -24796,7 +25299,7 @@ rows_from_pos_range (struct window *w, while (g < e) { - if (BUFFERP (g->object) + if ((BUFFERP (g->object) || INTEGERP (g->object)) && start_charpos <= g->charpos && g->charpos < end_charpos) break; g++; @@ -25899,13 +26402,13 @@ note_mouse_highlight (struct frame *f, int x, int y) && XFASTINT (w->last_modified) == BUF_MODIFF (b) && XFASTINT (w->last_overlay_modified) == BUF_OVERLAY_MODIFF (b)) { - int hpos, vpos, i, dx, dy, area; + int hpos, vpos, dx, dy, area; EMACS_INT pos; struct glyph *glyph; Lisp_Object object; Lisp_Object mouse_face = Qnil, position; Lisp_Object *overlay_vec = NULL; - int noverlays; + ptrdiff_t i, noverlays; struct buffer *obuf; EMACS_INT obegv, ozv; int same_region; @@ -26828,7 +27331,7 @@ x_intersect_rectangles (XRectangle *r1, XRectangle *r2, XRectangle *result) { result->x = right->x; - /* The right end of the intersection is the minimum of the + /* The right end of the intersection is the minimum of the right ends of left and right. */ result->width = (min (left->x + left->width, right->x + right->width) - result->x); @@ -26873,8 +27376,7 @@ syms_of_xdisp (void) Vmessage_stack = Qnil; staticpro (&Vmessage_stack); - Qinhibit_redisplay = intern_c_string ("inhibit-redisplay"); - staticpro (&Qinhibit_redisplay); + DEFSYM (Qinhibit_redisplay, "inhibit-redisplay"); message_dolog_marker1 = Fmake_marker (); staticpro (&message_dolog_marker1); @@ -26899,141 +27401,72 @@ syms_of_xdisp (void) defsubr (&Sinvisible_p); defsubr (&Scurrent_bidi_paragraph_direction); - staticpro (&Qmenu_bar_update_hook); - Qmenu_bar_update_hook = intern_c_string ("menu-bar-update-hook"); - - staticpro (&Qoverriding_terminal_local_map); - Qoverriding_terminal_local_map = intern_c_string ("overriding-terminal-local-map"); - - staticpro (&Qoverriding_local_map); - Qoverriding_local_map = intern_c_string ("overriding-local-map"); - - staticpro (&Qwindow_scroll_functions); - Qwindow_scroll_functions = intern_c_string ("window-scroll-functions"); - - staticpro (&Qwindow_text_change_functions); - Qwindow_text_change_functions = intern_c_string ("window-text-change-functions"); - - staticpro (&Qredisplay_end_trigger_functions); - Qredisplay_end_trigger_functions = intern_c_string ("redisplay-end-trigger-functions"); - - staticpro (&Qinhibit_point_motion_hooks); - Qinhibit_point_motion_hooks = intern_c_string ("inhibit-point-motion-hooks"); - - Qeval = intern_c_string ("eval"); - staticpro (&Qeval); - - QCdata = intern_c_string (":data"); - staticpro (&QCdata); - Qdisplay = intern_c_string ("display"); - staticpro (&Qdisplay); - Qspace_width = intern_c_string ("space-width"); - staticpro (&Qspace_width); - Qraise = intern_c_string ("raise"); - staticpro (&Qraise); - Qslice = intern_c_string ("slice"); - staticpro (&Qslice); - Qspace = intern_c_string ("space"); - staticpro (&Qspace); - Qmargin = intern_c_string ("margin"); - staticpro (&Qmargin); - Qpointer = intern_c_string ("pointer"); - staticpro (&Qpointer); - Qleft_margin = intern_c_string ("left-margin"); - staticpro (&Qleft_margin); - Qright_margin = intern_c_string ("right-margin"); - staticpro (&Qright_margin); - Qcenter = intern_c_string ("center"); - staticpro (&Qcenter); - Qline_height = intern_c_string ("line-height"); - staticpro (&Qline_height); - QCalign_to = intern_c_string (":align-to"); - staticpro (&QCalign_to); - QCrelative_width = intern_c_string (":relative-width"); - staticpro (&QCrelative_width); - QCrelative_height = intern_c_string (":relative-height"); - staticpro (&QCrelative_height); - QCeval = intern_c_string (":eval"); - staticpro (&QCeval); - QCpropertize = intern_c_string (":propertize"); - staticpro (&QCpropertize); - QCfile = intern_c_string (":file"); - staticpro (&QCfile); - Qfontified = intern_c_string ("fontified"); - staticpro (&Qfontified); - Qfontification_functions = intern_c_string ("fontification-functions"); - staticpro (&Qfontification_functions); - Qtrailing_whitespace = intern_c_string ("trailing-whitespace"); - staticpro (&Qtrailing_whitespace); - Qescape_glyph = intern_c_string ("escape-glyph"); - staticpro (&Qescape_glyph); - Qnobreak_space = intern_c_string ("nobreak-space"); - staticpro (&Qnobreak_space); - Qimage = intern_c_string ("image"); - staticpro (&Qimage); - Qtext = intern_c_string ("text"); - staticpro (&Qtext); - Qboth = intern_c_string ("both"); - staticpro (&Qboth); - Qboth_horiz = intern_c_string ("both-horiz"); - staticpro (&Qboth_horiz); - Qtext_image_horiz = intern_c_string ("text-image-horiz"); - staticpro (&Qtext_image_horiz); - QCmap = intern_c_string (":map"); - staticpro (&QCmap); - QCpointer = intern_c_string (":pointer"); - staticpro (&QCpointer); - Qrect = intern_c_string ("rect"); - staticpro (&Qrect); - Qcircle = intern_c_string ("circle"); - staticpro (&Qcircle); - Qpoly = intern_c_string ("poly"); - staticpro (&Qpoly); - Qmessage_truncate_lines = intern_c_string ("message-truncate-lines"); - staticpro (&Qmessage_truncate_lines); - Qgrow_only = intern_c_string ("grow-only"); - staticpro (&Qgrow_only); - Qinhibit_menubar_update = intern_c_string ("inhibit-menubar-update"); - staticpro (&Qinhibit_menubar_update); - Qinhibit_eval_during_redisplay = intern_c_string ("inhibit-eval-during-redisplay"); - staticpro (&Qinhibit_eval_during_redisplay); - Qposition = intern_c_string ("position"); - staticpro (&Qposition); - Qbuffer_position = intern_c_string ("buffer-position"); - staticpro (&Qbuffer_position); - Qobject = intern_c_string ("object"); - staticpro (&Qobject); - Qbar = intern_c_string ("bar"); - staticpro (&Qbar); - Qhbar = intern_c_string ("hbar"); - staticpro (&Qhbar); - Qbox = intern_c_string ("box"); - staticpro (&Qbox); - Qhollow = intern_c_string ("hollow"); - staticpro (&Qhollow); - Qhand = intern_c_string ("hand"); - staticpro (&Qhand); - Qarrow = intern_c_string ("arrow"); - staticpro (&Qarrow); - Qtext = intern_c_string ("text"); - staticpro (&Qtext); - Qinhibit_free_realized_faces = intern_c_string ("inhibit-free-realized-faces"); - staticpro (&Qinhibit_free_realized_faces); + DEFSYM (Qmenu_bar_update_hook, "menu-bar-update-hook"); + DEFSYM (Qoverriding_terminal_local_map, "overriding-terminal-local-map"); + DEFSYM (Qoverriding_local_map, "overriding-local-map"); + DEFSYM (Qwindow_scroll_functions, "window-scroll-functions"); + DEFSYM (Qwindow_text_change_functions, "window-text-change-functions"); + DEFSYM (Qredisplay_end_trigger_functions, "redisplay-end-trigger-functions"); + DEFSYM (Qinhibit_point_motion_hooks, "inhibit-point-motion-hooks"); + DEFSYM (Qeval, "eval"); + DEFSYM (QCdata, ":data"); + DEFSYM (Qdisplay, "display"); + DEFSYM (Qspace_width, "space-width"); + DEFSYM (Qraise, "raise"); + DEFSYM (Qslice, "slice"); + DEFSYM (Qspace, "space"); + DEFSYM (Qmargin, "margin"); + DEFSYM (Qpointer, "pointer"); + DEFSYM (Qleft_margin, "left-margin"); + DEFSYM (Qright_margin, "right-margin"); + DEFSYM (Qcenter, "center"); + DEFSYM (Qline_height, "line-height"); + DEFSYM (QCalign_to, ":align-to"); + DEFSYM (QCrelative_width, ":relative-width"); + DEFSYM (QCrelative_height, ":relative-height"); + DEFSYM (QCeval, ":eval"); + DEFSYM (QCpropertize, ":propertize"); + DEFSYM (QCfile, ":file"); + DEFSYM (Qfontified, "fontified"); + DEFSYM (Qfontification_functions, "fontification-functions"); + DEFSYM (Qtrailing_whitespace, "trailing-whitespace"); + DEFSYM (Qescape_glyph, "escape-glyph"); + DEFSYM (Qnobreak_space, "nobreak-space"); + DEFSYM (Qimage, "image"); + DEFSYM (Qtext, "text"); + DEFSYM (Qboth, "both"); + DEFSYM (Qboth_horiz, "both-horiz"); + DEFSYM (Qtext_image_horiz, "text-image-horiz"); + DEFSYM (QCmap, ":map"); + DEFSYM (QCpointer, ":pointer"); + DEFSYM (Qrect, "rect"); + DEFSYM (Qcircle, "circle"); + DEFSYM (Qpoly, "poly"); + DEFSYM (Qmessage_truncate_lines, "message-truncate-lines"); + DEFSYM (Qgrow_only, "grow-only"); + DEFSYM (Qinhibit_menubar_update, "inhibit-menubar-update"); + DEFSYM (Qinhibit_eval_during_redisplay, "inhibit-eval-during-redisplay"); + DEFSYM (Qposition, "position"); + DEFSYM (Qbuffer_position, "buffer-position"); + DEFSYM (Qobject, "object"); + DEFSYM (Qbar, "bar"); + DEFSYM (Qhbar, "hbar"); + DEFSYM (Qbox, "box"); + DEFSYM (Qhollow, "hollow"); + DEFSYM (Qhand, "hand"); + DEFSYM (Qarrow, "arrow"); + DEFSYM (Qtext, "text"); + DEFSYM (Qinhibit_free_realized_faces, "inhibit-free-realized-faces"); list_of_error = Fcons (Fcons (intern_c_string ("error"), Fcons (intern_c_string ("void-variable"), Qnil)), Qnil); staticpro (&list_of_error); - Qlast_arrow_position = intern_c_string ("last-arrow-position"); - staticpro (&Qlast_arrow_position); - Qlast_arrow_string = intern_c_string ("last-arrow-string"); - staticpro (&Qlast_arrow_string); - - Qoverlay_arrow_string = intern_c_string ("overlay-arrow-string"); - staticpro (&Qoverlay_arrow_string); - Qoverlay_arrow_bitmap = intern_c_string ("overlay-arrow-bitmap"); - staticpro (&Qoverlay_arrow_bitmap); + DEFSYM (Qlast_arrow_position, "last-arrow-position"); + DEFSYM (Qlast_arrow_string, "last-arrow-string"); + DEFSYM (Qoverlay_arrow_string, "overlay-arrow-string"); + DEFSYM (Qoverlay_arrow_bitmap, "overlay-arrow-bitmap"); echo_buffer[0] = echo_buffer[1] = Qnil; staticpro (&echo_buffer[0]); @@ -27067,10 +27500,8 @@ syms_of_xdisp (void) staticpro (&previous_help_echo_string); help_echo_pos = -1; - Qright_to_left = intern_c_string ("right-to-left"); - staticpro (&Qright_to_left); - Qleft_to_right = intern_c_string ("left-to-right"); - staticpro (&Qleft_to_right); + DEFSYM (Qright_to_left, "right-to-left"); + DEFSYM (Qleft_to_right, "left-to-right"); #ifdef HAVE_WINDOW_SYSTEM DEFVAR_BOOL ("x-stretch-cursor", x_stretch_cursor_p, @@ -27359,18 +27790,18 @@ but does not change the fact they are interpreted as raw bytes. */); unibyte_display_via_language_environment = 0; DEFVAR_LISP ("max-mini-window-height", Vmax_mini_window_height, - doc: /* *Maximum height for resizing mini-windows. + doc: /* *Maximum height for resizing mini-windows (the minibuffer and the echo area). If a float, it specifies a fraction of the mini-window frame's height. If an integer, it specifies a number of lines. */); Vmax_mini_window_height = make_float (0.25); DEFVAR_LISP ("resize-mini-windows", Vresize_mini_windows, - doc: /* *How to resize mini-windows. + doc: /* How to resize mini-windows (the minibuffer and the echo area). A value of nil means don't automatically resize mini-windows. A value of t means resize them to fit the text displayed in them. -A value of `grow-only', the default, means let mini-windows grow -only, until their display becomes empty, at which point the windows -go back to their normal size. */); +A value of `grow-only', the default, means let mini-windows grow only; +they return to their normal size when the minibuffer is closed, or the +echo area becomes empty. */); Vresize_mini_windows = Qgrow_only; DEFVAR_LISP ("blink-cursor-alist", Vblink_cursor_alist, @@ -27390,8 +27821,7 @@ the frame's other specifications determine how to blink the cursor off. */); If non-nil, windows are automatically scrolled horizontally to make point visible. */); automatic_hscrolling_p = 1; - Qauto_hscroll_mode = intern_c_string ("auto-hscroll-mode"); - staticpro (&Qauto_hscroll_mode); + DEFSYM (Qauto_hscroll_mode, "auto-hscroll-mode"); DEFVAR_INT ("hscroll-margin", hscroll_margin, doc: /* *How many columns away from the window edge point is allowed to get @@ -27447,8 +27877,7 @@ property. To add a prefix to non-continuation lines, use `line-prefix'. */); Vwrap_prefix = Qnil; - staticpro (&Qwrap_prefix); - Qwrap_prefix = intern_c_string ("wrap-prefix"); + DEFSYM (Qwrap_prefix, "wrap-prefix"); Fmake_variable_buffer_local (Qwrap_prefix); DEFVAR_LISP ("line-prefix", Vline_prefix, @@ -27461,8 +27890,7 @@ property. To add a prefix to continuation lines, use `wrap-prefix'. */); Vline_prefix = Qnil; - staticpro (&Qline_prefix); - Qline_prefix = intern_c_string ("line-prefix"); + DEFSYM (Qline_prefix, "line-prefix"); Fmake_variable_buffer_local (Qline_prefix); DEFVAR_BOOL ("inhibit-eval-during-redisplay", inhibit_eval_during_redisplay, @@ -27555,31 +27983,27 @@ Its value should be an ASCII acronym string, `hex-code', `empty-box', or void init_xdisp (void) { - Lisp_Object root_window; - struct window *mini_w; - current_header_line_height = current_mode_line_height = -1; CHARPOS (this_line_start_pos) = 0; - mini_w = XWINDOW (minibuf_window); - root_window = FRAME_ROOT_WINDOW (XFRAME (WINDOW_FRAME (mini_w))); - echo_area_window = minibuf_window; - if (!noninteractive) { - struct frame *f = XFRAME (WINDOW_FRAME (XWINDOW (root_window))); + struct window *m = XWINDOW (minibuf_window); + Lisp_Object frame = m->frame; + struct frame *f = XFRAME (frame); + Lisp_Object root = FRAME_ROOT_WINDOW (f); + struct window *r = XWINDOW (root); int i; - XWINDOW (root_window)->top_line = make_number (FRAME_TOP_MARGIN (f)); - set_window_height (root_window, - FRAME_LINES (f) - 1 - FRAME_TOP_MARGIN (f), - 0); - mini_w->top_line = make_number (FRAME_LINES (f) - 1); - set_window_height (minibuf_window, 1, 0); + echo_area_window = minibuf_window; - XWINDOW (root_window)->total_cols = make_number (FRAME_COLS (f)); - mini_w->total_cols = make_number (FRAME_COLS (f)); + XSETFASTINT (r->top_line, FRAME_TOP_MARGIN (f)); + XSETFASTINT (r->total_lines, FRAME_LINES (f) - 1 - FRAME_TOP_MARGIN (f)); + XSETFASTINT (r->total_cols, FRAME_COLS (f)); + XSETFASTINT (m->top_line, FRAME_LINES (f) - 1); + XSETFASTINT (m->total_lines, 1); + XSETFASTINT (m->total_cols, FRAME_COLS (f)); scratch_glyph_row.glyphs[TEXT_AREA] = scratch_glyphs; scratch_glyph_row.glyphs[TEXT_AREA + 1]