Have nobreak-char-display handle U+2010 and U+2011.
[bpt/emacs.git] / src / xdisp.c
index 1716cc8..7576361 100644 (file)
@@ -606,7 +606,7 @@ int current_mode_line_height, current_header_line_height;
     if (CACHE)                                 \
       bidi_unshelve_cache (CACHE, 1);          \
     ITCOPY = ITORIG;                           \
-    CACHE = bidi_shelve_cache();               \
+    CACHE = bidi_shelve_cache ();              \
   } while (0)
 
 #define RESTORE_IT(pITORIG,pITCOPY,CACHE)      \
@@ -1210,6 +1210,34 @@ line_bottom_y (struct it *it)
   return line_top_y + line_height;
 }
 
+/* Subroutine of pos_visible_p below.  Extracts a display string, if
+   any, from the display spec given as its argument.  */
+static Lisp_Object
+string_from_display_spec (Lisp_Object spec)
+{
+  if (CONSP (spec))
+    {
+      while (CONSP (spec))
+       {
+         if (STRINGP (XCAR (spec)))
+           return XCAR (spec);
+         spec = XCDR (spec);
+       }
+    }
+  else if (VECTORP (spec))
+    {
+      ptrdiff_t i;
+
+      for (i = 0; i < ASIZE (spec); i++)
+       {
+         if (STRINGP (AREF (spec, i)))
+           return AREF (spec, i);
+       }
+      return Qnil;
+    }
+
+  return spec;
+}
 
 /* Return 1 if position CHARPOS is visible in window W.
    CHARPOS < 0 means return info about WINDOW_END position.
@@ -1304,6 +1332,136 @@ pos_visible_p (struct window *w, EMACS_INT charpos, int *x, int *y,
                    }
                }
            }
+         else if (IT_CHARPOS (it) != charpos)
+           {
+             Lisp_Object cpos = make_number (charpos);
+             Lisp_Object spec = Fget_char_property (cpos, Qdisplay, Qnil);
+             Lisp_Object string = string_from_display_spec (spec);
+             int newline_in_string = 0;
+
+             if (STRINGP (string))
+               {
+                 const char *s = SSDATA (string);
+                 const char *e = s + SBYTES (string);
+                 while (s < e)
+                   {
+                     if (*s++ == '\n')
+                       {
+                         newline_in_string = 1;
+                         break;
+                       }
+                   }
+               }
+             /* The tricky code below is needed because there's a
+                discrepancy between move_it_to and how we set cursor
+                when the display line ends in a newline from a
+                display string.  move_it_to will stop _after_ such
+                display strings, whereas set_cursor_from_row
+                conspires with cursor_row_p to place the cursor on
+                the first glyph produced from the display string.  */
+
+             /* We have overshoot PT because it is covered by a
+                display property whose value is a string.  If the
+                string includes embedded newlines, we are also in the
+                wrong display line.  Backtrack to the correct line,
+                where the display string begins.  */
+             if (newline_in_string)
+               {
+                 Lisp_Object startpos, endpos;
+                 EMACS_INT start, end;
+                 struct it it3;
+
+                 /* Find the first and the last buffer positions
+                    covered by the display string.  */
+                 endpos =
+                   Fnext_single_char_property_change (cpos, Qdisplay,
+                                                      Qnil, Qnil);
+                 startpos =
+                   Fprevious_single_char_property_change (endpos, Qdisplay,
+                                                          Qnil, Qnil);
+                 start = XFASTINT (startpos);
+                 end = XFASTINT (endpos);
+                 /* Move to the last buffer position before the
+                    display property.  */
+                 start_display (&it3, w, top);
+                 move_it_to (&it3, start - 1, -1, -1, -1, MOVE_TO_POS);
+                 /* Move forward one more line if the position before
+                    the display string is a newline or if it is the
+                    rightmost character on a line that is
+                    continued or word-wrapped.  */
+                 if (it3.method == GET_FROM_BUFFER
+                     && it3.c == '\n')
+                   move_it_by_lines (&it3, 1);
+                 else if (move_it_in_display_line_to (&it3, -1,
+                                                      it3.current_x
+                                                      + it3.pixel_width,
+                                                      MOVE_TO_X)
+                          == MOVE_LINE_CONTINUED)
+                   {
+                     move_it_by_lines (&it3, 1);
+                     /* When we are under word-wrap, the #$@%!
+                        move_it_by_lines moves 2 lines, so we need to
+                        fix that up.  */
+                     if (it3.line_wrap == WORD_WRAP)
+                       move_it_by_lines (&it3, -1);
+                   }
+
+                 /* Record the vertical coordinate of the display
+                    line where we wound up.  */
+                 top_y = it3.current_y;
+                 if (it3.bidi_p)
+                   {
+                     /* When characters are reordered for display,
+                        the character displayed to the left of the
+                        display string could be _after_ the display
+                        property in the logical order.  Use the
+                        smallest vertical position of these two.  */
+                     start_display (&it3, w, top);
+                     move_it_to (&it3, end + 1, -1, -1, -1, MOVE_TO_POS);
+                     if (it3.current_y < top_y)
+                       top_y = it3.current_y;
+                   }
+                 /* Move from the top of the window to the beginning
+                    of the display line where the display string
+                    begins.  */
+                 start_display (&it3, w, top);
+                 move_it_to (&it3, -1, 0, top_y, -1, MOVE_TO_X | MOVE_TO_Y);
+                 /* Finally, advance the iterator until we hit the
+                    first display element whose character position is
+                    CHARPOS, or until the first newline from the
+                    display string, which signals the end of the
+                    display line.  */
+                 while (get_next_display_element (&it3))
+                   {
+                     PRODUCE_GLYPHS (&it3);
+                     if (IT_CHARPOS (it3) == charpos
+                         || ITERATOR_AT_END_OF_LINE_P (&it3))
+                       break;
+                     set_iterator_to_next (&it3, 0);
+                   }
+                 top_x = it3.current_x - it3.pixel_width;
+                 /* Normally, we would exit the above loop because we
+                    found the display element whose character
+                    position is CHARPOS.  For the contingency that we
+                    didn't, and stopped at the first newline from the
+                    display string, move back over the glyphs
+                    prfoduced from the string, until we find the
+                    rightmost glyph not from the string.  */
+                 if (IT_CHARPOS (it3) != charpos && EQ (it3.object, string))
+                   {
+                     struct glyph *g = it3.glyph_row->glyphs[TEXT_AREA]
+                                       + it3.glyph_row->used[TEXT_AREA];
+
+                     while (EQ ((g - 1)->object, string))
+                       {
+                         --g;
+                         top_x -= g->pixel_width;
+                       }
+                     xassert (g < it3.glyph_row->glyphs[TEXT_AREA]
+                                   + it3.glyph_row->used[TEXT_AREA]);
+                   }
+               }
+           }
 
          *x = top_x;
          *y = max (top_y + max (0, it.max_ascent - it.ascent), window_top_y);
