changeset 97833:6e54941ad0d7

Include font.h. (it_props): Delete the entry for Qauto_composed. (init_iterator): Initialize it->cmp_it.id to -1. (compute_stop_pos): Call composition_compute_stop_pos. (face_before_or_after_it_pos): Adjusted for the change of struct it. (handle_auto_composed_prop): Delete it. (handle_composition_prop): Handle only static composition. (next_overlay_string): Remove it->method == GET_FROM_COMPOSITION from xassert. Initialize it->cmp_it.stop_pos. (push_it): Adjusted for the change of struct it. (pop_it): Likewise. (get_next_element): Delete next_element_from_composition. (CHAR_COMPOSED_P): New macro. (get_next_display_element): For automatic composition, get a face from the font in the glyph-string. (set_iterator_to_next): For GET_FROM_BUFFER and GET_FROM_STRING, check composition by it->cmp_it.id. Delete GET_FROM_COMPOSITION case. (next_element_from_string): Check if the character at the current position is composed by CHAR_COMPOSED_P. (next_element_from_buffer): Likewise. (next_element_from_composition): Adjusted for the change of struct it. Update it->cmp_it. (dump_glyph): Adjusted for the change of struct glyph. (fill_composite_glyph_string): Adjusted for the change of struct it and struct glyph. Don't handle automatic composition here. (fill_gstring_glyph_string): New function. (x_get_glyph_overhangs): Handle automatic composition. (BUILD_COMPOSITE_GLYPH_STRING): Adjusted for the change of struct glyph. (BUILD_GSTRING_GLYPH_STRING): New macro. (BUILD_GLYPH_STRINGS): Call BUILD_GSTRING_GLYPH_STRING for automatic composition. (append_composite_glyph): Adjusted for the change of struct it and struct glyph. (x_produce_glyphs): Adjusted for the change of struct it.
author Kenichi Handa <handa@m17n.org>
date Fri, 29 Aug 2008 07:58:08 +0000
parents e33a2e6c1dab
children 7ef2445b45d7
files src/xdisp.c
diffstat 1 files changed, 388 insertions(+), 347 deletions(-) [+]
line wrap: on
line diff
--- a/src/xdisp.c	Fri Aug 29 07:57:43 2008 +0000
+++ b/src/xdisp.c	Fri Aug 29 07:58:08 2008 +0000
@@ -188,6 +188,7 @@
 #include "coding.h"
 #include "process.h"
 #include "region-cache.h"
+#include "font.h"
 #include "fontset.h"
 #include "blockinput.h"
 
@@ -767,7 +768,6 @@
 static enum prop_handled handle_composition_prop P_ ((struct it *));
 static enum prop_handled handle_overlay_change P_ ((struct it *));
 static enum prop_handled handle_fontified_prop P_ ((struct it *));
-static enum prop_handled handle_auto_composed_prop P_ ((struct it *));
 
 /* Properties handled by iterators.  */
 
@@ -779,7 +779,6 @@
   {&Qface,		FACE_PROP_IDX,		handle_face_prop},
   {&Qdisplay,		DISPLAY_PROP_IDX,	handle_display_prop},
   {&Qinvisible,		INVISIBLE_PROP_IDX,	handle_invisible_prop},
-  {&Qauto_composed,	AUTO_COMPOSED_PROP_IDX,	handle_auto_composed_prop},
   {&Qcomposition,	COMPOSITION_PROP_IDX,	handle_composition_prop},
   {NULL,		0,			NULL}
 };
@@ -2574,6 +2573,8 @@
   it->w = w;
   it->f = XFRAME (w->frame);
 
+  it->cmp_it.id = -1;
+
   /* Extra space between lines (on window systems only).  */
   if (base_face_id == DEFAULT_FACE_ID
       && FRAME_WINDOW_P (it->f))
@@ -3181,6 +3182,7 @@
 {
   register INTERVAL iv, next_iv;
   Lisp_Object object, limit, position;
+  EMACS_INT charpos, bytepos;
 
   /* If nowhere else, stop at the end.  */
   it->stop_charpos = it->end_charpos;
@@ -3191,19 +3193,22 @@
 	 properties.  */
       object = it->string;
       limit = Qnil;
-      position = make_number (IT_STRING_CHARPOS (*it));
-    }
-  else
-    {
-      int charpos;
+      charpos = IT_STRING_CHARPOS (*it);
+      bytepos = IT_STRING_BYTEPOS (*it);
+    }
+  else
+    {
+      EMACS_INT pos;
 
       /* If next overlay change is in front of the current stop pos
 	 (which is IT->end_charpos), stop there.  Note: value of
 	 next_overlay_change is point-max if no overlay change
 	 follows.  */
-      charpos = next_overlay_change (IT_CHARPOS (*it));
-      if (charpos < it->stop_charpos)
-	it->stop_charpos = charpos;
+      charpos = IT_CHARPOS (*it);
+      bytepos = IT_BYTEPOS (*it);
+      pos = next_overlay_change (charpos);
+      if (pos < it->stop_charpos)
+	it->stop_charpos = pos;
 
       /* If showing the region, we have to stop at the region
 	 start or end because the face might change there.  */
@@ -3219,12 +3224,11 @@
          property changes.  */
       XSETBUFFER (object, current_buffer);
       limit = make_number (IT_CHARPOS (*it) + TEXT_PROP_DISTANCE_LIMIT);
-      position = make_number (IT_CHARPOS (*it));
-
     }
 
   /* Get the interval containing IT's position.  Value is a null
      interval if there isn't such an interval.  */
