/* 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);
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
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)
{
EMACS_INT bpos = CHAR_TO_BYTE (newpos);
-
- if (FETCH_BYTE (bpos) == '\n'
- || (newpos > BEGV && FETCH_BYTE (bpos - 1) == '\n'))
+ 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 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;
+ 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;
+ }
}
else /* Must use the slow method. */
{
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. */
+ 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,
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)
{
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))
{
{
/* 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. */
/* 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);
|| (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. */
++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 =
STRINGP (it->string) ? it->current.string_pos : it->current.pos;
}
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
#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);
/* 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];
}
&& 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"),
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)
{