@@ -1916,7 +2074,7 @@ get_phys_cursor_geometry (struct window *w, struct glyph_row *row,
      rectangle as wide as the glyph, but use a canonical character
      width instead.  */
   wd = glyph->pixel_width - 1;
-#if defined(HAVE_NTGUI) || defined(HAVE_NS)
+#if defined (HAVE_NTGUI) || defined (HAVE_NS)
   wd++; /* Why? */
 #endif
 
@@ -3132,9 +3290,9 @@ next_overlay_change (EMACS_INT pos)
 }
 
 /* How many characters forward to search for a display property or
-   display string.  Enough for a screenful of 100 lines x 50
-   characters in a line.  */
-#define MAX_DISP_SCAN 5000
+   display string.  Searching too far forward makes the bidi display
+   sluggish, especially in small windows.  */
+#define MAX_DISP_SCAN 250
 
 /* Return the character position of a display string at or after
    position specified by POSITION.  If no display string exists at or
@@ -3228,9 +3386,10 @@ compute_display_string_pos (struct text_pos *position,
 }
 
 /* Return the character position of the end of the display string that
-   started at CHARPOS.  A display string is either an overlay with
-   `display' property whose value is a string or a `display' text
-   property whose value is a string.  */
+   started at CHARPOS.  If there's no display string at CHARPOS,
+   return -1.  A display string is either an overlay with `display'
+   property whose value is a string or a `display' text property whose
+   value is a string.  */
 EMACS_INT
 compute_display_string_end (EMACS_INT charpos, struct bidi_string_data *string)
 {
@@ -3244,8 +3403,22 @@ compute_display_string_end (EMACS_INT charpos, struct bidi_string_data *string)
   if (charpos >= eob || (string->s && !STRINGP (object)))
     return eob;
 
+  /* It could happen that the display property or overlay was removed
+     since we found it in compute_display_string_pos above.  One way
+     this can happen is if JIT font-lock was called (through
+     handle_fontified_prop), and jit-lock-functions remove text
+     properties or overlays from the portion of buffer that includes
+     CHARPOS.  Muse mode is known to do that, for example.  In this
+     case, we return -1 to the caller, to signal that no display
+     string is actually present at CHARPOS.  See bidi_fetch_char for
+     how this is handled.
+
+     An alternative would be to never look for display properties past
+     it->stop_charpos.  But neither compute_display_string_pos nor
+     bidi_fetch_char that calls it know or care where the next
+     stop_charpos is.  */
   if (NILP (Fget_char_property (pos, Qdisplay, object)))
-    abort ();
+    return -1;
 
   /* Look forward for the first character where the `display' property
      changes.  */
@@ -3898,40 +4071,67 @@ handle_invisible_prop (struct it *it)
          /* The position newpos is now either ZV or on visible text.  */
          if (it->bidi_p && newpos < ZV)
            {
-             /* With bidi iteration, the region of invisible text
-                could start and/or end in the middle of a non-base
-                embedding level.  Therefore, we need to skip
-                invisible text using the bidi iterator, starting at
-                IT's current position, until we find ourselves
-                outside the invisible text.  Skipping invisible text
-                _after_ bidi iteration avoids affecting the visual
-                order of the displayed text when invisible properties
-                are added or removed.  */
-             if (it->bidi_it.first_elt && it->bidi_it.charpos < ZV)
+             EMACS_INT bpos = CHAR_TO_BYTE (newpos);
+
+             if (FETCH_BYTE (bpos) == '\n'
+                 || (newpos > BEGV && FETCH_BYTE (bpos - 1) == '\n'))
                {
-                 /* If we were `reseat'ed to a new paragraph,
-                    determine the paragraph base direction.  We need
-                    to do it now because next_element_from_buffer may
-                    not have a chance to do it, if we are going to
-                    skip any text at the beginning, which resets the
-                    FIRST_ELT flag.  */
-                 bidi_paragraph_init (it->paragraph_embedding,
-                                      &it->bidi_it, 1);
+                 /* If the invisible text ends on a newline or the
+                    character after a newline, we can avoid the
+                    costly, character by character, bidi iteration to
+                    newpos, and instead simply reseat the iterator
+                    there.  That's because all bidi reordering
+                    information is tossed at the newline.  This is a
+                    big win for modes that hide complete lines, like
+                    Outline, Org, etc.  (Implementation note: the
+                    call to reseat_1 is necessary, because it signals
+                    to the bidi iterator that it needs to reinit its
+                    internal information when the next element for
+                    display is requested.  */
+                 struct text_pos tpos;
+
+                 SET_TEXT_POS (tpos, newpos, bpos);
+                 reseat_1 (it, tpos, 0);
                }
-             do
+             else      /* Must use the slow method.  */
                {
-                 bidi_move_to_visually_next (&it->bidi_it);
+                 /* With bidi iteration, the region of invisible text
+                    could start and/or end in the middle of a
+                    non-base embedding level.  Therefore, we need to
+                    skip invisible text using the bidi iterator,
+                    starting at IT's current position, until we find
+                    ourselves outside the invisible text.  Skipping
+                    invisible text _after_ bidi iteration avoids
+                    affecting the visual order of the displayed text
+                    when invisible properties are added or
+                    removed.  */
+                 if (it->bidi_it.first_elt && it->bidi_it.charpos < ZV)
+                   {
+                     /* If we were `reseat'ed to a new paragraph,
+                        determine the paragraph base direction.  We
+                        need to do it now because
+                        next_element_from_buffer may not have a
+                        chance to do it, if we are going to skip any
+                        text at the beginning, which resets the
+                        FIRST_ELT flag.  */
+                     bidi_paragraph_init (it->paragraph_embedding,
+                                          &it->bidi_it, 1);
+                   }
+                 do
+                   {
+                     bidi_move_to_visually_next (&it->bidi_it);
+                   }
+                 while (it->stop_charpos <= it->bidi_it.charpos
+                        && it->bidi_it.charpos < newpos);
+                 IT_CHARPOS (*it) = it->bidi_it.charpos;
+                 IT_BYTEPOS (*it) = it->bidi_it.bytepos;
+                 /* If we overstepped NEWPOS, record its position in
+                    the iterator, so that we skip invisible text if
+                    later the bidi iteration lands us in the
+                    invisible region again. */
+                 if (IT_CHARPOS (*it) >= newpos)
+                   it->prev_stop = newpos;
                }
-             while (it->stop_charpos <= it->bidi_it.charpos
-                    && it->bidi_it.charpos < newpos);
-             IT_CHARPOS (*it) = it->bidi_it.charpos;
-             IT_BYTEPOS (*it) = it->bidi_it.bytepos;
-             /* If we overstepped NEWPOS, record its position in the
-                iterator, so that we skip invisible text if later the
-                bidi iteration lands us in the invisible region
-                again. */
-             if (IT_CHARPOS (*it) >= newpos)
-               it->prev_stop = newpos;
            }
          else
            {
@@ -5459,7 +5659,8 @@ pop_it (struct it *it)
                && IT_BYTEPOS (*it) == it->bidi_it.bytepos)
               || (STRINGP (it->object)
                   && IT_STRING_CHARPOS (*it) == it->bidi_it.charpos
-                  && IT_STRING_BYTEPOS (*it) == it->bidi_it.bytepos));
+                  && IT_STRING_BYTEPOS (*it) == it->bidi_it.bytepos)
+              || (CONSP (it->object) && it->method == GET_FROM_STRETCH));
     }
 }
 
