Merge from emacs-23
[bpt/emacs.git] / src / xdisp.c
index be6ff12..1c22064 100644 (file)
@@ -1,8 +1,8 @@
 /* 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, 2009, 2010
-                 Free Software Foundation, Inc.
+
+Copyright (C) 1985, 1986, 1987, 1988, 1993, 1994, 1995, 1997, 1998,
+  1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009,
+  2010  Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
 
@@ -214,11 +214,41 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
    leftmost character with special glyphs, which will display as,
    well, empty.  On text terminals, these special glyphs are simply
    blank characters.  On graphics terminals, there's a single stretch
-   glyph with suitably computed width.  Both the blanks and the
+   glyph of a suitably computed width.  Both the blanks and the
    stretch glyph are given the face of the background of the line.
    This way, the terminal-specific back-end can still draw the glyphs
    left to right, even for R2L lines.
 
+   Bidirectional display and character compositions
+
+   Some scripts cannot be displayed by drawing each character
+   individually, because adjacent characters change each other's shape
+   on display.  For example, Arabic and Indic scripts belong to this
+   category.
+
+   Emacs display supports this by providing "character compositions",
+   most of which is implemented in composite.c.  During the buffer
+   scan that delivers characters to PRODUCE_GLYPHS, if the next
+   character to be delivered is a composed character, the iteration
+   calls composition_reseat_it and next_element_from_composition.  If
+   they succeed to compose the character with one or more of the
+   following characters, the whole sequence of characters that where
+   composed is recorded in the `struct composition_it' object that is
+   part of the buffer iterator.  The composed sequence could produce
+   one or more font glyphs (called "grapheme clusters") on the screen.
+   Each of these grapheme clusters is then delivered to PRODUCE_GLYPHS
+   in the direction corresponding to the current bidi scan direction
+   (recorded in the scan_dir member of the `struct bidi_it' object
+   that is part of the buffer iterator).  In particular, if the bidi
+   iterator currently scans the buffer backwards, the grapheme
+   clusters are delivered back to front.  This reorders the grapheme
+   clusters as appropriate for the current bidi context.  Note that
+   this means that the grapheme clusters are always stored in the
+   LGSTRING object (see composite.c) in the logical order.
+
+   Moving an iterator in bidirectional text
+   without producing glyphs
+
    Note one important detail mentioned above: that the bidi reordering
    engine, driven by the iterator, produces characters in R2L rows
    starting at the character that will be the rightmost on display.
@@ -888,6 +918,9 @@ static int clear_face_cache_count;
 #ifdef HAVE_WINDOW_SYSTEM
 #define CLEAR_IMAGE_CACHE_COUNT        101
 static int clear_image_cache_count;
+
+/* Null glyph slice */
+static struct glyph_slice null_glyph_slice = { 0, 0, 0, 0 };
 #endif
 
 /* Non-zero while redisplay_internal is in progress.  */
@@ -907,16 +940,12 @@ Lisp_Object Qinhibit_free_realized_faces;
 Lisp_Object help_echo_string;
 Lisp_Object help_echo_window;
 Lisp_Object help_echo_object;
-int help_echo_pos;
+EMACS_INT help_echo_pos;
 
 /* Temporary variable for XTread_socket.  */
 
 Lisp_Object previous_help_echo_string;
 
-/* Null glyph slice */
-
-static struct glyph_slice null_glyph_slice = { 0, 0, 0, 0 };
-
 /* Platform-independent portion of hourglass implementation. */
 
 /* Non-zero means we're allowed to display a hourglass pointer.  */
@@ -932,6 +961,21 @@ struct atimer *hourglass_atimer;
 /* Number of seconds to wait before displaying an hourglass cursor.  */
 Lisp_Object Vhourglass_delay;
 
+/* Name of the face used to display glyphless characters.  */
+Lisp_Object Qglyphless_char;
+
+/* Char-table to control the display of glyphless characters.  */
+Lisp_Object Vglyphless_char_display;
+
+/* Symbol for the purpose of Vglyphless_char_display.  */
+Lisp_Object Qglyphless_char_display;
+
+/* Method symbols for Vglyphless_char_display.  */
+static Lisp_Object Qhex_code, Qempty_box, Qthin_space, Qzero_width;
+
+/* Default pixel width of `thin-space' display method.  */
+#define THIN_SPACE_WIDTH 1
+
 /* Default number of seconds to wait before displaying an hourglass
    cursor.  */
 #define DEFAULT_HOURGLASS_DELAY 1
@@ -956,13 +1000,12 @@ static void pint2hrstr (char *, int, int);
 static struct text_pos run_window_scroll_functions (Lisp_Object,
                                                     struct text_pos);
 static void reconsider_clip_changes (struct window *, struct buffer *);
-static int text_outside_line_unchanged_p (struct window *, int, int);
+static int text_outside_line_unchanged_p (struct window *,
+                                         EMACS_INT, EMACS_INT);
 static void store_mode_line_noprop_char (char);
 static int store_mode_line_noprop (const unsigned char *, int, int);
-static void x_consider_frame_title (Lisp_Object);
 static void handle_stop (struct it *);
 static void handle_stop_backwards (struct it *, EMACS_INT);
-static int tool_bar_lines_needed (struct frame *, int *);
 static int single_display_spec_intangible_p (Lisp_Object);
 static void ensure_echo_area_buffers (void);
 static Lisp_Object unwind_with_echo_area_buffer (Lisp_Object);
@@ -991,8 +1034,9 @@ static int append_space_for_newline (struct it *, int);
 static int cursor_row_fully_visible_p (struct window *, int, int);
 static int try_scrolling (Lisp_Object, int, EMACS_INT, EMACS_INT, int, int);
 static int try_cursor_movement (Lisp_Object, struct text_pos, int *);
-static int trailing_whitespace_p (int);
-static int message_log_check_duplicate (int, int, int, int);
+static int trailing_whitespace_p (EMACS_INT);
+static int message_log_check_duplicate (EMACS_INT, EMACS_INT,
+                                       EMACS_INT, EMACS_INT);
 static void push_it (struct it *);
 static void pop_it (struct it *);
 static void sync_frame_with_window_matrix_rows (struct window *);
@@ -1015,13 +1059,14 @@ static int store_mode_line_string (const char *, Lisp_Object, int, int, int, Lis
 static const char *decode_mode_spec (struct window *, int, int, int,
                                     Lisp_Object *);
 static void display_menu_bar (struct window *);
-static int display_count_lines (int, int, int, int, int *);
+static int display_count_lines (EMACS_INT, EMACS_INT, EMACS_INT, int,
+                               EMACS_INT *);
 static int display_string (const unsigned char *, Lisp_Object, Lisp_Object,
                            EMACS_INT, EMACS_INT, struct it *, int, int, int, int);
 static void compute_line_metrics (struct it *);
 static void run_redisplay_end_trigger_hook (struct it *);
-static int get_overlay_strings (struct it *, int);
-static int get_overlay_strings_1 (struct it *, int, int);
+static int get_overlay_strings (struct it *, EMACS_INT);
+static int get_overlay_strings_1 (struct it *, EMACS_INT, int);
 static void next_overlay_string (struct it *);
 static void reseat (struct it *, struct text_pos, int);
 static void reseat_1 (struct it *, struct text_pos, int);
@@ -1036,11 +1081,11 @@ static int next_element_from_buffer (struct it *);
 static int next_element_from_composition (struct it *);
 static int next_element_from_image (struct it *);
 static int next_element_from_stretch (struct it *);
-static void load_overlay_strings (struct it *, int);
+static void load_overlay_strings (struct it *, EMACS_INT);
 static int init_from_display_pos (struct it *, struct window *,
                                   struct display_pos *);
 static void reseat_to_string (struct it *, const unsigned char *,
-                              Lisp_Object, int, int, int, int);
+                              Lisp_Object, EMACS_INT, EMACS_INT, int, int);
 static enum move_it_result
        move_it_in_display_line_to (struct it *, EMACS_INT, int,
                                   enum move_operation_enum);
@@ -1052,10 +1097,10 @@ static int init_to_row_end (struct it *, struct window *,
 static void back_to_previous_line_start (struct it *);
 static int forward_to_next_line_start (struct it *, int *);
 static struct text_pos string_pos_nchars_ahead (struct text_pos,
-                                                Lisp_Object, int);
-static struct text_pos string_pos (int, Lisp_Object);
-static struct text_pos c_string_pos (int, const unsigned char *, int);
-static int number_of_chars (const unsigned char *, int);
+                                                Lisp_Object, EMACS_INT);
+static struct text_pos string_pos (EMACS_INT, Lisp_Object);
+static struct text_pos c_string_pos (EMACS_INT, const unsigned char *, int);
+static EMACS_INT number_of_chars (const unsigned char *, int);
 static void compute_stop_pos (struct it *);
 static void compute_string_pos (struct text_pos *, struct text_pos,
                                 Lisp_Object);
