area AREA of window W. ANY_AREA means return the right edge of the
whole window, to the left of the right fringe of W. */
-int
+static int
window_box_right_offset (struct window *w, enum glyph_row_area area)
{
/* Don't return more than the window's pixel width. */
glyph. */
int top_x = it.current_x;
int top_y = it.current_y;
- /* Calling line_bottom_y may change it.method, it.position, etc. */
- enum it_method it_method = it.method;
- int bottom_y = (last_height = 0, line_bottom_y (&it));
int window_top_y = WINDOW_HEADER_LINE_HEIGHT (w);
+ int bottom_y;
+ struct it save_it;
+ void *save_it_data = NULL;
+ /* Calling line_bottom_y may change it.method, it.position, etc. */
+ SAVE_IT (save_it, it, save_it_data);
+ last_height = 0;
+ bottom_y = line_bottom_y (&it);
if (top_y < window_top_y)
visible_p = bottom_y > window_top_y;
else if (top_y < it.last_visible_y)
- visible_p = true;
+ visible_p = 1;
if (bottom_y >= it.last_visible_y
&& it.bidi_p && it.bidi_it.scan_dir == -1
&& IT_CHARPOS (it) < charpos)
move_it_to again with a slightly larger vertical limit,
and see if it actually moved vertically; if it did, we
didn't really reach CHARPOS, which is beyond window end. */
- struct it save_it = it;
/* Why 10? because we don't know how many canonical lines
will the height of the next line(s) be. So we guess. */
int ten_more_lines = 10 * default_line_pixel_height (w);
if (it.current_y > top_y)
visible_p = 0;
- it = save_it;
}
+ RESTORE_IT (&it, &save_it, save_it_data);
if (visible_p)
{
- if (it_method == GET_FROM_DISPLAY_VECTOR)
+ if (it.method == GET_FROM_DISPLAY_VECTOR)
{
/* We stopped on the last glyph of a display vector.
Try and recompute. Hack alert! */
if (s->x > r.x)
{
- r.width -= s->x - r.x;
+ if (r.width >= s->x - r.x)
+ r.width -= s->x - r.x;
+ else /* R2L hscrolled row with cursor outside text area */
+ r.width = 0;
r.x = s->x;
}
r.width = min (r.width, glyph->pixel_width);
gy = 0;
/* The bottom divider prevails. */
height = WINDOW_PIXEL_HEIGHT (w) - WINDOW_BOTTOM_DIVIDER_WIDTH (w);
- goto add_edge;;
+ goto add_edge;
case ON_BOTTOM_DIVIDER:
gx = 0;
{
ptrdiff_t i;
ptrdiff_t count = SPECPDL_INDEX ();
- struct gcpro gcpro1;
- Lisp_Object *args = alloca (nargs * word_size);
+ Lisp_Object *args;
+ USE_SAFE_ALLOCA;
+ SAFE_ALLOCA_LISP (args, nargs);
args[0] = func;
for (i = 1; i < nargs; i++)
args[i] = va_arg (ap, Lisp_Object);
- GCPRO1 (args[0]);
- gcpro1.nvars = nargs;
specbind (Qinhibit_redisplay, Qt);
if (inhibit_quit)
specbind (Qinhibit_quit, Qt);
so there is no possibility of wanting to redisplay. */
val = internal_condition_case_n (Ffuncall, nargs, args, Qt,
safe_eval_handler);
- UNGCPRO;
+ SAFE_FREE ();
val = unbind_to (count, val);
}
/* If we truncate lines, leave room for the truncation glyph(s) at
the right margin. Otherwise, leave room for the continuation
- glyph(s). Done only if the window has no fringes. Since we
- don't know at this point whether there will be any R2L lines in
- the window, we reserve space for truncation/continuation glyphs
- even if only one of the fringes is absent. */
- if (WINDOW_RIGHT_FRINGE_WIDTH (it->w) == 0
- || (it->bidi_p && WINDOW_LEFT_FRINGE_WIDTH (it->w) == 0))
+ glyph(s). Done only if the window has no right fringe. */
+ if (WINDOW_RIGHT_FRINGE_WIDTH (it->w) == 0)
{
if (it->line_wrap == TRUNCATE)
it->last_visible_x -= it->truncation_pixel_width;
iterator. */
if (it->bidi_p)
{
+ /* Since we don't know at this point whether there will be
+ any R2L lines in the window, we reserve space for
+ truncation/continuation glyphs even if only the left
+ fringe is absent. */
+ if (base_face_id == DEFAULT_FACE_ID
+ && WINDOW_LEFT_FRINGE_WIDTH (it->w) == 0
+ && WINDOW_RIGHT_FRINGE_WIDTH (it->w) != 0)
+ {
+ if (it->line_wrap == TRUNCATE)
+ it->last_visible_x -= it->truncation_pixel_width;
+ else
+ it->last_visible_x -= it->continuation_pixel_width;
+ }
/* Note the paragraph direction that this buffer wants to
use. */
if (EQ (BVAR (current_buffer, bidi_paragraph_direction),
if (it->selective_display_ellipsis_p)
it->saved_face_id = it->face_id;
+ /* Here's the description of the semantics of, and the logic behind,
+ the various HANDLED_* statuses:
+
+ HANDLED_NORMALLY means the handler did its job, and the loop
+ should proceed to calling the next handler in order.
+
+ HANDLED_RECOMPUTE_PROPS means the handler caused a significant
+ change in the properties and overlays at current position, so the
+ loop should be restarted, to re-invoke the handlers that were
+ already called. This happens when fontification-functions were
+ called by handle_fontified_prop, and actually fontified
+ something. Another case where HANDLED_RECOMPUTE_PROPS is
+ returned is when we discover overlay strings that need to be
+ displayed right away. The loop below will continue for as long
+ as the status is HANDLED_RECOMPUTE_PROPS.
+
+ HANDLED_RETURN means return immediately to the caller, to
+ continue iteration without calling any further handlers. This is
+ used when we need to act on some property right away, for example
+ when we need to display the ellipsis or a replacing display
+ property, such as display string or image.
+
+ HANDLED_OVERLAY_STRING_CONSUMED means an overlay string was just
+ consumed, and the handler switched to the next overlay string.
+ This signals the loop below to refrain from looking for more
+ overlays before all the overlay strings of the current overlay
+ are processed.
+
+ Some of the handlers called by the loop push the iterator state
+ onto the stack (see 'push_it'), and arrange for the iteration to
+ continue with another object, such as an image, a display string,
+ or an overlay string. In most such cases, it->stop_charpos is
+ set to the first character of the string, so that when the
+ iteration resumes, this function will immediately be called
+ again, to examine the properties at the beginning of the string.
+
+ When a display or overlay string is exhausted, the iterator state
+ is popped (see 'pop_it'), and iteration continues with the
+ previous object. Again, in many such cases this function is
+ called again to find the next position where properties might
+ change. */
+
do
{
handled = HANDLED_NORMALLY;
ptrdiff_t i, noverlays;
ptrdiff_t endpos;
Lisp_Object *overlays;
+ USE_SAFE_ALLOCA;
/* Get all overlays at the given position. */
GET_OVERLAYS_AT (pos, overlays, noverlays, &endpos, 1);
endpos = min (endpos, oendpos);
}
+ SAFE_FREE ();
return endpos;
}
if (it)
{
- int face_id = lookup_basic_face (it->f, DEFAULT_FACE_ID);;
+ int face_id = lookup_basic_face (it->f, DEFAULT_FACE_ID);
if (CONSP (XCDR (XCDR (spec))))
{
Lisp_Object overlay, window, str, invisible;
struct Lisp_Overlay *ov;
ptrdiff_t start, end;
- ptrdiff_t size = 20;
ptrdiff_t n = 0, i, j;
int invis_p;
- struct overlay_entry *entries = alloca (size * sizeof *entries);
+ struct overlay_entry entriesbuf[20];
+ ptrdiff_t size = ARRAYELTS (entriesbuf);
+ struct overlay_entry *entries = entriesbuf;
USE_SAFE_ALLOCA;
if (charpos <= 0)
back_to_previous_visible_line_start (it);
it->vpos--;
}
+ reseat_1 (it, it->current.pos, 1);
}
else
RESTORE_IT (it, it, it2data);
{
ptrdiff_t nbytes = SBYTES (m);
bool multibyte = STRING_MULTIBYTE (m);
+ char *buffer;
USE_SAFE_ALLOCA;
- char *buffer = SAFE_ALLOCA (nbytes);
- memcpy (buffer, SDATA (m), nbytes);
+ SAFE_ALLOCA_STRING (buffer, m);
message_dolog (buffer, nbytes, 1, multibyte);
SAFE_FREE ();
}
{
ptrdiff_t len;
ptrdiff_t maxsize = FRAME_MESSAGE_BUF_SIZE (f);
- char *message_buf = alloca (maxsize + 1);
+ USE_SAFE_ALLOCA;
+ char *message_buf = SAFE_ALLOCA (maxsize + 1);
len = doprnt (message_buf, maxsize, m, 0, ap);
message3 (make_string (message_buf, len));
+ SAFE_FREE ();
}
else
message1 (0);
build_desired_tool_bar_string (struct frame *f)
{
int i, size, size_needed;
- struct gcpro gcpro1, gcpro2, gcpro3;
- Lisp_Object image, plist, props;
+ struct gcpro gcpro1, gcpro2;
+ Lisp_Object image, plist;
- image = plist = props = Qnil;
- GCPRO3 (image, plist, props);
+ image = plist = Qnil;
+ GCPRO2 (image, plist);
/* Prepare F->desired_tool_bar_string. If we can reuse it, do so.
Otherwise, make a new string. */
(f, Fmake_string (make_number (size_needed), make_number (' ')));
else
{
- props = list4 (Qdisplay, Qnil, Qmenu_item, Qnil);
+ AUTO_LIST4 (props, Qdisplay, Qnil, Qmenu_item, Qnil);
+ struct gcpro gcpro1;
+ GCPRO1 (props);
Fremove_text_properties (make_number (0), make_number (size),
props, f->desired_tool_bar_string);
+ UNGCPRO;
}
/* Put a `display' property on the string for the images to display,
the start of this item's properties in the tool-bar items
vector. */
image = Fcons (Qimage, plist);
- props = list4 (Qdisplay, image,
- Qmenu_item, make_number (i * TOOL_BAR_ITEM_NSLOTS));
+ AUTO_LIST4 (props, Qdisplay, image, Qmenu_item,
+ make_number (i * TOOL_BAR_ITEM_NSLOTS));
+ struct gcpro gcpro1;
+ GCPRO1 (props);
/* Let the last image hide all remaining spaces in the tool bar
string. The string can be longer than needed when we reuse a
end = i + 1;
Fadd_text_properties (make_number (i), make_number (end),
props, f->desired_tool_bar_string);
+ UNGCPRO;
#undef PROP
}
if (mode_line_update_needed (w))
w->update_mode_line = 1;
+
+ /* If reconsider_clip_changes above decided that the narrowing
+ in the current buffer changed, make sure all other windows
+ showing that buffer will be redisplayed. */
+ if (current_buffer->clip_changed)
+ bset_update_mode_line (current_buffer);
}
/* Normally the message* functions will have already displayed and
If FORCE_P is non-zero, return 0 even if partial visible cursor row
is higher than window.
+ If CURRENT_MATRIX_P is non-zero, use the information from the
+ window's current glyph matrix; otherwise use the desired glyph
+ matrix.
+
A value of 0 means the caller should do scrolling
as if point had gone off the screen. */
/* If someone specified a new starting point but did not insist,
check whether it can be used. */
- if (w->optional_new_start
+ if ((w->optional_new_start || window_frozen_p (w))
&& CHARPOS (startp) >= BEGV
&& CHARPOS (startp) <= ZV)
{
+ ptrdiff_t it_charpos;
+
w->optional_new_start = 0;
start_display (&it, w, startp);
move_it_to (&it, PT, 0, it.last_visible_y, -1,
MOVE_TO_POS | MOVE_TO_X | MOVE_TO_Y);
- if (IT_CHARPOS (it) == PT)
- w->force_start = 1;
- /* IT may overshoot PT if text at PT is invisible. */
- else if (IT_CHARPOS (it) > PT && CHARPOS (startp) <= PT)
- w->force_start = 1;
+ /* Record IT's position now, since line_bottom_y might change
+ that. */
+ it_charpos = IT_CHARPOS (it);
+ /* Make sure we set the force_start flag only if the cursor row
+ will be fully visible. Otherwise, the code under force_start
+ label below will try to move point back into view, which is
+ not what the code which sets optional_new_start wants. */
+ if ((it.current_y == 0 || line_bottom_y (&it) < it.last_visible_y)
+ && !w->force_start)
+ {
+ if (it_charpos == PT)
+ w->force_start = 1;
+ /* IT may overshoot PT if text at PT is invisible. */
+ else if (it_charpos > PT && CHARPOS (startp) <= PT)
+ w->force_start = 1;
+#ifdef GLYPH_DEBUG
+ if (w->force_start)
+ {
+ if (window_frozen_p (w))
+ debug_method_add (w, "set force_start from frozen window start");
+ else
+ debug_method_add (w, "set force_start from optional_new_start");
+ }
+#endif
+ }
}
force_start:
/* Handle case where place to start displaying has been specified,
unless the specified location is outside the accessible range. */
- if (w->force_start || window_frozen_p (w))
+ if (w->force_start)
{
/* We set this later on if we have to adjust point. */
int new_vpos = -1;
goto need_larger_matrices;
}
- if (w->cursor.vpos < 0 && !window_frozen_p (w))
+ if (w->cursor.vpos < 0)
{
/* If point does not appear, try to move point so it does
appear. The desired matrix has been built above, so we
}
*/
}
+ if (w->cursor.vpos < 0 || !cursor_row_fully_visible_p (w, 0, 0))
+ {
+ clear_glyph_matrix (w->desired_matrix);
+ goto try_to_scroll;
+ }
#ifdef GLYPH_DEBUG
debug_method_add (w, "forced window start");
|| CHARPOS (startp) == BEGV
|| !window_outdated (w)))
{
- int d1, d2, d3, d4, d5, d6;
+ int d1, d2, d5, d6;
+ int rtop, rbot;
/* If first window line is a continuation line, and window start
is inside the modified region, but the first change is before
&& compute_window_start_on_continuation_line (w)
/* It doesn't make sense to force the window start like we
do at label force_start if it is already known that point
- will not be visible in the resulting window, because
+ will not be fully visible in the resulting window, because
doing so will move point from its correct position
instead of scrolling the window to bring point into view.
See bug#9324. */
- && pos_visible_p (w, PT, &d1, &d2, &d3, &d4, &d5, &d6))
+ && pos_visible_p (w, PT, &d1, &d2, &rtop, &rbot, &d5, &d6)
+ /* A very tall row could need more than the window height,
+ in which case we accept that it is partially visible. */
+ && (rtop != 0) == (rbot != 0))
{
w->force_start = 1;
SET_TEXT_POS_FROM_MARKER (startp, w->start);
+#ifdef GLYPH_DEBUG
+ debug_method_add (w, "recomputed window start in continuation line");
+#endif
goto force_start;
}
else if (glyphs == 1)
{
int area;
+ char s[SHRT_MAX + 4];
for (area = LEFT_MARGIN_AREA; area < LAST_AREA; ++area)
{
- char *s = alloca (row->used[area] + 4);
int i;
for (i = 0; i < row->used[area]; ++i)
struct buffer *buffer = XBUFFER (w->contents);
struct buffer *old = current_buffer;
const unsigned char *arrow_string = SDATA (overlay_arrow_string);
- int arrow_len = SCHARS (overlay_arrow_string);
+ ptrdiff_t arrow_len = SCHARS (overlay_arrow_string);
const unsigned char *arrow_end = arrow_string + arrow_len;
const unsigned char *p;
struct it it;
for (row_width = 0, g = row_start; g < row_end; g++)
row_width += g->pixel_width;
- stretch_width = window_box_width (it->w, TEXT_AREA) - row_width;
+
+ /* FIXME: There are various minor display glitches in R2L
+ rows when only one of the fringes is missing. The
+ strange condition below produces the least bad effect. */
+ if ((WINDOW_LEFT_FRINGE_WIDTH (it->w) == 0)
+ == (WINDOW_RIGHT_FRINGE_WIDTH (it->w) == 0)
+ || WINDOW_RIGHT_FRINGE_WIDTH (it->w) != 0)
+ stretch_width = window_box_width (it->w, TEXT_AREA);
+ else
+ stretch_width = it->last_visible_x - it->first_visible_x;
+ stretch_width -= row_width;
+
if (stretch_width > 0)
{
stretch_ascent =
/* When the last glyph of an R2L row only fits
partially on the line, we need to set row->x to a
negative offset, so that the leftmost glyph is
- the one that is partially visible. */
- if (row->reversed_p && new_x > it->last_visible_x)
- row->x = it->last_visible_x - new_x;
+ the one that is partially visible. But if we are
+ going to produce the truncation glyph, this will
+ be taken care of in produce_special_glyphs. */
+ if (row->reversed_p
+ && new_x > it->last_visible_x
+ && !(it->line_wrap == TRUNCATE
+ && WINDOW_LEFT_FRINGE_WIDTH (it->w) == 0))
+ {
+ eassert (FRAME_WINDOW_P (it->f));
+ row->x = it->last_visible_x - new_x;
+ }
}
else
{
that they are cropped at the right edge of the
window, so an image glyph will always end exactly at
last_visible_x, even if there's no right fringe. */
- && (WINDOW_RIGHT_FRINGE_WIDTH (it->w) || it->what == IT_IMAGE))
+ && ((row->reversed_p
+ ? WINDOW_LEFT_FRINGE_WIDTH (it->w)
+ : WINDOW_RIGHT_FRINGE_WIDTH (it->w))
+ || it->what == IT_IMAGE))
? (it->current_x >= it->last_visible_x)
: (it->current_x > it->last_visible_x)))
{
row->truncated_on_right_p = 1;
it->continuation_lines_width = 0;
reseat_at_next_visible_line_start (it, 0);
- if (IT_BYTEPOS (*it) <= BEG_BYTE)
- row->ends_at_zv_p = true;
+ /* We insist below that IT's position be at ZV because in
+ bidi-reordered lines the character at visible line start
+ might not be the character that follows the newline in
+ the logical order. */
+ if (IT_BYTEPOS (*it) > BEG_BYTE)
+ row->ends_at_zv_p =
+ IT_BYTEPOS (*it) >= ZV_BYTE && FETCH_BYTE (ZV_BYTE - 1) != '\n';
else
- row->ends_at_zv_p = FETCH_BYTE (IT_BYTEPOS (*it) - 1) != '\n';
+ row->ends_at_zv_p = false;
break;
}
}
the previous non-empty line. */
if (pos >= ZV && pos > BEGV)
DEC_BOTH (pos, bytepos);
- if (fast_looking_at (build_string ("[\f\t ]*\n"),
+ AUTO_STRING (trailing_white_space, "[\f\t ]*\n");
+ if (fast_looking_at (trailing_white_space,
pos, bytepos, ZV, ZV_BYTE, Qnil) > 0)
{
while ((c = FETCH_BYTE (bytepos)) == '\n'
if ((gpt->resolved_level - row->reversed_p) % 2 == 0)
new_pos += (row->reversed_p ? -dir : dir);
else
- new_pos -= (row->reversed_p ? -dir : dir);;
+ new_pos -= (row->reversed_p ? -dir : dir);
}
else if (BUFFERP (g->object))
new_pos = g->charpos;
}
else if (CHARACTERP (eoltype))
{
- unsigned char *tmp = alloca (MAX_MULTIBYTE_LENGTH);
int c = XFASTINT (eoltype);
- eol_str_len = CHAR_STRING (c, tmp);
- eol_str = tmp;
+ return buf + CHAR_STRING (c, (unsigned char *) buf);
}
else
{
}
case 'e':
-#ifndef SYSTEM_MALLOC
+#if !defined SYSTEM_MALLOC && !defined HYBRID_MALLOC
{
if (NILP (Vmemory_full))
return "";
face_id = (row)->glyphs[area][START].face_id; \
\
s = alloca (sizeof *s); \
- char2b = alloca ((END - START) * sizeof *char2b); \
+ SAFE_NALLOCA (char2b, 1, (END) - (START)); \
INIT_GLYPH_STRING (s, char2b, w, row, area, START, HL); \
append_glyph_string (&HEAD, &TAIL, s); \
s->x = (X); \
struct glyph_string *first_s = NULL; \
int n; \
\
- char2b = alloca (cmp->glyph_len * sizeof *char2b); \
+ SAFE_NALLOCA (char2b, 1, cmp->glyph_len); \
\
/* Make glyph_strings for each glyph sequence that is drawable by \
the same face, and append them to HEAD/TAIL. */ \
gstring = (composition_gstring_from_id \
((row)->glyphs[area][START].u.cmp.id)); \
s = alloca (sizeof *s); \
- char2b = alloca (LGSTRING_GLYPH_LEN (gstring) * sizeof *char2b); \
+ SAFE_NALLOCA (char2b, 1, LGSTRING_GLYPH_LEN (gstring)); \
INIT_GLYPH_STRING (s, char2b, w, row, area, START, HL); \
append_glyph_string (&(HEAD), &(TAIL), s); \
s->x = (X); \
BUILD_GLYPH_STRINGS will modify its start parameter. That's
the reason we use a separate variable `i'. */
i = start;
+ USE_SAFE_ALLOCA;
BUILD_GLYPH_STRINGS (i, end, head, tail, hl, x, last_x);
if (tail)
x_reached = tail->x + tail->background_width;
RELEASE_HDC (hdc, f);
+ SAFE_FREE ();
return x_reached;
}
temp_it.dp = NULL;
temp_it.what = IT_CHARACTER;
- temp_it.len = 1;
temp_it.c = temp_it.char_to_display = GLYPH_CHAR (glyph);
temp_it.face_id = GLYPH_FACE (glyph);
temp_it.len = CHAR_BYTES (temp_it.c);
PRODUCE_GLYPHS (&temp_it);
it->pixel_width = temp_it.pixel_width;
- it->nglyphs = temp_it.pixel_width;
+ it->nglyphs = temp_it.nglyphs;
}
#ifdef HAVE_WINDOW_SYSTEM
&& (!on
|| w->phys_cursor.x != x
|| w->phys_cursor.y != y
+ /* HPOS can be negative in R2L rows whose
+ exact_window_width_line_p flag is set (i.e. their newline
+ would "overflow into the fringe"). */
+ || hpos < 0
|| new_cursor_type != w->phys_cursor_type
|| ((new_cursor_type == BAR_CURSOR || new_cursor_type == HBAR_CURSOR)
&& new_cursor_width != w->phys_cursor_width)))
/* Is this char mouse-active or does it have help-echo? */
position = make_number (pos);
+ USE_SAFE_ALLOCA;
+
if (BUFFERP (object))
{
/* Put all the overlays we want in a vector in overlay_vec. */
BEGV = obegv;
ZV = ozv;
current_buffer = obuf;
+ SAFE_FREE ();
}
set_cursor:
r.x = r.y = 0;
r.width = FRAME_TEXT_WIDTH (f);
r.height = FRAME_TEXT_HEIGHT (f);
-/** r.width = FRAME_COLUMN_WIDTH (f) * FRAME_COLS (f); **/
-/** r.height = FRAME_LINE_HEIGHT (f) * FRAME_LINES (f); **/
}
else
{