@@ -6170,8 +6371,8 @@ get_next_display_element (struct it *it)
        {
          Lisp_Object dv;
          struct charset *unibyte = CHARSET_FROM_ID (charset_unibyte);
-         enum { char_is_other = 0, char_is_nbsp, char_is_soft_hyphen }
-         nbsp_or_shy = char_is_other;
+         int nonascii_space_p = 0;
+         int nonascii_hyphen_p = 0;
          int c = it->c;        /* This is the character to display.  */
 
          if (! it->multibyte_p && ! ASCII_CHAR_P (c))
@@ -6223,10 +6424,15 @@ get_next_display_element (struct it *it)
              goto get_next;
            }
 
+         /* If `nobreak-char-display' is non-nil, we display
+            non-ASCII spaces and hyphens specially.  */
          if (! ASCII_CHAR_P (c) && ! NILP (Vnobreak_char_display))
-           nbsp_or_shy = (c == 0xA0   ? char_is_nbsp
-                          : c == 0xAD ? char_is_soft_hyphen
-                          :             char_is_other);
+           {
+             if (c == 0xA0)
+               nonascii_space_p = 1;
+             else if (c == 0xAD || c == 0x2010 || c == 0x2011)
+               nonascii_hyphen_p = 1;
+           }
 
          /* Translate control characters into `\003' or `^C' form.
             Control characters coming from a display table entry are
@@ -6234,7 +6440,8 @@ get_next_display_element (struct it *it)
             the translation.  This could easily be changed but I
             don't believe that it is worth doing.
 
-            NBSP and SOFT-HYPEN are property translated too.
+            The characters handled by `nobreak-char-display' must be
+            translated too.
 
             Non-printable characters and raw-byte characters are also
             translated to octal form.  */
@@ -6245,14 +6452,15 @@ get_next_display_element (struct it *it)
                      && it->glyph_row
                      && (it->glyph_row->mode_line_p || it->avoid_cursor_p))
                  || (c != '\n' && c != '\t'))
