Fix bug #11068 with window display when default face was remapped.
[bpt/emacs.git] / src / xdisp.c
index c90184f..118480a 100644 (file)
@@ -2750,9 +2750,12 @@ init_iterator (struct it *it, struct window *w,
   if (charpos >= BUF_BEG (current_buffer))
     {
       it->end_charpos = ZV;
-      it->face_id = -1;
       IT_CHARPOS (*it) = charpos;
 
+      /* We will rely on `reseat' to set this up properly, via
+        handle_face_prop.  */
+      it->face_id = it->base_face_id;
+
       /* Compute byte position if not specified.  */
       if (bytepos < charpos)
        IT_BYTEPOS (*it) = CHAR_TO_BYTE (charpos);
@@ -3670,7 +3673,9 @@ handle_face_prop (struct it *it)
             with, so that overlay strings appear in the same face as
             surrounding text, unless they specify their own
             faces.  */
-         base_face_id = underlying_face_id (it);
+         base_face_id = it->string_from_prefix_prop_p
+           ? DEFAULT_FACE_ID
+           : underlying_face_id (it);
        }
 
       new_face_id = face_at_string_position (it->w,
@@ -5153,6 +5158,12 @@ next_overlay_string (struct it *it)
       it->current.overlay_string_index = -1;
       it->n_overlay_strings = 0;
       it->overlay_strings_charpos = -1;
+      /* If there's an empty display string on the stack, pop the
+        stack, to resync the bidi iterator with IT's position.  Such
+        empty strings are pushed onto the stack in
+        get_overlay_strings_1.  */
+      if (it->sp > 0 && STRINGP (it->string) && !SCHARS (it->string))
+       pop_it (it);
 
       /* If we're at the end of the buffer, record that we have
         processed the overlay strings there already, so that
@@ -5450,8 +5461,15 @@ get_overlay_strings_1 (struct it *it, EMACS_INT charpos, int compute_stop_p)
       xassert (!compute_stop_p || it->sp == 0);
 
       /* When called from handle_stop, there might be an empty display
-         string loaded.  In that case, don't bother saving it.  */
-      if (!STRINGP (it->string) || SCHARS (it->string))
+         string loaded.  In that case, don't bother saving it.  But
+         don't use this optimization with the bidi iterator, since we
+         need the corresponding pop_it call to resync the bidi
+         iterator's position with IT's position, after we are done
+         with the overlay strings.  (The corresponding call to pop_it
+         in case of an empty display string is in
+         next_overlay_string.)  */
+      if (!(!it->bidi_p
+           && STRINGP (it->string) && !SCHARS (it->string)))
        push_it (it, NULL);
 
       /* Set up IT to deliver display elements from the first overlay
@@ -5560,6 +5578,7 @@ push_it (struct it *it, struct text_pos *position)
   p->font_height = it->font_height;
   p->voffset = it->voffset;
   p->string_from_display_prop_p = it->string_from_display_prop_p;
+  p->string_from_prefix_prop_p = it->string_from_prefix_prop_p;
   p->display_ellipsis_p = 0;
   p->line_wrap = it->line_wrap;
   p->bidi_p = it->bidi_p;
@@ -5669,6 +5688,7 @@ pop_it (struct it *it)
   it->font_height = p->font_height;
   it->voffset = p->voffset;
   it->string_from_display_prop_p = p->string_from_display_prop_p;
+  it->string_from_prefix_prop_p = p->string_from_prefix_prop_p;
   it->line_wrap = p->line_wrap;
   it->bidi_p = p->bidi_p;
   it->paragraph_embedding = p->paragraph_embedding;
@@ -6099,6 +6119,8 @@ reseat_1 (struct it *it, struct text_pos pos, int set_stop_p)
   it->multibyte_p = !NILP (BVAR (current_buffer, enable_multibyte_characters));
   it->sp = 0;
   it->string_from_display_prop_p = 0;
+  it->string_from_prefix_prop_p = 0;
+
   it->from_disp_prop_p = 0;
   it->face_before_selective_p = 0;
   if (it->bidi_p)
@@ -7346,7 +7368,7 @@ next_element_from_string (struct it *it)
   if (it->current.overlay_string_index >= 0)
     {
       /* Get the next character from an overlay string.  In overlay
-        strings, There is no field width or padding with spaces to
+        strings, there is no field width or padding with spaces to
         do.  */
       if (IT_STRING_CHARPOS (*it) >= SCHARS (it->string))
        {
@@ -15586,7 +15608,7 @@ redisplay_window (Lisp_Object window, int just_this_one_p)
             accessible region of the buffer.  This can happen when we
             have just switched to a different buffer and/or changed
             its restriction.  In that case, startp is initialized to
-            the character position 1 (BEG) because we did not yet
+            the character position 1 (BEGV) because we did not yet
             have chance to display the buffer even once.  */
          && BEGV <= CHARPOS (startp) && CHARPOS (startp) <= ZV)
        {
@@ -15595,7 +15617,7 @@ redisplay_window (Lisp_Object window, int just_this_one_p)
 
          SAVE_IT (it1, it, it1data);
          start_display (&it1, w, startp);
-         move_it_vertically (&it1, margin);
+         move_it_vertically (&it1, margin * FRAME_LINE_HEIGHT (f));
          margin_pos = IT_CHARPOS (it1);
          RESTORE_IT (&it, &it, it1data);
        }
@@ -16306,7 +16328,10 @@ try_window_reusing_current_matrix (struct window *w)
           ++first_row_to_display)
        {
          if (PT >= MATRIX_ROW_START_CHARPOS (first_row_to_display)
-             && PT < MATRIX_ROW_END_CHARPOS (first_row_to_display))
+             && (PT < MATRIX_ROW_END_CHARPOS (first_row_to_display)
+                 || (PT == MATRIX_ROW_END_CHARPOS (first_row_to_display)
+                     && first_row_to_display->ends_at_zv_p
+                     && pt_row == NULL)))
            pt_row = first_row_to_display;
        }
 