+  position = make_number (charpos);
   iv = validate_interval_range (object, &position, &position, 0);
   if (!NULL_INTERVAL_P (iv))
     {
@@ -3268,6 +3272,9 @@
 	}
     }
 
+  composition_compute_stop_pos (&it->cmp_it, charpos, bytepos,
+				it->stop_charpos, it->string);
+
   xassert (STRINGP (it->string)
 	   || (it->stop_charpos >= BEGV
 	       && it->stop_charpos >= IT_CHARPOS (*it)));
@@ -3600,7 +3607,8 @@
 	/* For composition, we must check the character after the
            composition.  */
 	pos = (it->what == IT_COMPOSITION
-	       ? string_pos (IT_STRING_CHARPOS (*it) + it->cmp_len, it->string)
+	       ? string_pos (IT_STRING_CHARPOS (*it)
+			     + it->cmp_it.nchars, it->string)
 	       : string_pos (IT_STRING_CHARPOS (*it) + 1, it->string));
 
       if (it->current.overlay_string_index >= 0)
@@ -3650,7 +3658,7 @@
 	  if (it->what == IT_COMPOSITION)
 	    /* For composition, we must check the position after the
 	       composition.  */
-	    pos.charpos += it->cmp_len, pos.bytepos += it->len;
+	    pos.charpos += it->cmp_it.nchars, pos.bytepos += it->len;
 	  else
 	    INC_TEXT_POS (pos, it->multibyte_p);
 	}
@@ -4624,97 +4632,6 @@
 			`composition' property
  ***********************************************************************/
 
-static enum prop_handled
-handle_auto_composed_prop (it)
-     struct it *it;
-{
-  enum prop_handled handled = HANDLED_NORMALLY;
-
-  if (FUNCTIONP (Vauto_composition_function))
-    {
-      Lisp_Object val = Qnil;
-      EMACS_INT pos, limit = -1;
-
-      if (STRINGP (it->string))
-	pos = IT_STRING_CHARPOS (*it);
-      else
-	pos = IT_CHARPOS (*it);
-
-      val = Fget_text_property (make_number (pos), Qauto_composed, it->string);
-      if (! NILP (val))
-	{
-	  Lisp_Object cmp_prop;
-	  EMACS_INT cmp_start, cmp_end;
-
-	  if (get_property_and_range (pos, Qcomposition, &cmp_prop,
-				      &cmp_start, &cmp_end, it->string)
-	      && cmp_start == pos
-	      && COMPOSITION_METHOD (cmp_prop) == COMPOSITION_WITH_GLYPH_STRING)
-	    {
-	      Lisp_Object gstring = COMPOSITION_COMPONENTS (cmp_prop);
-	      Lisp_Object font_object = LGSTRING_FONT (gstring);
-
-	      if (! EQ (font_object,
-			font_at (-1, pos, FACE_FROM_ID (it->f, it->face_id),
-				 it->w, it->string)))
-		/* We must re-compute the composition for the
-		   different font.  */
-		val = Qnil;
-	    }
-
-	  if (! NILP (val))
-	    {
-	      Lisp_Object end;
-
-	      /* As Fnext_single_char_property_change is very slow, we
-		 limit the search to the current line.  */
-	      if (STRINGP (it->string))
-		limit = SCHARS (it->string);
-	      else
-		limit = find_next_newline_no_quit (pos, 1);
-	      end = Fnext_single_char_property_change (make_number (pos),
-						       Qauto_composed,
-						       it->string,
-						       make_number (limit));
-
-	      if (XINT (end) < limit)
-		/* The current point is auto-composed, but there exist
-		   characters not yet composed beyond the
-		   auto-composed region.  There's a possiblity that
-		   the last characters in the region may be newly
-		   composed.  */
-		val = Qnil;
-	    }
-	}
-      if (NILP (val) && ! STRINGP (it->string))
-	{
-	  if (limit < 0)
-	    limit = (STRINGP (it->string) ? SCHARS (it->string)
-		     : find_next_newline_no_quit (pos, 1));
-	  if (pos < limit)
-	    {
-	      int count = SPECPDL_INDEX ();
-	      Lisp_Object args[5];
-
-	      if (FRAME_WINDOW_P (it->f))
-		limit = font_range (pos, limit,
-				    FACE_FROM_ID (it->f, it->face_id),
-				    it->f, it->string);
-	      args[0] = Vauto_composition_function;
-	      specbind (Qauto_composition_function, Qnil);
-	      args[1] = make_number (pos);
-	      args[2] = make_number (limit);
-	      args[3] = it->window;
-	      args[4] = it->string;
-	      safe_call (5, args);
-	      unbind_to (count, Qnil);
-	    }
-	}
-    }
-
-  return handled;
-}
-
 /* Set up iterator IT from `composition' property at its current
    position.  Called from handle_stop.  */
 
