cache and mode line face are not yet initialized. */
if (FRAME_FACE_CACHE (f))
{
- struct face *face = FACE_FROM_ID (f, face_id);
+ struct face *face = FACE_OPT_FROM_ID (f, face_id);
if (face)
{
if (face->font)
/* If we have a boxed mode line, make the first character appear
with a left box line. */
- face = FACE_FROM_ID (it->f, remapped_base_face_id);
+ face = FACE_OPT_FROM_ID (it->f, remapped_base_face_id);
if (face && face->box != FACE_NO_BOX)
it->start_of_box_run_p = true;
}
{
struct face *new_face = FACE_FROM_ID (it->f, new_face_id);
/* If it->face_id is -1, old_face below will be NULL, see
- the definition of FACE_FROM_ID. This will happen if this
+ the definition of FACE_OPT_FROM_ID. This will happen if this
is the initial call that gets the face. */
- struct face *old_face = FACE_FROM_ID (it->f, it->face_id);
+ struct face *old_face = FACE_OPT_FROM_ID (it->f, it->face_id);
/* If the value of face_id of the iterator is -1, we have to
look in front of IT's position and see whether there is a
{
int prev_face_id = face_before_it_pos (it);
- old_face = FACE_FROM_ID (it->f, prev_face_id);
+ old_face = FACE_OPT_FROM_ID (it->f, prev_face_id);
}
/* If the new face has a box, but the old face does not,
if (new_face_id != it->face_id)
{
struct face *new_face = FACE_FROM_ID (it->f, new_face_id);
- struct face *old_face = FACE_FROM_ID (it->f, it->face_id);
+ struct face *old_face = FACE_OPT_FROM_ID (it->f, it->face_id);
/* If new face has a box but old face hasn't, this is the
start of a run of characters with box, i.e. it has a
it->font_height = XCAR (XCDR (spec));
if (!NILP (it->font_height))
{
- struct face *face = FACE_FROM_ID (it->f, it->face_id);
int new_height = -1;
if (CONSP (it->font_height)
{
/* Call function with current height as argument.
Value is the new height. */
+ struct face *face = FACE_FROM_ID (it->f, it->face_id);
Lisp_Object height;
height = safe_call1 (it->font_height,
face->lface[LFACE_HEIGHT_INDEX]);
/* Evaluate IT->font_height with `height' bound to the
current specified height to get the new height. */
ptrdiff_t count = SPECPDL_INDEX ();
+ struct face *face = FACE_FROM_ID (it->f, it->face_id);
specbind (Qheight, face->lface[LFACE_HEIGHT_INDEX]);
value = safe_eval (it->font_height);
break;
case GET_FROM_STRING:
{
- struct face *face = FACE_FROM_ID (it->f, it->face_id);
+ struct face *face = FACE_OPT_FROM_ID (it->f, it->face_id);
/* Restore the face_box_p flag, since it could have been
overwritten by the face of the object that we just finished
|| ((IT)->cmp_it.stop_pos == (CHARPOS) \
&& composition_reseat_it (&(IT)->cmp_it, CHARPOS, BYTEPOS, \
END_CHARPOS, (IT)->w, \
- FACE_FROM_ID ((IT)->f, (IT)->face_id), \
+ FACE_OPT_FROM_ID ((IT)->f, (IT)->face_id), \
(IT)->string)))
goto display_control;
}
+ /* Handle non-ascii hyphens in the mode where it only
+ gets highlighting. */
+
+ if (nonascii_hyphen_p && EQ (Vnobreak_char_display, Qt))
+ {
+ /* Merge `nobreak-space' into the current face. */
+ face_id = merge_faces (it->f, Qnobreak_hyphen, 0,
+ it->face_id);
+ XSETINT (it->ctl_chars[0], '-');
+ ctl_len = 1;
+ goto display_control;
+ }
+
/* Handle sequences that start with the "escape glyph". */
/* the default escape glyph is \. */
? merge_faces (it->f, Qt, lface_id, it->face_id)
: merge_escape_glyph_face (it));
- /* Draw non-ASCII hyphen with just highlighting: */
-
- if (nonascii_hyphen_p && EQ (Vnobreak_char_display, Qt))
- {
- XSETINT (it->ctl_chars[0], '-');
- ctl_len = 1;
- goto display_control;
- }
-
/* Draw non-ASCII space/hyphen with escape glyph: */
if (nonascii_space_p || nonascii_hyphen_p)
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);
+ struct face *face = FACE_OPT_FROM_ID (it->f, face_id);
if (face)
{
{
ptrdiff_t ignore;
int next_face_id;
+ bool text_from_string = false;
+ /* Normally, the next buffer location is stored in
+ IT->current.pos... */
struct text_pos pos = it->current.pos;
- /* For a string from a display property, the next
- buffer position is stored in the 'position'
+ /* ...but for a string from a display property, the
+ next buffer position is stored in the 'position'
member of the iteration stack slot below the
current one, see handle_single_display_spec. By
- contrast, it->current.pos was not yet updated
- to point to that buffer position; that will
- happen in pop_it, after we finish displaying the
- current string. Note that we already checked
- above that it->sp is positive, so subtracting one
- from it is safe. */
+ contrast, it->current.pos was not yet updated to
+ point to that buffer position; that will happen
+ in pop_it, after we finish displaying the current
+ string. Note that we already checked above that
+ it->sp is positive, so subtracting one from it is
+ safe. */
if (it->from_disp_prop_p)
{
int stackp = it->sp - 1;
while (stackp >= 0
&& STRINGP ((it->stack + stackp)->string))
stackp--;
- eassert (stackp >= 0);
- pos = (it->stack + stackp)->position;
+ if (stackp < 0)
+ {
+ /* If no stack slot was found for iterating
+ a buffer, we are displaying text from a
+ string, most probably the mode line or
+ the header line, and that string has a
+ display string on some of its
+ characters. */
+ text_from_string = true;
+ pos = it->stack[it->sp - 1].position;
+ }
+ else
+ pos = (it->stack + stackp)->position;
}
else
INC_TEXT_POS (pos, it->multibyte_p);
- if (CHARPOS (pos) >= ZV)
+ if (text_from_string)
+ {
+ Lisp_Object base_string = it->stack[it->sp - 1].string;
+
+ if (CHARPOS (pos) >= SCHARS (base_string) - 1)
+ it->end_of_box_run_p = true;
+ else
+ {
+ next_face_id
+ = face_at_string_position (it->w, base_string,
+ CHARPOS (pos), 0,
+ &ignore, face_id, false);
+ it->end_of_box_run_p
+ = (FACE_FROM_ID (it->f, next_face_id)->box
+ == FACE_NO_BOX);
+ }
+ }
+ else if (CHARPOS (pos) >= ZV)
it->end_of_box_run_p = true;
else
{
- next_face_id = face_at_buffer_position
- (it->w, CHARPOS (pos), &ignore,
- CHARPOS (pos) + TEXT_PROP_DISTANCE_LIMIT, false, -1);
+ next_face_id =
+ face_at_buffer_position (it->w, CHARPOS (pos), &ignore,
+ CHARPOS (pos)
+ + TEXT_PROP_DISTANCE_LIMIT,
+ false, -1);
it->end_of_box_run_p
= (FACE_FROM_ID (it->f, next_face_id)->box
== FACE_NO_BOX);
/* Glyphs in the display vector could have the box face, so we
need to set the related flags in the iterator, as
appropriate. */
- this_face = FACE_FROM_ID (it->f, it->face_id);
- prev_face = FACE_FROM_ID (it->f, prev_face_id);
+ this_face = FACE_OPT_FROM_ID (it->f, it->face_id);
+ prev_face = FACE_OPT_FROM_ID (it->f, prev_face_id);
/* Is this character the first character of a box-face run? */
it->start_of_box_run_p = (this_face && this_face->box != FACE_NO_BOX
it->saved_face_id);
}
}
- next_face = FACE_FROM_ID (it->f, next_face_id);
+ next_face = FACE_OPT_FROM_ID (it->f, next_face_id);
it->end_of_box_run_p = (this_face && this_face->box != FACE_NO_BOX
&& (!next_face
|| next_face->box == FACE_NO_BOX));
? WINDOW_LEFT_FRINGE_WIDTH (it->w)
: WINDOW_RIGHT_FRINGE_WIDTH (it->w)))))
{
+ bool moved_forward = false;
+
if (/* IT->hpos == 0 means the very first glyph
doesn't fit on the line, e.g. a wide image. */
it->hpos == 0
now that we know it fits in this row. */
if (BUFFER_POS_REACHED_P ())
{
+ bool can_wrap = true;
+
+ /* If we are at a whitespace character
+ that barely fits on this screen line,
+ but the next character is also
+ whitespace, we cannot wrap here. */
+ if (it->line_wrap == WORD_WRAP
+ && wrap_it.sp >= 0
+ && may_wrap
+ && IT_OVERFLOW_NEWLINE_INTO_FRINGE (it))
+ {
+ struct it tem_it;
+ void *tem_data = NULL;
+
+ SAVE_IT (tem_it, *it, tem_data);
+ set_iterator_to_next (it, true);
+ if (get_next_display_element (it)
+ && IT_DISPLAYING_WHITESPACE (it))
+ can_wrap = false;
+ RESTORE_IT (it, &tem_it, tem_data);
+ }
if (it->line_wrap != WORD_WRAP
|| wrap_it.sp < 0
- /* If we've just found whitespace to
- wrap, effectively ignore the
- previous wrap point -- it is no
- longer relevant, but we won't
- have an opportunity to update it,
- since we've reached the edge of
- this screen line. */
- || (may_wrap
+ /* If we've just found whitespace
+ where we can wrap, effectively
+ ignore the previous wrap point --
+ it is no longer relevant, but we
+ won't have an opportunity to
+ update it, since we've reached
+ the edge of this screen line. */
+ || (may_wrap && can_wrap
&& IT_OVERFLOW_NEWLINE_INTO_FRINGE (it)))
{
it->hpos = hpos_before_this_char;
result = MOVE_POS_MATCH_OR_ZV;
break;
}
+ moved_forward = true;
if (BUFFER_POS_REACHED_P ())
{
if (ITERATOR_AT_END_OF_LINE_P (it))
longer relevant, but we won't have an opportunity
to update it, since we are done with this screen
line. */
- if (may_wrap && IT_OVERFLOW_NEWLINE_INTO_FRINGE (it))
+ if (may_wrap && IT_OVERFLOW_NEWLINE_INTO_FRINGE (it)
+ /* If the character after the one which set the
+ may_wrap flag is also whitespace, we can't
+ wrap here, since the screen line cannot be
+ wrapped in the middle of whitespace.
+ Therefore, wrap_it _is_ relevant in that
+ case. */
+ && !(moved_forward && IT_DISPLAYING_WHITESPACE (it)))
{
/* If we've found TO_X, go back there, as we now
know the last word fits on this screen line. */
#undef BUFFER_POS_REACHED_P
- /* If we scanned beyond to_pos and didn't find a point to wrap at,
- restore the saved iterator. */
- if (atpos_it.sp >= 0)
+ /* If we scanned beyond TO_POS, restore the saved iterator either to
+ the wrap point (if found), or to atpos/atx location. We decide which
+ data to use to restore the saved iterator state by their X coordinates,
+ since buffer positions might increase non-monotonically with screen
+ coordinates due to bidi reordering. */
+ if (result == MOVE_LINE_CONTINUED
+ && it->line_wrap == WORD_WRAP
+ && wrap_it.sp >= 0
+ && ((atpos_it.sp >= 0 && wrap_it.current_x < atpos_it.current_x)
+ || (atx_it.sp >= 0 && wrap_it.current_x < atx_it.current_x)))
+ RESTORE_IT (it, &wrap_it, wrap_data);
+ else if (atpos_it.sp >= 0)
RESTORE_IT (it, &atpos_it, atpos_data);
else if (atx_it.sp >= 0)
RESTORE_IT (it, &atx_it, atx_data);
long lines that shall be truncated anyway.
The optional argument Y-LIMIT, if non-nil, specifies the maximum text
-height (exluding the height of the mode- or header-line, if any) that
+height (excluding the height of the mode- or header-line, if any) that
can be returned. Text lines whose y-coordinate is beyond Y-LIMIT are
ignored. Since calculating the text height of a large buffer can take
some time, it makes sense to specify this argument if the size of the
static void
ensure_echo_area_buffers (void)
{
- int i;
-
- for (i = 0; i < 2; ++i)
+ for (int i = 0; i < 2; i++)
if (!BUFFERP (echo_buffer[i])
|| !BUFFER_LIVE_P (XBUFFER (echo_buffer[i])))
{
- char name[30];
- Lisp_Object old_buffer;
- int j;
-
- old_buffer = echo_buffer[i];
- echo_buffer[i] = Fget_buffer_create
- (make_formatted_string (name, " *Echo Area %d*", i));
+ Lisp_Object old_buffer = echo_buffer[i];
+ static char const name_fmt[] = " *Echo Area %d*";
+ char name[sizeof name_fmt + INT_STRLEN_BOUND (int)];
+ AUTO_STRING_WITH_LEN (lname, name, sprintf (name, name_fmt, i));
+ echo_buffer[i] = Fget_buffer_create (lname);
bset_truncate_lines (XBUFFER (echo_buffer[i]), Qnil);
/* to force word wrap in echo area -
it was decided to postpone this*/
/* XBUFFER (echo_buffer[i])->word_wrap = Qt; */
- for (j = 0; j < 2; ++j)
+ for (int j = 0; j < 2; j++)
if (EQ (old_buffer, echo_area_buffer[j]))
echo_area_buffer[j] = echo_buffer[i];
}
specbind (Qinhibit_free_realized_faces, Qnil);
/* Record this function, so it appears on the profiler's backtraces. */
- record_in_backtrace (Qredisplay_internal, 0, 0);
+ record_in_backtrace (Qredisplay_internal_xC_functionx, 0, 0);
FOR_EACH_FRAME (tail, frame)
XFRAME (frame)->already_hscrolled_p = false;
ignore_mouse_drag_p = true;
#endif
}
+ ptrdiff_t count1 = SPECPDL_INDEX ();
+ /* x_consider_frame_title calls select-frame, which calls
+ resize_mini_window, which could resize the mini-window and by
+ that undo the effect of this redisplay cycle wrt minibuffer
+ and echo-area display. Binding inhibit-redisplay to t makes
+ the call to resize_mini_window a no-op, thus avoiding the
+ adverse side effects. */
+ specbind (Qinhibit_redisplay, Qt);
x_consider_frame_title (w->frame);
+ unbind_to (count1, Qnil);
#endif
}
eassert (MATRIX_ROW_DISPLAYS_TEXT_P (first_unchanged_at_end_row));
row = find_last_row_displaying_text (w->current_matrix, &it,
first_unchanged_at_end_row);
- eassert (row && MATRIX_ROW_DISPLAYS_TEXT_P (row));
+ eassume (row && MATRIX_ROW_DISPLAYS_TEXT_P (row));
adjust_window_ends (w, row, true);
eassert (w->window_end_bytepos >= 0);
IF_DEBUG (debug_method_add (w, "A"));
struct glyph_row *current_row = current_matrix->rows + vpos;
struct glyph_row *desired_row = desired_matrix->rows + vpos;
- for (row = NULL;
- row == NULL && vpos >= first_vpos;
- --vpos, --current_row, --desired_row)
+ for (row = NULL; !row; --vpos, --current_row, --desired_row)
{
+ eassert (first_vpos <= vpos);
if (desired_row->enabled_p)
{
if (MATRIX_ROW_DISPLAYS_TEXT_P (desired_row))
row = current_row;
}
- eassert (row != NULL);
w->window_end_vpos = vpos + 1;
w->window_end_pos = Z - MATRIX_ROW_END_CHARPOS (row);
w->window_end_bytepos = Z_BYTE - MATRIX_ROW_END_BYTEPOS (row);
return;
/* The default face, possibly remapped. */
- default_face = FACE_FROM_ID (f, lookup_basic_face (f, DEFAULT_FACE_ID));
+ default_face = FACE_OPT_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->face_before_selective_p)
- face = FACE_FROM_ID (f, it->saved_face_id);
- else
- face = FACE_FROM_ID (f, it->face_id);
+ face = FACE_OPT_FROM_ID (f, (it->face_before_selective_p
+ ? it->saved_face_id
+ : it->face_id));
if (FRAME_WINDOW_P (f)
&& MATRIX_ROW_DISPLAYS_TEXT_P (it->glyph_row)
face = FACE_FROM_ID (f, glyph->face_id);
/* Make sure X resources of the face are allocated. */
- eassert (face != NULL);
prepare_face_for_display (f, face);
if (face->font)
s->cmp_id = glyph->u.cmp.id;
s->cmp_from = glyph->slice.cmp.from;
s->cmp_to = glyph->slice.cmp.to + 1;
- s->face = FACE_FROM_ID (s->f, face_id);
+ s->face = FACE_OPT_FROM_ID (s->f, face_id);
lgstring = composition_gstring_from_id (s->cmp_id);
s->font = XFONT_OBJECT (LGSTRING_FONT (lgstring));
glyph++;
#define BUILD_COMPOSITE_GLYPH_STRING(START, END, HEAD, TAIL, HL, X, LAST_X) \
do { \
int face_id = (row)->glyphs[area][START].face_id; \
- struct face *base_face = FACE_FROM_ID (f, face_id); \
+ struct face *base_face = FACE_OPT_FROM_ID (f, face_id); \
ptrdiff_t cmp_id = (row)->glyphs[area][START].u.cmp.id; \
struct composition *cmp = composition_table[cmp_id]; \
XChar2b *char2b; \
glyph->object = it->object;
if (it->pixel_width > 0)
{
+ eassert (it->pixel_width <= SHRT_MAX);
glyph->pixel_width = it->pixel_width;
glyph->padding_p = false;
}
}
glyph->charpos = it->cmp_it.charpos;
glyph->object = it->object;
+ eassert (it->pixel_width <= SHRT_MAX);
glyph->pixel_width = it->pixel_width;
glyph->ascent = it->ascent;
glyph->descent = it->descent;
eassert (it->what == IT_IMAGE);
face = FACE_FROM_ID (it->f, it->face_id);
- eassert (face);
/* Make sure X resources of the face is loaded. */
prepare_face_for_display (it->f, face);
}
img = IMAGE_FROM_ID (it->f, it->image_id);
- eassert (img);
/* Make sure X resources of the image is loaded. */
prepare_image_for_display (it->f, img);
{
glyph->charpos = CHARPOS (it->position);
glyph->object = it->object;
- glyph->pixel_width = it->pixel_width;
+ glyph->pixel_width = clip_to_bounds (-1, it->pixel_width, SHRT_MAX);
glyph->ascent = glyph_ascent;
glyph->descent = it->descent;
glyph->voffset = it->voffset;
eassert (it->what == IT_XWIDGET);
struct face *face = FACE_FROM_ID (it->f, it->face_id);
- eassert (face);
/* Make sure X resources of the face is loaded. */
prepare_face_for_display (it->f, face);
{
glyph->charpos = CHARPOS (it->position);
glyph->object = it->object;
- glyph->pixel_width = it->pixel_width;
+ glyph->pixel_width = clip_to_bounds (-1, it->pixel_width, SHRT_MAX);
glyph->ascent = glyph_ascent;
glyph->descent = it->descent;
glyph->voffset = it->voffset;
}
glyph->charpos = CHARPOS (it->position);
glyph->object = object;
- glyph->pixel_width = width;
+ /* FIXME: It would be better to use TYPE_MAX here, but
+ __typeof__ is not portable enough... */
+ glyph->pixel_width = clip_to_bounds (-1, width, SHRT_MAX);
glyph->ascent = ascent;
glyph->descent = height - ascent;
glyph->voffset = it->voffset;
}
glyph->charpos = CHARPOS (it->position);
glyph->object = it->object;
+ eassert (it->pixel_width <= SHRT_MAX);
glyph->pixel_width = it->pixel_width;
glyph->ascent = it->ascent;
glyph->descent = it->descent;
int leftmost, rightmost, lowest, highest;
int lbearing, rbearing;
int i, width, ascent, descent;
- int c IF_LINT (= 0); /* cmp->glyph_len can't be zero; see Bug#8512 */
+ int c;
XChar2b char2b;
struct font_metrics *pcm;
ptrdiff_t pos;
- for (glyph_len = cmp->glyph_len; glyph_len > 0; glyph_len--)
- if ((c = COMPOSITION_GLYPH (cmp, glyph_len - 1)) != '\t')
- break;
+ eassume (0 < glyph_len); /* See Bug#8512. */
+ do
+ c = COMPOSITION_GLYPH (cmp, --glyph_len);
+ while (c == '\t' && 0 < glyph_len);
+
bool right_padded = glyph_len < cmp->glyph_len;
for (i = 0; i < glyph_len; i++)
{
- if ((c = COMPOSITION_GLYPH (cmp, i)) != '\t')
+ c = COMPOSITION_GLYPH (cmp, i);
+ if (c != '\t')
break;
cmp->offsets[i * 2] = cmp->offsets[i * 2 + 1] = 0;
}
/* Using a block cursor on large images can be very annoying.
So use a hollow cursor for "large" images.
If image is not transparent (no mask), also use hollow cursor. */
- struct image *img = IMAGE_FROM_ID (f, glyph->u.img_id);
+ struct image *img = IMAGE_OPT_FROM_ID (f, glyph->u.img_id);
if (img != NULL && IMAGEP (img->spec))
{
/* Arbitrarily, interpret "Large" as >32x32 and >NxN
/* Look for :pointer property on image. */
if (glyph != NULL && glyph->type == IMAGE_GLYPH)
{
- struct image *img = IMAGE_FROM_ID (f, glyph->u.img_id);
+ struct image *img = IMAGE_OPT_FROM_ID (f, glyph->u.img_id);
if (img != NULL && IMAGEP (img->spec))
{
Lisp_Object image_map, hotspot;
/* Non-nil means don't actually do any redisplay. */
DEFSYM (Qinhibit_redisplay, "inhibit-redisplay");
- DEFSYM (Qredisplay_internal, "redisplay_internal (C function)");
+ DEFSYM (Qredisplay_internal_xC_functionx, "redisplay_internal (C function)");
DEFVAR_BOOL("inhibit-message", inhibit_message,
doc: /* Non-nil means calls to `message' are not displayed.
/* Name and number of the face used to highlight escape glyphs. */
DEFSYM (Qescape_glyph, "escape-glyph");
- /* Name and number of the face used to highlight non-breaking spaces. */
+ /* Name and number of the face used to highlight non-breaking
+ spaces/hyphens. */
DEFSYM (Qnobreak_space, "nobreak-space");
+ DEFSYM (Qnobreak_hyphen, "nobreak-hyphen");
/* The symbol 'image' which is the car of the lists used to represent
images in Lisp. Also a tool bar style. */
doc: /* Control highlighting of non-ASCII space and hyphen chars.
If the value is t, Emacs highlights non-ASCII chars which have the
same appearance as an ASCII space or hyphen, using the `nobreak-space'
-or `escape-glyph' face respectively.
+or `nobreak-hyphen' face respectively.
U+00A0 (no-break space), U+00AD (soft hyphen), U+2010 (hyphen), and
U+2011 (non-breaking hyphen) are affected.
Vtruncate_partial_width_windows,
doc: /* Non-nil means truncate lines in windows narrower than the frame.
For an integer value, truncate lines in each window narrower than the
-full frame width, provided the window width is less than that integer;
-otherwise, respect the value of `truncate-lines'.
+full frame width, provided the total window width in column units is less
+than that integer; otherwise, respect the value of `truncate-lines'.
+The total width of the window is as returned by `window-total-width', it
+includes the fringes, the continuation and truncation glyphs, the
+display margins (if any), and the scroll bar
For any other non-nil value, truncate lines in all windows that do
not span the full frame width.