changeset 26879:b4de7fa9866e

(x_append_glyph): Setup members of struct glyph properly for composition. (x_append_composite_glyph): New function. (VCENTER_BASELINE_OFFSET): New macro. (x_produce_glyphs): If it->what == IT_COMPOSITION, setup members of struct it for the composition. Cache pixel offsets in the struct composition. Delete codes for a composite character. Handle Vignore_relative_composition in composition code. (struct glyph_string): Delete member cmpcharp, add new member cmp. (x_set_cursor_gc): Check s->cmp, not s->cmpcharp. (x_compute_glyph_string_overhangs): Likewise. (x_get_glyph_overhangs): Delete codes for a composite character. (x_right_overwritten): Check s->cmp, not s->cmpcharp. (x_draw_glyph_string_background): Likewise. Delete codes for checking s->gidx for a composition. (x_draw_glyph_string_foreground): Delete code for a composite character. (x_draw_composite_glyph_string_foreground): New function. (x_draw_glyph_string_box): Check s->cmp, not s->cmpcharp. (x_draw_glyph_string): Handle the case of COMPOSITE_GLYPH. (struct work): Deleted. (x_fill_composite_glyph_string): Argument changed. Mostly rewritten for that. (x_fill_glyph_string): Don't check CHARSET_COMPOSITION. (BUILD_CHAR_GLYPH_STRINGS): Don't handle composition here. (BUILD_COMPOSITE_GLYPH_STRING): New macro. (BUILD_GLYPH_STRINGS): For composition, call BUILD_COMPOSITE_GLYPH_STRING. (x_new_font): Initialize f->output_data.x->baseline_offset, not f->output_data.x->font_baseline.
author Kenichi Handa <handa@m17n.org>
date Wed, 15 Dec 1999 00:27:21 +0000
parents 0020f5359d09
children 98564c5250e4
files src/xterm.c
diffstat 1 files changed, 572 insertions(+), 418 deletions(-) [+]
line wrap: on
line diff
--- a/src/xterm.c	Wed Dec 15 00:26:32 1999 +0000
+++ b/src/xterm.c	Wed Dec 15 00:27:21 1999 +0000
@@ -1096,6 +1096,7 @@
 static XCharStruct *x_per_char_metric P_ ((XFontStruct *, XChar2b *));
 static void x_encode_char P_ ((int, XChar2b *, struct font_info *));
 static void x_append_glyph P_ ((struct it *));
+static void x_append_composite_glyph P_ ((struct it *));
 static void x_append_stretch_glyph P_ ((struct it *it, Lisp_Object,
 					int, int, double));
 static void x_produce_glyphs P_ ((struct it *));
@@ -1310,9 +1311,9 @@
 
       /* Get the face for displaying C.  If `face' is not suitable for
 	 charset, get the one that fits.  (This can happen for the
-	 translations of composite characters where the glyph
-	 specifies a face for ASCII, but translations have a different
-	 charset.)  */
+	 translations of a composition where the glyph
+	 specifies a face for the first component, but the other
+	 components have a different charset.)  */
       if (!FACE_SUITABLE_FOR_CHARSET_P (face, charset))
 	{
 	  face_id = FACE_FOR_CHARSET (f, face_id, charset);
@@ -1444,6 +1445,42 @@
     }
 }
 
+/* Store one glyph for the composition IT->cmp_id in IT->glyph_row.  
+   Called from x_produce_glyphs when IT->glyph_row is non-null.  */
+
+static INLINE void
+x_append_composite_glyph (it)
+     struct it *it;
+{
+  struct glyph *glyph;
+  enum glyph_row_area area = it->area;
+  
+  xassert (it->glyph_row);
+  
+  glyph = it->glyph_row->glyphs[area] + it->glyph_row->used[area];
+  if (glyph < it->glyph_row->glyphs[area + 1])
+    {
+      /* Play it safe.  If sub-structures of the glyph are not all the
+	 same size, it otherwise be that some bits stay set.  This
+	 would prevent a comparison with GLYPH_EQUAL_P.  */
+      glyph->u.val = 0;
+      
+      glyph->type = COMPOSITE_GLYPH;
+      glyph->pixel_width = it->pixel_width;
+      glyph->u.cmp.id = it->cmp_id;
+      glyph->u.cmp.face_id = it->face_id;
+      glyph->charpos = CHARPOS (it->position);
+      glyph->object = it->object;
+      glyph->left_box_line_p = it->start_of_box_run_p;
+      glyph->right_box_line_p = it->end_of_box_run_p;
+      glyph->voffset = it->voffset;
+      glyph->multibyte_p = it->multibyte_p;
+      glyph->overlaps_vertically_p = (it->phys_ascent > it->ascent
+				      || it->phys_descent > it->descent);
+      ++it->glyph_row->used[area];
+    }
+}
+
 
 /* Change IT->ascent and IT->height according to the setting of
    IT->voffset.  */
@@ -1709,6 +1746,38 @@
   take_vertical_position_into_account (it);
 }
 
+/* Return proper value to be used as baseline offset of font that has
+   ASCENT and DESCENT to draw characters by the font at the vertical
+   center of the line of frame F.
+
+   Here, out task is to find the value of BOFF in the following figure;
+
+	-------------------------+-----------+-
+	 -+-+---------+-+        |           |
+	  | |         | |        |           |
+	  | |         | |        F_ASCENT    F_HEIGHT
+	  | |         | ASCENT   |           |
+     HEIGHT |         | |        |           |
+	  | |         |-|-+------+-----------|------- baseline
+	  | |         | | BOFF   |           |
+	  | |---------|-+-+      |           |
+	  | |         | DESCENT  |           |
+	 -+-+---------+-+        F_DESCENT   |
+	-------------------------+-----------+-
+
+	-BOFF + DESCENT + (F_HEIGHT - HEIGHT) / 2 = F_DESCENT
+	BOFF = DESCENT +  (F_HEIGHT - HEIGHT) / 2 - F_DESCENT
+	DESCENT = FONT->descent
+	HEIGHT = FONT_HEIGHT (FONT)
+	F_DESCENT = (F->output_data.x->font->descent
+		     - F->output_data.x->baseline_offset)
+	F_HEIGHT = FRAME_LINE_HEIGHT (F)
+*/
+
+#define VCENTER_BASELINE_OFFSET(FONT, F)		\
+ ((FONT)->descent						\
+  + (FRAME_LINE_HEIGHT ((F)) - FONT_HEIGHT ((FONT))) / 2	\
+  - ((F)->output_data.x->font->descent - (F)->output_data.x->baseline_offset))
 
 /* Produce glyphs/get display metrics for the display element IT is
    loaded with.  See the description of struct display_iterator in
@@ -1725,6 +1794,8 @@
       struct face *face;
       XCharStruct *pcm;
       int font_not_found_p;
+      struct font_info *font_info;
+      int boff;			/* baseline offset */
 
       /* Maybe translate single-byte characters to multibyte.  */
       it->char_to_display = it->c;