@@ -4724,7 +4641,6 @@
 {
   Lisp_Object prop, string;
   EMACS_INT pos, pos_byte, start, end;
-  enum prop_handled handled = HANDLED_NORMALLY;
 
   if (STRINGP (it->string))
     {
@@ -4751,8 +4667,6 @@
       && COMPOSITION_VALID_P (start, end, prop)
       && (STRINGP (it->string) || (PT <= start || PT >= end)))
     {
-      int id;
-
       if (start != pos)
 	{
 	  if (STRINGP (it->string))
@@ -4760,63 +4674,17 @@
 	  else
 	    pos_byte = CHAR_TO_BYTE (start);
 	}
-      id = get_composition_id (start, pos_byte, end - start, prop, string);
-
-      if (id >= 0)
-	{
-	  struct composition *cmp = composition_table[id];
-
-	  if (cmp->glyph_len == 0)
-	    {
-	      /* No glyph.  */
-	      if (STRINGP (it->string))
-		{
-		  IT_STRING_CHARPOS (*it) = end;
-		  IT_STRING_BYTEPOS (*it) = string_char_to_byte (it->string,
-								 end);
-		}
-	      else
-		{
-		  IT_CHARPOS (*it) = end;
-		  IT_BYTEPOS (*it) = CHAR_TO_BYTE (end);
-		}
-	      return HANDLED_RECOMPUTE_PROPS;
-	    }
-
-	  it->stop_charpos = end;
-	  push_it (it);
-
-	  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.  */
-	  if (composition_table[id]->method == COMPOSITION_WITH_GLYPH_STRING)
-	    {
-	      /* FIXME: This doesn't do anything!?! */
-	      Lisp_Object lgstring = AREF (XHASH_TABLE (composition_hash_table)
-					   ->key_and_value,
-					   cmp->hash_index * 2);
-	    }
-	  else
-	    {
-	      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;
-	  handled = HANDLED_RETURN;
-	}
-    }
-
-  return handled;
+      it->cmp_it.id = get_composition_id (start, pos_byte, end - start,
+					       prop, string);
+
+      if (it->cmp_it.id >= 0)
+	{
+	  it->cmp_it.nchars = COMPOSITION_LENGTH (prop);
+	  it->cmp_it.nglyphs = -1;
+	}
+    }
+
+  return HANDLED_NORMALLY;
 }
 
 
@@ -4872,7 +4740,6 @@
       it->ellipsis_p = (it->stack[it->sp - 1].display_ellipsis_p != 0);
       pop_it (it);
       xassert (it->sp > 0
-	       || it->method == GET_FROM_COMPOSITION
 	       || (NILP (it->string)
 		   && it->method == GET_FROM_BUFFER
 		   && it->stop_charpos >= BEGV
@@ -4904,6 +4771,8 @@
       SET_TEXT_POS (it->current.string_pos, 0, 0);
       it->method = GET_FROM_STRING;
       it->stop_charpos = 0;
+      if (it->cmp_it.stop_pos >= 0)
+	it->cmp_it.stop_pos = 0;
     }
 
   CHECK_IT (it);
@@ -5218,6 +5087,7 @@
   p = it->stack + it->sp;
 
   p->stop_charpos = it->stop_charpos;
+  p->cmp_it = it->cmp_it;
   xassert (it->face_id >= 0);
   p->face_id = it->face_id;
   p->string = it->string;
@@ -5230,13 +5100,6 @@
       p->u.image.image_id = it->image_id;
       p->u.image.slice = it->slice;
       break;
-    case GET_FROM_COMPOSITION:
-      p->u.comp.object = it->object;
-      p->u.comp.c = it->c;
-      p->u.comp.len = it->len;
-      p->u.comp.cmp_id = it->cmp_id;
-      p->u.comp.cmp_len = it->cmp_len;
-      break;
     case GET_FROM_STRETCH:
       p->u.stretch.object = it->object;
       break;
@@ -5273,6 +5136,7 @@
   --it->sp;
   p = it->stack + it->sp;
   it->stop_charpos = p->stop_charpos;
+  it->cmp_it = p->cmp_it;
   it->face_id = p->face_id;
   it->current = p->current;
   it->position = p->position;
@@ -5288,13 +5152,6 @@
       it->object = p->u.image.object;
       it->slice = p->u.image.slice;
       break;
-    case GET_FROM_COMPOSITION:
-      it->object = p->u.comp.object;
-      it->c = p->u.comp.c;
-      it->len = p->u.comp.len;
-      it->cmp_id = p->u.comp.cmp_id;
-      it->cmp_len = p->u.comp.cmp_len;
-      break;
     case GET_FROM_STRETCH:
       it->object = p->u.comp.object;
       break;
@@ -5754,7 +5611,6 @@
 {
   next_element_from_buffer,
   next_element_from_display_vector,
-  next_element_from_composition,
   next_element_from_string,
   next_element_from_c_string,
   next_element_from_image,
@@ -5763,6 +5619,19 @@
 
 #define GET_NEXT_DISPLAY_ELEMENT(it) (*get_next_element[(it)->method]) (it)
 
+
+/* Return 1 iff a character at CHARPOS (and BYTEPOS) is composed
+   (possibly with the following characters).  */
+
+#define CHAR_COMPOSED_P(IT,CHARPOS,BYTEPOS)				\
+  ((IT)->cmp_it.id >= 0							\
+   || ((IT)->cmp_it.stop_pos == (CHARPOS)				\
+       && composition_reseat_it (&(IT)->cmp_it, CHARPOS, BYTEPOS,	\
+				 (IT)->end_charpos, (IT)->w,		\
+				 FACE_FROM_ID ((IT)->f, (IT)->face_id),	\
+				 (IT)->string)))
+
+
 /* Load IT's display element fields with information about the next
    display element from the current position of IT.  Value is zero if
    end of buffer (or C string) is reached.  */
@@ -6037,6 +5906,7 @@
 	}
     }
 