@@ -16398,7 +16423,9 @@ try_window_reusing_current_matrix (struct window *w)
       if (pt_row)
        {
          for (row = MATRIX_ROW (w->current_matrix, w->cursor.vpos);
-              row < bottom_row && PT >= MATRIX_ROW_END_CHARPOS (row);
+              row < bottom_row
+                && PT >= MATRIX_ROW_END_CHARPOS (row)
+                && !row->ends_at_zv_p;
               row++)
            {
              w->cursor.vpos++;
@@ -18145,8 +18172,10 @@ append_space_for_newline (struct it *it, int default_face_p)
          it->c = it->char_to_display = ' ';
          it->len = 1;
 
+         /* If the default face was remapped, be sure to use the
+            remapped face for the appended newline. */
          if (default_face_p)
-           it->face_id = DEFAULT_FACE_ID;
+           it->face_id = lookup_basic_face (it->f, DEFAULT_FACE_ID);
          else if (it->face_before_selective_p)
            it->face_id = it->saved_face_id;
          face = FACE_FROM_ID (it->f, it->face_id);
@@ -18182,7 +18211,7 @@ append_space_for_newline (struct it *it, int default_face_p)
 static void
 extend_face_to_end_of_line (struct it *it)
 {
-  struct face *face;
+  struct face *face, *default_face;
   struct frame *f = it->f;
 
   /* If line is already filled, do nothing.  Non window-system frames
@@ -18196,6 +18225,9 @@ extend_face_to_end_of_line (struct it *it)
         && !it->glyph_row->continued_p))
     return;
 
+  /* The default face, possibly remapped. */
+  default_face = FACE_FROM_ID (f, lookup_basic_face (f, DEFAULT_FACE_ID));
+
   /* Face extension extends the background and box of IT->face_id
      to the end of the line.  If the background equals the background
      of the frame, we don't have to do anything.  */
@@ -18233,7 +18265,7 @@ extend_face_to_end_of_line (struct it *it)
       if (it->glyph_row->used[TEXT_AREA] == 0)
        {
          it->glyph_row->glyphs[TEXT_AREA][0] = space_glyph;
-         it->glyph_row->glyphs[TEXT_AREA][0].face_id = it->face_id;
+         it->glyph_row->glyphs[TEXT_AREA][0].face_id = face->id;
          it->glyph_row->used[TEXT_AREA] = 1;
        }
 #ifdef HAVE_WINDOW_SYSTEM
@@ -18269,7 +18301,7 @@ extend_face_to_end_of_line (struct it *it)
                 face, to avoid painting the rest of the window with
                 the region face, if the region ends at ZV.  */
              if (it->glyph_row->ends_at_zv_p)
-               it->face_id = DEFAULT_FACE_ID;
+               it->face_id = default_face->id;
              else
                it->face_id = face->id;
              append_stretch_glyph (it, make_number (0), stretch_width,
@@ -18302,7 +18334,7 @@ extend_face_to_end_of_line (struct it *it)
         avoid painting the rest of the window with the region face,
         if the region ends at ZV.  */
       if (it->glyph_row->ends_at_zv_p)
-       it->face_id = DEFAULT_FACE_ID;
+       it->face_id = default_face->id;
       else
        it->face_id = face->id;
 
@@ -18435,9 +18467,11 @@ cursor_row_p (struct glyph_row *row)
       /* Suppose the row ends on a string.
         Unless the row is continued, that means it ends on a newline
         in the string.  If it's anything other than a display string
-        (e.g. a before-string from an overlay), we don't want the
+        (e.g., a before-string from an overlay), we don't want the
         cursor there.  (This heuristic seems to give the optimal
-        behavior for the various types of multi-line strings.)  */
+        behavior for the various types of multi-line strings.)
+        One exception: if the string has `cursor' property on one of
+        its characters, we _do_ want the cursor there.  */
       if (CHARPOS (row->end.string_pos) >= 0)
        {
          if (row->continued_p)
@@ -18459,6 +18493,25 @@ cursor_row_p (struct glyph_row *row)
                    result =
                      (!NILP (prop)
                       && display_prop_string_p (prop, glyph->object));
+                   /* If there's a `cursor' property on one of the
+                      string's characters, this row is a cursor row,
+                      even though this is not a display string.  */
+                   if (!result)
+                     {
+                       Lisp_Object s = glyph->object;
+
+                       for ( ; glyph >= beg && EQ (glyph->object, s); --glyph)
+                         {
+                           EMACS_INT gpos = glyph->charpos;
+
+                           if (!NILP (Fget_char_property (make_number (gpos),
+                                                          Qcursor, s)))
+                             {
+                               result = 1;
+                               break;
+                             }
+                         }
+                     }
                    break;
                  }
            }
@@ -18497,7 +18550,7 @@ cursor_row_p (struct glyph_row *row)
    `line-prefix' and `wrap-prefix' properties.  */
 
 static int
-push_display_prop (struct it *it, Lisp_Object prop)
+push_prefix_prop (struct it *it, Lisp_Object prop)
 {
   struct text_pos pos =
     STRINGP (it->string) ? it->current.string_pos : it->current.pos;
@@ -18521,6 +18574,7 @@ push_display_prop (struct it *it, Lisp_Object prop)
        }
 
       it->string = prop;
+      it->string_from_prefix_prop_p = 1;
       it->multibyte_p = STRING_MULTIBYTE (it->string);
       it->current.overlay_string_index = -1;
       IT_STRING_CHARPOS (*it) = IT_STRING_BYTEPOS (*it) = 0;
@@ -18607,7 +18661,7 @@ handle_line_prefix (struct it *it)
       if (NILP (prefix))
        prefix = Vline_prefix;
     }
