update.
[chise/xemacs-chise.git.1] / src / redisplay.c
index 733315f..ac3416f 100644 (file)
@@ -147,9 +147,9 @@ typedef struct position_redisplay_data_type
                           to be skipped before anything is displayed. */
   Bytind bi_start_col_enabled;
   int start_col_xoffset;       /* Number of pixels that still need to
-                          be skipped.  This is used for
-                          horizontal scrolling of glyphs, where we want
-                          to be able to scroll over part of the glyph. */
+                                   be skipped.  This is used for
+                                   horizontal scrolling of glyphs, where we want
+                                   to be able to scroll over part of the glyph. */
 
   int hscroll_glyph_width_adjust;  /* how much the width of the hscroll
                                      glyph differs from space_width (w).
@@ -163,18 +163,20 @@ typedef struct position_redisplay_data_type
   struct extent_fragment *ef;
   face_index findex;
 
-  /* The height of a pixmap may either be predetermined if the user
-     has set a baseline value, or it may be dependent on whatever the
-     line ascent and descent values end up being, based just on font
-     information.  In the first case we can immediately update the
-     values, thus their inclusion here.  In the last case we cannot
-     determine the actual contribution to the line height until we
-     have finished laying out all text on the line.  Thus we propagate
-     the max height of such pixmaps and do a final calculation after
-     all text has been added to the line. */
+  /* The height of a pixmap may either be predetermined if the user has set a
+     baseline value, or it may be dependent on whatever the line ascent and
+     descent values end up being, based just on font and pixmap-ascent
+     information.  In the first case we can immediately update the values, thus
+     their inclusion here.  In the last case we cannot determine the actual
+     contribution to the line height until we have finished laying out all text
+     on the line.  Thus we propagate the max height of such pixmaps and do a
+     final calculation (in calculate_baseline()) after all text has been added
+     to the line. */
   int new_ascent;
   int new_descent;
   int max_pixmap_height;
+  int need_baseline_computation;
+  int end_glyph_width;         /* Well, it is the kitchen sink after all ... */
 
   Lisp_Object result_str; /* String where we put the result of
                             generating a formatted string in the modeline. */
@@ -192,15 +194,24 @@ enum prop_type
   PROP_STRING,
   PROP_CHAR,
   PROP_MINIBUF_PROMPT,
-  PROP_BLANK
+  PROP_BLANK,
+  PROP_GLYPH
 };
 
 /* Data that should be propagated to the next line.  Either a single
-   Emchar or a string of Bufbyte's.
+   Emchar, a string of Bufbyte's or a glyph.
 
    The actual data that is propagated ends up as a Dynarr of these
    blocks.
 
+   prop_blocks are used to indicate that data that was supposed to go
+   on the previous line couldn't actually be displayed. Generally this
+   shouldn't happen if we are clipping the end of lines. If we are
+   wrapping then we need to display the propagation data before moving
+   on. Its questionable whether we should wrap or clip glyphs in this
+   instance. Most e-lisp relies on clipping so we preserve this
+   behavior.
+
    #### It's unclean that both Emchars and Bufbytes are here.
    */
 
@@ -229,6 +240,14 @@ struct prop_block
       int width;
       face_index findex;
     } p_blank;
+
+    struct
+    {
+      /* Not used as yet, but could be used to wrap rather than clip glyphs. */
+      int width;               
+      Lisp_Object glyph;
+    } p_glyph;
+
   } data;
 };
 
@@ -265,6 +284,9 @@ static void free_display_line (struct display_line *dl);
 static void update_line_start_cache (struct window *w, Bufpos from, Bufpos to,
                                     Bufpos point, int no_regen);
 static int point_visible (struct window *w, Bufpos point, int type);
+static void calculate_yoffset (struct display_line *dl,
+                               struct display_block *fixup);
+static void calculate_baseline (pos_data *data);
 
 /* This used to be 10 but 30 seems to give much better performance. */
 #define INIT_MAX_PREEMPTS      30
@@ -300,7 +322,7 @@ static Bytecount_dynarr *formatted_string_extent_end_dynarr;
 
 
 /* #### probably temporary */
-int cache_adjustment;
+Fixnum cache_adjustment;
 
 /* This holds a string representing the text corresponding to a single
    modeline % spec. */
@@ -315,10 +337,10 @@ int disable_preemption;   /* Used for debugging redisplay and for
 static int preemption_count;
 
 /* Minimum pixel height of clipped bottom display line. */
-int vertical_clip;
+Fixnum vertical_clip;
 
 /* Minimum visible pixel width of clipped glyphs at right margin. */
-int horizontal_clip;
+Fixnum horizontal_clip;
 
 /* Nonzero means reading single-character input with prompt
    so put cursor on minibuffer after the prompt.  */
@@ -392,6 +414,10 @@ int asynch_device_change_pending;
 int toolbar_changed;
 int toolbar_changed_set;
 
+/* Nonzero if some frame has changed the layout of internal elements
+   (gutters or toolbars). */
+int frame_layout_changed;
+
 /* non-nil if any gutter has changed */
 int gutter_changed;
 int gutter_changed_set;
@@ -425,10 +451,10 @@ Lisp_Object Vglobal_mode_string;
 
 /* The number of lines scroll a window by when point leaves the window; if
   it is <=0 then point is centered in the window */
-int scroll_step;
+Fixnum scroll_step;
 
 /* Scroll up to this many lines, to bring point back on screen. */
-int scroll_conservatively;
+Fixnum scroll_conservatively;
 
 /* Marker for where to display an arrow on top of the buffer text.  */
 Lisp_Object Voverlay_arrow_position;
@@ -451,7 +477,8 @@ Lisp_Object Vpre_redisplay_hook, Vpost_redisplay_hook;
 Lisp_Object Qpre_redisplay_hook, Qpost_redisplay_hook;
 #endif /* INHIBIT_REDISPLAY_HOOKS */
 
-static int last_display_warning_tick, display_warning_tick;
+static Fixnum last_display_warning_tick;
+static Fixnum display_warning_tick;
 Lisp_Object Qdisplay_warning_buffer;
 int inhibit_warning_display;
 
@@ -474,13 +501,13 @@ Lisp_Object Qtop_bottom;
 /***************************************************************************/
 
 static int
-redisplay_text_width_emchar_string (struct window *w, int findex,
-                                   Emchar *str, Charcount len)
+redisplay_text_width_charc_string (struct window *w, int findex,
+                                  Charc *str, Charcount len)
 {
-  unsigned char charsets[NUM_LEADING_BYTES];
+  Charset_ID charsets[NUM_LEADING_BYTES];
   Lisp_Object window;
 
-  find_charsets_in_emchar_string (charsets, str, len);
+  find_charsets_in_charc_string (charsets, str, len);
   XSETWINDOW (window, w);
   ensure_face_cachel_complete (WINDOW_FACE_CACHEL (w, findex), window,
                               charsets);
@@ -489,24 +516,24 @@ redisplay_text_width_emchar_string (struct window *w, int findex,
                               WINDOW_FACE_CACHEL (w, findex), str, len));
 }
 
