changeset 90615:93ead736a6ac

(handle_composition_prop): Set it->c to the first non-TAB component. (fill_composite_glyph_string): Argument changed. (BUILD_COMPOSITE_GLYPH_STRING): Adjusted for the above change. (x_produce_glyphs): Fix handling of left/right padding.
author Kenichi Handa <handa@m17n.org>
date Mon, 16 Oct 2006 07:26:19 +0000
parents 8dd8c8286063
children 68d59ef20174
files src/xdisp.c
diffstat 1 files changed, 352 insertions(+), 387 deletions(-) [+]
line wrap: on
line diff
--- a/src/xdisp.c	Sun Oct 15 02:54:13 2006 +0000
+++ b/src/xdisp.c	Mon Oct 16 07:26:19 2006 +0000
@@ -4655,24 +4655,29 @@
 	  it->method = GET_FROM_COMPOSITION;
 	  it->cmp_id = id;
 	  it->cmp_len = COMPOSITION_LENGTH (prop);
+	  /* For a terminal, draw only the first (non-TAB) character
+	     of the components.  */
 #ifdef USE_FONT_BACKEND
 	  if (composition_table[id]->method == COMPOSITION_WITH_GLYPH_STRING)
 	    {
 	      Lisp_Object lgstring = AREF (XHASH_TABLE (composition_hash_table)
 					   ->key_and_value,
 					   cmp->hash_index * 2);
-	      Lisp_Object font_object = LGSTRING_FONT (lgstring);
-	      struct font *font = XSAVE_VALUE (font_object)->pointer;
-	      struct face *face = FACE_FROM_ID (it->f, it->face_id);
-
-	      it->face_id = face_for_font (it->f, font, face);
-	      it->c = ' ';
+
+	      it->c = XINT (LGLYPH_CHAR (LGSTRING_GLYPH (lgstring, 0)));
 	    }
 	  else
 #endif /* USE_FONT_BACKEND */
-	  /* For a terminal, draw only the first character of the
-             components.  */
-	  it->c = COMPOSITION_GLYPH (composition_table[id], 0);
+	    {
+	      int i;
+
+	      for (i = 0; i < cmp->glyph_len; i++)
+		if ((it->c = COMPOSITION_GLYPH (composition_table[id], i))
+		    != '\t')
+		  break;
+	    }
+	  if (it->c == '\t')
+	    it->c = ' ';
 	  it->len = (STRINGP (it->string)
 		     ? string_char_to_byte (it->string, end)
 		     : CHAR_TO_BYTE (end)) - pos_byte;
@@ -18898,6 +18903,80 @@
 }
 
 
