/* Display generation from window structure and buffer text.
-Copyright (C) 1985-1988, 1993-1995, 1997-2011 Free Software Foundation, Inc.
+Copyright (C) 1985-1988, 1993-1995, 1997-2012 Free Software Foundation, Inc.
This file is part of GNU Emacs.
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)
{
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
- prfoduced from the string, until we find the
+ produced from the string, until we find the
rightmost glyph not from the string. */
if (IT_CHARPOS (it3) != charpos && EQ (it3.object, string))
{
environments with anti-aliased text: if the same text is
drawn onto the same place multiple times, it gets thicker.
If the overlap we are processing is for the erased cursor, we
- take the intersection with the rectagle of the cursor. */
+ take the intersection with the rectangle of the cursor. */
if (s->for_overlaps & OVERLAPS_ERASED_CURSOR)
{
XRectangle rc, r_save = r;
if (charpos >= BUF_BEG (current_buffer))
{
it->end_charpos = ZV;
- it->face_id = -1;
IT_CHARPOS (*it) = charpos;
+ /* We will rely on `reseat' to set this up properly, via
+ handle_face_prop. */
+ it->face_id = it->base_face_id;
+
/* Compute byte position if not specified. */
if (bytepos < charpos)
IT_BYTEPOS (*it) = CHAR_TO_BYTE (charpos);
/* 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
|| (new_x == it->last_visible_x
&& FRAME_WINDOW_P (it->f))))
{
- if (it->current.dpvec_index >= 0
- || it->current.overlay_string_index >= 0)
+ if ((it->current.dpvec_index >= 0
+ || it->current.overlay_string_index >= 0)
+ /* If we are on a newline from a display vector or
+ overlay string, then we are already at the end of
+ a screen line; no need to go to the next line in
+ that case, as this line is not really continued.
+ (If we do go to the next line, C-e will not DTRT.) */
+ && it->c != '\n')
{
set_iterator_to_next (it, 1);
move_it_in_display_line_to (it, -1, -1, 0);
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
Lisp_Object object, limit, position;
EMACS_INT charpos, bytepos;
- /* If nowhere else, stop at the end. */
- it->stop_charpos = it->end_charpos;
-
if (STRINGP (it->string))
{
/* Strings are usually short, so don't limit the search for
properties. */
+ it->stop_charpos = it->end_charpos;
object = it->string;
limit = Qnil;
charpos = IT_STRING_CHARPOS (*it);
{
EMACS_INT pos;
+ /* If end_charpos is out of range for some reason, such as a
+ misbehaving display function, rationalize it (Bug#5984). */
+ if (it->end_charpos > ZV)
+ it->end_charpos = ZV;
+ it->stop_charpos = it->end_charpos;
+
/* If next overlay change is in front of the current stop pos
(which is IT->end_charpos), stop there. Note: value of
next_overlay_change is point-max if no overlay change
}
/* 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. */
with, so that overlay strings appear in the same face as
surrounding text, unless they specify their own
faces. */
- base_face_id = underlying_face_id (it);
+ base_face_id = it->string_from_prefix_prop_p
+ ? DEFAULT_FACE_ID
+ : underlying_face_id (it);
}
new_face_id = face_at_string_position (it->w,
while (invis_p);
/* The position newpos is now either ZV or on visible text. */
- if (it->bidi_p && newpos < ZV)
+ if (it->bidi_p)
{
- /* 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);
+ int on_newline =
+ bpos == ZV_BYTE || FETCH_BYTE (bpos) == '\n';
+ int after_newline =
+ newpos <= BEGV || FETCH_BYTE (bpos - 1) == '\n';
+
+ /* If the invisible text ends on a newline or on a
+ 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. */
+ if (on_newline || after_newline)
{
- /* 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);
+ struct text_pos tpos;
+ bidi_dir_t pdir = it->bidi_it.paragraph_dir;
+
+ SET_TEXT_POS (tpos, newpos, bpos);
+ reseat_1 (it, tpos, 0);
+ /* If we reseat on a newline/ZV, we need to prep the
+ bidi iterator for advancing to the next character
+ after the newline/EOB, keeping the current paragraph
+ direction (so that PRODUCE_GLYPHS does TRT wrt
+ prepending/appending glyphs to a glyph row). */
+ if (on_newline)
+ {
+ it->bidi_it.first_elt = 0;
+ it->bidi_it.paragraph_dir = pdir;
+ it->bidi_it.ch = (bpos == ZV_BYTE) ? -1 : '\n';
+ it->bidi_it.nchars = 1;
+ it->bidi_it.ch_len = 1;
+ }
}
- 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 of 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
{
int rv;
if (CONSP (spec)
- /* Simple specerties. */
+ /* Simple specifications. */
&& !EQ (XCAR (spec), Qimage)
&& !EQ (XCAR (spec), Qspace)
&& !EQ (XCAR (spec), Qwhen)
it->current.overlay_string_index = -1;
it->n_overlay_strings = 0;
it->overlay_strings_charpos = -1;
+ /* If there's an empty display string on the stack, pop the
+ stack, to resync the bidi iterator with IT's position. Such
+ empty strings are pushed onto the stack in
+ get_overlay_strings_1. */
+ if (it->sp > 0 && STRINGP (it->string) && !SCHARS (it->string))
+ pop_it (it);
/* If we're at the end of the buffer, record that we have
processed the overlay strings there already, so that
xassert (!compute_stop_p || it->sp == 0);
/* When called from handle_stop, there might be an empty display
- string loaded. In that case, don't bother saving it. */
- if (!STRINGP (it->string) || SCHARS (it->string))
+ string loaded. In that case, don't bother saving it. But
+ don't use this optimization with the bidi iterator, since we
+ need the corresponding pop_it call to resync the bidi
+ iterator's position with IT's position, after we are done
+ with the overlay strings. (The corresponding call to pop_it
+ in case of an empty display string is in
+ next_overlay_string.) */
+ if (!(!it->bidi_p
+ && STRINGP (it->string) && !SCHARS (it->string)))
push_it (it, NULL);
/* Set up IT to deliver display elements from the first overlay
p->font_height = it->font_height;
p->voffset = it->voffset;
p->string_from_display_prop_p = it->string_from_display_prop_p;
+ p->string_from_prefix_prop_p = it->string_from_prefix_prop_p;
p->display_ellipsis_p = 0;
p->line_wrap = it->line_wrap;
p->bidi_p = it->bidi_p;
it->font_height = p->font_height;
it->voffset = p->voffset;
it->string_from_display_prop_p = p->string_from_display_prop_p;
+ it->string_from_prefix_prop_p = p->string_from_prefix_prop_p;
it->line_wrap = p->line_wrap;
it->bidi_p = p->bidi_p;
it->paragraph_embedding = p->paragraph_embedding;
it->multibyte_p = !NILP (BVAR (current_buffer, enable_multibyte_characters));
it->sp = 0;
it->string_from_display_prop_p = 0;
+ it->string_from_prefix_prop_p = 0;
+
it->from_disp_prop_p = 0;
it->face_before_selective_p = 0;
if (it->bidi_p)
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;
}
}
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')))
{
if (it->current.overlay_string_index >= 0)
{
/* Get the next character from an overlay string. In overlay
- strings, There is no field width or padding with spaces to
+ strings, there is no field width or padding with spaces to
do. */
if (IT_STRING_CHARPOS (*it) >= SCHARS (it->string))
{
((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
reordering. We want to get to the character position
that is immediately after the newline of the previous
line. */
- if (it->bidi_p && IT_CHARPOS (*it) > BEGV
+ 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 =
{
/* DVPOS == 0 means move to the start of the screen line. */
move_it_vertically_backward (it, 0);
- xassert (it->current_x == 0 && it->hpos == 0);
/* Let next call to line_bottom_y calculate real line height */
last_height = 0;
}
{
move_it_to (it, -1, -1, -1, it->vpos + dvpos, MOVE_TO_VPOS);
if (!IT_POS_VALID_AFTER_MOVE_P (it))
- move_it_to (it, IT_CHARPOS (*it) + 1, -1, -1, -1, MOVE_TO_POS);
+ {
+ /* Only move to the next buffer position if we ended up in a
+ string from display property, not in an overlay string
+ (before-string or after-string). That is because the
+ latter don't conceal the underlying buffer position, so
+ we can ask to move the iterator to the exact position we
+ are interested in. Note that, even if we are already at
+ IT_CHARPOS (*it), the call below is not a no-op, as it
+ will detect that we are at the end of the string, pop the
+ iterator, and compute it->current_x and it->hpos
+ correctly. */
+ move_it_to (it, IT_CHARPOS (*it) + it->string_from_display_prop_p,
+ -1, -1, -1, MOVE_TO_POS);
+ }
}
else
{
}
-/* Push the current message on Vmessage_stack for later restauration
+/* Push the current message on Vmessage_stack for later restoration
by restore_message. Value is non-zero if the current message isn't
empty. This is a relatively infrequent operation, so it's not
worth optimizing. */
= (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)
/* Non-zero means we've seen at least one glyph that came from a
display string. */
int string_seen = 0;
- /* Largest and smalles buffer positions seen so far during scan of
+ /* Largest and smallest buffer positions seen so far during scan of
glyph row. */
EMACS_INT bpos_max = pos_before;
EMACS_INT bpos_min = pos_after;
chprop = Fget_char_property (make_number (glyph_pos), Qcursor,
glyph->object);
+ if (!NILP (chprop))
+ {
+ /* If the string came from a `display' text property,
+ look up the buffer position of that property and
+ use that position to update bpos_max, as if we
+ actually saw such a position in one of the row's
+ glyphs. This helps with supporting integer values
+ of `cursor' property on the display string in
+ situations where most or all of the row's buffer
+ text is completely covered by display properties,
+ so that no glyph with valid buffer positions is
+ ever seen in the row. */
+ EMACS_INT prop_pos =
+ string_buffer_position_lim (glyph->object, pos_before,
+ pos_after, 0);
+
+ if (prop_pos >= pos_before)
+ bpos_max = prop_pos - 1;
+ }
if (INTEGERP (chprop))
{
bpos_covered = bpos_max + XINT (chprop);
/* If the `cursor' property covers buffer positions up
to and including point, we should display cursor on
- this glyph. Note that overlays and text properties
- with string values stop bidi reordering, so every
- buffer position to the left of the string is always
- smaller than any position to the right of the
- string. Therefore, if a `cursor' property on one
+ this glyph. Note that, if a `cursor' property on one
of the string's characters has an integer value, we
will break out of the loop below _before_ we get to
the position match above. IOW, integer values of
chprop = Fget_char_property (make_number (glyph_pos), Qcursor,
glyph->object);
+ if (!NILP (chprop))
+ {
+ EMACS_INT prop_pos =
+ string_buffer_position_lim (glyph->object, pos_before,
+ pos_after, 0);
+
+ if (prop_pos >= pos_before)
+ bpos_max = prop_pos - 1;
+ }
if (INTEGERP (chprop))
{
bpos_covered = bpos_max + XINT (chprop);
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. But if a display string
- covers point, defer to the string-handling code
- below to figure this out. */
- || (!string_seen
- && ((row->truncated_on_left_p && pt_old < bpos_min)
- || (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)))))
+ else if (match_with_avoid_cursor)
{
cursor = glyph_after;
x = -1;
&& 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)
{
int scroll_margin_y;
- /* Compute the pixel ypos of the scroll margin, then move it to
+ /* Compute the pixel ypos of the scroll margin, then move IT to
either that ypos or PT, whichever comes first. */
start_display (&it, w, startp);
scroll_margin_y = it.last_visible_y - this_scroll_margin
if (dy > scroll_max)
return SCROLLING_FAILED;
- scroll_down_p = 1;
+ if (dy > 0)
+ scroll_down_p = 1;
}
}
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)
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 ();
? min (scroll_margin, WINDOW_TOTAL_LINES (w) / 4)
: 0;
EMACS_INT margin_pos = CHARPOS (startp);
- int scrolling_up;
Lisp_Object aggressive;
+ int scrolling_up;
/* If there is a scroll margin at the top of the window, find
its character position. */
accessible region of the buffer. This can happen when we
have just switched to a different buffer and/or changed
its restriction. In that case, startp is initialized to
- the character position 1 (BEG) because we did not yet
+ the character position 1 (BEGV) because we did not yet
have chance to display the buffer even once. */
&& BEGV <= CHARPOS (startp) && CHARPOS (startp) <= ZV)
{
SAVE_IT (it1, it, it1data);
start_display (&it1, w, startp);
- move_it_vertically (&it1, margin);
+ move_it_vertically (&it1, margin * FRAME_LINE_HEIGHT (f));
margin_pos = IT_CHARPOS (it1);
RESTORE_IT (&it, &it, it1data);
}
pt_offset = float_amount * WINDOW_BOX_TEXT_HEIGHT (w);
if (pt_offset == 0 && float_amount > 0)
pt_offset = 1;
- if (pt_offset)
+ if (pt_offset && margin > 0)
margin -= 1;
}
/* Compute how much to move the window start backward from
goto recenter;
}
+ /* Users who set scroll-conservatively to a large number want
+ point just above/below the scroll margin. If we ended up
+ with point's row partially visible, move the window start to
+ make that row fully visible and out of the margin. */
+ if (scroll_conservatively > SCROLL_LIMIT)
+ {
+ int margin =
+ scroll_margin > 0
+ ? min (scroll_margin, WINDOW_TOTAL_LINES (w) / 4)
+ : 0;
+ int move_down = w->cursor.vpos >= WINDOW_TOTAL_LINES (w) / 2;
+
+ move_it_by_lines (&it, move_down ? margin + 1 : -(margin + 1));
+ clear_glyph_matrix (w->desired_matrix);
+ if (1 == try_window (window, it.current.pos,
+ TRY_WINDOW_CHECK_MARGINS))
+ goto done;
+ }
+
/* If centering point failed to make the whole line visible,
put point at the top instead. That has to make the whole line
visible, if it can be done. */
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
++first_row_to_display)
{
if (PT >= MATRIX_ROW_START_CHARPOS (first_row_to_display)
- && PT < MATRIX_ROW_END_CHARPOS (first_row_to_display))
+ && (PT < MATRIX_ROW_END_CHARPOS (first_row_to_display)
+ || (PT == MATRIX_ROW_END_CHARPOS (first_row_to_display)
+ && first_row_to_display->ends_at_zv_p
+ && pt_row == NULL)))
pt_row = first_row_to_display;
}
if (pt_row)
{
for (row = MATRIX_ROW (w->current_matrix, w->cursor.vpos);
- row < bottom_row && PT >= MATRIX_ROW_END_CHARPOS (row);
+ row < bottom_row
+ && PT >= MATRIX_ROW_END_CHARPOS (row)
+ && !row->ends_at_zv_p;
row++)
{
w->cursor.vpos++;
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. */
}
}
+/* 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;
it->c = it->char_to_display = ' ';
it->len = 1;
+ /* If the default face was remapped, be sure to use the
+ remapped face for the appended newline. */
if (default_face_p)
- it->face_id = DEFAULT_FACE_ID;
+ it->face_id = lookup_basic_face (it->f, DEFAULT_FACE_ID);
else if (it->face_before_selective_p)
it->face_id = it->saved_face_id;
face = FACE_FROM_ID (it->f, it->face_id);
static void
extend_face_to_end_of_line (struct it *it)
{
- struct face *face;
+ struct face *face, *default_face;
struct frame *f = it->f;
/* If line is already filled, do nothing. Non window-system frames
&& !it->glyph_row->continued_p))
return;
+ /* The default face, possibly remapped. */
+ default_face = FACE_FROM_ID (f, lookup_basic_face (f, DEFAULT_FACE_ID));
+
/* Face extension extends the background and box of IT->face_id
to the end of the line. If the background equals the background
of the frame, we don't have to do anything. */
if (it->glyph_row->used[TEXT_AREA] == 0)
{
it->glyph_row->glyphs[TEXT_AREA][0] = space_glyph;
- it->glyph_row->glyphs[TEXT_AREA][0].face_id = it->face_id;
+ it->glyph_row->glyphs[TEXT_AREA][0].face_id = face->id;
it->glyph_row->used[TEXT_AREA] = 1;
}
#ifdef HAVE_WINDOW_SYSTEM
face, to avoid painting the rest of the window with
the region face, if the region ends at ZV. */
if (it->glyph_row->ends_at_zv_p)
- it->face_id = DEFAULT_FACE_ID;
+ it->face_id = default_face->id;
else
it->face_id = face->id;
append_stretch_glyph (it, make_number (0), stretch_width,
avoid painting the rest of the window with the region face,
if the region ends at ZV. */
if (it->glyph_row->ends_at_zv_p)
- it->face_id = DEFAULT_FACE_ID;
+ it->face_id = default_face->id;
else
it->face_id = face->id;
/* Suppose the row ends on a string.
Unless the row is continued, that means it ends on a newline
in the string. If it's anything other than a display string
- (e.g. a before-string from an overlay), we don't want the
+ (e.g., a before-string from an overlay), we don't want the
cursor there. (This heuristic seems to give the optimal
- behavior for the various types of multi-line strings.) */
+ behavior for the various types of multi-line strings.)
+ One exception: if the string has `cursor' property on one of
+ its characters, we _do_ want the cursor there. */
if (CHARPOS (row->end.string_pos) >= 0)
{
if (row->continued_p)
result =
(!NILP (prop)
&& display_prop_string_p (prop, glyph->object));
+ /* If there's a `cursor' property on one of the
+ string's characters, this row is a cursor row,
+ even though this is not a display string. */
+ if (!result)
+ {
+ Lisp_Object s = glyph->object;
+
+ for ( ; glyph >= beg && EQ (glyph->object, s); --glyph)
+ {
+ EMACS_INT gpos = glyph->charpos;
+
+ if (!NILP (Fget_char_property (make_number (gpos),
+ Qcursor, s)))
+ {
+ result = 1;
+ break;
+ }
+ }
+ }
break;
}
}
`line-prefix' and `wrap-prefix' properties. */
static int
-push_display_prop (struct it *it, Lisp_Object prop)
+push_prefix_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
}
it->string = prop;
+ it->string_from_prefix_prop_p = 1;
it->multibyte_p = STRING_MULTIBYTE (it->string);
it->current.overlay_string_index = -1;
IT_STRING_CHARPOS (*it) = IT_STRING_BYTEPOS (*it) = 0;
if (NILP (prefix))
prefix = Vline_prefix;
}
- if (! NILP (prefix) && push_display_prop (it, prefix))
+ if (! NILP (prefix) && push_prefix_prop (it, prefix))
{
/* If the prefix is wider than the window, and we try to wrap
it, it would acquire its own wrap prefix, and so on till the
seen_this_string = 1;
}
else
- abort ();
+ /* 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
{
seen_this_string = 1;
}
else
- abort ();
+ seen_this_string = 1;
}
}
/* Take note of each display string that covers a newline only
#define RECORD_MAX_MIN_POS(IT) \
do \
{ \
- int composition_p = (IT)->what == IT_COMPOSITION; \
+ int composition_p = !STRINGP ((IT)->string) \
+ && ((IT)->what == IT_COMPOSITION); \
EMACS_INT current_pos = \
composition_p ? (IT)->cmp_it.charpos \
: IT_CHARPOS (*(IT)); \
/* A row that displays right-to-left text must always have
its last face extended all the way to the end of line,
even if this row ends in ZV, because we still write to
- the screen left to right. */
- if (row->reversed_p)
+ the screen left to right. We also need to extend the
+ last face if the default face is remapped to some
+ different face, otherwise the functions that clear
+ portions of the screen will clear with the default face's
+ background color. */
+ if (row->reversed_p
+ || lookup_basic_face (it->f, DEFAULT_FACE_ID) != DEFAULT_FACE_ID)
extend_face_to_end_of_line (it);
break;
}
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);
bytepos--;
}
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.string.bufpos = 0;
/* 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)
}
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;
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); \
+ struct glyph_string *first_s = NULL; \
int n; \
\
char2b = (XChar2b *) alloca ((sizeof *char2b) * cmp->glyph_len); \
{
width = it->last_visible_x - it->current_x;
#ifdef HAVE_WINDOW_SYSTEM
- /* Subtact one more pixel from the stretch width, but only on
+ /* 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
sprintf (buf, "%0*X", it->c < 0x10000 ? 4 : 6, it->c);
str = buf;
}
- for (len = 0; str[len] && ASCII_BYTE_P (str[len]); len++)
+ for (len = 0; str[len] && ASCII_BYTE_P (str[len]) && len < 6; len++)
code[len] = font->driver->encode_char (font, str[len]);
upper_len = (len + 1) / 2;
font->driver->text_extents (font, code, upper_len,
/* Initialize the bounding box. */
if (pcm)
{
- width = pcm->width;
+ width = cmp->glyph_len > 0 ? pcm->width : 0;
ascent = pcm->ascent;
descent = pcm->descent;
lbearing = pcm->lbearing;
}
else
{
- width = font->space_width;
+ width = cmp->glyph_len > 0 ? font->space_width : 0;
ascent = FONT_BASE (font);
descent = FONT_DESCENT (font);
lbearing = 0;
if (it->descent < 0)
it->descent = 0;
- if (it->glyph_row)
+ if (it->glyph_row && cmp->glyph_len > 0)
append_composite_glyph (it);
}
else if (it->what == IT_COMPOSITION)
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);
}
\f
/* Find the glyph rows START_ROW and END_ROW of window W that display
characters between buffer positions START_CHARPOS and END_CHARPOS
- (excluding END_CHARPOS). This is similar to row_containing_pos,
- but is more accurate when bidi reordering makes buffer positions
- change non-linearly with glyph rows. */
+ (excluding END_CHARPOS). DISP_STRING is a display string that
+ covers these buffer positions. This is similar to
+ row_containing_pos, but is more accurate when bidi reordering makes
+ buffer positions change non-linearly with glyph rows. */
static void
rows_from_pos_range (struct window *w,
EMACS_INT start_charpos, EMACS_INT end_charpos,
+ Lisp_Object disp_string,
struct glyph_row **start, struct glyph_row **end)
{
struct glyph_row *first = MATRIX_FIRST_TEXT_ROW (w->current_matrix);
while (g < e)
{
- if ((BUFFERP (g->object) || INTEGERP (g->object))
- && start_charpos <= g->charpos && g->charpos < end_charpos)
+ if (((BUFFERP (g->object) || INTEGERP (g->object))
+ && start_charpos <= g->charpos && g->charpos < end_charpos)
+ /* A glyph that comes from DISP_STRING is by
+ definition to be highlighted. */
+ || EQ (g->object, disp_string))
*start = row;
g++;
}
for ( ; row->enabled_p && MATRIX_ROW_BOTTOM_Y (row) <= last_y; row++)
{
struct glyph_row *next = row + 1;
+ EMACS_INT next_start = MATRIX_ROW_START_CHARPOS (next);
if (!next->enabled_p
|| next >= MATRIX_BOTTOM_TEXT_ROW (w->current_matrix, w)
/* The first row >= START whose range of displayed characters
does NOT intersect the range [START_CHARPOS..END_CHARPOS]
is the row END + 1. */
- || (start_charpos < MATRIX_ROW_START_CHARPOS (next)
- && end_charpos < MATRIX_ROW_START_CHARPOS (next))
+ || (start_charpos < next_start
+ && end_charpos < next_start)
|| ((start_charpos > MATRIX_ROW_END_CHARPOS (next)
|| (start_charpos == MATRIX_ROW_END_CHARPOS (next)
&& !next->ends_at_zv_p
but none of the characters it displays are in the range, it is
also END + 1. */
struct glyph *g = next->glyphs[TEXT_AREA];
+ struct glyph *s = g;
struct glyph *e = g + next->used[TEXT_AREA];
while (g < e)
{
- if ((BUFFERP (g->object) || INTEGERP (g->object))
- && start_charpos <= g->charpos && g->charpos < end_charpos)
+ if (((BUFFERP (g->object) || INTEGERP (g->object))
+ && ((start_charpos <= g->charpos && g->charpos < end_charpos)
+ /* If the buffer position of the first glyph in
+ the row is equal to END_CHARPOS, it means
+ the last character to be highlighted is the
+ newline of ROW, and we must consider NEXT as
+ END, not END+1. */
+ || (((!next->reversed_p && g == s)
+ || (next->reversed_p && g == e - 1))
+ && (g->charpos == end_charpos
+ /* Special case for when NEXT is an
+ empty line at ZV. */
+ || (g->charpos == -1
+ && !row->ends_at_zv_p
+ && next_start == end_charpos)))))
+ /* A glyph that comes from DISP_STRING is by
+ definition to be highlighted. */
+ || EQ (g->object, disp_string))
break;
g++;
}
*end = row;
break;
}
+ /* The first row that ends at ZV must be the last to be
+ highlighted. */
+ else if (next->ends_at_zv_p)
+ {
+ *end = next;
+ break;
+ }
}
}
}
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));
/* Find the rows corresponding to START_CHARPOS and END_CHARPOS. */
- rows_from_pos_range (w, start_charpos, end_charpos, &r1, &r2);
+ rows_from_pos_range (w, start_charpos, end_charpos, disp_string, &r1, &r2);
if (r1 == NULL)
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));
}
x += end->pixel_width;
}
+ /* If we exited the above loop because we arrived at the last
+ glyph of the row, and its buffer position is still not in
+ range, it means the last character in range is the preceding
+ newline. Bump the end column and x values to get past the
+ last glyph. */
+ if (end == glyph
+ && BUFFERP (end->object)
+ && (end->charpos < start_charpos
+ || end->charpos >= end_charpos))
+ {
+ x += end->pixel_width;
+ ++end;
+ }
hlinfo->mouse_face_end_x = x;
hlinfo->mouse_face_end_col = end - r2->glyphs[TEXT_AREA];
}
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;
}
}
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,
Each function is called with two arguments, the window and its new
display-start position. Note that these functions are also called by
`set-window-buffer'. Also note that the value of `window-end' is not
-valid when these functions are called. */);
+valid when these functions are called.
+
+Warning: Do not use this feature to alter the way the window
+is scrolled. It is not designed for that, and such use probably won't
+work. */);
Vwindow_scroll_functions = Qnil;
DEFVAR_LISP ("window-text-change-functions",
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",
/* Platform-independent portion of hourglass implementation. */
-/* Return non-zero if houglass timer has been started or hourglass is shown. */
+/* Return non-zero if hourglass timer has been started or hourglass is
+ shown. */
int
hourglass_started (void)
{