-static Emchar_dynarr *rtw_emchar_dynarr;
+static Charc_dynarr *rtw_charc_dynarr;
 
 int
 redisplay_text_width_string (struct window *w, int findex,
                             Bufbyte *nonreloc, Lisp_Object reloc,
                             Bytecount offset, Bytecount len)
 {
-  if (!rtw_emchar_dynarr)
-    rtw_emchar_dynarr = Dynarr_new (Emchar);
-  Dynarr_reset (rtw_emchar_dynarr);
+  if (!rtw_charc_dynarr)
+    rtw_charc_dynarr = Dynarr_new (Charc);
+  Dynarr_reset (rtw_charc_dynarr);
 
   fixup_internal_substring (nonreloc, reloc, offset, &len);
   if (STRINGP (reloc))
     nonreloc = XSTRING_DATA (reloc);
-  convert_bufbyte_string_into_emchar_dynarr (nonreloc, len, rtw_emchar_dynarr);
-  return redisplay_text_width_emchar_string
-    (w, findex, Dynarr_atp (rtw_emchar_dynarr, 0),
-     Dynarr_length (rtw_emchar_dynarr));
+  convert_bufbyte_string_into_charc_dynarr (nonreloc, len, rtw_charc_dynarr);
+  return redisplay_text_width_charc_string
+    (w, findex, Dynarr_atp (rtw_charc_dynarr, 0),
+     Dynarr_length (rtw_charc_dynarr));
 }
 
 int
@@ -514,26 +541,26 @@ redisplay_frame_text_width_string (struct frame *f, Lisp_Object face,
                                   Bufbyte *nonreloc, Lisp_Object reloc,
                                   Bytecount offset, Bytecount len)
 {
-  unsigned char charsets[NUM_LEADING_BYTES];
+  Charset_ID charsets[NUM_LEADING_BYTES];
   Lisp_Object frame;
   struct face_cachel cachel;
 
-  if (!rtw_emchar_dynarr)
-    rtw_emchar_dynarr = Dynarr_new (Emchar);
-  Dynarr_reset (rtw_emchar_dynarr);
+  if (!rtw_charc_dynarr)
+    rtw_charc_dynarr = Dynarr_new (Charc);
+  Dynarr_reset (rtw_charc_dynarr);
 
   fixup_internal_substring (nonreloc, reloc, offset, &len);
   if (STRINGP (reloc))
     nonreloc = XSTRING_DATA (reloc);
-  convert_bufbyte_string_into_emchar_dynarr (nonreloc, len, rtw_emchar_dynarr);
+  convert_bufbyte_string_into_charc_dynarr (nonreloc, len, rtw_charc_dynarr);
   find_charsets_in_bufbyte_string (charsets, nonreloc, len);
   reset_face_cachel (&cachel);
   cachel.face = face;
   XSETFRAME (frame, f);
   ensure_face_cachel_complete (&cachel, frame, charsets);
   return DEVMETH (XDEVICE (FRAME_DEVICE (f)),
-                 text_width, (f, &cachel, Dynarr_atp (rtw_emchar_dynarr, 0),
-                              Dynarr_length (rtw_emchar_dynarr)));
+                 text_width, (f, &cachel, Dynarr_atp (rtw_charc_dynarr, 0),
+                              Dynarr_length (rtw_charc_dynarr)));
 }
 
 /* Return the display block from DL of the given TYPE.  A display line
@@ -679,6 +706,108 @@ calculate_display_line_boundaries (struct window *w, int modeline)
   return bounds;
 }
 
+/* This takes a display_block and its containing line and corrects the yoffset
+   of each glyph in the block to cater for the ascent of the line as a
+   whole. Must be called *after* the line-ascent is known! */
+
+static void
+calculate_yoffset (struct display_line *dl, struct display_block *fixup)
+{
+  int i;
+  for (i=0; i<Dynarr_length (fixup->runes); i++)
+    {
+      struct rune *r = Dynarr_atp (fixup->runes,i);
+      if (r->type == RUNE_DGLYPH)
+        {
+          if (r->object.dglyph.ascent < dl->ascent)
+            r->object.dglyph.yoffset = dl->ascent - r->object.dglyph.ascent +
+             r->object.dglyph.descent;
+        }
+    }
+}
+
+/* Calculate the textual baseline (the ascent and descent values for the
+   display_line as a whole).
+
+   If the baseline is completely blank, or contains no manually positioned
+   glyphs, then the textual baseline is simply the baseline of the default font.
+   (The `contains no manually positioned glyphs' part is actually done for
+   us by `add_emchar_rune'.)
+
+   If the baseline contains pixmaps, and they're all manually positioned, then
+   the textual baseline location is constrained that way, and we need do no
+   work.
+
+   If the baseline contains pixmaps, and at least one is automatically
+   positioned, then the textual ascent is the largest ascent on the line, and
+   the textual descent is the largest descent (which is how things are set up at
+   entry to this function anyway): except that if the max_ascent + max_descent
+   is too small for the height of the line (say you've adjusted the baseline of
+   a short glyph, and there's a tall one next to it), then take the ascent and
+   descent for the line individually from the largest of the explicitly set
+   ascent/descent, and the rescaled ascent/descent of the default font, scaled
+   such that the largest glyph will fit.
+
+   This means that if you have a short glyph (but taller than the default
+   font's descent) forced right under the baseline, and a really tall
+   automatically positioned glyph, that the descent for the line is just big
+   enough for the manually positioned short glyph, and the tall one uses as
+   much of that space as the default font would were it as tall as the tall
+   glyph; but that the ascent is big enough for the tall glyph to fit.
+
+   This behaviour means that under no circumstances will changing the baseline
+   of a short glyph cause a tall glyph to move around; nor will it move the
+   textual baseline more than necessary. (Changing a tall glyph's baseline
+   might move the text's baseline arbitrarily, of course.) */
+
+static void
+calculate_baseline (pos_data *data)
+{
+  /* Blank line: baseline is default font's baseline. */
+
+  if (!data->new_ascent && !data->new_descent)
+    {
+      /* We've got a blank line so initialize these values from the default
+         face. */
+      default_face_font_info (data->window, &data->new_ascent,
+                             &data->new_descent, 0, 0, 0);
+    }
+  
+  /* No automatically positioned glyphs? Return at once. */
+  if (!data->need_baseline_computation)
+    return;
+
+  /* Is the tallest glyph on the line automatically positioned?
+     If it's manually positioned, or it's automatically positioned
+     and there's enough room for it anyway, we need do no more work. */
+  if (data->max_pixmap_height > data->new_ascent + data->new_descent)
+    {
+      int default_font_ascent, default_font_descent, default_font_height;
+      int scaled_default_font_ascent, scaled_default_font_descent;
+      
+      default_face_font_info (data->window, &default_font_ascent,
+                             &default_font_descent, &default_font_height,
+                             0, 0);
+
+      scaled_default_font_ascent = data->max_pixmap_height *
+       default_font_ascent / default_font_height;
+
+      data->new_ascent = max (data->new_ascent, scaled_default_font_ascent);
+
+      /* The ascent may have expanded now. Do we still need to grow the descent,
+         or are things big enough?
+
+         The +1 caters for the baseline row itself. */
+      if (data->max_pixmap_height > data->new_ascent + data->new_descent)
+        {
+          scaled_default_font_descent = (data->max_pixmap_height *
+                                        default_font_descent / default_font_height) + 1;
+
+          data->new_descent = max (data->new_descent, scaled_default_font_descent);
+        }
+    }
+}
+
 /* Given a display line and a starting position, ensure that the
    contents of the display line accurately represent the visual
    representation of the buffer contents starting from the given
@@ -810,15 +939,18 @@ add_hscroll_rune (pos_data *data)
   return retval;
 }
 
-/* Adds a character rune to a display block.  If there is not enough
-   room to fit the rune on the display block (as determined by the
-   MAX_PIXPOS) then it adds nothing and returns ADD_FAILED. */
+/* Adds a character rune to a display block.  If there is not enough room
+   to fit the rune on the display block (as determined by the MAX_PIXPOS)
+   then it adds nothing and returns ADD_FAILED.  If
+   NO_CONTRIBUTE_TO_LINE_HEIGHT is non-zero, don't allow the char's height
+   to affect the total line height. (See add_intbyte_string_runes()). */
 
 static prop_block_dynarr *
