--- orig/src/extents.c	2006-06-21 18:30:36.000000000 +0100
+++ mod/src/extents.c	2008-06-23 22:21:02.000000000 +0100
@@ -209,6 +209,32 @@ Boston, MA 02111-1307, USA.  */
    than I and thus it is greater than any extent in S, including F.
    Otherwise, F2 includes I and thus is in S, and thus F2 >= F.
 
+
+   Extent glyph rendering follows from extent ordering, with
+   exceptions for zero-sized extents and non-inline-text glyphs.
+
+   . Non-inline text glyphs are always visible, regardless of whether
+   the extent they are attached to is within a (larger) invisible
+   extent.
+
+   . Inline text glyphs are not visible when the start or end of the
+   extent they are attached to is within an invisible extent.
+   Including sharing the start or end point with that larger extent.
+
+   . For the purposes of glyph rendering, zero length extents are
+   considered to be outside any non-zero length extent with a
+   coincident start or end point.
+
+   . Multiple non-zero length extents that end at the same position
+   have their end glyphs rendered in reverse display order.
+
+   . Multiple non-zero length extents that start at the same position
+   have their start glyphs rendered in display order.
+
+   . Zero length extents are rendered between the end glyphs and start
+   glyphs of non-zero length extents.  It is unspecified whether the
+   zero length extent glyphs nest, or are adjacent.
+   
 */
 
 #include <config.h>
@@ -2919,8 +2945,7 @@ extent_fragment_new (Lisp_Object buffer_
   ef->object = buffer_or_string;
   ef->frm = frm;
   ef->extents = Dynarr_new (EXTENT);
-  ef->begin_glyphs = Dynarr_new (glyph_block);
-  ef->end_glyphs   = Dynarr_new (glyph_block);
+  ef->glyphs = Dynarr_new (glyph_block);
 
   return ef;
 }
@@ -2929,8 +2954,7 @@ void
 extent_fragment_delete (struct extent_fragment *ef)
 {
   Dynarr_free (ef->extents);
-  Dynarr_free (ef->begin_glyphs);
-  Dynarr_free (ef->end_glyphs);
+  Dynarr_free (ef->glyphs);
   xfree (ef, struct extent_fragment *);
 }
 