+/* Get face and two-byte form of character C in face FACE_ID on frame
+   F.  The encoding of C is returned in *CHAR2B.  MULTIBYTE_P non-zero
+   means we want to display multibyte text.  DISPLAY_P non-zero means
+   make sure that X resources for the face returned are allocated.
+   Value is a pointer to a realized face that is ready for display if
+   DISPLAY_P is non-zero.  */
+
+static INLINE struct face *
+get_char_face_and_encoding (f, c, face_id, char2b, multibyte_p, display_p)
+     struct frame *f;
+     int c, face_id;
+     XChar2b *char2b;
+     int multibyte_p, display_p;
+{
+  struct face *face = FACE_FROM_ID (f, face_id);
+
+#ifdef USE_FONT_BACKEND
+  if (enable_font_backend)
+    {
+      struct font *font = (struct font *) face->font_info;
+
+      if (font)
+	{
+	  unsigned code = font->driver->encode_char (font, c);
+
+	  if (code != FONT_INVALID_CODE)
+	    STORE_XCHAR2B (char2b, (code >> 8), (code & 0xFF));
+	  else
+	    STORE_XCHAR2B (char2b, 0, 0);
+	}
+    }
+  else
+#endif	/* USE_FONT_BACKEND */
+  if (!multibyte_p)
+    {
+      /* Unibyte case.  We don't have to encode, but we have to make
+	 sure to use a face suitable for unibyte.  */
+      STORE_XCHAR2B (char2b, 0, c);
+      face_id = FACE_FOR_CHAR (f, face, c, -1, Qnil);
+      face = FACE_FROM_ID (f, face_id);
+    }
+  else if (c < 128)
+    {
+      /* Case of ASCII in a face known to fit ASCII.  */
+      STORE_XCHAR2B (char2b, 0, c);
+    }
+  else if (face->font != NULL)
+    {
+      struct font_info *font_info
+	= FONT_INFO_FROM_ID (f, face->font_info_id);
+      struct charset *charset = CHARSET_FROM_ID (font_info->charset);
+      unsigned code = ENCODE_CHAR (charset, c);
+
+      if (CHARSET_DIMENSION (charset) == 1)
+	STORE_XCHAR2B (char2b, 0, code);
+      else
+	STORE_XCHAR2B (char2b, (code >> 8), (code & 0xFF));
+       /* Maybe encode the character in *CHAR2B.  */
+      rif->encode_char (c, char2b, font_info, charset, NULL);
+    }
+
+  /* Make sure X resources of the face are allocated.  */
+#ifdef HAVE_X_WINDOWS
+  if (display_p)
+#endif
+    {
+      xassert (face != NULL);
+      PREPARE_FACE_FOR_DISPLAY (f, face);
+    }
+
+  return face;
+}
+
+
 /* Get face and two-byte form of character glyph GLYPH on frame F.
    The encoding of GLYPH->u.ch is returned in *CHAR2B.  Value is
    a pointer to a realized face that is ready for display.  */
@@ -18978,7 +19057,7 @@
 
 /* Fill glyph string S with composition components specified by S->cmp.
 
-   FACES is an array of faces for all components of this composition.
+   BASE_FACE is the base face of the composition.
    S->gidx is the index of the first component for S.
 
    OVERLAPS non-zero means S should draw the foreground only, and use
@@ -18987,9 +19066,9 @@
    Value is the index of a component not in S.  */
 
 static int
-fill_composite_glyph_string (s, faces, overlaps)
+fill_composite_glyph_string (s, base_face, overlaps)
      struct glyph_string *s;