-              : (nbsp_or_shy
+              : (nonascii_space_p
+                 || nonascii_hyphen_p
                  || CHAR_BYTE8_P (c)
                  || ! CHAR_PRINTABLE_P (c))))
            {
-             /* C is a control character, NBSP, SOFT-HYPEN, raw-byte,
-                or a non-printable character which must be displayed
-                either as '\003' or as `^C' where the '\\' and '^'
-                can be defined in the display table.  Fill
+             /* C is a control character, non-ASCII space/hyphen,
+                raw-byte, or a non-printable character which must be
+                displayed either as '\003' or as `^C' where the '\\'
+                and '^' can be defined in the display table.  Fill
                 IT->ctl_chars with glyphs for what we have to
                 display.  Then, set IT->dpvec to these glyphs.  */
              Lisp_Object gc;
@@ -6301,17 +6509,14 @@ get_next_display_element (struct it *it)
                  goto display_control;
                }
 
-             /* Handle non-break space in the mode where it only gets
+             /* Handle non-ascii space in the mode where it only gets
                 highlighting.  */
 
-             if (EQ (Vnobreak_char_display, Qt)
-                 && nbsp_or_shy == char_is_nbsp)
+             if (nonascii_space_p && EQ (Vnobreak_char_display, Qt))
                {
-                 /* Merge the no-break-space face into the current face.  */
+                 /* Merge `nobreak-space' into the current face.  */
                  face_id = merge_faces (it->f, Qnobreak_space, 0,
                                         it->face_id);
-
-                 c = ' ';
                  XSETINT (it->ctl_chars[0], ' ');
                  ctl_len = 1;
                  goto display_control;
@@ -6351,25 +6556,21 @@ get_next_display_element (struct it *it)
                  last_escape_glyph_merged_face_id = face_id;
                }
 
-             /* Handle soft hyphens in the mode where they only get
-                highlighting.  */
+             /* Draw non-ASCII hyphen with just highlighting: */
 
-             if (EQ (Vnobreak_char_display, Qt)
-                 && nbsp_or_shy == char_is_soft_hyphen)
+             if (nonascii_hyphen_p && EQ (Vnobreak_char_display, Qt))
                {
                  XSETINT (it->ctl_chars[0], '-');
                  ctl_len = 1;
                  goto display_control;
                }
 
-             /* Handle non-break space and soft hyphen
-                with the escape glyph.  */
+             /* Draw non-ASCII space/hyphen with escape glyph: */
 
-             if (nbsp_or_shy)
+             if (nonascii_space_p || nonascii_hyphen_p)
                {
                  XSETINT (it->ctl_chars[0], escape_glyph);
-                 c = (nbsp_or_shy == char_is_nbsp ? ' ' : '-');
-                 XSETINT (it->ctl_chars[1], c);
+                 XSETINT (it->ctl_chars[1], nonascii_space_p ? ' ' : '-');
                  ctl_len = 2;
                  goto display_control;
                }
@@ -6441,6 +6642,8 @@ get_next_display_element (struct it *it)
 
              c = ' ';
              for (i = 0; i < cmp->glyph_len; i++)
+               /* TAB in a composition means display glyphs with
+                  padding space on the left or right.  */
                if ((c = COMPOSITION_GLYPH (cmp, i)) != '\t')
                  break;
            }
