2002-04-13  Nix  <nix@esperi.demon.co.uk>

	* redisplay.h (struct rune): Add ascent, descent, and yoffset fields.
	* redisplay-output.c (compare_runes): Compare them.
	* redisplay.c: Update copyright date.
	* redisplay.c (pos_data): Add need_baseline_computation field.
	* redisplay.c (add_glyph_rune): Update ascent, descent, and
	need_baseline_computation; zero yoffset. Set max_pixmap_height
	for all pixmaps, not just automatically positioned ones.
	* redisplay.c (calculate_yoffset): New, compute yoffset values.
	* redisplay.c (calculate_baseline): New, compute textual baseline.
	* redisplay.c (add_glyph_rune): Call them.
	* redisplay.c (create_text_block): Likewise.
	* redisplay.c (create_overlay_glyph_block): Likewise.
	* redisplay.c (add_margin_runes): Likewise.
	* redisplay.c (create_string_text_block): Likewise. Fix tabdamage.

	* redisplay.h: (redisplay_calculate_display_boxes): Change prototype.
	* redisplay-output.c (redisplay_calculate_display_boxes): Use yoffset.
	* redisplay-msw.c (mswindows_output_blank): Pass 0 as yoffset.
	* redisplay-msw.c (mswindows_output_string): Likewise.
	* redisplay-msw.c (mswindows_output_display_block): Pass yoffset.
	* redisplay-gtk.c (gtk_output_display_block): Likewise.
	* redisplay-x.c (x_output_display_block): Likewise.

