/* Display generation from window structure and buffer text.
-Copyright (C) 1985-1988, 1993-1995, 1997-2014 Free Software Foundation,
+Copyright (C) 1985-1988, 1993-1995, 1997-2015 Free Software Foundation,
Inc.
This file is part of GNU Emacs.
/* Holds the list (error). */
static Lisp_Object list_of_error;
-static Lisp_Object Qfontification_functions;
+Lisp_Object Qfontification_functions;
static Lisp_Object Qwrap_prefix;
static Lisp_Object Qline_prefix;
static void pop_it (struct it *);
static void sync_frame_with_window_matrix_rows (struct window *);
static void redisplay_internal (void);
-static int echo_area_display (int);
+static bool echo_area_display (bool);
static void redisplay_windows (Lisp_Object);
static void redisplay_window (Lisp_Object, bool);
static Lisp_Object redisplay_window_error (Lisp_Object);
struct text_pos top;
int visible_p = 0;
struct buffer *old_buffer = NULL;
+ bool r2l = false;
if (FRAME_INITIAL_P (XFRAME (WINDOW_FRAME (w))))
return visible_p;
*rowh = max (0, (min (bottom_y, it.last_visible_y)
- max (top_y, window_top_y)));
*vpos = it.vpos;
+ if (it.bidi_it.paragraph_dir == R2L)
+ r2l = true;
}
}
else
- max (it2.current_y,
WINDOW_HEADER_LINE_HEIGHT (w))));
*vpos = it2.vpos;
+ if (it2.bidi_it.paragraph_dir == R2L)
+ r2l = true;
}
else
bidi_unshelve_cache (it2data, 1);
if (old_buffer)
set_buffer_internal_1 (old_buffer);
- if (visible_p && w->hscroll > 0)
- *x -=
- window_hscroll_limited (w, WINDOW_XFRAME (w))
- * WINDOW_FRAME_COLUMN_WIDTH (w);
+ if (visible_p)
+ {
+ if (w->hscroll > 0)
+ *x -=
+ window_hscroll_limited (w, WINDOW_XFRAME (w))
+ * WINDOW_FRAME_COLUMN_WIDTH (w);
+ /* For lines in an R2L paragraph, we need to mirror the X pixel
+ coordinate wrt the text area. For the reasons, see the
+ commentary in buffer_posn_from_coords and the explanation of
+ the geometry used by the move_it_* functions at the end of
+ the large commentary near the beginning of this file. */
+ if (r2l)
+ *x = window_box_width (w, TEXT_AREA) - *x - 1;
+ }
#if 0
/* Debugging code. */
glyph, and `x-stretch-block-cursor' is nil, don't draw a
rectangle as wide as the glyph, but use a canonical character
width instead. */
- wd = glyph->pixel_width - 1;
-#if defined (HAVE_NTGUI) || defined (HAVE_NS)
- wd++; /* Why? */
-#endif
+ wd = glyph->pixel_width;
x = w->phys_cursor.x;
if (x < 0)
iterate_out_of_display_property (it);
*position = it->position;
}
+ /* If we were to display this fringe bitmap,
+ next_element_from_image would have reset this flag.
+ Do the same, to avoid affecting overlays that
+ follow. */
+ it->ignore_overlay_strings_at_pos_p = 0;
return 1;
}
}
iterate_out_of_display_property (it);
*position = it->position;
}
+ if (it)
+ /* Reset this flag like next_element_from_image would. */
+ it->ignore_overlay_strings_at_pos_p = 0;
return 1;
}
is R..." */
/* FIXME: Do we need an exception for characters from display
tables? */
- if (it->bidi_p && it->bidi_it.type == STRONG_R)
+ if (it->bidi_p && it->bidi_it.type == STRONG_R
+ && !inhibit_bidi_mirroring)
it->c = bidi_mirror_char (it->c);
/* Map via display table or translate control characters.
IT->c, IT->len etc. have been set to the next character by
else if (it->cmp_it.id >= 0)
{
/* We are currently getting glyphs from a composition. */
- int i;
-
if (! it->bidi_p)
{
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->end_charpos, Qnil);
- }
}
- else if (! it->cmp_it.reversed_p)
+ else
{
- /* Composition created while scanning forward. */
+ int i;
+
/* Update IT's char/byte positions to point to the first
character of the next grapheme cluster, or to the
character visually after the current composition. */
bidi_move_to_visually_next (&it->bidi_it);
IT_BYTEPOS (*it) = it->bidi_it.bytepos;
IT_CHARPOS (*it) = it->bidi_it.charpos;
+ }
- if (it->cmp_it.to < it->cmp_it.nglyphs)
- {
- /* Proceed to the next grapheme cluster. */
- it->cmp_it.from = it->cmp_it.to;
- }
- else
- {
- /* No more grapheme clusters in this composition.
- Find the next stop position. */
- ptrdiff_t stop = it->end_charpos;
- if (it->bidi_it.scan_dir < 0)
- /* Now we are scanning backward and don't know
- where to stop. */
- stop = -1;
- composition_compute_stop_pos (&it->cmp_it, IT_CHARPOS (*it),
- IT_BYTEPOS (*it), stop, Qnil);
- }
+ if ((! it->bidi_p || ! it->cmp_it.reversed_p)
+ && it->cmp_it.to < it->cmp_it.nglyphs)
+ {
+ /* Composition created while scanning forward. Proceed
+ to the next grapheme cluster. */
+ it->cmp_it.from = it->cmp_it.to;
+ }
+ else if ((it->bidi_p && it->cmp_it.reversed_p)
+ && it->cmp_it.from > 0)
+ {
+ /* Composition created while scanning backward. Proceed
+ to the previous grapheme cluster. */
+ it->cmp_it.to = it->cmp_it.from;
}
else
{
- /* Composition created while scanning backward. */
- /* Update IT's char/byte positions to point to the last
- character of the previous grapheme cluster, or the
- character visually after the current composition. */
- for (i = 0; i < it->cmp_it.nchars; i++)
- bidi_move_to_visually_next (&it->bidi_it);
- IT_BYTEPOS (*it) = it->bidi_it.bytepos;
- IT_CHARPOS (*it) = it->bidi_it.charpos;
- if (it->cmp_it.from > 0)
- {
- /* Proceed to the previous grapheme cluster. */
- it->cmp_it.to = it->cmp_it.from;
- }
- else
- {
- /* No more grapheme clusters in this composition.
- Find the next stop position. */
- ptrdiff_t stop = it->end_charpos;
- if (it->bidi_it.scan_dir < 0)
- /* Now we are scanning backward and don't know
- where to stop. */
- stop = -1;
- composition_compute_stop_pos (&it->cmp_it, IT_CHARPOS (*it),
- IT_BYTEPOS (*it), stop, Qnil);
- }
+ /* No more grapheme clusters in this composition.
+ Find the next stop position. */
+ ptrdiff_t stop = it->end_charpos;
+
+ if (it->bidi_it.scan_dir < 0)
+ /* Now we are scanning backward and don't know
+ where to stop. */
+ stop = -1;
+ composition_compute_stop_pos (&it->cmp_it, IT_CHARPOS (*it),
+ IT_BYTEPOS (*it), stop, Qnil);
}
}
else
}
if (it->cmp_it.id >= 0)
{
- int i;
-
+ /* We are delivering display elements from a composition.
+ Update the string position past the grapheme cluster
+ we've just processed. */
if (! it->bidi_p)
{
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->end_charpos, it->string);
- }
}
- else if (! it->cmp_it.reversed_p)
+ else
{
+ int i;
+
for (i = 0; i < it->cmp_it.nchars; i++)
bidi_move_to_visually_next (&it->bidi_it);
IT_STRING_BYTEPOS (*it) = it->bidi_it.bytepos;
IT_STRING_CHARPOS (*it) = it->bidi_it.charpos;
+ }
- if (it->cmp_it.to < it->cmp_it.nglyphs)
- it->cmp_it.from = it->cmp_it.to;
- else
- {
- ptrdiff_t stop = it->end_charpos;
- if (it->bidi_it.scan_dir < 0)
- stop = -1;
- composition_compute_stop_pos (&it->cmp_it,
- IT_STRING_CHARPOS (*it),
- IT_STRING_BYTEPOS (*it), stop,
- it->string);
- }
+ /* Did we exhaust all the grapheme clusters of this
+ composition? */
+ if ((! it->bidi_p || ! it->cmp_it.reversed_p)
+ && (it->cmp_it.to < it->cmp_it.nglyphs))
+ {
+ /* Not all the grapheme clusters were processed yet;
+ advance to the next cluster. */
+ it->cmp_it.from = it->cmp_it.to;
+ }
+ else if ((it->bidi_p && it->cmp_it.reversed_p)
+ && it->cmp_it.from > 0)
+ {
+ /* Likewise: advance to the next cluster, but going in
+ the reverse direction. */
+ it->cmp_it.to = it->cmp_it.from;
}
else
{
- for (i = 0; i < it->cmp_it.nchars; i++)
- bidi_move_to_visually_next (&it->bidi_it);
- IT_STRING_BYTEPOS (*it) = it->bidi_it.bytepos;
- IT_STRING_CHARPOS (*it) = it->bidi_it.charpos;
- if (it->cmp_it.from > 0)
- it->cmp_it.to = it->cmp_it.from;
- else
+ /* This composition was fully processed; find the next
+ candidate place for checking for composed
+ characters. */
+ /* Always limit string searches to the string length;
+ any padding spaces are not part of the string, and
+ there cannot be any compositions in that padding. */
+ ptrdiff_t stop = SCHARS (it->string);
+
+ if (it->bidi_p && it->bidi_it.scan_dir < 0)
+ stop = -1;
+ else if (it->end_charpos < stop)
{
- ptrdiff_t stop = it->end_charpos;
- if (it->bidi_it.scan_dir < 0)
- stop = -1;
- composition_compute_stop_pos (&it->cmp_it,
- IT_STRING_CHARPOS (*it),
- IT_STRING_BYTEPOS (*it), stop,
- it->string);
+ /* Cf. PRECISION in reseat_to_string: we might be
+ limited in how many of the string characters we
+ need to deliver. */
+ stop = it->end_charpos;
}
+ composition_compute_stop_pos (&it->cmp_it,
+ IT_STRING_CHARPOS (*it),
+ IT_STRING_BYTEPOS (*it), stop,
+ it->string);
}
}
else
bidi_move_to_visually_next (&it->bidi_it);
IT_STRING_BYTEPOS (*it) = it->bidi_it.bytepos;
IT_STRING_CHARPOS (*it) = it->bidi_it.charpos;
+ /* If the scan direction changes, we may need to update
+ the place where to check for composed characters. */
if (prev_scan_dir != it->bidi_it.scan_dir)
{
- ptrdiff_t stop = it->end_charpos;
+ ptrdiff_t stop = SCHARS (it->string);
if (it->bidi_it.scan_dir < 0)
stop = -1;
+ else if (it->end_charpos < stop)
+ stop = it->end_charpos;
+
composition_compute_stop_pos (&it->cmp_it,
IT_STRING_CHARPOS (*it),
IT_STRING_BYTEPOS (*it), stop,
unsigned char *p;
ptrdiff_t stop;
+ /* We moved to the next buffer position, so any info about
+ previously seen overlays is no longer valid. */
+ it->ignore_overlay_strings_at_pos_p = 0;
+
/* Maybe run the redisplay end trigger hook. Performance note:
This doesn't seem to cost measurable time. */
if (it->redisplay_end_trigger_charpos
doesn't fit on the line, e.g. a wide image. */
it->hpos == 0
|| (new_x == it->last_visible_x
- && FRAME_WINDOW_P (it->f)
- /* When word-wrap is ON and we have a valid
- wrap point, we don't allow the last glyph
- to "just barely fit" on the line. */
- && (it->line_wrap != WORD_WRAP
- || wrap_it.sp < 0)))
+ && FRAME_WINDOW_P (it->f)))
{
++it->hpos;
it->current_x = new_x;
}
if (ITERATOR_AT_END_OF_LINE_P (it)
&& (it->line_wrap != WORD_WRAP
- || wrap_it.sp < 0))
+ || wrap_it.sp < 0
+ || IT_OVERFLOW_NEWLINE_INTO_FRINGE (it)))
{
result = MOVE_NEWLINE_OR_CR;
break;
else
clear_message (true, true);
- do_pending_window_change (0);
- echo_area_display (1);
- do_pending_window_change (0);
+ do_pending_window_change (false);
+ echo_area_display (true);
+ do_pending_window_change (false);
if (FRAME_TERMINAL (f)->frame_up_to_date_hook)
(*FRAME_TERMINAL (f)->frame_up_to_date_hook) (f);
}
is non-zero update selected_frame. Value is non-zero if the
mini-windows height has been changed. */
-static int
-echo_area_display (int update_frame_p)
+static bool
+echo_area_display (bool update_frame_p)
{
Lisp_Object mini_window;
struct window *w;
struct frame *f;
- int window_height_changed_p = 0;
+ bool window_height_changed_p = false;
struct frame *sf = SELECTED_FRAME ();
mini_window = FRAME_MINIBUF_WINDOW (sf);
/* Window configuration is the same as before.
Can do with a display update of the echo area,
unless we displayed some mode lines. */
- update_single_window (w, 1);
+ update_single_window (w);
flush_frame (f);
}
else
- update_frame (f, 1, 1);
+ update_frame (f, true, true);
/* If cursor is in the echo area, make sure that the next
redisplay displays the minibuffer, so that the cursor will
menu_bar_hooks_run = update_menu_bar (f, 0, menu_bar_hooks_run);
#ifdef HAVE_WINDOW_SYSTEM
update_tool_bar (f, 0);
-#endif
-#ifdef HAVE_NS
- if (windows_or_buffers_changed
- && FRAME_NS_P (f))
- ns_set_doc_edited
- (f, Fbuffer_modified_p (XWINDOW (f->selected_window)->contents));
#endif
UNGCPRO;
}
struct window *w = XWINDOW (selected_window);
struct window *sw;
struct frame *fr;
- int pending;
+ bool pending;
bool must_finish = 0, match_p;
struct text_pos tlbufpos, tlendpos;
int number_of_visible_frames;
/* Remember the currently selected window. */
sw = w;
- pending = 0;
+ pending = false;
last_escape_glyph_frame = NULL;
last_escape_glyph_face_id = (1 << FACE_ID_BITS);
last_glyphless_glyph_frame = NULL;
}
/* Notice any pending interrupt request to change frame size. */
- do_pending_window_change (1);
+ do_pending_window_change (true);
/* do_pending_window_change could change the selected_window due to
frame resizing which makes the selected window too small. */
echo-area doesn't show through. */
&& !MINI_WINDOW_P (XWINDOW (selected_window))))
{
- int window_height_changed_p = echo_area_display (0);
+ int window_height_changed_p = echo_area_display (false);
if (message_cleared_p)
update_miniwindow_p = true;
{
if (!must_finish)
{
- do_pending_window_change (1);
+ do_pending_window_change (true);
/* If selected_window changed, redisplay again. */
if (WINDOWP (selected_window)
&& (w = XWINDOW (selected_window)) != sw)
if (f->fonts_changed)
{
adjust_frame_glyphs (f);
- f->fonts_changed = 0;
+ f->fonts_changed = false;
goto retry_frame;
}
/* See if we have to hscroll. */
if (!f->already_hscrolled_p)
{
- f->already_hscrolled_p = 1;
+ f->already_hscrolled_p = true;
if (hscroll_windows (f->root_window))
goto retry_frame;
}
unrequest_sigio ();
STOP_POLLING;
- pending |= update_frame (f, 0, 0);
- f->cursor_type_changed = 0;
- f->updated_p = 1;
+ pending |= update_frame (f, false, false);
+ f->cursor_type_changed = false;
+ f->updated_p = true;
}
}
}
goto retry;
XWINDOW (selected_window)->must_be_updated_p = true;
- pending = update_frame (sf, 0, 0);
- sf->cursor_type_changed = 0;
+ pending = update_frame (sf, false, false);
+ sf->cursor_type_changed = false;
}
/* We may have called echo_area_display at the top of this
if (mini_frame != sf && FRAME_WINDOW_P (mini_frame))
{
XWINDOW (mini_window)->must_be_updated_p = true;
- pending |= update_frame (mini_frame, 0, 0);
- mini_frame->cursor_type_changed = 0;
+ pending |= update_frame (mini_frame, false, false);
+ mini_frame->cursor_type_changed = false;
if (!pending && hscroll_windows (mini_window))
goto retry;
}
}
/* Change frame size now if a change is pending. */
- do_pending_window_change (1);
+ do_pending_window_change (true);
/* If we just did a pending size change, or have additional
visible frames, or selected_window changed, redisplay again. */
if (clear_face_cache_count > CLEAR_FACE_CACHE_COUNT)
{
- clear_face_cache (0);
+ clear_face_cache (false);
clear_face_cache_count = 0;
}
#endif /* HAVE_WINDOW_SYSTEM */
end_of_redisplay:
+#ifdef HAVE_NS
+ ns_set_doc_edited ();
+#endif
if (interrupt_input && interrupts_deferred)
request_sigio ();
{
/* We have a previously displayed message, but no current
message. Redisplay the previous message. */
- display_last_displayed_message_p = 1;
+ display_last_displayed_message_p = true;
redisplay_internal ();
- display_last_displayed_message_p = 0;
+ display_last_displayed_message_p = false;
}
else
redisplay_internal ();
non-zero margins, because scroll_up_aggressively
means put point that fraction of window height
_from_the_bottom_margin_. */
- if (aggressive_scroll + 2*this_scroll_margin > height)
- aggressive_scroll = height - 2*this_scroll_margin;
+ if (aggressive_scroll + 2 * this_scroll_margin > height)
+ aggressive_scroll = height - 2 * this_scroll_margin;
amount_to_scroll = dy + aggressive_scroll;
}
}
start_display (&it, w, startp);
if (arg_scroll_conservatively)
- amount_to_scroll = max (dy, frame_line_height *
- max (scroll_step, temp_scroll_step));
+ amount_to_scroll = max (dy, frame_line_height
+ * max (scroll_step, temp_scroll_step));
else if (scroll_step || temp_scroll_step)
amount_to_scroll = scroll_max;
else
bottom of the window, if the value of
scroll_down_aggressively happens to be too
large. */
- if (aggressive_scroll + 2*this_scroll_margin > height)
- aggressive_scroll = height - 2*this_scroll_margin;
+ if (aggressive_scroll + 2 * this_scroll_margin > height)
+ aggressive_scroll = height - 2 * this_scroll_margin;
amount_to_scroll = dy + aggressive_scroll;
}
}
set_cursor_from_row (w, row, w->desired_matrix, 0, 0, 0, 0);
- /* If we are highlighting the region, then we just changed
- the region, so redisplay to show it. */
- /* FIXME: We need to (re)run pre-redisplay-function! */
- /* if (markpos_of_region () >= 0)
+ /* Re-run pre-redisplay-function so it can update the region
+ according to the new position of point. */
+ /* Other than the cursor, w's redisplay is done so we can set its
+ redisplay to false. Also the buffer's redisplay can be set to
+ false, since propagate_buffer_redisplay should have already
+ propagated its info to `w' anyway. */
+ w->redisplay = false;
+ XBUFFER (w->contents)->text->redisplay = false;
+ safe__call1 (true, Vpre_redisplay_function, Fcons (window, Qnil));
+
+ if (w->redisplay || XBUFFER (w->contents)->text->redisplay)
{
+ /* pre-redisplay-function made changes (e.g. move the region)
+ that require another round of redisplay. */
clear_glyph_matrix (w->desired_matrix);
if (!try_window (window, startp, 0))
goto need_larger_matrices;
}
- */
}
if (w->cursor.vpos < 0 || !cursor_row_fully_visible_p (w, 0, 0))
{
{
int window_total_lines
= WINDOW_TOTAL_LINES (w) * FRAME_LINE_HEIGHT (f) / frame_line_height;
- int margin =
- scroll_margin > 0
+ int margin
+ = scroll_margin > 0
? min (scroll_margin, window_total_lines / 4)
: 0;
ptrdiff_t margin_pos = CHARPOS (startp);
doc: /* Dump the current matrix of the selected window to stderr.
Shows contents of glyph row structures. With non-nil
parameter GLYPHS, dump glyphs as well. If GLYPHS is 1 show
-glyphs in short form, otherwise show glyphs in long form. */)
+glyphs in short form, otherwise show glyphs in long form.
+
+Interactively, no argument means show glyphs in short form;
+with numeric argument, its value is passed as the GLYPHS flag. */)
(Lisp_Object glyphs)
{
struct window *w = XWINDOW (selected_window);
DEFUN ("dump-frame-glyph-matrix", Fdump_frame_glyph_matrix,
- Sdump_frame_glyph_matrix, 0, 0, "", doc: /* */)
+ Sdump_frame_glyph_matrix, 0, 0, "", doc: /* Dump the current glyph matrix of the selected frame to stderr.
+Only text-mode frames have frame glyph matrices. */)
(void)
{
struct frame *f = XFRAME (selected_frame);
- dump_glyph_matrix (f->current_matrix, 1);
+
+ if (f->current_matrix)
+ dump_glyph_matrix (f->current_matrix, 1);
+ else
+ fprintf (stderr, "*** This frame doesn't have a frame glyph matrix ***\n");
return Qnil;
}
{
/* If line-wrap is on, check if a previous
wrap point was found. */
- if (wrap_row_used > 0
+ if (!IT_OVERFLOW_NEWLINE_INTO_FRINGE (it)
+ && wrap_row_used > 0
/* Even if there is a previous wrap
point, continue the line here as
usual, if (i) the previous character
row->continued_p = 0;
row->exact_window_width_line_p = 1;
}
+ /* If line-wrap is on, check if a
+ previous wrap point was found. */
+ else if (wrap_row_used > 0
+ /* Even if there is a previous wrap
+ point, continue the line here as
+ usual, if (i) the previous character
+ was a space or tab AND (ii) the
+ current character is not. */
+ && (!may_wrap
+ || IT_DISPLAYING_WHITESPACE (it)))
+ goto back_to_wrap;
+
}
}
else if (it->bidi_p)
}
}
+DEFUN ("bidi-find-overridden-directionality",
+ Fbidi_find_overridden_directionality,
+ Sbidi_find_overridden_directionality, 2, 3, 0,
+ doc: /* Return position between FROM and TO where directionality was overridden.
+
+This function returns the first character position in the specified
+region of OBJECT where there is a character whose `bidi-class' property
+is `L', but which was forced to display as `R' by a directional
+override, and likewise with characters whose `bidi-class' is `R'
+or `AL' that were forced to display as `L'.
+
+If no such character is found, the function returns nil.
+
+OBJECT is a Lisp string or buffer to search for overridden
+directionality, and defaults to the current buffer if nil or omitted.
+OBJECT can also be a window, in which case the function will search
+the buffer displayed in that window. Passing the window instead of
+a buffer is preferable when the buffer is displayed in some window,
+because this function will then be able to correctly account for
+window-specific overlays, which can affect the results.
+
+Strong directional characters `L', `R', and `AL' can have their
+intrinsic directionality overridden by directional override
+control characters RLO \(u+202e) and LRO \(u+202d). See the
+function `get-char-code-property' for a way to inquire about
+the `bidi-class' property of a character. */)
+ (Lisp_Object from, Lisp_Object to, Lisp_Object object)
+{
+ struct buffer *buf = current_buffer;
+ struct buffer *old = buf;
+ struct window *w = NULL;
+ bool frame_window_p = FRAME_WINDOW_P (SELECTED_FRAME ());
+ struct bidi_it itb;
+ ptrdiff_t from_pos, to_pos, from_bpos;
+ void *itb_data;
+
+ if (!NILP (object))
+ {
+ if (BUFFERP (object))
+ buf = XBUFFER (object);
+ else if (WINDOWP (object))
+ {
+ w = decode_live_window (object);
+ buf = XBUFFER (w->contents);
+ frame_window_p = FRAME_WINDOW_P (XFRAME (w->frame));
+ }
+ else
+ CHECK_STRING (object);
+ }
+
+ if (STRINGP (object))
+ {
+ /* Characters in unibyte strings are always treated by bidi.c as
+ strong LTR. */
+ if (!STRING_MULTIBYTE (object)
+ /* When we are loading loadup.el, the character property
+ tables needed for bidi iteration are not yet
+ available. */
+ || !NILP (Vpurify_flag))
+ return Qnil;
+
+ validate_subarray (object, from, to, SCHARS (object), &from_pos, &to_pos);
+ if (from_pos >= SCHARS (object))
+ return Qnil;
+
+ /* Set up the bidi iterator. */
+ itb_data = bidi_shelve_cache ();
+ itb.paragraph_dir = NEUTRAL_DIR;
+ itb.string.lstring = object;
+ itb.string.s = NULL;
+ itb.string.schars = SCHARS (object);
+ itb.string.bufpos = 0;
+ itb.string.from_disp_str = 0;
+ itb.string.unibyte = 0;
+ itb.w = w;
+ bidi_init_it (0, 0, frame_window_p, &itb);
+ }
+ else
+ {
+ /* Nothing this fancy can happen in unibyte buffers, or in a
+ buffer that disabled reordering, or if FROM is at EOB. */
+ if (NILP (BVAR (buf, bidi_display_reordering))
+ || NILP (BVAR (buf, enable_multibyte_characters))
+ /* When we are loading loadup.el, the character property
+ tables needed for bidi iteration are not yet
+ available. */
+ || !NILP (Vpurify_flag))
+ return Qnil;
+
+ set_buffer_temp (buf);
+ validate_region (&from, &to);
+ from_pos = XINT (from);
+ to_pos = XINT (to);
+ if (from_pos >= ZV)
+ return Qnil;
+
+ /* Set up the bidi iterator. */
+ itb_data = bidi_shelve_cache ();
+ from_bpos = CHAR_TO_BYTE (from_pos);
+ if (from_pos == BEGV)
+ {
+ itb.charpos = BEGV;
+ itb.bytepos = BEGV_BYTE;
+ }
+ else if (FETCH_CHAR (from_bpos - 1) == '\n')
+ {
+ itb.charpos = from_pos;
+ itb.bytepos = from_bpos;
+ }
+ else
+ itb.charpos = find_newline_no_quit (from_pos, CHAR_TO_BYTE (from_pos),
+ -1, &itb.bytepos);
+ itb.paragraph_dir = NEUTRAL_DIR;
+ itb.string.s = NULL;
+ itb.string.lstring = Qnil;
+ itb.string.bufpos = 0;
+ itb.string.from_disp_str = 0;
+ itb.string.unibyte = 0;
+ itb.w = w;
+ bidi_init_it (itb.charpos, itb.bytepos, frame_window_p, &itb);
+ }
+
+ ptrdiff_t found;
+ do {
+ /* For the purposes of this function, the actual base direction of
+ the paragraph doesn't matter, so just set it to L2R. */
+ bidi_paragraph_init (L2R, &itb, 0);
+ while ((found = bidi_find_first_overridden (&itb)) < from_pos)
+ ;
+ } while (found == ZV && itb.ch == '\n' && itb.charpos < to_pos);
+
+ bidi_unshelve_cache (itb_data, 0);
+ set_buffer_temp (old);
+
+ return (from_pos <= found && found < to_pos) ? make_number (found) : Qnil;
+}
+
DEFUN ("move-point-visually", Fmove_point_visually,
Smove_point_visually, 1, 1, 0,
doc: /* Move point in the visual order in the specified DIRECTION.
#undef ROW_GLYPH_NEWLINE_P
}
+DEFUN ("bidi-resolved-levels", Fbidi_resolved_levels,
+ Sbidi_resolved_levels, 0, 1, 0,
+ doc: /* Return the resolved bidirectional levels of characters at VPOS.
+
+The resolved levels are produced by the Emacs bidi reordering engine
+that implements the UBA, the Unicode Bidirectional Algorithm. Please
+read the Unicode Standard Annex 9 (UAX#9) for background information
+about these levels.
+
+VPOS is the zero-based number of the current window's screen line
+for which to produce the resolved levels. If VPOS is nil or omitted,
+it defaults to the screen line of point. If the window displays a
+header line, VPOS of zero will report on the header line, and first
+line of text in the window will have VPOS of 1.
+
+Value is an array of resolved levels, indexed by glyph number.
+Glyphs are numbered from zero starting from the beginning of the
+screen line, i.e. the left edge of the window for left-to-right lines
+and from the right edge for right-to-left lines. The resolved levels
+are produced only for the window's text area; text in display margins
+is not included.
+
+If the selected window's display is not up-to-date, or if the specified
+screen line does not display text, this function returns nil. It is
+highly recommended to bind this function to some simple key, like F8,
+in order to avoid these problems.
+
+This function exists mainly for testing the correctness of the
+Emacs UBA implementation, in particular with the test suite. */)
+ (Lisp_Object vpos)
+{
+ struct window *w = XWINDOW (selected_window);
+ struct buffer *b = XBUFFER (w->contents);
+ int nrow;
+ struct glyph_row *row;
+
+ if (NILP (vpos))
+ {
+ int d1, d2, d3, d4, d5;
+
+ pos_visible_p (w, PT, &d1, &d2, &d3, &d4, &d5, &nrow);
+ }
+ else
+ {
+ CHECK_NUMBER_COERCE_MARKER (vpos);
+ nrow = XINT (vpos);
+ }
+
+ /* We require up-to-date glyph matrix for this window. */
+ if (w->window_end_valid
+ && !windows_or_buffers_changed
+ && b
+ && !b->clip_changed
+ && !b->prevent_redisplay_optimizations_p
+ && !window_outdated (w)
+ && nrow >= 0
+ && nrow < w->current_matrix->nrows
+ && (row = MATRIX_ROW (w->current_matrix, nrow))->enabled_p
+ && MATRIX_ROW_DISPLAYS_TEXT_P (row))
+ {
+ struct glyph *g, *e, *g1;
+ int nglyphs, i;
+ Lisp_Object levels;
+
+ if (!row->reversed_p) /* Left-to-right glyph row. */
+ {
+ g = g1 = row->glyphs[TEXT_AREA];
+ e = g + row->used[TEXT_AREA];
+
+ /* Skip over glyphs at the start of the row that was
+ generated by redisplay for its own needs. */
+ while (g < e
+ && INTEGERP (g->object)
+ && g->charpos < 0)
+ g++;
+ g1 = g;
+
+ /* Count the "interesting" glyphs in this row. */
+ for (nglyphs = 0; g < e && !INTEGERP (g->object); g++)
+ nglyphs++;
+
+ /* Create and fill the array. */
+ levels = make_uninit_vector (nglyphs);
+ for (i = 0; g1 < g; i++, g1++)
+ ASET (levels, i, make_number (g1->resolved_level));
+ }
+ else /* Right-to-left glyph row. */
+ {
+ g = row->glyphs[TEXT_AREA] + row->used[TEXT_AREA] - 1;
+ e = row->glyphs[TEXT_AREA] - 1;
+ while (g > e
+ && INTEGERP (g->object)
+ && g->charpos < 0)
+ g--;
+ g1 = g;
+ for (nglyphs = 0; g > e && !INTEGERP (g->object); g--)
+ nglyphs++;
+ levels = make_uninit_vector (nglyphs);
+ for (i = 0; g1 > g; i++, g1--)
+ ASET (levels, i, make_number (g1->resolved_level));
+ }
+ return levels;
+ }
+ else
+ return Qnil;
+}
+
+
\f
/***********************************************************************
Menu Bar
if (it->bidi_p)
{
glyph->resolved_level = it->bidi_it.resolved_level;
- if ((it->bidi_it.type & 7) != it->bidi_it.type)
- emacs_abort ();
+ eassert ((it->bidi_it.type & 7) == it->bidi_it.type);
glyph->bidi_type = it->bidi_it.type;
}
else
if (it->bidi_p)
{
glyph->resolved_level = it->bidi_it.resolved_level;
- if ((it->bidi_it.type & 7) != it->bidi_it.type)
- emacs_abort ();
+ eassert ((it->bidi_it.type & 7) == it->bidi_it.type);
glyph->bidi_type = it->bidi_it.type;
}
++it->glyph_row->used[area];
if (it->bidi_p)
{
glyph->resolved_level = it->bidi_it.resolved_level;
- if ((it->bidi_it.type & 7) != it->bidi_it.type)
- emacs_abort ();
+ eassert ((it->bidi_it.type & 7) == it->bidi_it.type);
glyph->bidi_type = it->bidi_it.type;
}
++it->glyph_row->used[area];
if (it->bidi_p)
{
glyph->resolved_level = it->bidi_it.resolved_level;
- if ((it->bidi_it.type & 7) != it->bidi_it.type)
- emacs_abort ();
+ eassert ((it->bidi_it.type & 7) == it->bidi_it.type);
glyph->bidi_type = it->bidi_it.type;
}
else
if (it->bidi_p)
{
glyph->resolved_level = it->bidi_it.resolved_level;
- if ((it->bidi_it.type & 7) != it->bidi_it.type)
- emacs_abort ();
+ eassert ((it->bidi_it.type & 7) == it->bidi_it.type);
glyph->bidi_type = it->bidi_it.type;
}
++it->glyph_row->used[area];
#ifdef HAVE_WINDOW_SYSTEM
/* Change the mouse cursor. */
- if (FRAME_WINDOW_P (f))
+ if (FRAME_WINDOW_P (f) && NILP (do_mouse_tracking))
{
#if ! defined (USE_GTK) && ! defined (HAVE_NS)
if (draw == DRAW_NORMAL_TEXT
defsubr (&Scurrent_bidi_paragraph_direction);
defsubr (&Swindow_text_pixel_size);
defsubr (&Smove_point_visually);
+ defsubr (&Sbidi_find_overridden_directionality);
DEFSYM (Qmenu_bar_update_hook, "menu-bar-update-hook");
DEFSYM (Qoverriding_terminal_local_map, "overriding-terminal-local-map");
DEFSYM (Qright_to_left, "right-to-left");
DEFSYM (Qleft_to_right, "left-to-right");
+ defsubr (&Sbidi_resolved_levels);
#ifdef HAVE_WINDOW_SYSTEM
DEFVAR_BOOL ("x-stretch-cursor", x_stretch_cursor_p,
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 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.
+display-start position.
+These functions are called whenever the `window-start' marker is modified,
+either to point into another buffer (e.g. via `set-window-buffer') or another
+place in the same buffer.
+Note that the value of `window-end' is not valid when these functions are
+called.
Warning: Do not use this feature to alter the way the window
is scrolled. It is not designed for that, and such use probably won't
doc: /* Non-nil means don't free realized faces. Internal use only. */);
inhibit_free_realized_faces = 0;
+ DEFVAR_BOOL ("inhibit-bidi-mirroring", inhibit_bidi_mirroring,
+ doc: /* Non-nil means don't mirror characters even when bidi context requires that.
+Intended for use during debugging and for testing bidi display;
+see biditest.el in the test suite. */);
+ inhibit_bidi_mirroring = 0;
+
#ifdef GLYPH_DEBUG
DEFVAR_BOOL ("inhibit-try-window-id", inhibit_try_window_id,
doc: /* Inhibit try_window_id display optimization. */);