if (CACHE) \
bidi_unshelve_cache (CACHE, 1); \
ITCOPY = ITORIG; \
- CACHE = bidi_shelve_cache(); \
+ CACHE = bidi_shelve_cache (); \
} while (0)
#define RESTORE_IT(pITORIG,pITCOPY,CACHE) \
This is the height of W minus the height of a mode line, if any. */
-inline int
+int
window_text_bottom_y (struct window *w)
{
int height = WINDOW_TOTAL_HEIGHT (w);
means return the total width of W, not including fringes to
the left and right of the window. */
-inline int
+int
window_box_width (struct window *w, int area)
{
int cols = XFASTINT (w->total_cols);
/* Return the pixel height of the display area of window W, not
including mode lines of W, if any. */
-inline int
+int
window_box_height (struct window *w)
{
struct frame *f = XFRAME (w->frame);
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
+int
window_box_left_offset (struct window *w, int area)
{
int x;
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
+int
window_box_right_offset (struct window *w, int area)
{
return window_box_left_offset (w, area) + window_box_width (w, 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
+int
window_box_left (struct window *w, int area)
{
struct frame *f = XFRAME (w->frame);
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
+int
window_box_right (struct window *w, int area)
{
return window_box_left (w, area) + window_box_width (w, 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
+void
window_box (struct window *w, int area, int *box_x, int *box_y,
int *box_width, int *box_height)
{
return line_top_y + line_height;
}
+/* Subroutine of pos_visible_p below. Extracts a display string, if
+ any, from the display spec given as its argument. */
+static Lisp_Object
+string_from_display_spec (Lisp_Object spec)
+{
+ if (CONSP (spec))
+ {
+ while (CONSP (spec))
+ {
+ if (STRINGP (XCAR (spec)))
+ return XCAR (spec);
+ spec = XCDR (spec);
+ }
+ }
+ else if (VECTORP (spec))
+ {
+ ptrdiff_t i;
+
+ for (i = 0; i < ASIZE (spec); i++)
+ {
+ if (STRINGP (AREF (spec, i)))
+ return AREF (spec, i);
+ }
+ return Qnil;
+ }
+
+ return spec;
+}
/* Return 1 if position CHARPOS is visible in window W.
CHARPOS < 0 means return info about WINDOW_END position.
}
}
}
+ else if (IT_CHARPOS (it) != charpos)
+ {
+ Lisp_Object cpos = make_number (charpos);
+ Lisp_Object spec = Fget_char_property (cpos, Qdisplay, Qnil);
+ Lisp_Object string = string_from_display_spec (spec);
+ int newline_in_string = 0;
+
+ if (STRINGP (string))
+ {
+ const char *s = SSDATA (string);
+ const char *e = s + SBYTES (string);
+ while (s < e)
+ {
+ if (*s++ == '\n')
+ {
+ newline_in_string = 1;
+ break;
+ }
+ }
+ }
+ /* The tricky code below is needed because there's a
+ discrepancy between move_it_to and how we set cursor
+ when the display line ends in a newline from a
+ display string. move_it_to will stop _after_ such
+ display strings, whereas set_cursor_from_row
+ conspires with cursor_row_p to place the cursor on
+ the first glyph produced from the display string. */
+
+ /* We have overshoot PT because it is covered by a
+ display property whose value is a string. If the
+ string includes embedded newlines, we are also in the
+ wrong display line. Backtrack to the correct line,
+ where the display string begins. */
+ if (newline_in_string)
+ {
+ Lisp_Object startpos, endpos;
+ EMACS_INT start, end;
+ struct it it3;
+
+ /* Find the first and the last buffer positions
+ covered by the display string. */
+ endpos =
+ Fnext_single_char_property_change (cpos, Qdisplay,
+ Qnil, Qnil);
+ startpos =
+ Fprevious_single_char_property_change (endpos, Qdisplay,
+ Qnil, Qnil);
+ start = XFASTINT (startpos);
+ end = XFASTINT (endpos);
+ /* Move to the last buffer position before the
+ display property. */
+ start_display (&it3, w, top);
+ move_it_to (&it3, start - 1, -1, -1, -1, MOVE_TO_POS);
+ /* Move forward one more line if the position before
+ the display string is a newline or if it is the
+ rightmost character on a line that is
+ continued or word-wrapped. */
+ if (it3.method == GET_FROM_BUFFER
+ && it3.c == '\n')
+ move_it_by_lines (&it3, 1);
+ else if (move_it_in_display_line_to (&it3, -1,
+ it3.current_x
+ + it3.pixel_width,
+ MOVE_TO_X)
+ == MOVE_LINE_CONTINUED)
+ {
+ move_it_by_lines (&it3, 1);
+ /* When we are under word-wrap, the #$@%!
+ move_it_by_lines moves 2 lines, so we need to
+ fix that up. */
+ if (it3.line_wrap == WORD_WRAP)
+ move_it_by_lines (&it3, -1);
+ }
+
+ /* Record the vertical coordinate of the display
+ line where we wound up. */
+ top_y = it3.current_y;
+ if (it3.bidi_p)
+ {
+ /* When characters are reordered for display,
+ the character displayed to the left of the
+ display string could be _after_ the display
+ property in the logical order. Use the
+ smallest vertical position of these two. */
+ start_display (&it3, w, top);
+ move_it_to (&it3, end + 1, -1, -1, -1, MOVE_TO_POS);
+ if (it3.current_y < top_y)
+ top_y = it3.current_y;
+ }
+ /* Move from the top of the window to the beginning
+ of the display line where the display string
+ begins. */
+ start_display (&it3, w, top);
+ move_it_to (&it3, -1, 0, top_y, -1, MOVE_TO_X | MOVE_TO_Y);
+ /* Finally, advance the iterator until we hit the
+ first display element whose character position is
+ CHARPOS, or until the first newline from the
+ display string, which signals the end of the
+ display line. */
+ while (get_next_display_element (&it3))
+ {
+ PRODUCE_GLYPHS (&it3);
+ if (IT_CHARPOS (it3) == charpos
+ || ITERATOR_AT_END_OF_LINE_P (&it3))
+ break;
+ set_iterator_to_next (&it3, 0);
+ }
+ top_x = it3.current_x - it3.pixel_width;
+ /* Normally, we would exit the above loop because we
+ found the display element whose character
+ position is CHARPOS. For the contingency that we
+ didn't, and stopped at the first newline from the
+ display string, move back over the glyphs
+ produced from the string, until we find the
+ rightmost glyph not from the string. */
+ if (IT_CHARPOS (it3) != charpos && EQ (it3.object, string))
+ {
+ struct glyph *g = it3.glyph_row->glyphs[TEXT_AREA]
+ + it3.glyph_row->used[TEXT_AREA];
+
+ while (EQ ((g - 1)->object, string))
+ {
+ --g;
+ top_x -= g->pixel_width;
+ }
+ xassert (g < it3.glyph_row->glyphs[TEXT_AREA]
+ + it3.glyph_row->used[TEXT_AREA]);
+ }
+ }
+ }
*x = top_x;
*y = max (top_y + max (0, it.max_ascent - it.ascent), window_top_y);
rectangle as wide as the glyph, but use a canonical character
width instead. */
wd = glyph->pixel_width - 1;
-#if defined(HAVE_NTGUI) || defined(HAVE_NS)
+#if defined (HAVE_NTGUI) || defined (HAVE_NS)
wd++; /* Why? */
#endif
else if (INTEGERP (w->redisplay_end_trigger))
it->redisplay_end_trigger_charpos = XINT (w->redisplay_end_trigger);
- /* Correct bogus values of tab_width. */
- it->tab_width = XINT (BVAR (current_buffer, tab_width));
- if (it->tab_width <= 0 || it->tab_width > 1000)
- it->tab_width = 8;
+ it->tab_width = SANE_TAB_WIDTH (current_buffer);
/* Are lines in the display truncated? */
if (base_face_id != DEFAULT_FACE_ID
/* Do we need to reorder bidirectional text? Not if this is a
unibyte buffer: by definition, none of the single-byte
characters are strong R2L, so no reordering is needed. And
- bidi.c doesn't support unibyte buffers anyway. */
+ bidi.c doesn't support unibyte buffers anyway. Also, don't
+ reorder while we are loading loadup.el, since the tables of
+ character properties needed for reordering are not yet
+ available. */
it->bidi_p =
- !NILP (BVAR (current_buffer, bidi_display_reordering))
+ NILP (Vpurify_flag)
+ && !NILP (BVAR (current_buffer, bidi_display_reordering))
&& it->multibyte_p;
/* If we are to reorder bidirectional text, init the bidi
it->continuation_lines_width += it->current_x;
}
+ /* If the character at POS is displayed via a display
+ vector, move_it_to above stops at the final glyph of
+ IT->dpvec. To make the caller redisplay that character
+ again (a.k.a. start at POS), we need to reset the
+ dpvec_index to the beginning of IT->dpvec. */
+ else if (it->current.dpvec_index >= 0)
+ it->current.dpvec_index = 0;
/* We're starting a new display line, not affected by the
height of the continued line, so clear the appropriate
}
/* 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
+ display string. Searching too far forward makes the bidi display
+ sluggish, especially in small windows. */
+#define MAX_DISP_SCAN 250
/* Return the character position of a display string at or after
position specified by POSITION. If no display string exists at or
text property whose value is a string. STRING is data about the
string to iterate; if STRING->lstring is nil, we are iterating a
buffer. FRAME_WINDOW_P is non-zero when we are displaying a window
- on a GUI frame. */
+ on a GUI frame. DISP_PROP is set to zero if we searched
+ MAX_DISP_SCAN characters forward without finding any display
+ strings, non-zero otherwise. It is set to 2 if the display string
+ uses any kind of `(space ...)' spec that will produce a stretch of
+ white space in the text area. */
EMACS_INT
compute_display_string_pos (struct text_pos *position,
struct bidi_string_data *string,
- int frame_window_p, int *disp_prop_p)
+ int frame_window_p, int *disp_prop)
{
/* OBJECT = nil means current buffer. */
Lisp_Object object =
EMACS_INT lim =
(charpos < eob - MAX_DISP_SCAN) ? charpos + MAX_DISP_SCAN : eob;
struct text_pos tpos;
+ int rv = 0;
- *disp_prop_p = 1;
+ *disp_prop = 1;
if (charpos >= eob
/* We don't support display properties whose values are strings
/* C strings cannot have display properties. */
|| (string->s && !STRINGP (object)))
{
- *disp_prop_p = 0;
+ *disp_prop = 0;
return eob;
}
|| !EQ (Fget_char_property (make_number (charpos - 1), Qdisplay,
object),
spec))
- && handle_display_spec (NULL, spec, object, Qnil, &tpos, bufpos,
- frame_window_p))
+ && (rv = handle_display_spec (NULL, spec, object, Qnil, &tpos, bufpos,
+ frame_window_p)))
{
+ if (rv == 2)
+ *disp_prop = 2;
return charpos;
}
CHARPOS (tpos) = XFASTINT (pos);
if (CHARPOS (tpos) >= lim)
{
- *disp_prop_p = 0;
+ *disp_prop = 0;
break;
}
if (STRINGP (object))
if (!STRINGP (object))
bufpos = CHARPOS (tpos);
} while (NILP (spec)
- || !handle_display_spec (NULL, spec, object, Qnil, &tpos, bufpos,
- frame_window_p));
+ || !(rv = handle_display_spec (NULL, spec, object, Qnil, &tpos,
+ bufpos, frame_window_p)));
+ if (rv == 2)
+ *disp_prop = 2;
return CHARPOS (tpos);
}
/* Return the character position of the end of the display string that
- started at CHARPOS. A display string is either an overlay with
- `display' property whose value is a string or a `display' text
- property whose value is a string. */
+ started at CHARPOS. If there's no display string at CHARPOS,
+ return -1. A display string is either an overlay with `display'
+ property whose value is a string or a `display' text property whose
+ value is a string. */
EMACS_INT
compute_display_string_end (EMACS_INT charpos, struct bidi_string_data *string)
{
if (charpos >= eob || (string->s && !STRINGP (object)))
return eob;
+ /* It could happen that the display property or overlay was removed
+ since we found it in compute_display_string_pos above. One way
+ this can happen is if JIT font-lock was called (through
+ handle_fontified_prop), and jit-lock-functions remove text
+ properties or overlays from the portion of buffer that includes
+ CHARPOS. Muse mode is known to do that, for example. In this
+ case, we return -1 to the caller, to signal that no display
+ string is actually present at CHARPOS. See bidi_fetch_char for
+ how this is handled.
+
+ An alternative would be to never look for display properties past
+ it->stop_charpos. But neither compute_display_string_pos nor
+ bidi_fetch_char that calls it know or care where the next
+ stop_charpos is. */
if (NILP (Fget_char_property (pos, Qdisplay, object)))
- abort ();
+ return -1;
/* Look forward for the first character where the `display' property
changes. */
/* The position newpos is now either ZV or on visible text. */
if (it->bidi_p && newpos < ZV)
{
- /* With bidi iteration, the region of invisible text
- could start and/or end in the middle of a non-base
- embedding level. Therefore, we need to skip
- invisible text using the bidi iterator, starting at
- IT's current position, until we find ourselves
- outside the invisible text. Skipping invisible text
- _after_ bidi iteration avoids affecting the visual
- order of the displayed text when invisible properties
- are added or removed. */
- if (it->bidi_it.first_elt && it->bidi_it.charpos < ZV)
+ EMACS_INT bpos = CHAR_TO_BYTE (newpos);
+
+ if (FETCH_BYTE (bpos) == '\n'
+ || (newpos > BEGV && FETCH_BYTE (bpos - 1) == '\n'))
{
- /* If we were `reseat'ed to a new paragraph,
- determine the paragraph base direction. We need
- to do it now because next_element_from_buffer may
- not have a chance to do it, if we are going to
- skip any text at the beginning, which resets the
- FIRST_ELT flag. */
- bidi_paragraph_init (it->paragraph_embedding,
- &it->bidi_it, 1);
+ /* If the invisible text ends on a newline or the
+ character after a newline, we can avoid the
+ costly, character by character, bidi iteration to
+ newpos, and instead simply reseat the iterator
+ there. That's because all bidi reordering
+ information is tossed at the newline. This is a
+ big win for modes that hide complete lines, like
+ Outline, Org, etc. (Implementation note: the
+ call to reseat_1 is necessary, because it signals
+ to the bidi iterator that it needs to reinit its
+ internal information when the next element for
+ display is requested. */
+ struct text_pos tpos;
+
+ SET_TEXT_POS (tpos, newpos, bpos);
+ reseat_1 (it, tpos, 0);
}
- do
+ else /* Must use the slow method. */
{
- bidi_move_to_visually_next (&it->bidi_it);
+ /* With bidi iteration, the region of invisible text
+ could start and/or end in the middle of a
+ non-base embedding level. Therefore, we need to
+ skip invisible text using the bidi iterator,
+ starting at IT's current position, until we find
+ ourselves outside the invisible text. Skipping
+ invisible text _after_ bidi iteration avoids
+ affecting the visual order of the displayed text
+ when invisible properties are added or
+ removed. */
+ if (it->bidi_it.first_elt && it->bidi_it.charpos < ZV)
+ {
+ /* If we were `reseat'ed to a new paragraph,
+ determine the paragraph base direction. We
+ need to do it now because
+ next_element_from_buffer may not have a
+ chance to do it, if we are going to skip any
+ text at the beginning, which resets the
+ FIRST_ELT flag. */
+ bidi_paragraph_init (it->paragraph_embedding,
+ &it->bidi_it, 1);
+ }
+ do
+ {
+ bidi_move_to_visually_next (&it->bidi_it);
+ }
+ while (it->stop_charpos <= it->bidi_it.charpos
+ && it->bidi_it.charpos < newpos);
+ IT_CHARPOS (*it) = it->bidi_it.charpos;
+ IT_BYTEPOS (*it) = it->bidi_it.bytepos;
+ /* If we overstepped NEWPOS, record its position in
+ the iterator, so that we skip invisible text if
+ later the bidi iteration lands us in the
+ invisible region again. */
+ if (IT_CHARPOS (*it) >= newpos)
+ it->prev_stop = newpos;
}
- while (it->stop_charpos <= it->bidi_it.charpos
- && it->bidi_it.charpos < newpos);
- IT_CHARPOS (*it) = it->bidi_it.charpos;
- IT_BYTEPOS (*it) = it->bidi_it.bytepos;
- /* If we overstepped NEWPOS, record its position in the
- iterator, so that we skip invisible text if later the
- bidi iteration lands us in the invisible region
- again. */
- if (IT_CHARPOS (*it) >= newpos)
- it->prev_stop = newpos;
}
else
{
/* Subroutine of handle_display_prop. Returns non-zero if the display
specification in SPEC is a replacing specification, i.e. it would
replace the text covered by `display' property with something else,
- such as an image or a display string.
+ such as an image or a display string. If SPEC includes any kind or
+ `(space ...) specification, the value is 2; this is used by
+ compute_display_string_pos, which see.
See handle_single_display_spec for documentation of arguments.
frame_window_p is non-zero if the window being redisplayed is on a
EMACS_INT bufpos, int frame_window_p)
{
int replacing_p = 0;
+ int rv;
if (CONSP (spec)
/* Simple specerties. */
{
for (; CONSP (spec); spec = XCDR (spec))
{
- if (handle_single_display_spec (it, XCAR (spec), object, overlay,
- position, bufpos, replacing_p,
- frame_window_p))
+ if ((rv = handle_single_display_spec (it, XCAR (spec), object,
+ overlay, position, bufpos,
+ replacing_p, frame_window_p)))
{
- replacing_p = 1;
+ replacing_p = rv;
/* If some text in a string is replaced, `position' no
longer points to the position of `object'. */
if (!it || STRINGP (object))
{
int i;
for (i = 0; i < ASIZE (spec); ++i)
- if (handle_single_display_spec (it, AREF (spec, i), object, overlay,
- position, bufpos, replacing_p,
- frame_window_p))
+ if ((rv = handle_single_display_spec (it, AREF (spec, i), object,
+ overlay, position, bufpos,
+ replacing_p, frame_window_p)))
{
- replacing_p = 1;
+ replacing_p = rv;
/* If some text in a string is replaced, `position' no
longer points to the position of `object'. */
if (!it || STRINGP (object))
}
else
{
- if (handle_single_display_spec (it, spec, object, overlay,
- position, bufpos, 0, frame_window_p))
- replacing_p = 1;
+ if ((rv = handle_single_display_spec (it, spec, object, overlay,
+ position, bufpos, 0,
+ frame_window_p)))
+ replacing_p = rv;
}
return replacing_p;
if (valid_p && !display_replaced_p)
{
+ int retval = 1;
+
if (!it)
- return 1;
+ {
+ /* Callers need to know whether the display spec is any kind
+ of `(space ...)' spec that is about to affect text-area
+ display. */
+ if (CONSP (value) && EQ (XCAR (value), Qspace) && NILP (location))
+ retval = 2;
+ return retval;
+ }
/* Save current settings of IT so that we can restore them
when we are finished with the glyph property value. */
it->method = GET_FROM_STRETCH;
it->object = value;
*position = it->position = start_pos;
+ retval = 1 + (it->area == TEXT_AREA);
}
#ifdef HAVE_WINDOW_SYSTEM
else
}
#endif /* HAVE_WINDOW_SYSTEM */
- return 1;
+ return retval;
}
/* Invalid property or property not supported. Restore
&& 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));
+ && IT_STRING_BYTEPOS (*it) == it->bidi_it.bytepos)
+ || (CONSP (it->object) && it->method == GET_FROM_STRETCH));
}
}
if (it->bidi_it.disp_pos < limit)
{
it->bidi_it.disp_pos = limit;
- it->bidi_it.disp_prop_p = 0;
+ it->bidi_it.disp_prop = 0;
}
do {
bprev = it->bidi_it;
it->multibyte_p = multibyte > 0;
/* Bidirectional reordering of strings is controlled by the default
- value of bidi-display-reordering. */
- it->bidi_p = !NILP (BVAR (&buffer_defaults, bidi_display_reordering));
+ value of bidi-display-reordering. Don't try to reorder while
+ loading loadup.el, as the necessary character property tables are
+ not yet available. */
+ it->bidi_p =
+ NILP (Vpurify_flag)
+ && !NILP (BVAR (&buffer_defaults, bidi_display_reordering));
if (s == NULL)
{
{
Lisp_Object dv;
struct charset *unibyte = CHARSET_FROM_ID (charset_unibyte);
- enum { char_is_other = 0, char_is_nbsp, char_is_soft_hyphen }
- nbsp_or_shy = char_is_other;
+ int nonascii_space_p = 0;
+ int nonascii_hyphen_p = 0;
int c = it->c; /* This is the character to display. */
if (! it->multibyte_p && ! ASCII_CHAR_P (c))
goto get_next;
}
+ /* If `nobreak-char-display' is non-nil, we display
+ non-ASCII spaces and hyphens specially. */
if (! ASCII_CHAR_P (c) && ! NILP (Vnobreak_char_display))
- nbsp_or_shy = (c == 0xA0 ? char_is_nbsp
- : c == 0xAD ? char_is_soft_hyphen
- : char_is_other);
+ {
+ if (c == 0xA0)
+ nonascii_space_p = 1;
+ else if (c == 0xAD || c == 0x2010 || c == 0x2011)
+ nonascii_hyphen_p = 1;
+ }
/* Translate control characters into `\003' or `^C' form.
Control characters coming from a display table entry are
the translation. This could easily be changed but I
don't believe that it is worth doing.
- NBSP and SOFT-HYPEN are property translated too.
+ The characters handled by `nobreak-char-display' must be
+ translated too.
Non-printable characters and raw-byte characters are also
translated to octal form. */
&& it->glyph_row
&& (it->glyph_row->mode_line_p || it->avoid_cursor_p))
|| (c != '\n' && c != '\t'))
- : (nbsp_or_shy
+ : (nonascii_space_p
+ || nonascii_hyphen_p
|| CHAR_BYTE8_P (c)
|| ! CHAR_PRINTABLE_P (c))))
{
- /* C is a control character, NBSP, SOFT-HYPEN, raw-byte,
- or a non-printable character which must be displayed
- either as '\003' or as `^C' where the '\\' and '^'
- can be defined in the display table. Fill
+ /* C is a control character, non-ASCII space/hyphen,
+ raw-byte, or a non-printable character which must be
+ displayed either as '\003' or as `^C' where the '\\'
+ and '^' can be defined in the display table. Fill
IT->ctl_chars with glyphs for what we have to
display. Then, set IT->dpvec to these glyphs. */
Lisp_Object gc;
goto display_control;
}
- /* Handle non-break space in the mode where it only gets
+ /* Handle non-ascii space in the mode where it only gets
highlighting. */
- if (EQ (Vnobreak_char_display, Qt)
- && nbsp_or_shy == char_is_nbsp)
+ if (nonascii_space_p && EQ (Vnobreak_char_display, Qt))
{
- /* Merge the no-break-space face into the current face. */
+ /* Merge `nobreak-space' into the current face. */
face_id = merge_faces (it->f, Qnobreak_space, 0,
it->face_id);
-
- c = ' ';
XSETINT (it->ctl_chars[0], ' ');
ctl_len = 1;
goto display_control;
last_escape_glyph_merged_face_id = face_id;
}
- /* Handle soft hyphens in the mode where they only get
- highlighting. */
+ /* Draw non-ASCII hyphen with just highlighting: */
- if (EQ (Vnobreak_char_display, Qt)
- && nbsp_or_shy == char_is_soft_hyphen)
+ if (nonascii_hyphen_p && EQ (Vnobreak_char_display, Qt))
{
XSETINT (it->ctl_chars[0], '-');
ctl_len = 1;
goto display_control;
}
- /* Handle non-break space and soft hyphen
- with the escape glyph. */
+ /* Draw non-ASCII space/hyphen with escape glyph: */
- if (nbsp_or_shy)
+ if (nonascii_space_p || nonascii_hyphen_p)
{
XSETINT (it->ctl_chars[0], escape_glyph);
- c = (nbsp_or_shy == char_is_nbsp ? ' ' : '-');
- XSETINT (it->ctl_chars[1], c);
+ XSETINT (it->ctl_chars[1], nonascii_space_p ? ' ' : '-');
ctl_len = 2;
goto display_control;
}
c = ' ';
for (i = 0; i < cmp->glyph_len; i++)
+ /* TAB in a composition means display glyphs with
+ padding space on the left or right. */
if ((c = COMPOSITION_GLYPH (cmp, i)) != '\t')
break;
}
}
else if (it->bidi_it.charpos == bob
|| (!string_p
- /* FIXME: Should support all Unicode line separators. */
&& (FETCH_CHAR (it->bidi_it.bytepos - 1) == '\n'
|| FETCH_CHAR (it->bidi_it.bytepos) == '\n')))
{
((op & MOVE_TO_POS) != 0 \
&& BUFFERP (it->object) \
&& (IT_CHARPOS (*it) == to_charpos \
- || (!it->bidi_p && IT_CHARPOS (*it) > to_charpos) \
+ || ((!it->bidi_p \
+ || BIDI_AT_BASE_LEVEL (it->bidi_it)) \
+ && IT_CHARPOS (*it) > to_charpos) \
|| (it->what == IT_COMPOSITION \
&& ((IT_CHARPOS (*it) > to_charpos \
&& to_charpos >= it->cmp_it.charpos) \
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
+ /* When the iterator is at base embedding level, we
+ are guaranteed that characters are delivered for
+ display in strictly increasing order of their
+ buffer positions. */
+ || BIDI_AT_BASE_LEVEL (it->bidi_it))
+ && IT_CHARPOS (*it) > to_charpos)
|| (it->bidi_p
&& (prev_method == GET_FROM_IMAGE
|| prev_method == GET_FROM_STRETCH
&& !saw_smaller_pos
&& IT_CHARPOS (*it) > to_charpos))
{
- if (!at_eob_p && IT_CHARPOS (ppos_it) < ZV)
+ if (it->bidi_p
+ && !at_eob_p && IT_CHARPOS (ppos_it) < ZV)
RESTORE_IT (it, &ppos_it, ppos_data);
result = MOVE_POS_MATCH_OR_ZV;
break;
else if (BUFFERP (it->object)
&& (it->method == GET_FROM_BUFFER
|| it->method == GET_FROM_STRETCH)
- && IT_CHARPOS (*it) >= to_charpos)
+ && IT_CHARPOS (*it) >= to_charpos
+ /* Under bidi iteration, a call to set_iterator_to_next
+ can scan far beyond to_charpos if the initial
+ portion of the next line needs to be reordered. In
+ that case, give move_it_in_display_line_to another
+ chance below. */
+ && !(it->bidi_p
+ && it->bidi_it.scan_dir == -1))
skip = MOVE_POS_MATCH_OR_ZV;
else
skip = move_it_in_display_line_to (it, to_charpos, -1, MOVE_TO_POS);
reseat_1 (it, it->current.pos, 1);
/* We are now surely at a line start. */
- it->current_x = it->hpos = 0;
+ it->current_x = it->hpos = 0; /* FIXME: this is incorrect when bidi
+ reordering is in effect. */
it->continuation_lines_width = 0;
/* Move forward and see what y-distance we moved. First move to the
move_it_to (&it2, start_pos, -1, -1, it2.vpos + 1,
MOVE_TO_POS | MOVE_TO_VPOS);
}
- while (!IT_POS_VALID_AFTER_MOVE_P (&it2));
+ while (!(IT_POS_VALID_AFTER_MOVE_P (&it2)
+ /* If we are in a display string which starts at START_POS,
+ and that display string includes a newline, and we are
+ right after that newline (i.e. at the beginning of a
+ display line), exit the loop, because otherwise we will
+ infloop, since move_it_to will see that it is already at
+ START_POS and will not move. */
+ || (it2.method == GET_FROM_STRING
+ && IT_CHARPOS (it2) == start_pos
+ && SREF (it2.string, IT_STRING_BYTEPOS (it2) - 1) == '\n')));
xassert (IT_CHARPOS (*it) >= BEGV);
SAVE_IT (it3, it2, it3data);
if (dy == 0)
{
/* DY == 0 means move to the start of the screen line. The
- value of nlines is > 0 if continuation lines were involved. */
+ value of nlines is > 0 if continuation lines were involved,
+ or if the original IT position was at start of a line. */
RESTORE_IT (it, it, it2data);
if (nlines > 0)
move_it_by_lines (it, nlines);
+ /* The above code moves us to some position NLINES down,
+ usually to its first glyph (leftmost in an L2R line), but
+ that's not necessarily the start of the line, under bidi
+ reordering. We want to get to the character position
+ that is immediately after the newline of the previous
+ line. */
+ if (it->bidi_p
+ && !it->continuation_lines_width
+ && !STRINGP (it->string)
+ && IT_CHARPOS (*it) > BEGV
+ && FETCH_BYTE (IT_BYTEPOS (*it) - 1) != '\n')
+ {
+ EMACS_INT nl_pos =
+ find_next_newline_no_quit (IT_CHARPOS (*it) - 1, -1);
+
+ move_it_to (it, nl_pos, -1, -1, -1, MOVE_TO_POS);
+ }
bidi_unshelve_cache (it3data, 1);
}
else
store_mode_line_noprop_char (char c)
{
/* If output position has reached the end of the allocated buffer,
- double the buffer's size. */
+ increase the buffer's size. */
if (mode_line_noprop_ptr == mode_line_noprop_buf_end)
{
- int len = MODE_LINE_NOPROP_LEN (0);
- int new_size = 2 * len * sizeof *mode_line_noprop_buf;
- mode_line_noprop_buf = (char *) xrealloc (mode_line_noprop_buf, new_size);
- mode_line_noprop_buf_end = mode_line_noprop_buf + new_size;
+ ptrdiff_t len = MODE_LINE_NOPROP_LEN (0);
+ ptrdiff_t size = len;
+ mode_line_noprop_buf =
+ xpalloc (mode_line_noprop_buf, &size, 1, STRING_BYTES_BOUND, 1);
+ mode_line_noprop_buf_end = mode_line_noprop_buf + size;
mode_line_noprop_ptr = mode_line_noprop_buf + len;
}
/* Do we have more than one visible frame on this X display? */
Lisp_Object tail;
Lisp_Object fmt;
- int title_start;
+ ptrdiff_t title_start;
char *title;
- int len;
+ ptrdiff_t len;
struct it it;
int count = SPECPDL_INDEX ();
= (desired_cursor_row->enabled_p
? desired_cursor_row
: current_cursor_row);
+ int row_r2l_p = cursor_row->reversed_p;
text_area_width = window_box_width (w, TEXT_AREA);
h_margin = hscroll_margin * WINDOW_FRAME_COLUMN_WIDTH (w);
if (!NILP (Fbuffer_local_value (Qauto_hscroll_mode, w->buffer))
- && ((XFASTINT (w->hscroll)
- && w->cursor.x <= h_margin)
- || (cursor_row->enabled_p
- && cursor_row->truncated_on_right_p
- && (w->cursor.x >= text_area_width - h_margin))))
+ /* For left-to-right rows, hscroll when cursor is either
+ (i) inside the right hscroll margin, or (ii) if it is
+ inside the left margin and the window is already
+ hscrolled. */
+ && ((!row_r2l_p
+ && ((XFASTINT (w->hscroll)
+ && w->cursor.x <= h_margin)
+ || (cursor_row->enabled_p
+ && cursor_row->truncated_on_right_p
+ && (w->cursor.x >= text_area_width - h_margin))))
+ /* For right-to-left rows, the logic is similar,
+ except that rules for scrolling to left and right
+ are reversed. E.g., if cursor.x <= h_margin, we
+ need to hscroll "to the right" unconditionally,
+ and that will scroll the screen to the left so as
+ to reveal the next portion of the row. */
+ || (row_r2l_p
+ && ((cursor_row->enabled_p
+ /* FIXME: It is confusing to set the
+ truncated_on_right_p flag when R2L rows
+ are actually truncated on the left. */
+ && cursor_row->truncated_on_right_p
+ && w->cursor.x <= h_margin)
+ || (XFASTINT (w->hscroll)
+ && (w->cursor.x >= text_area_width - h_margin))))))
{
struct it it;
int hscroll;
? (text_area_width - 4 * FRAME_COLUMN_WIDTH (it.f))
: (text_area_width / 2))))
/ FRAME_COLUMN_WIDTH (it.f);
- else if (w->cursor.x >= text_area_width - h_margin)
+ else if ((!row_r2l_p
+ && w->cursor.x >= text_area_width - h_margin)
+ || (row_r2l_p && w->cursor.x <= h_margin))
{
if (hscroll_relative_p)
wanted_x = text_area_width * (1 - hscroll_step_rel)
}
hscroll = max (hscroll, XFASTINT (w->min_hscroll));
- /* Don't call Fset_window_hscroll if value hasn't
- changed because it will prevent redisplay
- optimizations. */
+ /* Don't prevent redisplay optimizations if hscroll
+ hasn't changed, as it will unnecessarily slow down
+ redisplay. */
if (XFASTINT (w->hscroll) != hscroll)
{
XBUFFER (w->buffer)->prevent_redisplay_optimizations_p = 1;
glyph--;
}
}
- else if (match_with_avoid_cursor
- /* A truncated row may not include PT among its
- character positions. Setting the cursor inside the
- scroll margin will trigger recalculation of hscroll
- in hscroll_window_tree. */
- || (row->truncated_on_left_p && pt_old < bpos_min)
- || (row->truncated_on_right_p && pt_old > bpos_max)
- /* Zero-width characters produce no glyphs. */
- || (!string_seen
- && !empty_line_p
- && (row->reversed_p
- ? glyph_after > glyphs_end
- : glyph_after < glyphs_end)))
+ else if (match_with_avoid_cursor)
{
cursor = glyph_after;
x = -1;
x = -1;
+ /* If the row ends in a newline from a display string,
+ reordering could have moved the glyphs belonging to the
+ string out of the [GLYPH_BEFORE..GLYPH_AFTER] range. So
+ in this case we extend the search to the last glyph in
+ the row that was not inserted by redisplay. */
+ if (row->ends_in_newline_from_string_p)
+ {
+ glyph_after = end;
+ pos_after = MATRIX_ROW_END_CHARPOS (row) + delta;
+ }
+
/* GLYPH_BEFORE and GLYPH_AFTER are the glyphs that
correspond to POS_BEFORE and POS_AFTER, respectively. We
need START and STOP in the order that corresponds to the
&& row->continued_p)
return 0;
}
+ /* A truncated row may not include PT among its character positions.
+ Setting the cursor inside the scroll margin will trigger
+ recalculation of hscroll in hscroll_window_tree. But if a
+ display string covers point, defer to the string-handling
+ code below to figure this out. */
+ else if (row->truncated_on_left_p && pt_old < bpos_min)
+ {
+ cursor = glyph_before;
+ x = -1;
+ }
+ else if ((row->truncated_on_right_p && pt_old > bpos_max)
+ /* Zero-width characters produce no glyphs. */
+ || (!empty_line_p
+ && (row->reversed_p
+ ? glyph_after > glyphs_end
+ : glyph_after < glyphs_end)))
+ {
+ cursor = glyph_after;
+ x = -1;
+ }
}
compute_x:
|| (STRINGP (g1->object)
&& (!NILP (Fget_char_property (make_number (g1->charpos),
Qcursor, g1->object))
- /* pevious candidate is from the same display
+ /* previous candidate is from the same display
string as this one, and the display string
came from a text property */
|| (EQ (g1->object, 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
bidi-reordered rows. */
while (MATRIX_ROW_CONTINUATION_LINE_P (row))
{
- xassert (row->enabled_p);
- --row;
/* If we hit the beginning of the displayed portion
without finding the first row of a continued
line, give up. */
rc = CURSOR_MOVEMENT_MUST_SCROLL;
break;
}
-
+ xassert (row->enabled_p);
+ --row;
}
}
if (must_scroll)
do
{
+ int at_zv_p = 0, exact_match_p = 0;
+
if (MATRIX_ROW_START_CHARPOS (row) <= PT
&& PT <= MATRIX_ROW_END_CHARPOS (row)
&& cursor_row_p (row))
rv |= set_cursor_from_row (w, row, w->current_matrix,
0, 0, 0, 0);
- /* As soon as we've found the first suitable row
- whose ends_at_zv_p flag is set, we are done. */
- if (rv
- && MATRIX_ROW (w->current_matrix, w->cursor.vpos)->ends_at_zv_p)
+ /* As soon as we've found the exact match for point,
+ or the first suitable row whose ends_at_zv_p flag
+ is set, we are done. */
+ at_zv_p =
+ MATRIX_ROW (w->current_matrix, w->cursor.vpos)->ends_at_zv_p;
+ if (rv && !at_zv_p
+ && w->cursor.hpos >= 0
+ && w->cursor.hpos < MATRIX_ROW_USED (w->current_matrix,
+ w->cursor.vpos))
+ {
+ struct glyph_row *candidate =
+ MATRIX_ROW (w->current_matrix, w->cursor.vpos);
+ struct glyph *g =
+ candidate->glyphs[TEXT_AREA] + w->cursor.hpos;
+ EMACS_INT endpos = MATRIX_ROW_END_CHARPOS (candidate);
+
+ exact_match_p =
+ (BUFFERP (g->object) && g->charpos == PT)
+ || (INTEGERP (g->object)
+ && (g->charpos == PT
+ || (g->charpos == 0 && endpos - 1 == PT)));
+ }
+ if (rv && (at_zv_p || exact_match_p))
{
rc = CURSOR_MOVEMENT_SUCCESS;
break;
}
+ if (MATRIX_ROW_BOTTOM_Y (row) == last_y)
+ break;
++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));
loop before all the candidates were examined, signal
to the caller that this method failed. */
if (rc != CURSOR_MOVEMENT_SUCCESS
- && (!rv || MATRIX_ROW_CONTINUATION_LINE_P (row)))
+ && !(rv
+ && !MATRIX_ROW_CONTINUATION_LINE_P (row)
+ && !row->continued_p))
rc = CURSOR_MOVEMENT_MUST_SCROLL;
else if (rv)
rc = CURSOR_MOVEMENT_SUCCESS;
int current_matrix_up_to_date_p = 0;
int used_current_matrix_p = 0;
/* This is less strict than current_matrix_up_to_date_p.
- It indictes that the buffer contents and narrowing are unchanged. */
+ It indicates that the buffer contents and narrowing are unchanged. */
int buffer_unchanged_p = 0;
int temp_scroll_step = 0;
int count = SPECPDL_INDEX ();
|| (XFASTINT (w->last_modified) >= MODIFF
&& XFASTINT (w->last_overlay_modified) >= OVERLAY_MODIFF)))
{
+ int d1, d2, d3, d4, d5, d6;
/* If first window line is a continuation line, and window start
is inside the modified region, but the first change is before
compute_window_start_on_continuation_line. (See also
bug#197). */
&& XMARKER (w->start)->buffer == current_buffer
- && compute_window_start_on_continuation_line (w))
+ && compute_window_start_on_continuation_line (w)
+ /* It doesn't make sense to force the window start like we
+ do at label force_start if it is already known that point
+ will not be visible in the resulting window, because
+ doing so will move point from its correct position
+ instead of scrolling the window to bring point into view.
+ See bug#9324. */
+ && pos_visible_p (w, PT, &d1, &d2, &d3, &d4, &d5, &d6))
{
w->force_start = Qt;
SET_TEXT_POS_FROM_MARKER (startp, w->start);
start_vpos = MATRIX_ROW_VPOS (start_row, w->current_matrix);
}
- /* If we have reached alignment,
- we can copy the rest of the rows. */
- if (IT_CHARPOS (it) == CHARPOS (start))
+ /* If we have reached alignment, we can copy the rest of the
+ rows. */
+ if (IT_CHARPOS (it) == CHARPOS (start)
+ /* Don't accept "alignment" inside a display vector,
+ since start_row could have started in the middle of
+ that same display vector (thus their character
+ positions match), and we have no way of telling if
+ that is the case. */
+ && it.current.dpvec_index < 0)
break;
if (display_line (&it))
last_text_row = it.glyph_row - 1;
+
}
/* A value of current_y < last_visible_y means that we stopped
if (row < bottom_row)
{
struct glyph *glyph = row->glyphs[TEXT_AREA] + w->cursor.hpos;
- struct glyph *end = glyph + row->used[TEXT_AREA];
+ struct glyph *end = row->glyphs[TEXT_AREA] + row->used[TEXT_AREA];
/* Can't use this optimization with bidi-reordered glyph
rows, unless cursor is already at point. */
last_unchanged_at_beg_row = find_last_unchanged_at_beg_row (w);
if (last_unchanged_at_beg_row)
{
- /* Avoid starting to display in the moddle of a character, a TAB
+ /* Avoid starting to display in the middle of a character, a TAB
for instance. This is easier than to set up the iterator
exactly, and it's not a frequent case, so the additional
effort wouldn't really pay off. */
{
int this_scroll_margin, cursor_height;
- this_scroll_margin = max (0, scroll_margin);
- this_scroll_margin = min (this_scroll_margin, WINDOW_TOTAL_LINES (w) / 4);
+ this_scroll_margin =
+ max (0, min (scroll_margin, WINDOW_TOTAL_LINES (w) / 4));
this_scroll_margin *= FRAME_LINE_HEIGHT (it.f);
cursor_height = MATRIX_ROW (w->desired_matrix, w->cursor.vpos)->height;
}
}
+/* Compute the hash code for ROW. */
+unsigned
+row_hash (struct glyph_row *row)
+{
+ int area, k;
+ unsigned hashval = 0;
+
+ for (area = LEFT_MARGIN_AREA; area < LAST_AREA; ++area)
+ for (k = 0; k < row->used[area]; ++k)
+ hashval = ((((hashval << 4) + (hashval >> 24)) & 0x0fffffff)
+ + row->glyphs[area][k].u.val
+ + row->glyphs[area][k].face_id
+ + row->glyphs[area][k].padding_p
+ + (row->glyphs[area][k].type << 2));
+
+ return hashval;
+}
/* Compute the pixel height and width of IT->glyph_row.
}
/* Compute a hash code for this row. */
- {
- int area, i;
- row->hash = 0;
- for (area = LEFT_MARGIN_AREA; area < LAST_AREA; ++area)
- for (i = 0; i < row->used[area]; ++i)
- row->hash = ((((row->hash << 4) + (row->hash >> 24)) & 0x0fffffff)
- + row->glyphs[area][i].u.val
- + row->glyphs[area][i].face_id
- + row->glyphs[area][i].padding_p
- + (row->glyphs[area][i].type << 2));
- }
+ row->hash = row_hash (row);
it->max_ascent = it->max_descent = 0;
it->max_phys_ascent = it->max_phys_descent = 0;
{
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
push_display_prop (struct it *it, Lisp_Object prop)
{
struct text_pos pos =
- (it->method == GET_FROM_STRING) ? it->current.string_pos : it->current.pos;
+ STRINGP (it->string) ? it->current.string_pos : it->current.pos;
xassert (it->method == GET_FROM_BUFFER
+ || it->method == GET_FROM_DISPLAY_VECTOR
|| it->method == GET_FROM_STRING);
/* We need to save the current buffer/string position, so it will be
Line ends in a newline from buffer eol_pos + 1
Line is continued from buffer max_pos + 1
Line is truncated on right it->current.pos
- Line ends in a newline from string max_pos
+ Line ends in a newline from string max_pos + 1(*)
+ (*) + 1 only when line ends in a forward scan
Line is continued from string max_pos
Line is continued from display vector max_pos
Line is entirely from a string min_pos == max_pos
row->maxpos = it->current.pos;
else if (row->used[TEXT_AREA])
{
- if (row->ends_in_newline_from_string_p)
- SET_TEXT_POS (row->maxpos, max_pos, max_bpos);
+ int seen_this_string = 0;
+ struct glyph_row *r1 = row - 1;
+
+ /* Did we see the same display string on the previous row? */
+ if (STRINGP (it->object)
+ /* this is not the first row */
+ && row > it->w->desired_matrix->rows
+ /* previous row is not the header line */
+ && !r1->mode_line_p
+ /* previous row also ends in a newline from a string */
+ && r1->ends_in_newline_from_string_p)
+ {
+ struct glyph *start, *end;
+
+ /* Search for the last glyph of the previous row that came
+ from buffer or string. Depending on whether the row is
+ L2R or R2L, we need to process it front to back or the
+ other way round. */
+ if (!r1->reversed_p)
+ {
+ start = r1->glyphs[TEXT_AREA];
+ end = start + r1->used[TEXT_AREA];
+ /* Glyphs inserted by redisplay have an integer (zero)
+ as their object. */
+ while (end > start
+ && INTEGERP ((end - 1)->object)
+ && (end - 1)->charpos <= 0)
+ --end;
+ if (end > start)
+ {
+ if (EQ ((end - 1)->object, it->object))
+ seen_this_string = 1;
+ }
+ else
+ /* If all the glyphs of the previous row were inserted
+ by redisplay, it means the previous row was
+ produced from a single newline, which is only
+ possible if that newline came from the same string
+ as the one which produced this ROW. */
+ seen_this_string = 1;
+ }
+ else
+ {
+ end = r1->glyphs[TEXT_AREA] - 1;
+ start = end + r1->used[TEXT_AREA];
+ while (end < start
+ && INTEGERP ((end + 1)->object)
+ && (end + 1)->charpos <= 0)
+ ++end;
+ if (end < start)
+ {
+ if (EQ ((end + 1)->object, it->object))
+ seen_this_string = 1;
+ }
+ else
+ seen_this_string = 1;
+ }
+ }
+ /* Take note of each display string that covers a newline only
+ once, the first time we see it. This is for when a display
+ string includes more than one newline in it. */
+ if (row->ends_in_newline_from_string_p && !seen_this_string)
+ {
+ /* If we were scanning the buffer forward when we displayed
+ the string, we want to account for at least one buffer
+ position that belongs to this row (position covered by
+ the display string), so that cursor positioning will
+ consider this row as a candidate when point is at the end
+ of the visual line represented by this row. This is not
+ required when scanning back, because max_pos will already
+ have a much larger value. */
+ if (CHARPOS (row->end.pos) > max_pos)
+ INC_BOTH (max_pos, max_bpos);
+ SET_TEXT_POS (row->maxpos, max_pos, max_bpos);
+ }
else if (CHARPOS (it->eol_pos) > 0)
SET_TEXT_POS (row->maxpos,
CHARPOS (it->eol_pos) + 1, BYTEPOS (it->eol_pos) + 1);
min_pos = current_pos; \
min_bpos = current_bpos; \
} \
- if (current_pos > max_pos) \
+ if (IT_CHARPOS (*it) > max_pos) \
{ \
- max_pos = current_pos; \
- max_bpos = current_bpos; \
+ max_pos = IT_CHARPOS (*it); \
+ max_bpos = IT_BYTEPOS (*it); \
} \
} \
while (0)
it->current_x = new_x;
it->continuation_lines_width += new_x;
++it->hpos;
- /* Record the maximum and minimum buffer
- positions seen so far in glyphs that will be
- displayed by this row. */
- if (it->bidi_p)
- RECORD_MAX_MIN_POS (it);
if (i == nglyphs - 1)
{
/* If line-wrap is on, check if a previous
|| IT_DISPLAYING_WHITESPACE (it)))
goto back_to_wrap;
+ /* Record the maximum and minimum buffer
+ positions seen so far in glyphs that will be
+ displayed by this row. */
+ if (it->bidi_p)
+ RECORD_MAX_MIN_POS (it);
set_iterator_to_next (it, 1);
if (IT_OVERFLOW_NEWLINE_INTO_FRINGE (it))
{
}
}
}
+ else if (it->bidi_p)
+ RECORD_MAX_MIN_POS (it);
}
else if (CHAR_GLYPH_PADDING_P (*glyph)
&& !FRAME_WINDOW_P (it->f))
xassert (it->first_visible_x <= it->last_visible_x);
}
}
+ /* Even if this display element produced no glyphs at all,
+ we want to record its position. */
+ if (it->bidi_p && nglyphs == 0)
+ RECORD_MAX_MIN_POS (it);
row->ascent = max (row->ascent, it->max_ascent);
row->height = max (row->height, it->max_ascent + it->max_descent);
overlay_arrow_seen = 1;
}
+ /* Highlight trailing whitespace. */
+ if (!NILP (Vshow_trailing_whitespace))
+ highlight_trailing_whitespace (it->f, it->glyph_row);
+
/* Compute pixel dimensions of this line. */
compute_line_metrics (it);
+ /* Implementation note: No changes in the glyphs of ROW or in their
+ faces can be done past this point, because compute_line_metrics
+ computes ROW's hash value and stores it within the glyph_row
+ structure. */
+
/* Record whether this row ends inside an ellipsis. */
row->ends_in_ellipsis_p
= (it->method == GET_FROM_DISPLAY_VECTOR
&& cursor_row_p (row))
set_cursor_from_row (it->w, row, it->w->desired_matrix, 0, 0, 0, 0);
- /* Highlight trailing whitespace. */
- if (!NILP (Vshow_trailing_whitespace))
- highlight_trailing_whitespace (it->f, it->glyph_row);
-
/* Prepare for the next line. This line starts horizontally at (X
HPOS) = (0 0). Vertical positions are incremented. As a
convenience for the caller, IT->glyph_row is set to the next
}
if (NILP (BVAR (buf, bidi_display_reordering))
- || NILP (BVAR (buf, enable_multibyte_characters)))
+ || NILP (BVAR (buf, enable_multibyte_characters))
+ /* When we are loading loadup.el, the character property tables
+ needed for bidi iteration are not yet available. */
+ || !NILP (Vpurify_flag))
return Qleft_to_right;
else if (!NILP (BVAR (buf, bidi_paragraph_direction)))
return BVAR (buf, bidi_paragraph_direction);
EMACS_INT pos = BUF_PT (buf);
EMACS_INT bytepos = BUF_PT_BYTE (buf);
int c;
+ void *itb_data = bidi_shelve_cache ();
set_buffer_temp (buf);
/* bidi_paragraph_init finds the base direction of the paragraph
pos--;
bytepos = CHAR_TO_BYTE (pos);
}
- while ((c = FETCH_BYTE (bytepos)) == '\n'
- || c == ' ' || c == '\t' || c == '\f')
+ if (fast_looking_at (build_string ("[\f\t ]*\n"),
+ pos, bytepos, ZV, ZV_BYTE, Qnil) > 0)
{
- if (bytepos <= BEGV_BYTE)
- break;
- bytepos--;
- pos--;
+ while ((c = FETCH_BYTE (bytepos)) == '\n'
+ || c == ' ' || c == '\t' || c == '\f')
+ {
+ if (bytepos <= BEGV_BYTE)
+ break;
+ bytepos--;
+ pos--;
+ }
+ while (!CHAR_HEAD_P (FETCH_BYTE (bytepos)))
+ bytepos--;
}
- while (!CHAR_HEAD_P (FETCH_BYTE (bytepos)))
- bytepos--;
- itb.charpos = pos;
- itb.bytepos = bytepos;
- itb.nchars = -1;
+ bidi_init_it (pos, bytepos, FRAME_WINDOW_P (SELECTED_FRAME ()), &itb);
+ itb.paragraph_dir = NEUTRAL_DIR;
itb.string.s = NULL;
itb.string.lstring = Qnil;
- itb.frame_window_p = FRAME_WINDOW_P (SELECTED_FRAME ()); /* guesswork */
- itb.first_elt = 1;
- itb.separator_limit = -1;
- itb.paragraph_dir = NEUTRAL_DIR;
-
+ itb.string.bufpos = 0;
+ itb.string.unibyte = 0;
bidi_paragraph_init (NEUTRAL_DIR, &itb, 1);
+ bidi_unshelve_cache (itb_data, 0);
set_buffer_temp (old);
switch (itb.paragraph_dir)
{
? XFLOATINT (X) \
: - 1)
-int
+static int
calc_pixel_width_or_height (double *res, struct it *it, Lisp_Object prop,
struct font *font, int width_p, int *align_to)
{
if (FRAME_WINDOW_P (it->f)
&& valid_image_p (prop))
{
- int id = lookup_image (it->f, prop);
+ ptrdiff_t id = lookup_image (it->f, prop);
struct image *img = IMAGE_FROM_ID (it->f, id);
return OK_PIXELS (width_p ? img->width : img->height);
/* 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. */
+ Return 1 if FONT has a glyph for C, otherwise return 0. */
static inline int
get_char_glyph_code (int c, struct font *font, XChar2b *char2b)
{
int c = COMPOSITION_GLYPH (s->cmp, i);
+ /* TAB in a composition means display glyphs with padding space
+ on the left or right. */
if (c != '\t')
{
int face_id = FACE_FOR_CHAR (s->f, base_face->ascii_face, c,
}
s->cmp_to = i;
+ if (s->face == NULL)
+ {
+ s->face = base_face->ascii_face;
+ s->font = s->face->font;
+ }
+
/* All glyph strings for the same composition has the same width,
i.e. the width set for the first component of the composition. */
s->width = s->first_glyph->pixel_width;
do { \
int face_id = (row)->glyphs[area][START].face_id; \
struct face *base_face = FACE_FROM_ID (f, face_id); \
- int cmp_id = (row)->glyphs[area][START].u.cmp.id; \
+ ptrdiff_t cmp_id = (row)->glyphs[area][START].u.cmp.id; \
struct composition *cmp = composition_table[cmp_id]; \
XChar2b *char2b; \
struct glyph_string *first_s IF_LINT (= NULL); \
IT_EXPAND_MATRIX_WIDTH (it, area);
}
+#endif /* HAVE_WINDOW_SYSTEM */
/* Produce a stretch glyph for iterator IT. IT->object is the value
of the glyph property displayed. The value must be a list
of the stretch should be used for the ascent of the stretch.
ASCENT must be in the range 0 <= ASCENT <= 100. */
-static void
+void
produce_stretch_glyph (struct it *it)
{
/* (space :width WIDTH :height HEIGHT ...) */
Lisp_Object prop, plist;
int width = 0, height = 0, align_to = -1;
- int zero_width_ok_p = 0, zero_height_ok_p = 0;
+ int zero_width_ok_p = 0;
int ascent = 0;
double tem;
- struct face *face = FACE_FROM_ID (it->f, it->face_id);
- struct font *font = face->font ? face->font : FRAME_FONT (it->f);
+ struct face *face = NULL;
+ struct font *font = NULL;
- PREPARE_FACE_FOR_DISPLAY (it->f, face);
+#ifdef HAVE_WINDOW_SYSTEM
+ int zero_height_ok_p = 0;
+
+ if (FRAME_WINDOW_P (it->f))
+ {
+ face = FACE_FROM_ID (it->f, it->face_id);
+ font = face->font ? face->font : FRAME_FONT (it->f);
+ PREPARE_FACE_FOR_DISPLAY (it->f, face);
+ }
+#endif
/* List should start with `space'. */
xassert (CONSP (it->object) && EQ (XCAR (it->object), Qspace));
zero_width_ok_p = 1;
width = (int)tem;
}
- else if (prop = Fplist_get (plist, QCrelative_width),
- NUMVAL (prop) > 0)
+#ifdef HAVE_WINDOW_SYSTEM
+ else if (FRAME_WINDOW_P (it->f)
+ && (prop = Fplist_get (plist, QCrelative_width), NUMVAL (prop) > 0))
{
/* Relative width `:relative-width FACTOR' specified and valid.
Compute the width of the characters having the `glyph'
x_produce_glyphs (&it2);
width = NUMVAL (prop) * it2.pixel_width;
}
+#endif /* HAVE_WINDOW_SYSTEM */
else if ((prop = Fplist_get (plist, QCalign_to), !NILP (prop))
&& calc_pixel_width_or_height (&tem, it, prop, font, 1, &align_to))
{
if (width <= 0 && (width < 0 || !zero_width_ok_p))
width = 1;
+#ifdef HAVE_WINDOW_SYSTEM
/* Compute height. */
- if ((prop = Fplist_get (plist, QCheight), !NILP (prop))
- && calc_pixel_width_or_height (&tem, it, prop, font, 0, 0))
+ if (FRAME_WINDOW_P (it->f))
{
- height = (int)tem;
- zero_height_ok_p = 1;
- }
- else if (prop = Fplist_get (plist, QCrelative_height),
- NUMVAL (prop) > 0)
- height = FONT_HEIGHT (font) * NUMVAL (prop);
- else
- height = FONT_HEIGHT (font);
+ if ((prop = Fplist_get (plist, QCheight), !NILP (prop))
+ && calc_pixel_width_or_height (&tem, it, prop, font, 0, 0))
+ {
+ height = (int)tem;
+ zero_height_ok_p = 1;
+ }
+ else if (prop = Fplist_get (plist, QCrelative_height),
+ NUMVAL (prop) > 0)
+ height = FONT_HEIGHT (font) * NUMVAL (prop);
+ else
+ height = FONT_HEIGHT (font);
- if (height <= 0 && (height < 0 || !zero_height_ok_p))
- height = 1;
+ if (height <= 0 && (height < 0 || !zero_height_ok_p))
+ height = 1;
- /* Compute percentage of height used for ascent. If
- `:ascent ASCENT' is present and valid, use that. Otherwise,
- derive the ascent from the font in use. */
- if (prop = Fplist_get (plist, QCascent),
- NUMVAL (prop) > 0 && NUMVAL (prop) <= 100)
- ascent = height * NUMVAL (prop) / 100.0;
- else if (!NILP (prop)
- && calc_pixel_width_or_height (&tem, it, prop, font, 0, 0))
- ascent = min (max (0, (int)tem), height);
+ /* Compute percentage of height used for ascent. If
+ `:ascent ASCENT' is present and valid, use that. Otherwise,
+ derive the ascent from the font in use. */
+ if (prop = Fplist_get (plist, QCascent),
+ NUMVAL (prop) > 0 && NUMVAL (prop) <= 100)
+ ascent = height * NUMVAL (prop) / 100.0;
+ else if (!NILP (prop)
+ && calc_pixel_width_or_height (&tem, it, prop, font, 0, 0))
+ ascent = min (max (0, (int)tem), height);
+ else
+ ascent = (height * FONT_BASE (font)) / FONT_HEIGHT (font);
+ }
else
- ascent = (height * FONT_BASE (font)) / FONT_HEIGHT (font);
+#endif /* HAVE_WINDOW_SYSTEM */
+ height = 1;
if (width > 0 && it->line_wrap != TRUNCATE
&& it->current_x + width > it->last_visible_x)
- width = it->last_visible_x - it->current_x - 1;
+ {
+ width = it->last_visible_x - it->current_x;
+#ifdef HAVE_WINDOW_SYSTEM
+ /* Subtract one more pixel from the stretch width, but only on
+ GUI frames, since on a TTY each glyph is one "pixel" wide. */
+ width -= FRAME_WINDOW_P (it->f);
+#endif
+ }
if (width > 0 && height > 0 && it->glyph_row)
{
+ Lisp_Object o_object = it->object;
Lisp_Object object = it->stack[it->sp - 1].string;
+ int n = width;
+
if (!STRINGP (object))
object = it->w->buffer;
- append_stretch_glyph (it, object, width, height, ascent);
+#ifdef HAVE_WINDOW_SYSTEM
+ if (FRAME_WINDOW_P (it->f))
+ append_stretch_glyph (it, object, width, height, ascent);
+ else
+#endif
+ {
+ it->object = object;
+ it->char_to_display = ' ';
+ it->pixel_width = it->len = 1;
+ while (n--)
+ tty_append_glyph (it);
+ it->object = o_object;
+ }
}
it->pixel_width = width;
- it->ascent = it->phys_ascent = ascent;
- it->descent = it->phys_descent = height - it->ascent;
- it->nglyphs = width > 0 && height > 0 ? 1 : 0;
-
- take_vertical_position_into_account (it);
+#ifdef HAVE_WINDOW_SYSTEM
+ if (FRAME_WINDOW_P (it->f))
+ {
+ it->ascent = it->phys_ascent = ascent;
+ it->descent = it->phys_descent = height - it->ascent;
+ it->nglyphs = width > 0 && height > 0 ? 1 : 0;
+ take_vertical_position_into_account (it);
+ }
+ else
+#endif
+ it->nglyphs = width;
}
+#ifdef HAVE_WINDOW_SYSTEM
+
/* Calculate line-height and line-spacing properties.
An integer value specifies explicit pixel value.
A float value specifies relative value to current face height.
void
x_write_glyphs (struct glyph *start, int len)
{
- int x, hpos;
+ int x, hpos, chpos = updated_window->phys_cursor.hpos;
xassert (updated_window && updated_row);
+ /* When the window is hscrolled, cursor hpos can legitimately be out
+ of bounds, but we draw the cursor at the corresponding window
+ margin in that case. */
+ if (!updated_row->reversed_p && chpos < 0)
+ chpos = 0;
+ if (updated_row->reversed_p && chpos >= updated_row->used[TEXT_AREA])
+ chpos = updated_row->used[TEXT_AREA] - 1;
+
BLOCK_INPUT;
/* Write glyphs. */
if (updated_area == TEXT_AREA
&& updated_window->phys_cursor_on_p
&& updated_window->phys_cursor.vpos == output_cursor.vpos
- && updated_window->phys_cursor.hpos >= hpos
- && updated_window->phys_cursor.hpos < hpos + len)
+ && chpos >= hpos
+ && chpos < hpos + len)
updated_window->phys_cursor_on_p = 0;
UNBLOCK_INPUT;
{
int on_p = w->phys_cursor_on_p;
int x1;
- x1 = draw_glyphs (w, w->phys_cursor.x, row, TEXT_AREA,
- w->phys_cursor.hpos, w->phys_cursor.hpos + 1,
+ int hpos = w->phys_cursor.hpos;
+
+ /* When the window is hscrolled, cursor hpos can legitimately be
+ out of bounds, but we draw the cursor at the corresponding
+ window margin in that case. */
+ if (!row->reversed_p && hpos < 0)
+ hpos = 0;
+ if (row->reversed_p && hpos >= row->used[TEXT_AREA])
+ hpos = row->used[TEXT_AREA] - 1;
+
+ x1 = draw_glyphs (w, w->phys_cursor.x, row, TEXT_AREA, hpos, hpos + 1,
hl, 0);
w->phys_cursor_on_p = on_p;
: (w->phys_cursor.hpos >= cursor_row->used[TEXT_AREA])))
goto mark_cursor_off;
+ /* When the window is hscrolled, cursor hpos can legitimately be out
+ of bounds, but we draw the cursor at the corresponding window
+ margin in that case. */
+ if (!cursor_row->reversed_p && hpos < 0)
+ hpos = 0;
+ if (cursor_row->reversed_p && hpos >= cursor_row->used[TEXT_AREA])
+ hpos = cursor_row->used[TEXT_AREA] - 1;
+
/* If the cursor is in the mouse face area, redisplay that when
we clear the cursor. */
if (! NILP (hlinfo->mouse_face_window)
of being deleted. */
if (w->current_matrix)
{
+ int hpos = w->phys_cursor.hpos;
+ int vpos = w->phys_cursor.vpos;
+ struct glyph_row *row;
+
+ if (vpos >= w->current_matrix->nrows
+ || hpos >= w->current_matrix->matrix_w)
+ return;
+
+ row = MATRIX_ROW (w->current_matrix, vpos);
+
+ /* When the window is hscrolled, cursor hpos can legitimately be
+ out of bounds, but we draw the cursor at the corresponding
+ window margin in that case. */
+ if (!row->reversed_p && hpos < 0)
+ hpos = 0;
+ if (row->reversed_p && hpos >= row->used[TEXT_AREA])
+ hpos = row->used[TEXT_AREA] - 1;
+
BLOCK_INPUT;
- display_and_set_cursor (w, on, w->phys_cursor.hpos, w->phys_cursor.vpos,
+ display_and_set_cursor (w, on, hpos, vpos,
w->phys_cursor.x, w->phys_cursor.y);
UNBLOCK_INPUT;
}
if (FRAME_WINDOW_P (f)
&& phys_cursor_on_p && !w->phys_cursor_on_p)
{
+ int hpos = w->phys_cursor.hpos;
+
+ /* When the window is hscrolled, cursor hpos can legitimately be
+ out of bounds, but we draw the cursor at the corresponding
+ window margin in that case. */
+ if (!row->reversed_p && hpos < 0)
+ hpos = 0;
+ if (row->reversed_p && hpos >= row->used[TEXT_AREA])
+ hpos = row->used[TEXT_AREA] - 1;
+
BLOCK_INPUT;
- display_and_set_cursor (w, 1,
- w->phys_cursor.hpos, w->phys_cursor.vpos,
+ display_and_set_cursor (w, 1, hpos, w->phys_cursor.vpos,
w->phys_cursor.x, w->phys_cursor.y);
UNBLOCK_INPUT;
}
int
cursor_in_mouse_face_p (struct window *w)
{
- return coords_in_mouse_face_p (w, w->phys_cursor.hpos, w->phys_cursor.vpos);
+ int hpos = w->phys_cursor.hpos;
+ int vpos = w->phys_cursor.vpos;
+ struct glyph_row *row = MATRIX_ROW (w->current_matrix, vpos);
+
+ /* When the window is hscrolled, cursor hpos can legitimately be out
+ of bounds, but we draw the cursor at the corresponding window
+ margin in that case. */
+ if (!row->reversed_p && hpos < 0)
+ hpos = 0;
+ if (row->reversed_p && hpos >= row->used[TEXT_AREA])
+ hpos = row->used[TEXT_AREA] - 1;
+
+ return coords_in_mouse_face_p (w, hpos, vpos);
}
for the overlay or run of text properties specifying the mouse
face. BEFORE_STRING and AFTER_STRING, if non-nil, are a
before-string and after-string that must also be highlighted.
- COVER_STRING, if non-nil, is a display string that may cover some
+ DISP_STRING, if non-nil, is a display string that may cover some
or all of the highlighted text. */
static void
EMACS_INT end_charpos,
Lisp_Object before_string,
Lisp_Object after_string,
- Lisp_Object cover_string)
+ Lisp_Object disp_string)
{
struct window *w = XWINDOW (window);
struct glyph_row *first = MATRIX_FIRST_TEXT_ROW (w->current_matrix);
EMACS_INT ignore, pos;
int x;
- xassert (NILP (cover_string) || STRINGP (cover_string));
+ xassert (NILP (disp_string) || STRINGP (disp_string));
xassert (NILP (before_string) || STRINGP (before_string));
xassert (NILP (after_string) || STRINGP (after_string));
r1 = MATRIX_ROW (w->current_matrix, XFASTINT (w->window_end_vpos));
/* If the before-string or display-string contains newlines,
rows_from_pos_range skips to its last row. Move back. */
- if (!NILP (before_string) || !NILP (cover_string))
+ if (!NILP (before_string) || !NILP (disp_string))
{
struct glyph_row *prev;
while ((prev = r1 - 1, prev >= first)
while (--glyph >= beg && INTEGERP (glyph->object));
if (glyph < beg
|| !(EQ (glyph->object, before_string)
- || EQ (glyph->object, cover_string)))
+ || EQ (glyph->object, disp_string)))
break;
r1 = prev;
}
r2 = next;
}
/* The rest of the display engine assumes that mouse_face_beg_row is
- either above below mouse_face_end_row or identical to it. But
- with bidi-reordered continued lines, the row for START_CHARPOS
- could be below the row for END_CHARPOS. If so, swap the rows and
- store them in correct order. */
+ either above mouse_face_end_row or identical to it. But with
+ bidi-reordered continued lines, the row for START_CHARPOS could
+ be below the row for END_CHARPOS. If so, swap the rows and store
+ them in correct order. */
if (r1->y > r2->y)
{
struct glyph_row *tem = r2;
hlinfo->mouse_face_end_row = MATRIX_ROW_VPOS (r2, w->current_matrix);
/* For a bidi-reordered row, the positions of BEFORE_STRING,
- AFTER_STRING, COVER_STRING, START_CHARPOS, and END_CHARPOS
+ AFTER_STRING, DISP_STRING, START_CHARPOS, and END_CHARPOS
could be anywhere in the row and in any order. The strategy
below is to find the leftmost and the rightmost glyph that
belongs to either of these 3 strings, or whose position is
x += glyph->pixel_width;
/* Scan the glyph row, looking for BEFORE_STRING, AFTER_STRING,
- or COVER_STRING, and the first glyph from buffer whose
+ or DISP_STRING, and the first glyph from buffer whose
position is between START_CHARPOS and END_CHARPOS. */
for (; glyph < end
&& !INTEGERP (glyph->object)
- && !EQ (glyph->object, cover_string)
+ && !EQ (glyph->object, disp_string)
&& !(BUFFERP (glyph->object)
&& (glyph->charpos >= start_charpos
&& glyph->charpos < end_charpos));
;
/* Scan the glyph row, looking for BEFORE_STRING, AFTER_STRING,
- or COVER_STRING, and the first glyph from buffer whose
+ or DISP_STRING, and the first glyph from buffer whose
position is between START_CHARPOS and END_CHARPOS. */
for (; glyph > end
&& !INTEGERP (glyph->object)
- && !EQ (glyph->object, cover_string)
+ && !EQ (glyph->object, disp_string)
&& !(BUFFERP (glyph->object)
&& (glyph->charpos >= start_charpos
&& glyph->charpos < end_charpos));
row, and also blanks and stretch glyphs inserted by
extend_face_to_end_of_line. */
while (end > glyph
- && INTEGERP ((end - 1)->object)
- && (end - 1)->charpos <= 0)
+ && INTEGERP ((end - 1)->object))
--end;
/* Scan the rest of the glyph row from the end, looking for the
first glyph that comes from BEFORE_STRING, AFTER_STRING, or
- COVER_STRING, or whose position is between START_CHARPOS
+ DISP_STRING, or whose position is between START_CHARPOS
and END_CHARPOS */
for (--end;
end > glyph
&& !INTEGERP (end->object)
- && !EQ (end->object, cover_string)
+ && !EQ (end->object, disp_string)
&& !(BUFFERP (end->object)
&& (end->charpos >= start_charpos
&& end->charpos < end_charpos));
x = r2->x;
end++;
while (end < glyph
- && INTEGERP (end->object)
- && end->charpos <= 0)
+ && INTEGERP (end->object))
{
x += end->pixel_width;
++end;
}
/* Scan the rest of the glyph row from the end, looking for the
first glyph that comes from BEFORE_STRING, AFTER_STRING, or
- COVER_STRING, or whose position is between START_CHARPOS
+ DISP_STRING, or whose position is between START_CHARPOS
and END_CHARPOS */
for ( ;
end < glyph
&& !INTEGERP (end->object)
- && !EQ (end->object, cover_string)
+ && !EQ (end->object, disp_string)
&& !(BUFFERP (end->object)
&& (end->charpos >= start_charpos
&& end->charpos < end_charpos));
note_mouse_highlight (struct frame *f, int x, int y)
{
Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
- enum window_part part;
+ enum window_part part = ON_NOTHING;
Lisp_Object window;
struct window *w;
Cursor cursor = No_Cursor;
/* Which window is that in? */
window = window_from_coordinates (f, x, y, &part, 1);
- /* If we were displaying active text in another window, clear that.
- Also clear if we move out of text area in same window. */
+ /* If displaying active text in another window, clear that. */
if (! EQ (window, hlinfo->mouse_face_window)
- || (part != ON_TEXT && part != ON_MODE_LINE && part != ON_HEADER_LINE
- && !NILP (hlinfo->mouse_face_window)))
+ /* Also clear if we move out of text area in same window. */
+ || (!NILP (hlinfo->mouse_face_window)
+ && !NILP (window)
+ && part != ON_TEXT
+ && part != ON_MODE_LINE
+ && part != ON_HEADER_LINE))
clear_mouse_face (hlinfo);
/* Not on a window -> return. */
&& XFASTINT (w->last_modified) == BUF_MODIFF (b)
&& XFASTINT (w->last_overlay_modified) == BUF_OVERLAY_MODIFF (b))
{
- int hpos, vpos, dx, dy, area;
+ int hpos, vpos, dx, dy, area = LAST_AREA;
EMACS_INT pos;
struct glyph *glyph;
Lisp_Object object;
/* The mouse-highlighting, if any, comes from an overlay
or text property in the buffer. */
Lisp_Object buffer IF_LINT (= Qnil);
- Lisp_Object cover_string IF_LINT (= Qnil);
+ Lisp_Object disp_string IF_LINT (= Qnil);
if (STRINGP (object))
{
mouse_face = get_char_property_and_overlay
(make_number (pos), Qmouse_face, w->buffer, &overlay);
buffer = w->buffer;
- cover_string = object;
+ disp_string = object;
}
}
else
{
buffer = object;
- cover_string = Qnil;
+ disp_string = Qnil;
}
if (!NILP (mouse_face))
}
mouse_face_from_buffer_pos (window, hlinfo, pos,
- XFASTINT (before),
- XFASTINT (after),
+ NILP (before)
+ ? 1
+ : XFASTINT (before),
+ NILP (after)
+ ? BUF_Z (XBUFFER (buffer))
+ : XFASTINT (after),
before_string, after_string,
- cover_string);
+ disp_string);
cursor = No_Cursor;
}
}
{
int yb = window_text_bottom_y (w);
struct glyph_row *row;
- int cursor_cleared_p;
+ int cursor_cleared_p, phys_cursor_on_p;
struct glyph_row *first_overlapping_row, *last_overlapping_row;
TRACE ((stderr, "expose_window (%d, %d, %d, %d)\n",
else
cursor_cleared_p = 0;
+ /* If the row containing the cursor extends face to end of line,
+ then expose_area might overwrite the cursor outside the
+ rectangle and thus notice_overwritten_cursor might clear
+ w->phys_cursor_on_p. We remember the original value and
+ check later if it is changed. */
+ phys_cursor_on_p = w->phys_cursor_on_p;
+
/* Update lines intersecting rectangle R. */
first_overlapping_row = last_overlapping_row = NULL;
for (row = w->current_matrix->rows;
x_draw_vertical_border (w);
/* Turn the cursor on again. */
- if (cursor_cleared_p)
+ if (cursor_cleared_p
+ || (phys_cursor_on_p && !w->phys_cursor_on_p))
update_window_cursor (w, 1);
}
}
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"),
Vshow_trailing_whitespace = Qnil;
DEFVAR_LISP ("nobreak-char-display", Vnobreak_char_display,
- doc: /* *Control highlighting of nobreak space and soft hyphen.
-A value of t means highlight the character itself (for nobreak space,
-use face `nobreak-space').
-A value of nil means no highlighting.
-Other values mean display the escape glyph followed by an ordinary
-space or ordinary hyphen. */);
+ doc: /* Control highlighting of non-ASCII space and hyphen chars.
+If the value is t, Emacs highlights non-ASCII chars which have the
+same appearance as an ASCII space or hyphen, using the `nobreak-space'
+or `escape-glyph' face respectively.
+
+U+00A0 (no-break space), U+00AD (soft hyphen), U+2010 (hyphen), and
+U+2011 (non-breaking hyphen) are affected.
+
+Any other non-nil value means to display these characters as a escape
+glyph followed by an ordinary space or hyphen.
+
+A value of nil means no special handling of these characters. */);
Vnobreak_char_display = Qt;
DEFVAR_LISP ("void-text-area-pointer", Vvoid_text_area_pointer,
DEFVAR_INT ("overline-margin", overline_margin,
doc: /* *Space between overline and text, in pixels.
The default value is 2: the height of the overline (1 pixel) plus 1 pixel
-margin to the caracter height. */);
+margin to the character height. */);
overline_margin = 2;
DEFVAR_INT ("underline-minimum-offset",