+#ifdef HAVE_WINDOW_SYSTEM
   /* Adjust face id for a multibyte character.  There are no multibyte
      character in unibyte text.  */
   if ((it->what == IT_CHARACTER || it->what == IT_COMPOSITION)
@@ -6045,12 +5915,24 @@
       && FRAME_WINDOW_P (it->f))
     {
       struct face *face = FACE_FROM_ID (it->f, it->face_id);
-      int pos = (it->s ? -1
-		 : STRINGP (it->string) ? IT_STRING_CHARPOS (*it)
-		 : IT_CHARPOS (*it));
-
-      it->face_id = FACE_FOR_CHAR (it->f, face, it->c, pos, it->string);
-    }
+
+      if (it->what == IT_COMPOSITION && it->cmp_it.ch >= 0)
+	{
+	  /* Automatic composition with glyph-string.   */
+	  Lisp_Object gstring = composition_gstring_from_id (it->cmp_it.id);
+	  
+	  it->face_id = face_for_font (it->f, LGSTRING_FONT (gstring), face);
+	}
+      else
+	{
+	  int pos = (it->s ? -1
+		     : STRINGP (it->string) ? IT_STRING_CHARPOS (*it)
+		     : IT_CHARPOS (*it));
+
+	  it->face_id = FACE_FOR_CHAR (it->f, face, it->c, pos, it->string);
+	}
+    }
+#endif
 
   /* Is this character the last one of a run of characters with
      box?  If yes, set IT->end_of_box_run_p to 1.  */
@@ -6105,6 +5987,20 @@
 	 invisible lines that are so because of selective display.  */
       if (ITERATOR_AT_END_OF_LINE_P (it) && reseat_p)
 	reseat_at_next_visible_line_start (it, 0);
+      else if (it->cmp_it.id >= 0)
+	{
+	  IT_CHARPOS (*it) += it->cmp_it.nchars;
+	  IT_BYTEPOS (*it) += it->cmp_it.nbytes;
+	  if (it->cmp_it.to < it->cmp_it.nglyphs)
+	    it->cmp_it.from = it->cmp_it.to;
+	  else
+	    {
+	      it->cmp_it.id = -1;
+	      composition_compute_stop_pos (&it->cmp_it, IT_CHARPOS (*it),
+					    IT_BYTEPOS (*it), it->stop_charpos,
+					    Qnil);
+	    }
+	}
       else
 	{
 	  xassert (it->len != 0);
@@ -6114,23 +6010,6 @@
 	}
       break;
 
-    case GET_FROM_COMPOSITION:
-      xassert (it->cmp_id >= 0 && it->cmp_id < n_compositions);
-      xassert (it->sp > 0);
-      pop_it (it);
-      if (it->method == GET_FROM_STRING)
-	{
-	  IT_STRING_BYTEPOS (*it) += it->len;
-	  IT_STRING_CHARPOS (*it) += it->cmp_len;
-	  goto consider_string_end;
-	}
-      else if (it->method == GET_FROM_BUFFER)
-	{
-	  IT_BYTEPOS (*it) += it->len;
-	  IT_CHARPOS (*it) += it->cmp_len;
-	}
-      break;
-
     case GET_FROM_C_STRING:
       /* Current display element of IT is from a C string.  */
       IT_BYTEPOS (*it) += it->len;
@@ -6186,8 +6065,26 @@
     case GET_FROM_STRING:
       /* Current display element is a character from a Lisp string.  */
       xassert (it->s == NULL && STRINGP (it->string));
-      IT_STRING_BYTEPOS (*it) += it->len;
-      IT_STRING_CHARPOS (*it) += 1;
+      if (it->cmp_it.id >= 0)
+	{
+	  IT_STRING_CHARPOS (*it) += it->cmp_it.nchars;
+	  IT_STRING_BYTEPOS (*it) += it->cmp_it.nbytes;
+	  if (it->cmp_it.to < it->cmp_it.nglyphs)
+	    it->cmp_it.from = it->cmp_it.to;
+	  else
+	    {
+	      it->cmp_it.id = -1;
+	      composition_compute_stop_pos (&it->cmp_it,
+					    IT_STRING_CHARPOS (*it),
+					    IT_STRING_BYTEPOS (*it),
+					    it->stop_charpos, it->string);
+	    }
+	}
+      else
+	{
+	  IT_STRING_BYTEPOS (*it) += it->len;
+	  IT_STRING_CHARPOS (*it) += 1;
+	}
 
     consider_string_end:
 