-add_emchar_rune (pos_data *data)
+add_emchar_rune_1 (pos_data *data, int no_contribute_to_line_height)
 {
   struct rune rb, *crb;
   int width, local;
+  Charc char_glyph;
 
   if (data->start_col)
     {
@@ -835,13 +967,17 @@ add_emchar_rune (pos_data *data)
 
   if (data->ch == '\n')
     {
+      char_glyph = ASCII_TO_CHARC ('\n');
       data->font_is_bogus = 0;
       /* Cheesy end-of-line pseudo-character. */
       width = data->blank_width;
     }
   else
     {
-      Lisp_Object charset = CHAR_CHARSET (data->ch);
+      Lisp_Object charset;
+
+      char_glyph = CHAR_TO_CHARC (data->ch);
+      charset = CHARC_CHARSET (char_glyph);
       if (!EQ (charset, data->last_charset) ||
          data->findex != data->last_findex)
        {
@@ -867,8 +1003,13 @@ add_emchar_rune (pos_data *data)
            data->last_char_width = fi->width;
          else
            data->last_char_width = -1;
-         data->new_ascent  = max (data->new_ascent,  (int) fi->ascent);
-         data->new_descent = max (data->new_descent, (int) fi->descent);
+
+         if (!no_contribute_to_line_height)
+           {
+             data->new_ascent  = max (data->new_ascent,  (int) fi->ascent);
+             data->new_descent = max (data->new_descent, (int) fi->descent);
+           }
+
          data->last_charset = charset;
          data->last_findex = data->findex;
        }
@@ -877,9 +1018,9 @@ add_emchar_rune (pos_data *data)
       if (width < 0)
        {
          /* bummer.  Proportional fonts. */
-         width = redisplay_text_width_emchar_string (XWINDOW (data->window),
-                                                     data->findex,
-                                                     &data->ch, 1);
+         width = redisplay_text_width_charc_string (XWINDOW (data->window),
+                                                    data->findex,
+                                                    &char_glyph, 1);
        }
     }
 
@@ -910,7 +1051,8 @@ add_emchar_rune (pos_data *data)
                            data->bi_bufpos);
       else
        crb->bufpos =
-         bytecount_to_charcount (XSTRING_DATA (data->string), data->bi_bufpos);
+         bytecount_to_charcount (XSTRING_DATA (data->string),
+                                 data->bi_bufpos);
     }
   else if (data->is_modeline)
     crb->bufpos = data->modeline_charpos;
@@ -918,7 +1060,9 @@ add_emchar_rune (pos_data *data)
     /* Text but not in buffer */
     crb->bufpos = 0;
   crb->type = RUNE_CHAR;
-  crb->object.chr.ch = data->font_is_bogus ? '~' : data->ch;
+  crb->object.cglyph = data->font_is_bogus
+    ? ASCII_TO_CHARC ('~')
+    : char_glyph;
   crb->endpos = 0;
 
   if (data->cursor_type == CURSOR_ON)
@@ -952,13 +1096,24 @@ add_emchar_rune (pos_data *data)
   return NULL;
 }
 
-/* Given a string C_STRING of length C_LENGTH, call add_emchar_rune
-   for each character in the string.  Propagate any left-over data
-   unless NO_PROP is non-zero. */
-
+static prop_block_dynarr *
+add_emchar_rune (pos_data *data)
+{
+  return add_emchar_rune_1 (data, 0);
+}
+  
+/* Given a string C_STRING of length C_LENGTH, call add_emchar_rune for
+   each character in the string.  Propagate any left-over data unless
+   NO_PROP is non-zero.  If NO_CONTRIBUTE_TO_LINE_HEIGHT is non-zero, don't
+   allow this character to increase the total height of the line. (This is
+   used when the character is part of a text glyph.  In that case, the
+   glyph code itself adjusts the line height as necessary, depending on
+   whether glyph-contrib-p is true.) */
+  
 static prop_block_dynarr *
 add_bufbyte_string_runes (pos_data *data, Bufbyte *c_string,
-                         Bytecount c_length, int no_prop)
+                         Bytecount c_length, int no_prop,
+                         int no_contribute_to_line_height)
 {
   Bufbyte *pos, *end = c_string + c_length;
   prop_block_dynarr *prop;
@@ -971,9 +1126,11 @@ add_bufbyte_string_runes (pos_data *data, Bufbyte *c_string,
 
   for (pos = c_string; pos < end;)
     {
+      Bufbyte *old_pos = pos;
+
       data->ch = charptr_emchar (pos);
 
-      prop = add_emchar_rune (data);
+      prop = add_emchar_rune_1 (data, no_contribute_to_line_height);
 
       if (prop)
        {
@@ -996,6 +1153,9 @@ add_bufbyte_string_runes (pos_data *data, Bufbyte *c_string,
        }
       INC_CHARPTR (pos);
       assert (pos <= end);
+      /* #### Duplicate code from add_string_to_fstring_db_runes
+        should we do more?*/
+      data->bytepos += pos - old_pos;
     }
 
   return NULL;
@@ -1105,12 +1265,11 @@ add_blank_rune (pos_data *data, struct window *w, int char_tab_width)
 static prop_block_dynarr *
 add_octal_runes (pos_data *data)
 {
-  prop_block_dynarr *prop, *add_failed;
+  prop_block_dynarr *add_failed, *prop = 0;
   Emchar orig_char = data->ch;
   unsigned int orig_cursor_type = data->cursor_type;
 
   /* Initialize */
-  prop = NULL;
   add_failed = NULL;
 
   if (data->start_col)
@@ -1170,7 +1329,7 @@ add_octal_runes (pos_data *data)
   ADD_NEXT_OCTAL_RUNE_CHAR;
 
   data->cursor_type = orig_cursor_type;
-  return prop;
+  return NULL;
 }
 
 #undef ADD_NEXT_OCTAL_RUNE_CHAR
@@ -1255,7 +1414,7 @@ add_disp_table_entry_runes_1 (pos_data *data, Lisp_Object entry)
       prop = add_bufbyte_string_runes (data,
                                       XSTRING_DATA   (entry),
                                       XSTRING_LENGTH (entry),
-                                      0);
+                                      0, 0);
     }
   else if (GLYPHP (entry))
     {
@@ -1314,7 +1473,7 @@ add_disp_table_entry_runes_1 (pos_data *data, Lisp_Object entry)
                    }
                }
            }
-         prop = add_bufbyte_string_runes (data, result, dst - result, 0);
+         prop = add_bufbyte_string_runes (data, result, dst - result, 0, 0);
        }
     }
 
@@ -1484,7 +1643,7 @@ add_propagation_runes (prop_block_dynarr **prop, pos_data *data)
          }
          break;
        default:
-         abort ();
+         ABORT ();
        }
     }
 