@@ -1747,7 +1818,18 @@
       /* When no suitable font found, use the default font.  */
       font_not_found_p = font == NULL;
       if (font_not_found_p)
-	font = FRAME_FONT (it->f);
+	{
+	  font = FRAME_FONT (it->f);
+	  boff = it->f->output_data.x->baseline_offset;
+	  font_info = NULL;
+	}
+      else
+	{
+	  font_info = FONT_INFO_FROM_ID (it->f, face->font_info_id);
+	  boff = font_info->baseline_offset;
+	  if (font_info->vertical_centering)
+	    boff = VCENTER_BASELINE_OFFSET (font, it->f) - boff;
+	}
 
       if (it->char_to_display >= ' '
 	  && (!it->multibyte_p || it->char_to_display < 128))
@@ -1758,10 +1840,10 @@
 	  it->nglyphs = 1;
 
 	  pcm = x_per_char_metric (font, &char2b);
-	  it->ascent = font->ascent;
-	  it->descent = font->descent;
-	  it->phys_ascent = pcm->ascent;
-	  it->phys_descent = pcm->descent;
+	  it->ascent = font->ascent + boff;
+	  it->descent = font->descent - boff;
+	  it->phys_ascent = pcm->ascent + boff;
+	  it->phys_descent = pcm->descent - boff;
 	  it->pixel_width = pcm->width;
 
 	  /* If this is a space inside a region of text with
@@ -1820,8 +1902,8 @@
 	  /* A newline has no width but we need the height of the line.  */
 	  it->pixel_width = 0;
 	  it->nglyphs = 0;