@@ -6330,6 +6227,12 @@
 	  it->what = IT_EOB;
 	  return 0;
 	}
+      else if (CHAR_COMPOSED_P (it, IT_STRING_CHARPOS (*it),
+				IT_STRING_BYTEPOS (*it))
+	       && next_element_from_composition (it))
+	{
+	  return 1;
+	}
       else if (STRING_MULTIBYTE (it->string))
 	{
 	  int remaining = SBYTES (it->string) - IT_STRING_BYTEPOS (*it);
@@ -6360,6 +6263,12 @@
 	  it->c = ' ', it->len = 1;
 	  CHARPOS (position) = BYTEPOS (position) = -1;
 	}
+      else if (CHAR_COMPOSED_P (it, IT_STRING_CHARPOS (*it),
+				IT_STRING_BYTEPOS (*it))
+	       && next_element_from_composition (it))
+	{
+	  return 1;
+	}
       else if (STRING_MULTIBYTE (it->string))
 	{
 	  int maxlen = SBYTES (it->string) - IT_STRING_BYTEPOS (*it);
@@ -6546,14 +6455,16 @@
 	  && IT_CHARPOS (*it) >= it->redisplay_end_trigger_charpos)
 	run_redisplay_end_trigger_hook (it);
 
+      if (CHAR_COMPOSED_P (it, IT_CHARPOS (*it), IT_BYTEPOS (*it))
+	  && next_element_from_composition (it))
+	{
+	  return 1;
+	}
+
       /* Get the next character, maybe multibyte.  */
       p = BYTE_POS_ADDR (IT_BYTEPOS (*it));
       if (it->multibyte_p && !ASCII_BYTE_P (*p))
-	{
-	  int maxlen = ((IT_BYTEPOS (*it) >= GPT_BYTE ? ZV_BYTE : GPT_BYTE)
-			- IT_BYTEPOS (*it));
-	  it->c = string_char_and_length (p, maxlen, &it->len);
-	}
+	it->c = STRING_CHAR_AND_LENGTH (p, 0, it->len);
       else
 	it->c = *p, it->len = 1;
 
@@ -6625,22 +6536,43 @@
 }
 
 
-/* Deliver a composition display element.  The iterator IT is already
-   filled with composition information (done in
-   handle_composition_prop).  Value is always 1.  */
+/* Deliver a composition display element.  Unlike the other
+   next_element_from_XXX, this function is not registered in the array
+   get_next_element[].  It is called from next_element_from_buffer and
+   next_element_from_string when necessary.  */
 
 static int
 next_element_from_composition (it)
      struct it *it;
 {
   it->what = IT_COMPOSITION;
-  it->position = (STRINGP (it->string)
-		  ? it->current.string_pos
-		  : it->current.pos);
+  it->len = it->cmp_it.nbytes;
   if (STRINGP (it->string))
-    it->object = it->string;
-  else
-    it->object = it->w->buffer;
+    {
+      if (it->c < 0)
+	{
+	  IT_STRING_CHARPOS (*it) += it->cmp_it.nchars;
+	  IT_STRING_BYTEPOS (*it) += it->cmp_it.nbytes;
+	  return 0;
+	}
+      it->position = it->current.string_pos;
+      it->object = it->string;
+      it->c = composition_update_it (&it->cmp_it, IT_STRING_CHARPOS (*it),
+				     IT_STRING_BYTEPOS (*it), it->string);
+    }
+  else
+    {
+      if (it->c < 0)
+	{
+	  IT_CHARPOS (*it) += it->cmp_it.nchars;
+	  IT_BYTEPOS (*it) += it->cmp_it.nbytes;
+	  return 0;
+	}
+      it->position = it->current.pos;
+      it->object = it->w->buffer;
+      it->c = composition_update_it (&it->cmp_it, IT_CHARPOS (*it),
+				     IT_BYTEPOS (*it), Qnil);
+    }    
   return 1;
 }
 
@@ -15674,7 +15606,7 @@
   else if (glyph->type == COMPOSITE_GLYPH)
     {
       fprintf (stderr,
-	       "  %5d %4c %6d %c %3d 0x%05x %c %4d %1.1d%1.1d\n",
+	       "  %5d %4c %6d %c %3d 0x%05x",
 	       glyph - row->glyphs[TEXT_AREA],
 	       '+',
 	       glyph->charpos,
@@ -15684,8 +15616,12 @@
 		   ? 'S'
 		   : '-')),
 	       glyph->pixel_width,
-	       glyph->u.cmp_id,
-	       '.',
+	       glyph->u.cmp.id);
+      if (glyph->u.cmp.automatic)
+	fprintf (stderr,
+		 "[%d-%d]",
+		 glyph->u.cmp.from, glyph->u.cmp.to);
+      fprintf (stderr, " . %4d %1.1d%1.1d\n"
 	       glyph->face_id,
 	       glyph->left_box_line_p,
 	       glyph->right_box_line_p);