-  if (! NILP (prefix) && push_display_prop (it, prefix))
+  if (! NILP (prefix) && push_prefix_prop (it, prefix))
     {
       /* If the prefix is wider than the window, and we try to wrap
         it, it would acquire its own wrap prefix, and so on till the
@@ -18944,8 +18998,13 @@ display_line (struct it *it)
          /* A row that displays right-to-left text must always have
             its last face extended all the way to the end of line,
             even if this row ends in ZV, because we still write to
-            the screen left to right.  */
-         if (row->reversed_p)
+            the screen left to right.  We also need to extend the
+            last face if the default face is remapped to some
+            different face, otherwise the functions that clear
+            portions of the screen will clear with the default face's
+            background color.  */
+         if (row->reversed_p
+             || lookup_basic_face (it->f, DEFAULT_FACE_ID) != DEFAULT_FACE_ID)
            extend_face_to_end_of_line (it);
          break;
        }
@@ -22738,7 +22797,7 @@ compute_overhangs_and_x (struct glyph_string *s, int x, int backward_p)
     ptrdiff_t cmp_id = (row)->glyphs[area][START].u.cmp.id;                \
     struct composition *cmp = composition_table[cmp_id];                   \
     XChar2b *char2b;                                                       \
-    struct glyph_string *first_s IF_LINT (= NULL);                         \
+    struct glyph_string *first_s = NULL;                                   \
     int n;                                                                 \
                                                                            \
     char2b = (XChar2b *) alloca ((sizeof *char2b) * cmp->glyph_len);       \
@@ -23964,7 +24023,7 @@ produce_glyphless_glyph (struct it *it, int for_no_font, Lisp_Object acronym)
          sprintf (buf, "%0*X", it->c < 0x10000 ? 4 : 6, it->c);
          str = buf;
        }
-      for (len = 0; str[len] && ASCII_BYTE_P (str[len]); len++)
+      for (len = 0; str[len] && ASCII_BYTE_P (str[len]) && len < 6; len++)
        code[len] = font->driver->encode_char (font, str[len]);
       upper_len = (len + 1) / 2;
       font->driver->text_extents (font, code, upper_len,
@@ -24400,7 +24459,7 @@ x_produce_glyphs (struct it *it)
          /* Initialize the bounding box.  */
          if (pcm)
            {
-             width = pcm->width;
+             width = cmp->glyph_len > 0 ? pcm->width : 0;
              ascent = pcm->ascent;
              descent = pcm->descent;
              lbearing = pcm->lbearing;
@@ -24408,7 +24467,7 @@ x_produce_glyphs (struct it *it)
            }
          else
            {
-             width = font->space_width;
+             width = cmp->glyph_len > 0 ? font->space_width : 0;
              ascent = FONT_BASE (font);
              descent = FONT_DESCENT (font);
              lbearing = 0;
@@ -24626,7 +24685,7 @@ x_produce_glyphs (struct it *it)
       if (it->descent < 0)
        it->descent = 0;
 
-      if (it->glyph_row)
+      if (it->glyph_row && cmp->glyph_len > 0)
        append_composite_glyph (it);
     }
   else if (it->what == IT_COMPOSITION)