@@ -6945,7 +7148,6 @@ get_visually_first_element (struct it *it)
     }
   else if (it->bidi_it.charpos == bob
           || (!string_p
-              /* FIXME: Should support all Unicode line separators.  */
               && (FETCH_CHAR (it->bidi_it.bytepos - 1) == '\n'
                   || FETCH_CHAR (it->bidi_it.bytepos) == '\n')))
     {
@@ -7719,7 +7921,9 @@ move_it_in_display_line_to (struct it *it,
   ((op & MOVE_TO_POS) != 0                                     \
    && BUFFERP (it->object)                                     \
    && (IT_CHARPOS (*it) == to_charpos                          \
-       || (!it->bidi_p && IT_CHARPOS (*it) > to_charpos)       \
+       || ((!it->bidi_p                                                \
+           || BIDI_AT_BASE_LEVEL (it->bidi_it))                \
+          && IT_CHARPOS (*it) > to_charpos)                    \
        || (it->what == IT_COMPOSITION                          \
           && ((IT_CHARPOS (*it) > to_charpos                   \
                && to_charpos >= it->cmp_it.charpos)            \
@@ -7751,7 +7955,13 @@ move_it_in_display_line_to (struct it *it,
       if ((op & MOVE_TO_POS) != 0
          && BUFFERP (it->object)
          && it->method == GET_FROM_BUFFER
-         && ((!it->bidi_p && IT_CHARPOS (*it) > to_charpos)
+         && (((!it->bidi_p
+               /* When the iterator is at base embedding level, we
+                  are guaranteed that characters are delivered for
+                  display in strictly increasing order of their
+                  buffer positions.  */
+               || BIDI_AT_BASE_LEVEL (it->bidi_it))
+              && IT_CHARPOS (*it) > to_charpos)
              || (it->bidi_p
                  && (prev_method == GET_FROM_IMAGE
                      || prev_method == GET_FROM_STRETCH
@@ -8116,7 +8326,8 @@ move_it_in_display_line_to (struct it *it,
                      && !saw_smaller_pos
                      && IT_CHARPOS (*it) > to_charpos))
                {
-                 if (!at_eob_p && IT_CHARPOS (ppos_it) < ZV)
+                 if (it->bidi_p
+                     && !at_eob_p && IT_CHARPOS (ppos_it) < ZV)
                    RESTORE_IT (it, &ppos_it, ppos_data);
                  result = MOVE_POS_MATCH_OR_ZV;
                  break;
@@ -8517,7 +8728,16 @@ move_it_vertically_backward (struct it *it, int dy)
       move_it_to (&it2, start_pos, -1, -1, it2.vpos + 1,
                  MOVE_TO_POS | MOVE_TO_VPOS);
     }
-  while (!IT_POS_VALID_AFTER_MOVE_P (&it2));
+  while (!(IT_POS_VALID_AFTER_MOVE_P (&it2)
+          /* If we are in a display string which starts at START_POS,
+             and that display string includes a newline, and we are
+             right after that newline (i.e. at the beginning of a
+             display line), exit the loop, because otherwise we will
+             infloop, since move_it_to will see that it is already at
+             START_POS and will not move.  */
+          || (it2.method == GET_FROM_STRING
+              && IT_CHARPOS (it2) == start_pos
+              && SREF (it2.string, IT_STRING_BYTEPOS (it2) - 1) == '\n')));
   xassert (IT_CHARPOS (*it) >= BEGV);
   SAVE_IT (it3, it2, it3data);
 
@@ -8548,7 +8768,10 @@ move_it_vertically_backward (struct it *it, int dy)
         reordering.  We want to get to the character position
         that is immediately after the newline of the previous
         line.  */
-      if (it->bidi_p && IT_CHARPOS (*it) > BEGV
+      if (it->bidi_p
+         && !it->continuation_lines_width
+         && !STRINGP (it->string)
+         && IT_CHARPOS (*it) > BEGV
          && FETCH_BYTE (IT_BYTEPOS (*it) - 1) != '\n')
        {
          EMACS_INT nl_pos =
@@ -11844,6 +12067,7 @@ hscroll_window_tree (Lisp_Object window)
            = (desired_cursor_row->enabled_p
               ? desired_cursor_row
               : current_cursor_row);
+         int row_r2l_p = cursor_row->reversed_p;
 
          text_area_width = window_box_width (w, TEXT_AREA);
 
@@ -11851,11 +12075,31 @@ hscroll_window_tree (Lisp_Object window)
          h_margin = hscroll_margin * WINDOW_FRAME_COLUMN_WIDTH (w);
 
          if (!NILP (Fbuffer_local_value (Qauto_hscroll_mode, w->buffer))
-             && ((XFASTINT (w->hscroll)
-                  && w->cursor.x <= h_margin)
-                 || (cursor_row->enabled_p
-                     && cursor_row->truncated_on_right_p
-                     && (w->cursor.x >= text_area_width - h_margin))))
+             /* For left-to-right rows, hscroll when cursor is either
+                (i) inside the right hscroll margin, or (ii) if it is
+                inside the left margin and the window is already
+                hscrolled. */
+             && ((!row_r2l_p
+                  && ((XFASTINT (w->hscroll)
+                       && w->cursor.x <= h_margin)
+                      || (cursor_row->enabled_p
+                          && cursor_row->truncated_on_right_p
+                          && (w->cursor.x >= text_area_width - h_margin))))
+                 /* For right-to-left rows, the logic is similar,
+                    except that rules for scrolling to left and right
+                    are reversed.  E.g., if cursor.x <= h_margin, we
+                    need to hscroll "to the right" unconditionally,
+                    and that will scroll the screen to the left so as
+                    to reveal the next portion of the row.  */
+                 || (row_r2l_p
+                     && ((cursor_row->enabled_p
+                          /* FIXME: It is confusing to set the
+                             truncated_on_right_p flag when R2L rows
+                             are actually truncated on the left. */
+                          && cursor_row->truncated_on_right_p
+                          && w->cursor.x <= h_margin)
+                         || (XFASTINT (w->hscroll)
+                             && (w->cursor.x >= text_area_width - h_margin))))))
            {
              struct it it;
              int hscroll;
@@ -11890,7 +12134,9 @@ hscroll_window_tree (Lisp_Object window)
                                      ? (text_area_width - 4 * FRAME_COLUMN_WIDTH (it.f))
                                      : (text_area_width / 2))))
                          / FRAME_COLUMN_WIDTH (it.f);
-             else if (w->cursor.x >= text_area_width - h_margin)
+             else if ((!row_r2l_p
+                       && w->cursor.x >= text_area_width - h_margin)
+                      || (row_r2l_p && w->cursor.x <= h_margin))
                {
                  if (hscroll_relative_p)
                    wanted_x = text_area_width * (1 - hscroll_step_rel)
@@ -11915,9 +12161,9 @@ hscroll_window_tree (Lisp_Object window)
                }
              hscroll = max (hscroll, XFASTINT (w->min_hscroll));
 
-             /* Don't call Fset_window_hscroll if value hasn't
-                changed because it will prevent redisplay
-                optimizations.  */
+             /* Don't prevent redisplay optimizations if hscroll
+                hasn't changed, as it will unnecessarily slow down
+                redisplay.  */
              if (XFASTINT (w->hscroll) != hscroll)
                {
                  XBUFFER (w->buffer)->prevent_redisplay_optimizations_p = 1;
@@ -13630,19 +13876,7 @@ set_cursor_from_row (struct window *w, struct glyph_row *row,
              glyph--;
            }
        }
-      else if (match_with_avoid_cursor
-              /* 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)))
+      else if (match_with_avoid_cursor)
        {
          cursor = glyph_after;
          x = -1;
@@ -13661,6 +13895,17 @@ set_cursor_from_row (struct window *w, struct glyph_row *row,
 
          x = -1;
 
+         /* If the row ends in a newline from a display string,
+            reordering could have moved the glyphs belonging to the
+            string out of the [GLYPH_BEFORE..GLYPH_AFTER] range.  So
+            in this case we extend the search to the last glyph in
+            the row that was not inserted by redisplay.  */
+         if (row->ends_in_newline_from_string_p)
+           {
+             glyph_after = end;
+             pos_after = MATRIX_ROW_END_CHARPOS (row) + delta;
+           }
+
          /* GLYPH_BEFORE and GLYPH_AFTER are the glyphs that
             correspond to POS_BEFORE and POS_AFTER, respectively.  We
             need START and STOP in the order that corresponds to the
@@ -13772,6 +14017,26 @@ set_cursor_from_row (struct window *w, struct glyph_row *row,
              && row->continued_p)
            return 0;
        }
+      /* 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.  But if a
+        display string covers point, defer to the string-handling
+        code below to figure this out.  */
+      else if (row->truncated_on_left_p && pt_old < bpos_min)
+       {
+         cursor = glyph_before;
+         x = -1;
+       }
+      else if ((row->truncated_on_right_p && pt_old > bpos_max)
+              /* Zero-width characters produce no glyphs.  */
+              || (!empty_line_p
+                  && (row->reversed_p
+                      ? glyph_after > glyphs_end
+                      : glyph_after < glyphs_end)))
+       {
+         cursor = glyph_after;
+         x = -1;
+       }
     }
 
  compute_x:
@@ -14626,7 +14891,10 @@ try_cursor_movement (Lisp_Object window, struct text_pos startp, int *scroll_ste
                     is set, we are done.  */
                  at_zv_p =
                    MATRIX_ROW (w->current_matrix, w->cursor.vpos)->ends_at_zv_p;
-                 if (!at_zv_p)
+                 if (rv && !at_zv_p
+                     && w->cursor.hpos >= 0
+                     && w->cursor.hpos < MATRIX_ROW_USED (w->current_matrix,
+                                                          w->cursor.vpos))
                    {
                      struct glyph_row *candidate =
                        MATRIX_ROW (w->current_matrix, w->cursor.vpos);
@@ -16076,7 +16344,7 @@ try_window_reusing_current_matrix (struct window *w)
          if (row < bottom_row)
            {
              struct glyph *glyph = row->glyphs[TEXT_AREA] + w->cursor.hpos;
-             struct glyph *end = glyph + row->used[TEXT_AREA];
+             struct glyph *end = row->glyphs[TEXT_AREA] + row->used[TEXT_AREA];
 
              /* Can't use this optimization with bidi-reordered glyph
                 rows, unless cursor is already at point. */
@@ -16919,8 +17187,8 @@ try_window_id (struct window *w)
   {
     int this_scroll_margin, cursor_height;
 
-    this_scroll_margin = max (0, scroll_margin);
-    this_scroll_margin = min (this_scroll_margin, WINDOW_TOTAL_LINES (w) / 4);
+    this_scroll_margin =
+      max (0, min (scroll_margin, WINDOW_TOTAL_LINES (w) / 4));
     this_scroll_margin *= FRAME_LINE_HEIGHT (it.f);
     cursor_height = MATRIX_ROW (w->desired_matrix, w->cursor.vpos)->height;
 
@@ -18162,9 +18430,10 @@ static int
 push_display_prop (struct it *it, Lisp_Object prop)
 {
   struct text_pos pos =
-    (it->method == GET_FROM_STRING) ? it->current.string_pos : it->current.pos;
+    STRINGP (it->string) ? it->current.string_pos : it->current.pos;
 
   xassert (it->method == GET_FROM_BUFFER
+          || it->method == GET_FROM_DISPLAY_VECTOR
           || it->method == GET_FROM_STRING);
 
   /* We need to save the current buffer/string position, so it will be
@@ -18333,7 +18602,8 @@ find_row_edges (struct it *it, struct glyph_row *row,
      Line ends in a newline from buffer       eol_pos + 1
      Line is continued from buffer            max_pos + 1
      Line is truncated on right               it->current.pos
-     Line ends in a newline from string       max_pos
+     Line ends in a newline from string       max_pos + 1(*)
+      (*) + 1 only when line ends in a forward scan
      Line is continued from string            max_pos
      Line is continued from display vector    max_pos
      Line is entirely from a string           min_pos == max_pos
@@ -18346,8 +18616,81 @@ find_row_edges (struct it *it, struct glyph_row *row,
     row->maxpos = it->current.pos;
   else if (row->used[TEXT_AREA])
     {
-      if (row->ends_in_newline_from_string_p)
-       SET_TEXT_POS (row->maxpos, max_pos, max_bpos);
+      int seen_this_string = 0;
+      struct glyph_row *r1 = row - 1;
+
+      /* Did we see the same display string on the previous row?  */
+      if (STRINGP (it->object)
+         /* this is not the first row */
+         && row > it->w->desired_matrix->rows
+         /* previous row is not the header line */
+         && !r1->mode_line_p
+         /* previous row also ends in a newline from a string */
+         && r1->ends_in_newline_from_string_p)
+       {
+         struct glyph *start, *end;
+
+         /* Search for the last glyph of the previous row that came
+            from buffer or string.  Depending on whether the row is
+            L2R or R2L, we need to process it front to back or the
+            other way round.  */
+         if (!r1->reversed_p)
+           {
+             start = r1->glyphs[TEXT_AREA];
+             end = start + r1->used[TEXT_AREA];
+             /* Glyphs inserted by redisplay have an integer (zero)
+                as their object.  */
+             while (end > start
+                    && INTEGERP ((end - 1)->object)
+                    && (end - 1)->charpos <= 0)
+               --end;
+             if (end > start)
+               {
+                 if (EQ ((end - 1)->object, it->object))
+                   seen_this_string = 1;
+               }
+             else
+               /* If all the glyphs of the previous row were inserted
+                  by redisplay, it means the previous row was
+                  produced from a single newline, which is only
+                  possible if that newline came from the same string
+                  as the one which produced this ROW.  */
+               seen_this_string = 1;
+           }
+         else
+           {
+             end = r1->glyphs[TEXT_AREA] - 1;
+             start = end + r1->used[TEXT_AREA];
+             while (end < start
+                    && INTEGERP ((end + 1)->object)
+                    && (end + 1)->charpos <= 0)
+               ++end;
+             if (end < start)
+               {
+                 if (EQ ((end + 1)->object, it->object))
+                   seen_this_string = 1;
+               }
+             else
+               seen_this_string = 1;
+           }
+       }
+      /* Take note of each display string that covers a newline only
+        once, the first time we see it.  This is for when a display
+        string includes more than one newline in it.  */
+      if (row->ends_in_newline_from_string_p && !seen_this_string)
+       {
+         /* If we were scanning the buffer forward when we displayed
+            the string, we want to account for at least one buffer
+            position that belongs to this row (position covered by
+            the display string), so that cursor positioning will
+            consider this row as a candidate when point is at the end
+            of the visual line represented by this row.  This is not
+            required when scanning back, because max_pos will already
+            have a much larger value.  */
+         if (CHARPOS (row->end.pos) > max_pos)
+           INC_BOTH (max_pos, max_bpos);
+         SET_TEXT_POS (row->maxpos, max_pos, max_bpos);
+       }
       else if (CHARPOS (it->eol_pos) > 0)
        SET_TEXT_POS (row->maxpos,
                      CHARPOS (it->eol_pos) + 1, BYTEPOS (it->eol_pos) + 1);
@@ -18655,11 +18998,6 @@ display_line (struct it *it)
                      it->current_x = new_x;
                      it->continuation_lines_width += new_x;
                      ++it->hpos;
-                     /* Record the maximum and minimum buffer
-                        positions seen so far in glyphs that will be
-                        displayed by this row.  */
-                     if (it->bidi_p)
-                       RECORD_MAX_MIN_POS (it);
                      if (i == nglyphs - 1)
                        {
                          /* If line-wrap is on, check if a previous
@@ -18674,6 +19012,11 @@ display_line (struct it *it)
                                  || IT_DISPLAYING_WHITESPACE (it)))
                            goto back_to_wrap;
 
+                         /* Record the maximum and minimum buffer
+                            positions seen so far in glyphs that will be
+                            displayed by this row.  */
+                         if (it->bidi_p)
+                           RECORD_MAX_MIN_POS (it);
                          set_iterator_to_next (it, 1);
                          if (IT_OVERFLOW_NEWLINE_INTO_FRINGE (it))
                            {
@@ -18691,6 +19034,8 @@ display_line (struct it *it)
                                }
                            }
                        }
+                     else if (it->bidi_p)
+                       RECORD_MAX_MIN_POS (it);
                    }
                  else if (CHAR_GLYPH_PADDING_P (*glyph)
                           && !FRAME_WINDOW_P (it->f))
@@ -18821,6 +19166,10 @@ display_line (struct it *it)
                  xassert (it->first_visible_x <= it->last_visible_x);
                }
            }
+         /* Even if this display element produced no glyphs at all,
+            we want to record its position.  */
+         if (it->bidi_p && nglyphs == 0)
+           RECORD_MAX_MIN_POS (it);
 
          row->ascent = max (row->ascent, it->max_ascent);
          row->height = max (row->height, it->max_ascent + it->max_descent);
@@ -19111,6 +19460,7 @@ See also `bidi-paragraph-direction'.  */)
       EMACS_INT pos = BUF_PT (buf);
       EMACS_INT bytepos = BUF_PT_BYTE (buf);
       int c;
+      void *itb_data = bidi_shelve_cache ();
 
       set_buffer_temp (buf);
       /* bidi_paragraph_init finds the base direction of the paragraph
@@ -19123,27 +19473,28 @@ See also `bidi-paragraph-direction'.  */)
          pos--;
          bytepos = CHAR_TO_BYTE (pos);
        }
-      while ((c = FETCH_BYTE (bytepos)) == '\n'
-            || c == ' ' || c == '\t' || c == '\f')
+      if (fast_looking_at (build_string ("[\f\t ]*\n"),
+                          pos, bytepos, ZV, ZV_BYTE, Qnil) > 0)
        {
-         if (bytepos <= BEGV_BYTE)
-           break;
-         bytepos--;
-         pos--;
+         while ((c = FETCH_BYTE (bytepos)) == '\n'
+                || c == ' ' || c == '\t' || c == '\f')
+           {
+             if (bytepos <= BEGV_BYTE)
+               break;
+             bytepos--;
+             pos--;
+           }
+         while (!CHAR_HEAD_P (FETCH_BYTE (bytepos)))
+           bytepos--;
        }
-      while (!CHAR_HEAD_P (FETCH_BYTE (bytepos)))
-       bytepos--;
-      itb.charpos = pos;
-      itb.bytepos = bytepos;
-      itb.nchars = -1;
+      bidi_init_it (pos, bytepos, FRAME_WINDOW_P (SELECTED_FRAME ()), &itb);
+      itb.paragraph_dir = NEUTRAL_DIR;
       itb.string.s = NULL;
       itb.string.lstring = Qnil;
-      itb.frame_window_p = FRAME_WINDOW_P (SELECTED_FRAME ()); /* guesswork */
-      itb.first_elt = 1;
-      itb.separator_limit = -1;
-      itb.paragraph_dir = NEUTRAL_DIR;
-
+      itb.string.bufpos = 0;
+      itb.string.unibyte = 0;
       bidi_paragraph_init (NEUTRAL_DIR, &itb, 1);
+      bidi_unshelve_cache (itb_data, 0);
       set_buffer_temp (old);
       switch (itb.paragraph_dir)
        {
@@ -21292,7 +21643,7 @@ else if the text is replaced by an ellipsis.  */)
       ? XFLOATINT (X)                          \
       : - 1)
 
-int
+static int
 calc_pixel_width_or_height (double *res, struct it *it, Lisp_Object prop,
                            struct font *font, int width_p, int *align_to)
 {
@@ -21722,6 +22073,8 @@ fill_composite_glyph_string (struct glyph_string *s, struct face *base_face,
     {
       int c = COMPOSITION_GLYPH (s->cmp, i);
 
+      /* TAB in a composition means display glyphs with padding space
+        on the left or right.  */
       if (c != '\t')
        {
          int face_id = FACE_FOR_CHAR (s->f, base_face->ascii_face, c,
@@ -23236,7 +23589,14 @@ produce_stretch_glyph (struct it *it)
 
   if (width > 0 && it->line_wrap != TRUNCATE
       && it->current_x + width > it->last_visible_x)
-    width = it->last_visible_x - it->current_x - 1;
+    {
+      width = it->last_visible_x - it->current_x;
+#ifdef HAVE_WINDOW_SYSTEM
+      /* Subtact one more pixel from the stretch width, but only on
+        GUI frames, since on a TTY each glyph is one "pixel" wide.  */
+      width -= FRAME_WINDOW_P (it->f);
+#endif
+    }
 
   if (width > 0 && height > 0 && it->glyph_row)
     {
@@ -23248,13 +23608,7 @@ produce_stretch_glyph (struct it *it)
        object = it->w->buffer;
 #ifdef HAVE_WINDOW_SYSTEM
       if (FRAME_WINDOW_P (it->f))
-       {
-         append_stretch_glyph (it, object, width, height, ascent);
-         it->ascent = it->phys_ascent = ascent;
-         it->descent = it->phys_descent = height - it->ascent;
-         it->nglyphs = width > 0 && height > 0 ? 1 : 0;
-         take_vertical_position_into_account (it);
-       }
+       append_stretch_glyph (it, object, width, height, ascent);
       else
 #endif
        {
@@ -23264,9 +23618,21 @@ produce_stretch_glyph (struct it *it)
          while (n--)
            tty_append_glyph (it);
          it->object = o_object;
-         it->pixel_width = width;
        }
     }
+
+  it->pixel_width = width;
+#ifdef HAVE_WINDOW_SYSTEM
+  if (FRAME_WINDOW_P (it->f))
+    {
+      it->ascent = it->phys_ascent = ascent;
+      it->descent = it->phys_descent = height - it->ascent;
+      it->nglyphs = width > 0 && height > 0 ? 1 : 0;
+      take_vertical_position_into_account (it);
+    }
+  else
+#endif
+    it->nglyphs = width;
 }
 
 #ifdef HAVE_WINDOW_SYSTEM
@@ -27204,7 +27570,7 @@ expose_window (struct window *w, XRectangle *fr)
     {
       int yb = window_text_bottom_y (w);
       struct glyph_row *row;
-      int cursor_cleared_p;
+      int cursor_cleared_p, phys_cursor_on_p;
       struct glyph_row *first_overlapping_row, *last_overlapping_row;
 
       TRACE ((stderr, "expose_window (%d, %d, %d, %d)\n",
@@ -27224,6 +27590,13 @@ expose_window (struct window *w, XRectangle *fr)
       else
        cursor_cleared_p = 0;
 
+      /* If the row containing the cursor extends face to end of line,
+        then expose_area might overwrite the cursor outside the
+        rectangle and thus notice_overwritten_cursor might clear
+        w->phys_cursor_on_p.  We remember the original value and
+        check later if it is changed.  */
+      phys_cursor_on_p = w->phys_cursor_on_p;
+
       /* Update lines intersecting rectangle R.  */
       first_overlapping_row = last_overlapping_row = NULL;
       for (row = w->current_matrix->rows;
@@ -27290,7 +27663,8 @@ expose_window (struct window *w, XRectangle *fr)
          x_draw_vertical_border (w);
 
          /* Turn the cursor on again.  */
-         if (cursor_cleared_p)
+         if (cursor_cleared_p
+             || (phys_cursor_on_p && !w->phys_cursor_on_p))
            update_window_cursor (w, 1);
        }
     }
@@ -27627,12 +28001,18 @@ The face used for trailing whitespace is `trailing-whitespace'.  */);
   Vshow_trailing_whitespace = Qnil;
 
   DEFVAR_LISP ("nobreak-char-display", Vnobreak_char_display,
-    doc: /* *Control highlighting of nobreak space and soft hyphen.
-A value of t means highlight the character itself (for nobreak space,
-use face `nobreak-space').
-A value of nil means no highlighting.
-Other values mean display the escape glyph followed by an ordinary
-space or ordinary hyphen.  */);
+    doc: /* Control highlighting of non-ASCII space and hyphen chars.
+If the value is t, Emacs highlights non-ASCII chars which have the
+same appearance as an ASCII space or hyphen, using the `nobreak-space'
+or `escape-glyph' face respectively.
+
+U+00A0 (no-break space), U+00AD (soft hyphen), U+2010 (hyphen), and
+U+2011 (non-breaking hyphen) are affected.
+
+Any other non-nil value means to display these characters as a escape
+glyph followed by an ordinary space or hyphen.
+
+A value of nil means no special handling of these characters.  */);
   Vnobreak_char_display = Qt;
 
   DEFVAR_LISP ("void-text-area-pointer", Vvoid_text_area_pointer,