/* Display generation from window structure and buffer text.
Copyright (C) 1985, 1986, 1987, 1988, 1993, 1994, 1995,
1997, 1998, 1999, 2000, 2001, 2002, 2003,
- 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+ 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
This file is part of GNU Emacs.
#include "coding.h"
#include "process.h"
#include "region-cache.h"
+#include "font.h"
#include "fontset.h"
#include "blockinput.h"
extern Lisp_Object Qmenu_item;
extern Lisp_Object Qwhen;
extern Lisp_Object Qhelp_echo;
+extern Lisp_Object Qbefore_string, Qafter_string;
Lisp_Object Qoverriding_local_map, Qoverriding_terminal_local_map;
Lisp_Object Qwindow_scroll_functions, Vwindow_scroll_functions;
&& it->current_x == it->last_visible_x \
&& it->line_wrap != WORD_WRAP)
+#else /* !HAVE_WINDOW_SYSTEM */
+#define IT_OVERFLOW_NEWLINE_INTO_FRINGE(it) 0
#endif /* HAVE_WINDOW_SYSTEM */
/* Test if the display element loaded in IT is a space or tab
static enum prop_handled handle_composition_prop P_ ((struct it *));
static enum prop_handled handle_overlay_change P_ ((struct it *));
static enum prop_handled handle_fontified_prop P_ ((struct it *));
-static enum prop_handled handle_auto_composed_prop P_ ((struct it *));
/* Properties handled by iterators. */
{&Qface, FACE_PROP_IDX, handle_face_prop},
{&Qdisplay, DISPLAY_PROP_IDX, handle_display_prop},
{&Qinvisible, INVISIBLE_PROP_IDX, handle_invisible_prop},
- {&Qauto_composed, AUTO_COMPOSED_PROP_IDX, handle_auto_composed_prop},
{&Qcomposition, COMPOSITION_PROP_IDX, handle_composition_prop},
{NULL, 0, NULL}
};
int visible_p = 0;
struct buffer *old_buffer = NULL;
- if (noninteractive)
+ if (FRAME_INITIAL_P (XFRAME (WINDOW_FRAME (w))))
return visible_p;
if (XBUFFER (w->buffer) != current_buffer)
move_it_to (&it, charpos, -1, it.last_visible_y-1, -1,
(charpos >= 0 ? MOVE_TO_POS : 0) | MOVE_TO_Y);
- /* Note that we may overshoot because of invisible text. */
if (charpos >= 0 && IT_CHARPOS (it) >= charpos)
{
+ /* We have reached CHARPOS, or passed it. How the call to
+ move_it_to can overshoot: (i) If CHARPOS is on invisible
+ text, move_it_to stops at the end of the invisible text,
+ after CHARPOS. (ii) If CHARPOS is in a display vector,
+ move_it_to stops on its last glyph. */
int top_x = it.current_x;
int top_y = it.current_y;
+ enum it_method it_method = it.method;
+ /* Calling line_bottom_y may change it.method. */
int bottom_y = (last_height = 0, line_bottom_y (&it));
int window_top_y = WINDOW_HEADER_LINE_HEIGHT (w);
if (top_y < window_top_y)
visible_p = bottom_y > window_top_y;
else if (top_y < it.last_visible_y)
- visible_p = 1;
+ visible_p = 1;
if (visible_p)
{
- if (it.method == GET_FROM_BUFFER)
+ if (it_method == GET_FROM_BUFFER)
{
Lisp_Object window, prop;
struct glyph *end = glyph + row->used[TEXT_AREA];
int x = row->x;
- for (; glyph < end && glyph->charpos < charpos; glyph++)
+ for (; glyph < end
+ && (!BUFFERP (glyph->object)
+ || glyph->charpos < charpos);
+ glyph++)
x += glyph->pixel_width;
-
top_x = x;
}
}
+ else if (it_method == GET_FROM_DISPLAY_VECTOR)
+ {
+ /* We stopped on the last glyph of a display vector.
+ Try and recompute. Hack alert! */
+ if (charpos < 2 || top.charpos >= charpos)
+ top_x = it.glyph_row->x;
+ else
+ {
+ struct it it2;
+ start_display (&it2, w, top);
+ move_it_to (&it2, charpos - 1, -1, -1, -1, MOVE_TO_POS);
+ get_next_display_element (&it2);
+ PRODUCE_GLYPHS (&it2);
+ if (ITERATOR_AT_END_OF_LINE_P (&it2)
+ || it2.current_x > it2.last_visible_x)
+ top_x = it.glyph_row->x;
+ else
+ {
+ top_x = it2.current_x;
+ top_y = it2.current_y;
+ }
+ }
+ }
*x = top_x;
*y = max (top_y + max (0, it.max_ascent - it.ascent), window_top_y);
it->w = w;
it->f = XFRAME (w->frame);
+ it->cmp_it.id = -1;
+
/* Extra space between lines (on window systems only). */
if (base_face_id == DEFAULT_FACE_ID
&& FRAME_WINDOW_P (it->f))
it->current_x = it->hpos = 0;
}
}
-
-#if 0 /* Don't assert the following because start_display is sometimes
- called intentionally with a window start that is not at a
- line start. Please leave this code in as a comment. */
-
- /* Window start should be on a line start, now. */
- xassert (it->continuation_lines_width
- || IT_CHARPOS (it) == BEGV
- || FETCH_BYTE (IT_BYTEPOS (it) - 1) == '\n');
-#endif /* 0 */
}
it->method = GET_FROM_STRING;
}
-#if 0 /* This is bogus because POS not having an overlay string
- position does not mean it's after the string. Example: A
- line starting with a before-string and initialization of IT
- to the previous row's end position. */
- else if (it->current.overlay_string_index >= 0)
- {
- /* If POS says we're already after an overlay string ending at
- POS, make sure to pop the iterator because it will be in
- front of that overlay string. When POS is ZV, we've thereby
- also ``processed'' overlay strings at ZV. */
- while (it->sp)
- pop_it (it);
- xassert (it->current.overlay_string_index == -1);
- xassert (it->method == GET_FROM_BUFFER);
- if (CHARPOS (pos->pos) == ZV)
- it->overlay_strings_at_end_processed_p = 1;
- }
-#endif /* 0 */
-
if (CHARPOS (pos->string_pos) >= 0)
{
/* Recorded position is not in an overlay string, but in another
{
if (it->ellipsis_p)
setup_for_ellipsis (it, 0);
+ /* When handling a display spec, we might load an
+ empty string. In that case, discard it here. We
+ used to discard it in handle_single_display_spec,
+ but that causes get_overlay_strings_1, above, to
+ ignore overlay strings that we must check. */
+ if (STRINGP (it->string) && !SCHARS (it->string))
+ pop_it (it);
return;
}
- it->ignore_overlay_strings_at_pos_p = 1;
- it->string_from_display_prop_p = 0;
- handle_overlay_change_p = 0;
+ else if (STRINGP (it->string) && !SCHARS (it->string))
+ pop_it (it);
+ else
+ {
+ it->ignore_overlay_strings_at_pos_p = 1;
+ it->string_from_display_prop_p = 0;
+ handle_overlay_change_p = 0;
+ }
handled = HANDLED_RECOMPUTE_PROPS;
break;
}
{
register INTERVAL iv, next_iv;
Lisp_Object object, limit, position;
+ EMACS_INT charpos, bytepos;
/* If nowhere else, stop at the end. */
it->stop_charpos = it->end_charpos;
properties. */
object = it->string;
limit = Qnil;
- position = make_number (IT_STRING_CHARPOS (*it));
+ charpos = IT_STRING_CHARPOS (*it);
+ bytepos = IT_STRING_BYTEPOS (*it);
}
else
{
- int charpos;
+ EMACS_INT pos;
/* 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
follows. */
- charpos = next_overlay_change (IT_CHARPOS (*it));
- if (charpos < it->stop_charpos)
- it->stop_charpos = charpos;
+ charpos = IT_CHARPOS (*it);
+ bytepos = IT_BYTEPOS (*it);
+ pos = next_overlay_change (charpos);
+ if (pos < it->stop_charpos)
+ it->stop_charpos = pos;
/* If showing the region, we have to stop at the region
start or end because the face might change there. */
property changes. */
XSETBUFFER (object, current_buffer);
limit = make_number (IT_CHARPOS (*it) + TEXT_PROP_DISTANCE_LIMIT);
- position = make_number (IT_CHARPOS (*it));
-
}
/* Get the interval containing IT's position. Value is a null
interval if there isn't such an interval. */
+ position = make_number (charpos);
iv = validate_interval_range (object, &position, &position, 0);
if (!NULL_INTERVAL_P (iv))
{
}
}
+ composition_compute_stop_pos (&it->cmp_it, charpos, bytepos,
+ it->stop_charpos, it->string);
+
xassert (STRINGP (it->string)
|| (it->stop_charpos >= BEGV
&& it->stop_charpos >= IT_CHARPOS (*it)));
&next_stop,
(IT_CHARPOS (*it)
+ TEXT_PROP_DISTANCE_LIMIT),
- 0);
+ 0, it->base_face_id);
/* Is this a start of a run of characters with box face?
Caveat: this can be called for a freshly initialized
&next_stop,
base_face_id, 0);
-#if 0 /* This shouldn't be neccessary. Let's check it. */
- /* If IT is used to display a mode line we would really like to
- use the mode line face instead of the frame's default face. */
- if (it->glyph_row == MATRIX_MODE_LINE_ROW (it->w->desired_matrix)
- && new_face_id == DEFAULT_FACE_ID)
- new_face_id = CURRENT_MODE_LINE_FACE_ID (it->w);
-#endif
-
/* Is this a start of a run of characters with box? Caveat:
this can be called for a freshly allocated iterator; face_id
is -1 is this case. We know that the new face will not
/* For composition, we must check the character after the
composition. */
pos = (it->what == IT_COMPOSITION
- ? string_pos (IT_STRING_CHARPOS (*it) + it->cmp_len, it->string)
+ ? string_pos (IT_STRING_CHARPOS (*it)
+ + it->cmp_it.nchars, it->string)
: string_pos (IT_STRING_CHARPOS (*it) + 1, it->string));
if (it->current.overlay_string_index >= 0)
if (it->what == IT_COMPOSITION)
/* For composition, we must check the position after the
composition. */
- pos.charpos += it->cmp_len, pos.bytepos += it->len;
+ pos.charpos += it->cmp_it.nchars, pos.bytepos += it->len;
else
INC_TEXT_POS (pos, it->multibyte_p);
}
it->region_beg_charpos,
it->region_end_charpos,
&next_check_charpos,
- limit, 0);
+ limit, 0, -1);
/* Correct the face for charsets different from ASCII. Do it
for the multibyte case only. The face returned above is
}
else
{
- int ret = handle_single_display_spec (it, prop, object, overlay,
- position, 0);
- if (ret < 0) /* Replaced by "", i.e. nothing. */
- return HANDLED_RECOMPUTE_PROPS;
- if (ret)
+ if (handle_single_display_spec (it, prop, object, overlay,
+ position, 0))
display_replaced_p = 1;
}
property ends.
Value is non-zero if something was found which replaces the display
- of buffer or string text. Specifically, the value is -1 if that
- "something" is "nothing". */
+ of buffer or string text. */
static int
handle_single_display_spec (it, spec, object, overlay, position,
if (STRINGP (value))
{
- if (SCHARS (value) == 0)
- {
- pop_it (it);
- return -1; /* Replaced by "", i.e. nothing. */
- }
it->string = value;
it->multibyte_p = STRING_MULTIBYTE (it->string);
it->current.overlay_string_index = -1;
`composition' property
***********************************************************************/
-static enum prop_handled
-handle_auto_composed_prop (it)
- struct it *it;
-{
- enum prop_handled handled = HANDLED_NORMALLY;
-
- if (FUNCTIONP (Vauto_composition_function))
- {
- Lisp_Object val = Qnil;
- EMACS_INT pos, limit = -1;
-
- if (STRINGP (it->string))
- pos = IT_STRING_CHARPOS (*it);
- else
- pos = IT_CHARPOS (*it);
-
- val = Fget_text_property (make_number (pos), Qauto_composed, it->string);
- if (! NILP (val))
- {
- Lisp_Object cmp_prop;
- EMACS_INT cmp_start, cmp_end;
-
- if (get_property_and_range (pos, Qcomposition, &cmp_prop,
- &cmp_start, &cmp_end, it->string)
- && cmp_start == pos
- && COMPOSITION_METHOD (cmp_prop) == COMPOSITION_WITH_GLYPH_STRING)
- {
- Lisp_Object gstring = COMPOSITION_COMPONENTS (cmp_prop);
- Lisp_Object font_object = LGSTRING_FONT (gstring);
-
- if (! EQ (font_object,
- font_at (-1, pos, FACE_FROM_ID (it->f, it->face_id),
- it->w, it->string)))
- /* We must re-compute the composition for the
- different font. */
- val = Qnil;
- }
-
- if (! NILP (val))
- {
- Lisp_Object end;
-
- /* As Fnext_single_char_property_change is very slow, we
- limit the search to the current line. */
- if (STRINGP (it->string))
- limit = SCHARS (it->string);
- else
- limit = find_next_newline_no_quit (pos, 1);
- end = Fnext_single_char_property_change (make_number (pos),
- Qauto_composed,
- it->string,
- make_number (limit));
-
- if (XINT (end) < limit)
- /* The current point is auto-composed, but there exist
- characters not yet composed beyond the
- auto-composed region. There's a possiblity that
- the last characters in the region may be newly
- composed. */
- val = Qnil;
- }
- }
- if (NILP (val) && ! STRINGP (it->string))
- {
- if (limit < 0)
- limit = (STRINGP (it->string) ? SCHARS (it->string)
- : find_next_newline_no_quit (pos, 1));
- if (pos < limit)
- {
- int count = SPECPDL_INDEX ();
- Lisp_Object args[5];
-
- if (FRAME_WINDOW_P (it->f))
- limit = font_range (pos, limit,
- FACE_FROM_ID (it->f, it->face_id),
- it->f, it->string);
- args[0] = Vauto_composition_function;
- specbind (Qauto_composition_function, Qnil);
- args[1] = make_number (pos);
- args[2] = make_number (limit);
- args[3] = it->window;
- args[4] = it->string;
- safe_call (5, args);
- unbind_to (count, Qnil);
- }
- }
- }
-
- return handled;
-}
-
/* Set up iterator IT from `composition' property at its current
position. Called from handle_stop. */
{
Lisp_Object prop, string;
EMACS_INT pos, pos_byte, start, end;
- enum prop_handled handled = HANDLED_NORMALLY;
if (STRINGP (it->string))
{
&& COMPOSITION_VALID_P (start, end, prop)
&& (STRINGP (it->string) || (PT <= start || PT >= end)))
{
- int id;
-
if (start != pos)
{
if (STRINGP (it->string))
else
pos_byte = CHAR_TO_BYTE (start);
}
- id = get_composition_id (start, pos_byte, end - start, prop, string);
+ it->cmp_it.id = get_composition_id (start, pos_byte, end - start,
+ prop, string);
- if (id >= 0)
+ if (it->cmp_it.id >= 0)
{
- struct composition *cmp = composition_table[id];
-
- if (cmp->glyph_len == 0)
- {
- /* No glyph. */
- if (STRINGP (it->string))
- {
- IT_STRING_CHARPOS (*it) = end;
- IT_STRING_BYTEPOS (*it) = string_char_to_byte (it->string,
- end);
- }
- else
- {
- IT_CHARPOS (*it) = end;
- IT_BYTEPOS (*it) = CHAR_TO_BYTE (end);
- }
- return HANDLED_RECOMPUTE_PROPS;
- }
-
- it->stop_charpos = end;
- push_it (it);
-
- it->method = GET_FROM_COMPOSITION;
- it->cmp_id = id;
- it->cmp_len = COMPOSITION_LENGTH (prop);
- /* For a terminal, draw only the first (non-TAB) character
- of the components. */
- if (composition_table[id]->method == COMPOSITION_WITH_GLYPH_STRING)
- {
- /* FIXME: This doesn't do anything!?! */
- Lisp_Object lgstring = AREF (XHASH_TABLE (composition_hash_table)
- ->key_and_value,
- cmp->hash_index * 2);
- }
- else
- {
- int i;
-
- for (i = 0; i < cmp->glyph_len; i++)
- if ((it->c = COMPOSITION_GLYPH (composition_table[id], i))
- != '\t')
- break;
- }
- if (it->c == '\t')
- it->c = ' ';
- it->len = (STRINGP (it->string)
- ? string_char_to_byte (it->string, end)
- : CHAR_TO_BYTE (end)) - pos_byte;
- handled = HANDLED_RETURN;
+ it->cmp_it.ch = -1;
+ it->cmp_it.nchars = COMPOSITION_LENGTH (prop);
+ it->cmp_it.nglyphs = -1;
}
}
- return handled;
+ return HANDLED_NORMALLY;
}
it->ellipsis_p = (it->stack[it->sp - 1].display_ellipsis_p != 0);
pop_it (it);
xassert (it->sp > 0
- || it->method == GET_FROM_COMPOSITION
|| (NILP (it->string)
&& it->method == GET_FROM_BUFFER
&& it->stop_charpos >= BEGV
SET_TEXT_POS (it->current.string_pos, 0, 0);
it->method = GET_FROM_STRING;
it->stop_charpos = 0;
+ if (it->cmp_it.stop_pos >= 0)
+ it->cmp_it.stop_pos = 0;
}
CHECK_IT (it);
struct it *it;
int charpos;
{
- extern Lisp_Object Qafter_string, Qbefore_string, Qwindow, Qpriority;
+ extern Lisp_Object Qwindow, Qpriority;
Lisp_Object overlay, window, str, invisible;
struct Lisp_Overlay *ov;
int start, end;
/* Save IT's settings. They are restored after all overlay
strings have been processed. */
xassert (!compute_stop_p || it->sp == 0);
- push_it (it);
+
+ /* 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))
+ push_it (it);
/* Set up IT to deliver display elements from the first overlay
string. */
p = it->stack + it->sp;
p->stop_charpos = it->stop_charpos;
+ p->cmp_it = it->cmp_it;
xassert (it->face_id >= 0);
p->face_id = it->face_id;
p->string = it->string;
p->u.image.image_id = it->image_id;
p->u.image.slice = it->slice;
break;
- case GET_FROM_COMPOSITION:
- p->u.comp.object = it->object;
- p->u.comp.c = it->c;
- p->u.comp.len = it->len;
- p->u.comp.cmp_id = it->cmp_id;
- p->u.comp.cmp_len = it->cmp_len;
- break;
case GET_FROM_STRETCH:
p->u.stretch.object = it->object;
break;
p->voffset = it->voffset;
p->string_from_display_prop_p = it->string_from_display_prop_p;
p->display_ellipsis_p = 0;
+ p->line_wrap = it->line_wrap;
++it->sp;
}
--it->sp;
p = it->stack + it->sp;
it->stop_charpos = p->stop_charpos;
+ it->cmp_it = p->cmp_it;
it->face_id = p->face_id;
it->current = p->current;
it->position = p->position;
it->object = p->u.image.object;
it->slice = p->u.image.slice;
break;
- case GET_FROM_COMPOSITION:
- it->object = p->u.comp.object;
- it->c = p->u.comp.c;
- it->len = p->u.comp.len;
- it->cmp_id = p->u.comp.cmp_id;
- it->cmp_len = p->u.comp.cmp_len;
- break;
case GET_FROM_STRETCH:
it->object = p->u.comp.object;
break;
it->font_height = p->font_height;
it->voffset = p->voffset;
it->string_from_display_prop_p = p->string_from_display_prop_p;
+ it->line_wrap = p->line_wrap;
}
{
next_element_from_buffer,
next_element_from_display_vector,
- next_element_from_composition,
next_element_from_string,
next_element_from_c_string,
next_element_from_image,
#define GET_NEXT_DISPLAY_ELEMENT(it) (*get_next_element[(it)->method]) (it)
+
+/* Return 1 iff a character at CHARPOS (and BYTEPOS) is composed
+ (possibly with the following characters). */
+
+#define CHAR_COMPOSED_P(IT,CHARPOS,BYTEPOS) \
+ ((IT)->cmp_it.id >= 0 \
+ || ((IT)->cmp_it.stop_pos == (CHARPOS) \
+ && composition_reseat_it (&(IT)->cmp_it, CHARPOS, BYTEPOS, \
+ (IT)->end_charpos, (IT)->w, \
+ FACE_FROM_ID ((IT)->f, (IT)->face_id), \
+ (IT)->string)))
+
+
/* Load IT's display element fields with information about the next
display element from the current position of IT. Value is zero if
end of buffer (or C string) is reached. */
if (success_p && it->dpvec == NULL)
{
Lisp_Object dv;
+ struct charset *unibyte = CHARSET_FROM_ID (charset_unibyte);
if (it->dp
&& (dv = DISP_CHAR_VECTOR (it->dp, it->c),
? (it->area != TEXT_AREA
/* In mode line, treat \n, \t like other crl chars. */
|| (it->c != '\t'
- && it->glyph_row && it->glyph_row->mode_line_p)
+ && it->glyph_row
+ && (it->glyph_row->mode_line_p || it->avoid_cursor_p))
|| (it->c != '\n' && it->c != '\t'))
: (it->multibyte_p
? (!CHAR_PRINTABLE_P (it->c)
|| it->c == 0xAD /* SOFT HYPHEN */)))
: (it->c >= 127
&& (! unibyte_display_via_language_environment
- || (UNIBYTE_CHAR_HAS_MULTIBYTE_P (it->c)))))))
+ || (DECODE_CHAR (unibyte, it->c) <= 0xA0))))))
{
/* IT->c is a control character which must be displayed
either as '\003' or as `^C' where the '\\' and '^'
}
}
+#ifdef HAVE_WINDOW_SYSTEM
/* Adjust face id for a multibyte character. There are no multibyte
character in unibyte text. */
if ((it->what == IT_CHARACTER || it->what == IT_COMPOSITION)
&& FRAME_WINDOW_P (it->f))
{
struct face *face = FACE_FROM_ID (it->f, it->face_id);
- int pos = (it->s ? -1
- : STRINGP (it->string) ? IT_STRING_CHARPOS (*it)
- : IT_CHARPOS (*it));
- it->face_id = FACE_FOR_CHAR (it->f, face, it->c, pos, it->string);
+ if (it->what == IT_COMPOSITION && it->cmp_it.ch >= 0)
+ {
+ /* Automatic composition with glyph-string. */
+ Lisp_Object gstring = composition_gstring_from_id (it->cmp_it.id);
+
+ it->face_id = face_for_font (it->f, LGSTRING_FONT (gstring), face);
+ }
+ else
+ {
+ int pos = (it->s ? -1
+ : STRINGP (it->string) ? IT_STRING_CHARPOS (*it)
+ : IT_CHARPOS (*it));
+
+ it->face_id = FACE_FOR_CHAR (it->f, face, it->c, pos, it->string);
+ }
}
+#endif
/* Is this character the last one of a run of characters with
box? If yes, set IT->end_of_box_run_p to 1. */
if (it->face_box_p
&& it->s == NULL)
{
- int face_id;
- struct face *face;
+ if (it->method == GET_FROM_STRING && it->sp)
+ {
+ int face_id = underlying_face_id (it);
+ struct face *face = FACE_FROM_ID (it->f, face_id);
- it->end_of_box_run_p
- = ((face_id = face_after_it_pos (it),
- face_id != it->face_id)
- && (face = FACE_FROM_ID (it->f, face_id),
- face->box == FACE_NO_BOX));
+ if (face)
+ {
+ if (face->box == FACE_NO_BOX)
+ {
+ /* If the box comes from face properties in a
+ display string, check faces in that string. */
+ int string_face_id = face_after_it_pos (it);
+ it->end_of_box_run_p
+ = (FACE_FROM_ID (it->f, string_face_id)->box
+ == FACE_NO_BOX);
+ }
+ /* Otherwise, the box comes from the underlying face.
+ If this is the last string character displayed, check
+ the next buffer location. */
+ else if ((IT_STRING_CHARPOS (*it) >= SCHARS (it->string) - 1)
+ && (it->current.overlay_string_index
+ == it->n_overlay_strings - 1))
+ {
+ EMACS_INT ignore;
+ int next_face_id;
+ struct text_pos pos = it->current.pos;
+ INC_TEXT_POS (pos, it->multibyte_p);
+
+ next_face_id = face_at_buffer_position
+ (it->w, CHARPOS (pos), it->region_beg_charpos,
+ it->region_end_charpos, &ignore,
+ (IT_CHARPOS (*it) + TEXT_PROP_DISTANCE_LIMIT), 0,
+ -1);
+ it->end_of_box_run_p
+ = (FACE_FROM_ID (it->f, next_face_id)->box
+ == FACE_NO_BOX);
+ }
+ }
+ }
+ else
+ {
+ int face_id = face_after_it_pos (it);
+ it->end_of_box_run_p
+ = (face_id != it->face_id
+ && FACE_FROM_ID (it->f, face_id)->box == FACE_NO_BOX);
+ }
}
/* Value is 0 if end of buffer or string reached. */
invisible lines that are so because of selective display. */
if (ITERATOR_AT_END_OF_LINE_P (it) && reseat_p)
reseat_at_next_visible_line_start (it, 0);
+ else if (it->cmp_it.id >= 0)
+ {
+ IT_CHARPOS (*it) += it->cmp_it.nchars;
+ IT_BYTEPOS (*it) += it->cmp_it.nbytes;
+ if (it->cmp_it.to < it->cmp_it.nglyphs)
+ it->cmp_it.from = it->cmp_it.to;
+ else
+ {
+ it->cmp_it.id = -1;
+ composition_compute_stop_pos (&it->cmp_it, IT_CHARPOS (*it),
+ IT_BYTEPOS (*it), it->stop_charpos,
+ Qnil);
+ }
+ }
else
{
xassert (it->len != 0);
}
break;
- case GET_FROM_COMPOSITION:
- xassert (it->cmp_id >= 0 && it->cmp_id < n_compositions);
- xassert (it->sp > 0);
- pop_it (it);
- if (it->method == GET_FROM_STRING)
- {
- IT_STRING_BYTEPOS (*it) += it->len;
- IT_STRING_CHARPOS (*it) += it->cmp_len;
- goto consider_string_end;
- }
- else if (it->method == GET_FROM_BUFFER)
- {
- IT_BYTEPOS (*it) += it->len;
- IT_CHARPOS (*it) += it->cmp_len;
- }
- break;
-
case GET_FROM_C_STRING:
/* Current display element of IT is from a C string. */
IT_BYTEPOS (*it) += it->len;
case GET_FROM_STRING:
/* Current display element is a character from a Lisp string. */
xassert (it->s == NULL && STRINGP (it->string));
- IT_STRING_BYTEPOS (*it) += it->len;
- IT_STRING_CHARPOS (*it) += 1;
+ if (it->cmp_it.id >= 0)
+ {
+ IT_STRING_CHARPOS (*it) += it->cmp_it.nchars;
+ IT_STRING_BYTEPOS (*it) += it->cmp_it.nbytes;
+ if (it->cmp_it.to < it->cmp_it.nglyphs)
+ it->cmp_it.from = it->cmp_it.to;
+ else
+ {
+ it->cmp_it.id = -1;
+ composition_compute_stop_pos (&it->cmp_it,
+ IT_STRING_CHARPOS (*it),
+ IT_STRING_BYTEPOS (*it),
+ it->stop_charpos, it->string);
+ }
+ }
+ else
+ {
+ IT_STRING_BYTEPOS (*it) += it->len;
+ IT_STRING_CHARPOS (*it) += 1;
+ }
consider_string_end:
it->what = IT_EOB;
return 0;
}
+ else if (CHAR_COMPOSED_P (it, IT_STRING_CHARPOS (*it),
+ IT_STRING_BYTEPOS (*it))
+ && next_element_from_composition (it))
+ {
+ return 1;
+ }
else if (STRING_MULTIBYTE (it->string))
{
int remaining = SBYTES (it->string) - IT_STRING_BYTEPOS (*it);
it->c = ' ', it->len = 1;
CHARPOS (position) = BYTEPOS (position) = -1;
}
+ else if (CHAR_COMPOSED_P (it, IT_STRING_CHARPOS (*it),
+ IT_STRING_BYTEPOS (*it))
+ && next_element_from_composition (it))
+ {
+ return 1;
+ }
else if (STRING_MULTIBYTE (it->string))
{
int maxlen = SBYTES (it->string) - IT_STRING_BYTEPOS (*it);
{
int success_p = 1;
- /* Check this assumption, otherwise, we would never enter the
- if-statement, below. */
- xassert (IT_CHARPOS (*it) >= BEGV
- && IT_CHARPOS (*it) <= it->stop_charpos);
+ xassert (IT_CHARPOS (*it) >= BEGV);
if (IT_CHARPOS (*it) >= it->stop_charpos)
{
&& IT_CHARPOS (*it) >= it->redisplay_end_trigger_charpos)
run_redisplay_end_trigger_hook (it);
+ if (CHAR_COMPOSED_P (it, IT_CHARPOS (*it), IT_BYTEPOS (*it))
+ && next_element_from_composition (it))
+ {
+ return 1;
+ }
+
/* Get the next character, maybe multibyte. */
p = BYTE_POS_ADDR (IT_BYTEPOS (*it));
if (it->multibyte_p && !ASCII_BYTE_P (*p))
- {
- int maxlen = ((IT_BYTEPOS (*it) >= GPT_BYTE ? ZV_BYTE : GPT_BYTE)
- - IT_BYTEPOS (*it));
- it->c = string_char_and_length (p, maxlen, &it->len);
- }
+ it->c = STRING_CHAR_AND_LENGTH (p, 0, it->len);
else
it->c = *p, it->len = 1;
}
-/* Deliver a composition display element. The iterator IT is already
- filled with composition information (done in
- handle_composition_prop). Value is always 1. */
+/* Deliver a composition display element. Unlike the other
+ next_element_from_XXX, this function is not registered in the array
+ get_next_element[]. It is called from next_element_from_buffer and
+ next_element_from_string when necessary. */
static int
next_element_from_composition (it)
struct it *it;
{
it->what = IT_COMPOSITION;
- it->position = (STRINGP (it->string)
- ? it->current.string_pos
- : it->current.pos);
+ it->len = it->cmp_it.nbytes;
if (STRINGP (it->string))
- it->object = it->string;
+ {
+ if (it->c < 0)
+ {
+ IT_STRING_CHARPOS (*it) += it->cmp_it.nchars;
+ IT_STRING_BYTEPOS (*it) += it->cmp_it.nbytes;
+ return 0;
+ }
+ it->position = it->current.string_pos;
+ it->object = it->string;
+ it->c = composition_update_it (&it->cmp_it, IT_STRING_CHARPOS (*it),
+ IT_STRING_BYTEPOS (*it), it->string);
+ }
else
- it->object = it->w->buffer;
+ {
+ if (it->c < 0)
+ {
+ IT_CHARPOS (*it) += it->cmp_it.nchars;
+ IT_BYTEPOS (*it) += it->cmp_it.nbytes;
+ return 0;
+ }
+ it->position = it->current.pos;
+ it->object = it->w->buffer;
+ it->c = composition_update_it (&it->cmp_it, IT_CHARPOS (*it),
+ IT_BYTEPOS (*it), Qnil);
+ }
return 1;
}
}
set_iterator_to_next (it, 1);
-#ifdef HAVE_WINDOW_SYSTEM
- if (IT_OVERFLOW_NEWLINE_INTO_FRINGE (it))
+ /* One graphical terminals, newlines may
+ "overflow" into the fringe if
+ overflow-newline-into-fringe is non-nil.
+ On text-only terminals, newlines may
+ overflow into the last glyph on the
+ display line.*/
+ if (!FRAME_WINDOW_P (it->f)
+ || IT_OVERFLOW_NEWLINE_INTO_FRINGE (it))
{
if (!get_next_display_element (it))
{
break;
}
}
-#endif /* HAVE_WINDOW_SYSTEM */
}
}
else
if (it->line_wrap == TRUNCATE
&& it->current_x >= it->last_visible_x)
{
-#ifdef HAVE_WINDOW_SYSTEM
- if (IT_OVERFLOW_NEWLINE_INTO_FRINGE (it))
+ if (!FRAME_WINDOW_P (it->f)
+ || IT_OVERFLOW_NEWLINE_INTO_FRINGE (it))
{
if (!get_next_display_element (it)
|| BUFFER_POS_REACHED_P ())
break;
}
}
-#endif /* HAVE_WINDOW_SYSTEM */
result = MOVE_LINE_TRUNCATED;
break;
}
int op;
{
enum move_it_result skip, skip2 = MOVE_X_REACHED;
- int line_height;
- int reached = 0;
+ int line_height, line_start_x = 0, reached = 0;
for (;;)
{
break;
}
else if (BUFFERP (it->object)
- && it->method == GET_FROM_BUFFER
+ && (it->method == GET_FROM_BUFFER
+ || it->method == GET_FROM_STRETCH)
&& IT_CHARPOS (*it) >= to_charpos)
skip = MOVE_POS_MATCH_OR_ZV;
else
associated with the tab are displayed on the current
line. Since it->current_x does not include these glyphs,
we use it->last_visible_x instead. */
- it->continuation_lines_width +=
- (it->c == '\t') ? it->last_visible_x : it->current_x;
+ if (it->c == '\t')
+ {
+ it->continuation_lines_width += it->last_visible_x;
+ /* When moving by vpos, ensure that the iterator really
+ advances to the next line (bug#847, bug#969). Fixme:
+ do we need to do this in other circumstances? */
+ if (it->current_x != it->last_visible_x
+ && (op & MOVE_TO_VPOS)
+ && !(op & (MOVE_TO_X | MOVE_TO_POS)))
+ {
+ line_start_x = it->current_x + it->pixel_width
+ - it->last_visible_x;
+ set_iterator_to_next (it, 0);
+ }
+ }
+ else
+ it->continuation_lines_width += it->current_x;
break;
default:
/* Reset/increment for the next run. */
recenter_overlay_lists (current_buffer, IT_CHARPOS (*it));
- it->current_x = it->hpos = 0;
+ it->current_x = line_start_x;
+ line_start_x = 0;
+ it->hpos = 0;
it->current_y += it->max_ascent + it->max_descent;
++it->vpos;
last_height = it->max_ascent + it->max_descent;
value of nlines is > 0 if continuation lines were involved. */
if (nlines > 0)
move_it_by_lines (it, nlines, 1);
-#if 0
- /* I think this assert is bogus if buffer contains
- invisible text or images. KFS. */
- xassert (IT_CHARPOS (*it) <= start_pos);
-#endif
}
else
{
}
while (target_y >= line_bottom_y (it) && IT_CHARPOS (*it) < ZV);
}
-
-#if 0
- /* I think this assert is bogus if buffer contains
- invisible text or images. KFS. */
- xassert (IT_CHARPOS (*it) >= BEGV);
-#endif
}
}
}
struct frame *sf = SELECTED_FRAME ();
message_enable_multibyte = multibyte;
- if (noninteractive)
+ if (FRAME_INITIAL_P (sf))
{
if (noninteractive_need_newline)
putc ('\n', stderr);
struct frame *sf = SELECTED_FRAME ();
message_enable_multibyte = multibyte;
- if (noninteractive)
+ if (FRAME_INITIAL_P (sf))
{
if (noninteractive_need_newline)
putc ('\n', stderr);
putc ('\n', stderr);
noninteractive_need_newline = 0;
fprintf (stderr, m, SDATA (string));
- if (cursor_in_echo_area == 0)
+ if (!cursor_in_echo_area)
fprintf (stderr, "\n");
fflush (stderr);
}
sprintf (name, " *Echo Area %d*", i);
echo_buffer[i] = Fget_buffer_create (build_string (name));
XBUFFER (echo_buffer[i])->truncate_lines = Qnil;
- /* to force word wrap in echo area -
+ /* to force word wrap in echo area -
it was decided to postpone this*/
/* XBUFFER (echo_buffer[i])->word_wrap = Qt; */
while (CONSP (functions))
{
- call1 (XCAR (functions), frame);
+ if (!EQ (XCAR (functions), Qt))
+ call1 (XCAR (functions), frame);
functions = XCDR (functions);
}
UNGCPRO;
int last_tool_bar_item;
+static Lisp_Object
+update_tool_bar_unwind (frame)
+ Lisp_Object frame;
+{
+ selected_frame = frame;
+ return Qnil;
+}
+
/* Update the tool-bar item list for frame F. This has to be done
before we start to fill in any display lines. Called from
prepare_menu_bars. If SAVE_MATCH_DATA is non-zero, we must save
struct frame *f;
int save_match_data;
{
-#if defined (USE_GTK) || defined (HAVE_NS) || USE_MAC_TOOLBAR
+#if defined (USE_GTK) || defined (HAVE_NS)
int do_update = FRAME_EXTERNAL_TOOL_BAR (f);
#else
int do_update = WINDOWP (f->tool_bar_window)
{
struct buffer *prev = current_buffer;
int count = SPECPDL_INDEX ();
- Lisp_Object new_tool_bar;
+ Lisp_Object frame, new_tool_bar;
int new_n_tool_bar;
struct gcpro gcpro1;
GCPRO1 (new_tool_bar);
+ /* We must temporarily set the selected frame to this frame
+ before calling tool_bar_items, because the calculation of
+ the tool-bar keymap uses the selected frame (see
+ `tool-bar-make-keymap' in tool-bar.el). */
+ record_unwind_protect (update_tool_bar_unwind, selected_frame);
+ XSETFRAME (frame, f);
+ selected_frame = frame;
+
/* Build desired tool-bar items from keymaps. */
new_tool_bar = tool_bar_items (Fcopy_sequence (f->tool_bar_items),
&new_n_tool_bar);
struct it it;
struct glyph_row *row;
-#if defined (USE_GTK) || defined (HAVE_NS) || USE_MAC_TOOLBAR
+#if defined (USE_GTK) || defined (HAVE_NS)
if (FRAME_EXTERNAL_TOOL_BAR (f))
update_frame_tool_bar (f);
return 0;
/* No redisplay if running in batch mode or frame is not yet fully
initialized, or redisplay is explicitly turned off by setting
Vinhibit_redisplay. */
- if (noninteractive
+ if (FRAME_INITIAL_P (SELECTED_FRAME ())
|| !NILP (Vinhibit_redisplay))
return;
if (face_change_count)
++windows_or_buffers_changed;
- if (FRAME_TERMCAP_P (sf)
+ if ((FRAME_TERMCAP_P (sf) || FRAME_MSDOS_P (sf))
&& FRAME_TTY (sf)->previous_frame != sf)
{
/* Since frames on a single ASCII terminal share the same
}
}
-
/* Notice any pending interrupt request to change frame size. */
do_pending_window_change (1);
if (FRAME_VISIBLE_P (f) && !FRAME_OBSCURED_P (f))
redisplay_windows (FRAME_ROOT_WINDOW (f));
+ /* The X error handler may have deleted that frame. */
+ if (!FRAME_LIVE_P (f))
+ continue;
+
/* Any scroll bars which redisplay_windows should have
nuked should now go away. */
if (FRAME_TERMINAL (f)->judge_scroll_bars_hook)
redisplay_windows (w->hchild);
else if (!NILP (w->vchild))
redisplay_windows (w->vchild);
- else
+ else if (!NILP (w->buffer))
{
displayed_buffer = XBUFFER (w->buffer);
/* Use list_of_error, not Qerror, so that
return 1;
}
return 0;
-
-#if 0
- /* This code used to try to scroll the window just enough to make
- the line visible. It returned 0 to say that the caller should
- allocate larger glyph matrices. */
-
- if (MATRIX_ROW_PARTIALLY_VISIBLE_AT_TOP_P (w, row))
- {
- int dy = row->height - row->visible_height;
- w->vscroll = 0;
- w->cursor.y += dy;
- shift_glyph_matrix (w, matrix, 0, matrix->nrows, dy);
- }
- else /* MATRIX_ROW_PARTIALLY_VISIBLE_AT_BOTTOM_P (w, row)) */
- {
- int dy = - (row->height - row->visible_height);
- w->vscroll = dy;
- w->cursor.y += dy;
- shift_glyph_matrix (w, matrix, 0, matrix->nrows, dy);
- }
-
- /* When we change the cursor y-position of the selected window,
- change this_line_y as well so that the display optimization for
- the cursor line of the selected window in redisplay_internal uses
- the correct y-position. */
- if (w == XWINDOW (selected_window))
- this_line_y = w->cursor.y;
-
- /* If vscrolling requires a larger glyph matrix, arrange for a fresh
- redisplay with larger matrices. */
- if (matrix->nrows < required_matrix_height (w))
- {
- fonts_changed_p = 1;
- return 0;
- }
-
- return 1;
-#endif /* 0 */
}
/* Compute scroll margin height in pixels. We scroll when point is
within this distance from the top or bottom of the window. */
if (scroll_margin > 0)
- {
- this_scroll_margin = min (scroll_margin, WINDOW_TOTAL_LINES (w) / 4);
- this_scroll_margin *= FRAME_LINE_HEIGHT (f);
- }
+ this_scroll_margin = min (scroll_margin, WINDOW_TOTAL_LINES (w) / 4)
+ * FRAME_LINE_HEIGHT (f);
else
this_scroll_margin = 0;
/* Force scroll_conservatively to have a reasonable value, to avoid
- overflow while computing how much to scroll. Note that it's
- fairly common for users to supply scroll-conservatively equal to
- `most-positive-fixnum', which can be larger than INT_MAX. */
+ overflow while computing how much to scroll. Note that the user
+ can supply scroll-conservatively equal to `most-positive-fixnum',
+ which can be larger than INT_MAX. */
if (scroll_conservatively > scroll_limit)
{
scroll_conservatively = scroll_limit;
too_near_end:
- /* Decide whether we have to scroll down. */
+ /* Decide whether to scroll down. */
if (PT > CHARPOS (startp))
{
int scroll_margin_y;
if (PT > CHARPOS (it.current.pos))
{
- /* Point is in the scroll margin at the bottom of the
- window, or below. Compute the distance from the scroll
- margin to PT, and give up if the distance is greater than
- scroll_max. */
- move_it_to (&it, PT, -1, it.last_visible_y - 1, -1,
- MOVE_TO_POS | MOVE_TO_Y);
+ int y0 = line_bottom_y (&it);
- /* To make point visible, we must move the window start down
- so that the cursor line is visible, which means we have
- to add in the height of the cursor line. */
- dy = line_bottom_y (&it) - scroll_margin_y;
+ /* Compute the distance from the scroll margin to PT
+ (including the height of the cursor line). Moving the
+ iterator unconditionally to PT can be slow if PT is far
+ away, so stop 10 lines past the window bottom (is there a
+ way to do the right thing quickly?). */
+ move_it_to (&it, PT, -1,
+ it.last_visible_y + 10 * FRAME_LINE_HEIGHT (f),
+ -1, MOVE_TO_POS | MOVE_TO_Y);
+ dy = line_bottom_y (&it) - y0;
if (dy > scroll_max)
return SCROLLING_FAILED;
if (scroll_down_p)
{
- /* Move the window start down. If scrolling conservatively,
- move it just enough down to make point visible. If
- scroll_step is set, move it down by scroll_step. */
- start_display (&it, w, startp);
-
+ /* Point is in or below the bottom scroll margin, so move the
+ window start down. If scrolling conservatively, move it just
+ enough down to make point visible. If scroll_step is set,
+ move it down by scroll_step. */
if (scroll_conservatively)
- /* Set AMOUNT_TO_SCROLL to at least one line,
- and at most scroll_conservatively lines. */
amount_to_scroll
= min (max (dy, FRAME_LINE_HEIGHT (f)),
FRAME_LINE_HEIGHT (f) * scroll_conservatively);
if (amount_to_scroll <= 0)
return SCROLLING_FAILED;
- /* If moving by amount_to_scroll leaves STARTP unchanged,
- move it down one screen line. */
-
+ start_display (&it, w, startp);
move_it_vertically (&it, amount_to_scroll);
+
+ /* If STARTP is unchanged, move it down another screen line. */
if (CHARPOS (it.current.pos) == CHARPOS (startp))
move_it_by_lines (&it, 1, 1);
startp = it.current.pos;
used_current_matrix_p = 1;
goto done;
-#if 0 /* try_cursor_movement never returns this value. */
- case CURSOR_MOVEMENT_NEED_LARGER_MATRICES:
- goto need_larger_matrices;
-#endif
-
case CURSOR_MOVEMENT_MUST_SCROLL:
goto try_to_scroll;
#ifdef HAVE_WINDOW_SYSTEM
if (FRAME_WINDOW_P (f))
{
-#if defined (USE_GTK) || defined (HAVE_NS) || USE_MAC_TOOLBAR
+#if defined (USE_GTK) || defined (HAVE_NS)
redisplay_tool_bar_p = FRAME_EXTERNAL_TOOL_BAR (f);
#else
redisplay_tool_bar_p = WINDOWP (f->tool_bar_window)
if (display_line (&it))
last_text_row = it.glyph_row - 1;
- /* Give up If point isn't in a row displayed or reused. */
- if (w->cursor.vpos < 0)
- {
- clear_glyph_matrix (w->desired_matrix);
- return 0;
- }
-
/* If point is in a reused row, adjust y and vpos of the cursor
position. */
if (pt_row)
w->cursor.y -= first_reusable_row->y - start_row->y;
}
+ /* Give up if point isn't in a row displayed or reused. (This
+ also handles the case where w->cursor.vpos < nrows_scrolled
+ after the calls to display_line, which can happen with scroll
+ margins. See bug#1295.) */
+ if (w->cursor.vpos < 0)
+ {
+ clear_glyph_matrix (w->desired_matrix);
+ return 0;
+ }
+
/* Scroll the display. */
run.current_y = first_reusable_row->y;
run.desired_y = WINDOW_HEADER_LINE_HEIGHT (w);
if (row < bottom_row)
{
struct glyph *glyph = row->glyphs[TEXT_AREA] + w->cursor.hpos;
- while (glyph->charpos < PT)
+ struct glyph *end = glyph + row->used[TEXT_AREA];
+
+ for (; glyph < end
+ && (!BUFFERP (glyph->object)
+ || glyph->charpos < PT);
+ glyph++)
{
w->cursor.hpos++;
w->cursor.x += glyph->pixel_width;
- glyph++;
}
}
}
else
abort ();
-#if 0 /* This leads to problems, for instance when the cursor is
- at ZV, and the cursor line displays no text. */
- /* Disable rows below what's displayed in the window. This makes
- debugging easier. */
- enable_glyph_matrix_rows (current_matrix,
- XFASTINT (w->window_end_vpos) + 1,
- bottom_vpos, 0);
-#endif
-
IF_DEBUG (debug_end_pos = XFASTINT (w->window_end_pos);
debug_end_vpos = XFASTINT (w->window_end_vpos));
else if (glyph->type == COMPOSITE_GLYPH)
{
fprintf (stderr,
- " %5d %4c %6d %c %3d 0x%05x %c %4d %1.1d%1.1d\n",
+ " %5d %4c %6d %c %3d 0x%05x",
glyph - row->glyphs[TEXT_AREA],
'+',
glyph->charpos,
? 'S'
: '-')),
glyph->pixel_width,
- glyph->u.cmp_id,
- '.',
+ glyph->u.cmp.id);
+ if (glyph->u.cmp.automatic)
+ fprintf (stderr,
+ "[%d-%d]",
+ glyph->u.cmp.from, glyph->u.cmp.to);
+ fprintf (stderr, " . %4d %1.1d%1.1d\n",
glyph->face_id,
glyph->left_box_line_p,
glyph->right_box_line_p);
prefix = Vline_prefix;
}
if (! NILP (prefix))
- push_display_prop (it, prefix);
+ {
+ push_display_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
+ iterator stack overflows. So, don't wrap the prefix. */
+ it->line_wrap = TRUNCATE;
+ }
}
\f
display the cursor there under X. Set the charpos of the
first glyph of blank lines not corresponding to any text
to -1. */
-#ifdef HAVE_WINDOW_SYSTEM
if (IT_OVERFLOW_NEWLINE_INTO_FRINGE (it))
row->exact_window_width_line_p = 1;
- else
-#endif /* HAVE_WINDOW_SYSTEM */
- if ((append_space_for_newline (it, 1) && row->used[TEXT_AREA] == 1)
- || row->used[TEXT_AREA] == 0)
+ else if ((append_space_for_newline (it, 1) && row->used[TEXT_AREA] == 1)
+ || row->used[TEXT_AREA] == 0)
{
row->glyphs[TEXT_AREA]->charpos = -1;
row->displays_text_p = 0;
goto back_to_wrap;
set_iterator_to_next (it, 1);
-#ifdef HAVE_WINDOW_SYSTEM
if (IT_OVERFLOW_NEWLINE_INTO_FRINGE (it))
{
if (!get_next_display_element (it))
row->exact_window_width_line_p = 1;
}
}
-#endif /* HAVE_WINDOW_SYSTEM */
}
}
else if (CHAR_GLYPH_PADDING_P (*glyph)
row->ends_in_newline_from_string_p = STRINGP (it->object);
-#ifdef HAVE_WINDOW_SYSTEM
/* Add a space at the end of the line that is used to
display the cursor there. */
if (!IT_OVERFLOW_NEWLINE_INTO_FRINGE (it))
append_space_for_newline (it, 0);
-#endif /* HAVE_WINDOW_SYSTEM */
/* Extend the face to the end of the line. */
extend_face_to_end_of_line (it);
produce_special_glyphs (it, IT_TRUNCATION);
}
}
-#ifdef HAVE_WINDOW_SYSTEM
- else
+ else if (IT_OVERFLOW_NEWLINE_INTO_FRINGE (it))
{
/* Don't truncate if we can overflow newline into fringe. */
- if (IT_OVERFLOW_NEWLINE_INTO_FRINGE (it))
+ if (!get_next_display_element (it))
{
- if (!get_next_display_element (it))
- {
- it->continuation_lines_width = 0;
- row->ends_at_zv_p = 1;
- row->exact_window_width_line_p = 1;
- break;
- }
- if (ITERATOR_AT_END_OF_LINE_P (it))
- {
- row->exact_window_width_line_p = 1;
- goto at_end_of_line;
- }
+ it->continuation_lines_width = 0;
+ row->ends_at_zv_p = 1;
+ row->exact_window_width_line_p = 1;
+ break;
+ }
+ if (ITERATOR_AT_END_OF_LINE_P (it))
+ {
+ row->exact_window_width_line_p = 1;
+ goto at_end_of_line;
}
}
-#endif /* HAVE_WINDOW_SYSTEM */
row->truncated_on_right_p = 1;
it->continuation_lines_width = 0;
/* Fill glyph string S with composition components specified by S->cmp.
BASE_FACE is the base face of the composition.
- S->gidx is the index of the first component for S.
+ S->cmp_from is the index of the first component for S.
OVERLAPS non-zero means S should draw the foreground only, and use
its physical height for clipping. See also draw_glyphs.
int overlaps;
{
int i;
+ /* For all glyphs of this composition, starting at the offset
+ S->cmp_from, until we reach the end of the definition or encounter a
+ glyph that requires the different face, add it to S. */
+ struct face *face;
xassert (s);
s->for_overlaps = overlaps;
-
- if (s->cmp->method == COMPOSITION_WITH_GLYPH_STRING)
- {
- Lisp_Object gstring
- = AREF (XHASH_TABLE (composition_hash_table)->key_and_value,
- s->cmp->hash_index * 2);
-
- s->face = base_face;
- s->font = base_face->font;
- for (i = 0, s->nchars = 0; i < s->cmp->glyph_len; i++, s->nchars++)
- {
- Lisp_Object g = LGSTRING_GLYPH (gstring, i);
- unsigned code;
- XChar2b * store_pos;
- if (NILP (g))
- break;
- code = LGLYPH_CODE (g);
- store_pos = s->char2b + i;
- STORE_XCHAR2B (store_pos, code >> 8, code & 0xFF);
- }
- s->width = s->cmp->pixel_width;
- }
- else
+ s->face = NULL;
+ s->font = NULL;
+ for (i = s->cmp_from; i < s->cmp->glyph_len; i++)
{
- /* For all glyphs of this composition, starting at the offset
- S->gidx, until we reach the end of the definition or encounter a
- glyph that requires the different face, add it to S. */
- struct face *face;
+ int c = COMPOSITION_GLYPH (s->cmp, i);
- s->face = NULL;
- s->font = NULL;
- for (i = s->gidx; i < s->cmp->glyph_len; i++)
+ if (c != '\t')
{
- int c = COMPOSITION_GLYPH (s->cmp, i);
+ int face_id = FACE_FOR_CHAR (s->f, base_face->ascii_face, c,
+ -1, Qnil);
- if (c != '\t')
+ face = get_char_face_and_encoding (s->f, c, face_id,
+ s->char2b + i, 1, 1);
+ if (face)
{
- int face_id = FACE_FOR_CHAR (s->f, base_face->ascii_face, c,
- -1, Qnil);
-
- face = get_char_face_and_encoding (s->f, c, face_id,
- s->char2b + i, 1, 1);
- if (face)
+ if (! s->face)
{
- if (! s->face)
- {
- s->face = face;
- s->font = s->face->font;
- }
- else if (s->face != face)
- break;
+ s->face = face;
+ s->font = s->face->font;
}
+ else if (s->face != face)
+ break;
}
- ++s->nchars;
}
-
- /* 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;
+ ++s->nchars;
}
+ s->cmp_to = i;
+
+ /* 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;
/* If the specified font could not be loaded, use the frame's
default font, but record the fact that we couldn't load it in
/* This glyph string must always be drawn with 16-bit functions. */
s->two_byte_p = 1;
- return s->gidx + s->nchars;
+ return s->cmp_to;
+}
+
+static int
+fill_gstring_glyph_string (s, face_id, start, end, overlaps)
+ struct glyph_string *s;
+ int face_id;
+ int start, end, overlaps;
+{
+ struct glyph *glyph, *last;
+ Lisp_Object lgstring;
+ int i;
+
+ s->for_overlaps = overlaps;
+ glyph = s->row->glyphs[s->area] + start;
+ last = s->row->glyphs[s->area] + end;
+ s->cmp_id = glyph->u.cmp.id;
+ s->cmp_from = glyph->u.cmp.from;
+ s->cmp_to = glyph->u.cmp.to + 1;
+ s->face = FACE_FROM_ID (s->f, face_id);
+ lgstring = composition_gstring_from_id (s->cmp_id);
+ s->font = XFONT_OBJECT (LGSTRING_FONT (lgstring));
+ glyph++;
+ while (glyph < last
+ && glyph->u.cmp.automatic
+ && glyph->u.cmp.id == s->cmp_id
+ && s->cmp_to == glyph->u.cmp.from)
+ s->cmp_to = (glyph++)->u.cmp.to + 1;
+
+ for (i = s->cmp_from; i < s->cmp_to; i++)
+ {
+ Lisp_Object lglyph = LGSTRING_GLYPH (lgstring, i);
+ unsigned code = LGLYPH_CODE (lglyph);
+
+ STORE_XCHAR2B ((s->char2b + i), code >> 8, code & 0xFF);
+ }
+ s->width = composition_gstring_width (lgstring, s->cmp_from, s->cmp_to, NULL);
+ return glyph - s->row->glyphs[s->area];
}
xassert (s->nchars == 0);
xassert (start >= 0 && end > start);
- s->for_overlaps = overlaps,
+ s->for_overlaps = overlaps;
glyph = s->row->glyphs[s->area] + start;
last = s->row->glyphs[s->area] + end;
voffset = glyph->voffset;
{
static struct font_metrics metrics;
unsigned code = (XCHAR2B_BYTE1 (char2b) << 8) | XCHAR2B_BYTE2 (char2b);
- struct font *fontp;
if (! font || code == FONT_INVALID_CODE)
return NULL;
}
else if (glyph->type == COMPOSITE_GLYPH)
{
- struct composition *cmp = composition_table[glyph->u.cmp_id];
+ if (! glyph->u.cmp.automatic)
+ {
+ struct composition *cmp = composition_table[glyph->u.cmp.id];
+
+ if (cmp->rbearing > cmp->pixel_width)
+ *right = cmp->rbearing - cmp->pixel_width;
+ if (cmp->lbearing < 0)
+ *left = - cmp->lbearing;
+ }
+ else
+ {
+ Lisp_Object gstring = composition_gstring_from_id (glyph->u.cmp.id);
+ struct font_metrics metrics;
- *right = cmp->rbearing - cmp->pixel_width;
- *left = - cmp->lbearing;
+ composition_gstring_width (gstring, glyph->u.cmp.from,
+ glyph->u.cmp.to + 1, &metrics);
+ if (metrics.rbearing > metrics.width)
+ *right = metrics.rbearing - metrics.width;
+ if (metrics.lbearing < 0)
+ *left = - metrics.lbearing;
+ }
}
}
INIT_GLYPH_STRING (s, char2b, w, row, area, START, HL); \
append_glyph_string (&HEAD, &TAIL, s); \
s->x = (X); \
- START = fill_glyph_string (s, face_id, START, END, overlaps); \
+ START = fill_glyph_string (s, face_id, START, END, overlaps); \
} \
while (0)
do { \
int face_id = (row)->glyphs[area][START].face_id; \
struct face *base_face = FACE_FROM_ID (f, face_id); \
- int cmp_id = (row)->glyphs[area][START].u.cmp_id; \
+ int cmp_id = (row)->glyphs[area][START].u.cmp.id; \
struct composition *cmp = composition_table[cmp_id]; \
XChar2b *char2b; \
struct glyph_string *first_s; \
INIT_GLYPH_STRING (s, char2b, w, row, area, START, HL); \
append_glyph_string (&(HEAD), &(TAIL), s); \
s->cmp = cmp; \
- s->gidx = n; \
+ s->cmp_from = n; \
s->x = (X); \
if (n == 0) \
first_s = s; \
} while (0)
+/* Add a glyph string for a glyph-string sequence to the list of strings
+ between HEAD and TAIL. */
+
+#define BUILD_GSTRING_GLYPH_STRING(START, END, HEAD, TAIL, HL, X, LAST_X) \
+ do { \
+ int face_id; \
+ XChar2b *char2b; \
+ Lisp_Object gstring; \
+ \
+ face_id = (row)->glyphs[area][START].face_id; \
+ gstring = (composition_gstring_from_id \
+ ((row)->glyphs[area][START].u.cmp.id)); \
+ s = (struct glyph_string *) alloca (sizeof *s); \
+ char2b = (XChar2b *) alloca ((sizeof *char2b) \
+ * LGSTRING_GLYPH_LEN (gstring)); \
+ INIT_GLYPH_STRING (s, char2b, w, row, area, START, HL); \
+ append_glyph_string (&(HEAD), &(TAIL), s); \
+ s->x = (X); \
+ START = fill_gstring_glyph_string (s, face_id, START, END, overlaps); \
+ } while (0)
+
+
/* Build a list of glyph strings between HEAD and TAIL for the glyphs
of AREA of glyph row ROW on window W between indices START and END.
HL overrides the face for drawing glyph strings, e.g. it is
to allocate glyph strings (because draw_glyphs can be called
asynchronously). */
-#define BUILD_GLYPH_STRINGS(START, END, HEAD, TAIL, HL, X, LAST_X) \
- do \
- { \
- HEAD = TAIL = NULL; \
- while (START < END) \
- { \
- struct glyph *first_glyph = (row)->glyphs[area] + START; \
- switch (first_glyph->type) \
- { \
- case CHAR_GLYPH: \
- BUILD_CHAR_GLYPH_STRINGS (START, END, HEAD, TAIL, \
- HL, X, LAST_X); \
- break; \
- \
- case COMPOSITE_GLYPH: \
- BUILD_COMPOSITE_GLYPH_STRING (START, END, HEAD, TAIL, \
- HL, X, LAST_X); \
- break; \
- \
- case STRETCH_GLYPH: \
- BUILD_STRETCH_GLYPH_STRING (START, END, HEAD, TAIL, \
- HL, X, LAST_X); \
- break; \
- \
- case IMAGE_GLYPH: \
- BUILD_IMAGE_GLYPH_STRING (START, END, HEAD, TAIL, \
- HL, X, LAST_X); \
- break; \
- \
- default: \
- abort (); \
- } \
- \
- if (s) \
- { \
- set_glyph_string_background_width (s, START, LAST_X); \
- (X) += s->width; \
- } \
- } \
- } \
- while (0)
+#define BUILD_GLYPH_STRINGS(START, END, HEAD, TAIL, HL, X, LAST_X) \
+ do \
+ { \
+ HEAD = TAIL = NULL; \
+ while (START < END) \
+ { \
+ struct glyph *first_glyph = (row)->glyphs[area] + START; \
+ switch (first_glyph->type) \
+ { \
+ case CHAR_GLYPH: \
+ BUILD_CHAR_GLYPH_STRINGS (START, END, HEAD, TAIL, \
+ HL, X, LAST_X); \
+ break; \
+ \
+ case COMPOSITE_GLYPH: \
+ if (first_glyph->u.cmp.automatic) \
+ BUILD_GSTRING_GLYPH_STRING (START, END, HEAD, TAIL, \
+ HL, X, LAST_X); \
+ else \
+ BUILD_COMPOSITE_GLYPH_STRING (START, END, HEAD, TAIL, \
+ HL, X, LAST_X); \
+ break; \
+ \
+ case STRETCH_GLYPH: \
+ BUILD_STRETCH_GLYPH_STRING (START, END, HEAD, TAIL, \
+ HL, X, LAST_X); \
+ break; \
+ \
+ case IMAGE_GLYPH: \
+ BUILD_IMAGE_GLYPH_STRING (START, END, HEAD, TAIL, \
+ HL, X, LAST_X); \
+ break; \
+ \
+ default: \
+ abort (); \
+ } \
+ \
+ if (s) \
+ { \
+ set_glyph_string_background_width (s, START, LAST_X); \
+ (X) += s->width; \
+ } \
+ } \
+ } while (0)
/* Draw glyphs between START and END in AREA of ROW on window W,
for (s = head; s; s = s->next)
FRAME_RIF (f)->draw_glyph_string (s);
+#ifndef HAVE_NS
+ /* When focus a sole frame and move horizontally, this sets on_p to 0
+ causing a failure to erase prev cursor position. */
if (area == TEXT_AREA
&& !row->full_width_p
/* When drawing overlapping rows, only the glyph strings'
notice_overwritten_cursor (w, TEXT_AREA, x0, x1,
row->y, MATRIX_ROW_BOTTOM_Y (row));
}
+#endif
/* Value is the x-position up to which drawn, relative to AREA of W.
This doesn't include parts drawn because of overhangs. */
IT_EXPAND_MATRIX_WIDTH (it, area);
}
-/* Store one glyph for the composition IT->cmp_id in IT->glyph_row.
- Called from x_produce_glyphs when IT->glyph_row is non-null. */
+/* Store one glyph for the composition IT->cmp_it.id in
+ IT->glyph_row. Called from x_produce_glyphs when IT->glyph_row is
+ non-null. */
static INLINE void
append_composite_glyph (it)
glyph->descent = it->descent;
glyph->voffset = it->voffset;
glyph->type = COMPOSITE_GLYPH;
+ if (it->cmp_it.ch < 0)
+ {
+ glyph->u.cmp.automatic = 0;
+ glyph->u.cmp.id = it->cmp_it.id;
+ }
+ else
+ {
+ glyph->u.cmp.automatic = 1;
+ glyph->u.cmp.id = it->cmp_it.id;
+ glyph->u.cmp.from = it->cmp_it.from;
+ glyph->u.cmp.to = it->cmp_it.to - 1;
+ }
glyph->avoid_cursor_p = it->avoid_cursor_p;
glyph->multibyte_p = it->multibyte_p;
glyph->left_box_line_p = it->start_of_box_run_p;
glyph->padding_p = 0;
glyph->glyph_not_available_p = 0;
glyph->face_id = it->face_id;
- glyph->u.cmp_id = it->cmp_id;
glyph->slice = null_glyph_slice;
glyph->font_type = FONT_TYPE_UNKNOWN;
++it->glyph_row->used[area];
if (it->descent < 0)
it->descent = 0;
-#if 0 /* this breaks image tiling */
- /* If this glyph is alone on the last line, adjust it.ascent to minimum row ascent. */
- int face_ascent = face->font ? FONT_BASE (face->font) : FRAME_BASELINE_OFFSET (it->f);
- if (face_ascent > it->ascent)
- it->ascent = it->phys_ascent = face_ascent;
-#endif
-
it->nglyphs = 1;
if (face->box != FACE_NO_BOX)
{
if (SINGLE_BYTE_CHAR_P (it->c)
&& unibyte_display_via_language_environment)
- it->char_to_display = unibyte_char_to_multibyte (it->c);
- if (! SINGLE_BYTE_CHAR_P (it->char_to_display))
{
+ struct charset *unibyte = CHARSET_FROM_ID (charset_unibyte);
+
+ /* get_next_display_element assures that this decoding
+ never fails. */
+ it->char_to_display = DECODE_CHAR (unibyte, it->c);
it->multibyte_p = 1;
it->face_id = FACE_FOR_CHAR (it->f, face, it->char_to_display,
-1, Qnil);
}
it->multibyte_p = saved_multibyte_p;
}
- else if (it->what == IT_COMPOSITION)
+ else if (it->what == IT_COMPOSITION && it->cmp_it.ch < 0)
{
- /* Note: A composition is represented as one glyph in the
+ /* A static compositoin.
+
+ Note: A composition is represented as one glyph in the
glyph matrix. There are no padding glyphs.
Important is that pixel_width, ascent, and descent are the
the overall glyphs composed). */
struct face *face = FACE_FROM_ID (it->f, it->face_id);
int boff; /* baseline offset */
- struct composition *cmp = composition_table[it->cmp_id];
+ struct composition *cmp = composition_table[it->cmp_it.id];
int glyph_len = cmp->glyph_len;
struct font *font = face->font;
it->nglyphs = 1;
- if (cmp->method == COMPOSITION_WITH_GLYPH_STRING)
- {
- PREPARE_FACE_FOR_DISPLAY (it->f, face);
- font_prepare_composition (cmp, it->f);
- }
- else
/* If we have not yet calculated pixel size data of glyphs of
the composition for the current face font, calculate them
now. Theoretically, we have to check all fonts for the
int lbearing, rbearing;
int i, width, ascent, descent;
int left_padded = 0, right_padded = 0;
- int face_id;
int c;
XChar2b char2b;
struct font_metrics *pcm;
if (it->descent < 0)
it->descent = 0;
+ if (it->glyph_row)
+ append_composite_glyph (it);
+ }
+ else if (it->what == IT_COMPOSITION)
+ {
+ /* A dynamic (automatic) composition. */
+ struct face *face = FACE_FROM_ID (it->f, it->face_id);
+ Lisp_Object gstring;
+ struct font_metrics metrics;
+
+ gstring = composition_gstring_from_id (it->cmp_it.id);
+ it->pixel_width
+ = composition_gstring_width (gstring, it->cmp_it.from, it->cmp_it.to,
+ &metrics);
+ if (it->glyph_row
+ && (metrics.lbearing < 0 || metrics.rbearing > metrics.width))
+ it->glyph_row->contains_overlapping_glyphs_p = 1;
+ it->ascent = it->phys_ascent = metrics.ascent;
+ it->descent = it->phys_descent = metrics.descent;
+ if (face->box != FACE_NO_BOX)
+ {
+ int thick = face->box_line_width;
+
+ if (thick > 0)
+ {
+ it->ascent += thick;
+ it->descent += thick;
+ }
+ else
+ thick = - thick;
+
+ if (it->start_of_box_run_p)
+ it->pixel_width += thick;
+ if (it->end_of_box_run_p)
+ it->pixel_width += thick;
+ }
+ /* If face has an overline, add the height of the overline
+ (1 pixel) and a 1 pixel margin to the character height. */
+ if (face->overline_p)
+ it->ascent += overline_margin;
+ take_vertical_position_into_account (it);
+ if (it->ascent < 0)
+ it->ascent = 0;
+ if (it->descent < 0)
+ it->descent = 0;
+
if (it->glyph_row)
append_composite_glyph (it);
}
\f
-/* Find the glyph matrix position of buffer position CHARPOS in window
- *W. HPOS, *VPOS, *X, and *Y are set to the positions found. W's
- current glyphs must be up to date. If CHARPOS is above window
- start return (0, 0, 0, 0). If CHARPOS is after end of W, return end
- of last line in W. In the row containing CHARPOS, stop before glyphs
- having STOP as object. */
-
-#if 1 /* This is a version of fast_find_position that's more correct
- in the presence of hscrolling, for example. I didn't install
- it right away because the problem fixed is minor, it failed
- in 20.x as well, and I think it's too risky to install
- so near the release of 21.1. 2001-09-25 gerd. */
+/* This function sets the mouse_face_* elements of DPYINFO, assuming
+ the mouse cursor is on a glyph with buffer charpos MOUSE_CHARPOS in
+ window WINDOW. START_CHARPOS and END_CHARPOS are buffer positions
+ 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.
+ DISPLAY_STRING, if non-nil, is a display string that may cover some
+ or all of the highlighted text. */
-static
-int
-fast_find_position (w, charpos, hpos, vpos, x, y, stop)
- struct window *w;
- EMACS_INT charpos;
- int *hpos, *vpos, *x, *y;
- Lisp_Object stop;
+static void
+mouse_face_from_buffer_pos (Lisp_Object window,
+ Display_Info *dpyinfo,
+ EMACS_INT mouse_charpos,
+ EMACS_INT start_charpos,
+ EMACS_INT end_charpos,
+ Lisp_Object before_string,
+ Lisp_Object after_string,
+ Lisp_Object display_string)
{
- struct glyph_row *row, *first;
+ struct window *w = XWINDOW (window);
+ struct glyph_row *first = MATRIX_FIRST_TEXT_ROW (w->current_matrix);
+ struct glyph_row *row;
struct glyph *glyph, *end;
- int past_end = 0;
+ EMACS_INT ignore;
+ int x;
- first = MATRIX_FIRST_TEXT_ROW (w->current_matrix);
- if (charpos < MATRIX_ROW_START_CHARPOS (first))
+ xassert (NILP (display_string) || STRINGP (display_string));
+ xassert (NILP (before_string) || STRINGP (before_string));
+ xassert (NILP (after_string) || STRINGP (after_string));
+
+ /* Find the first highlighted glyph. */
+ if (start_charpos < MATRIX_ROW_START_CHARPOS (first))
{
- *x = first->x;
- *y = first->y;
- *hpos = 0;
- *vpos = MATRIX_ROW_VPOS (first, w->current_matrix);
- return 1;
+ dpyinfo->mouse_face_beg_col = 0;
+ dpyinfo->mouse_face_beg_row = MATRIX_ROW_VPOS (first, w->current_matrix);
+ dpyinfo->mouse_face_beg_x = first->x;
+ dpyinfo->mouse_face_beg_y = first->y;
}
+ else
+ {
+ row = row_containing_pos (w, start_charpos, first, NULL, 0);
+ if (row == NULL)
+ row = MATRIX_ROW (w->current_matrix, XFASTINT (w->window_end_vpos));
- row = row_containing_pos (w, charpos, first, NULL, 0);
+ /* If the before-string or display-string contains newlines,
+ row_containing_pos skips to its last row. Move back. */
+ if (!NILP (before_string) || !NILP (display_string))
+ {
+ struct glyph_row *prev;
+ while ((prev = row - 1, prev >= first)
+ && MATRIX_ROW_END_CHARPOS (prev) == start_charpos
+ && prev->used[TEXT_AREA] > 0)
+ {
+ struct glyph *beg = prev->glyphs[TEXT_AREA];
+ glyph = beg + prev->used[TEXT_AREA];
+ while (--glyph >= beg && INTEGERP (glyph->object));
+ if (glyph < beg
+ || !(EQ (glyph->object, before_string)
+ || EQ (glyph->object, display_string)))
+ break;
+ row = prev;
+ }
+ }
+
+ glyph = row->glyphs[TEXT_AREA];
+ end = glyph + row->used[TEXT_AREA];
+ x = row->x;
+ dpyinfo->mouse_face_beg_y = row->y;
+ dpyinfo->mouse_face_beg_row = MATRIX_ROW_VPOS (row, w->current_matrix);
+
+ /* Skip truncation glyphs at the start of the glyph row. */
+ if (row->displays_text_p)
+ for (; glyph < end
+ && INTEGERP (glyph->object)
+ && glyph->charpos < 0;
+ ++glyph)
+ x += glyph->pixel_width;
+
+ /* Scan the glyph row, stopping before BEFORE_STRING or
+ DISPLAY_STRING or START_CHARPOS. */
+ for (; glyph < end
+ && !INTEGERP (glyph->object)
+ && !EQ (glyph->object, before_string)
+ && !EQ (glyph->object, display_string)
+ && !(BUFFERP (glyph->object)
+ && glyph->charpos >= start_charpos);
+ ++glyph)
+ x += glyph->pixel_width;
+
+ dpyinfo->mouse_face_beg_x = x;
+ dpyinfo->mouse_face_beg_col = glyph - row->glyphs[TEXT_AREA];
+ }
+
+ /* Find the last highlighted glyph. */
+ row = row_containing_pos (w, end_charpos, first, NULL, 0);
if (row == NULL)
{
row = MATRIX_ROW (w->current_matrix, XFASTINT (w->window_end_vpos));
- past_end = 1;
+ dpyinfo->mouse_face_past_end = 1;
}
-
- /* If whole rows or last part of a row came from a display overlay,
- row_containing_pos will skip over such rows because their end pos
- equals the start pos of the overlay or interval.
-
- Move back if we have a STOP object and previous row's
- end glyph came from STOP. */
- if (!NILP (stop))
+ else if (!NILP (after_string))
{
- struct glyph_row *prev;
- while ((prev = row - 1, prev >= first)
- && MATRIX_ROW_END_CHARPOS (prev) == charpos
- && prev->used[TEXT_AREA] > 0)
- {
- struct glyph *beg = prev->glyphs[TEXT_AREA];
- glyph = beg + prev->used[TEXT_AREA];
- while (--glyph >= beg
- && INTEGERP (glyph->object));
- if (glyph < beg
- || !EQ (stop, glyph->object))
- break;
- row = prev;
- }
- }
+ /* If the after-string has newlines, advance to its last row. */
+ struct glyph_row *next;
+ struct glyph_row *last
+ = MATRIX_ROW (w->current_matrix, XFASTINT (w->window_end_vpos));
- *x = row->x;
- *y = row->y;
- *vpos = MATRIX_ROW_VPOS (row, w->current_matrix);
+ for (next = row + 1;
+ next <= last
+ && next->used[TEXT_AREA] > 0
+ && EQ (next->glyphs[TEXT_AREA]->object, after_string);
+ ++next)
+ row = next;
+ }
glyph = row->glyphs[TEXT_AREA];
end = glyph + row->used[TEXT_AREA];
+ x = row->x;
+ dpyinfo->mouse_face_end_y = row->y;
+ dpyinfo->mouse_face_end_row = MATRIX_ROW_VPOS (row, w->current_matrix);
- /* Skip over glyphs not having an object at the start of the row.
- These are special glyphs like truncation marks on terminal
- frames. */
+ /* Skip truncation glyphs at the start of the row. */
if (row->displays_text_p)
- while (glyph < end
+ for (; glyph < end
&& INTEGERP (glyph->object)
- && !EQ (stop, glyph->object)
- && glyph->charpos < 0)
- {
- *x += glyph->pixel_width;
- ++glyph;
- }
+ && glyph->charpos < 0;
+ ++glyph)
+ x += glyph->pixel_width;
- while (glyph < end
+ /* Scan the glyph row, stopping at END_CHARPOS or when we encounter
+ AFTER_STRING. */
+ for (; glyph < end
&& !INTEGERP (glyph->object)
- && !EQ (stop, glyph->object)
- && (!BUFFERP (glyph->object)
- || glyph->charpos < charpos))
- {
- *x += glyph->pixel_width;
- ++glyph;
- }
-
- *hpos = glyph - row->glyphs[TEXT_AREA];
- return !past_end;
-}
-
-#else /* not 1 */
-
-static int
-fast_find_position (w, pos, hpos, vpos, x, y, stop)
- struct window *w;
- EMACS_INT pos;
- int *hpos, *vpos, *x, *y;
- Lisp_Object stop;
-{
- int i;
- int lastcol;
- int maybe_next_line_p = 0;
- int line_start_position;
- int yb = window_text_bottom_y (w);
- struct glyph_row *row, *best_row;
- int row_vpos, best_row_vpos;
- int current_x;
-
- row = best_row = MATRIX_FIRST_TEXT_ROW (w->current_matrix);
- row_vpos = best_row_vpos = MATRIX_ROW_VPOS (row, w->current_matrix);
+ && !EQ (glyph->object, after_string)
+ && !(BUFFERP (glyph->object) && glyph->charpos >= end_charpos);
+ ++glyph)
+ x += glyph->pixel_width;
- while (row->y < yb)
+ /* If we found AFTER_STRING, consume it and stop. */
+ if (EQ (glyph->object, after_string))
{
- if (row->used[TEXT_AREA])
- line_start_position = row->glyphs[TEXT_AREA]->charpos;
- else
- line_start_position = 0;
-
- if (line_start_position > pos)
- break;
- /* If the position sought is the end of the buffer,
- don't include the blank lines at the bottom of the window. */
- else if (line_start_position == pos
- && pos == BUF_ZV (XBUFFER (w->buffer)))
- {
- maybe_next_line_p = 1;
- break;
- }
- else if (line_start_position > 0)
- {
- best_row = row;
- best_row_vpos = row_vpos;
- }
-
- if (row->y + row->height >= yb)
- break;
-
- ++row;
- ++row_vpos;
+ for (; EQ (glyph->object, after_string) && glyph < end; ++glyph)
+ x += glyph->pixel_width;
}
-
- /* Find the right column within BEST_ROW. */
- lastcol = 0;
- current_x = best_row->x;
- for (i = 0; i < best_row->used[TEXT_AREA]; i++)
+ else
{
- struct glyph *glyph = best_row->glyphs[TEXT_AREA] + i;
- int charpos = glyph->charpos;
+ /* If there's no after-string, we must check if we overshot,
+ which might be the case if we stopped after a string glyph.
+ That glyph may belong to a before-string or display-string
+ associated with the end position, which must not be
+ highlighted. */
+ Lisp_Object prev_object;
+ int pos;
- if (BUFFERP (glyph->object))
+ while (glyph > row->glyphs[TEXT_AREA])
{
- if (charpos == pos)
- {
- *hpos = i;
- *vpos = best_row_vpos;
- *x = current_x;
- *y = best_row->y;
- return 1;
- }
- else if (charpos > pos)
+ prev_object = (glyph - 1)->object;
+ if (!STRINGP (prev_object) || EQ (prev_object, display_string))
break;
- }
- else if (EQ (glyph->object, stop))
- break;
- if (charpos > 0)
- lastcol = i;
- current_x += glyph->pixel_width;
- }
+ pos = string_buffer_position (w, prev_object, end_charpos);
+ if (pos && pos < end_charpos)
+ break;
- /* If we're looking for the end of the buffer,
- and we didn't find it in the line we scanned,
- use the start of the following line. */
- if (maybe_next_line_p)
- {
- ++best_row;
- ++best_row_vpos;
- lastcol = 0;
- current_x = best_row->x;
+ for (; glyph > row->glyphs[TEXT_AREA]
+ && EQ ((glyph - 1)->object, prev_object);
+ --glyph)
+ x -= (glyph - 1)->pixel_width;
+ }
}
- *vpos = best_row_vpos;
- *hpos = lastcol + 1;
- *x = current_x;
- *y = best_row->y;
- return 0;
+ dpyinfo->mouse_face_end_x = x;
+ dpyinfo->mouse_face_end_col = glyph - row->glyphs[TEXT_AREA];
+ dpyinfo->mouse_face_window = window;
+ dpyinfo->mouse_face_face_id
+ = face_at_buffer_position (w, mouse_charpos, 0, 0, &ignore,
+ mouse_charpos + 1,
+ !dpyinfo->mouse_face_hidden, -1);
+ show_mouse_face (dpyinfo, DRAW_MOUSE_FACE);
}
-#endif /* not 1 */
-
/* Find the position of the glyph for position POS in OBJECT in
window W's current matrix, and return in *X, *Y the pixel
|| (OVERLAYP (dpyinfo->mouse_face_overlay)
&& mouse_face_overlay_overlaps (dpyinfo->mouse_face_overlay)))
{
- /* Find the highest priority overlay that has a mouse-face
- property. */
+ /* Find the highest priority overlay with a mouse-face. */
overlay = Qnil;
for (i = noverlays - 1; i >= 0 && NILP (overlay); --i)
{
overlay = overlay_vec[i];
}
- /* If we're actually highlighting the same overlay as
- before, there's no need to do that again. */
- if (!NILP (overlay)
- && EQ (overlay, dpyinfo->mouse_face_overlay))
+ /* If we're highlighting the same overlay as before, there's
+ no need to do that again. */
+ if (!NILP (overlay) && EQ (overlay, dpyinfo->mouse_face_overlay))
goto check_help_echo;
-
dpyinfo->mouse_face_overlay = overlay;
/* Clear the display of the old active region, if any. */
if (NILP (overlay))
mouse_face = Fget_text_property (position, Qmouse_face, object);
- /* Handle the overlay case. */
- if (!NILP (overlay))
- {
- /* Find the range of text around this char that
- should be active. */
- Lisp_Object before, after;
- EMACS_INT ignore;
-
- before = Foverlay_start (overlay);
- after = Foverlay_end (overlay);
- /* Record this as the current active region. */
- fast_find_position (w, XFASTINT (before),
- &dpyinfo->mouse_face_beg_col,
- &dpyinfo->mouse_face_beg_row,
- &dpyinfo->mouse_face_beg_x,
- &dpyinfo->mouse_face_beg_y, Qnil);
-
- dpyinfo->mouse_face_past_end
- = !fast_find_position (w, XFASTINT (after),
- &dpyinfo->mouse_face_end_col,
- &dpyinfo->mouse_face_end_row,
- &dpyinfo->mouse_face_end_x,
- &dpyinfo->mouse_face_end_y, Qnil);
- dpyinfo->mouse_face_window = window;
-
- dpyinfo->mouse_face_face_id
- = face_at_buffer_position (w, pos, 0, 0,
- &ignore, pos + 1,
- !dpyinfo->mouse_face_hidden);
-
- /* Display it as active. */
- show_mouse_face (dpyinfo, DRAW_MOUSE_FACE);
- cursor = No_Cursor;
- }
- /* Handle the text property case. */
- else if (!NILP (mouse_face) && BUFFERP (object))
- {
- /* Find the range of text around this char that
- should be active. */
- Lisp_Object before, after, beginning, end;
- EMACS_INT ignore;
-
- beginning = Fmarker_position (w->start);
- end = make_number (BUF_Z (XBUFFER (object))
- - XFASTINT (w->window_end_pos));
- before
- = Fprevious_single_property_change (make_number (pos + 1),
- Qmouse_face,
- object, beginning);
- after
- = Fnext_single_property_change (position, Qmouse_face,
- object, end);
-
- /* Record this as the current active region. */
- fast_find_position (w, XFASTINT (before),
- &dpyinfo->mouse_face_beg_col,
- &dpyinfo->mouse_face_beg_row,
- &dpyinfo->mouse_face_beg_x,
- &dpyinfo->mouse_face_beg_y, Qnil);
- dpyinfo->mouse_face_past_end
- = !fast_find_position (w, XFASTINT (after),
- &dpyinfo->mouse_face_end_col,
- &dpyinfo->mouse_face_end_row,
- &dpyinfo->mouse_face_end_x,
- &dpyinfo->mouse_face_end_y, Qnil);
- dpyinfo->mouse_face_window = window;
-
- if (BUFFERP (object))
- dpyinfo->mouse_face_face_id
- = face_at_buffer_position (w, pos, 0, 0,
- &ignore, pos + 1,
- !dpyinfo->mouse_face_hidden);
-
- /* Display it as active. */
- show_mouse_face (dpyinfo, DRAW_MOUSE_FACE);
- cursor = No_Cursor;
- }
- else if (!NILP (mouse_face) && STRINGP (object))
+ /* Next, compute the bounds of the mouse highlighting and
+ display it. */
+ if (!NILP (mouse_face) && STRINGP (object))
{
+ /* The mouse-highlighting comes from a display string
+ with a mouse-face. */
Lisp_Object b, e;
EMACS_INT ignore;
- b = Fprevious_single_property_change (make_number (pos + 1),
- Qmouse_face,
- object, Qnil);
- e = Fnext_single_property_change (position, Qmouse_face,
- object, Qnil);
+ b = Fprevious_single_property_change
+ (make_number (pos + 1), Qmouse_face, object, Qnil);
+ e = Fnext_single_property_change
+ (position, Qmouse_face, object, Qnil);
if (NILP (b))
b = make_number (0);
if (NILP (e))
show_mouse_face (dpyinfo, DRAW_MOUSE_FACE);
cursor = No_Cursor;
}
- else if (STRINGP (object) && NILP (mouse_face))
+ else
{
- /* A string which doesn't have mouse-face, but
- the text ``under'' it might have. */
- struct glyph_row *r = MATRIX_ROW (w->current_matrix, vpos);
- int start = MATRIX_ROW_START_CHARPOS (r);
-
- pos = string_buffer_position (w, object, start);
- if (pos > 0)
- mouse_face = get_char_property_and_overlay (make_number (pos),
- Qmouse_face,
- w->buffer,
- &overlay);
- if (!NILP (mouse_face) && !NILP (overlay))
+ /* The mouse-highlighting, if any, comes from an overlay
+ or text property in the buffer. */
+ Lisp_Object buffer, display_string;
+
+ if (STRINGP (object))
{
- Lisp_Object before = Foverlay_start (overlay);
- Lisp_Object after = Foverlay_end (overlay);
- EMACS_INT ignore;
+ /* If we are on a display string with no mouse-face,
+ check if the text under it has one. */
+ struct glyph_row *r = MATRIX_ROW (w->current_matrix, vpos);
+ int start = MATRIX_ROW_START_CHARPOS (r);
+ pos = string_buffer_position (w, object, start);
+ if (pos > 0)
+ {
+ mouse_face = get_char_property_and_overlay
+ (make_number (pos), Qmouse_face, w->buffer, &overlay);
+ buffer = w->buffer;
+ display_string = object;
+ }
+ }
+ else
+ {
+ buffer = object;
+ display_string = Qnil;
+ }
+
+ if (!NILP (mouse_face))
+ {
+ Lisp_Object before, after;
+ Lisp_Object before_string, after_string;
+
+ if (NILP (overlay))
+ {
+ /* Handle the text property case. */
+ before = Fprevious_single_property_change
+ (make_number (pos + 1), Qmouse_face, buffer,
+ Fmarker_position (w->start));
+ after = Fnext_single_property_change
+ (make_number (pos), Qmouse_face, buffer,
+ make_number (BUF_Z (XBUFFER (buffer))
+ - XFASTINT (w->window_end_pos)));
+ before_string = after_string = Qnil;
+ }
+ else
+ {
+ /* Handle the overlay case. */
+ before = Foverlay_start (overlay);
+ after = Foverlay_end (overlay);
+ before_string = Foverlay_get (overlay, Qbefore_string);
+ after_string = Foverlay_get (overlay, Qafter_string);
+
+ if (!STRINGP (before_string)) before_string = Qnil;
+ if (!STRINGP (after_string)) after_string = Qnil;
+ }
- /* Note that we might not be able to find position
- BEFORE in the glyph matrix if the overlay is
- entirely covered by a `display' property. In
- this case, we overshoot. So let's stop in
- the glyph matrix before glyphs for OBJECT. */
- fast_find_position (w, XFASTINT (before),
- &dpyinfo->mouse_face_beg_col,
- &dpyinfo->mouse_face_beg_row,
- &dpyinfo->mouse_face_beg_x,
- &dpyinfo->mouse_face_beg_y,
- object);
-
- dpyinfo->mouse_face_past_end
- = !fast_find_position (w, XFASTINT (after),
- &dpyinfo->mouse_face_end_col,
- &dpyinfo->mouse_face_end_row,
- &dpyinfo->mouse_face_end_x,
- &dpyinfo->mouse_face_end_y,
- Qnil);
- dpyinfo->mouse_face_window = window;
- dpyinfo->mouse_face_face_id
- = face_at_buffer_position (w, pos, 0, 0,
- &ignore, pos + 1,
- !dpyinfo->mouse_face_hidden);
-
- /* Display it as active. */
- show_mouse_face (dpyinfo, DRAW_MOUSE_FACE);
+ mouse_face_from_buffer_pos (window, dpyinfo, pos,
+ XFASTINT (before),
+ XFASTINT (after),
+ before_string, after_string,
+ display_string);
cursor = No_Cursor;
}
}
For any other non-nil value, truncate lines in all windows with
less than the full frame width.
-A value of nil means to respect the value of `truncate-lines'. */);
- Vtruncate_partial_width_windows = make_number (30);
+A value of nil means to respect the value of `truncate-lines'.
+
+If `word-wrap' is enabled, you might want to reduce this. */);
+ Vtruncate_partial_width_windows = make_number (50);
DEFVAR_BOOL ("mode-line-inverse-video", &mode_line_inverse_video,
doc: /* When nil, display the mode-line/header-line/menu-bar in the default face.
DEFVAR_LISP ("window-scroll-functions", &Vwindow_scroll_functions,
doc: /* List of functions to call before redisplaying a window with scrolling.
-Each function is called with two arguments, the window
-and its new display-start position. Note that the value of `window-end'
-is not valid when these functions are called. */);
+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. */);
Vwindow_scroll_functions = Qnil;
DEFVAR_LISP ("window-text-change-functions",
inhibit_menubar_update = 0;
DEFVAR_LISP ("wrap-prefix", &Vwrap_prefix,
- doc: /* Prefix added to the beginning of all continuation lines at display-time.
-May be a string, an image, or a stretch-glyph such as used by the
-`display' text-property.
+ doc: /* Prefix prepended to all continuation lines at display time.
+The value may be a string, an image, or a stretch-glyph; it is
+interpreted in the same way as the value of a `display' text property.
-This variable is overridden by any `wrap-prefix' text-property.
+This variable is overridden by any `wrap-prefix' text or overlay
+property.
-To add a prefix to non-continuation lines, use the `line-prefix' variable. */);
+To add a prefix to non-continuation lines, use `line-prefix'. */);
Vwrap_prefix = Qnil;
staticpro (&Qwrap_prefix);
Qwrap_prefix = intern ("wrap-prefix");
Fmake_variable_buffer_local (Qwrap_prefix);
DEFVAR_LISP ("line-prefix", &Vline_prefix,
- doc: /* Prefix added to the beginning of all non-continuation lines at display-time.
-May be a string, an image, or a stretch-glyph such as used by the
-`display' text-property.
+ doc: /* Prefix prepended to all non-continuation lines at display time.
+The value may be a string, an image, or a stretch-glyph; it is
+interpreted in the same way as the value of a `display' text property.
-This variable is overridden by any `line-prefix' text-property.
+This variable is overridden by any `line-prefix' text or overlay
+property.
-To add a prefix to continuation lines, use the `wrap-prefix' variable. */);
+To add a prefix to continuation lines, use `wrap-prefix'. */);
Vline_prefix = Qnil;
staticpro (&Qline_prefix);
Qline_prefix = intern ("line-prefix");