@@ -3074,13 +3098,19 @@ face_index
 extent_fragment_update (struct window *w, struct extent_fragment *ef,
 			Bytexpos pos, Lisp_Object last_glyph)
 {
-  int i;
+  int i, j;
   int seen_glyph = NILP (last_glyph) ? 1 : 0;
   Extent_List *sel =
     buffer_or_string_stack_of_extents_force (ef->object)->extents;
   EXTENT lhe = 0;
   struct extent dummy_lhe_extent;
   Memxpos mempos = buffer_or_string_bytexpos_to_memxpos (ef->object, pos);
+  glyph_block_dynarr *glyphs; /* List of glyphs to post process */
+  int invis_before = 0;   /* Exiting an invisible extent.  */
+  int invis_after = 0;    /* Entering an invisible extent. */
+  int invis_over = 0;     /* Within an invisible extent. */
+  int insert_empty = 0;   /* Position to insert empty extent glyphs  */
+  int queuing_begin = 0;  /* Queuing begin glyphs. */
 
 #ifdef ERROR_CHECK_EXTENTS
   assert (pos >= buffer_or_string_accessible_begin_byte (ef->object)
@@ -3088,8 +3118,7 @@ extent_fragment_update (struct window *w
 #endif
 
   Dynarr_reset (ef->extents);
-  Dynarr_reset (ef->begin_glyphs);
-  Dynarr_reset (ef->end_glyphs);
+  Dynarr_reset (ef->glyphs);
 
   ef->previously_invisible = ef->invisible;
   if (ef->invisible)
@@ -3109,44 +3138,6 @@ extent_fragment_update (struct window *w
   /* Note that extent_find_end_of_run() already moved the SOE for us. */
   /* soe_move (ef->object, mempos); */
 
-  /* Determine the begin glyphs at POS. */
-  for (i = 0; i < extent_list_num_els (sel); i++)
-    {
-      EXTENT e = extent_list_at (sel, i, 0);
-      if (extent_start (e) == mempos && !NILP (extent_begin_glyph (e)))
-	{
-	  Lisp_Object glyph = extent_begin_glyph (e);
-	  if (seen_glyph) {
-	    struct glyph_block gb;
-	    
-	    gb.glyph = glyph;
-	    gb.extent = wrap_extent (e);
-	    Dynarr_add (ef->begin_glyphs, gb);
-	  }
-	  else if (EQ (glyph, last_glyph))
-	    seen_glyph = 1;
-	}
-    }
-
-  /* Determine the end glyphs at POS. */
-  for (i = 0; i < extent_list_num_els (sel); i++)
-    {
-      EXTENT e = extent_list_at (sel, i, 1);
-      if (extent_end (e) == mempos && !NILP (extent_end_glyph (e)))
-	{
-	  Lisp_Object glyph = extent_end_glyph (e);
-	  if (seen_glyph) {
-	    struct glyph_block gb;
-
-	    gb.glyph = glyph;
-	    gb.extent = wrap_extent (e);
-	    Dynarr_add (ef->end_glyphs, gb);
-	  }
-	  else if (EQ (glyph, last_glyph))
-	    seen_glyph = 1;
-	}
-    }
-
   /* We tried determining all the charsets used in the run here,
      but that fails even if we only do the current line -- display
      tables or non-printable characters might cause other charsets
@@ -3156,17 +3147,118 @@ extent_fragment_update (struct window *w
   if (EXTENTP (Vlast_highlighted_extent))
     lhe = XEXTENT (Vlast_highlighted_extent);
 
-  /* Now add all extents that overlap the character after POS and
-     have a non-nil face.  Also check if the character is invisible. */
+  /* Now add all extents that overlap the character after POS and have
+     a non-nil face.  Also check if the character is invisible.  We
+     also queue begin and end glyphs of extents that being/end at just
+     before POS.  These are ordered as follows. 1) end glyphs of
+     non-empty extents in reverse display order.  2) begin glyphs of
+     empty extents.  3) end glyphs of empty extents.  4) begin glyphs
+     of non-empty extents in display order.  Empty extents are shown
+     nested, but the invisibility property of an empty extent is
+     ignored and not used to determine whether an 'interior' empty
+     extent's glyphs should be shown or not.  */
+  glyphs = Dynarr_new(glyph_block);
   for (i = 0; i < extent_list_num_els (sel); i++)
     {
       EXTENT e = extent_list_at (sel, i, 0);
-      if (extent_end (e) > mempos)
+      int zero_width = extent_start(e) == extent_end(e);
+      Lisp_Object invis_prop = extent_invisible(e);
+      Lisp_Object glyph;
+
+      if (extent_start (e) == mempos)
 	{
-	  Lisp_Object invis_prop = extent_invisible (e);
+	  /* The extent starts here.  If we are queuing end glyphs, we
+             should display all the end glyphs we've pushed.  */
+
+	  if (!queuing_begin)
+	    {
+	      /* Append any already seen end glyphs */
+	      for (j = Dynarr_length (glyphs); j--;)
+		{
+		  struct glyph_block *gbp = Dynarr_atp (glyphs, j);
+
+		  if (seen_glyph)
+		    Dynarr_add (ef->glyphs, *gbp);
+		  else if (EQ (gbp->glyph, last_glyph))
+		    seen_glyph = 1;
+		}
 
+	      /* Pop the end glyphs just displayed. */
+	      Dynarr_set_size (glyphs, 0);
+	      /* We are now queuing begin glyphs. */
+	      queuing_begin = 1;
+	      /* And will insert empty extent glyphs just here.  */
+	      insert_empty = Dynarr_length (ef->glyphs);
+	    }
+
+	  glyph = extent_begin_glyph (e);
+
+	  if (!NILP (glyph))
+	    {
+	      struct glyph_block gb;
+
+	      gb.glyph = glyph;
+	      gb.active = 0; /* BEGIN_GLYPH */
+	      gb.extent = wrap_extent (e);
+
+	      if (extent_begin_glyph_layout (e) != GL_TEXT)
+		Dynarr_add (ef->glyphs, gb);
+	      else if (invis_over)
+		;
+	      else if (zero_width)
+		{
+		  if (insert_empty == Dynarr_length (ef->glyphs))
+		    Dynarr_add (ef->glyphs, gb);
+		  else
+		    Dynarr_insert_many (ef->glyphs, &gb, 1, insert_empty);
+		}
+	      else if (!invis_after) 
+		Dynarr_add (glyphs, gb);
+	    }
+	}
+
+      if (extent_end (e) == mempos)
+	{
+	  /* The extend ends here.  Push the end glyph.  */
+	  glyph = extent_end_glyph (e);
+
+	  if (!NILP (glyph))
+	    {
+	      struct glyph_block gb;
+
+	      gb.glyph = glyph;
+	      gb.active = 1; /* END_GLYPH */
+	      gb.extent = wrap_extent (e);
+
+	      if (extent_end_glyph_layout (e) != GL_TEXT)
+		Dynarr_add (ef->glyphs, gb);
+	      else if (invis_over)
+		;
+	      else if (zero_width)
+		Dynarr_add (ef->glyphs, gb);
+	      else if (!invis_before)
+		Dynarr_add (glyphs, gb);
+	    }
+	  
+	  /* If this extent is not empty, any inner extents ending here
+             will not be visible.  */
+	  if (extent_start (e) < mempos && !NILP (invis_prop))
+	    invis_before = 1;
+	}
+
+      if (extent_end (e) > mempos)
+	{
+	  /* This extent covers POS. */
 	  if (!NILP (invis_prop))
 	    {
+	      invis_after = 1;
+	      /* If this extend spans POS, all glyphs are invisible.  */
+	      if (extent_start (e) < mempos)
+		{
+		  Dynarr_set_size (glyphs, 0);
+		  invis_over = 1;
+		}
+
 	      if (!BUFFERP (ef->object))
 		/* #### no `string-invisibility-spec' */
 		ef->invisible = 1;
@@ -3237,6 +3329,51 @@ extent_fragment_update (struct window *w
 	}
     }
 
+  if (!queuing_begin)
+    /* Append end glyphs in reverse order */
+    for (j = Dynarr_length (glyphs); j--;)
+      {
+	struct glyph_block *gbp = Dynarr_atp (glyphs, j);
+
+	if (seen_glyph)
+	  Dynarr_add (ef->glyphs, *gbp);
+	else if (EQ (gbp->glyph, last_glyph))
+	  seen_glyph = 1;
+      }
+  else
+    {
+      if (!seen_glyph)
+	{
+	  /* Scan the zero length glyphs and see where we start a
+             glyph that has not been displayed yet.  */
+	  for (j = insert_empty; j != Dynarr_length (ef->glyphs); j++)
+	    {
+	      struct glyph_block *gbp = Dynarr_atp (ef->glyphs, j);
+
+	      if (EQ (gbp->glyph, last_glyph))
+		{
+		  seen_glyph = 1;
+		  j++;
+		  break;
+		}
+	    }
+	  Dynarr_delete_many (ef->glyphs, insert_empty, j - insert_empty);
+	}
+
+      /* Now copy the begin glyphs. */
+      for (j = 0; j != Dynarr_length (glyphs); j++)
+	{
+	  struct glyph_block *gbp = Dynarr_atp (glyphs, j);
+
+	  if (seen_glyph)
+	    Dynarr_add (ef->glyphs, *gbp);
+	  else if (EQ (gbp->glyph, last_glyph))
+	    seen_glyph = 1;
+	}
+    }
+
+  Dynarr_free (glyphs);
+
   extent_fragment_sort_by_priority (ef->extents);
 
   /* Now merge the faces together into a single face.  The code to
--- orig/src/redisplay.c	2006-11-05 22:31:45.000000000 +0000
+++ mod/src/redisplay.c	2008-06-20 04:21:54.000000000 +0100
@@ -2080,20 +2080,19 @@ add_glyph_rune (pos_data *data, struct g
    data. */
 
 static prop_block_dynarr *
-add_glyph_runes (pos_data *data, int pos_type)
+add_glyph_runes (pos_data *data)
 {
   /* #### This still needs to handle the start_col parameter.  Duh, Chuck,
      why didn't you just modify add_glyph_rune in the first place? */
   int elt;
-  glyph_block_dynarr *glyph_arr = (pos_type == BEGIN_GLYPHS
-				   ? data->ef->begin_glyphs
-				   : data->ef->end_glyphs);
+  glyph_block_dynarr *glyph_arr = data->ef->glyphs;
   prop_block_dynarr *prop;
 
   for (elt = 0; elt < Dynarr_length (glyph_arr); elt++)
     {
-      prop = add_glyph_rune (data, Dynarr_atp (glyph_arr, elt), pos_type, 0,
-			     0);
+      struct glyph_block *gb = Dynarr_atp (glyph_arr, elt);
+      prop = add_glyph_rune (data, gb, gb->active ? END_GLYPHS : BEGIN_GLYPHS,
+			    0, 0);
 
       if (prop)
 	{
@@ -2327,13 +2326,59 @@ create_text_block (struct window *w, str
          display then we determine what to do based on the character at the
          current buffer position. */
 
-      /* If the current position is covered by an invisible extent, do
-         nothing (except maybe add some ellipses).
+      /* If there are glyphs, add them to the line.  These are the end
+         glyphs for the previous run of text.  We add them here rather
+         than doing them at the end of handling the previous run so
+         that glyphs at the beginning and end of a line are handled
+         correctly. */
+      if (Dynarr_length (data.ef->glyphs) > 0)
+	{
+	  glyph_block_dynarr* tmpglyphs = 0;
+	  /* #### I think this is safe, but could be wrong. */
+	  data.ch = BYTE_BUF_FETCH_CHAR (b, data.byte_charpos);
+
+	  *prop = add_glyph_runes (&data);
+	  tmpglyphs = data.ef->glyphs;
+
+	  if (*prop) 
+	    {
+	      /* If we just clipped a glyph and we are at the end of a
+                 line and there are more glyphs to display then do
+                 appropriate processing to not get a continuation
+                 glyph.  */
+	      if (*prop != ADD_FAILED 
+		  && Dynarr_atp (*prop, 0)->type == PROP_GLYPH
+		  && data.ch == '\n')
+		{
+		  /* If there are no more glyphs then do the normal
+                     processing.
+
+		     #### This doesn't actually work if the same glyph
+		     #### is present more than once in the block. To
+		     #### solve this we would have to carry the index
+		     #### around which might be problematic since the
+		     #### fragment is recalculated for each line.  */ 
+		  if (EQ (Dynarr_end (tmpglyphs)->glyph,
+			  Dynarr_atp (*prop, 0)->data.p_glyph.glyph))
+		    {
+		      Dynarr_free (*prop);
+		      *prop = 0;
+		    }
+		  else
+		    {
+		      data.blank_width = DEVMETH (d, eol_cursor_width, ());
+		      add_ichar_rune (&data); /* discard prop data. */
+		      goto done;
+		    }
+		}
+	      else
+		goto done;
+	    }
+	}
 
-	 #### The behavior of begin and end-glyphs at the edge of an
-	 invisible extent should be investigated further.  This is
-	 fairly low priority though. */
-      if (data.ef->invisible)
+      /* If the current position is covered by an invisible extent, do
+         nothing (except maybe add some ellipses).  */
+      else if (data.ef->invisible)
 	{
 	  /* #### Chuck, perhaps you could look at this code?  I don't
 	     really know what I'm doing. */
@@ -2402,66 +2447,6 @@ create_text_block (struct window *w, str
 	    INC_BYTEBPOS (b, data.byte_charpos);
 	}
 
-      /* If there are end glyphs, add them to the line.  These are
-	 the end glyphs for the previous run of text.  We add them
-	 here rather than doing them at the end of handling the
-	 previous run so that glyphs at the beginning and end of
-	 a line are handled correctly. */
-      else if (Dynarr_length (data.ef->end_glyphs) > 0
-	       || Dynarr_length (data.ef->begin_glyphs) > 0)
-	{
-	  glyph_block_dynarr* tmpglyphs = 0;
-	  /* #### I think this is safe, but could be wrong. */
-	  data.ch = BYTE_BUF_FETCH_CHAR (b, data.byte_charpos);
-
-	  if (Dynarr_length (data.ef->end_glyphs) > 0) 
-	    {
-	      *prop = add_glyph_runes (&data, END_GLYPHS);
-	      tmpglyphs = data.ef->end_glyphs;
-	    }
-
-	  /* If there are begin glyphs, add them to the line. */
-	  if (!*prop && Dynarr_length (data.ef->begin_glyphs) > 0) 
-	    {
-	      *prop = add_glyph_runes (&data, BEGIN_GLYPHS);
-	      tmpglyphs = data.ef->begin_glyphs;
-	    }
-
-	  if (*prop) 
-	    {
-	      /* If we just clipped a glyph and we are at the end of a
-		 line and there are more glyphs to display then do
-		 appropriate processing to not get a continuation
-		 glyph. */
-	      if (*prop != ADD_FAILED 
-		  && Dynarr_atp (*prop, 0)->type == PROP_GLYPH
-		  && data.ch == '\n')
-		{ 
-		  /* If there are no more glyphs then do the normal
-		     processing. 
-
-		     #### This doesn't actually work if the same glyph is
-		     present more than once in the block. To solve
-		     this we would have to carry the index around
-		     which might be problematic since the fragment is
-		     recalculated for each line. */
-		  if (EQ (Dynarr_end (tmpglyphs)->glyph,
-			  Dynarr_atp (*prop, 0)->data.p_glyph.glyph))
-		    {
-		      Dynarr_free (*prop);
-		      *prop = 0;
-		    }
-		  else {
-		    data.blank_width = DEVMETH (d, eol_cursor_width, ());
-		    add_ichar_rune (&data); /* discard prop data. */
-		    goto done;
-		  }
-		}
-	      else
-		goto done;
-	    }
-	}
-
       /* If at end-of-buffer, we've already processed begin and
 	 end-glyphs at this point and there's no text to process,
 	 so we're done. */
@@ -4802,13 +4787,21 @@ create_string_text_block (struct window 
          display then we determine what to do based on the character at the
          current buffer position. */
 
-      /* If the current position is covered by an invisible extent, do
-         nothing (except maybe add some ellipses).
+      /* If there are glyphs, add them to the line.  We add the end
+         glyphs for the previous run of text here rather than doing
+         them at the end of handling the previous run so that glyphs
+         at the beginning and end of a line are handled correctly. */
+      if (Dynarr_length (data.ef->glyphs) > 0)
+	{
+	  data.ch = string_ichar (disp_string, data.byte_charpos);
+	  *prop = add_glyph_runes (&data);
+	  if (*prop)
+	    goto done;
+	}
 
-	 #### The behavior of begin and end-glyphs at the edge of an
-	 invisible extent should be investigated further.  This is
-	 fairly low priority though. */
-      if (data.ef->invisible)
+      /* If the current position is covered by an invisible extent, do
+         nothing (except maybe add some ellipses). */
+      else if (data.ef->invisible)
 	{
 	  /* #### Chuck, perhaps you could look at this code?  I don't
 	     really know what I'm doing. */
@@ -4869,32 +4862,6 @@ create_string_text_block (struct window 
 	    INC_BYTECOUNT (XSTRING_DATA (disp_string), data.byte_charpos);
 	}
 
-      /* If there are end glyphs, add them to the line.  These are
-	 the end glyphs for the previous run of text.  We add them
-	 here rather than doing them at the end of handling the
-	 previous run so that glyphs at the beginning and end of
-	 a line are handled correctly. */
-      else if (Dynarr_length (data.ef->end_glyphs) > 0)
-	{
-	  data.ch = string_ichar (disp_string, data.byte_charpos);
-	  *prop = add_glyph_runes (&data, END_GLYPHS);
-
-	  if (*prop) {
-	    goto done;
-	  }
-	}
-
-      /* If there are begin glyphs, add them to the line. */
-      else if (Dynarr_length (data.ef->begin_glyphs) > 0)
-	{
-	  data.ch = string_ichar (disp_string, data.byte_charpos);
-	  *prop = add_glyph_runes (&data, BEGIN_GLYPHS);
-
-	  if (*prop) {
-	    goto done;
-	  }
-	}
-
       /* If at end-of-buffer, we've already processed begin and
 	 end-glyphs at this point and there's no text to process,
 	 so we're done. */
diff -r -up orig/src/redisplay.h mod/src/redisplay.h
--- orig/src/redisplay.h	2005-03-09 19:47:41.000000000 +0000
+++ mod/src/redisplay.h	2008-06-20 04:03:33.000000000 +0100
@@ -244,10 +244,11 @@ struct glyph_block
 {
   Lisp_Object glyph;
   Lisp_Object extent;
-  /* The rest are only used by margin routines. */
-  face_index findex;
-  int active;
-  int width;
+
+  face_index findex; /* Only used by margin routines.  */
+  int active;        /* For begin/end glyph indicates type, otherwise
+                        for margin routines. */
+  int width;         /* Only used by margin routines.  */
 };
 
 typedef struct
@@ -395,7 +396,7 @@ struct extent_fragment
   struct frame *frm;
   Bytexpos pos, end;
   EXTENT_dynarr *extents;
-  glyph_block_dynarr *begin_glyphs, *end_glyphs;
+  glyph_block_dynarr *glyphs;
   unsigned int invisible:1;
   unsigned int invisible_ellipses:1;
   unsigned int previously_invisible:1;