@@ -1073,6 +1118,8 @@ static int in_ellipses_for_invisible_text_p (struct display_pos *,
 
 #ifdef HAVE_WINDOW_SYSTEM
 
+static void x_consider_frame_title (Lisp_Object);
+static int tool_bar_lines_needed (struct frame *, int *);
 static void update_tool_bar (struct frame *, int);
 static void build_desired_tool_bar_string (struct frame *f);
 static int redisplay_tool_bar (struct frame *);
@@ -1084,9 +1131,11 @@ static void append_stretch_glyph (struct it *, Lisp_Object,
                                   int, int, int);
 
 
-
 #endif /* HAVE_WINDOW_SYSTEM */
 
+static int coords_in_mouse_face_p (struct window *, int, int);
+
+
 \f
 /***********************************************************************
                      Window display dimensions
@@ -1362,7 +1411,7 @@ line_bottom_y (struct it *it)
    Set *ROWH and *VPOS to row's visible height and VPOS (row number).  */
 
 int
-pos_visible_p (struct window *w, int charpos, int *x, int *y,
+pos_visible_p (struct window *w, EMACS_INT charpos, int *x, int *y,
               int *rtop, int *rbot, int *rowh, int *vpos)
 {
   struct it it;
@@ -1495,11 +1544,10 @@ pos_visible_p (struct window *w, int charpos, int *x, int *y,
 }
 
 
-/* Return the next character from STR which is MAXLEN bytes long.
-   Return in *LEN the length of the character.  This is like
-   STRING_CHAR_AND_LENGTH but never returns an invalid character.  If
-   we find one, we return a `?', but with the length of the invalid
-   character.  */
+/* Return the next character from STR.  Return in *LEN the length of
+   the character.  This is like STRING_CHAR_AND_LENGTH but never
+   returns an invalid character.  If we find one, we return a `?', but
+   with the length of the invalid character.  */
 
 static INLINE int
 string_char_and_length (const unsigned char *str, int *len)
@@ -1522,21 +1570,19 @@ string_char_and_length (const unsigned char *str, int *len)
    in STRING, return the position NCHARS ahead (NCHARS >= 0).  */
 
 static struct text_pos
-string_pos_nchars_ahead (struct text_pos pos, Lisp_Object string, int nchars)
+string_pos_nchars_ahead (struct text_pos pos, Lisp_Object string, EMACS_INT nchars)
 {
   xassert (STRINGP (string) && nchars >= 0);
 
   if (STRING_MULTIBYTE (string))
     {
-      int rest = SBYTES (string) - BYTEPOS (pos);
       const unsigned char *p = SDATA (string) + BYTEPOS (pos);
       int len;
 
       while (nchars--)
        {
          string_char_and_length (p, &len);
-         p += len, rest -= len;
-         xassert (rest >= 0);
+         p += len;
          CHARPOS (pos) += 1;
          BYTEPOS (pos) += len;
        }
@@ -1552,7 +1598,7 @@ string_pos_nchars_ahead (struct text_pos pos, Lisp_Object string, int nchars)
    for character position CHARPOS in STRING.  */
 
 static INLINE struct text_pos
-string_pos (int charpos, Lisp_Object string)
+string_pos (EMACS_INT charpos, Lisp_Object string)
 {
   struct text_pos pos;
   xassert (STRINGP (string));
@@ -1567,7 +1613,7 @@ string_pos (int charpos, Lisp_Object string)
    means recognize multibyte characters.  */
 
 static struct text_pos
-c_string_pos (int charpos, const unsigned char *s, int multibyte_p)
+c_string_pos (EMACS_INT charpos, const unsigned char *s, int multibyte_p)
 {
   struct text_pos pos;
 
@@ -1576,14 +1622,13 @@ c_string_pos (int charpos, const unsigned char *s, int multibyte_p)
 
   if (multibyte_p)
     {
-      int rest = strlen (s), len;
+      int len;
 
       SET_TEXT_POS (pos, 0, 0);
       while (charpos--)
        {
          string_char_and_length (s, &len);
-         s += len, rest -= len;
-         xassert (rest >= 0);
+         s += len;
          CHARPOS (pos) += 1;
          BYTEPOS (pos) += len;
        }
@@ -1598,14 +1643,15 @@ c_string_pos (int charpos, const unsigned char *s, int multibyte_p)
 /* Value is the number of characters in C string S.  MULTIBYTE_P
    non-zero means recognize multibyte characters.  */
 
-static int
+static EMACS_INT
 number_of_chars (const unsigned char *s, int multibyte_p)
 {
-  int nchars;
+  EMACS_INT nchars;
 
   if (multibyte_p)
     {
-      int rest = strlen (s), len;
+      EMACS_INT rest = strlen (s);
+      int len;
       unsigned char *p = (unsigned char *) s;
 
       for (nchars = 0; rest > 0; ++nchars)
@@ -1776,8 +1822,6 @@ glyph_to_pixel_coords (struct window *w, int hpos, int vpos,
 }
 
 
-#ifdef HAVE_WINDOW_SYSTEM
-
 /* Find the glyph under window-relative coordinates X/Y in window W.
    Consider only glyphs from buffer text, i.e. no glyphs from overlay
    strings.  Return in *HPOS and *VPOS the row and column number of
@@ -1860,7 +1904,6 @@ x_y_to_hpos_vpos (struct window *w, int x, int y, int *hpos, int *vpos,
   return glyph;
 }
 
-
 /* EXPORT:
    Convert frame-relative x/y to coordinates relative to window W.
    Takes pseudo-windows into account.  */
@@ -1883,6 +1926,8 @@ frame_to_window_pixel_xy (struct window *w, int *x, int *y)
     }
 }
 
+#ifdef HAVE_WINDOW_SYSTEM
+
 /* EXPORT:
    Return in RECTS[] at most N clipping rectangles for glyph string S.
    Return the number of stored rectangles.  */
@@ -2168,7 +2213,7 @@ remember_mouse_glyph (struct frame *f, int gx, int gy, NativeRectangle *rect)
      frame pixel coordinates X/Y on frame F.  */
 
   if (!f->glyphs_initialized_p
-      || (window = window_from_coordinates (f, gx, gy, &part, &x, &y, 0),
+      || (window = window_from_coordinates (f, gx, gy, &part, 0),
          NILP (window)))
     {
       width = FRAME_SMALLEST_CHAR_WIDTH (f);
@@ -2180,6 +2225,9 @@ remember_mouse_glyph (struct frame *f, int gx, int gy, NativeRectangle *rect)
   width = WINDOW_FRAME_COLUMN_WIDTH (w);
   height = WINDOW_FRAME_LINE_HEIGHT (w);
 
+  x = window_relative_x_coord (w, part, gx);
+  y = gy - WINDOW_TOP_EDGE_Y (w);
+
   r = MATRIX_FIRST_TEXT_ROW (w->current_matrix);
   end_row = MATRIX_BOTTOM_TEXT_ROW (w->current_matrix, w);
 
@@ -2653,7 +2701,7 @@ init_iterator (struct it *it, struct window *w,
              && WINDOWP (minibuf_selected_window)
              && w == XWINDOW (minibuf_selected_window))))
     {
-      int charpos = marker_position (current_buffer->mark);
+      EMACS_INT charpos = marker_position (current_buffer->mark);
       it->region_beg_charpos = min (PT, charpos);
       it->region_end_charpos = max (PT, charpos);
     }
@@ -2899,7 +2947,7 @@ in_ellipses_for_invisible_text_p (struct display_pos *pos, struct window *w)
 {
   Lisp_Object prop, window;
   int ellipses_p = 0;
-  int charpos = CHARPOS (pos->pos);
+  EMACS_INT charpos = CHARPOS (pos->pos);
 
   /* If POS specifies a position in a display vector, this might
      be for an ellipsis displayed for invisible text.  We won't
@@ -3455,7 +3503,8 @@ handle_face_prop (struct it *it)
     }
   else
     {
-      int base_face_id, bufpos;
+      int base_face_id;
+      EMACS_INT bufpos;
       int i;
       Lisp_Object from_overlay
        = (it->current.overlay_string_index >= 0
@@ -3579,7 +3628,8 @@ face_before_or_after_it_pos (struct it *it, int before_p)
 
   if (STRINGP (it->string))
     {
-      int bufpos, base_face_id;
+      EMACS_INT bufpos;
+      int base_face_id;
 
       /* No face change past the end of the string (for the case
         we are padding with spaces).  No face change before the
@@ -3622,7 +3672,6 @@ face_before_or_after_it_pos (struct it *it, int before_p)
       if (STRING_MULTIBYTE (it->string))
        {
          const unsigned char *p = SDATA (it->string) + BYTEPOS (pos);
-         int rest = SBYTES (it->string) - BYTEPOS (pos);
          int c, len;
          struct face *face = FACE_FROM_ID (it->f, face_id);
 
@@ -3825,7 +3874,7 @@ handle_invisible_prop (struct it *it)
                     skip any text at the beginning, which resets the
                     FIRST_ELT flag.  */
                  bidi_paragraph_init (it->paragraph_embedding,
-                                      &it->bidi_it, 0);
+                                      &it->bidi_it, 1);
                }
              do
                {
@@ -4640,7 +4689,6 @@ string_buffer_position_lim (struct window *w, Lisp_Object string,
 EMACS_INT
 string_buffer_position (struct window *w, Lisp_Object string, EMACS_INT around_charpos)
 {
-  Lisp_Object limit, prop, pos;
   const int MAX_DISTANCE = 1000;
   EMACS_INT found = string_buffer_position_lim (w, string, around_charpos,
                                                around_charpos + MAX_DISTANCE,
@@ -4770,6 +4818,7 @@ next_overlay_string (struct it *it)
                   && it->stop_charpos <= it->end_charpos));
       it->current.overlay_string_index = -1;
       it->n_overlay_strings = 0;
+      it->overlay_strings_charpos = -1;
 
       /* If we're at the end of the buffer, record that we have
         processed the overlay strings there already, so that
@@ -4782,11 +4831,13 @@ next_overlay_string (struct it *it)
       /* There are more overlay strings to process.  If
         IT->current.overlay_string_index has advanced to a position
         where we must load IT->overlay_strings with more strings, do
-        it.  */
+        it.  We must load at the IT->overlay_strings_charpos where
+        IT->n_overlay_strings was originally computed; when invisible
+        text is present, this might not be IT_CHARPOS (Bug#7016).  */
       int i = it->current.overlay_string_index % OVERLAY_STRING_CHUNK_SIZE;
 
       if (it->current.overlay_string_index && i == 0)
-       load_overlay_strings (it, 0);
+       load_overlay_strings (it, it->overlay_strings_charpos);
 
       /* Initialize IT to deliver display elements from the overlay
          string.  */
@@ -4871,11 +4922,11 @@ compare_overlay_entries (const void *e1, const void *e2)
    compare_overlay_entries.  */
 
 static void
-load_overlay_strings (struct it *it, int charpos)
+load_overlay_strings (struct it *it, EMACS_INT charpos)
 {
   Lisp_Object overlay, window, str, invisible;
   struct Lisp_Overlay *ov;
-  int start, end;
+  EMACS_INT start, end;
   int size = 20;
   int n = 0, i, j, invis_p;
   struct overlay_entry *entries
@@ -4998,8 +5049,9 @@ load_overlay_strings (struct it *it, int charpos)
   if (n > 1)
     qsort (entries, n, sizeof *entries, compare_overlay_entries);
 
-  /* Record the total number of strings to process.  */
+  /* Record number of overlay strings, and where we computed it.  */
   it->n_overlay_strings = n;
+  it->overlay_strings_charpos = charpos;
 
   /* IT->current.overlay_string_index is the number of overlay strings
      that have already been consumed by IT.  Copy some of the
@@ -5021,7 +5073,7 @@ load_overlay_strings (struct it *it, int charpos)
    least one overlay string was found.  */
 
 static int
-get_overlay_strings_1 (struct it *it, int charpos, int compute_stop_p)
+get_overlay_strings_1 (struct it *it, EMACS_INT charpos, int compute_stop_p)
 {
   /* Get the first OVERLAY_STRING_CHUNK_SIZE overlay strings to
      process.  This fills IT->overlay_strings with strings, and sets
@@ -5072,7 +5124,7 @@ get_overlay_strings_1 (struct it *it, int charpos, int compute_stop_p)
 }
 
 static int
-get_overlay_strings (struct it *it, int charpos)
+get_overlay_strings (struct it *it, EMACS_INT charpos)
 {
   it->string = Qnil;
   it->method = GET_FROM_BUFFER;
@@ -5147,7 +5199,7 @@ iterate_out_of_display_property (struct it *it)
      of a new paragraph, next_element_from_buffer may not have a
      chance to do that.  */
   if (it->bidi_it.first_elt && it->bidi_it.charpos < ZV)
-    bidi_paragraph_init (it->paragraph_embedding, &it->bidi_it, 0);
+    bidi_paragraph_init (it->paragraph_embedding, &it->bidi_it, 1);
   /* prev_stop can be zero, so check against BEGV as well.  */
   while (it->bidi_it.charpos >= BEGV
         && it->prev_stop <= it->bidi_it.charpos
@@ -5318,8 +5370,8 @@ forward_to_next_line_start (struct it *it, int *skipped_p)
      short-cut.  */
   if (!newline_found_p)
     {
-      int start = IT_CHARPOS (*it);
-      int limit = find_next_newline_no_quit (start, 1);
+      EMACS_INT start = IT_CHARPOS (*it);
+      EMACS_INT limit = find_next_newline_no_quit (start, 1);
       Lisp_Object pos;
 
       xassert (!STRINGP (it->string));
@@ -5390,7 +5442,7 @@ back_to_previous_visible_line_start (struct it *it)
 
       {
        struct it it2;
-       int pos;
+       EMACS_INT pos;
        EMACS_INT beg, end;
        Lisp_Object val, overlay;
 
@@ -5512,7 +5564,7 @@ reseat_at_next_visible_line_start (struct it *it, int on_newline_p)
 static void
 reseat (struct it *it, struct text_pos pos, int force_p)
 {
-  int original_pos = IT_CHARPOS (*it);
+  EMACS_INT original_pos = IT_CHARPOS (*it);
 
   reseat_1 (it, pos, 0);
 
@@ -5579,7 +5631,10 @@ reseat_1 (struct it *it, struct text_pos pos, int set_stop_p)
   it->string_from_display_prop_p = 0;
   it->face_before_selective_p = 0;
   if (it->bidi_p)
-    it->bidi_it.first_elt = 1;
+    {
+      it->bidi_it.first_elt = 1;
+      it->bidi_it.paragraph_dir = NEUTRAL_DIR;
+    }
 
   if (set_stop_p)
     {
@@ -5609,7 +5664,8 @@ reseat_1 (struct it *it, struct text_pos pos, int set_stop_p)
 
 static void
 reseat_to_string (struct it *it, const unsigned char *s, Lisp_Object string,
-                 int charpos, int precision, int field_width, int multibyte)
+                 EMACS_INT charpos, EMACS_INT precision, int field_width,
+                 int multibyte)
 {
   /* No region in strings.  */
   it->region_beg_charpos = it->region_end_charpos = -1;
@@ -5722,6 +5778,57 @@ static int (* get_next_element[NUM_IT_METHODS]) (struct it *it) =
                                 (IT)->string)))
 
 
+/* Lookup the char-table Vglyphless_char_display for character C (-1
+   if we want information for no-font case), and return the display
+   method symbol.  By side-effect, update it->what and
+   it->glyphless_method.  This function is called from
+   get_next_display_element for each character element, and from
+   x_produce_glyphs when no suitable font was found.  */
+
+Lisp_Object
+lookup_glyphless_char_display (int c, struct it *it)
+{
+  Lisp_Object glyphless_method = Qnil;
+
+  if (CHAR_TABLE_P (Vglyphless_char_display)
+      && CHAR_TABLE_EXTRA_SLOTS (XCHAR_TABLE (Vglyphless_char_display)) >= 1)
+    glyphless_method = (c >= 0
+                       ? CHAR_TABLE_REF (Vglyphless_char_display, c)
+                       : XCHAR_TABLE (Vglyphless_char_display)->extras[0]);
+ retry:
+  if (NILP (glyphless_method))
+    {
+      if (c >= 0)
+       /* The default is to display the character by a proper font.  */
+       return Qnil;
+      /* The default for the no-font case is to display an empty box.  */
+      glyphless_method = Qempty_box;
+    }
+  if (EQ (glyphless_method, Qzero_width))
+    {
+      if (c >= 0)
+       return glyphless_method;
+      /* This method can't be used for the no-font case.  */
+      glyphless_method = Qempty_box;
+    }
+  if (EQ (glyphless_method, Qthin_space))
+    it->glyphless_method = GLYPHLESS_DISPLAY_THIN_SPACE;
+  else if (EQ (glyphless_method, Qempty_box))
+    it->glyphless_method = GLYPHLESS_DISPLAY_EMPTY_BOX;
+  else if (EQ (glyphless_method, Qhex_code))
+    it->glyphless_method = GLYPHLESS_DISPLAY_HEX_CODE;
+  else if (STRINGP (glyphless_method))
+    it->glyphless_method = GLYPHLESS_DISPLAY_ACRONYM;
+  else
+    {
+      /* Invalid value.  We use the default method.  */
+      glyphless_method = Qnil;
+      goto retry;
+    }
+  it->what = IT_GLYPHLESS;
+  return glyphless_method;
+}
+
 /* 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.  */
@@ -5730,6 +5837,10 @@ static struct frame *last_escape_glyph_frame = NULL;
 static unsigned last_escape_glyph_face_id = (1 << FACE_ID_BITS);
 static int last_escape_glyph_merged_face_id = 0;
 
+struct frame *last_glyphless_glyph_frame = NULL;
+unsigned last_glyphless_glyph_face_id = (1 << FACE_ID_BITS);
+int last_glyphless_glyph_merged_face_id = 0;
+
 int
 get_next_display_element (struct it *it)
 {
@@ -5808,6 +5919,15 @@ get_next_display_element (struct it *it)
              goto get_next;
            }
 
+         if (! NILP (lookup_glyphless_char_display (c, it)))
+           {
+             if (it->what == IT_GLYPHLESS)
+               goto done;
+             /* Don't display this character.  */
+             set_iterator_to_next (it, 0);
+             goto get_next;
+           }
+
          if (! ASCII_CHAR_P (c) && ! NILP (Vnobreak_char_display))
            nbsp_or_shy = (c == 0xA0   ? char_is_nbsp
                           : c == 0xAD ? char_is_soft_hyphen
@@ -6012,9 +6132,9 @@ get_next_display_element (struct it *it)
        }
       else
        {
-         int pos = (it->s ? -1
-                    : STRINGP (it->string) ? IT_STRING_CHARPOS (*it)
-                    : IT_CHARPOS (*it));
+         EMACS_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->char_to_display, pos,
                                       it->string);
@@ -6022,6 +6142,7 @@ get_next_display_element (struct it *it)
     }
 #endif
 
+ done:
   /* 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
@@ -6447,7 +6568,6 @@ next_element_from_string (struct it *it)
        }
       else if (STRING_MULTIBYTE (it->string))
        {
-         int remaining = SBYTES (it->string) - IT_STRING_BYTEPOS (*it);
          const unsigned char *s = (SDATA (it->string)
                                    + IT_STRING_BYTEPOS (*it));
          it->c = string_char_and_length (s, &it->len);
@@ -6483,7 +6603,6 @@ next_element_from_string (struct it *it)
        }
       else if (STRING_MULTIBYTE (it->string))
        {
-         int maxlen = SBYTES (it->string) - IT_STRING_BYTEPOS (*it);
          const unsigned char *s = (SDATA (it->string)
                                    + IT_STRING_BYTEPOS (*it));
          it->c = string_char_and_length (s, &it->len);
@@ -6536,13 +6655,7 @@ next_element_from_c_string (struct it *it)
       BYTEPOS (it->position) = CHARPOS (it->position) = -1;
     }
   else if (it->multibyte_p)
-    {
-      /* Implementation note: The calls to strlen apparently aren't a
-        performance problem because there is no noticeable performance
-        difference between Emacs running in unibyte or multibyte mode.  */
-      int maxlen = strlen (it->s) - IT_BYTEPOS (*it);
-      it->c = string_char_and_length (it->s + IT_BYTEPOS (*it), &it->len);
-    }
+    it->c = string_char_and_length (it->s + IT_BYTEPOS (*it), &it->len);
   else
     it->c = it->s[IT_BYTEPOS (*it)], it->len = 1;
 
@@ -6677,12 +6790,12 @@ next_element_from_buffer (struct it *it)
        {
          /* If we are at the beginning of a line, we can produce the
             next element right away.  */
-         bidi_paragraph_init (it->paragraph_embedding, &it->bidi_it, 0);
+         bidi_paragraph_init (it->paragraph_embedding, &it->bidi_it, 1);
          bidi_move_to_visually_next (&it->bidi_it);
        }
       else
        {
-         int orig_bytepos = IT_BYTEPOS (*it);
+         EMACS_INT orig_bytepos = IT_BYTEPOS (*it);
 
          /* We need to prime the bidi iterator starting at the line's
             beginning, before we will be able to produce the next
@@ -6691,7 +6804,7 @@ next_element_from_buffer (struct it *it)
          IT_BYTEPOS (*it) = CHAR_TO_BYTE (IT_CHARPOS (*it));
          it->bidi_it.charpos = IT_CHARPOS (*it);
          it->bidi_it.bytepos = IT_BYTEPOS (*it);
-         bidi_paragraph_init (it->paragraph_embedding, &it->bidi_it, 0);
+         bidi_paragraph_init (it->paragraph_embedding, &it->bidi_it, 1);
          do
            {
              /* Now return to buffer position where we were asked to
@@ -7411,7 +7524,7 @@ move_it_in_display_line (struct it *it,
    TO_CHARPOS.  */
 
 void
-move_it_to (struct it *it, int to_charpos, int to_x, int to_y, int to_vpos, int op)
+move_it_to (struct it *it, EMACS_INT to_charpos, int to_x, int to_y, int to_vpos, int op)
 {
   enum move_it_result skip, skip2 = MOVE_X_REACHED;
   int line_height, line_start_x = 0, reached = 0;
@@ -7666,7 +7779,7 @@ move_it_vertically_backward (struct it *it, int dy)
 {
   int nlines, h;
   struct it it2, it3;
-  int start_pos;
+  EMACS_INT start_pos;
 
  move_further_back:
   xassert (dy >= 0);
@@ -7827,12 +7940,12 @@ move_it_past_eol (struct it *it)
 void
 move_it_by_lines (struct it *it, int dvpos, int need_y_p)
 {
-  struct position pos;
 
   /* The commented-out optimization uses vmotion on terminals.  This
      gives bad results, because elements like it->what, on which
      callers such as pos_visible_p rely, aren't updated. */
-  /*  if (!FRAME_WINDOW_P (it->f))
+  /* struct position pos;
+    if (!FRAME_WINDOW_P (it->f))
     {
       struct text_pos textpos;
 
@@ -7861,7 +7974,7 @@ move_it_by_lines (struct it *it, int dvpos, int need_y_p)
   else
     {
       struct it it2;
-      int start_charpos, i;
+      EMACS_INT start_charpos, i;
 
       /* Start at the beginning of the screen line containing IT's
         position.  This may actually move vertically backwards,
@@ -7941,7 +8054,7 @@ add_to_log (const char *format, Lisp_Object arg1, Lisp_Object arg2)
   Lisp_Object args[3];
   Lisp_Object msg, fmt;
   char *buffer;
-  int len;
+  EMACS_INT len;
   struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
   USE_SAFE_ALLOCA;
 
@@ -7990,7 +8103,7 @@ message_log_maybe_newline (void)
    so the buffer M must NOT point to a Lisp string.  */
 
 void
-message_dolog (const char *m, int nbytes, int nlflag, int multibyte)
+message_dolog (const char *m, EMACS_INT nbytes, int nlflag, int multibyte)
 {
   if (!NILP (Vmemory_full))
     return;
@@ -8000,8 +8113,8 @@ message_dolog (const char *m, int nbytes, int nlflag, int multibyte)
       struct buffer *oldbuf;
       Lisp_Object oldpoint, oldbegv, oldzv;
       int old_windows_or_buffers_changed = windows_or_buffers_changed;
-      int point_at_end = 0;
-      int zv_at_end = 0;
+      EMACS_INT point_at_end = 0;
+      EMACS_INT zv_at_end = 0;
       Lisp_Object old_deactivate_mark, tem;
       struct gcpro gcpro1;
 
@@ -8034,7 +8147,8 @@ message_dolog (const char *m, int nbytes, int nlflag, int multibyte)
       if (multibyte
          && NILP (current_buffer->enable_multibyte_characters))
        {
-         int i, c, char_bytes;
+         EMACS_INT i;
+         int c, char_bytes;
          unsigned char work[1];
 
          /* Convert a multibyte string to single-byte
@@ -8051,7 +8165,8 @@ message_dolog (const char *m, int nbytes, int nlflag, int multibyte)
       else if (! multibyte
               && ! NILP (current_buffer->enable_multibyte_characters))
        {
-         int i, c, char_bytes;
+         EMACS_INT i;
+         int c, char_bytes;
          unsigned char *msg = (unsigned char *) m;
          unsigned char str[MAX_MULTIBYTE_LENGTH];
          /* Convert a single-byte string to multibyte
@@ -8069,7 +8184,8 @@ message_dolog (const char *m, int nbytes, int nlflag, int multibyte)
 
       if (nlflag)
        {
-         int this_bol, this_bol_byte, prev_bol, prev_bol_byte, dup;
+         EMACS_INT this_bol, this_bol_byte, prev_bol, prev_bol_byte;
+         int dup;
          insert_1 ("\n", 1, 1, 0, 0);
 
          scan_newline (Z, Z_BYTE, BEG, BEG_BYTE, -2, 0);
@@ -8160,11 +8276,11 @@ message_dolog (const char *m, int nbytes, int nlflag, int multibyte)
    value N > 1 if we should also append " [N times]".  */
 
 static int
-message_log_check_duplicate (int prev_bol, int prev_bol_byte,
-                            int this_bol, int this_bol_byte)
+message_log_check_duplicate (EMACS_INT prev_bol, EMACS_INT prev_bol_byte,
+                            EMACS_INT this_bol, EMACS_INT this_bol_byte)
 {
-  int i;
-  int len = Z_BYTE - 1 - this_bol_byte;
+  EMACS_INT i;
+  EMACS_INT len = Z_BYTE - 1 - this_bol_byte;
   int seen_dots = 0;
   unsigned char *p1 = BUF_BYTE_ADDRESS (current_buffer, prev_bol_byte);
   unsigned char *p2 = BUF_BYTE_ADDRESS (current_buffer, this_bol_byte);
@@ -8199,7 +8315,7 @@ message_log_check_duplicate (int prev_bol, int prev_bol_byte,
    This may GC, so the buffer M must NOT point to a Lisp string.  */
 
 void
-message2 (const char *m, int nbytes, int multibyte)
+message2 (const char *m, EMACS_INT nbytes, int multibyte)
 {
   /* First flush out any partial line written with print.  */
   message_log_maybe_newline ();
@@ -8212,7 +8328,7 @@ message2 (const char *m, int nbytes, int multibyte)
 /* The non-logging counterpart of message2.  */
 
 void
-message2_nolog (const char *m, int nbytes, int multibyte)
+message2_nolog (const char *m, EMACS_INT nbytes, int multibyte)
 {
   struct frame *sf = SELECTED_FRAME ();
   message_enable_multibyte = multibyte;
@@ -8274,7 +8390,7 @@ message2_nolog (const char *m, int nbytes, int multibyte)
    This function cancels echoing.  */
 
 void
-message3 (Lisp_Object m, int nbytes, int multibyte)
+message3 (Lisp_Object m, EMACS_INT nbytes, int multibyte)
 {
   struct gcpro gcpro1;
 
@@ -8306,7 +8422,7 @@ message3 (Lisp_Object m, int nbytes, int multibyte)
    and make this cancel echoing.  */
 
 void
-message3_nolog (Lisp_Object m, int nbytes, int multibyte)
+message3_nolog (Lisp_Object m, EMACS_INT nbytes, int multibyte)
 {
   struct frame *sf = SELECTED_FRAME ();
   message_enable_multibyte = multibyte;
@@ -8492,7 +8608,7 @@ vmessage (const char *m, va_list ap)
        {
          if (m)
            {
-             int len;
+             EMACS_INT len;
 
              len = doprnt (FRAME_MESSAGE_BUF (f),
                            FRAME_MESSAGE_BUF_SIZE (f), m, (char *)0, ap);
@@ -9189,7 +9305,7 @@ check_message_stack (void)
    time we display it---but don't redisplay it now.  */
 
 void
-truncate_echo_area (int nchars)
+truncate_echo_area (EMACS_INT nchars)
 {
   if (nchars == 0)
     echo_area_buffer[0] = Qnil;
@@ -9236,7 +9352,8 @@ truncate_message_1 (EMACS_INT nchars, Lisp_Object a2, EMACS_INT a3, EMACS_INT a4
   */
 
 void
-set_message (const char *s, Lisp_Object string, int nbytes, int multibyte_p)
+set_message (const char *s, Lisp_Object string,
+            EMACS_INT nbytes, int multibyte_p)
 {
   message_enable_multibyte
     = ((s && multibyte_p)
@@ -9266,13 +9383,15 @@ set_message_1 (EMACS_INT a1, Lisp_Object a2, EMACS_INT nbytes, EMACS_INT multiby
     Fset_buffer_multibyte (message_enable_multibyte ? Qt : Qnil);
 
   current_buffer->truncate_lines = message_truncate_lines ? Qt : Qnil;
+  if (!NILP (current_buffer->bidi_display_reordering))
+    current_buffer->bidi_paragraph_direction = Qleft_to_right;
 
   /* Insert new message at BEG.  */
   TEMP_SET_PT_BOTH (BEG, BEG_BYTE);
 
   if (STRINGP (string))
     {
-      int nchars;
+      EMACS_INT nchars;
 
       if (nbytes == 0)
        nbytes = SBYTES (string);
@@ -9291,7 +9410,8 @@ set_message_1 (EMACS_INT a1, Lisp_Object a2, EMACS_INT nbytes, EMACS_INT multiby
       if (multibyte_p && NILP (current_buffer->enable_multibyte_characters))
        {
          /* Convert from multi-byte to single-byte.  */
-         int i, c, n;
+         EMACS_INT i;
+         int c, n;
          unsigned char work[1];
 
          /* Convert a multibyte string to single-byte.  */
@@ -9308,7 +9428,8 @@ set_message_1 (EMACS_INT a1, Lisp_Object a2, EMACS_INT nbytes, EMACS_INT multiby
               && !NILP (current_buffer->enable_multibyte_characters))
        {
          /* Convert from single-byte to multi-byte.  */
-         int i, c, n;
+         EMACS_INT i;
+         int c, n;
          const unsigned char *msg = (const unsigned char *) s;
          unsigned char str[MAX_MULTIBYTE_LENGTH];
 
@@ -9628,7 +9749,7 @@ static int
 store_mode_line_noprop (const unsigned char *str, int field_width, int precision)
 {
   int n = 0;
-  int dummy, nbytes;
+  EMACS_INT dummy, nbytes;
 
   /* Copy at most PRECISION chars from STR.  */
   nbytes = strlen (str);
@@ -10730,7 +10851,7 @@ static int
 get_tool_bar_item (struct frame *f, int x, int y, struct glyph **glyph,
                   int *hpos, int *vpos, int *prop_idx)
 {
-  Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
+  Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
   struct window *w = XWINDOW (f->tool_bar_window);
   int area;
 
@@ -10745,14 +10866,14 @@ get_tool_bar_item (struct frame *f, int x, int y, struct glyph **glyph,
     return -1;
 
   /* Is mouse on the highlighted item?  */
-  if (EQ (f->tool_bar_window, dpyinfo->mouse_face_window)
-      && *vpos >= dpyinfo->mouse_face_beg_row
-      && *vpos <= dpyinfo->mouse_face_end_row
-      && (*vpos > dpyinfo->mouse_face_beg_row
-         || *hpos >= dpyinfo->mouse_face_beg_col)
-      && (*vpos < dpyinfo->mouse_face_end_row
-         || *hpos < dpyinfo->mouse_face_end_col
-         || dpyinfo->mouse_face_past_end))
+  if (EQ (f->tool_bar_window, hlinfo->mouse_face_window)
+      && *vpos >= hlinfo->mouse_face_beg_row
+      && *vpos <= hlinfo->mouse_face_end_row
+      && (*vpos > hlinfo->mouse_face_beg_row
+         || *hpos >= hlinfo->mouse_face_beg_col)
+      && (*vpos < hlinfo->mouse_face_end_row
+         || *hpos < hlinfo->mouse_face_end_col
+         || hlinfo->mouse_face_past_end))
     return 0;
 
   return 1;
@@ -10769,7 +10890,7 @@ void
 handle_tool_bar_click (struct frame *f, int x, int y, int down_p,
                       unsigned int modifiers)
 {
-  Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
+  Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
   struct window *w = XWINDOW (f->tool_bar_window);
   int hpos, vpos, prop_idx;
   struct glyph *glyph;
@@ -10788,8 +10909,8 @@ handle_tool_bar_click (struct frame *f, int x, int y, int down_p,
   if (down_p)
     {
       /* Show item in pressed state.  */
-      show_mouse_face (dpyinfo, DRAW_IMAGE_SUNKEN);
-      dpyinfo->mouse_face_image_state = DRAW_IMAGE_SUNKEN;
+      show_mouse_face (hlinfo, DRAW_IMAGE_SUNKEN);
+      hlinfo->mouse_face_image_state = DRAW_IMAGE_SUNKEN;
       last_tool_bar_item = prop_idx;
     }
   else
@@ -10799,8 +10920,8 @@ handle_tool_bar_click (struct frame *f, int x, int y, int down_p,
       EVENT_INIT (event);
 
       /* Show item in released state.  */
-      show_mouse_face (dpyinfo, DRAW_IMAGE_RAISED);
-      dpyinfo->mouse_face_image_state = DRAW_IMAGE_RAISED;
+      show_mouse_face (hlinfo, DRAW_IMAGE_RAISED);
+      hlinfo->mouse_face_image_state = DRAW_IMAGE_RAISED;
 
       key = AREF (f->tool_bar_items, prop_idx + TOOL_BAR_ITEM_KEY);
 
@@ -10830,6 +10951,7 @@ note_tool_bar_highlight (struct frame *f, int x, int y)
   Lisp_Object window = f->tool_bar_window;
   struct window *w = XWINDOW (window);
   Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
+  Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
   int hpos, vpos;
   struct glyph *glyph;
   struct glyph_row *row;
@@ -10843,7 +10965,7 @@ note_tool_bar_highlight (struct frame *f, int x, int y)
      values when mouse moves outside of the frame.  */
   if (x <= 0 || y <= 0)
     {
-      clear_mouse_face (dpyinfo);
+      clear_mouse_face (hlinfo);
       return;
     }
 
@@ -10851,14 +10973,14 @@ note_tool_bar_highlight (struct frame *f, int x, int y)
   if (rc < 0)
     {
       /* Not on tool-bar item.  */
-      clear_mouse_face (dpyinfo);
+      clear_mouse_face (hlinfo);
       return;
     }
   else if (rc == 0)
     /* On same tool-bar item as before.  */
     goto set_help_echo;
 
-  clear_mouse_face (dpyinfo);
+  clear_mouse_face (hlinfo);
 
   /* Mouse is down, but on different tool-bar item?  */
   mouse_down_p = (dpyinfo->grabbed
@@ -10868,7 +10990,7 @@ note_tool_bar_highlight (struct frame *f, int x, int y)
       && last_tool_bar_item != prop_idx)
     return;
 
-  dpyinfo->mouse_face_image_state = DRAW_NORMAL_TEXT;
+  hlinfo->mouse_face_image_state = DRAW_NORMAL_TEXT;
   draw = mouse_down_p ? DRAW_IMAGE_SUNKEN : DRAW_IMAGE_RAISED;
 
   /* If tool-bar item is not enabled, don't highlight it.  */
@@ -10882,22 +11004,22 @@ note_tool_bar_highlight (struct frame *f, int x, int y)
        x += row->glyphs[TEXT_AREA][i].pixel_width;
 
       /* Record this as the current active region.  */
-      dpyinfo->mouse_face_beg_col = hpos;
-      dpyinfo->mouse_face_beg_row = vpos;
-      dpyinfo->mouse_face_beg_x = x;
-      dpyinfo->mouse_face_beg_y = row->y;
-      dpyinfo->mouse_face_past_end = 0;
-
-      dpyinfo->mouse_face_end_col = hpos + 1;
-      dpyinfo->mouse_face_end_row = vpos;
-      dpyinfo->mouse_face_end_x = x + glyph->pixel_width;
-      dpyinfo->mouse_face_end_y = row->y;
-      dpyinfo->mouse_face_window = window;
-      dpyinfo->mouse_face_face_id = TOOL_BAR_FACE_ID;
+      hlinfo->mouse_face_beg_col = hpos;
+      hlinfo->mouse_face_beg_row = vpos;
+      hlinfo->mouse_face_beg_x = x;
+      hlinfo->mouse_face_beg_y = row->y;
+      hlinfo->mouse_face_past_end = 0;
+
+      hlinfo->mouse_face_end_col = hpos + 1;
+      hlinfo->mouse_face_end_row = vpos;
+      hlinfo->mouse_face_end_x = x + glyph->pixel_width;
+      hlinfo->mouse_face_end_y = row->y;
+      hlinfo->mouse_face_window = window;
+      hlinfo->mouse_face_face_id = TOOL_BAR_FACE_ID;
 
       /* Display it as active.  */
-      show_mouse_face (dpyinfo, draw);
-      dpyinfo->mouse_face_image_state = draw;
+      show_mouse_face (hlinfo, draw);
+      hlinfo->mouse_face_image_state = draw;
     }
 
  set_help_echo:
@@ -10990,7 +11112,7 @@ hscroll_window_tree (Lisp_Object window)
              struct it it;
              int hscroll;
              struct buffer *saved_current_buffer;
-             int pt;
+             EMACS_INT pt;
              int wanted_x;
 
              /* Find point in a display of infinite width.  */
@@ -11103,7 +11225,7 @@ int debug_dvpos, debug_dy;
 
 /* Delta in characters and bytes for try_window_id.  */
 
-int debug_delta, debug_delta_bytes;
+EMACS_INT debug_delta, debug_delta_bytes;
 
 /* Values of window_end_pos and window_end_vpos at the end of
    try_window_id.  */
@@ -11155,7 +11277,8 @@ debug_method_add (w, fmt, a1, a2, a3, a4, a5, a6, a7, a8, a9)
    redisplay_internal for display optimization.  */
 
 static INLINE int
-text_outside_line_unchanged_p (struct window *w, int start, int end)
+text_outside_line_unchanged_p (struct window *w,
+                              EMACS_INT start, EMACS_INT end)
 {
   int unchanged_p = 1;
 
@@ -11378,8 +11501,8 @@ overlay_arrow_at_row (struct it *it, struct glyph_row *row)
    position.  BUF and PT are the current point buffer and position.  */
 
 int
-check_point_in_composition (struct buffer *prev_buf, int prev_pt,
-                           struct buffer *buf, int pt)
+check_point_in_composition (struct buffer *prev_buf, EMACS_INT prev_pt,
+                           struct buffer *buf, EMACS_INT pt)
 {
   EMACS_INT start, end;
   Lisp_Object prop;
@@ -11432,7 +11555,7 @@ reconsider_clip_changes (struct window *w, struct buffer *b)
   if (!b->clip_changed
       && BUFFERP (w->buffer) && !NILP (w->window_end_valid))
     {
-      int pt;
+      EMACS_INT pt;
 
       if (w == XWINDOW (selected_window))
        pt = BUF_PT (current_buffer);
@@ -11570,6 +11693,8 @@ redisplay_internal (int preserve_echo_area)
   reconsider_clip_changes (w, current_buffer);
   last_escape_glyph_frame = NULL;
   last_escape_glyph_face_id = (1 << FACE_ID_BITS);
+  last_glyphless_glyph_frame = NULL;
+  last_glyphless_glyph_face_id = (1 << FACE_ID_BITS);
 
   /* If new fonts have been loaded that make a glyph matrix adjustment
      necessary, do it.  */
@@ -11834,7 +11959,7 @@ redisplay_internal (int preserve_echo_area)
                {
                  struct glyph_row *row
                    = MATRIX_ROW (w->current_matrix, this_line_vpos + 1);
-                 int delta, delta_bytes;
+                 EMACS_INT delta, delta_bytes;
 
                  /* We used to distinguish between two cases here,
                     conditioned by Z - CHARPOS (tlendpos) == ZV, for
@@ -12463,14 +12588,15 @@ redisplay_window_1 (Lisp_Object window)
 
 int
 set_cursor_from_row (struct window *w, struct glyph_row *row,
-                    struct glyph_matrix *matrix, int delta, int delta_bytes,
+                    struct glyph_matrix *matrix,
+                    EMACS_INT delta, EMACS_INT delta_bytes,
                     int dy, int dvpos)
 {
   struct glyph *glyph = row->glyphs[TEXT_AREA];
   struct glyph *end = glyph + row->used[TEXT_AREA];
   struct glyph *cursor = NULL;
   /* The last known character position in row.  */
-  int last_pos = MATRIX_ROW_START_CHARPOS (row) + delta;
+  EMACS_INT last_pos = MATRIX_ROW_START_CHARPOS (row) + delta;
   int x = row->x;
   EMACS_INT pt_old = PT - delta;
   EMACS_INT pos_before = MATRIX_ROW_START_CHARPOS (row) + delta;
@@ -12485,8 +12611,10 @@ set_cursor_from_row (struct window *w, struct glyph_row *row,
   /* Non-zero means we've seen at least one glyph that came from a
      display string.  */
   int string_seen = 0;
-  /* Largest buffer position seen so far during scan of glyph row.  */
-  EMACS_INT bpos_max = last_pos;
+  /* Largest and smalles buffer positions seen so far during scan of
+     glyph row.  */
+  EMACS_INT bpos_max = pos_before;
+  EMACS_INT bpos_min = pos_after;
   /* Last buffer position covered by an overlay string with an integer
      `cursor' property.  */
   EMACS_INT bpos_covered = 0;
@@ -12576,6 +12704,8 @@ set_cursor_from_row (struct window *w, struct glyph_row *row,
 
            if (glyph->charpos > bpos_max)
              bpos_max = glyph->charpos;
+           if (glyph->charpos < bpos_min)
+             bpos_min = glyph->charpos;
            if (!glyph->avoid_cursor_p)
              {
                /* If we hit point, we've found the glyph on which to
@@ -12607,7 +12737,7 @@ set_cursor_from_row (struct window *w, struct glyph_row *row,
        else if (STRINGP (glyph->object))
          {
            Lisp_Object chprop;
-           int glyph_pos = glyph->charpos;
+           EMACS_INT glyph_pos = glyph->charpos;
 
            chprop = Fget_char_property (make_number (glyph_pos), Qcursor,
                                         glyph->object);
@@ -12650,6 +12780,8 @@ set_cursor_from_row (struct window *w, struct glyph_row *row,
 
            if (glyph->charpos > bpos_max)
              bpos_max = glyph->charpos;
+           if (glyph->charpos < bpos_min)
+             bpos_min = glyph->charpos;
            if (!glyph->avoid_cursor_p)
              {
                if (dpos == 0)
@@ -12674,7 +12806,7 @@ set_cursor_from_row (struct window *w, struct glyph_row *row,
        else if (STRINGP (glyph->object))
          {
            Lisp_Object chprop;
-           int glyph_pos = glyph->charpos;
+           EMACS_INT glyph_pos = glyph->charpos;
 
            chprop = Fget_char_property (make_number (glyph_pos), Qcursor,
                                         glyph->object);
@@ -12708,6 +12840,15 @@ set_cursor_from_row (struct window *w, struct glyph_row *row,
        && BUFFERP (glyph->object) && glyph->charpos == pt_old)
       && bpos_covered < pt_old)
     {
+      /* An empty line has a single glyph whose OBJECT is zero and
+        whose CHARPOS is the position of a newline on that line.
+        Note that on a TTY, there are more glyphs after that, which
+        were produced by extend_face_to_end_of_line, but their
+        CHARPOS is zero or negative.  */
+      int empty_line_p =
+       (row->reversed_p ? glyph > glyphs_end : glyph < glyphs_end)
+       && INTEGERP (glyph->object) && glyph->charpos > 0;
+
       if (row->ends_in_ellipsis_p && pos_after == last_pos)
        {
          EMACS_INT ellipsis_pos;
@@ -12736,11 +12877,18 @@ set_cursor_from_row (struct window *w, struct glyph_row *row,
            }
        }
       else if (match_with_avoid_cursor
-              /* zero-width characters produce no glyphs */
-              || ((row->reversed_p
-                   ? glyph_after > glyphs_end
-                   : glyph_after < glyphs_end)
-                  && eabs (glyph_after - glyph_before) == 1))
+              /* A truncated row may not include PT among its
+                 character positions.  Setting the cursor inside the
+                 scroll margin will trigger recalculation of hscroll
+                 in hscroll_window_tree.  */
+              || (row->truncated_on_left_p && pt_old < bpos_min)
+              || (row->truncated_on_right_p && pt_old > bpos_max)
+              /* Zero-width characters produce no glyphs.  */
+              || (!string_seen
+                  && !empty_line_p
+                  && (row->reversed_p
+                      ? glyph_after > glyphs_end
+                      : glyph_after < glyphs_end)))
        {
          cursor = glyph_after;
          x = -1;
@@ -12792,16 +12940,17 @@ set_cursor_from_row (struct window *w, struct glyph_row *row,
                             be a character in the string with the
                             `cursor' property, which means display
                             cursor on that character's glyph.  */
-                         int strpos = glyph->charpos;
+                         EMACS_INT strpos = glyph->charpos;
 
-                         cursor = glyph;
-                         for (glyph += incr;
+                         if (tem)
+                           cursor = glyph;
+                         for ( ;
                               (row->reversed_p ? glyph > stop : glyph < stop)
                                 && EQ (glyph->object, str);
                               glyph += incr)
                            {
                              Lisp_Object cprop;
-                             int gpos = glyph->charpos;
+                             EMACS_INT gpos = glyph->charpos;
 
                              cprop = Fget_char_property (make_number (gpos),
                                                          Qcursor,
@@ -12811,7 +12960,7 @@ set_cursor_from_row (struct window *w, struct glyph_row *row,
                                  cursor = glyph;
                                  break;
                                }
-                             if (glyph->charpos < strpos)
+                             if (tem && glyph->charpos < strpos)
                                {
                                  strpos = glyph->charpos;
                                  cursor = glyph;
@@ -12826,10 +12975,9 @@ set_cursor_from_row (struct window *w, struct glyph_row *row,
                    }
                  /* This string is not what we want; skip all of the
                     glyphs that came from it.  */
-                 do
-                   glyph += incr;
                  while ((row->reversed_p ? glyph > stop : glyph < stop)
-                        && EQ (glyph->object, str));
+                        && EQ (glyph->object, str))
+                   glyph += incr;
                }
              else
                glyph += incr;
@@ -13277,7 +13425,11 @@ try_scrolling (Lisp_Object window, int just_this_one_p,
 
       /* If cursor ends up on a partially visible line,
         treat that as being off the bottom of the screen.  */
-      if (! cursor_row_fully_visible_p (w, extra_scroll_margin_lines <= 1, 0))
+      if (! cursor_row_fully_visible_p (w, extra_scroll_margin_lines <= 1, 0)
+         /* It's possible that the cursor is on the first line of the
+            buffer, which is partially obscured due to a vscroll
+            (Bug#7537).  In that case, avoid looping forever . */
+         && extra_scroll_margin_lines < w->desired_matrix->nrows - 1)
        {
          clear_glyph_matrix (w->desired_matrix);
          ++extra_scroll_margin_lines;
@@ -13691,7 +13843,7 @@ try_cursor_movement (Lisp_Object window, struct text_pos startp, int *scroll_ste
 void
 set_vertical_scroll_bar (struct window *w)
 {
-  int start, end, whole;
+  EMACS_INT start, end, whole;
 
   /* Calculate the start and end positions for the current window.
      At some point, it would be nice to choose between scrollbars
@@ -13755,7 +13907,7 @@ redisplay_window (Lisp_Object window, int just_this_one_p)
   int rc;
   int centering_position = -1;
   int last_line_misfit = 0;
-  int beg_unchanged, end_unchanged;
+  EMACS_INT beg_unchanged, end_unchanged;
 
   SET_TEXT_POS (lpoint, PT, PT_BYTE);
   opoint = lpoint;
@@ -13897,8 +14049,8 @@ redisplay_window (Lisp_Object window, int just_this_one_p)
      window, set up appropriate value.  */
   if (!EQ (window, selected_window))
     {
-      int new_pt = XMARKER (w->pointm)->charpos;
-      int new_pt_byte = marker_byte_position (w->pointm);
+      EMACS_INT new_pt = XMARKER (w->pointm)->charpos;
+      EMACS_INT new_pt_byte = marker_byte_position (w->pointm);
       if (new_pt < BEGV)
        {
          new_pt = BEGV;
@@ -15056,7 +15208,7 @@ try_window_reusing_current_matrix (struct window *w)
 
 static struct glyph_row *find_last_unchanged_at_beg_row (struct window *);
 static struct glyph_row *find_first_unchanged_at_end_row (struct window *,
-                                                          int *, int *);
+                                                          EMACS_INT *, EMACS_INT *);
 static struct glyph_row *
 find_last_row_displaying_text (struct glyph_matrix *, struct it *,
                                struct glyph_row *);
@@ -15104,7 +15256,7 @@ find_last_row_displaying_text (struct glyph_matrix *matrix, struct it *it,
 static struct glyph_row *
 find_last_unchanged_at_beg_row (struct window *w)
 {
-  int first_changed_pos = BEG + BEG_UNCHANGED;
+  EMACS_INT first_changed_pos = BEG + BEG_UNCHANGED;
   struct glyph_row *row;
   struct glyph_row *row_found = NULL;
   int yb = window_text_bottom_y (w);
@@ -15151,7 +15303,8 @@ find_last_unchanged_at_beg_row (struct window *w)
    changes.  */
 
 static struct glyph_row *
-find_first_unchanged_at_end_row (struct window *w, int *delta, int *delta_bytes)
+find_first_unchanged_at_end_row (struct window *w,
+                                EMACS_INT *delta, EMACS_INT *delta_bytes)
 {
   struct glyph_row *row;
   struct glyph_row *row_found = NULL;
@@ -15179,9 +15332,11 @@ find_first_unchanged_at_end_row (struct window *w, int *delta, int *delta_bytes)
         corresponds to window_end_pos.  This allows us to translate
         buffer positions in the current matrix to current buffer
         positions for characters not in changed text.  */
-      int Z_old = MATRIX_ROW_END_CHARPOS (row) + XFASTINT (w->window_end_pos);
-      int Z_BYTE_old = MATRIX_ROW_END_BYTEPOS (row) + w->window_end_bytepos;
-      int last_unchanged_pos, last_unchanged_pos_old;
+      EMACS_INT Z_old =
+       MATRIX_ROW_END_CHARPOS (row) + XFASTINT (w->window_end_pos);
+      EMACS_INT Z_BYTE_old =
+       MATRIX_ROW_END_BYTEPOS (row) + w->window_end_bytepos;
+      EMACS_INT last_unchanged_pos, last_unchanged_pos_old;
       struct glyph_row *first_text_row
        = MATRIX_FIRST_TEXT_ROW (w->current_matrix);
 
@@ -15268,8 +15423,8 @@ sync_frame_with_window_matrix_rows (struct window *w)
    containing CHARPOS or null.  */
 
 struct glyph_row *
-row_containing_pos (struct window *w, int charpos, struct glyph_row *start,
-                   struct glyph_row *end, int dy)
+row_containing_pos (struct window *w, EMACS_INT charpos,
+                   struct glyph_row *start, struct glyph_row *end, int dy)
 {
   struct glyph_row *row = start;
   struct glyph_row *best_row = NULL;
@@ -15309,10 +15464,12 @@ row_containing_pos (struct window *w, int charpos, struct glyph_row *start,
        {
          struct glyph *g;
 
-         if (NILP (XBUFFER (w->buffer)->bidi_display_reordering))
+         if (NILP (XBUFFER (w->buffer)->bidi_display_reordering)
+             || (!best_row && !row->continued_p))
            return row;
          /* In bidi-reordered rows, there could be several rows
-            occluding point.  We need to find the one which fits
+            occluding point, all of them belonging to the same
+            continued line.  We need to find the row which fits
             CHARPOS the best.  */
          for (g = row->glyphs[TEXT_AREA];
               g < row->glyphs[TEXT_AREA] + row->used[TEXT_AREA];
@@ -15324,11 +15481,14 @@ row_containing_pos (struct window *w, int charpos, struct glyph_row *start,
                    {
                      mindif = eabs (g->charpos - charpos);
                      best_row = row;
+                     /* Exact match always wins.  */
+                     if (mindif == 0)
+                       return best_row;
                    }
                }
            }
        }
-      else if (best_row)
+      else if (best_row && !row->continued_p)
        return best_row;
       ++row;
     }
@@ -15382,13 +15542,14 @@ try_window_id (struct window *w)
   struct glyph_row *bottom_row;
   int bottom_vpos;
   struct it it;
-  int delta = 0, delta_bytes = 0, stop_pos, dvpos, dy;
+  EMACS_INT delta = 0, delta_bytes = 0, stop_pos;
+  int dvpos, dy;
   struct text_pos start_pos;
   struct run run;
   int first_unchanged_at_end_vpos = 0;
   struct glyph_row *last_text_row, *last_text_row_at_end;
   struct text_pos start;
-  int first_changed_charpos, last_changed_charpos;
+  EMACS_INT first_changed_charpos, last_changed_charpos;
 
 #if GLYPH_DEBUG
   if (inhibit_try_window_id)
@@ -15515,7 +15676,7 @@ try_window_id (struct window *w)
          || (last_changed_charpos < CHARPOS (start) - 1
              && FETCH_BYTE (BYTEPOS (start) - 1) == '\n')))
     {
-      int Z_old, delta, Z_BYTE_old, delta_bytes;
+      EMACS_INT Z_old, delta, Z_BYTE_old, delta_bytes;
       struct glyph_row *r0;
 
       /* Compute how many chars/bytes have been added to or removed
@@ -15872,6 +16033,9 @@ try_window_id (struct window *w)
                     + (WINDOW_WANTS_HEADER_LINE_P (w) ? 1 : 0)
                     + window_internal_height (w));
 
+#if defined (HAVE_GPM) || defined (MSDOS)
+         x_clear_window_mouse_face (w);
+#endif
          /* Perform the operation on the screen.  */
          if (dvpos > 0)
            {
@@ -16214,7 +16378,7 @@ dump_glyph (row, glyph, area)
       if (glyph->u.cmp.automatic)
        fprintf (stderr,
                 "[%d-%d]",
-                glyph->u.cmp.from, glyph->u.cmp.to);
+                glyph->slice.cmp.from, glyph->slice.cmp.to);
       fprintf (stderr, " . %4d %1.1d%1.1d\n",
               glyph->face_id,
               glyph->left_box_line_p,
@@ -16899,9 +17063,9 @@ extend_face_to_end_of_line (struct it *it)
    trailing whitespace.  */
 
 static int
-trailing_whitespace_p (int charpos)
+trailing_whitespace_p (EMACS_INT charpos)
 {
-  int bytepos = CHAR_TO_BYTE (charpos);
+  EMACS_INT bytepos = CHAR_TO_BYTE (charpos);
   int c = 0;
 
   while (bytepos < ZV_BYTE
@@ -18377,7 +18541,7 @@ display_mode_element (struct it *it, int depth, int field_width, int precision,
       {
        /* A string: output it and check for %-constructs within it.  */
        unsigned char c;
-       int offset = 0;
+       EMACS_INT offset = 0;
 
        if (SCHARS (elt) > 0
            && (!NILP (props) || risky))
@@ -18474,7 +18638,7 @@ display_mode_element (struct it *it, int depth, int field_width, int precision,
               && (mode_line_target != MODE_LINE_DISPLAY
                   || it->current_x < it->last_visible_x))
          {
-           int last_offset = offset;
+           EMACS_INT last_offset = offset;
 
            /* Advance to end of string or next format specifier.  */
            while ((c = SREF (elt, offset++)) != '\0' && c != '%')
@@ -18482,7 +18646,7 @@ display_mode_element (struct it *it, int depth, int field_width, int precision,
 
            if (offset - 1 != last_offset)
              {
-               int nchars, nbytes;
+               EMACS_INT nchars, nbytes;
 
                /* Output to end of string or up to '%'.  Field width
                   is length of string.  Don't output more than
@@ -18501,11 +18665,11 @@ display_mode_element (struct it *it, int depth, int field_width, int precision,
                    break;
                  case MODE_LINE_STRING:
                    {
-                     int bytepos = last_offset;
-                     int charpos = string_byte_to_char (elt, bytepos);
-                     int endpos = (precision <= 0
-                                   ? string_byte_to_char (elt, offset)
-                                   : charpos + nchars);
+                     EMACS_INT bytepos = last_offset;
+                     EMACS_INT charpos = string_byte_to_char (elt, bytepos);
+                     EMACS_INT endpos = (precision <= 0
+                                         ? string_byte_to_char (elt, offset)
+                                         : charpos + nchars);
 
                      n += store_mode_line_string (NULL,
                                                   Fsubstring (elt, make_number (charpos),
@@ -18515,8 +18679,8 @@ display_mode_element (struct it *it, int depth, int field_width, int precision,
                    break;
                  case MODE_LINE_DISPLAY:
                    {
-                     int bytepos = last_offset;
-                     int charpos = string_byte_to_char (elt, bytepos);
+                     EMACS_INT bytepos = last_offset;
+                     EMACS_INT charpos = string_byte_to_char (elt, bytepos);
 
                      if (precision <= 0)
                        nchars = string_byte_to_char (elt, offset) - charpos;
@@ -18529,7 +18693,7 @@ display_mode_element (struct it *it, int depth, int field_width, int precision,
              }
            else /* c == '%' */
              {
-               int percent_position = offset;
+               EMACS_INT percent_position = offset;
 
                /* Get the specified minimum width.  Zero means
                   don't pad.  */
@@ -18551,7 +18715,7 @@ display_mode_element (struct it *it, int depth, int field_width, int precision,
                else if (c != 0)
                  {
                    int multibyte;
-                   int bytepos, charpos;
+                   EMACS_INT bytepos, charpos;
                    const unsigned char *spec;
                    Lisp_Object string;
 
@@ -18825,7 +18989,7 @@ static int
 store_mode_line_string (const char *string, Lisp_Object lisp_string, int copy_string,
                        int field_width, int precision, Lisp_Object props)
 {
-  int len;
+  EMACS_INT len;
   int n = 0;
 
   if (string != NULL)
@@ -19370,22 +19534,23 @@ decode_mode_spec (struct window *w, register int c, int field_width,
 
     case 'i':
       {
-       int size = ZV - BEGV;
+       EMACS_INT size = ZV - BEGV;
        pint2str (decode_mode_spec_buf, field_width, size);
        return decode_mode_spec_buf;
       }
 
     case 'I':
       {
-       int size = ZV - BEGV;
+       EMACS_INT size = ZV - BEGV;
        pint2hrstr (decode_mode_spec_buf, field_width, size);
        return decode_mode_spec_buf;
       }
 
     case 'l':
       {
-       int startpos, startpos_byte, line, linepos, linepos_byte;
-       int topline, nlines, junk, height;
+       EMACS_INT startpos, startpos_byte, line, linepos, linepos_byte;
+       int topline, nlines, height;
+       EMACS_INT junk;
 
        /* %c and %l are ignored in `frame-title-format'.  */
        if (mode_line_target == MODE_LINE_TITLE)
@@ -19446,9 +19611,9 @@ decode_mode_spec (struct window *w, register int c, int field_width,
        else if (nlines < height + 25 || nlines > height * 3 + 50
                 || linepos == BUF_BEGV (b))
          {
-           int limit = BUF_BEGV (b);
-           int limit_byte = BUF_BEGV_BYTE (b);
-           int position;
+           EMACS_INT limit = BUF_BEGV (b);
+           EMACS_INT limit_byte = BUF_BEGV_BYTE (b);
+           EMACS_INT position;
            int distance = (height * 2 + 30) * line_number_display_limit_width;
 
            if (startpos - distance > limit)
@@ -19510,8 +19675,8 @@ decode_mode_spec (struct window *w, register int c, int field_width,
 
     case 'p':
       {
-       int pos = marker_position (w->start);
-       int total = BUF_ZV (b) - BUF_BEGV (b);
+       EMACS_INT pos = marker_position (w->start);
+       EMACS_INT total = BUF_ZV (b) - BUF_BEGV (b);
 
        if (XFASTINT (w->window_end_pos) <= BUF_Z (b) - BUF_ZV (b))
          {
@@ -19533,7 +19698,7 @@ decode_mode_spec (struct window *w, register int c, int field_width,
               so get us a 2-digit number that is close.  */
            if (total == 100)
              total = 99;
-           sprintf (decode_mode_spec_buf, "%2d%%", total);
+           sprintf (decode_mode_spec_buf, "%2ld%%", (long)total);
            return decode_mode_spec_buf;
          }
       }
@@ -19541,9 +19706,9 @@ decode_mode_spec (struct window *w, register int c, int field_width,
       /* Display percentage of size above the bottom of the screen.  */
     case 'P':
       {
-       int toppos = marker_position (w->start);
-       int botpos = BUF_Z (b) - XFASTINT (w->window_end_pos);
-       int total = BUF_ZV (b) - BUF_BEGV (b);
+       EMACS_INT toppos = marker_position (w->start);
+       EMACS_INT botpos = BUF_Z (b) - XFASTINT (w->window_end_pos);
+       EMACS_INT total = BUF_ZV (b) - BUF_BEGV (b);
 
        if (botpos >= BUF_ZV (b))
          {
@@ -19564,9 +19729,9 @@ decode_mode_spec (struct window *w, register int c, int field_width,
            if (total == 100)
              total = 99;
            if (toppos <= BUF_BEGV (b))
-             sprintf (decode_mode_spec_buf, "Top%2d%%", total);
+             sprintf (decode_mode_spec_buf, "Top%2ld%%", (long)total);
            else
-             sprintf (decode_mode_spec_buf, "%2d%%", total);
+             sprintf (decode_mode_spec_buf, "%2ld%%", (long)total);
            return decode_mode_spec_buf;
          }
       }
@@ -19657,8 +19822,9 @@ decode_mode_spec (struct window *w, register int c, int field_width,
    Set *BYTE_POS_PTR to 1 if we found COUNT lines, 0 if we hit LIMIT.  */
 
 static int
-display_count_lines (int start, int start_byte, int limit_byte, int count,
-                    int *byte_pos_ptr)
+display_count_lines (EMACS_INT start, EMACS_INT start_byte,
+                    EMACS_INT limit_byte, int count,
+                    EMACS_INT *byte_pos_ptr)
 {
   register unsigned char *cursor;
   unsigned char *base;
@@ -20600,8 +20766,8 @@ fill_gstring_glyph_string (struct glyph_string *s, int face_id,
   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->cmp_from = glyph->slice.cmp.from;
+  s->cmp_to = glyph->slice.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));
@@ -20609,8 +20775,8 @@ fill_gstring_glyph_string (struct glyph_string *s, int face_id,
   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;
+        && s->cmp_to == glyph->slice.cmp.from)
+    s->cmp_to = (glyph++)->slice.cmp.to + 1;
 
   for (i = s->cmp_from; i < s->cmp_to; i++)
     {
@@ -20624,6 +20790,42 @@ fill_gstring_glyph_string (struct glyph_string *s, int face_id,
 }
 
 
+/* Fill glyph string S from a sequence glyphs for glyphless characters.
+   See the comment of fill_glyph_string for arguments.
+   Value is the index of the first glyph not in S.  */
+
+
+static int
+fill_glyphless_glyph_string (struct glyph_string *s, int face_id,
+                            int start, int end, int overlaps)
+{
+  struct glyph *glyph, *last;
+  int voffset;
+
+  xassert (s->first_glyph->type == GLYPHLESS_GLYPH);
+  s->for_overlaps = overlaps;
+  glyph = s->row->glyphs[s->area] + start;
+  last = s->row->glyphs[s->area] + end;
+  voffset = glyph->voffset;
+  s->face = FACE_FROM_ID (s->f, face_id);
+  s->font = s->face->font;
+  s->nchars = 1;
+  s->width = glyph->pixel_width;
+  glyph++;
+  while (glyph < last
+        && glyph->type == GLYPHLESS_GLYPH
+        && glyph->voffset == voffset
+        && glyph->face_id == face_id)
+    {
+      s->nchars++;
+      s->width += glyph->pixel_width;
+      glyph++;
+    }
+  s->ybase += voffset;
+  return glyph - s->row->glyphs[s->area];
+}
+
+
 /* Fill glyph string S from a sequence of character glyphs.
 
    FACE_ID is the face id of the string.  START is the index of the
@@ -20700,7 +20902,7 @@ fill_image_glyph_string (struct glyph_string *s)
   xassert (s->first_glyph->type == IMAGE_GLYPH);
   s->img = IMAGE_FROM_ID (s->f, s->first_glyph->u.img_id);
   xassert (s->img);
-  s->slice = s->first_glyph->slice;
+  s->slice = s->first_glyph->slice.img;
   s->face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
   s->font = s->face->font;
   s->width = s->first_glyph->pixel_width;
@@ -20806,8 +21008,8 @@ x_get_glyph_overhangs (struct glyph *glyph, struct frame *f, int *left, int *rig
          Lisp_Object gstring = composition_gstring_from_id (glyph->u.cmp.id);
          struct font_metrics metrics;
 
-         composition_gstring_width (gstring, glyph->u.cmp.from,
-                                    glyph->u.cmp.to + 1, &metrics);
+         composition_gstring_width (gstring, glyph->slice.cmp.from,
+                                    glyph->slice.cmp.to + 1, &metrics);
          if (metrics.rbearing > metrics.width)
            *right = metrics.rbearing - metrics.width;
          if (metrics.lbearing < 0)
@@ -21134,6 +21336,28 @@ compute_overhangs_and_x (struct glyph_string *s, int x, int backward_p)
   } while (0)
 
 
+/* Add a glyph string for a sequence of glyphless character's glyphs
+   to the list of strings between HEAD and TAIL.  The meanings of
+   arguments are the same as those of BUILD_CHAR_GLYPH_STRINGS.  */
+
+#define BUILD_GLYPHLESS_GLYPH_STRING(START, END, HEAD, TAIL, HL, X, LAST_X) \
+  do                                                                       \
+    {                                                                      \
+      int face_id;                                                         \
+      XChar2b *char2b;                                                     \
+                                                                           \
+      face_id = (row)->glyphs[area][START].face_id;                        \
+                                                                           \
+      s = (struct glyph_string *) alloca (sizeof *s);                      \
+      INIT_GLYPH_STRING (s, NULL, w, row, area, START, HL);                \
+      append_glyph_string (&HEAD, &TAIL, s);                               \
+      s->x = (X);                                                          \
+      START = fill_glyphless_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
@@ -21157,7 +21381,7 @@ compute_overhangs_and_x (struct glyph_string *s, int x, int backward_p)
              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,     \
@@ -21166,21 +21390,26 @@ compute_overhangs_and_x (struct glyph_string *s, int x, int backward_p)
                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;                                                    \
-                                                                       \
+                                                                       \
+           case GLYPHLESS_GLYPH:                                       \
+             BUILD_GLYPHLESS_GLYPH_STRING (START, END, HEAD, TAIL,     \
+                                           HL, X, LAST_X);             \
+             break;                                                    \
+                                                                       \
            default:                                                    \
              abort ();                                                 \
            }                                                           \
-                                                                       \
+                                                                       \
          if (s)                                                        \
            {                                                           \
              set_glyph_string_background_width (s, START, LAST_X);     \
@@ -21264,7 +21493,7 @@ draw_glyphs (struct window *w, int x, struct glyph_row *row,
   if (head && !overlaps && row->contains_overlapping_glyphs_p)
     {
       struct glyph_string *h, *t;
-      Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
+      Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
       int mouse_beg_col, mouse_end_col, check_mouse_face = 0;
       int dummy_x = 0;
 
@@ -21274,16 +21503,16 @@ draw_glyphs (struct window *w, int x, struct glyph_row *row,
        {
          struct glyph_row *mouse_beg_row, *mouse_end_row;
 
-         mouse_beg_row = MATRIX_ROW (w->current_matrix, dpyinfo->mouse_face_beg_row);
-         mouse_end_row = MATRIX_ROW (w->current_matrix, dpyinfo->mouse_face_end_row);
+         mouse_beg_row = MATRIX_ROW (w->current_matrix, hlinfo->mouse_face_beg_row);
+         mouse_end_row = MATRIX_ROW (w->current_matrix, hlinfo->mouse_face_end_row);
 
          if (row >= mouse_beg_row && row <= mouse_end_row)
            {
              check_mouse_face = 1;
              mouse_beg_col = (row == mouse_beg_row)
-               ? dpyinfo->mouse_face_beg_col : 0;
+               ? hlinfo->mouse_face_beg_col : 0;
              mouse_end_col = (row == mouse_end_row)
-               ? dpyinfo->mouse_face_end_col
+               ? hlinfo->mouse_face_end_col
                : row->used[TEXT_AREA];
            }
        }
@@ -21512,7 +21741,7 @@ append_glyph (struct it *it)
       glyph->glyph_not_available_p = it->glyph_not_available_p;
       glyph->face_id = it->face_id;
       glyph->u.ch = it->char_to_display;
-      glyph->slice = null_glyph_slice;
+      glyph->slice.img = null_glyph_slice;
       glyph->font_type = FONT_TYPE_UNKNOWN;
       if (it->bidi_p)
        {
@@ -21569,13 +21798,14 @@ append_composite_glyph (struct it *it)
        {
          glyph->u.cmp.automatic = 0;
          glyph->u.cmp.id = it->cmp_it.id;
+         glyph->slice.cmp.from = glyph->slice.cmp.to = 0;
        }
       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->slice.cmp.from = it->cmp_it.from;
+         glyph->slice.cmp.to = it->cmp_it.to - 1;
        }
       glyph->avoid_cursor_p = it->avoid_cursor_p;
       glyph->multibyte_p = it->multibyte_p;
@@ -21586,7 +21816,6 @@ append_composite_glyph (struct it *it)
       glyph->padding_p = 0;
       glyph->glyph_not_available_p = 0;
       glyph->face_id = it->face_id;
-      glyph->slice = null_glyph_slice;
       glyph->font_type = FONT_TYPE_UNKNOWN;
       if (it->bidi_p)
        {
@@ -21765,7 +21994,7 @@ produce_image_glyph (struct it *it)
          glyph->glyph_not_available_p = 0;
          glyph->face_id = it->face_id;
          glyph->u.img_id = img->id;
-         glyph->slice = slice;
+         glyph->slice.img = slice;
          glyph->font_type = FONT_TYPE_UNKNOWN;
          if (it->bidi_p)
            {
@@ -21826,7 +22055,7 @@ append_stretch_glyph (struct it *it, Lisp_Object object,
       glyph->face_id = it->face_id;
       glyph->u.stretch.ascent = ascent;
       glyph->u.stretch.height = height;
-      glyph->slice = null_glyph_slice;
+      glyph->slice.img = null_glyph_slice;
       glyph->font_type = FONT_TYPE_UNKNOWN;
       if (it->bidi_p)
        {
@@ -21915,11 +22144,7 @@ produce_stretch_glyph (struct it *it)
 
       it2 = *it;
       if (it->multibyte_p)
-       {
-         int maxlen = ((IT_BYTEPOS (*it) >= GPT ? ZV : GPT)
-                       - IT_BYTEPOS (*it));
-         it2.c = it2.char_to_display = STRING_CHAR_AND_LENGTH (p, it2.len);
-       }
+       it2.c = it2.char_to_display = STRING_CHAR_AND_LENGTH (p, it2.len);
       else
        {
          it2.c = it2.char_to_display = *p, it2.len = 1;
@@ -22080,6 +22305,229 @@ calc_line_height_property (struct it *it, Lisp_Object val, struct font *font,
 }
 
 
+/* Append a glyph for a glyphless character to IT->glyph_row.  FACE_ID
+   is a face ID to be used for the glyph.  FOR_NO_FONT is nonzero if
+   and only if this is for a character for which no font was found.
+
+   If the display method (it->glyphless_method) is
+   GLYPHLESS_DISPLAY_ACRONYM or GLYPHLESS_DISPLAY_HEX_CODE, LEN is a
+   length of the acronym or the hexadecimal string, UPPER_XOFF and
+   UPPER_YOFF are pixel offsets for the upper part of the string,
+   LOWER_XOFF and LOWER_YOFF are for the lower part.
+
+   For the other display methods, LEN through LOWER_YOFF are zero.  */
+
+static void
+append_glyphless_glyph (struct it *it, int face_id, int for_no_font, int len,
+                       short upper_xoff, short upper_yoff,
+                       short lower_xoff, short lower_yoff)
+{
+  struct glyph *glyph;
+  enum glyph_row_area area = it->area;
+
+  glyph = it->glyph_row->glyphs[area] + it->glyph_row->used[area];
+  if (glyph < it->glyph_row->glyphs[area + 1])
+    {
+      /* If the glyph row is reversed, we need to prepend the glyph
+        rather than append it.  */
+      if (it->glyph_row->reversed_p && area == TEXT_AREA)
+       {
+         struct glyph *g;
+
+         /* Make room for the additional glyph.  */
+         for (g = glyph - 1; g >= it->glyph_row->glyphs[area]; g--)
+           g[1] = *g;
+         glyph = it->glyph_row->glyphs[area];
+       }
+      glyph->charpos = CHARPOS (it->position);
+      glyph->object = it->object;
+      glyph->pixel_width = it->pixel_width;
+      glyph->ascent = it->ascent;
+      glyph->descent = it->descent;
+      glyph->voffset = it->voffset;
+      glyph->type = GLYPHLESS_GLYPH;
+      glyph->u.glyphless.method = it->glyphless_method;
+      glyph->u.glyphless.for_no_font = for_no_font;
+      glyph->u.glyphless.len = len;
+      glyph->u.glyphless.ch = it->c;
+      glyph->slice.glyphless.upper_xoff = upper_xoff;
+      glyph->slice.glyphless.upper_yoff = upper_yoff;
+      glyph->slice.glyphless.lower_xoff = lower_xoff;
+      glyph->slice.glyphless.lower_yoff = lower_yoff;
+      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->right_box_line_p = it->end_of_box_run_p;
+      glyph->overlaps_vertically_p = (it->phys_ascent > it->ascent
+                                     || it->phys_descent > it->descent);
+      glyph->padding_p = 0;
+      glyph->glyph_not_available_p = 0;
+      glyph->face_id = face_id;
+      glyph->font_type = FONT_TYPE_UNKNOWN;
+      if (it->bidi_p)
+       {
+         glyph->resolved_level = it->bidi_it.resolved_level;
+         if ((it->bidi_it.type & 7) != it->bidi_it.type)
+           abort ();
+         glyph->bidi_type = it->bidi_it.type;
+       }
+      ++it->glyph_row->used[area];
+    }
+  else
+    IT_EXPAND_MATRIX_WIDTH (it, area);
+}
+
+
+/* Produce a glyph for a glyphless character for iterator IT.
+   IT->glyphless_method specifies which method to use for displaying
+   the character.  See the description of enum
+   glyphless_display_method in dispextern.h for the detail.
+
+   FOR_NO_FONT is nonzero if and only if this is for a character for
+   which no font was found.  ACRONYM, if non-nil, is an acronym string
+   for the character.  */
+
+static void
+produce_glyphless_glyph (struct it *it, int for_no_font, Lisp_Object acronym)
+{
+  int face_id;
+  struct face *face;
+  struct font *font;
+  int base_width, base_height, width, height;
+  short upper_xoff, upper_yoff, lower_xoff, lower_yoff;
+  int len;
+
+  /* Get the metrics of the base font.  We always refer to the current
+     ASCII face.  */
+  face = FACE_FROM_ID (it->f, it->face_id)->ascii_face;
+  font = face->font ? face->font : FRAME_FONT (it->f);
+  it->ascent = FONT_BASE (font) + font->baseline_offset;
+  it->descent = FONT_DESCENT (font) - font->baseline_offset;
+  base_height = it->ascent + it->descent;
+  base_width = font->average_width;
+
+  /* Get a face ID for the glyph by utilizing a cache (the same way as
+     doen for `escape-glyph' in get_next_display_element).  */
+  if (it->f == last_glyphless_glyph_frame
+      && it->face_id == last_glyphless_glyph_face_id)
+    {
+      face_id = last_glyphless_glyph_merged_face_id;
+    }
+  else
+    {
+      /* Merge the `glyphless-char' face into the current face.  */
+      face_id = merge_faces (it->f, Qglyphless_char, 0, it->face_id);
+      last_glyphless_glyph_frame = it->f;
+      last_glyphless_glyph_face_id = it->face_id;
+      last_glyphless_glyph_merged_face_id = face_id;
+    }
+
+  if (it->glyphless_method == GLYPHLESS_DISPLAY_THIN_SPACE)
+    {
+      it->pixel_width = THIN_SPACE_WIDTH;
+      len = 0;
+      upper_xoff = upper_yoff = lower_xoff = lower_yoff = 0;
+    }
+  else if (it->glyphless_method == GLYPHLESS_DISPLAY_EMPTY_BOX)
+    {
+      width = CHAR_WIDTH (it->c);
+      if (width == 0)
+       width = 1;
+      else if (width > 4)
+       width = 4;
+      it->pixel_width = base_width * width;
+      len = 0;
+      upper_xoff = upper_yoff = lower_xoff = lower_yoff = 0;
+    }
+  else
+    {
+      char buf[7], *str;
+      unsigned int code[6];
+      int upper_len;
+      int ascent, descent;
+      struct font_metrics metrics_upper, metrics_lower;
+
+      face = FACE_FROM_ID (it->f, face_id);
+      font = face->font ? face->font : FRAME_FONT (it->f);
+      PREPARE_FACE_FOR_DISPLAY (it->f, face);
+
+      if (it->glyphless_method == GLYPHLESS_DISPLAY_ACRONYM)
+       {
+         if (! STRINGP (acronym) && CHAR_TABLE_P (Vglyphless_char_display))
+           acronym = CHAR_TABLE_REF (Vglyphless_char_display, it->c);
+         str = STRINGP (acronym) ? (char *) SDATA (acronym) : "";
+       }
+      else
+       {
+         xassert (it->glyphless_method == GLYPHLESS_DISPLAY_HEX_CODE);
+         sprintf (buf, "%0*X", it->c < 0x10000 ? 4 : 6, it->c);
+         str = buf;
+       }
+      for (len = 0; str[len] && ASCII_BYTE_P (str[len]); len++)
+       code[len] = font->driver->encode_char (font, str[len]);
+      upper_len = (len + 1) / 2;
+      font->driver->text_extents (font, code, upper_len,
+                                 &metrics_upper);
+      font->driver->text_extents (font, code + upper_len, len - upper_len,
+                                 &metrics_lower);
+
+
+
+      /* +4 is for vertical bars of a box plus 1-pixel spaces at both side.  */
+      width = max (metrics_upper.width, metrics_lower.width) + 4;
+      upper_xoff = upper_yoff = 2; /* the typical case */
+      if (base_width >= width)
+       {
+         /* Align the upper to the left, the lower to the right.  */
+         it->pixel_width = base_width;
+         lower_xoff = base_width - 2 - metrics_lower.width;
+       }
+      else
+       {
+         /* Center the shorter one.  */
+         it->pixel_width = width;
+         if (metrics_upper.width >= metrics_lower.width)
+           lower_xoff = (width - metrics_lower.width) / 2;
+         else
+           upper_xoff = (width - metrics_upper.width) / 2;
+       }
+  
+      /* +5 is for horizontal bars of a box plus 1-pixel spaces at
+        top, bottom, and between upper and lower strings.  */
+      height = (metrics_upper.ascent + metrics_upper.descent
+               + metrics_lower.ascent + metrics_lower.descent) + 5;
+      /* Center vertically.
+        H:base_height, D:base_descent
+        h:height, ld:lower_descent, la:lower_ascent, ud:upper_descent
+
+        ascent = - (D - H/2 - h/2 + 1); "+ 1" for rounding up
+        descent = D - H/2 + h/2;
+        lower_yoff = descent - 2 - ld;
+        upper_yoff = lower_yoff - la - 1 - ud;  */
+      ascent = - (it->descent - (base_height + height + 1) / 2);
+      descent = it->descent - (base_height - height) / 2;
+      lower_yoff = descent - 2 - metrics_lower.descent;
+      upper_yoff = (lower_yoff - metrics_lower.ascent - 1
+                   - metrics_upper.descent);
+      /* Don't make the height shorter than the base height. */
+      if (height > base_height)
+       {
+         it->ascent = ascent;
+         it->descent = descent;
+       }
+    }
+
+  it->phys_ascent = it->ascent;
+  it->phys_descent = it->descent;
+  if (it->glyph_row)
+    append_glyphless_glyph (it, face_id, for_no_font, len,
+                           upper_xoff, upper_yoff,
+                           lower_xoff, lower_yoff);
+  it->nglyphs = 1;
+  take_vertical_position_into_account (it);
+}
+
+
 /* RIF:
    Produce glyphs/get display metrics for the display element IT is
    loaded with.  See the description of struct it in dispextern.h
@@ -22097,29 +22545,25 @@ x_produce_glyphs (struct it *it)
       XChar2b char2b;
       struct face *face = FACE_FROM_ID (it->f, it->face_id);
       struct font *font = face->font;
-      int font_not_found_p = font == NULL;
       struct font_metrics *pcm = NULL;
       int boff;                        /* baseline offset */
 
-      if (font_not_found_p)
-       {
-         /* When no suitable font found, display an empty box based
-            on the metrics of the font of the default face (or what
-            remapped).  */
-         struct face *no_font_face
-           = FACE_FROM_ID (it->f,
-                           NILP (Vface_remapping_alist) ? DEFAULT_FACE_ID
-                           : lookup_basic_face (it->f, DEFAULT_FACE_ID));
-         font = no_font_face->font;
-         boff = font->baseline_offset;
-       }
-      else
+      if (font == NULL)
        {
-         boff = font->baseline_offset;
-         if (font->vertical_centering)
-           boff = VCENTER_BASELINE_OFFSET (font, it->f) - boff;
+         /* When no suitable font is found, display this character by
+            the method specified in the first extra slot of
+            Vglyphless_char_display.  */
+         Lisp_Object acronym = lookup_glyphless_char_display (-1, it);
+
+         xassert (it->what == IT_GLYPHLESS);
+         produce_glyphless_glyph (it, 1, STRINGP (acronym) ? acronym : Qnil);
+         goto done;
        }
 
+      boff = font->baseline_offset;
+      if (font->vertical_centering)
+       boff = VCENTER_BASELINE_OFFSET (font, it->f) - boff;
+
       if (it->char_to_display != '\n' && it->char_to_display != '\t')
        {
          int stretched_p;
@@ -22138,8 +22582,7 @@ x_produce_glyphs (struct it *it)
              it->descent = FONT_DESCENT (font) - boff;
            }
 
-         if (! font_not_found_p
-             && get_char_glyph_code (it->char_to_display, font, &char2b))
+         if (get_char_glyph_code (it->char_to_display, font, &char2b))
            {
              pcm = get_per_char_metric (it->f, font, &char2b);
              if (pcm->width == 0
@@ -22405,7 +22848,7 @@ x_produce_glyphs (struct it *it)
          XChar2b char2b;
          struct font_metrics *pcm;
          int font_not_found_p;
-         int pos;
+         EMACS_INT pos;
 
          for (glyph_len = cmp->glyph_len; glyph_len > 0; glyph_len--)
            if ((c = COMPOSITION_GLYPH (cmp, glyph_len - 1)) != '\t')
@@ -22729,11 +23172,14 @@ x_produce_glyphs (struct it *it)
       if (it->glyph_row)
        append_composite_glyph (it);
     }
+  else if (it->what == IT_GLYPHLESS)
+    produce_glyphless_glyph (it, 0, Qnil);
   else if (it->what == IT_IMAGE)
     produce_image_glyph (it);
   else if (it->what == IT_STRETCH)
     produce_stretch_glyph (it);
 
+ done:
   /* Accumulate dimensions.  Note: can't assume that it->descent > 0
      because this isn't true for images with `:ascent 100'.  */
   xassert (it->ascent >= 0 && it->descent >= 0);
@@ -23005,6 +23451,8 @@ set_frame_cursor_types (struct frame *f, Lisp_Object arg)
 }
 
 
+#ifdef HAVE_WINDOW_SYSTEM
+
 /* Return the cursor we want to be displayed in window W.  Return
    width of bar/hbar cursor through WIDTH arg.  Return with
    ACTIVE_CURSOR arg set to 1 if cursor in window W is `active'
@@ -23050,10 +23498,7 @@ get_window_cursor_type (struct window *w, struct glyph *glyph, int *width,
 
   /* Detect a nonselected window or nonselected frame.  */
   else if (w != XWINDOW (f->selected_window)
-#ifdef HAVE_WINDOW_SYSTEM
-          || f != FRAME_X_DISPLAY_INFO (f)->x_highlight_frame
-#endif
-          )
+          || f != FRAME_X_DISPLAY_INFO (f)->x_highlight_frame)
     {
       *active_cursor = 0;
 
@@ -23094,7 +23539,6 @@ get_window_cursor_type (struct window *w, struct glyph *glyph, int *width,
   /* Use normal cursor if not blinked off.  */
   if (!w->cursor_off_p)
     {
-#ifdef HAVE_WINDOW_SYSTEM
       if (glyph != NULL && glyph->type == IMAGE_GLYPH)
        {
          if (cursor_type == FILLED_BOX_CURSOR)
@@ -23122,7 +23566,6 @@ get_window_cursor_type (struct window *w, struct glyph *glyph, int *width,
              cursor_type = HOLLOW_BOX_CURSOR;
            }
       }
-#endif
       return cursor_type;
     }
 
@@ -23164,8 +23607,6 @@ get_window_cursor_type (struct window *w, struct glyph *glyph, int *width,
 }
 
 
-#ifdef HAVE_WINDOW_SYSTEM
-
 /* Notice when the text cursor of window W has been completely
    overwritten by a drawing operation that outputs glyphs in AREA
    starting at X0 and ending at X1 in the line starting at Y0 and
@@ -23331,7 +23772,7 @@ void
 erase_phys_cursor (struct window *w)
 {
   struct frame *f = XFRAME (w->frame);
-  Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
+  Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
   int hpos = w->phys_cursor.hpos;
   int vpos = w->phys_cursor.vpos;
   int mouse_face_here_p = 0;
@@ -23387,14 +23828,8 @@ erase_phys_cursor (struct window *w)
 
   /* If the cursor is in the mouse face area, redisplay that when
      we clear the cursor.  */
-  if (! NILP (dpyinfo->mouse_face_window)
-      && w == XWINDOW (dpyinfo->mouse_face_window)
-      && (vpos > dpyinfo->mouse_face_beg_row
-         || (vpos == dpyinfo->mouse_face_beg_row
-             && hpos >= dpyinfo->mouse_face_beg_col))
-      && (vpos < dpyinfo->mouse_face_end_row
-         || (vpos == dpyinfo->mouse_face_end_row
-             && hpos < dpyinfo->mouse_face_end_col))
+  if (! NILP (hlinfo->mouse_face_window)
+      && coords_in_mouse_face_p (w, hpos, vpos)
       /* Don't redraw the cursor's spot in mouse face if it is at the
         end of a line (on a newline).  The cursor appears there, but
         mouse highlighting does not.  */
@@ -23585,30 +24020,50 @@ x_clear_cursor (struct window *w)
     update_window_cursor (w, 0);
 }
 
+#endif /* HAVE_WINDOW_SYSTEM */
+
+/* Implementation of draw_row_with_mouse_face for GUI sessions, GPM,
+   and MSDOS.  */
+void
+draw_row_with_mouse_face (struct window *w, int start_x, struct glyph_row *row,
+                         int start_hpos, int end_hpos,
+                         enum draw_glyphs_face draw)
+{
+#ifdef HAVE_WINDOW_SYSTEM
+  if (FRAME_WINDOW_P (XFRAME (w->frame)))
+    {
+      draw_glyphs (w, start_x, row, TEXT_AREA, start_hpos, end_hpos, draw, 0);
+      return;
+    }
+#endif
+#if defined (HAVE_GPM) || defined (MSDOS)
+  tty_draw_row_with_mouse_face (w, row, start_hpos, end_hpos, draw);
+#endif
+}
 
 /* EXPORT:
    Display the active region described by mouse_face_* according to DRAW.  */
 
 void
-show_mouse_face (Display_Info *dpyinfo, enum draw_glyphs_face draw)
+show_mouse_face (Mouse_HLInfo *hlinfo, enum draw_glyphs_face draw)
 {
-  struct window *w = XWINDOW (dpyinfo->mouse_face_window);
+  struct window *w = XWINDOW (hlinfo->mouse_face_window);
   struct frame *f = XFRAME (WINDOW_FRAME (w));
 
   if (/* If window is in the process of being destroyed, don't bother
         to do anything.  */
       w->current_matrix != NULL
       /* Don't update mouse highlight if hidden */
-      && (draw != DRAW_MOUSE_FACE || !dpyinfo->mouse_face_hidden)
+      && (draw != DRAW_MOUSE_FACE || !hlinfo->mouse_face_hidden)
       /* Recognize when we are called to operate on rows that don't exist
         anymore.  This can happen when a window is split.  */
-      && dpyinfo->mouse_face_end_row < w->current_matrix->nrows)
+      && hlinfo->mouse_face_end_row < w->current_matrix->nrows)
     {
       int phys_cursor_on_p = w->phys_cursor_on_p;
       struct glyph_row *row, *first, *last;
 
-      first = MATRIX_ROW (w->current_matrix, dpyinfo->mouse_face_beg_row);
-      last = MATRIX_ROW (w->current_matrix, dpyinfo->mouse_face_end_row);
+      first = MATRIX_ROW (w->current_matrix, hlinfo->mouse_face_beg_row);
+      last = MATRIX_ROW (w->current_matrix, hlinfo->mouse_face_end_row);
 
       for (row = first; row <= last && row->enabled_p; ++row)
        {
@@ -23617,8 +24072,30 @@ show_mouse_face (Display_Info *dpyinfo, enum draw_glyphs_face draw)
          /* For all but the first row, the highlight starts at column 0.  */
          if (row == first)
            {
-             start_hpos = dpyinfo->mouse_face_beg_col;
-             start_x = dpyinfo->mouse_face_beg_x;
+             /* R2L rows have BEG and END in reversed order, but the
+                screen drawing geometry is always left to right.  So
+                we need to mirror the beginning and end of the
+                highlighted area in R2L rows.  */
+             if (!row->reversed_p)
+               {
+                 start_hpos = hlinfo->mouse_face_beg_col;
+                 start_x = hlinfo->mouse_face_beg_x;
+               }
+             else if (row == last)
+               {
+                 start_hpos = hlinfo->mouse_face_end_col;
+                 start_x = hlinfo->mouse_face_end_x;
+               }
+             else
+               {
+                 start_hpos = 0;
+                 start_x = 0;
+               }
+           }
+         else if (row->reversed_p && row == last)
+           {
+             start_hpos = hlinfo->mouse_face_end_col;
+             start_x = hlinfo->mouse_face_end_x;
            }
          else
            {
@@ -23627,7 +24104,20 @@ show_mouse_face (Display_Info *dpyinfo, enum draw_glyphs_face draw)
            }
 
          if (row == last)
-           end_hpos = dpyinfo->mouse_face_end_col;
+           {
+             if (!row->reversed_p)
+               end_hpos = hlinfo->mouse_face_end_col;
+             else if (row == first)
+               end_hpos = hlinfo->mouse_face_beg_col;
+             else
+               {
+                 end_hpos = row->used[TEXT_AREA];
+                 if (draw == DRAW_NORMAL_TEXT)
+                   row->fill_line_p = 1; /* Clear to end of line */
+               }
+           }
+         else if (row->reversed_p && row == first)
+           end_hpos = hlinfo->mouse_face_beg_col;
          else
            {
              end_hpos = row->used[TEXT_AREA];
@@ -23637,18 +24127,19 @@ show_mouse_face (Display_Info *dpyinfo, enum draw_glyphs_face draw)
 
          if (end_hpos > start_hpos)
            {
-             draw_glyphs (w, start_x, row, TEXT_AREA,
-                          start_hpos, end_hpos,
-                          draw, 0);
+             draw_row_with_mouse_face (w, start_x, row,
+                                       start_hpos, end_hpos, draw);
 
              row->mouse_face_p
                = draw == DRAW_MOUSE_FACE || draw == DRAW_IMAGE_RAISED;
            }
        }
 
+#ifdef HAVE_WINDOW_SYSTEM
       /* When we've written over the cursor, arrange for it to
         be displayed again.  */
-      if (phys_cursor_on_p && !w->phys_cursor_on_p)
+      if (FRAME_WINDOW_P (f)
+         && phys_cursor_on_p && !w->phys_cursor_on_p)
        {
          BLOCK_INPUT;
          display_and_set_cursor (w, 1,
@@ -23656,40 +24147,94 @@ show_mouse_face (Display_Info *dpyinfo, enum draw_glyphs_face draw)
                                  w->phys_cursor.x, w->phys_cursor.y);
          UNBLOCK_INPUT;
        }
+#endif /* HAVE_WINDOW_SYSTEM */
     }
 
+#ifdef HAVE_WINDOW_SYSTEM
   /* Change the mouse cursor.  */
-  if (draw == DRAW_NORMAL_TEXT && !EQ (dpyinfo->mouse_face_window, f->tool_bar_window))
-    FRAME_RIF (f)->define_frame_cursor (f, FRAME_X_OUTPUT (f)->text_cursor);
-  else if (draw == DRAW_MOUSE_FACE)
-    FRAME_RIF (f)->define_frame_cursor (f, FRAME_X_OUTPUT (f)->hand_cursor);
-  else
-    FRAME_RIF (f)->define_frame_cursor (f, FRAME_X_OUTPUT (f)->nontext_cursor);
-}
-
+  if (FRAME_WINDOW_P (f))
+    {
+      if (draw == DRAW_NORMAL_TEXT
+         && !EQ (hlinfo->mouse_face_window, f->tool_bar_window))
+       FRAME_RIF (f)->define_frame_cursor (f, FRAME_X_OUTPUT (f)->text_cursor);
+      else if (draw == DRAW_MOUSE_FACE)
+       FRAME_RIF (f)->define_frame_cursor (f, FRAME_X_OUTPUT (f)->hand_cursor);
+      else
+       FRAME_RIF (f)->define_frame_cursor (f, FRAME_X_OUTPUT (f)->nontext_cursor);
+    }
+#endif /* HAVE_WINDOW_SYSTEM */
+}
+
 /* EXPORT:
    Clear out the mouse-highlighted active region.
    Redraw it un-highlighted first.  Value is non-zero if mouse
    face was actually drawn unhighlighted.  */
 
 int
-clear_mouse_face (Display_Info *dpyinfo)
+clear_mouse_face (Mouse_HLInfo *hlinfo)
 {
   int cleared = 0;
 
-  if (!dpyinfo->mouse_face_hidden && !NILP (dpyinfo->mouse_face_window))
+  if (!hlinfo->mouse_face_hidden && !NILP (hlinfo->mouse_face_window))
     {
-      show_mouse_face (dpyinfo, DRAW_NORMAL_TEXT);
+      show_mouse_face (hlinfo, DRAW_NORMAL_TEXT);
       cleared = 1;
     }
 
-  dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
-  dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
-  dpyinfo->mouse_face_window = Qnil;
-  dpyinfo->mouse_face_overlay = Qnil;
+  hlinfo->mouse_face_beg_row = hlinfo->mouse_face_beg_col = -1;
+  hlinfo->mouse_face_end_row = hlinfo->mouse_face_end_col = -1;
+  hlinfo->mouse_face_window = Qnil;
+  hlinfo->mouse_face_overlay = Qnil;
   return cleared;
 }
 
+/* Return non-zero if the coordinates HPOS and VPOS on windows W are
+   within the mouse face on that window.  */
+static int
+coords_in_mouse_face_p (struct window *w, int hpos, int vpos)
+{
+  Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (XFRAME (w->frame));
+
+  /* Quickly resolve the easy cases.  */
+  if (!(WINDOWP (hlinfo->mouse_face_window)
+       && XWINDOW (hlinfo->mouse_face_window) == w))
+    return 0;
+  if (vpos < hlinfo->mouse_face_beg_row
+      || vpos > hlinfo->mouse_face_end_row)
+    return 0;
+  if (vpos > hlinfo->mouse_face_beg_row
+      && vpos < hlinfo->mouse_face_end_row)
+    return 1;
+
+  if (!MATRIX_ROW (w->current_matrix, vpos)->reversed_p)
+    {
+      if (hlinfo->mouse_face_beg_row == hlinfo->mouse_face_end_row)
+       {
+         if (hlinfo->mouse_face_beg_col <= hpos && hpos < hlinfo->mouse_face_end_col)
+           return 1;
+       }
+      else if ((vpos == hlinfo->mouse_face_beg_row
+               && hpos >= hlinfo->mouse_face_beg_col)
+              || (vpos == hlinfo->mouse_face_end_row
+                  && hpos < hlinfo->mouse_face_end_col))
+       return 1;
+    }
+  else
+    {
+       if (hlinfo->mouse_face_beg_row == hlinfo->mouse_face_end_row)
+       {
+         if (hlinfo->mouse_face_end_col < hpos && hpos <= hlinfo->mouse_face_beg_col)
+           return 1;
+       }
+      else if ((vpos == hlinfo->mouse_face_beg_row
+               && hpos <= hlinfo->mouse_face_beg_col)
+              || (vpos == hlinfo->mouse_face_end_row
+                  && hpos > hlinfo->mouse_face_end_col))
+       return 1;
+    }
+  return 0;
+}
+
 
 /* EXPORT:
    Non-zero if physical cursor of window W is within mouse face.  */
@@ -23697,32 +24242,135 @@ clear_mouse_face (Display_Info *dpyinfo)
 int
 cursor_in_mouse_face_p (struct window *w)
 {
-  Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (XFRAME (w->frame));
-  int in_mouse_face = 0;
+  return coords_in_mouse_face_p (w, w->phys_cursor.hpos, w->phys_cursor.vpos);
+}
 
-  if (WINDOWP (dpyinfo->mouse_face_window)
-      && XWINDOW (dpyinfo->mouse_face_window) == w)
-    {
-      int hpos = w->phys_cursor.hpos;
-      int vpos = w->phys_cursor.vpos;
 
-      if (vpos >= dpyinfo->mouse_face_beg_row
-         && vpos <= dpyinfo->mouse_face_end_row
-         && (vpos > dpyinfo->mouse_face_beg_row
-             || hpos >= dpyinfo->mouse_face_beg_col)
-         && (vpos < dpyinfo->mouse_face_end_row
-             || hpos < dpyinfo->mouse_face_end_col
-             || dpyinfo->mouse_face_past_end))
-       in_mouse_face = 1;
-    }
+\f
+/* Find the glyph rows START_ROW and END_ROW of window W that display
+   characters between buffer positions START_CHARPOS and END_CHARPOS
+   (excluding END_CHARPOS).  This is similar to row_containing_pos,
+   but is more accurate when bidi reordering makes buffer positions
+   change non-linearly with glyph rows.  */
+static void
+rows_from_pos_range (struct window *w,
+                    EMACS_INT start_charpos, EMACS_INT end_charpos,
+                    struct glyph_row **start, struct glyph_row **end)
+{
+  struct glyph_row *first = MATRIX_FIRST_TEXT_ROW (w->current_matrix);
+  int last_y = window_text_bottom_y (w);
+  struct glyph_row *row;
 
-  return in_mouse_face;
-}
+  *start = NULL;
+  *end = NULL;
+
+  while (!first->enabled_p
+        && first < MATRIX_BOTTOM_TEXT_ROW (w->current_matrix, w))
+    first++;
+
+  /* Find the START row.  */
+  for (row = first;
+       row->enabled_p && MATRIX_ROW_BOTTOM_Y (row) <= last_y;
+       row++)
+    {
+      /* A row can potentially be the START row if the range of the
+        characters it displays intersects the range
+        [START_CHARPOS..END_CHARPOS).  */
+      if (! ((start_charpos < MATRIX_ROW_START_CHARPOS (row)
+             && end_charpos < MATRIX_ROW_START_CHARPOS (row))
+            /* See the commentary in row_containing_pos, for the
+               explanation of the complicated way to check whether
+               some position is beyond the end of the characters
+               displayed by a row.  */
+            || ((start_charpos > MATRIX_ROW_END_CHARPOS (row)
+                 || (start_charpos == MATRIX_ROW_END_CHARPOS (row)
+                     && !row->ends_at_zv_p
+                     && !MATRIX_ROW_ENDS_IN_MIDDLE_OF_CHAR_P (row)))
+                && (end_charpos > MATRIX_ROW_END_CHARPOS (row)
+                    || (end_charpos == MATRIX_ROW_END_CHARPOS (row)
+                        && !row->ends_at_zv_p
+                        && !MATRIX_ROW_ENDS_IN_MIDDLE_OF_CHAR_P (row))))))
+       {
+         /* Found a candidate row.  Now make sure at least one of the
+            glyphs it displays has a charpos from the range
+            [START_CHARPOS..END_CHARPOS).
+
+            This is not obvious because bidi reordering could make
+            buffer positions of a row be 1,2,3,102,101,100, and if we
+            want to highlight characters in [50..60), we don't want
+            this row, even though [50..60) does intersect [1..103),
+            the range of character positions given by the row's start
+            and end positions.  */
+         struct glyph *g = row->glyphs[TEXT_AREA];
+         struct glyph *e = g + row->used[TEXT_AREA];
+
+         while (g < e)
+           {
+             if (BUFFERP (g->object)
+                 && start_charpos <= g->charpos && g->charpos < end_charpos)
+               *start = row;
+             g++;
+           }
+         if (*start)
+           break;
+       }
+    }
 
+  /* Find the END row.  */
+  if (!*start
+      /* If the last row is partially visible, start looking for END
+        from that row, instead of starting from FIRST.  */
+      && !(row->enabled_p
+          && row->y < last_y && MATRIX_ROW_BOTTOM_Y (row) > last_y))
+    row = first;
+  for ( ; row->enabled_p && MATRIX_ROW_BOTTOM_Y (row) <= last_y; row++)
+    {
+      struct glyph_row *next = row + 1;
+
+      if (!next->enabled_p
+         || next >= MATRIX_BOTTOM_TEXT_ROW (w->current_matrix, w)
+         /* The first row >= START whose range of displayed characters
+            does NOT intersect the range [START_CHARPOS..END_CHARPOS]
+            is the row END + 1.  */
+         || (start_charpos < MATRIX_ROW_START_CHARPOS (next)
+             && end_charpos < MATRIX_ROW_START_CHARPOS (next))
+         || ((start_charpos > MATRIX_ROW_END_CHARPOS (next)
+              || (start_charpos == MATRIX_ROW_END_CHARPOS (next)
+                  && !next->ends_at_zv_p
+                  && !MATRIX_ROW_ENDS_IN_MIDDLE_OF_CHAR_P (next)))
+             && (end_charpos > MATRIX_ROW_END_CHARPOS (next)
+                 || (end_charpos == MATRIX_ROW_END_CHARPOS (next)
+                     && !next->ends_at_zv_p
+                     && !MATRIX_ROW_ENDS_IN_MIDDLE_OF_CHAR_P (next)))))
+       {
+         *end = row;
+         break;
+       }
+      else
+       {
+         /* If the next row's edges intersect [START_CHARPOS..END_CHARPOS],
+            but none of the characters it displays are in the range, it is
+            also END + 1. */
+         struct glyph *g = next->glyphs[TEXT_AREA];
+         struct glyph *e = g + next->used[TEXT_AREA];
 
+         while (g < e)
+           {
+             if (BUFFERP (g->object)
+                 && start_charpos <= g->charpos && g->charpos < end_charpos)
+               break;
+             g++;
+           }
+         if (g == e)
+           {
+             *end = row;
+             break;
+           }
+       }
+    }
+}
 
-\f
-/* This function sets the mouse_face_* elements of DPYINFO, assuming
+/* This function sets the mouse_face_* elements of HLINFO, 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
@@ -23733,7 +24381,7 @@ cursor_in_mouse_face_p (struct window *w)
 
 static void
 mouse_face_from_buffer_pos (Lisp_Object window,
-                           Display_Info *dpyinfo,
+                           Mouse_HLInfo *hlinfo,
                            EMACS_INT mouse_charpos,
                            EMACS_INT start_charpos,
                            EMACS_INT end_charpos,
@@ -23743,166 +24391,313 @@ mouse_face_from_buffer_pos (Lisp_Object window,
 {
   struct window *w = XWINDOW (window);
   struct glyph_row *first = MATRIX_FIRST_TEXT_ROW (w->current_matrix);
-  struct glyph_row *row;
+  struct glyph_row *r1, *r2;
   struct glyph *glyph, *end;
-  EMACS_INT ignore;
+  EMACS_INT ignore, pos;
   int x;
 
   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))
+  /* Find the rows corresponding to START_CHARPOS and END_CHARPOS.  */
+  rows_from_pos_range (w, start_charpos, end_charpos, &r1, &r2);
+  if (r1 == NULL)
+    r1 = MATRIX_ROW (w->current_matrix, XFASTINT (w->window_end_vpos));
+  /* If the before-string or display-string contains newlines,
+     rows_from_pos_range skips to its last row.  Move back.  */
+  if (!NILP (before_string) || !NILP (display_string))
+    {
+      struct glyph_row *prev;
+      while ((prev = r1 - 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;
+         r1 = prev;
+       }
+    }
+  if (r2 == NULL)
     {
-      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;
+      r2 = MATRIX_ROW (w->current_matrix, XFASTINT (w->window_end_vpos));
+      hlinfo->mouse_face_past_end = 1;
     }
-  else
+  else if (!NILP (after_string))
     {
-      row = row_containing_pos (w, start_charpos, first, NULL, 0);
-      if (row == NULL)
-       row = MATRIX_ROW (w->current_matrix, XFASTINT (w->window_end_vpos));
-
-      /* 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;
-           }
-       }
+      /* 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));
 
-      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);
+      for (next = r2 + 1;
+          next <= last
+            && next->used[TEXT_AREA] > 0
+            && EQ (next->glyphs[TEXT_AREA]->object, after_string);
+          ++next)
+       r2 = next;
+    }
+  /* The rest of the display engine assumes that mouse_face_beg_row is
+     either above below mouse_face_end_row or identical to it.  But
+     with bidi-reordered continued lines, the row for START_CHARPOS
+     could be below the row for END_CHARPOS.  If so, swap the rows and
+     store them in correct order.  */
+  if (r1->y > r2->y)
+    {
+      struct glyph_row *tem = r2;
+
+      r2 = r1;
+      r1 = tem;
+    }
+
+  hlinfo->mouse_face_beg_y = r1->y;
+  hlinfo->mouse_face_beg_row = MATRIX_ROW_VPOS (r1, w->current_matrix);
+  hlinfo->mouse_face_end_y = r2->y;
+  hlinfo->mouse_face_end_row = MATRIX_ROW_VPOS (r2, w->current_matrix);
+
+  /* For a bidi-reordered row, the positions of BEFORE_STRING,
+     AFTER_STRING, DISPLAY_STRING, START_CHARPOS, and END_CHARPOS
+     could be anywhere in the row and in any order.  The strategy
+     below is to find the leftmost and the rightmost glyph that
+     belongs to either of these 3 strings, or whose position is
+     between START_CHARPOS and END_CHARPOS, and highlight all the
+     glyphs between those two.  This may cover more than just the text
+     between START_CHARPOS and END_CHARPOS if the range of characters
+     strides the bidi level boundary, e.g. if the beginning is in R2L
+     text while the end is in L2R text or vice versa.  */
+  if (!r1->reversed_p)
+    {
+      /* This row is in a left to right paragraph.  Scan it left to
+        right.  */
+      glyph = r1->glyphs[TEXT_AREA];
+      end = glyph + r1->used[TEXT_AREA];
+      x = r1->x;
 
       /* Skip truncation glyphs at the start of the glyph row.  */
-      if (row->displays_text_p)
+      if (r1->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.  */
+      /* Scan the glyph row, looking for BEFORE_STRING, AFTER_STRING,
+        or DISPLAY_STRING, and the first glyph from buffer whose
+        position is between START_CHARPOS and END_CHARPOS.  */
       for (; glyph < end
             && !INTEGERP (glyph->object)
-            && !EQ (glyph->object, before_string)
             && !EQ (glyph->object, display_string)
             && !(BUFFERP (glyph->object)
-                 && glyph->charpos >= start_charpos);
+                 && (glyph->charpos >= start_charpos
+                     && glyph->charpos < end_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));
-      dpyinfo->mouse_face_past_end = 1;
+       {
+         /* BEFORE_STRING or AFTER_STRING are only relevant if they
+            are present at buffer positions between START_CHARPOS and
+            END_CHARPOS, or if they come from an overlay.  */
+         if (EQ (glyph->object, before_string))
+           {
+             pos = string_buffer_position (w, before_string,
+                                           start_charpos);
+             /* If pos == 0, it means before_string came from an
+                overlay, not from a buffer position.  */
+             if (!pos || (pos >= start_charpos && pos < end_charpos))
+               break;
+           }
+         else if (EQ (glyph->object, after_string))
+           {
+             pos = string_buffer_position (w, after_string, end_charpos);
+             if (!pos || (pos >= start_charpos && pos < end_charpos))
+               break;
+           }
+         x += glyph->pixel_width;
+       }
+      hlinfo->mouse_face_beg_x = x;
+      hlinfo->mouse_face_beg_col = glyph - r1->glyphs[TEXT_AREA];
     }
-  else if (!NILP (after_string))
+  else
     {
-      /* 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));
+      /* This row is in a right to left paragraph.  Scan it right to
+        left.  */
+      struct glyph *g;
 
-      for (next = row + 1;
-          next <= last
-            && next->used[TEXT_AREA] > 0
-            && EQ (next->glyphs[TEXT_AREA]->object, after_string);
-          ++next)
-       row = next;
-    }
+      end = r1->glyphs[TEXT_AREA] - 1;
+      glyph = end + r1->used[TEXT_AREA];
 
-  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 truncation glyphs at the start of the glyph row.  */
+      if (r1->displays_text_p)
+       for (; glyph > end
+              && INTEGERP (glyph->object)
+              && glyph->charpos < 0;
+            --glyph)
+         ;
 
-  /* Skip truncation glyphs at the start of the 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 at END_CHARPOS or when we encounter
-     AFTER_STRING.  */
-  for (; glyph < end
-        && !INTEGERP (glyph->object)
-        && !EQ (glyph->object, after_string)
-        && !(BUFFERP (glyph->object) && glyph->charpos >= end_charpos);
-       ++glyph)
-    x += glyph->pixel_width;
+      /* Scan the glyph row, looking for BEFORE_STRING, AFTER_STRING,
+        or DISPLAY_STRING, and the first glyph from buffer whose
+        position is between START_CHARPOS and END_CHARPOS.  */
+      for (; glyph > end
+            && !INTEGERP (glyph->object)
+            && !EQ (glyph->object, display_string)
+            && !(BUFFERP (glyph->object)
+                 && (glyph->charpos >= start_charpos
+                     && glyph->charpos < end_charpos));
+          --glyph)
+       {
+         /* BEFORE_STRING or AFTER_STRING are only relevant if they
+            are present at buffer positions between START_CHARPOS and
+            END_CHARPOS, or if they come from an overlay.  */
+         if (EQ (glyph->object, before_string))
+           {
+             pos = string_buffer_position (w, before_string, start_charpos);
+             /* If pos == 0, it means before_string came from an
+                overlay, not from a buffer position.  */
+             if (!pos || (pos >= start_charpos && pos < end_charpos))
+               break;
+           }
+         else if (EQ (glyph->object, after_string))
+           {
+             pos = string_buffer_position (w, after_string, end_charpos);
+             if (!pos || (pos >= start_charpos && pos < end_charpos))
+               break;
+           }
+       }
 
-  /* If we found AFTER_STRING, consume it and stop.  */
-  if (EQ (glyph->object, after_string))
+      glyph++; /* first glyph to the right of the highlighted area */
+      for (g = r1->glyphs[TEXT_AREA], x = r1->x; g < glyph; g++)
+       x += g->pixel_width;
+      hlinfo->mouse_face_beg_x = x;
+      hlinfo->mouse_face_beg_col = glyph - r1->glyphs[TEXT_AREA];
+    }
+
+  /* If the highlight ends in a different row, compute GLYPH and END
+     for the end row.  Otherwise, reuse the values computed above for
+     the row where the highlight begins.  */
+  if (r2 != r1)
     {
-      for (; EQ (glyph->object, after_string) && glyph < end; ++glyph)
+      if (!r2->reversed_p)
+       {
+         glyph = r2->glyphs[TEXT_AREA];
+         end = glyph + r2->used[TEXT_AREA];
+         x = r2->x;
+       }
+      else
+       {
+         end = r2->glyphs[TEXT_AREA] - 1;
+         glyph = end + r2->used[TEXT_AREA];
+       }
+    }
+
+  if (!r2->reversed_p)
+    {
+      /* Skip truncation and continuation glyphs near the end of the
+        row, and also blanks and stretch glyphs inserted by
+        extend_face_to_end_of_line.  */
+      while (end > glyph
+            && INTEGERP ((end - 1)->object)
+            && (end - 1)->charpos <= 0)
+       --end;
+      /* Scan the rest of the glyph row from the end, looking for the
+        first glyph that comes from BEFORE_STRING, AFTER_STRING, or
+        DISPLAY_STRING, or whose position is between START_CHARPOS
+        and END_CHARPOS */
+      for (--end;
+            end > glyph
+            && !INTEGERP (end->object)
+            && !EQ (end->object, display_string)
+            && !(BUFFERP (end->object)
+                 && (end->charpos >= start_charpos
+                     && end->charpos < end_charpos));
+          --end)
+       {
+         /* BEFORE_STRING or AFTER_STRING are only relevant if they
+            are present at buffer positions between START_CHARPOS and
+            END_CHARPOS, or if they come from an overlay.  */
+         if (EQ (end->object, before_string))
+           {
+             pos = string_buffer_position (w, before_string, start_charpos);
+             if (!pos || (pos >= start_charpos && pos < end_charpos))
+               break;
+           }
+         else if (EQ (end->object, after_string))
+           {
+             pos = string_buffer_position (w, after_string, end_charpos);
+             if (!pos || (pos >= start_charpos && pos < end_charpos))
+               break;
+           }
+       }
+      /* Find the X coordinate of the last glyph to be highlighted.  */
+      for (; glyph <= end; ++glyph)
        x += glyph->pixel_width;
+
+      hlinfo->mouse_face_end_x = x;
+      hlinfo->mouse_face_end_col = glyph - r2->glyphs[TEXT_AREA];
     }
   else
     {
-      /* 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;
-      EMACS_INT pos;
-
-      while (glyph > row->glyphs[TEXT_AREA])
-       {
-         prev_object = (glyph - 1)->object;
-         if (!STRINGP (prev_object) || EQ (prev_object, display_string))
-           break;
-
-         pos = string_buffer_position (w, prev_object, end_charpos);
-         if (pos && pos < end_charpos)
-           break;
-
-         for (; glyph > row->glyphs[TEXT_AREA]
-                && EQ ((glyph - 1)->object, prev_object);
-              --glyph)
-           x -= (glyph - 1)->pixel_width;
+      /* Skip truncation and continuation glyphs near the end of the
+        row, and also blanks and stretch glyphs inserted by
+        extend_face_to_end_of_line.  */
+      x = r2->x;
+      end++;
+      while (end < glyph
+            && INTEGERP (end->object)
+            && end->charpos <= 0)
+       {
+         x += end->pixel_width;
+         ++end;
+       }
+      /* Scan the rest of the glyph row from the end, looking for the
+        first glyph that comes from BEFORE_STRING, AFTER_STRING, or
+        DISPLAY_STRING, or whose position is between START_CHARPOS
+        and END_CHARPOS */
+      for ( ;
+            end < glyph
+            && !INTEGERP (end->object)
+            && !EQ (end->object, display_string)
+            && !(BUFFERP (end->object)
+                 && (end->charpos >= start_charpos
+                     && end->charpos < end_charpos));
+          ++end)
+       {
+         /* BEFORE_STRING or AFTER_STRING are only relevant if they
+            are present at buffer positions between START_CHARPOS and
+            END_CHARPOS, or if they come from an overlay.  */
+         if (EQ (end->object, before_string))
+           {
+             pos = string_buffer_position (w, before_string, start_charpos);
+             if (!pos || (pos >= start_charpos && pos < end_charpos))
+               break;
+           }
+         else if (EQ (end->object, after_string))
+           {
+             pos = string_buffer_position (w, after_string, end_charpos);
+             if (!pos || (pos >= start_charpos && pos < end_charpos))
+               break;
+           }
+         x += end->pixel_width;
        }
+      hlinfo->mouse_face_end_x = x;
+      hlinfo->mouse_face_end_col = end - r2->glyphs[TEXT_AREA];
     }
 
-  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
+  hlinfo->mouse_face_window = window;
+  hlinfo->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);
+                              !hlinfo->mouse_face_hidden, -1);
+  show_mouse_face (hlinfo, DRAW_MOUSE_FACE);
 }
 
+/* The following function is not used anymore (replaced with
+   mouse_face_from_string_pos), but I leave it here for the time
+   being, in case someone would.  */
+
+#if 0  /* not used */
 
 /* Find the position of the glyph for position POS in OBJECT in
    window W's current matrix, and return in *X, *Y the pixel
@@ -23980,7 +24775,132 @@ fast_find_string_pos (struct window *w, EMACS_INT pos, Lisp_Object object,
 
   return best_glyph != NULL;
 }
+#endif /* not used */
+
+/* Find the positions of the first and the last glyphs in window W's
+   current matrix that occlude positions [STARTPOS..ENDPOS] in OBJECT
+   (assumed to be a string), and return in HLINFO's mouse_face_*
+   members the pixel and column/row coordinates of those glyphs.  */
+
+static void
+mouse_face_from_string_pos (struct window *w, Mouse_HLInfo *hlinfo,
+                           Lisp_Object object,
+                           EMACS_INT startpos, EMACS_INT endpos)
+{
+  int yb = window_text_bottom_y (w);
+  struct glyph_row *r;
+  struct glyph *g, *e;
+  int gx;
+  int found = 0;
+
+  /* Find the glyph row with at least one position in the range
+     [STARTPOS..ENDPOS], and the first glyph in that row whose
+     position belongs to that range.  */
+  for (r = MATRIX_FIRST_TEXT_ROW (w->current_matrix);
+       r->enabled_p && r->y < yb;
+       ++r)
+    {
+      if (!r->reversed_p)
+       {
+         g = r->glyphs[TEXT_AREA];
+         e = g + r->used[TEXT_AREA];
+         for (gx = r->x; g < e; gx += g->pixel_width, ++g)
+           if (EQ (g->object, object)
+               && startpos <= g->charpos && g->charpos <= endpos)
+             {
+               hlinfo->mouse_face_beg_row = r - w->current_matrix->rows;
+               hlinfo->mouse_face_beg_y = r->y;
+               hlinfo->mouse_face_beg_col = g - r->glyphs[TEXT_AREA];
+               hlinfo->mouse_face_beg_x = gx;
+               found = 1;
+               break;
+             }
+       }
+      else
+       {
+         struct glyph *g1;
+
+         e = r->glyphs[TEXT_AREA];
+         g = e + r->used[TEXT_AREA];
+         for ( ; g > e; --g)
+           if (EQ ((g-1)->object, object)
+               && startpos <= (g-1)->charpos && (g-1)->charpos <= endpos)
+             {
+               hlinfo->mouse_face_beg_row = r - w->current_matrix->rows;
+               hlinfo->mouse_face_beg_y = r->y;
+               hlinfo->mouse_face_beg_col = g - r->glyphs[TEXT_AREA];
+               for (gx = r->x, g1 = r->glyphs[TEXT_AREA]; g1 < g; ++g1)
+                 gx += g1->pixel_width;
+               hlinfo->mouse_face_beg_x = gx;
+               found = 1;
+               break;
+             }
+       }
+      if (found)
+       break;
+    }
+
+  if (!found)
+    return;
+
+  /* Starting with the next row, look for the first row which does NOT
+     include any glyphs whose positions are in the range.  */
+  for (++r; r->enabled_p && r->y < yb; ++r)
+    {
+      g = r->glyphs[TEXT_AREA];
+      e = g + r->used[TEXT_AREA];
+      found = 0;
+      for ( ; g < e; ++g)
+       if (EQ (g->object, object)
+           && startpos <= g->charpos && g->charpos <= endpos)
+         {
+           found = 1;
+           break;
+         }
+      if (!found)
+       break;
+    }
+
+  /* The highlighted region ends on the previous row.  */
+  r--;
+
+  /* Set the end row and its vertical pixel coordinate.  */
+  hlinfo->mouse_face_end_row = r - w->current_matrix->rows;
+  hlinfo->mouse_face_end_y = r->y;
+
+  /* Compute and set the end column and the end column's horizontal
+     pixel coordinate.  */
+  if (!r->reversed_p)
+    {
+      g = r->glyphs[TEXT_AREA];
+      e = g + r->used[TEXT_AREA];
+      for ( ; e > g; --e)
+       if (EQ ((e-1)->object, object)
+           && startpos <= (e-1)->charpos && (e-1)->charpos <= endpos)
+         break;
+      hlinfo->mouse_face_end_col = e - g;
+
+      for (gx = r->x; g < e; ++g)
+       gx += g->pixel_width;
+      hlinfo->mouse_face_end_x = gx;
+    }
+  else
+    {
+      e = r->glyphs[TEXT_AREA];
+      g = e + r->used[TEXT_AREA];
+      for (gx = r->x ; e < g; ++e)
+       {
+         if (EQ (e->object, object)
+             && startpos <= e->charpos && e->charpos <= endpos)
+           break;
+         gx += e->pixel_width;
+       }
+      hlinfo->mouse_face_end_col = e - r->glyphs[TEXT_AREA];
+      hlinfo->mouse_face_end_x = gx;
+    }
+}
 
+#ifdef HAVE_WINDOW_SYSTEM
 
 /* See if position X, Y is within a hot-spot of an image.  */
 
@@ -24152,6 +25072,8 @@ define_frame_cursor1 (struct frame *f, Cursor cursor, Lisp_Object pointer)
     FRAME_RIF (f)->define_frame_cursor (f, cursor);
 }
 
+#endif /* HAVE_WINDOW_SYSTEM */
+
 /* Take proper action when mouse has moved to the mode or header line
    or marginal area AREA of window W, x-position X and y-position Y.
    X is relative to the start of the text display area of W, so the
@@ -24164,10 +25086,14 @@ note_mode_line_or_margin_highlight (Lisp_Object window, int x, int y,
 {
   struct window *w = XWINDOW (window);
   struct frame *f = XFRAME (w->frame);
-  Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
-  Cursor cursor = FRAME_X_OUTPUT (f)->nontext_cursor;
+  Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
+#ifdef HAVE_WINDOW_SYSTEM
+  Display_Info *dpyinfo;
+#endif
+  Cursor cursor = No_Cursor;
   Lisp_Object pointer = Qnil;
-  int charpos, dx, dy, width, height;
+  int dx, dy, width, height;
+  EMACS_INT charpos;
   Lisp_Object string, object = Qnil;
   Lisp_Object pos, help;
 
@@ -24181,6 +25107,8 @@ note_mode_line_or_margin_highlight (Lisp_Object window, int x, int y,
       int x0;
       struct glyph *end;
 
+      /* Kludge alert: mode_line_string takes X/Y in pixels, but
+        returns them in row/column units!  */
       string = mode_line_string (w, area, &x, &y, &charpos,
                                 &object, &dx, &dy, &width, &height);
 
@@ -24188,7 +25116,7 @@ note_mode_line_or_margin_highlight (Lisp_Object window, int x, int y,
             ? MATRIX_MODE_LINE_ROW (w->current_matrix)
             : MATRIX_HEADER_LINE_ROW (w->current_matrix));
 
-      /* Find glyph */
+      /* Find the glyph under the mouse pointer.  */
       if (row->mode_line_p && row->enabled_p)
        {
          glyph = row_start_glyph = row->glyphs[TEXT_AREA];
@@ -24206,12 +25134,15 @@ note_mode_line_or_margin_highlight (Lisp_Object window, int x, int y,
   else
     {
       x -= WINDOW_LEFT_SCROLL_BAR_AREA_WIDTH (w);
+      /* Kludge alert: marginal_area_string takes X/Y in pixels, but
+        returns them in row/column units!  */
       string = marginal_area_string (w, area, &x, &y, &charpos,
                                     &object, &dx, &dy, &width, &height);
     }
 
   help = Qnil;
 
+#ifdef HAVE_WINDOW_SYSTEM
   if (IMAGEP (object))
     {
       Lisp_Object image_map, hotspot;
@@ -24248,6 +25179,7 @@ note_mode_line_or_margin_highlight (Lisp_Object window, int x, int y,
       if (NILP (pointer))
        pointer = Fplist_get (XCDR (object), QCpointer);
     }
+#endif /* HAVE_WINDOW_SYSTEM */
 
   if (STRINGP (string))
     {
@@ -24267,19 +25199,27 @@ note_mode_line_or_margin_highlight (Lisp_Object window, int x, int y,
            }
        }
 
-      if (NILP (pointer))
-       pointer = Fget_text_property (pos, Qpointer, string);
-
-     /* Change the mouse pointer according to what is under X/Y.  */
-      if (NILP (pointer) && ((area == ON_MODE_LINE) || (area == ON_HEADER_LINE)))
+#ifdef HAVE_WINDOW_SYSTEM
+      if (FRAME_WINDOW_P (f))
        {
-         Lisp_Object map;
-         map = Fget_text_property (pos, Qlocal_map, string);
-         if (!KEYMAPP (map))
-           map = Fget_text_property (pos, Qkeymap, string);
-         if (!KEYMAPP (map))
-           cursor = dpyinfo->vertical_scroll_bar_cursor;
+         dpyinfo = FRAME_X_DISPLAY_INFO (f);
+         cursor  = FRAME_X_OUTPUT (f)->nontext_cursor;
+         if (NILP (pointer))
+           pointer = Fget_text_property (pos, Qpointer, string);
+
+         /* Change the mouse pointer according to what is under X/Y.  */
+         if (NILP (pointer)
+             && ((area == ON_MODE_LINE) || (area == ON_HEADER_LINE)))
+           {
+             Lisp_Object map;
+             map = Fget_text_property (pos, Qlocal_map, string);
+             if (!KEYMAPP (map))
+               map = Fget_text_property (pos, Qkeymap, string);
+             if (!KEYMAPP (map))
+               cursor = dpyinfo->vertical_scroll_bar_cursor;
+           }
        }
+#endif
 
      /* Change the mouse face according to what is under X/Y.  */
       mouse_face = Fget_text_property (pos, Qmouse_face, string);
@@ -24294,102 +25234,128 @@ note_mode_line_or_margin_highlight (Lisp_Object window, int x, int y,
          int gpos;
          int gseq_length;
          int total_pixel_width;
-         EMACS_INT ignore;
+         EMACS_INT begpos, endpos, ignore;
 
          int vpos, hpos;
 
          b = Fprevious_single_property_change (make_number (charpos + 1),
                                                Qmouse_face, string, Qnil);
          if (NILP (b))
-           b = make_number (0);
+           begpos = 0;
+         else
+           begpos = XINT (b);
 
          e = Fnext_single_property_change (pos, Qmouse_face, string, Qnil);
          if (NILP (e))
-           e = make_number (SCHARS (string));
-
-         /* Calculate the position(glyph position: GPOS) of GLYPH in
-            displayed string. GPOS is different from CHARPOS.
-
-            CHARPOS is the position of glyph in internal string
-            object. A mode line string format has structures which
-            is converted to a flatten by emacs lisp interpreter.
-            The internal string is an element of the structures.
-            The displayed string is the flatten string. */
-         gpos = 0;
-         if (glyph > row_start_glyph)
-           {
-             tmp_glyph = glyph - 1;
-             while (tmp_glyph >= row_start_glyph
-                    && tmp_glyph->charpos >= XINT (b)
-                    && EQ (tmp_glyph->object, glyph->object))
-               {
-                 tmp_glyph--;
-                 gpos++;
-               }
-           }
-
-         /* Calculate the lenght(glyph sequence length: GSEQ_LENGTH) of
-            displayed string holding GLYPH.
-
-            GSEQ_LENGTH is different from SCHARS (STRING).
-            SCHARS (STRING) returns the length of the internal string. */
-         for (tmp_glyph = glyph, gseq_length = gpos;
-              tmp_glyph->charpos < XINT (e);
-              tmp_glyph++, gseq_length++)
-             {
-               if (!EQ (tmp_glyph->object, glyph->object))
-                 break;
-             }
+           endpos = SCHARS (string);
+         else
+           endpos = XINT (e);
+
+         /* Calculate the glyph position GPOS of GLYPH in the
+            displayed string, relative to the beginning of the
+            highlighted part of the string.
+
+            Note: GPOS is different from CHARPOS.  CHARPOS is the
+            position of GLYPH in the internal string object.  A mode
+            line string format has structures which are converted to
+            a flattened string by the Emacs Lisp interpreter.  The
+            internal string is an element of those structures.  The
+            displayed string is the flattened string.  */
+         tmp_glyph = row_start_glyph;
+         while (tmp_glyph < glyph
+                && (!(EQ (tmp_glyph->object, glyph->object)
+                      && begpos <= tmp_glyph->charpos
+                      && tmp_glyph->charpos < endpos)))
+           tmp_glyph++;
+         gpos = glyph - tmp_glyph;
+
+         /* Calculate the length GSEQ_LENGTH of the glyph sequence of
+            the highlighted part of the displayed string to which
+            GLYPH belongs.  Note: GSEQ_LENGTH is different from
+            SCHARS (STRING), because the latter returns the length of
+            the internal string.  */
+         for (tmp_glyph = row->glyphs[TEXT_AREA] + row->used[TEXT_AREA] - 1;
+              tmp_glyph > glyph
+                && (!(EQ (tmp_glyph->object, glyph->object)
+                      && begpos <= tmp_glyph->charpos
+                      && tmp_glyph->charpos < endpos));
+              tmp_glyph--)
+           ;
+         gseq_length = gpos + (tmp_glyph - glyph) + 1;
 
+         /* Calculate the total pixel width of all the glyphs between
+            the beginning of the highlighted area and GLYPH.  */
          total_pixel_width = 0;
          for (tmp_glyph = glyph - gpos; tmp_glyph != glyph; tmp_glyph++)
            total_pixel_width += tmp_glyph->pixel_width;
 
-         /* Pre calculation of re-rendering position */
-         vpos = (x - gpos);
-         hpos = (area == ON_MODE_LINE
+         /* Pre calculation of re-rendering position.  Note: X is in
+            column units here, after the call to mode_line_string or
+            marginal_area_string.  */
+         hpos = x - gpos;
+         vpos = (area == ON_MODE_LINE
                  ? (w->current_matrix)->nrows - 1
                  : 0);
 
-         /* If the re-rendering position is included in the last
-            re-rendering area, we should do nothing. */
-         if ( EQ (window, dpyinfo->mouse_face_window)
-              && dpyinfo->mouse_face_beg_col <= vpos
-              && vpos < dpyinfo->mouse_face_end_col
-              && dpyinfo->mouse_face_beg_row == hpos )
+         /* If GLYPH's position is included in the region that is
+            already drawn in mouse face, we have nothing to do.  */
+         if ( EQ (window, hlinfo->mouse_face_window)
+              && (!row->reversed_p
+                  ? (hlinfo->mouse_face_beg_col <= hpos
+                     && hpos < hlinfo->mouse_face_end_col)
+                  /* In R2L rows we swap BEG and END, see below.  */
+                  : (hlinfo->mouse_face_end_col <= hpos
+                     && hpos < hlinfo->mouse_face_beg_col))
+              && hlinfo->mouse_face_beg_row == vpos )
            return;
 
-         if (clear_mouse_face (dpyinfo))
+         if (clear_mouse_face (hlinfo))
            cursor = No_Cursor;
 
-         dpyinfo->mouse_face_beg_col = vpos;
-         dpyinfo->mouse_face_beg_row = hpos;
-
-         dpyinfo->mouse_face_beg_x   = original_x_pixel - (total_pixel_width + dx);
-         dpyinfo->mouse_face_beg_y   = 0;
-
-         dpyinfo->mouse_face_end_col = vpos + gseq_length;
-         dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_beg_row;
-
-         dpyinfo->mouse_face_end_x   = 0;
-         dpyinfo->mouse_face_end_y   = 0;
-
-         dpyinfo->mouse_face_past_end = 0;
-         dpyinfo->mouse_face_window  = window;
+         if (!row->reversed_p)
+           {
+             hlinfo->mouse_face_beg_col = hpos;
+             hlinfo->mouse_face_beg_x   = original_x_pixel
+                                           - (total_pixel_width + dx);
+             hlinfo->mouse_face_end_col = hpos + gseq_length;
+             hlinfo->mouse_face_end_x   = 0;
+           }
+         else
+           {
+             /* In R2L rows, show_mouse_face expects BEG and END
+                coordinates to be swapped.  */
+             hlinfo->mouse_face_end_col = hpos;
+             hlinfo->mouse_face_end_x   = original_x_pixel
+                                           - (total_pixel_width + dx);
+             hlinfo->mouse_face_beg_col = hpos + gseq_length;
+             hlinfo->mouse_face_beg_x   = 0;
+           }
 
-         dpyinfo->mouse_face_face_id = face_at_string_position (w, string,
-                                                                charpos,
-                                                                0, 0, 0, &ignore,
-                                                                glyph->face_id, 1);
-         show_mouse_face (dpyinfo, DRAW_MOUSE_FACE);
+         hlinfo->mouse_face_beg_row  = vpos;
+         hlinfo->mouse_face_end_row  = hlinfo->mouse_face_beg_row;
+         hlinfo->mouse_face_beg_y    = 0;
+         hlinfo->mouse_face_end_y    = 0;
+         hlinfo->mouse_face_past_end = 0;
+         hlinfo->mouse_face_window   = window;
+
+         hlinfo->mouse_face_face_id = face_at_string_position (w, string,
+                                                               charpos,
+                                                               0, 0, 0,
+                                                               &ignore,
+                                                               glyph->face_id,
+                                                               1);
+         show_mouse_face (hlinfo, DRAW_MOUSE_FACE);
 
          if (NILP (pointer))
            pointer = Qhand;
        }
       else if ((area == ON_MODE_LINE) || (area == ON_HEADER_LINE))
-       clear_mouse_face (dpyinfo);
+       clear_mouse_face (hlinfo);
     }
-  define_frame_cursor1 (f, cursor, pointer);
+#ifdef HAVE_WINDOW_SYSTEM
+  if (FRAME_WINDOW_P (f))
+    define_frame_cursor1 (f, cursor, pointer);
+#endif
 }
 
 
@@ -24402,7 +25368,7 @@ note_mode_line_or_margin_highlight (Lisp_Object window, int x, int y,
 void
 note_mouse_highlight (struct frame *f, int x, int y)
 {
-  Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
+  Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
   enum window_part part;
   Lisp_Object window;
   struct window *w;
@@ -24411,7 +25377,7 @@ note_mouse_highlight (struct frame *f, int x, int y)
   struct buffer *b;
 
   /* When a menu is active, don't highlight because this looks odd.  */
-#if defined (USE_X_TOOLKIT) || defined (USE_GTK) || defined (HAVE_NS)
+#if defined (USE_X_TOOLKIT) || defined (USE_GTK) || defined (HAVE_NS) || defined (MSDOS)
   if (popup_activated ())
     return;
 #endif
@@ -24421,28 +25387,28 @@ note_mouse_highlight (struct frame *f, int x, int y)
       || f->pointer_invisible)
     return;
 
-  dpyinfo->mouse_face_mouse_x = x;
-  dpyinfo->mouse_face_mouse_y = y;
-  dpyinfo->mouse_face_mouse_frame = f;
+  hlinfo->mouse_face_mouse_x = x;
+  hlinfo->mouse_face_mouse_y = y;
+  hlinfo->mouse_face_mouse_frame = f;
 
-  if (dpyinfo->mouse_face_defer)
+  if (hlinfo->mouse_face_defer)
     return;
 
   if (gc_in_progress)
     {
-      dpyinfo->mouse_face_deferred_gc = 1;
+      hlinfo->mouse_face_deferred_gc = 1;
       return;
     }
 
   /* Which window is that in?  */
-  window = window_from_coordinates (f, x, y, &part, 0, 0, 1);
+  window = window_from_coordinates (f, x, y, &part, 1);
 
   /* If we were displaying active text in another window, clear that.
      Also clear if we move out of text area in same window.  */
-  if (! EQ (window, dpyinfo->mouse_face_window)
+  if (! EQ (window, hlinfo->mouse_face_window)
       || (part != ON_TEXT && part != ON_MODE_LINE && part != ON_HEADER_LINE
-         && !NILP (dpyinfo->mouse_face_window)))
-    clear_mouse_face (dpyinfo);
+         && !NILP (hlinfo->mouse_face_window)))
+    clear_mouse_face (hlinfo);
 
   /* Not on a window -> return.  */
   if (!WINDOWP (window))
@@ -24455,6 +25421,7 @@ note_mouse_highlight (struct frame *f, int x, int y)
   w = XWINDOW (window);
   frame_to_window_pixel_xy (w, &x, &y);
 
+#ifdef HAVE_WINDOW_SYSTEM
   /* Handle tool-bar window differently since it doesn't display a
      buffer.  */
   if (EQ (window, f->tool_bar_window))
@@ -24462,6 +25429,7 @@ note_mouse_highlight (struct frame *f, int x, int y)
       note_tool_bar_highlight (f, x, y);
       return;
     }
+#endif
 
   /* Mouse is on the mode, header line or margin?  */
   if (part == ON_MODE_LINE || part == ON_HEADER_LINE
@@ -24471,6 +25439,7 @@ note_mouse_highlight (struct frame *f, int x, int y)
       return;
     }
 
+#ifdef HAVE_WINDOW_SYSTEM
   if (part == ON_VERTICAL_BORDER)
     {
       cursor = FRAME_X_OUTPUT (f)->horizontal_drag_cursor;
@@ -24481,6 +25450,7 @@ note_mouse_highlight (struct frame *f, int x, int y)
     cursor = FRAME_X_OUTPUT (f)->nontext_cursor;
   else
     cursor = FRAME_X_OUTPUT (f)->text_cursor;
+#endif
 
   /* Are we in a window whose display is up to date?
      And verify the buffer's text has not changed.  */
@@ -24498,11 +25468,13 @@ note_mouse_highlight (struct frame *f, int x, int y)
       Lisp_Object *overlay_vec = NULL;
       int noverlays;
       struct buffer *obuf;
-      int obegv, ozv, same_region;
+      EMACS_INT obegv, ozv;
+      int same_region;
 
       /* Find the glyph under X/Y.  */
       glyph = x_y_to_hpos_vpos (w, x, y, &hpos, &vpos, &dx, &dy, &area);
 
+#ifdef HAVE_WINDOW_SYSTEM
       /* Look for :pointer property on image.  */
       if (glyph != NULL && glyph->type == IMAGE_GLYPH)
        {
@@ -24513,8 +25485,8 @@ note_mouse_highlight (struct frame *f, int x, int y)
              if ((image_map = Fplist_get (XCDR (img->spec), QCmap),
                   !NILP (image_map))
                  && (hotspot = find_hot_spot (image_map,
-                                              glyph->slice.x + dx,
-                                              glyph->slice.y + dy),
+                                              glyph->slice.img.x + dx,
+                                              glyph->slice.img.y + dy),
                      CONSP (hotspot))
                  && (hotspot = XCDR (hotspot), CONSP (hotspot)))
                {
@@ -24544,21 +25516,38 @@ note_mouse_highlight (struct frame *f, int x, int y)
                pointer = Fplist_get (XCDR (img->spec), QCpointer);
            }
        }
+#endif /* HAVE_WINDOW_SYSTEM */
 
       /* Clear mouse face if X/Y not over text.  */
       if (glyph == NULL
          || area != TEXT_AREA
-         || !MATRIX_ROW (w->current_matrix, vpos)->displays_text_p)
-       {
-         if (clear_mouse_face (dpyinfo))
+         || !MATRIX_ROW (w->current_matrix, vpos)->displays_text_p
+         /* Glyph's OBJECT is an integer for glyphs inserted by the
+            display engine for its internal purposes, like truncation
+            and continuation glyphs and blanks beyond the end of
+            line's text on text terminals.  If we are over such a
+            glyph, we are not over any text.  */
+         || INTEGERP (glyph->object)
+         /* R2L rows have a stretch glyph at their front, which
+            stands for no text, whereas L2R rows have no glyphs at
+            all beyond the end of text.  Treat such stretch glyphs
+            like we do with NULL glyphs in L2R rows.  */
+         || (MATRIX_ROW (w->current_matrix, vpos)->reversed_p
+             && glyph == MATRIX_ROW (w->current_matrix, vpos)->glyphs[TEXT_AREA]
+             && glyph->type == STRETCH_GLYPH
+             && glyph->avoid_cursor_p))
+       {
+         if (clear_mouse_face (hlinfo))
            cursor = No_Cursor;
-         if (NILP (pointer))
+#ifdef HAVE_WINDOW_SYSTEM
+         if (FRAME_WINDOW_P (f) && NILP (pointer))
            {
              if (area != TEXT_AREA)
                cursor = FRAME_X_OUTPUT (f)->nontext_cursor;
              else
                pointer = Vvoid_text_area_pointer;
            }
+#endif
          goto set_cursor;
        }
 
@@ -24593,14 +25582,7 @@ note_mouse_highlight (struct frame *f, int x, int y)
       else
        noverlays = 0;
 
-      same_region = (EQ (window, dpyinfo->mouse_face_window)
-                    && vpos >= dpyinfo->mouse_face_beg_row
-                    && vpos <= dpyinfo->mouse_face_end_row
-                    && (vpos > dpyinfo->mouse_face_beg_row
-                        || hpos >= dpyinfo->mouse_face_beg_col)
-                    && (vpos < dpyinfo->mouse_face_end_row
-                        || hpos < dpyinfo->mouse_face_end_col
-                        || dpyinfo->mouse_face_past_end));
+      same_region = coords_in_mouse_face_p (w, hpos, vpos);
 
       if (same_region)
        cursor = No_Cursor;
@@ -24611,8 +25593,8 @@ note_mouse_highlight (struct frame *f, int x, int y)
             the one we are currently highlighting, we have to
             check if we enter the overlapping overlay, and then
             highlight only that.  */
-         || (OVERLAYP (dpyinfo->mouse_face_overlay)
-             && mouse_face_overlay_overlaps (dpyinfo->mouse_face_overlay)))
+         || (OVERLAYP (hlinfo->mouse_face_overlay)
+             && mouse_face_overlay_overlaps (hlinfo->mouse_face_overlay)))
        {
          /* Find the highest priority overlay with a mouse-face.  */
          overlay = Qnil;
@@ -24625,12 +25607,12 @@ note_mouse_highlight (struct frame *f, int x, int y)
 
          /* 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))
+         if (!NILP (overlay) && EQ (overlay, hlinfo->mouse_face_overlay))
            goto check_help_echo;
-         dpyinfo->mouse_face_overlay = overlay;
+         hlinfo->mouse_face_overlay = overlay;
 
          /* Clear the display of the old active region, if any.  */
-         if (clear_mouse_face (dpyinfo))
+         if (clear_mouse_face (hlinfo))
            cursor = No_Cursor;
 
          /* If no overlay applies, get a text property.  */
@@ -24654,23 +25636,14 @@ note_mouse_highlight (struct frame *f, int x, int y)
                b = make_number (0);
              if (NILP (e))
                e = make_number (SCHARS (object) - 1);
-
-             fast_find_string_pos (w, XINT (b), object,
-                                   &dpyinfo->mouse_face_beg_col,
-                                   &dpyinfo->mouse_face_beg_row,
-                                   &dpyinfo->mouse_face_beg_x,
-                                   &dpyinfo->mouse_face_beg_y, 0);
-             fast_find_string_pos (w, XINT (e), object,
-                                   &dpyinfo->mouse_face_end_col,
-                                   &dpyinfo->mouse_face_end_row,
-                                   &dpyinfo->mouse_face_end_x,
-                                   &dpyinfo->mouse_face_end_y, 1);
-             dpyinfo->mouse_face_past_end = 0;
-             dpyinfo->mouse_face_window = window;
-             dpyinfo->mouse_face_face_id
+             mouse_face_from_string_pos (w, hlinfo, object,
+                                         XINT (b), XINT (e));
+             hlinfo->mouse_face_past_end = 0;
+             hlinfo->mouse_face_window = window;
+             hlinfo->mouse_face_face_id
                = face_at_string_position (w, object, pos, 0, 0, 0, &ignore,
                                           glyph->face_id, 1);
-             show_mouse_face (dpyinfo, DRAW_MOUSE_FACE);
+             show_mouse_face (hlinfo, DRAW_MOUSE_FACE);
              cursor = No_Cursor;
            }
          else
@@ -24684,7 +25657,7 @@ note_mouse_highlight (struct frame *f, int x, int y)
                  /* 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);
+                 EMACS_INT start = MATRIX_ROW_START_CHARPOS (r);
                  pos = string_buffer_position (w, object, start);
                  if (pos > 0)
                    {
@@ -24704,17 +25677,33 @@ note_mouse_highlight (struct frame *f, int x, int y)
                {
                  Lisp_Object before, after;
                  Lisp_Object before_string, after_string;
+                 /* To correctly find the limits of mouse highlight
+                    in a bidi-reordered buffer, we must not use the
+                    optimization of limiting the search in
+                    previous-single-property-change and
+                    next-single-property-change, because
+                    rows_from_pos_range needs the real start and end
+                    positions to DTRT in this case.  That's because
+                    the first row visible in a window does not
+                    necessarily display the character whose position
+                    is the smallest.  */
+                 Lisp_Object lim1 =
+                   NILP (XBUFFER (buffer)->bidi_display_reordering)
+                   ? Fmarker_position (w->start)
+                   : Qnil;
+                 Lisp_Object lim2 =
+                   NILP (XBUFFER (buffer)->bidi_display_reordering)
+                   ? make_number (BUF_Z (XBUFFER (buffer))
+                                  - XFASTINT (w->window_end_pos))
+                   : Qnil;
 
                  if (NILP (overlay))
                    {
                      /* Handle the text property case.  */
                      before = Fprevious_single_property_change
-                       (make_number (pos + 1), Qmouse_face, buffer,
-                        Fmarker_position (w->start));
+                       (make_number (pos + 1), Qmouse_face, buffer, lim1);
                      after = Fnext_single_property_change
-                       (make_number (pos), Qmouse_face, buffer,
-                        make_number (BUF_Z (XBUFFER (buffer))
-                                     - XFASTINT (w->window_end_pos)));
+                       (make_number (pos), Qmouse_face, buffer, lim2);
                      before_string = after_string = Qnil;
                    }
                  else
@@ -24729,7 +25718,7 @@ note_mouse_highlight (struct frame *f, int x, int y)
                      if (!STRINGP (after_string))  after_string = Qnil;
                    }
 
-                 mouse_face_from_buffer_pos (window, dpyinfo, pos,
+                 mouse_face_from_buffer_pos (window, hlinfo, pos,
                                              XFASTINT (before),
                                              XFASTINT (after),
                                              before_string, after_string,
@@ -24763,7 +25752,7 @@ note_mouse_highlight (struct frame *f, int x, int y)
        else
          {
            Lisp_Object object = glyph->object;
-           int charpos = glyph->charpos;
+           EMACS_INT charpos = glyph->charpos;
 
            /* Try text properties.  */
            if (STRINGP (object)
@@ -24778,7 +25767,7 @@ note_mouse_highlight (struct frame *f, int x, int y)
                       see if the buffer text ``under'' it does.  */
                    struct glyph_row *r
                      = MATRIX_ROW (w->current_matrix, vpos);
-                   int start = MATRIX_ROW_START_CHARPOS (r);
+                   EMACS_INT start = MATRIX_ROW_START_CHARPOS (r);
                    EMACS_INT pos = string_buffer_position (w, object, start);
                    if (pos > 0)
                      {
@@ -24808,8 +25797,9 @@ note_mouse_highlight (struct frame *f, int x, int y)
          }
       }
 
+#ifdef HAVE_WINDOW_SYSTEM
       /* Look for a `pointer' property.  */
-      if (NILP (pointer))
+      if (FRAME_WINDOW_P (f) && NILP (pointer))
        {
          /* Check overlays first.  */
          for (i = noverlays - 1; i >= 0 && NILP (pointer); --i)
@@ -24818,7 +25808,7 @@ note_mouse_highlight (struct frame *f, int x, int y)
          if (NILP (pointer))
            {
              Lisp_Object object = glyph->object;
-             int charpos = glyph->charpos;
+             EMACS_INT charpos = glyph->charpos;
 
              /* Try text properties.  */
              if (STRINGP (object)
@@ -24833,7 +25823,7 @@ note_mouse_highlight (struct frame *f, int x, int y)
                         see if the buffer text ``under'' it does.  */
                      struct glyph_row *r
                        = MATRIX_ROW (w->current_matrix, vpos);
-                     int start = MATRIX_ROW_START_CHARPOS (r);
+                     EMACS_INT start = MATRIX_ROW_START_CHARPOS (r);
                      EMACS_INT pos = string_buffer_position (w, object,
                                                              start);
                      if (pos > 0)
@@ -24848,6 +25838,7 @@ note_mouse_highlight (struct frame *f, int x, int y)
                                              Qpointer, object);
            }
        }
+#endif /* HAVE_WINDOW_SYSTEM */
 
       BEGV = obegv;
       ZV = ozv;
@@ -24856,7 +25847,14 @@ note_mouse_highlight (struct frame *f, int x, int y)
 
  set_cursor:
 
-  define_frame_cursor1 (f, cursor, pointer);
+#ifdef HAVE_WINDOW_SYSTEM
+  if (FRAME_WINDOW_P (f))
+    define_frame_cursor1 (f, cursor, pointer);
+#else
+  /* This is here to prevent a compiler error, about "label at end of
+     compound statement".  */
+  return;
+#endif
 }
 
 
@@ -24868,13 +25866,13 @@ note_mouse_highlight (struct frame *f, int x, int y)
 void
 x_clear_window_mouse_face (struct window *w)
 {
-  Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (XFRAME (w->frame));
+  Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (XFRAME (w->frame));
   Lisp_Object window;
 
   BLOCK_INPUT;
   XSETWINDOW (window, w);
-  if (EQ (window, dpyinfo->mouse_face_window))
-    clear_mouse_face (dpyinfo);
+  if (EQ (window, hlinfo->mouse_face_window))
+    clear_mouse_face (hlinfo);
   UNBLOCK_INPUT;
 }
 
@@ -24887,20 +25885,18 @@ void
 cancel_mouse_face (struct frame *f)
 {
   Lisp_Object window;
-  Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
+  Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
 
-  window = dpyinfo->mouse_face_window;
+  window = hlinfo->mouse_face_window;
   if (! NILP (window) && XFRAME (XWINDOW (window)->frame) == f)
     {
-      dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
-      dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
-      dpyinfo->mouse_face_window = Qnil;
+      hlinfo->mouse_face_beg_row = hlinfo->mouse_face_beg_col = -1;
+      hlinfo->mouse_face_end_row = hlinfo->mouse_face_end_col = -1;
+      hlinfo->mouse_face_window = Qnil;
     }
 }
 
 
-#endif /* HAVE_WINDOW_SYSTEM */
-
 \f
 /***********************************************************************
                           Exposure Events
@@ -25357,12 +26353,12 @@ expose_frame (struct frame *f, int x, int y, int w, int h)
      focus-follows-mouse with delayed raise.  --jason 2001-10-12  */
   if (mouse_face_overwritten_p && !FRAME_GARBAGED_P (f))
     {
-      Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
-      if (f == dpyinfo->mouse_face_mouse_frame)
+      Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
+      if (f == hlinfo->mouse_face_mouse_frame)
        {
-         int x = dpyinfo->mouse_face_mouse_x;
-         int y = dpyinfo->mouse_face_mouse_y;
-         clear_mouse_face (dpyinfo);
+         int x = hlinfo->mouse_face_mouse_x;
+         int y = hlinfo->mouse_face_mouse_y;
+         clear_mouse_face (hlinfo);
          note_mouse_highlight (f, x, y);
        }
     }
@@ -25949,7 +26945,9 @@ the frame's other specifications determine how to blink the cursor off.  */);
   Vblink_cursor_alist = Qnil;
 
   DEFVAR_BOOL ("auto-hscroll-mode", &automatic_hscrolling_p,
-    doc: /* *Non-nil means scroll the display automatically to make point visible.  */);
+    doc: /* Allow or disallow automatic horizontal scrolling of windows.
+If non-nil, windows are automatically scrolled horizontally to make
+point visible.  */);
   automatic_hscrolling_p = 1;
   Qauto_hscroll_mode = intern_c_string ("auto-hscroll-mode");
   staticpro (&Qauto_hscroll_mode);
@@ -26064,16 +27062,46 @@ baseline.  The default value is 1.  */);
   underline_minimum_offset = 1;
 
   DEFVAR_BOOL ("display-hourglass", &display_hourglass_p,
-              doc: /* Non-zero means Emacs displays an hourglass pointer on window systems.  */);
+              doc: /* Non-nil means show an hourglass pointer, when Emacs is busy.
+This feature only works when on a window system that can change
+cursor shapes.  */);
   display_hourglass_p = 1;
 
   DEFVAR_LISP ("hourglass-delay", &Vhourglass_delay,
-              doc: /* *Seconds to wait before displaying an hourglass pointer.
-Value must be an integer or float.  */);
+              doc: /* *Seconds to wait before displaying an hourglass pointer when Emacs is busy.  */);
   Vhourglass_delay = make_number (DEFAULT_HOURGLASS_DELAY);
 
   hourglass_atimer = NULL;
   hourglass_shown_p = 0;
+
+  DEFSYM (Qglyphless_char, "glyphless-char");
+  DEFSYM (Qhex_code, "hex-code");
+  DEFSYM (Qempty_box, "empty-box");
+  DEFSYM (Qthin_space, "thin-space");
+  DEFSYM (Qzero_width, "zero-width");
+
+  DEFSYM (Qglyphless_char_display, "glyphless-char-display");
+  /* Intern this now in case it isn't already done.
+     Setting this variable twice is harmless.
+     But don't staticpro it here--that is done in alloc.c.  */
+  Qchar_table_extra_slots = intern_c_string ("char-table-extra-slots");
+  Fput (Qglyphless_char_display, Qchar_table_extra_slots, make_number (1));
+
+  DEFVAR_LISP ("glyphless-char-display", &Vglyphless_char_display,
+              doc: /* Char-table to control displaying of glyphless characters.
+Each element, if non-nil, is an ASCII acronym string (displayed in a box)
+or one of these symbols:
+  hex-code:   display the hexadecimal code of a character in a box
+  empty-box:  display as an empty box
+  thin-space: display as 1-pixel width space
+  zero-width: don't display
+
+It has one extra slot to control the display of a character for which
+no font is found.  The value of the slot is `hex-code' or `empty-box'.
+The default is `empty-box'.  */);
+  Vglyphless_char_display = Fmake_char_table (Qglyphless_char_display, Qnil);
+  Fset_char_table_extra_slot (Vglyphless_char_display, make_number (0),
+                             Qempty_box);
 }
 
 
@@ -26191,5 +27219,3 @@ cancel_hourglass (void)
 }
 #endif /* ! WINDOWSNT  */
 
-/* arch-tag: eacc864d-bb6a-4b74-894a-1a4399a1358b
-   (do not change this comment) */