-     struct face **faces;
+     struct face *base_face;
      int overlaps;
 {
   int i;
@@ -18998,18 +19077,6 @@
 
   s->for_overlaps = overlaps;
 
-  s->face = faces[s->gidx];
-  if (s->face == NULL)
-    {
-      s->font = NULL;
-      s->font_info = NULL;
-    }
-  else
-    {
-      s->font = s->face->font;
-      s->font_info = FONT_INFO_FROM_FACE (s->f, s->face);
-    }
-
 #ifdef USE_FONT_BACKEND
   if (enable_font_backend && s->cmp->method == COMPOSITION_WITH_GLYPH_STRING)
     {
@@ -19017,6 +19084,9 @@
 	= AREF (XHASH_TABLE (composition_hash_table)->key_and_value,
 		s->cmp->hash_index * 2);
 
+      s->face = base_face;
+      s->font_info = s->cmp->font;
+      s->font = s->font_info->font;
       for (i = 0, s->nchars = 0; i < s->cmp->glyph_len; i++, s->nchars++)
 	{
 	  Lisp_Object g = LGSTRING_GLYPH (gstring, i);
@@ -19030,24 +19100,45 @@
       s->width = s->cmp->pixel_width;
     }
   else
-    {
 #endif	/* USE_FONT_BACKEND */
-  /* 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 || ! 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;
-#ifdef USE_FONT_BACKEND
-    }
-#endif	/* USE_FONT_BACKEND */
+    {
+      /* 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.  */
+      struct face *face;
+
+      s->face = NULL;
+      s->font = NULL;
+      s->font_info = NULL;
+      for (i = s->gidx; i < s->cmp->glyph_len; i++)
+	{
+	  int c = COMPOSITION_GLYPH (s->cmp, i);
+
+	  if (c != '\t')
+	    {
+	      int face_id = FACE_FOR_CHAR (s->f, base_face, c, -1, Qnil);
+
+	      face = get_char_face_and_encoding (s->f, c, face_id,
+						 s->char2b + i, 1, 1);
+	      if (face)
+		{
+		  if (! s->face)
+		    {
+		      s->face = face;
+		      s->font = s->face->font;
+		      s->font_info = FONT_INFO_FROM_FACE (s->f, s->face);
+		    }
+		  else if (s->face != face)
+		    break;
+		}
+	    }
+	  ++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
      default font, but record the fact that we couldn't load it in
@@ -19388,80 +19479,6 @@
 }
 
 
-/* Get face and two-byte form of character C in face FACE_ID on frame
-   F.  The encoding of C is returned in *CHAR2B.  MULTIBYTE_P non-zero
-   means we want to display multibyte text.  DISPLAY_P non-zero means
-   make sure that X resources for the face returned are allocated.
-   Value is a pointer to a realized face that is ready for display if
-   DISPLAY_P is non-zero.  */
-
-static INLINE struct face *
-get_char_face_and_encoding (f, c, face_id, char2b, multibyte_p, display_p)
-     struct frame *f;
-     int c, face_id;
-     XChar2b *char2b;
-     int multibyte_p, display_p;
-{
-  struct face *face = FACE_FROM_ID (f, face_id);
-
-#ifdef USE_FONT_BACKEND
-  if (enable_font_backend)
-    {
-      struct font *font = (struct font *) face->font_info;
-
-      if (font)
-	{
-	  unsigned code = font->driver->encode_char (font, c);
-
-	  if (code != FONT_INVALID_CODE)
-	    STORE_XCHAR2B (char2b, (code >> 8), (code & 0xFF));
-	  else
-	    STORE_XCHAR2B (char2b, 0, 0);
-	}
-    }
-  else
-#endif	/* USE_FONT_BACKEND */
-  if (!multibyte_p)
-    {
-      /* Unibyte case.  We don't have to encode, but we have to make
-	 sure to use a face suitable for unibyte.  */
-      STORE_XCHAR2B (char2b, 0, c);
-      face_id = FACE_FOR_CHAR (f, face, c, -1, Qnil);
-      face = FACE_FROM_ID (f, face_id);
-    }
-  else if (c < 128)
-    {
-      /* Case of ASCII in a face known to fit ASCII.  */
-      STORE_XCHAR2B (char2b, 0, c);
-    }
-  else if (face->font != NULL)
-    {
-      struct font_info *font_info
-	= FONT_INFO_FROM_ID (f, face->font_info_id);
-      struct charset *charset = CHARSET_FROM_ID (font_info->charset);
-      unsigned code = ENCODE_CHAR (charset, c);
-
-      if (CHARSET_DIMENSION (charset) == 1)
-	STORE_XCHAR2B (char2b, 0, code);
-      else
-	STORE_XCHAR2B (char2b, (code >> 8), (code & 0xFF));
-       /* Maybe encode the character in *CHAR2B.  */
-      rif->encode_char (c, char2b, font_info, charset, NULL);
-    }
-
-  /* Make sure X resources of the face are allocated.  */
-#ifdef HAVE_X_WINDOWS
-  if (display_p)
-#endif
-    {
-      xassert (face != NULL);
-      PREPARE_FACE_FOR_DISPLAY (f, face);
-    }
-
-  return face;
-}
-
-
 /* Set background width of glyph string S.  START is the index of the
    first glyph following S.  LAST_X is the right-most x-position + 1
    in the drawing area.  */
@@ -19626,64 +19643,35 @@
    x-position of the drawing area.  */
 
 #define BUILD_COMPOSITE_GLYPH_STRING(START, END, HEAD, TAIL, HL, X, LAST_X) \
-  do {									  \
-    int cmp_id = (row)->glyphs[area][START].u.cmp_id;			  \
-    int face_id = (row)->glyphs[area][START].face_id;			  \
-    struct face *base_face = FACE_FROM_ID (f, 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;								  \
-    									  \
-    if (cmp->method > COMPOSITION_WITH_RULE_ALTCHARS)			  \
-      {									  \
-	/* This happens only when USE_FONT_BACKEND is defined.  */	  \
-	char2b = (XChar2b *) alloca ((sizeof *char2b) * glyph_len);	  \
-	faces = &base_face;						  \
-      }									  \
-    else								  \
-      {									  \
-    base_face = base_face->ascii_face;					  \
-    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 = COMPOSITION_GLYPH (cmp, n);				  \
-									  \
-	if (c == '\t')							  \
-	  faces[n] = NULL;						  \
-	else								  \
-	  {								  \
-	    int this_face_id = FACE_FOR_CHAR (f, base_face, c, -1, Qnil); \
-	    faces[n] = FACE_FROM_ID (f, this_face_id);			  \
-	    get_char_face_and_encoding (f, c, this_face_id,		  \
-				    char2b + n, 1, 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);			  \
-	INIT_GLYPH_STRING (s, char2b + n, w, row, area, START, HL);	  \
-	append_glyph_string (&(HEAD), &(TAIL), s);			  \
-	s->cmp = cmp;							  \
-	s->gidx = n;							  \
-	s->x = (X);							  \
-									  \
-	if (n == 0)							  \
-	  first_s = s;							  \
-									  \
-	n = fill_composite_glyph_string (s, faces, overlaps);		  \
-      }									  \
-    									  \
-    ++START;								  \
-    s = first_s;							  \
+  do {									    \
+    int face_id = (row)->glyphs[area][START].face_id;			    \
+    struct face *base_face = FACE_FROM_ID (f, face_id);			    \
+    int cmp_id = (row)->glyphs[area][START].u.cmp_id;			    \
+    struct composition *cmp = composition_table[cmp_id];		    \
+    XChar2b *char2b;							    \
+    struct glyph_string *first_s;					    \
+    int n;								    \
+    									    \
+    char2b = (XChar2b *) alloca ((sizeof *char2b) * cmp->glyph_len);	    \
+    base_face = base_face->ascii_face;					    \
+    									    \
+    /* 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);			    \
+	INIT_GLYPH_STRING (s, char2b, w, row, area, START, HL);		    \
+	append_glyph_string (&(HEAD), &(TAIL), s);			    \
+	s->cmp = cmp;							    \
+	s->gidx = n;							    \
+	s->x = (X);							    \
+	if (n == 0)							    \
+	  first_s = s;							    \
+	n = fill_composite_glyph_string (s, base_face, overlaps);	    \
+      }									    \
+    									    \
+    ++START;								    \
+    s = first_s;							    \
   } while (0)
 
 
@@ -20557,7 +20545,7 @@
 	  if (SINGLE_BYTE_CHAR_P (it->c)
 	      && unibyte_display_via_language_environment)
 	    it->char_to_display = unibyte_char_to_multibyte (it->c);
-	  if (! SINGLE_BYTE_CHAR_P (it->c))
+	  if (! SINGLE_BYTE_CHAR_P (it->char_to_display))
 	    {
 	      it->multibyte_p = 1;
 	      it->face_id = FACE_FOR_CHAR (it->f, face, it->char_to_display,
@@ -20883,63 +20871,25 @@
   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;
+	 glyph matrix.  There are no padding glyphs.
+
+	 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).  */
       struct face *face = FACE_FROM_ID (it->f, it->face_id);
-      XCharStruct *pcm;
-      int font_not_found_p;
-      struct font_info *font_info;
       int boff;			/* baseline offset */
       struct composition *cmp = composition_table[it->cmp_id];
-      int pos;
-
-      /* Maybe translate single-byte characters to multibyte.  */
-      it->char_to_display = it->c;
-      if (unibyte_display_via_language_environment
-	  && it->c >= 0200)
-	{
-	  it->char_to_display = unibyte_char_to_multibyte (it->c);
-	}
+
+      it->nglyphs = 1;
 
 #ifdef USE_FONT_BACKEND
-      if (cmp->method != COMPOSITION_WITH_GLYPH_STRING)
-	{
+      if (cmp->method == COMPOSITION_WITH_GLYPH_STRING)
+	{
+	  if (! cmp->font)
+	    font_prepare_composition (cmp);
+	}
+      else
 #endif	/* USE_FONT_BACKEND */
-      /* Get face and font to use.  Encode IT->char_to_display.  */
-      pos = STRINGP (it->string) ? IT_STRING_CHARPOS (*it) : IT_CHARPOS (*it);
-      it->face_id = FACE_FOR_CHAR (it->f, face, it->char_to_display,
-				   pos, it->string);
-      face = FACE_FROM_ID (it->f, it->face_id);
-      get_char_face_and_encoding (it->f, it->char_to_display, it->face_id,
-				  &char2b, it->multibyte_p, 0);
-      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 = FRAME_BASELINE_OFFSET (it->f);
-	  font_info = NULL;
-	}
-      else
-	{
-	  font_info = FONT_INFO_FROM_FACE (it->f, face);
-	  boff = font_info->baseline_offset;
-	  if (font_info->vertical_centering)
-	    boff = VCENTER_BASELINE_OFFSET (font, it->f) - boff;
-	}
-#ifdef USE_FONT_BACKEND
-	}
-#endif
-
-      /* 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
@@ -20947,49 +20897,79 @@
 	 here we check only the font of the first glyph.  This leads
 	 to incorrect display, but it's very rare, and C-l (recenter)
 	 can correct the display anyway.  */
-      if (cmp->glyph_len == 0)
-	{
-	  cmp->lbearing = cmp->rbearing = 0;
-	  cmp->pixel_width = cmp->ascent = cmp->descent = 0;
-	}
-#ifdef USE_FONT_BACKEND
-      else if (cmp->method == COMPOSITION_WITH_GLYPH_STRING)
-	{
-	  if (! cmp->font)
-	    font_prepare_composition (cmp);
-	}
-#endif	/* USE_FONT_BACKEND */
-      else 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_BASE (font) + boff;
-	  int font_descent = FONT_DESCENT (font) - boff;
-	  int font_height = FONT_HEIGHT (font);
+      if (! cmp->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_descent, font_height;
 	  /* Bounding box of the overall glyphs.  */
 	  int leftmost, rightmost, lowest, highest;
 	  int lbearing, rbearing;
 	  int i, width, ascent, descent;
-	  int fully_padded = 0;
+	  int left_padded = 0, right_padded = 0;
+	  int glyph_len = cmp->glyph_len;
+	  int face_id;
+	  int c;
+	  XChar2b char2b;
+	  XFontStruct *font;
+	  XCharStruct *pcm;
+	  int font_not_found_p;
+	  struct font_info *font_info;
+	  int pos;
+
+	  for (glyph_len = cmp->glyph_len; glyph_len > 0; glyph_len--)
+	    if ((c = COMPOSITION_GLYPH (cmp, glyph_len - 1)) != '\t')
+	      break;
+	  if (glyph_len < cmp->glyph_len)
+	    right_padded = 1;
+	  for (i = 0; i < glyph_len; i++)
+	    {
+	      if ((c = COMPOSITION_GLYPH (cmp, i)) != '\t')
+		break;
+	      cmp->offsets[i * 2] = cmp->offsets[i * 2 + 1] = 0;
+	    }
+	  if (i > 0)
+	    left_padded = 1;
+
+	  /* Get the font of the first non-TAB component.  */
+	  pos = (STRINGP (it->string) ? IT_STRING_CHARPOS (*it)
+		 : IT_CHARPOS (*it));
+	  face_id = FACE_FOR_CHAR (it->f, face, c, pos, it->string);
+	  font = FACE_FROM_ID (it->f, face_id)->font;
+	  /* When no suitable font found, use the default font.  */
+	  font_not_found_p = font == NULL;
+	  if (font_not_found_p)
+	    font = FACE_FROM_ID (it->f, it->face_id)->font;
+	  font_info
+	    = FONT_INFO_FROM_FACE (it->f, FACE_FROM_ID (it->f, face_id));
+	  boff = font_info->baseline_offset;
+	  if (font_info->vertical_centering)
+	    boff = VCENTER_BASELINE_OFFSET (font, it->f) - boff;
+	  font_ascent = FONT_BASE (font) + boff;
+	  font_descent = FONT_DESCENT (font) - boff;
+	  font_height = FONT_HEIGHT (font);
 
 	  cmp->font = (void *) font;
 
+	  pcm = NULL;
+	  if (! font_not_found_p)
+	    {
+	      get_char_face_and_encoding (it->f, c, face_id,
+					  &char2b, it->multibyte_p, 0);
+	      pcm = get_per_char_metric (font, font_info, &char2b,
+					 FONT_TYPE_FOR_MULTIBYTE (font, c));
+	    }
+
 	  /* Initialize the bounding box.  */
-	  if (font_info
-	      && (pcm = get_per_char_metric (font, font_info, &char2b,
-					      FONT_TYPE_FOR_MULTIBYTE (font, it->c))))
+	  if (pcm)
 	    {
 	      width = pcm->width;
 	      ascent = pcm->ascent;
 	      descent = pcm->descent;
 	      lbearing = pcm->lbearing;
-	      if (lbearing > 0)
-		lbearing = 0;
 	      rbearing = pcm->rbearing;
-	      if (rbearing < width)
-		rbearing = width;
 	    }
 	  else
 	    {
@@ -21001,11 +20981,11 @@
 	    }
 
 	  rightmost = width;
+	  leftmost = 0;
 	  lowest = - descent + boff;
 	  highest = ascent + boff;
-	  leftmost = 0;
-
-	  if (font_info
+
+	  if (! font_not_found_p
 	      && font_info->default_ascent
 	      && CHAR_TABLE_P (Vuse_default_ascent)
 	      && !NILP (Faref (Vuse_default_ascent,
@@ -21013,157 +20993,138 @@
 	    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;
+	     shifted to right later if some other glyphs are drawn
+	     at the left.  */
+	  cmp->offsets[i * 2] = 0;
+	  cmp->offsets[i * 2 + 1] = boff;
 	  cmp->lbearing = lbearing;
 	  cmp->rbearing = rbearing;
 
 	  /* Set cmp->offsets for the remaining glyphs.  */
-	  for (i = 1; i < cmp->glyph_len; i++)
+	  for (i++; i < glyph_len; i++)
 	    {
 	      int left, right, btm, top;
 	      int ch = COMPOSITION_GLYPH (cmp, i);
 	      int face_id;
+	      struct face *this_face;
+	      int this_boff;
 
 	      if (ch == '\t')
-		{
-		  fully_padded = 1;
-		  cmp->offsets[i * 2] = 0;
-		  cmp->offsets[i * 2 + 1] = boff;
-		  continue;
-		}
-
+		ch = ' ';
 	      face_id = FACE_FOR_CHAR (it->f, face, ch, pos, it->string);
-	      face = FACE_FROM_ID (it->f, face_id);
-	      get_char_face_and_encoding (it->f, ch, face->id,
-					  &char2b, it->multibyte_p, 0);
-	      font = face->font;
+	      this_face = FACE_FROM_ID (it->f, face_id);
+	      font = this_face->font;
+
 	      if (font == NULL)
-		{
-		  font = FRAME_FONT (it->f);
-		  boff = FRAME_BASELINE_OFFSET (it->f);
-		  font_info = NULL;
-		}
+		pcm = NULL;
 	      else
 		{
-		  font_info
-		    = FONT_INFO_FROM_FACE (it->f, face);
-		  boff = font_info->baseline_offset;
+		  font_info = FONT_INFO_FROM_FACE (it->f, this_face);
+		  this_boff = font_info->baseline_offset;
 		  if (font_info->vertical_centering)
-		    boff = VCENTER_BASELINE_OFFSET (font, it->f) - boff;
-		}
-
-	      if (font_info
-		  && (pcm = get_per_char_metric (font, font_info, &char2b,
-						  FONT_TYPE_FOR_MULTIBYTE (font, ch))))
+		    this_boff = VCENTER_BASELINE_OFFSET (font, it->f) - boff;
+		  get_char_face_and_encoding (it->f, ch, face_id,
+					      &char2b, it->multibyte_p, 0);
+		  pcm = get_per_char_metric (font, font_info, &char2b,
+					     FONT_TYPE_FOR_MULTIBYTE (font,
+								      ch));
+		}
+	      if (! pcm)
+		cmp->offsets[i * 2] = cmp->offsets[i * 2 + 1] = 0;
+	      else
 		{
 		  width = pcm->width;
 		  ascent = pcm->ascent;
 		  descent = pcm->descent;
 		  lbearing = pcm->lbearing;
-		  if (lbearing > 0)
-		    lbearing = 0;
 		  rbearing = pcm->rbearing;
-		  if (rbearing < width)
-		    rbearing = width;
-		}
-	      else
-		{
-		  width = FONT_WIDTH (font);
-		  ascent = 1;
-		  descent = 0;
-		  lbearing = 0;
-		  rbearing = width;
-		}
-
-	      if (cmp->method != COMPOSITION_WITH_RULE_ALTCHARS)
-		{
-		  /* Relative composition with or without
-		     alternate chars.  */
-		  left = (leftmost + rightmost - width) / 2;
-		  btm = - descent + boff;
-		  if (font_info && font_info->relative_compose
-		      && (! CHAR_TABLE_P (Vignore_relative_composition)
-			  || NILP (Faref (Vignore_relative_composition,
-					  make_number (ch)))))
+		  if (cmp->method != COMPOSITION_WITH_RULE_ALTCHARS)
 		    {
-
-		      if (- descent >= font_info->relative_compose)
-			/* One extra pixel between two glyphs.  */
-			btm = highest + 1;
-		      else if (ascent <= 0)
-			/* One extra pixel between two glyphs.  */
-			btm = lowest - 1 - ascent - descent;
+		      /* Relative composition with or without
+			 alternate chars.  */
+		      left = (leftmost + rightmost - width) / 2;
+		      btm = - descent + boff;
+		      if (font_info->relative_compose
+			  && (! CHAR_TABLE_P (Vignore_relative_composition)
+			      || NILP (Faref (Vignore_relative_composition,
+					      make_number (ch)))))
+			{
+
+			  if (- descent >= font_info->relative_compose)
+			    /* One extra pixel between two glyphs.  */
+			    btm = highest + 1;
+			  else if (ascent <= 0)
+			    /* One extra pixel between two glyphs.  */
+			    btm = lowest - 1 - ascent - 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, xoff, yoff;
-
-		  COMPOSITION_DECODE_RULE (rule, gref, nref, xoff, yoff);
-		  grefx = gref % 3, nrefx = nref % 3;
-		  grefy = gref / 3, nrefy = nref / 3;
-		  if (xoff)
-		    xoff = font_height * (xoff - 128) / 256;
-		  if (yoff)
-		    yoff = font_height * (yoff - 128) / 256;
-
-		  left = (leftmost
-			  + grefx * (rightmost - leftmost) / 2
-			  - nrefx * width / 2
-			  + xoff);
+		  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, xoff, yoff;
+
+		      COMPOSITION_DECODE_RULE (rule, gref, nref, xoff, yoff);
+		      grefx = gref % 3, nrefx = nref % 3;
+		      grefy = gref / 3, nrefy = nref / 3;
+		      if (xoff)
+			xoff = font_height * (xoff - 128) / 256;
+		      if (yoff)
+			yoff = font_height * (yoff - 128) / 256;
+
+		      left = (leftmost
+			      + grefx * (rightmost - leftmost) / 2
+			      - nrefx * width / 2
+			      + xoff);
 		  
-		  btm = ((grefy == 0 ? highest
-			  : grefy == 1 ? 0
-			  : grefy == 2 ? lowest
-			  : (highest + lowest) / 2)
-			 - (nrefy == 0 ? ascent + descent
-			    : nrefy == 1 ? descent - boff
-			    : nrefy == 2 ? 0
-			    : (ascent + descent) / 2)
-			 + yoff);
-		}
-
-	      cmp->offsets[i * 2] = left;
-	      cmp->offsets[i * 2 + 1] = btm + descent;
-
-	      /* Update the bounding box of the overall glyphs. */
-	      if (width > 0)
-		{
-		  right = left + width;
-		  if (left < leftmost)
-		    leftmost = left;
-		  if (right > rightmost)
-		    rightmost = right;
-		}
-	      top = btm + descent + ascent;
-	      if (top > highest)
-		highest = top;
-	      if (btm < lowest)
-		lowest = btm;
-
-	      if (cmp->lbearing > left + lbearing)
-		cmp->lbearing = left + lbearing;
-	      if (cmp->rbearing < left + rbearing)
-		cmp->rbearing = left + rbearing;
+		      btm = ((grefy == 0 ? highest
+			      : grefy == 1 ? 0
+			      : grefy == 2 ? lowest
+			      : (highest + lowest) / 2)
+			     - (nrefy == 0 ? ascent + descent
+				: nrefy == 1 ? descent - boff
+				: nrefy == 2 ? 0
+				: (ascent + descent) / 2)
+			     + yoff);
+		    }
+
+		  cmp->offsets[i * 2] = left;
+		  cmp->offsets[i * 2 + 1] = btm + descent;
+
+		  /* Update the bounding box of the overall glyphs. */
+		  if (width > 0)
+		    {
+		      right = left + width;
+		      if (left < leftmost)
+			leftmost = left;
+		      if (right > rightmost)
+			rightmost = right;
+		    }
+		  top = btm + descent + ascent;
+		  if (top > highest)
+		    highest = top;
+		  if (btm < lowest)
+		    lowest = btm;
+
+		  if (cmp->lbearing > left + lbearing)
+		    cmp->lbearing = left + lbearing;
+		  if (cmp->rbearing < left + rbearing)
+		    cmp->rbearing = left + rbearing;
+		}
 	    }
 
 	  /* If there are glyphs whose x-offsets are negative,
@@ -21178,13 +21139,17 @@
 	      cmp->rbearing -= leftmost;
 	    }
 
-	  if (fully_padded)
+	  if (left_padded && cmp->lbearing < 0)
 	    {
 	      for (i = 0; i < cmp->glyph_len; i++)
 		cmp->offsets[i * 2] -= cmp->lbearing;
-	      rightmost = cmp->rbearing - cmp->lbearing;
+	      rightmost -= cmp->lbearing;
+	      cmp->rbearing -= cmp->lbearing;
 	      cmp->lbearing = 0;
-	      cmp->rbearing = rightmost; 
+	    }
+	  if (right_padded && rightmost < cmp->rbearing)
+	    {
+	      rightmost = cmp->rbearing;
 	    }
 
 	  cmp->pixel_width = rightmost;