@@ -19609,70 +19545,45 @@
      int overlaps;
 {
   int i;
+  /* 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;
 
   xassert (s);
 
   s->for_overlaps = overlaps;
-
-  if (s->cmp->method == COMPOSITION_WITH_GLYPH_STRING)
-    {
-      Lisp_Object gstring
-	= AREF (XHASH_TABLE (composition_hash_table)->key_and_value,
-		s->cmp->hash_index * 2);
-
-      s->face = base_face;
-      s->font = base_face->font;
-      for (i = 0, s->nchars = 0; i < s->cmp->glyph_len; i++, s->nchars++)
-	{
-	  Lisp_Object g = LGSTRING_GLYPH (gstring, i);
-	  unsigned code;
-          XChar2b * store_pos;
-	  if (NILP (g))
-	    break;
-	  code = LGLYPH_CODE (g);
-          store_pos = s->char2b + i;
-	  STORE_XCHAR2B (store_pos, code >> 8, code & 0xFF);
-	}
-      s->width = s->cmp->pixel_width;
-    }
-  else
-    {
-      /* 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;
-      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->ascii_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;
-		    }
-		  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;
-    }
+  s->face = NULL;
+  s->font = NULL;
+  for (i = s->cmp_from; 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->ascii_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;
+		}
+	      else if (s->face != face)
+		break;
+	    }
+	}
+      ++s->nchars;
+    }
+  s->cmp_to = i;
+
+  /* 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
@@ -19690,7 +19601,43 @@
   /* This glyph string must always be drawn with 16-bit functions.  */
   s->two_byte_p = 1;
 
-  return s->gidx + s->nchars;
+  return s->cmp_to;
+}
+
+static int
+fill_gstring_glyph_string (s, face_id, start, end, overlaps)
+     struct glyph_string *s;
+     int face_id;
+     int start, end, overlaps;
+{
+  struct glyph *glyph, *last;
+  Lisp_Object lgstring;
+  int i;
+
+  s->for_overlaps = overlaps;
+  glyph = s->row->glyphs[s->area] + start;
+  last = s->row->glyphs[s->area] + end;
+  s->cmp_id = glyph->u.cmp.id;
+  s->cmp_from = glyph->u.cmp.from;
+  s->cmp_to = glyph->u.cmp.to;
+  s->face = FACE_FROM_ID (s->f, face_id);
+  lgstring = composition_gstring_from_id (s->cmp_id);
+  s->font = XFONT_OBJECT (LGSTRING_FONT (lgstring));
+  glyph++;
+  while (glyph < last
+	 && glyph->u.cmp.automatic
+	 && glyph->u.cmp.id == s->cmp_id)
+    s->cmp_to = (glyph++)->u.cmp.to;
+
+  for (i = s->cmp_from; i < s->cmp_to; i++)
+    {
+      Lisp_Object lglyph = LGSTRING_GLYPH (lgstring, i);
+      unsigned code = LGLYPH_CODE (lglyph);
+
+      STORE_XCHAR2B ((s->char2b + i), code >> 8, code & 0xFF);
+    }
+  s->width = composition_gstring_width (lgstring, s->cmp_from, s->cmp_to, NULL);
+  return glyph - s->row->glyphs[s->area];
 }
 
 
@@ -19837,7 +19784,6 @@
 {
   static struct font_metrics metrics;
   unsigned code = (XCHAR2B_BYTE1 (char2b) << 8) | XCHAR2B_BYTE2 (char2b);
-  struct font *fontp;
 
   if (! font || code == FONT_INVALID_CODE)
     return NULL;
@@ -19875,10 +19821,27 @@
     }
   else if (glyph->type == COMPOSITE_GLYPH)
     {
-      struct composition *cmp = composition_table[glyph->u.cmp_id];
-
-      *right = cmp->rbearing - cmp->pixel_width;
-      *left = - cmp->lbearing;
+      if (! glyph->u.cmp.automatic)
+	{
+	  struct composition *cmp = composition_table[glyph->u.cmp.id];
+
+	  if (cmp->rbearing - cmp->pixel_width)
+	    *right = cmp->rbearing - cmp->pixel_width;
+	  if (cmp->lbearing < 0);
+	  *left = - cmp->lbearing;
+	}
+      else
+	{
+	  Lisp_Object gstring = composition_gstring_from_id (glyph->u.cmp.id);
+	  struct font_metrics metrics;
+
+	  composition_gstring_width (gstring, glyph->u.cmp.from,
+				     glyph->u.cmp.to, &metrics);
+	  if (metrics.rbearing > metrics.width)
+	    *right = metrics.rbearing;
+	  if (metrics.lbearing < 0)
+	    *left = - metrics.lbearing;
+	}
     }
 }
 
@@ -20142,7 +20105,7 @@
 	 INIT_GLYPH_STRING (s, char2b, w, row, area, START, HL);	   \
 	 append_glyph_string (&HEAD, &TAIL, s);				   \
 	 s->x = (X);							   \
-	 START = fill_glyph_string (s, face_id, START, END, overlaps);   \
+	 START = fill_glyph_string (s, face_id, START, END, overlaps);	   \
        }								   \
      while (0)
 