diff -druN xemacs-orig/src/redisplay-gtk.c xemacs/src/redisplay-gtk.c
--- xemacs-orig/src/redisplay-gtk.c	Sat Apr 13 18:08:05 2002
+++ xemacs/src/redisplay-gtk.c	Sat Apr 13 18:23:45 2002
@@ -421,8 +421,8 @@
 	      struct display_box dbox;
 	      struct display_glyph_area dga;
 	      redisplay_calculate_display_boxes (dl, rb->xpos, rb->object.dglyph.xoffset,
-						 start_pixpos, rb->width,
-						 &dbox, &dga);
+						 rb->object.dglyph.yoffset ,start_pixpos,
+                                                 rb->width, &dbox, &dga);
 
 	      XSETWINDOW (window, w);
 	      instance = glyph_image_instance (rb->object.dglyph.glyph,
diff -druN xemacs-orig/src/redisplay-msw.c xemacs/src/redisplay-msw.c
--- xemacs-orig/src/redisplay-msw.c	Sat Apr 13 18:08:05 2002
+++ xemacs/src/redisplay-msw.c	Sat Apr 13 18:23:45 2002
@@ -309,6 +309,7 @@
       struct display_glyph_area dga;
       redisplay_calculate_display_boxes (dl, rb->xpos, 
 					 /*rb->object.dglyph.xoffset*/ 0,
+                                         /*rb->object.dglyph.yoffset*/ 0,
 					 start_pixpos, rb->width,
 					 &db, &dga);
       /* blank the background in the appropriate color */
@@ -512,7 +513,7 @@
     {
       struct display_box db;
       struct display_glyph_area dga;
-      redisplay_calculate_display_boxes (dl, xpos + xoffset, 0,
+      redisplay_calculate_display_boxes (dl, xpos + xoffset, 0, 0,
 					 clip_start, width, &db, &dga);
       /* blank the background in the appropriate color */
       mswindows_update_dc (hdc,
@@ -1165,8 +1166,8 @@
 	      struct display_glyph_area dga;
 
 	      redisplay_calculate_display_boxes (dl, rb->xpos, rb->object.dglyph.xoffset,
-						 start_pixpos, rb->width,
-						 &dbox, &dga);
+						 rb->object.dglyph.yoffset,
+                                                 start_pixpos, rb->width, &dbox, &dga);
 
 	      XSETWINDOW (window, w);
 	      instance = glyph_image_instance (rb->object.dglyph.glyph,
diff -druN xemacs-orig/src/redisplay-output.c xemacs/src/redisplay-output.c
--- xemacs-orig/src/redisplay-output.c	Sat Apr 13 18:08:05 2002
+++ xemacs/src/redisplay-output.c	Sat Apr 13 21:19:29 2002
@@ -230,7 +230,10 @@
   else if (crb->type == RUNE_DGLYPH &&
 	   (!EQ (crb->object.dglyph.glyph, drb->object.dglyph.glyph) ||
 	    !EQ (crb->object.dglyph.extent, drb->object.dglyph.extent) ||
-	    crb->object.dglyph.xoffset != drb->object.dglyph.xoffset))
+	    crb->object.dglyph.xoffset != drb->object.dglyph.xoffset ||
+	    crb->object.dglyph.yoffset != drb->object.dglyph.yoffset ||
+            crb->object.dglyph.ascent != drb->object.dglyph.ascent ||
+            crb->object.dglyph.descent != drb->object.dglyph.descent))
     return 0;
   /* Only check dirtiness if we know something has changed. */
   else if (crb->type == RUNE_DGLYPH &&
@@ -1789,7 +1792,7 @@
   /* Vertical offsets. This works because yoffset can be -ve as well as +ve */
   if (dest->ypos + glyphsrc->yoffset + glyphsrc->height > dest->ypos + dest->height)
     {
-      if (glyphsrc->yoffset > 0)
+      if ((glyphsrc->yoffset > 0) && (dest->height > glyphsrc->yoffset))
 	glyphsrc->height = dest->height - glyphsrc->yoffset;
       else
 	glyphsrc->height = dest->height;
@@ -1880,8 +1883,8 @@
  ****************************************************************************/
 int
 redisplay_calculate_display_boxes (struct display_line *dl, int xpos,
-				   int xoffset, int start_pixpos, int width,
-				   struct display_box* dest,
+				   int xoffset, int yoffset, int start_pixpos,
+                                   int width, struct display_box* dest,
 				   struct display_glyph_area* src)
 {
   dest->xpos = xpos;
@@ -1890,10 +1893,11 @@
   dest->height = DISPLAY_LINE_HEIGHT (dl);
 
   src->xoffset = -xoffset;
-  src->yoffset = -dl->top_clip;
   src->width = 0;
   src->height = 0;
 
+  src->yoffset = -dl->top_clip + yoffset;
+
   if (start_pixpos >=0 && start_pixpos > xpos)
     {
       /* Oops, we're asking for a start outside of the displayable
diff -druN xemacs-orig/src/redisplay-x.c xemacs/src/redisplay-x.c
--- xemacs-orig/src/redisplay-x.c	Sat Apr 13 18:08:06 2002
+++ xemacs/src/redisplay-x.c	Sat Apr 13 21:06:14 2002
@@ -439,11 +439,12 @@
 	      Lisp_Object instance;
 	      struct display_box dbox;
 	      struct display_glyph_area dga;
+
 	      redisplay_calculate_display_boxes (dl, rb->xpos, rb->object.dglyph.xoffset,
-						 start_pixpos, rb->width,
-						 &dbox, &dga);
+						 rb->object.dglyph.yoffset, start_pixpos,
+                                                 rb->width, &dbox, &dga);
 
-	      XSETWINDOW (window, w);
+              XSETWINDOW (window, w);
 	      instance = glyph_image_instance (rb->object.dglyph.glyph,
 					       window, ERROR_ME_NOT, 1);
 	      findex = rb->findex;
diff -druN xemacs-orig/src/redisplay.c xemacs/src/redisplay.c
--- xemacs-orig/src/redisplay.c	Sat Apr 13 18:08:06 2002
+++ xemacs/src/redisplay.c	Sat Apr 13 21:17:02 2002
@@ -4,6 +4,7 @@
    Copyright (C) 1995, 1996 Ben Wing.
    Copyright (C) 1995 Sun Microsystems, Inc.
    Copyright (C) 1996 Chuck Thompson.
+   Copyright (C) 1997 -- 2002 various XEmacs maintainers.
 
 This file is part of XEmacs.
 
@@ -147,9 +148,9 @@
 			   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 +164,19 @@
   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;
 
   Lisp_Object result_str; /* String where we put the result of
 			     generating a formatted string in the modeline. */
@@ -265,6 +267,9 @@
 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
@@ -680,6 +685,108 @@
   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
@@ -1622,6 +1729,8 @@
 
       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
@@ -1629,6 +1738,7 @@
 	  if (NILP (baseline))
 	    {
 	      int height = ascent + descent;
+              data->need_baseline_computation = 1;
 	      data->max_pixmap_height = max (data->max_pixmap_height, height);
 	    }
 
@@ -1651,6 +1761,9 @@
 
 	      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. */
@@ -1699,6 +1812,9 @@
       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)
 	{
@@ -2585,26 +2701,7 @@
   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;
@@ -2622,6 +2719,8 @@
       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))
@@ -2711,17 +2810,7 @@
       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;
@@ -2729,6 +2818,8 @@
   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;
 }
 
@@ -2800,20 +2891,13 @@
       (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;
 }
 
@@ -4243,9 +4327,9 @@
 
 
 /***************************************************************************/
-/*								*/
-/*                            displayable string routines			*/
-/*								*/
+/*                                                                         */
+/*                            displayable string routines                  */
+/*                                                                         */
 /***************************************************************************/
 
 /* Given a position for a string in a window, ensure that the given
@@ -4834,26 +4918,7 @@
   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;
@@ -4871,6 +4936,8 @@
       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)
diff -druN xemacs-orig/src/redisplay.h xemacs/src/redisplay.h
--- xemacs-orig/src/redisplay.h	Sat Apr 13 18:08:06 2002
+++ xemacs/src/redisplay.h	Sat Apr 13 18:23:46 2002
@@ -147,6 +147,9 @@
                                    If this is a rune in the modeline
                                    then this might be nil. */
 
+      int ascent;               /* Ascent of this glyph, in pixels. */
+      int descent;              /* Descent of this glyph, in pixels. */
+      int yoffset;              /* Offset from line top to reach glyph top */
       int xoffset;		/* Number of pixels that need to be
 				   chopped off the left of the glyph.
 				   This has the effect of shifting the
@@ -768,8 +771,8 @@
 			      face_index findex, int cursor_start, int cursor_width,
 			      int cursor_height, int offset_bitmap);
 int redisplay_calculate_display_boxes (struct display_line *dl, int xpos,
-				       int xoffset, int start_pixpos, int width,
-				       struct display_box* dest,
+				       int xoffset, int yoffset, int start_pixpos,
+                                       int width, struct display_box* dest,
 				       struct display_glyph_area* src);
 int redisplay_normalize_glyph_area (struct display_box* dest,
 				    struct display_glyph_area* glyphsrc);