@@ -1543,6 +1702,7 @@ add_glyph_rune (pos_data *data, struct glyph_block *gb, int pos_type,
       Lisp_Object face;
       Lisp_Object instance;
       face_index findex;
+      prop_block_dynarr *retval = 0;
 
       if (cachel)
        width = cachel->width;
@@ -1554,7 +1714,6 @@ add_glyph_rune (pos_data *data, struct glyph_block *gb, int pos_type,
 
       if (data->start_col || data->start_col_xoffset)
        {
-         prop_block_dynarr *retval;
          int glyph_char_width = width / space_width (w);
 
          /* If we still have not fully scrolled horizontally after
@@ -1590,17 +1749,41 @@ add_glyph_rune (pos_data *data, struct glyph_block *gb, int pos_type,
       if (data->pixpos + width > data->max_pixpos)
        {
          /* If this is the first object we are attempting to add to
-             the line then we ignore the horizontal_clip threshold.
-             Otherwise we will loop until the bottom of the window
-             continually failing to add this glyph because it is wider
-             than the window.  We could alternatively just completely
-             ignore the glyph and proceed from there but I think that
-             this is a better solution. */
+            the line then we ignore the horizontal_clip threshold.
+            Otherwise we will loop until the bottom of the window
+            continually failing to add this glyph because it is wider
+            than the window.  We could alternatively just completely
+            ignore the glyph and proceed from there but I think that
+            this is a better solution.
+            
+            This does, however, create a different problem in that we
+            can end up adding the object to every single line, never
+            getting any further - for instance an extent with a long
+            start-glyph that covers multitple following
+            characters.  */
          if (Dynarr_length (data->db->runes)
              && data->max_pixpos - data->pixpos < horizontal_clip)
            return ADD_FAILED;
-         else
+         else {
+           struct prop_block pb;
+
+           /* We need to account for the width of the end-of-line
+              glyph if there is nothing more in the line to display,
+              since we will not display it in this instance. It seems
+              kind of gross doing it here, but otherwise we have to
+              search the runes in create_text_block(). */
+           if (data->ch == '\n')
+             data->max_pixpos += data->end_glyph_width;
            width = data->max_pixpos - data->pixpos;
+           /* Add the glyph we are displaying, but clipping, to the
+              propagation data so that we don't try and do it
+              again. */ 
+           retval = Dynarr_new (prop_block);
+           pb.type = PROP_GLYPH;
+           pb.data.p_glyph.glyph = gb->glyph;
+           pb.data.p_glyph.width = width;
+           Dynarr_add (retval, pb);
+         }
        }
 
       if (cachel)
@@ -1616,6 +1799,8 @@ add_glyph_rune (pos_data *data, struct glyph_block *gb, int pos_type,
 
       baseline = glyph_baseline (gb->glyph, data->window);
 
+      rb.object.dglyph.descent = 0; /* Gets reset lower down, if it is known. */
+
       if (glyph_contrib_p (gb->glyph, data->window))
        {
          /* A pixmap that has not had a baseline explicitly set.  Its
@@ -1623,6 +1808,7 @@ add_glyph_rune (pos_data *data, struct glyph_block *gb, int pos_type,
          if (NILP (baseline))
            {
              int height = ascent + descent;
+             data->need_baseline_computation = 1;
              data->max_pixmap_height = max (data->max_pixmap_height, height);
            }
 
@@ -1645,11 +1831,14 @@ add_glyph_rune (pos_data *data, struct glyph_block *gb, int pos_type,
 
              data->new_ascent = max (data->new_ascent, pix_ascent);
              data->new_descent = max (data->new_descent, pix_descent);
+             data->max_pixmap_height = max (data->max_pixmap_height, height);
+             
+             rb.object.dglyph.descent = pix_descent;
            }
 
          /* Otherwise something is screwed up. */
          else
-           abort ();
+           ABORT ();
        }
 
       face = glyph_face (gb->glyph, data->window);
@@ -1672,11 +1861,11 @@ add_glyph_rune (pos_data *data, struct glyph_block *gb, int pos_type,
          if (!allow_cursor)
            data->bi_bufpos = 0;
          add_bufbyte_string_runes (data, XSTRING_DATA (string),
-                                   XSTRING_LENGTH (string), 0);
+                                   XSTRING_LENGTH (string), 0, 1);
          data->findex = orig_findex;
          data->bi_bufpos = orig_bufpos;
          data->bi_start_col_enabled = orig_start_col_enabled;
-         return NULL;
+         return retval;
        }
 
       rb.findex = findex;
@@ -1693,6 +1882,9 @@ add_glyph_rune (pos_data *data, struct glyph_block *gb, int pos_type,
       rb.object.dglyph.glyph = gb->glyph;
       rb.object.dglyph.extent = gb->extent;
       rb.object.dglyph.xoffset = xoffset;
+      rb.object.dglyph.ascent = ascent;
+      rb.object.dglyph.yoffset = 0;   /* Until we know better, assume that it has
+                                        a normal (textual) baseline. */
 
       if (allow_cursor)
        {
@@ -1728,7 +1920,7 @@ add_glyph_rune (pos_data *data, struct glyph_block *gb, int pos_type,
       Dynarr_add (data->db->runes, rb);
       data->pixpos += width;
 
-      return NULL;
+      return retval;
     }
   else
     {
@@ -1754,10 +1946,10 @@ add_glyph_rune (pos_data *data, struct glyph_block *gb, int pos_type,
          return NULL;
        }
       else
-       abort ();       /* there are no unknown types */
+       ABORT ();       /* there are no unknown types */
     }
 
-  return NULL; /* shut up compiler */
+  return NULL;
 }
 
 /* Add all glyphs at position POS_TYPE that are contained in the given
@@ -1817,7 +2009,6 @@ create_text_block (struct window *w, struct display_line *dl,
                           is_surrogate_for_selected_frame (f));
 
   int truncate_win = window_truncation_on (w);
-  int end_glyph_width;
 
   /* If the buffer's value of selective_display is an integer then
      only lines that start with less than selective_display columns of
@@ -1915,10 +2106,10 @@ create_text_block (struct window *w, struct display_line *dl,
      glyph.  Save the width of the end glyph for later use. */
   data.max_pixpos = dl->bounds.right_in;
   if (truncate_win)
-    end_glyph_width = GLYPH_CACHEL_WIDTH (w, TRUN_GLYPH_INDEX);
+    data.end_glyph_width = GLYPH_CACHEL_WIDTH (w, TRUN_GLYPH_INDEX);
   else
-    end_glyph_width = GLYPH_CACHEL_WIDTH (w, CONT_GLYPH_INDEX);
-  data.max_pixpos -= end_glyph_width;
+    data.end_glyph_width = GLYPH_CACHEL_WIDTH (w, CONT_GLYPH_INDEX);
+  data.max_pixpos -= data.end_glyph_width;
 
   if (cursor_in_echo_area && MINI_WINDOW_P (w) && echo_area_active (f))
     {
@@ -2011,10 +2202,25 @@ create_text_block (struct window *w, struct display_line *dl,
       /* Check for face changes. */
       if (initial || (!no_more_frags && data.bi_bufpos == data.ef->end))
        {
+         Lisp_Object last_glyph = Qnil;
+
+         /* Deal with glyphs that we have already displayed. The
+            theory is that if we end up with a PROP_GLYPH in the
+            propagation data then we are clipping the glyph and there
+            can be no propagation data before that point. The theory
+            works because we always recalculate the extent-fragments
+            for propagated data, we never actually propagate the
+            fragments that still need to be displayed. */
+         if (*prop && Dynarr_atp (*prop, 0)->type == PROP_GLYPH) 
+           {
+             last_glyph = Dynarr_atp (*prop, 0)->data.p_glyph.glyph;
+             Dynarr_free (*prop);
+             *prop = 0;
+           }
          /* Now compute the face and begin/end-glyph information. */
          data.findex =
            /* Remember that the extent-fragment routines deal in Bytind's. */
-           extent_fragment_update (w, data.ef, data.bi_bufpos);
+           extent_fragment_update (w, data.ef, data.bi_bufpos, last_glyph);
 
          get_display_tables (w, data.findex, &face_dt, &window_dt);
 
@@ -2084,9 +2290,9 @@ create_text_block (struct window *w, struct display_line *dl,
        }
 
       /* If there is propagation data, then it represents the current
-         buffer position being displayed.  Add them and advance the
-         position counter.  This might also add the minibuffer
-         prompt. */
+        buffer position being displayed.  Add them and advance the
+        position counter.  This might also add the minibuffer
+        prompt. */
       else if (*prop)
        {
          dl->used_prop_data = 1;
@@ -2108,19 +2314,59 @@ create_text_block (struct window *w, struct display_line *dl,
         here rather than doing them at the end of handling the
         previous run so that glyphs at the beginning and end of
         a line are handled correctly. */
-      else if (Dynarr_length (data.ef->end_glyphs) > 0)
+      else if (Dynarr_length (data.ef->end_glyphs) > 0
+              || Dynarr_length (data.ef->begin_glyphs) > 0)
        {
-         *prop = add_glyph_runes (&data, END_GLYPHS);
-         if (*prop)
-           goto done;
-       }
+         glyph_block_dynarr* tmpglyphs = 0;
+         /* #### I think this is safe, but could be wrong. */
+         data.ch = BI_BUF_FETCH_CHAR (b, data.bi_bufpos);
 
-      /* If there are begin glyphs, add them to the line. */
-      else if (Dynarr_length (data.ef->begin_glyphs) > 0)
-       {
-         *prop = add_glyph_runes (&data, BEGIN_GLYPHS);
-         if (*prop)
-           goto done;
+         if (Dynarr_length (data.ef->end_glyphs) > 0) 
+           {
+             *prop = add_glyph_runes (&data, END_GLYPHS);
+             tmpglyphs = data.ef->end_glyphs;
+           }
+
+         /* If there are begin glyphs, add them to the line. */
+         if (!*prop && Dynarr_length (data.ef->begin_glyphs) > 0) 
+           {
+             *prop = add_glyph_runes (&data, BEGIN_GLYPHS);
+             tmpglyphs = data.ef->begin_glyphs;
+           }
+
+         if (*prop) 
+           {
+             /* If we just clipped a glyph and we are at the end of a
+                line and there are more glyphs to display then do
+                appropriate processing to not get a continuation
+                glyph. */
+             if (*prop != ADD_FAILED 
+                 && Dynarr_atp (*prop, 0)->type == PROP_GLYPH
+                 && data.ch == '\n')
+               { 
+                 /* If there are no more glyphs then do the normal
+                    processing. 
+
+                    #### This doesn't actually work if the same glyph is
+                    present more than once in the block. To solve
+                    this we would have to carry the index around
+                    which might be problematic since the fragment is
+                    recalculated for each line. */
+                 if (EQ (Dynarr_end (tmpglyphs)->glyph,
+                         Dynarr_atp (*prop, 0)->data.p_glyph.glyph))
+                   {
+                     Dynarr_free (*prop);
+                     *prop = 0;
+                   }
+                 else {
+                   data.blank_width = DEVMETH (d, eol_cursor_width, ());
+                   add_emchar_rune (&data); /* discard prop data. */
+                   goto done;
+                 }
+               }
+             else
+               goto done;
+           }
        }
 
       /* If at end-of-buffer, we've already processed begin and
@@ -2154,7 +2400,7 @@ create_text_block (struct window *w, struct display_line *dl,
              /* We aren't going to be adding an end glyph so give its
                  space back in order to make sure that the cursor can
                  fit. */
-             data.max_pixpos += end_glyph_width;
+             data.max_pixpos += data.end_glyph_width;
 
              if (selective > 0
                  && (bi_spaces_at_point
@@ -2235,7 +2481,7 @@ create_text_block (struct window *w, struct display_line *dl,
 
              /* We won't be adding a truncation or continuation glyph
                  so give up the room allocated for them. */
-             data.max_pixpos += end_glyph_width;
+             data.max_pixpos += data.end_glyph_width;
 
              if (!NILP (b->selective_display_ellipses))
                {
@@ -2273,7 +2519,7 @@ create_text_block (struct window *w, struct display_line *dl,
 
              /* This had better be a newline but doing it this way
                  we'll see obvious incorrect results if it isn't.  No
-                 need to abort here. */
+                 need to ABORT here. */
              data.ch = BI_BUF_FETCH_CHAR (b, data.bi_bufpos);
 
              goto done;
@@ -2444,7 +2690,7 @@ done:
              for the next newline.  We also add the end-of-line glyph which
              we know will fit because we adjusted the right border before
              we starting laying out the line. */
-         data.max_pixpos += end_glyph_width;
+         data.max_pixpos += data.end_glyph_width;
          data.findex = DEFAULT_INDEX;
          gb.extent = Qnil;
 
@@ -2530,7 +2776,7 @@ done:
       {
        struct rune *rb = Dynarr_atp (db->runes, elt);
 
-       if ((rb->type == RUNE_CHAR && rb->object.chr.ch == ' ')
+       if ((rb->type == RUNE_CHAR && CHARC_ASCII_EQ (rb->object.cglyph, ' '))
            || rb->type == RUNE_BLANK)
          {
            dl->bounds.left_white += rb->width;
@@ -2550,8 +2796,7 @@ done:
       {
        struct rune *rb = Dynarr_atp (db->runes, elt);
 
-       if (!(rb->type == RUNE_CHAR && rb->object.chr.ch < 0x100
-           && isspace (rb->object.chr.ch))
+       if (!(rb->type == RUNE_CHAR && CHARC_IS_SPACE (rb->object.cglyph))
            && !rb->type == RUNE_BLANK)
          {
            dl->bounds.right_white = rb->xpos + rb->width;
@@ -2579,26 +2824,7 @@ done:
   else
     db->end_pos = dl->bounds.right_white;
 
-  /* update line height parameters */
-  if (!data.new_ascent && !data.new_descent)
-    {
-      /* We've got a blank line so initialize these values from the default
-         face. */
-      default_face_font_info (data.window, &data.new_ascent,
-                             &data.new_descent, 0, 0, 0);
-    }
-
-  if (data.max_pixmap_height)
-    {
-      int height = data.new_ascent + data.new_descent;
-      int pix_ascent, pix_descent;
-
-      pix_descent = data.max_pixmap_height * data.new_descent / height;
-      pix_ascent = data.max_pixmap_height - pix_descent;
-
-      data.new_ascent = max (data.new_ascent, pix_ascent);
-      data.new_descent = max (data.new_descent, pix_descent);
-    }
+  calculate_baseline (&data);
 
   dl->ascent = data.new_ascent;
   dl->descent = data.new_descent;
@@ -2616,6 +2842,8 @@ done:
       dl->descent = descent;
   }
 
+  calculate_yoffset (dl, db);
+
   dl->cursor_elt = data.cursor_x;
   /* #### lossage lossage lossage! Fix this shit! */
   if (data.bi_bufpos > BI_BUF_ZV (b))
@@ -2694,7 +2922,7 @@ create_overlay_glyph_block (struct window *w, struct display_line *dl)
        (&data,
         XSTRING_DATA   (Voverlay_arrow_string),
         XSTRING_LENGTH (Voverlay_arrow_string),
-        1);
+        1, 0);
     }
   else if (GLYPHP (Voverlay_arrow_string))
     {
@@ -2705,17 +2933,7 @@ create_overlay_glyph_block (struct window *w, struct display_line *dl)
       add_glyph_rune (&data, &gb, BEGIN_GLYPHS, 0, 0);
     }
 
-  if (data.max_pixmap_height)
-    {
-      int height = data.new_ascent + data.new_descent;
-      int pix_ascent, pix_descent;
-
-      pix_descent = data.max_pixmap_height * data.new_descent / height;
-      pix_ascent = data.max_pixmap_height - pix_descent;
-
-      data.new_ascent = max (data.new_ascent, pix_ascent);
-      data.new_descent = max (data.new_descent, pix_descent);
-    }
+  calculate_baseline (&data);
 
   dl->ascent = data.new_ascent;
   dl->descent = data.new_descent;
@@ -2723,6 +2941,8 @@ create_overlay_glyph_block (struct window *w, struct display_line *dl)
   data.db->start_pos = dl->bounds.left_in;
   data.db->end_pos = data.pixpos;
 
+  calculate_yoffset (dl, data.db);
+
   return data.pixpos - dl->bounds.left_in;
 }
 
@@ -2776,7 +2996,7 @@ add_margin_runes (struct display_line *dl, struct display_block *db, int start,
       struct glyph_block *gb = Dynarr_atp (gbd, elt);
 
       if (NILP (gb->extent))
-       abort ();       /* these should have been handled in add_glyph_rune */
+       ABORT ();       /* these should have been handled in add_glyph_rune */
 
       if (gb->active &&
          ((side == LEFT_GLYPHS &&
@@ -2794,20 +3014,13 @@ add_margin_runes (struct display_line *dl, struct display_block *db, int start,
       (reverse ? elt-- : elt++);
     }
 
-  if (data.max_pixmap_height)
-    {
-      int height = data.new_ascent + data.new_descent;
-      int pix_ascent, pix_descent;
-
-      pix_descent = data.max_pixmap_height * data.new_descent / height;
-      pix_ascent = data.max_pixmap_height - pix_descent;
-      data.new_ascent = max (data.new_ascent, pix_ascent);
-      data.new_descent = max (data.new_descent, pix_descent);
-    }
+  calculate_baseline (&data);
 
   dl->ascent = data.new_ascent;
   dl->descent = data.new_descent;
 
+  calculate_yoffset (dl, data.db);
+
   return data.pixpos;
 }
 
@@ -2868,7 +3081,7 @@ create_left_glyph_block (struct window *w, struct display_line *dl,
       struct glyph_block *gb = Dynarr_atp (dl->left_glyphs, elt);
 
       if (NILP (gb->extent))
-       abort ();       /* these should have been handled in add_glyph_rune */
+       ABORT ();       /* these should have been handled in add_glyph_rune */
 
       if (extent_begin_glyph_layout (XEXTENT (gb->extent)) == GL_WHITESPACE)
        {
@@ -2920,7 +3133,7 @@ create_left_glyph_block (struct window *w, struct display_line *dl,
        struct glyph_block *gb = Dynarr_atp (dl->left_glyphs, elt);
 
        if (NILP (gb->extent))
-         abort ();     /* these should have been handled in add_glyph_rune */
+         ABORT ();     /* these should have been handled in add_glyph_rune */
 
        if (extent_begin_glyph_layout (XEXTENT (gb->extent)) ==
            GL_INSIDE_MARGIN)
@@ -2989,7 +3202,7 @@ create_left_glyph_block (struct window *w, struct display_line *dl,
        struct glyph_block *gb = Dynarr_atp (dl->left_glyphs, elt);
 
        if (NILP (gb->extent))
-         abort ();     /* these should have been handled in add_glyph_rune */
+         ABORT ();     /* these should have been handled in add_glyph_rune */
 
        if (extent_begin_glyph_layout (XEXTENT (gb->extent)) ==
            GL_INSIDE_MARGIN)
@@ -3031,7 +3244,7 @@ create_left_glyph_block (struct window *w, struct display_line *dl,
       struct glyph_block *gb = Dynarr_atp (dl->left_glyphs, elt);
 
       if (NILP (gb->extent))
-       abort ();       /* these should have been handled in add_glyph_rune */
+       ABORT ();       /* these should have been handled in add_glyph_rune */
 
       if (extent_begin_glyph_layout (XEXTENT (gb->extent)) ==
          GL_OUTSIDE_MARGIN)
@@ -3189,7 +3402,7 @@ create_right_glyph_block (struct window *w, struct display_line *dl)
       struct glyph_block *gb = Dynarr_atp (dl->right_glyphs, elt);
 
       if (NILP (gb->extent))
-       abort ();       /* these should have been handled in add_glyph_rune */
+       ABORT ();       /* these should have been handled in add_glyph_rune */
 
       if (extent_end_glyph_layout (XEXTENT (gb->extent)) == GL_WHITESPACE)
        {
@@ -3239,7 +3452,7 @@ create_right_glyph_block (struct window *w, struct display_line *dl)
        struct glyph_block *gb = Dynarr_atp (dl->right_glyphs, elt);
 
        if (NILP (gb->extent))
-         abort ();     /* these should have been handled in add_glyph_rune */
+         ABORT ();     /* these should have been handled in add_glyph_rune */
 
        if (extent_end_glyph_layout (XEXTENT (gb->extent)) == GL_INSIDE_MARGIN)
          {
@@ -3303,7 +3516,7 @@ create_right_glyph_block (struct window *w, struct display_line *dl)
        struct glyph_block *gb = Dynarr_atp (dl->right_glyphs, elt);
 
        if (NILP (gb->extent))
-         abort ();     /* these should have been handled in add_glyph_rune */
+         ABORT ();     /* these should have been handled in add_glyph_rune */
 
        if (extent_end_glyph_layout (XEXTENT (gb->extent)) == GL_INSIDE_MARGIN)
          {
@@ -3344,7 +3557,7 @@ create_right_glyph_block (struct window *w, struct display_line *dl)
       struct glyph_block *gb = Dynarr_atp (dl->right_glyphs, elt);
 
       if (NILP (gb->extent))
-       abort ();       /* these should have been handled in add_glyph_rune */
+       ABORT ();       /* these should have been handled in add_glyph_rune */
 
       if (extent_end_glyph_layout (XEXTENT (gb->extent)) == GL_OUTSIDE_MARGIN)
        {
@@ -3549,8 +3762,9 @@ generate_formatted_string_db (Lisp_Object format_str, Lisp_Object result_str,
           if (Dynarr_atp (db->runes, elt)->type == RUNE_CHAR)
             {
               len += (set_charptr_emchar
-                      (strdata + len, Dynarr_atp (db->runes,
-                                                  elt)->object.chr.ch));
+                     (strdata + len,
+                      CHARC_TO_CHAR (Dynarr_atp (db->runes,
+                                                 elt)->object.cglyph)));
             }
         }
 
@@ -4237,9 +4451,9 @@ real_current_modeline_height (struct window *w)
 
 \f
 /***************************************************************************/
-/*                                                             */
-/*                            displayable string routines                      */
-/*                                                             */
+/*                                                                         */
+/*                            displayable string routines                  */
+/*                                                                         */
 /***************************************************************************/
 
 /* Given a position for a string in a window, ensure that the given
@@ -4281,7 +4495,6 @@ create_string_text_block (struct window *w, Lisp_Object disp_string,
   pos_data data;
 
   int truncate_win = b ? window_truncation_on (w) : 0;
-  int end_glyph_width = 0;
 
   /* We're going to ditch selective display for static text, it's an
      FSF thing and invisible extents are the way to go here.
@@ -4389,13 +4602,7 @@ create_string_text_block (struct window *w, Lisp_Object disp_string,
   /* Set the right boundary adjusting it to take into account any end
      glyph.  Save the width of the end glyph for later use. */
   data.max_pixpos = dl->bounds.right_in;
-#if 0
-  if (truncate_win)
-    end_glyph_width = GLYPH_CACHEL_WIDTH (w, TRUN_GLYPH_INDEX);
-  else
-    end_glyph_width = GLYPH_CACHEL_WIDTH (w, CONT_GLYPH_INDEX);
-#endif
-  data.max_pixpos -= end_glyph_width;
+  data.max_pixpos -= data.end_glyph_width;
 
   data.cursor_type = NO_CURSOR;
   data.cursor_x = -1;
@@ -4451,10 +4658,18 @@ create_string_text_block (struct window *w, Lisp_Object disp_string,
       /* Check for face changes. */
       if (initial || (!no_more_frags && data.bi_bufpos == data.ef->end))
        {
+         Lisp_Object last_glyph = Qnil;
+         /* Deal with clipped glyphs that we have already displayed. */
+         if (*prop && Dynarr_atp (*prop, 0)->type == PROP_GLYPH) 
+           {
+             last_glyph = Dynarr_atp (*prop, 0)->data.p_glyph.glyph;
+             Dynarr_free (*prop);
+             *prop = 0;
+           }
          /* Now compute the face and begin/end-glyph information. */
          data.findex =
            /* Remember that the extent-fragment routines deal in Bytind's. */
-           extent_fragment_update (w, data.ef, data.bi_bufpos);
+           extent_fragment_update (w, data.ef, data.bi_bufpos, last_glyph);
          /* This is somewhat cheesy but the alternative is to
              propagate default_face into extent_fragment_update. */
          if (data.findex == DEFAULT_INDEX)
@@ -4509,7 +4724,7 @@ create_string_text_block (struct window *w, Lisp_Object disp_string,
                goto done;
            }
 
-         /* #### What if we we're dealing with a display table? */
+         /* #### What if we're dealing with a display table? */
          if (data.start_col)
            data.start_col--;
 
@@ -4533,7 +4748,7 @@ create_string_text_block (struct window *w, Lisp_Object disp_string,
          else if (data.bi_bufpos == bi_string_zv)
            goto done;
          else if (data.bi_bufpos < 0)
-           /* #### urk urk urk! Aborts are not very fun! Fix this please! */
+           /* #### urk urk urk! ABORTs are not very fun! Fix this please! */
            data.bi_bufpos = 0;
          else
            INC_CHARBYTIND (string_data (s), data.bi_bufpos);
@@ -4546,17 +4761,23 @@ create_string_text_block (struct window *w, Lisp_Object disp_string,
         a line are handled correctly. */
       else if (Dynarr_length (data.ef->end_glyphs) > 0)
        {
+         data.ch = string_char (s, data.bi_bufpos);
          *prop = add_glyph_runes (&data, END_GLYPHS);
-         if (*prop)
+
+         if (*prop) {
            goto done;
+         }
        }
 
       /* If there are begin glyphs, add them to the line. */
       else if (Dynarr_length (data.ef->begin_glyphs) > 0)
        {
+         data.ch = string_char (s, data.bi_bufpos);
          *prop = add_glyph_runes (&data, BEGIN_GLYPHS);
-         if (*prop)
+
+         if (*prop) {
            goto done;
+         }
        }
 
       /* If at end-of-buffer, we've already processed begin and
@@ -4590,7 +4811,7 @@ create_string_text_block (struct window *w, Lisp_Object disp_string,
              /* We aren't going to be adding an end glyph so give its
                  space back in order to make sure that the cursor can
                  fit. */
-             data.max_pixpos += end_glyph_width;
+             data.max_pixpos += data.end_glyph_width;
              goto done;
            }
 
@@ -4632,7 +4853,7 @@ create_string_text_block (struct window *w, Lisp_Object disp_string,
              *prop = add_blank_rune (&data, w, char_tab_width);
 
              /* add_blank_rune is only supposed to be called with
-                 sizes guaranteed to fit in the available space. */
+                sizes guaranteed to fit in the available space. */
              assert (!(*prop));
 
              if (prop_width)
@@ -4688,7 +4909,7 @@ create_string_text_block (struct window *w, Lisp_Object disp_string,
        }
     }
 
-done:
+ done:
 
   /* Determine the starting point of the next line if we did not hit the
      end of the buffer. */
@@ -4721,7 +4942,7 @@ done:
              for the next newline.  We also add the end-of-line glyph which
              we know will fit because we adjusted the right border before
              we starting laying out the line. */
-         data.max_pixpos += end_glyph_width;
+         data.max_pixpos += data.end_glyph_width;
          data.findex = default_face;
          gb.extent = Qnil;
 
@@ -4749,7 +4970,7 @@ done:
              cachel = GLYPH_CACHEL (w, CONT_GLYPH_INDEX);
            }
 
-         if (end_glyph_width)
+         if (data.end_glyph_width)
            add_glyph_rune (&data, &gb, BEGIN_GLYPHS, 0, cachel);
 
          if (truncate_win && data.bi_bufpos == bi_string_zv)
@@ -4779,7 +5000,7 @@ done:
       {
        struct rune *rb = Dynarr_atp (db->runes, elt);
 
-       if ((rb->type == RUNE_CHAR && rb->object.chr.ch == ' ')
+       if ((rb->type == RUNE_CHAR && CHARC_ASCII_EQ (rb->object.cglyph, ' '))
            || rb->type == RUNE_BLANK)
          {
            dl->bounds.left_white += rb->width;
@@ -4799,8 +5020,7 @@ done:
       {
        struct rune *rb = Dynarr_atp (db->runes, elt);
 
-       if (!(rb->type == RUNE_CHAR && rb->object.chr.ch < 0x100
-           && isspace (rb->object.chr.ch))
+       if (!(rb->type == RUNE_CHAR && CHARC_IS_SPACE (rb->object.cglyph))
            && !rb->type == RUNE_BLANK)
          {
            dl->bounds.right_white = rb->xpos + rb->width;
@@ -4828,26 +5048,7 @@ done:
   else
     db->end_pos = dl->bounds.right_white;
 
-  /* update line height parameters */
-  if (!data.new_ascent && !data.new_descent)
-    {
-      /* We've got a blank line so initialize these values from the default
-         face. */
-      default_face_font_info (data.window, &data.new_ascent,
-                             &data.new_descent, 0, 0, 0);
-    }
-
-  if (data.max_pixmap_height)
-    {
-      int height = data.new_ascent + data.new_descent;
-      int pix_ascent, pix_descent;
-
-      pix_descent = data.max_pixmap_height * data.new_descent / height;
-      pix_ascent = data.max_pixmap_height - pix_descent;
-
-      data.new_ascent = max (data.new_ascent, pix_ascent);
-      data.new_descent = max (data.new_descent, pix_descent);
-    }
+  calculate_baseline (&data);
 
   dl->ascent = data.new_ascent;
   dl->descent = data.new_descent;
@@ -4865,6 +5066,8 @@ done:
       dl->descent = descent;
   }
 
+  calculate_yoffset (dl, db);
+
   dl->cursor_elt = data.cursor_x;
   /* #### lossage lossage lossage! Fix this shit! */
   if (data.bi_bufpos > bi_string_zv)
@@ -5095,7 +5298,7 @@ regenerate_window (struct window *w, Bufpos start_pos, Bufpos point, int type)
 
   /* The lines had better exist by this point. */
   if (!(dla = window_display_lines (w, type)))
-    abort ();
+    ABORT ();
   Dynarr_reset (dla);
   w->max_line_len = 0;
 
@@ -5287,7 +5490,7 @@ regenerate_window (struct window *w, Bufpos start_pos, Bufpos point, int type)
            dla_start = 0;                      \
          }                                     \
        else                                    \
-         abort ();     /* structs differ */    \
+         ABORT ();     /* structs differ */    \
                                                \
        dla_end = Dynarr_length (cdla) - 1;     \
       }                                                \
@@ -6270,7 +6473,8 @@ redisplay_frame (struct frame *f, int preemption_check)
 {
   struct device *d = XDEVICE (f->device);
 
-  if (preemption_check)
+  if (preemption_check
+      && !DEVICE_IMPL_FLAG (d, XDEVIMPF_DONT_PREEMPT_REDISPLAY))
     {
       /* The preemption check itself takes a lot of time,
         so normally don't do it here.  We do it if called
@@ -6308,7 +6512,7 @@ redisplay_frame (struct frame *f, int preemption_check)
   /* The menubar, toolbar, and icon updates must be done before
      hold_frame_size_changes is called and we are officially
      'in_display'.  They may eval lisp code which may call Fsignal.
-     If in_display is set Fsignal will abort. */
+     If in_display is set Fsignal will ABORT. */
 
 #ifdef HAVE_MENUBARS
   /* Update the menubar.  It is done first since it could change
@@ -6318,8 +6522,13 @@ redisplay_frame (struct frame *f, int preemption_check)
   update_frame_menubars (f);
 #endif /* HAVE_MENUBARS */
 #ifdef HAVE_TOOLBARS
-  /* Update the toolbars. */
-  update_frame_toolbars (f);
+  /* Update the toolbars geometry. We don't update the toolbars
+     themselves at this point since the space they are trying to
+     occupy may currently by occupied by gutter elements. Instead we
+     update the geometry, then update the gutter geometry, then update
+     the gutters - which will cause mapped windows to be repositioned
+     - and finally update the toolbars. */
+  update_frame_toolbars_geometry (f);
 #endif /* HAVE_TOOLBARS */
   /* Gutter update proper has to be done inside display when no frame
      size changes can occur, thus we separately update the gutter
@@ -6363,10 +6572,10 @@ redisplay_frame (struct frame *f, int preemption_check)
      We need to remove them.
 
      If Fsignal() is called during this critical section, we
-     will abort().
+     will ABORT().
 
      If garbage collection is called during this critical section,
-     we simply return. #### We should abort instead.
+     we simply return. #### We should ABORT instead.
 
      #### If a frame-size change does occur we should probably
      actually be preempting redisplay. */
@@ -6399,6 +6608,14 @@ redisplay_frame (struct frame *f, int preemption_check)
 
   update_frame_title (f);
 
+#ifdef HAVE_TOOLBARS
+  /* Finally update the toolbars. It seems its possible to get in a
+     cycle between updating the gutter and the toolbars. Basically we
+     want to end up with both being up-to-date and this doesn't seem
+     possible in a single pass. */
+  update_frame_toolbars (f);
+#endif /* HAVE_TOOLBARS */
+
   CLASS_RESET_CHANGED_FLAGS (f);
   f->window_face_cache_reset = 0;
   f->echo_area_garbaged = 0;
@@ -6430,27 +6647,29 @@ static int
 redisplay_device (struct device *d, int automatic)
 {
   Lisp_Object frame, frmcons;
-  int preempted = 0;
   int size_change_failed = 0;
   struct frame *f;
 
-  if (automatic
-      && (MAYBE_INT_DEVMETH (d, device_implementation_flags, ())
-         & XDEVIMPF_NO_AUTO_REDISPLAY))
+  if (automatic && DEVICE_IMPL_FLAG (d, XDEVIMPF_NO_AUTO_REDISPLAY))
     return 0;
 
   if (DEVICE_STREAM_P (d)) /* nothing to do */
     return 0;
 
   /* It is possible that redisplay has been called before the
-     device is fully initialized.  If so then continue with the
-     next device. */
+     device is fully initialized, or that the console implementation
+     allows frameless devices.  If so then continue with the next
+     device. */
   if (NILP (DEVICE_SELECTED_FRAME (d)))
     return 0;
 
-  REDISPLAY_PREEMPTION_CHECK;
-  if (preempted)
-    return 1;
+  if (!DEVICE_IMPL_FLAG (d, XDEVIMPF_DONT_PREEMPT_REDISPLAY))
+    {
+      int preempted;
+      REDISPLAY_PREEMPTION_CHECK;
+      if (preempted)
+       return 1;
+    }
 
   /* Always do the selected frame first. */
   frame = DEVICE_SELECTED_FRAME (d);
@@ -6464,12 +6683,11 @@ redisplay_device (struct device *d, int automatic)
     {
       if (CLASS_REDISPLAY_FLAGS_CHANGEDP(f))
        {
-         preempted = redisplay_frame (f, 0);
+         int preempted = redisplay_frame (f, 0);
+         if (preempted)
+           return 1;
        }
 
-      if (preempted)
-       return 1;
-
       /* If the frame redisplay did not get preempted, then this flag
          should have gotten set to 0.  It might be possible for that
          not to happen if a size change event were to occur at an odd
@@ -6494,12 +6712,11 @@ redisplay_device (struct device *d, int automatic)
        {
          if (CLASS_REDISPLAY_FLAGS_CHANGEDP (f))
            {
-             preempted = redisplay_frame (f, 0);
+             int preempted = redisplay_frame (f, 0);
+             if (preempted)
+               return 1;
            }
 
-         if (preempted)
-           return 1;
-
          if (f->size_change_pending)
            size_change_failed = 1;
        }
@@ -7093,7 +7310,6 @@ mark_redisplay (void)
   FRAME_LOOP_NO_BREAK (frmcons, devcons, concons)
     {
       struct frame *f = XFRAME (XCAR (frmcons));
-      update_frame_window_mirror (f);
       mark_window_mirror (f->root_mirror);
       mark_gutters (f);
     }
@@ -7265,7 +7481,8 @@ point_in_line_start_cache (struct window *w, Bufpos point, int min_past)
 {
   struct buffer *b = XBUFFER (w->buffer);
   line_start_cache_dynarr *cache = w->line_start_cache;
-  unsigned int top, bottom, pos;
+  unsigned int top, bottom;
+  EMACS_INT pos;
 
   validate_line_start_cache (w);
   w->line_cache_validation_override++;
@@ -7283,7 +7500,7 @@ point_in_line_start_cache (struct window *w, Bufpos point, int min_past)
       int win_char_height = window_char_height (w, 1);
 
       /* Occasionally we get here with a 0 height
-         window. find_next_newline_no_quit will abort if we pass it a
+         window. find_next_newline_no_quit will ABORT if we pass it a
          count of 0 so handle that case. */
       if (!win_char_height)
        win_char_height = 1;
@@ -7393,7 +7610,7 @@ find_point_loop:
 
   while (1)
     {
-      unsigned int new_pos;
+      EMACS_INT new_pos;
       Bufpos start, end;
 
       pos = (bottom + top + 1) >> 1;
@@ -7435,7 +7652,7 @@ find_point_loop:
       else if (point < start)
        top = pos - 1;
       else
-       abort ();
+       ABORT ();
 
       new_pos = (bottom + top + 1) >> 1;
       if (pos == new_pos)
@@ -8704,7 +8921,7 @@ pixel_to_glyph_translation (struct frame *f, int x_coord, int y_coord,
                    }
                  else if (past_end
                           || (rb->type == RUNE_CHAR
-                              && rb->object.chr.ch == '\n'))
+                              && CHARC_ASCII_EQ (rb->object.cglyph, '\n')))
                    {
                      (*row)--;
                      /* At this point we may have glyphs in the right
@@ -9177,6 +9394,15 @@ init_redisplay (void)
     }
 #endif /* HAVE_X_WINDOWS */
 
+#ifdef HAVE_GTK
+  if (!strcmp (display_use, "gtk"))
+    {
+      Vwindow_system = Qgtk;
+      Vinitial_window_system = Qgtk;
+      return;
+    }
+#endif
+
 #ifdef HAVE_MS_WINDOWS
   if (!strcmp (display_use, "mswindows"))
     {
@@ -9366,7 +9592,7 @@ Non-nil means put cursor in minibuffer, at end of any message there.
      maybe a caret cursor, etc. */
 
   DEFVAR_LISP ("bar-cursor", &Vbar_cursor /*
-Use vertical bar cursor if non-nil.  If t width is 1 pixel, otherwise 2.
+*Use vertical bar cursor if non-nil.  If t width is 1 pixel, otherwise 2.
 */ );
   Vbar_cursor = Qnil;