@@ -20160,7 +20123,7 @@
   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;			    \
+    int cmp_id = (row)->glyphs[area][START].u.cmp.id;			    \
     struct composition *cmp = composition_table[cmp_id];		    \
     XChar2b *char2b;							    \
     struct glyph_string *first_s;					    \
@@ -20176,7 +20139,7 @@
 	INIT_GLYPH_STRING (s, char2b, w, row, area, START, HL);		    \
 	append_glyph_string (&(HEAD), &(TAIL), s);			    \
 	s->cmp = cmp;							    \
-	s->gidx = n;							    \
+	s->cmp_from = n;						    \
 	s->x = (X);							    \
 	if (n == 0)							    \
 	  first_s = s;							    \
@@ -20188,6 +20151,28 @@
   } while (0)
 
 
+/* Add a glyph string for a glyph-string sequence to the list of strings
+   between HEAD and TAIL.  */
+
+#define BUILD_GSTRING_GLYPH_STRING(START, END, HEAD, TAIL, HL, X, LAST_X) \
+  do {									  \
+    int face_id;							  \
+    XChar2b *char2b;							  \
+    Lisp_Object gstring;						  \
+    									  \
+    face_id = (row)->glyphs[area][START].face_id;			  \
+    gstring = (composition_gstring_from_id				  \
+	       ((row)->glyphs[area][START].u.cmp.id));			  \
+    s = (struct glyph_string *) alloca (sizeof *s);			  \
+    char2b = (XChar2b *) alloca ((sizeof *char2b)			  \
+				 * LGSTRING_GLYPH_LEN (gstring));	  \
+    INIT_GLYPH_STRING (s, char2b, w, row, area, START, HL);		  \
+    append_glyph_string (&(HEAD), &(TAIL), s);				  \
+    s->x = (X);								  \
+    START = fill_gstring_glyph_string (s, face_id, START, END, overlaps); \
+  } 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
@@ -20198,47 +20183,50 @@
    to allocate glyph strings (because draw_glyphs can be called
    asynchronously).  */
 
-#define BUILD_GLYPH_STRINGS(START, END, HEAD, TAIL, HL, X, LAST_X)	   \
-     do									   \
-       {								   \
-	 HEAD = TAIL = NULL;						   \
-	 while (START < END)						   \
-	   {								   \
-             struct glyph *first_glyph = (row)->glyphs[area] + START;	   \
-             switch (first_glyph->type)					   \
-	       {							   \
-	       case CHAR_GLYPH:						   \
-                 BUILD_CHAR_GLYPH_STRINGS (START, END, HEAD, TAIL,	   \
-		                           HL, X, LAST_X);		   \
-		 break;							   \
-									   \
-	       case COMPOSITE_GLYPH:					   \
-                 BUILD_COMPOSITE_GLYPH_STRING (START, END, HEAD, TAIL,	   \
-					       HL, X, LAST_X);		   \
-		 break;							   \
-									   \
-	       case STRETCH_GLYPH:					   \
-		 BUILD_STRETCH_GLYPH_STRING (START, END, HEAD, TAIL,	   \
-					     HL, X, LAST_X);		   \
-		 break;							   \
-									   \
-	       case IMAGE_GLYPH:					   \
-		 BUILD_IMAGE_GLYPH_STRING (START, END, HEAD, TAIL,	   \
-					   HL, X, LAST_X);		   \
-		 break;							   \
-									   \
-	       default:							   \
-		 abort ();						   \
-	       }							   \
-									   \
-	     if (s)							   \
-	       {							   \
-		 set_glyph_string_background_width (s, START, LAST_X);	   \
-	         (X) += s->width;					   \
-	       }							   \
-            }								   \
-       }								   \
-     while (0)
+#define BUILD_GLYPH_STRINGS(START, END, HEAD, TAIL, HL, X, LAST_X)	\
+  do									\
+    {									\
+      HEAD = TAIL = NULL;						\
+      while (START < END)						\
+	{								\
+	  struct glyph *first_glyph = (row)->glyphs[area] + START;	\
+	  switch (first_glyph->type)					\
+	    {								\
+	    case CHAR_GLYPH:						\
+	      BUILD_CHAR_GLYPH_STRINGS (START, END, HEAD, TAIL,		\
+					HL, X, LAST_X);			\
+	      break;							\
+	      								\
+	    case COMPOSITE_GLYPH:					\
+	      if (first_glyph->u.cmp.automatic)				\
+		BUILD_GSTRING_GLYPH_STRING (START, END, HEAD, TAIL,	\
+					    HL, X, LAST_X);		\
+	      else							\
+		BUILD_COMPOSITE_GLYPH_STRING (START, END, HEAD, TAIL,	\
+					      HL, X, LAST_X);		\
+	      break;							\
+	      								\
+	    case STRETCH_GLYPH:						\
+	      BUILD_STRETCH_GLYPH_STRING (START, END, HEAD, TAIL,	\
+					  HL, X, LAST_X);		\
+	      break;							\
+	      								\
+	    case IMAGE_GLYPH:						\
+	      BUILD_IMAGE_GLYPH_STRING (START, END, HEAD, TAIL,		\
+					HL, X, LAST_X);			\
+	      break;							\
+	      								\
+	    default:							\
+	      abort ();							\
+	    }								\
+	  								\
+	  if (s)							\
+	    {								\
+	      set_glyph_string_background_width (s, START, LAST_X);	\
+	      (X) += s->width;						\
+	    }								\
+	}								\
+    } while (0)
 
 
 /* Draw glyphs between START and END in AREA of ROW on window W,
@@ -20559,8 +20547,9 @@
     IT_EXPAND_MATRIX_WIDTH (it, area);
 }
 
-/* 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.  */
+/* Store one glyph for the composition IT->cmp_it.id in
+   IT->glyph_row.  Called from x_produce_glyphs when IT->glyph_row is
+   non-null.  */
 
 static INLINE void
 append_composite_glyph (it)