-	  it->ascent = it->phys_ascent = font->ascent;
-	  it->descent = it->phys_descent = font->descent;
+	  it->ascent = it->phys_ascent = font->ascent + boff;
+	  it->descent = it->phys_descent = font->descent - boff;
       
 	  if (face->box != FACE_NO_BOX)
 	    {
@@ -1840,8 +1922,8 @@
       
 	  it->pixel_width = next_tab_x - x;
 	  it->nglyphs = 1;
-	  it->ascent = it->phys_ascent = font->ascent;
-	  it->descent = it->phys_descent = font->descent;
+	  it->ascent = it->phys_ascent = font->ascent + boff;
+	  it->descent = it->phys_descent = font->descent - boff;
 	  
 	  if (it->glyph_row)
 	    {
@@ -1854,55 +1936,26 @@
 	{
 	  /* A multi-byte character.  Assume that the display width of the
 	     character is the width of the character multiplied by the
-	     width of the font.  There has to be better support for
-	     variable sizes in cmpchar_info to do anything better than
-	     that.
-
-	     Note: composite characters are represented as one glyph in
-	     the glyph matrix.  There are no padding glyphs.  */
-	  if (it->charset == CHARSET_COMPOSITION)
-	    {
-	      struct cmpchar_info *cmpcharp;
-	      int idx;
-
-	      idx = COMPOSITE_CHAR_ID (it->char_to_display);
-	      cmpcharp = cmpchar_table[idx];
-	      it->pixel_width = font->max_bounds.width * cmpcharp->width;
-	  
-	      /* There are no padding glyphs, so there is only one glyph
-		 to produce for the composite char.  Important is that
-		 pixel_width, ascent and descent are the values of what is
-		 drawn by draw_glyphs.  */
-	      it->nglyphs = 1;
-
-	      /* These settings may not be correct.  We must have more
-		 information in cmpcharp to do the correct setting.  */
-	      it->ascent = font->ascent;
-	      it->descent = font->descent;
-	      it->phys_ascent = font->max_bounds.ascent;
-	      it->phys_descent = font->max_bounds.descent;
-	    }
-	  else
-	    {
-	      /* If we found a font, this font should give us the right
-		 metrics.  If we didn't find a font, use the frame's
-		 default font and calculate the width of the character
-		 from the charset width; this is what old redisplay code
-		 did.  */
-	      pcm = x_per_char_metric (font, &char2b);
-	      it->pixel_width = pcm->width;
-	      if (font_not_found_p)
-		it->pixel_width *= CHARSET_WIDTH (it->charset);
-	      it->nglyphs = 1;
-	      it->ascent = font->ascent;
-	      it->descent = font->descent;
-	      it->phys_ascent = pcm->ascent;
-	      it->phys_descent = pcm->descent;
-	      if (it->glyph_row
-		  && (pcm->lbearing < 0
-		      || pcm->rbearing > pcm->width))
-		it->glyph_row->contains_overlapping_glyphs_p = 1;
-	    }
+	     width of the font.  */
+
+	  /* If we found a font, this font should give us the right
+	     metrics.  If we didn't find a font, use the frame's
+	     default font and calculate the width of the character
+	     from the charset width; this is what old redisplay code
+	     did.  */
+	  pcm = x_per_char_metric (font, &char2b);
+	  it->pixel_width = pcm->width;
+	  if (font_not_found_p)
+	    it->pixel_width *= CHARSET_WIDTH (it->charset);
+	  it->nglyphs = 1;
+	  it->ascent = font->ascent + boff;
+	  it->descent = font->descent - boff;
+	  it->phys_ascent = pcm->ascent + boff;
+	  it->phys_descent = pcm->descent - boff;
+	  if (it->glyph_row
+	      && (pcm->lbearing < 0
+		  || pcm->rbearing > pcm->width))
+	    it->glyph_row->contains_overlapping_glyphs_p = 1;
 	
 	  if (face->box != FACE_NO_BOX)
 	    {
@@ -1927,6 +1980,245 @@
 	    x_append_glyph (it);
 	}
     }
+  else if (it->what == IT_COMPOSITION)
+    {
+      /* Note: A composition is represented as one glyph in the
+	 glyph matrix.  There are no padding glyphs.  */
+      XChar2b char2b;
+      XFontStruct *font;
+      struct face *face;
+      XCharStruct *pcm;
+      int font_not_found_p;
+      struct font_info *font_info;
+      int boff;			/* baseline offset */
+      struct composition *cmp = composition_table[it->cmp_id];
+
+      /* Maybe translate single-byte characters to multibyte.  */
+      it->char_to_display = it->c;
+      if (unibyte_display_via_language_environment
+	  && SINGLE_BYTE_CHAR_P (it->c)
+	  && (it->c >= 0240
+	      || (it->c >= 0200
+		  && !NILP (Vnonascii_translation_table))))
+	{
+	  it->char_to_display = unibyte_char_to_multibyte (it->c);
+	  it->charset = CHAR_CHARSET (it->char_to_display);
+	}
+      
+      /* Get face and font to use.  Encode IT->char_to_display.  */
+      face = x_get_char_face_and_encoding (it->f, it->char_to_display,
+					   it->face_id, &char2b,
+					   it->multibyte_p);
+      font = face->font;
+
+      /* When no suitable font found, use the default font.  */
+      font_not_found_p = font == NULL;
+      if (font_not_found_p)
+	{
+	  font = FRAME_FONT (it->f);
+	  boff = it->f->output_data.x->baseline_offset;
+	  font_info = NULL;
+	}
+      else
+	{
+	  font_info = FONT_INFO_FROM_ID (it->f, face->font_info_id);
+	  boff = font_info->baseline_offset;
+	  if (font_info->vertical_centering)
+	    boff = VCENTER_BASELINE_OFFSET (font, it->f) - boff;
+	}
+
+      /* There are no padding glyphs, so there is only one glyph to
+	 produce for the composition.  Important is that pixel_width,
+	 ascent and descent are the values of what is drawn by
+	 draw_glyphs (i.e. the values of the overall glyphs composed).  */
+      it->nglyphs = 1;
+
+      /* If we have not yet calculated pixel size data of glyphs of
+	 the composition for the current face font, calculate them
+	 now.  Theoretically, we have to check all fonts for the
+	 glyphs, but that requires much time and memory space.  So,
+	 here we check only the font of the first glyph.  This leads
+	 to incorrect display very rarely, and C-l (recenter) can
+	 correct the display anyway.  */
+      if (cmp->font != (void *) font)
+	{
+	  /* Ascent and descent of the font of the first character of
+	     this composition (adjusted by baseline offset).  Ascent
+	     and descent of overall glyphs should not be less than
+	     them respectively.  */
+	  int font_ascent = font->ascent + boff;
+	  int font_descent = font->descent - boff;
+	  /* Bounding box of the overall glyphs.  */
+	  int leftmost, rightmost, lowest, highest;
+	  int i;
+
+	  cmp->font = (void *) font;
+
+	  /* Initialize the bounding box.  */
+	  pcm = x_per_char_metric (font, &char2b);
+	  leftmost = 0;
+	  rightmost = pcm->width;
+	  lowest = - pcm->descent + boff;
+	  highest = pcm->ascent + boff;
+	  if (font_info
+	      && font_info->default_ascent
+	      && CHAR_TABLE_P (Vuse_default_ascent)
+	      && !NILP (Faref (Vuse_default_ascent,
+			       make_number (it->char_to_display))))
+	    highest = font_info->default_ascent + boff;
+
+	  /* Draw the first glyph at the normal position.  It may be
+	     shifted to right later if some other glyphs are drawn at
+	     the left.  */
+	  cmp->offsets[0] = 0;
+	  cmp->offsets[1] = boff;
+
+	  /* Set cmp->offsets for the remaining glyphs.  */
+	  for (i = 1; i < cmp->glyph_len; i++)
+	    {
+	      int left, right, btm, top;
+	      int ch = COMPOSITION_GLYPH (cmp, i);
+
+	      face = x_get_char_face_and_encoding (it->f, ch,
+						   it->face_id, &char2b,
+						   it->multibyte_p);
+	      font = face->font;
+	      if (font == NULL)
+		{
+		  font = FRAME_FONT (it->f);
+		  boff = it->f->output_data.x->baseline_offset;
+		  font_info = NULL;
+		}
+	      else
+		{
+		  font_info
+		    = FONT_INFO_FROM_ID (it->f, face->font_info_id);
+		  boff = font_info->baseline_offset;
+		  if (font_info->vertical_centering)
+		    boff = VCENTER_BASELINE_OFFSET (font, it->f) - boff;
+		}
+
+	      pcm = x_per_char_metric (font, &char2b);
+
+	      if (cmp->method != COMPOSITION_WITH_RULE_ALTCHARS)
+		{
+		  /* Relative composition with or without
+		     alternate chars.  */
+		  left = (leftmost + rightmost - pcm->width) / 2;
+		  btm = - pcm->descent + boff;
+		  if (font_info && font_info->relative_compose
+		      && (! CHAR_TABLE_P (Vignore_relative_composition)
+			  || NILP (Faref (Vignore_relative_composition,
+					  make_number (ch)))))
+		    {
+
+		      if (- pcm->descent
+			  >= font_info->relative_compose)
+			/* One extra pixel between two glyphs.  */
+			btm = highest + 1;
+		      else if (pcm->ascent <= 0)
+			/* One extra pixel between two glyphs.  */
+			btm = lowest - 1 - pcm->ascent - pcm->descent;
+		    }
+		}
+	      else
+		{
+		  /* A composition rule is specified by an integer
+		     value that encodes global and new reference
+		     points (GREF and NREF).  GREF and NREF are
+		     specified by numbers as below:
+
+			0---1---2 -- ascent
+			|       |
+			|       |
+			|       |
+			9--10--11 -- center
+			|       |
+		     ---3---4---5--- baseline
+			|       |
+			6---7---8 -- descent
+		  */
+		  int rule = COMPOSITION_RULE (cmp, i);
+		  int gref, nref, grefx, grefy, nrefx, nrefy;
+
+		  COMPOSITION_DECODE_RULE (rule, gref, nref);
+		  grefx = gref % 3, nrefx = nref % 3;
+		  grefy = gref / 3, nrefy = nref / 3;
+
+		  left = (leftmost
+			  + grefx * (rightmost - leftmost) / 2
+			  - nrefx * pcm->width / 2);
+		  btm = ((grefy == 0 ? highest
+			  : grefy == 1 ? 0
+			  : grefy == 2 ? lowest
+			  : (highest + lowest) / 2)
+			 - (nrefy == 0 ? pcm->ascent + pcm->descent
+			    : nrefy == 1 ? pcm->descent - boff
+			    : nrefy == 2 ? 0
+			    : (pcm->ascent + pcm->descent) / 2));
+		}
+
+	      cmp->offsets[i * 2] = left;
+	      cmp->offsets[i * 2 + 1] = btm + pcm->descent;
+
+	      /* Update the bounding box of the overall glyphs. */
+	      right = left + pcm->width;
+	      top = btm + pcm->descent + pcm->ascent;
+	      if (left < leftmost)
+		leftmost = left;
+	      if (right > rightmost)
+		rightmost = right;
+	      if (top > highest)
+		highest = top;
+	      if (btm < lowest)
+		lowest = btm;
+	    }
+
+	  /* If there are glyphs whose x-offsets are negative,
+	     shift all glyphs to the right and make all x-offsets
+	     non-negative.  */
+	  if (leftmost < 0)
+	    {
+	      for (i = 0; i < cmp->glyph_len; i++)
+		cmp->offsets[i * 2] -= leftmost;
+	      rightmost -= leftmost;
+	    }
+
+	  cmp->pixel_width = rightmost;
+	  cmp->ascent = highest;
+	  cmp->descent = - lowest;
+	  if (cmp->ascent < font_ascent)
+	    cmp->ascent = font_ascent;
+	  if (cmp->descent < font_descent)
+	    cmp->descent = font_descent;
+	}
+
+      it->pixel_width = cmp->pixel_width;
+      it->ascent = it->phys_ascent = cmp->ascent;
+      it->descent = it->phys_descent = cmp->descent;
+
+      if (face->box != FACE_NO_BOX)
+	{
+	  int thick = face->box_line_width;
+	  it->ascent += thick;
+	  it->descent += thick;
+	  
+	  if (it->start_of_box_run_p)
+	    it->pixel_width += thick;
+	  if (it->end_of_box_run_p)
+	    it->pixel_width += thick;
+	}
+  
+      /* If face has an overline, add the height of the overline
+	 (1 pixel) and a 1 pixel margin to the character height.  */
+      if (face->overline_p)
+	it->ascent += 2;
+
+      take_vertical_position_into_account (it);
+  
+      if (it->glyph_row)
+	x_append_composite_glyph (it);
+    }
   else if (it->what == IT_IMAGE)
     x_produce_image_glyph (it);
   else if (it->what == IT_STRETCH)
@@ -2043,14 +2335,13 @@
   /* Font info for this string.  */
   struct font_info *font_info;
 
-  /* Non-null means this string describes (part of) a composite
-     character.  All characters from char2b are drawn at the same
-     x-origin in that case.  */
-  struct cmpchar_info *cmpcharp;
+  /* Non-null means this string describes (part of) a composition.
+     All characters from char2b are drawn composed.  */
+  struct composition *cmp;
 
   /* Index of this glyph string's first character in the glyph
-     definition of cmpcharp.  If this is zero, this glyph string
-     describes the first character of a composite character.  */
+     definition of CMP.  If this is zero, this glyph string describes
+     the first character of a composition.  */
   int gidx;
 
   /* 1 means this glyph strings face has to be drawn to the right end
@@ -2146,6 +2437,7 @@
 static void x_draw_glyph_string_background P_ ((struct glyph_string *,
 						int));
 static void x_draw_glyph_string_foreground P_ ((struct glyph_string *));
+static void x_draw_composite_glyph_string_foreground P_ ((struct glyph_string *));
 static void x_draw_glyph_string_box P_ ((struct glyph_string *));
 static void x_draw_glyph_string  P_ ((struct glyph_string *));
 static void x_compute_glyph_string_overhangs P_ ((struct glyph_string *));
@@ -2239,7 +2531,7 @@
   if (s->font == FRAME_FONT (s->f)
       && s->face->background == FRAME_BACKGROUND_PIXEL (s->f)
       && s->face->foreground == FRAME_FOREGROUND_PIXEL (s->f)
-      && !s->cmpcharp)
+      && !s->cmp)
     s->gc = s->f->output_data.x->cursor_gc;
   else
     {
@@ -2466,13 +2758,13 @@
 
 
 /* Compute left and right overhang of glyph string S.  If S is a glyph
-   string for a composite character, assume overhangs don't exist.  */
+   string for a composition, assume overhangs don't exist.  */
 
 static INLINE void
 x_compute_glyph_string_overhangs (s)
      struct glyph_string *s;
 {
-  if (s->cmpcharp == NULL
+  if (s->cmp == NULL
       && s->first_glyph->type == CHAR_GLYPH)
     {
       XCharStruct cs;
@@ -2519,8 +2811,8 @@
 
 
 /* Set *LEFT and *RIGHT to the left and right overhang of GLYPH on
-   frame F.  Overhangs of glyphs other than type CHAR_GLYPH or of
-   character glyphs for composite characters are assumed to be zero.  */
+   frame F.  Overhangs of glyphs other than type CHAR_GLYPH are
+   assumed to be zero.  */
 
 static void
 x_get_glyph_overhangs (glyph, f, left, right)
@@ -2532,9 +2824,7 @@
   
   *left = *right = 0;
   
-  if (glyph->type == CHAR_GLYPH
-      && (c = glyph->u.ch.code,
-	  CHAR_CHARSET (c) != CHARSET_COMPOSITION))
+  if (glyph->type == CHAR_GLYPH)
     {
       XFontStruct *font;
       struct face *face;
@@ -2626,7 +2916,7 @@
     {
       int x = 0, i;
       struct glyph *glyphs = s->row->glyphs[s->area];
-      int first = (s->first_glyph - glyphs) + (s->cmpcharp ? 1 : s->nchars);
+      int first = (s->first_glyph - glyphs) + (s->cmp ? 1 : s->nchars);
       int end = s->row->used[s->area];
       
       for (i = first; i < end && s->right_overhang > x; ++i)
@@ -2650,7 +2940,7 @@
   int i, k, x;
   int end = s->row->used[s->area];
   struct glyph *glyphs = s->row->glyphs[s->area];
-  int first = (s->first_glyph - glyphs) + (s->cmpcharp ? 1 : s->nchars);
+  int first = (s->first_glyph - glyphs) + (s->cmp ? 1 : s->nchars);
 
   k = -1;
   x = 0;
@@ -2685,7 +2975,8 @@
 /* Draw the background of glyph_string S.  If S->background_filled_p
    is non-zero don't draw it.  FORCE_P non-zero means draw the
    background even if it wouldn't be drawn normally.  This is used
-   when a string preceding S draws into the background of S.  */
+   when a string preceding S draws into the background of S, or S
+   contains the first component of a composition.  */
 
 static void
 x_draw_glyph_string_background (s, force_p)
@@ -2696,16 +2987,7 @@
      shouldn't be drawn in the first place.  */
   if (!s->background_filled_p)
     {
-      if (s->cmpcharp
-	  && s->gidx > 0
-	  && !s->font_not_found_p
-	  && !s->extends_to_end_of_line_p)
-	{
-	  /* Don't draw background for glyphs of a composite
-	     characters, except for the first one.  */
-	  s->background_filled_p = 1;
-	}
-      else if (s->stippled_p)
+      if (s->stippled_p)
 	{
 	  /* Fill background with a stipple pattern.  */
 	  XSetFillStyle (s->display, s->gc, FillOpaqueStippled);
@@ -2719,7 +3001,6 @@
       else if (FONT_HEIGHT (s->font) < s->height - 2 * s->face->box_line_width
 	       || s->font_not_found_p
 	       || s->extends_to_end_of_line_p
-	       || s->cmpcharp
 	       || force_p)
 	{
 	  x_clear_glyph_string_rect (s, s->x, s->y + s->face->box_line_width,
@@ -2747,192 +3028,96 @@
   else
     x = s->x;
 
-  if (s->cmpcharp == NULL)
-    {
-      /* Not a composite character.  Draw characters of S as
-	 rectangles if S's font could not be loaded.  */
-      if (s->font_not_found_p)
-	{
-	  for (i = 0; i < s->nchars; ++i)
-	    {
-	      struct glyph *g = s->first_glyph + i;
-	      XDrawRectangle (s->display, s->window,
-			      s->gc, x, s->y, g->pixel_width - 1,
-			      s->height - 1);
-	      x += g->pixel_width;
-	    }
+  /* Draw characters of S as rectangles if S's font could not be
+     loaded.  */
+  if (s->font_not_found_p)
+    {
+      for (i = 0; i < s->nchars; ++i)
+	{
+	  struct glyph *g = s->first_glyph + i;
+	  XDrawRectangle (s->display, s->window,
+			  s->gc, x, s->y, g->pixel_width - 1,
+			  s->height - 1);
+	  x += g->pixel_width;
+	}
+    }
+  else
+    {
+      char *char1b = (char *) s->char2b;
+      int boff = s->font_info->baseline_offset;
+
+      if (s->font_info->vertical_centering)
+	boff = VCENTER_BASELINE_OFFSET (s->font, s->f) - boff;
+
+      /* If we can use 8-bit functions, condense S->char2b.  */
+      if (!s->two_byte_p)
+	for (i = 0; i < s->nchars; ++i)
+	  char1b[i] = s->char2b[i].byte2;
+
+      /* Draw text with XDrawString if background has already been
+	 filled.  Otherwise, use XDrawImageString.  (Note that
+	 XDrawImageString is usually faster than XDrawString.)  Always
+	 use XDrawImageString when drawing the cursor so that there is
+	 no chance that characters under a box cursor are invisible.  */
+      if (s->for_overlaps_p
+	  || (s->background_filled_p && s->hl != DRAW_CURSOR))
+	{
+	  /* Draw characters with 16-bit or 8-bit functions.  */
+	  if (s->two_byte_p)
+	    XDrawString16 (s->display, s->window, s->gc, x,
+			   s->ybase - boff, s->char2b, s->nchars);
+	  else
+	    XDrawString (s->display, s->window, s->gc, x,
+			 s->ybase - boff, char1b, s->nchars);
 	}
       else
 	{
-	  char *char1b = (char *) s->char2b;
-
-	  /* If we can use 8-bit functions, condense S->char2b.  */
-	  if (!s->two_byte_p)
-	    for (i = 0; i < s->nchars; ++i)
-	      char1b[i] = s->char2b[i].byte2;
-
-	  /* Draw text with XDrawString if background has already been
-	     filled.  Otherwise, use XDrawImageString.  (Note that
-	     XDrawImageString is usually faster than XDrawString.)
-	     Always use XDrawImageString when drawing the cursor so
-	     that there is no chance that characters under a box
-	     cursor are invisible.  */
-	  if (s->for_overlaps_p
-	      || (s->background_filled_p && s->hl != DRAW_CURSOR))
-	    {
-	      /* Draw characters with 16-bit or 8-bit functions.  */
-	      if (s->two_byte_p)
-		XDrawString16 (s->display, s->window, s->gc, x, s->ybase, 
-			       s->char2b, s->nchars);
-	      else
-		XDrawString (s->display, s->window, s->gc, x, s->ybase, 
-			     char1b, s->nchars);
-	    }
+	  if (s->two_byte_p)
+	    XDrawImageString16 (s->display, s->window, s->gc, x,
+				s->ybase - boff, s->char2b, s->nchars);
 	  else
-	    {
-	      if (s->two_byte_p)
-		XDrawImageString16 (s->display, s->window, s->gc,
-				    x, s->ybase, s->char2b, s->nchars);
-	      else
-		XDrawImageString (s->display, s->window, s->gc,
-				  x, s->ybase, char1b, s->nchars);
-	    }
-	}
-    }
-  else
-    {
-      /* S is a glyph string for a composite character. S->gidx is the
-	 index of the first character drawn in the vector
-	 S->cmpcharp->glyph.  S->gidx == 0 means we are drawing the
-	 very first component character of a composite char.  */
-
-      /* Draw a single rectangle for the composite character if S's
-	 font could not be loaded.  */
-      if (s->font_not_found_p && s->gidx == 0)
+	    XDrawImageString (s->display, s->window, s->gc, x,
+			      s->ybase - boff, char1b, s->nchars);
+	}
+    }
+}
+
+/* Draw the foreground of composite glyph string S.  */
+
+static void
+x_draw_composite_glyph_string_foreground (s)
+     struct glyph_string *s;
+{
+  int i, x;
+
+  /* If first glyph of S has a left box line, start drawing the text
+     of S to the right of that box line.  */
+  if (s->face->box != FACE_NO_BOX
+      && s->first_glyph->left_box_line_p)
+    x = s->x + s->face->box_line_width;
+  else
+    x = s->x;
+
+  /* S is a glyph string for a composition.  S->gidx is the index of
+     the first character drawn for glyphs of this composition.
+     S->gidx == 0 means we are drawing the very first character of
+     this composition.  */
+
+  /* Draw a rectangle for the composition if the font for the very
+     first character of the composition could not be loaded.  */
+  if (s->font_not_found_p)
+    {
+      if (s->gidx == 0)
 	XDrawRectangle (s->display, s->window, s->gc, x, s->y,
 			s->width - 1, s->height - 1);
-      else
-	{
-	  XCharStruct *pcm;
-	  int relative_compose, default_ascent, i;
-	  int highest = 0, lowest = 0;
-
-	  /* The value of font_info my be null if we couldn't find it
-	     in x_get_char_face_and_encoding.  */
-	  if (s->cmpcharp->cmp_rule == NULL && s->font_info)
-	    {
-	      relative_compose = s->font_info->relative_compose;
-	      default_ascent = s->font_info->default_ascent;
-	    }
-	  else
-	    relative_compose = default_ascent = 0;
-
-	  if ((s->cmpcharp->cmp_rule || relative_compose)
-	      && s->gidx == 0)
-	    {
-	      /* This is the first character.  Initialize variables.
-		 Highest is the highest position of glyphs ever
-		 written, lowest the lowest position.  */
-	      int x_offset = 0;
-	      int first_ch = s->first_glyph->u.ch.code;
-
-	      if (default_ascent
-		  && CHAR_TABLE_P (Vuse_default_ascent)
-		  && !NILP (Faref (Vuse_default_ascent, first_ch)))
-		{
-		  highest = default_ascent;
-		  lowest = 0;
-		}
-	      else
-		{
-		  pcm = PER_CHAR_METRIC (s->font, s->char2b);
-		  highest = pcm->ascent + 1;
-		  lowest = - pcm->descent;
-		}
-
-	      if (s->cmpcharp->cmp_rule)
-		x_offset = (s->cmpcharp->col_offset[0]
-			    * FONT_WIDTH (s->f->output_data.x->font));
-
-	      /* Draw the first character at the normal position.  */
-	      XDrawString16 (s->display, s->window, s->gc,
-			     x + x_offset,
-			     s->ybase, s->char2b, 1);
-	      i = 1;
-	      ++s->gidx;
-	    }
-	  else
-	    i = 0;
-
-	  for (; i < s->nchars; i++, ++s->gidx)
-	    {
-	      int x_offset = 0, y_offset = 0;
-
-	      if (relative_compose)
-		{
-		  pcm = PER_CHAR_METRIC (s->font, s->char2b + i);
-		  if (NILP (Vignore_relative_composition)
-		      || NILP (Faref (Vignore_relative_composition,
-				      make_number (s->cmpcharp->glyph[s->gidx]))))
-		    {
-		      if (- pcm->descent >= relative_compose)
-			{
-			  /* Draw above the current glyphs.  */
-			  y_offset = highest + pcm->descent;
-			  highest += pcm->ascent + pcm->descent;
-			}
-		      else if (pcm->ascent <= 0)
-			{
-			  /* Draw beneath the current glyphs.  */
-			  y_offset = lowest - pcm->ascent;
-			  lowest -= pcm->ascent + pcm->descent;
-			}
-		    }
-		  else
-		    {
-		      /* Draw the glyph at normal position.  If
-			 it sticks out of HIGHEST or LOWEST,
-			 update them appropriately.  */
-		      if (pcm->ascent > highest)
-			highest = pcm->ascent;
-		      else if (- pcm->descent < lowest)
-			lowest = - pcm->descent;
-		    }
-		}
-	      else if (s->cmpcharp->cmp_rule)
-		{
-		  int gref = (s->cmpcharp->cmp_rule[s->gidx] - 0xA0) / 9;
-		  int nref = (s->cmpcharp->cmp_rule[s->gidx] - 0xA0) % 9;
-		  int bottom, top;
-
-		  /* Re-encode GREF and NREF so that they specify
-		     only Y-axis information:
-		     0:top, 1:base, 2:bottom, 3:center  */
-		  gref = gref / 3 + (gref == 4) * 2;
-		  nref = nref / 3 + (nref == 4) * 2;
-
-		  pcm = PER_CHAR_METRIC (s->font, s->char2b + i);
-		  bottom = ((gref == 0 ? highest : gref == 1 ? 0
-			     : gref == 2 ? lowest
-			     : (highest + lowest) / 2)
-			    - (nref == 0 ? pcm->ascent + pcm->descent
-			       : nref == 1 ? pcm->descent : nref == 2 ? 0
-			       : (pcm->ascent + pcm->descent) / 2));
-		  top = bottom + (pcm->ascent + pcm->descent);
-		  if (top > highest)
-		    highest = top;
-		  if (bottom < lowest)
-		    lowest = bottom;
-		  y_offset = bottom + pcm->descent;
-		  x_offset = (s->cmpcharp->col_offset[s->gidx]
-			      * FONT_WIDTH (FRAME_FONT (s->f)));
-		}
-
-	      XDrawString16 (s->display, s->window, s->gc,
-			     x + x_offset, s->ybase - y_offset,
-			     s->char2b + i, 1);
-	    }
-	}
+    }
+  else
+    {
+      for (i = 0; i < s->nchars; i++, ++s->gidx)
+	XDrawString16 (s->display, s->window, s->gc,
+		       x + s->cmp->offsets[s->gidx * 2],
+		       s->ybase - s->cmp->offsets[s->gidx * 2 + 1],
+		       s->char2b + i, 1);
     }
 }
 
@@ -3315,7 +3500,7 @@
     }
   
   /* The glyph that may have a right box line.  */
-  last_glyph = (s->cmpcharp || s->img
+  last_glyph = (s->cmp || s->img
 		? s->first_glyph
 		: s->first_glyph + s->nchars - 1);
 
@@ -3774,6 +3959,14 @@
       x_draw_glyph_string_foreground (s);
       break;
 
+    case COMPOSITE_GLYPH:
+      if (s->for_overlaps_p || s->gidx > 0)
+	s->background_filled_p = 1;
+      else
+	x_draw_glyph_string_background (s, 1);
+      x_draw_composite_glyph_string_foreground (s);
+      break;
+
     default:
       abort ();
     }
@@ -3853,94 +4046,44 @@
 }
 
 
-/* A work-list entry used during the construction of glyph_string
-   structures for a composite character.  */
-
-struct work
-{
-  /* Pointer to composite char info defining has the composite
-     character is drawn.  */
-  struct cmpchar_info *cmpcharp;
-
-  /* Start index in compcharp->glyph[].  */
-  int gidx;
-
-  /* Next in stack.  */
-  struct work *next;
-};
-
-
-static void x_fill_composite_glyph_string P_ ((struct glyph_string *,
-					       int, struct work **,
-					       struct work **, int));
-
-
-/* Load glyph string S with information from the top of *STACK for a
-   composite character.  FACE_ID is the id of the face in which S is
-   drawn.  *NEW is a pointer to a struct work not on the stack, that
-   can be used if this function needs to push a new structure on the
-   stack.  If it uses it, *NEW is set to null.  OVERLAPS_P non-zero
-   means S should draw the foreground only, and use its lines physical
-   height for clipping.  */
-
-static void
-x_fill_composite_glyph_string (s, face_id, stack, new, overlaps_p)
+static int x_fill_composite_glyph_string P_ ((struct glyph_string *,
+					      struct face **, int));
+
+
+/* Load glyph string S with a composition components specified by S->cmp.
+   FACES is an array of faces for all components of this composition.
+   S->gidx is the index of the first component for S.
+   OVERLAPS_P non-zero means S should draw the foreground only, and
+   use its lines physical height for clipping.
+
+   Value is the index of a component not in S.  */
+
+static int
+x_fill_composite_glyph_string (s, faces, overlaps_p)
      struct glyph_string *s;
-     int face_id;
-     struct work **stack, **new;
+     struct face **faces;
      int overlaps_p;
 {
-  int i, c;
-  struct work *work;
-
-  xassert (s && *new && *stack);
-
-  s->for_overlaps_p = 1;
-  
-  /* Pop the work stack.  */
-  work = *stack;
-  *stack = work->next;
-  
-  /* For all glyphs of cmpcharp->glyph, starting at the offset
-     work->offset, until we reach the end of the definition or
-     encounter another composite char, get the font and face to use,
-     and add it to S.  */
-  for (i = work->gidx; i < work->cmpcharp->glyph_len; ++i)
-    {
-      c = FAST_GLYPH_CHAR (work->cmpcharp->glyph[i]);
-      if (CHAR_CHARSET (c) == CHARSET_COMPOSITION)
-	break;
-      s->face = x_get_char_face_and_encoding (s->f, c, face_id,
-					      s->char2b + s->nchars, 1);
-      s->font = s->face->font;
-      s->font_info = FONT_INFO_FROM_ID (s->f, s->face->font_info_id);
-      ++s->nchars;
-    }
-
-  /* If we find another composite char in the glyph definition of
-     work->cmpcharp, put back the rest of the glyphs on the work
-     stack, and make a new entry for the composite char.  */
-  if (i < work->cmpcharp->glyph_len)
-    {
-      /* Push back an unprocessed rest of this glyph spec.  */
-      if (i < work->cmpcharp->glyph_len - 1)
-	{
-	  work->gidx = i + 1;
-	  work->next = *stack;
-	  *stack = work;
-	  work = *new;
-	  *new = NULL;
-	}
-
-      /* Make an entry for the composite char on the work stack.  */
-      work->cmpcharp = cmpchar_table[COMPOSITE_CHAR_ID (c)];
-      work->gidx = 0;
-      work->next = *stack;
-      *stack = work;
-    }
-
-  /* The width of this glyph string equals the width of the first
-     glyph.  All characters are drawn at the same x-position.  */
+  int i;
+
+  xassert (s);
+
+  s->for_overlaps_p = overlaps_p;
+  
+  s->face = faces[s->gidx];
+  s->font = s->face->font;
+  s->font_info = FONT_INFO_FROM_ID (s->f, s->face->font_info_id);
+
+  /* For all glyphs of this composition, starting at the offset
+     S->gidx, until we reach the end of the definition or encounter a
+     glyph that requires the different face, add it to S.  */
+  ++s->nchars;
+  for (i = s->gidx + 1; i < s->cmp->glyph_len && faces[i] == s->face; ++i)
+    ++s->nchars;
+
+  /* All glyph strings for the same composition has the same width,
+     i.e. the width set for the first component of the composition.  */
+
   s->width = s->first_glyph->pixel_width;
 
   /* If the specified font could not be loaded, use the frame's
@@ -3960,10 +4103,12 @@
 
   /* This glyph string must always be drawn with 16-bit functions.  */
   s->two_byte_p = 1;
-}
-
-
-/* Load glyph string S with a sequence of non-composite characters.
+
+  return s->gidx + s->nchars;
+}
+
+
+/* Load glyph string S with a sequence characters.
    FACE_ID is the face id of the string.  START is the index of the
    first glyph to consider, END is the index of the last + 1.
    OVERLAPS_P non-zero means S should draw the foreground only, and
@@ -3980,7 +4125,6 @@
   struct glyph *glyph, *last;
   int voffset;
   
-  xassert (s->charset != CHARSET_COMPOSITION);
   xassert (s->f == XFRAME (s->w->frame));
   xassert (s->nchars == 0);
   xassert (start >= 0 && end > start);
@@ -4195,67 +4339,72 @@
 	 charset = CHAR_CHARSET (c);					   \
 	 face_id = (ROW)->glyphs[AREA][START].u.ch.face_id;		   \
 									   \
-	 if (charset == CHARSET_COMPOSITION)				   \
-	   {								   \
-	     struct work *stack, *work, *new = NULL;			   \
-	     int n = 0;							   \
-             struct glyph_string *first_s = NULL;			   \
-									   \
-	     /* Push an initial entry for character c on the stack.  */	   \
-	     stack = NULL;						   \
-	     work = (struct work *) alloca (sizeof *work);		   \
-	     work->cmpcharp = cmpchar_table[COMPOSITE_CHAR_ID (c)];	   \
-	     work->gidx = 0;						   \
-	     work->next = stack;					   \
-	     stack = work;						   \
-									   \
-	     /* While the stack is not empty, append glyph_strings	   \
-		to head/tail for glyphs to draw.  */			   \
-	     while (stack)						   \
-	       {							   \
-		 s = (struct glyph_string *) alloca (sizeof *s);	   \
-		 char2b = (XChar2b *) alloca (stack->cmpcharp->glyph_len   \
-					      * sizeof (XChar2b));	   \
-		 x_init_glyph_string (s, char2b, W, ROW, AREA, START, HL); \
-		 x_append_glyph_string (&(HEAD), &(TAIL), s);		   \
-		 s->cmpcharp = stack->cmpcharp;				   \
-		 s->gidx = stack->gidx;					   \
-		 s->charset = charset;					   \
-		 s->x = (X);						   \
-									   \
-                 if (n == 0)						   \
-		   {							   \
-		     /* Don't draw the background except for the	   \
-			first glyph string.  */				   \
-                     s->background_filled_p = n > 0;			   \
-		     first_s = s;					   \
-		   }							   \
-		 ++n;							   \
-									   \
-		 if (new == NULL)					   \
-		   new = (struct work *) alloca (sizeof *new);		   \
-		 x_fill_composite_glyph_string (s, face_id, &stack,	   \
-						&new, OVERLAPS_P);	   \
-	       }							   \
-									   \
-	     ++START;							   \
-             s = first_s;						   \
-	   }								   \
-	 else								   \
-	   {								   \
-	     s = (struct glyph_string *) alloca (sizeof *s);		   \
-	     char2b = (XChar2b *) alloca ((END - START) * sizeof *char2b); \
-	     x_init_glyph_string (s, char2b, W, ROW, AREA, START, HL);	   \
-	     x_append_glyph_string (&HEAD, &TAIL, s);			   \
-	     s->charset = charset;					   \
-	     s->x = (X);						   \
-	     START = x_fill_glyph_string (s, face_id, START, END,	   \
+	 s = (struct glyph_string *) alloca (sizeof *s);		   \
+	 char2b = (XChar2b *) alloca ((END - START) * sizeof *char2b);	   \
+	 x_init_glyph_string (s, char2b, W, ROW, AREA, START, HL);	   \
+	 x_append_glyph_string (&HEAD, &TAIL, s);			   \
+	 s->charset = charset;						   \
+	 s->x = (X);							   \
+	 START = x_fill_glyph_string (s, face_id, START, END,		   \
                                           OVERLAPS_P);			   \
-	   }								   \
        }								   \
      while (0)
      
 
+/* Add a glyph string for a composite sequence to the list of strings
+   between HEAD and TAIL.  START is the index of the first glyph in
+   row area AREA of glyph row ROW that is part of the new glyph
+   string.  END is the index of the last glyph in that glyph row area.
+   X is the current output position assigned to the new glyph string
+   constructed.  HL overrides that face of the glyph; e.g. it is
+   DRAW_CURSOR if a cursor has to be drawn.  LAST_X is the right-most
+   x-position of the drawing area.  */
+
+#define BUILD_COMPOSITE_GLYPH_STRING(W, ROW, AREA, START, END, HEAD,	  \
+				       TAIL, HL, X, LAST_X, OVERLAPS_P)	  \
+  do {									  \
+    int cmp_id = (ROW)->glyphs[AREA][START].u.cmp.id;			  \
+    int face_id = (ROW)->glyphs[AREA][START].u.cmp.face_id;		  \
+    struct composition *cmp = composition_table[cmp_id];		  \
+    int glyph_len = cmp->glyph_len;					  \
+    XChar2b *char2b;							  \
+    struct face **faces;						  \
+    struct glyph_string *first_s = NULL;				  \
+    int n;								  \
+    									  \
+    char2b = (XChar2b *) alloca ((sizeof *char2b) * glyph_len);		  \
+    faces = (struct face **) alloca ((sizeof *faces) * glyph_len);	  \
+    /* At first, fill in `char2b' and `faces'.  */			  \
+    for (n = 0; n < glyph_len; n++)					  \
+      {									  \
+	int c = FAST_GLYPH_CHAR (COMPOSITION_GLYPH (cmp, n));		  \
+	faces[n] = x_get_char_face_and_encoding (XFRAME (w->frame), c,	  \
+						 face_id, char2b + n, 1); \
+      }									  \
+    									  \
+    /* Make glyph_strings for each glyph sequence that is drawable by	  \
+       the same face, and append them to HEAD/TAIL.  */			  \
+    for (n = 0; n < cmp->glyph_len;)					  \
+      {									  \
+	s = (struct glyph_string *) alloca (sizeof *s);			  \
+	x_init_glyph_string (s, char2b + n, W, ROW, AREA, START, HL);	  \
+	x_append_glyph_string (&(HEAD), &(TAIL), s);			  \
+	s->cmp = cmp;							  \
+	s->gidx = n;							  \
+	s->charset = 0;							  \
+	s->x = (X);							  \
+									  \
+	if (n == 0)							  \
+	  first_s = s;							  \
+									  \
+	n = x_fill_composite_glyph_string (s, faces, OVERLAPS_P);	  \
+      }									  \
+    									  \
+    ++START;								  \
+    s = first_s;							  \
+  } while (0)
+    
+
 /* Build a list of glyph strings between HEAD and TAIL for the glyphs
    of AREA of glyph row ROW on window W between indices START and END.
    HL overrides the face for drawing glyph strings, e.g. it is
@@ -4281,6 +4430,12 @@
                                            OVERLAPS_P);	                   \
 		 break;							   \
 									   \
+	       case COMPOSITE_GLYPH:					   \
+                 BUILD_COMPOSITE_GLYPH_STRING (W, ROW, AREA, START, END,   \
+						 HEAD, TAIL, HL, X, LAST_X,\
+						 OVERLAPS_P);		   \
+		 break;							   \
+									   \
 	       case STRETCH_GLYPH:					   \
 		 BUILD_STRETCH_GLYPH_STRING (W, ROW, AREA, START, END,	   \
 					     HEAD, TAIL, HL, X, LAST_X);   \
@@ -10646,8 +10801,7 @@
     return Qnil;
 
   f->output_data.x->font = (XFontStruct *) (fontp->font);
-  f->output_data.x->font_baseline
-    = (f->output_data.x->font->ascent + fontp->baseline_offset);
+  f->output_data.x->baseline_offset = fontp->baseline_offset;
   f->output_data.x->fontset = -1;
   
   /* Compute the scroll bar width in character columns.  */