@@ -20581,6 +20570,18 @@
       glyph->descent = it->descent;
       glyph->voffset = it->voffset;
       glyph->type = COMPOSITE_GLYPH;
+      if (it->cmp_it.ch < 0)
+	{
+	  glyph->u.cmp.automatic = 0;
+	  glyph->u.cmp.id = it->cmp_it.id;
+	}
+      else
+	{
+	  glyph->u.cmp.automatic = 1;
+	  glyph->u.cmp.id = it->cmp_it.id;
+	  glyph->u.cmp.from = it->cmp_it.from;
+	  glyph->u.cmp.to = it->cmp_it.to;
+	}
       glyph->avoid_cursor_p = it->avoid_cursor_p;
       glyph->multibyte_p = it->multibyte_p;
       glyph->left_box_line_p = it->start_of_box_run_p;
@@ -20590,7 +20591,6 @@
       glyph->padding_p = 0;
       glyph->glyph_not_available_p = 0;
       glyph->face_id = it->face_id;
-      glyph->u.cmp_id = it->cmp_id;
       glyph->slice = null_glyph_slice;
       glyph->font_type = FONT_TYPE_UNKNOWN;
       ++it->glyph_row->used[area];
@@ -21447,9 +21447,11 @@
 	}
       it->multibyte_p = saved_multibyte_p;
     }
-  else if (it->what == IT_COMPOSITION)
-    {
-      /* Note: A composition is represented as one glyph in the
+  else if (it->what == IT_COMPOSITION && it->cmp_it.ch < 0)
+    {
+      /* A static compositoin.
+
+	 Note: A composition is represented as one glyph in the
 	 glyph matrix.  There are no padding glyphs.
 
 	 Important is that pixel_width, ascent, and descent are the
@@ -21457,18 +21459,12 @@
 	 the overall glyphs composed).  */
       struct face *face = FACE_FROM_ID (it->f, it->face_id);
       int boff;			/* baseline offset */
-      struct composition *cmp = composition_table[it->cmp_id];
+      struct composition *cmp = composition_table[it->cmp_it.id];
       int glyph_len = cmp->glyph_len;
       struct font *font = face->font;
 
       it->nglyphs = 1;
 
-      if (cmp->method == COMPOSITION_WITH_GLYPH_STRING)
-	{
-	  PREPARE_FACE_FOR_DISPLAY (it->f, face);
-	  font_prepare_composition (cmp, it->f);
-	}
-      else
       /* 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
@@ -21488,7 +21484,6 @@
 	  int lbearing, rbearing;
 	  int i, width, ascent, descent;
 	  int left_padded = 0, right_padded = 0;
-	  int face_id;
 	  int c;
 	  XChar2b char2b;
 	  struct font_metrics *pcm;
@@ -21771,6 +21766,52 @@
       if (it->glyph_row)
 	append_composite_glyph (it);
     }
+  else if (it->what == IT_COMPOSITION)
+    {
+      /* A dynamic (automatic) composition.  */
+      struct face *face = FACE_FROM_ID (it->f, it->face_id);
+      Lisp_Object gstring;
+      struct font_metrics metrics;
+
+      gstring = composition_gstring_from_id (it->cmp_it.id);
+      it->pixel_width
+	= composition_gstring_width (gstring, it->cmp_it.from, it->cmp_it.to,
+				     &metrics);
+      if (it->glyph_row
+	  && (metrics.lbearing < 0 || metrics.rbearing > metrics.width))
+	it->glyph_row->contains_overlapping_glyphs_p = 1;
+      it->ascent = it->phys_ascent = metrics.ascent;
+      it->descent = it->phys_descent = metrics.descent;
+      if (face->box != FACE_NO_BOX)
+	{
+	  int thick = face->box_line_width;
+
+	  if (thick > 0)
+	    {
+	      it->ascent += thick;
+	      it->descent += thick;
+	    }
+	  else
+	    thick = - 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 += overline_margin;
+      take_vertical_position_into_account (it);
+      if (it->ascent < 0)
+	it->ascent = 0;
+      if (it->descent < 0)
+	it->descent = 0;
+
+      if (it->glyph_row)
+	append_composite_glyph (it);
+    }
   else if (it->what == IT_IMAGE)
     produce_image_glyph (it);
   else if (it->what == IT_STRETCH)