[cairo] Cairo vs. Xft glyph rendering

Behdad Esfahbod behdad at behdad.org
Mon Dec 11 01:46:53 PST 2006


On Fri, 2006-12-08 at 10:04 -0500, Vladimir Vukicevic wrote:

> Maybe one of the X folks here could let us know whether doing this could 
> result in a performance gain?  We already have to do the lookup per 
> glyph to make sure that it's sent to the server, so we could always 
> change the data structure that's used to pass things down to 
> xlib_show_glyphs{8,16,32} so that it sends the right info, instead of 
> just sending down the cairo_glyph_t array.  That is, either pass down 
> cairo_glyph_t + per-glyph offsets, or even do the run computation ahead 
> of time and pass down some structure that can be trivially converted to 
> the appropriate size XGlyphElt array.

This is basically what I've done now, and pushed into my tree under the
branch xlib-show-glyphs-fast:

http://gitweb.freedesktop.org/?p=users/behdad/cairo.git;a=shortlog;h=xlib-show-glyphs-fast

The patch set is attached.  I started by introducing a new type
cairo_glyph_fixed_t and pass that down, but at the end I figured this is
actually a penalty for most backends and not much gain for any, so I
backed that up.

Other than compressing glyphs into elements, I also made a semantic
change to show_glyphs() calls all over the tree, that is, those
functions that get a non-const cairo_glyph_t* are allowed to modify the
glyph array unless then return CAIRO_STATUS_UNSUPPORTED.  This means,
backends can modify the input glyph array or use it for totally
different things instead of having to duplicate it or allocate memory.
My rewritten cairo_xlib_show_glyphs() heavily uses this.

Anyway, patchset attached.  It looks ready to me, and on my laptop saves
some 6% on timetext (plus a malloc per show_glyphs()).

Waiting for numbers :-)


-- 
behdad
http://behdad.org/

"Those who would give up Essential Liberty to purchase a little
 Temporary Safety, deserve neither Liberty nor Safety."
        -- Benjamin Franklin, 1759


-------------- next part --------------
>From 5a9642c5746fd677aed35ce620ce90b1029b1a0c Mon Sep 17 00:00:00 2001
From: Behdad Esfahbod <behdad at behdad.org>
Date: Mon, 11 Dec 2006 01:39:51 -0500
Subject: [PATCH] Add/remove const to cairo_glyph_t* arguments consistently

The rule is: cairo_glyph_t* is always passed as const for measurement
purposes.  This was not reflected in our public api previously.  Fixed

Showing glyphs used to have cairo_glyph_t* always as const.  With this
changed, it is only const on cairo_t and cairo_gstate_t operations.
cairo_surface_t, cairo_scaled_font_t, and individual backends receive
cairo_glyph_t* as non-const.  The desired semantics is that they may modify
the contents of the array as long as they do not return
CAIRO_STATUS_UNSUPPORTED.  This makes it possible to avoid copying the glyph
array again and again, and edit it in-place.  Backends are in fact free to use
the array as a generic buffer as they see fit.
---
 src/cairo-analysis-surface.c         |    2 +-
 src/cairo-atsui-font.c               |    2 +-
 src/cairo-directfb-surface.c         |    2 +-
 src/cairo-glitz-surface.c            |    2 +-
 src/cairo-gstate.c                   |   12 ++++++------
 src/cairo-meta-surface.c             |    2 +-
 src/cairo-nquartz-surface.c          |    2 +-
 src/cairo-paginated-surface.c        |    2 +-
 src/cairo-pdf-surface.c              |    2 +-
 src/cairo-ps-surface.c               |    2 +-
 src/cairo-scaled-font.c              |    4 ++--
 src/cairo-surface-fallback-private.h |    2 +-
 src/cairo-surface-fallback.c         |    4 ++--
 src/cairo-surface.c                  |    4 ++--
 src/cairo-svg-surface.c              |    2 +-
 src/cairo-win32-font.c               |    2 +-
 src/cairo-win32-surface.c            |    2 +-
 src/cairo-xcb-surface.c              |    4 ++--
 src/cairo-xlib-surface.c             |    4 ++--
 src/cairo.c                          |    4 ++--
 src/cairo.h                          |    6 +++---
 src/cairoint.h                       |   28 +++++++++++-----------------
 src/test-meta-surface.c              |    2 +-
 src/test-paginated-surface.c         |    2 +-
 24 files changed, 47 insertions(+), 53 deletions(-)

diff --git a/src/cairo-analysis-surface.c b/src/cairo-analysis-surface.c
index fd764c6..a89636e 100644
--- a/src/cairo-analysis-surface.c
+++ b/src/cairo-analysis-surface.c
@@ -154,7 +154,7 @@ static cairo_int_status_t
 _cairo_analysis_surface_show_glyphs (void		  *abstract_surface,
 				     cairo_operator_t	   op,
 				     cairo_pattern_t	  *source,
-				     const cairo_glyph_t  *glyphs,
+				     cairo_glyph_t	  *glyphs,
 				     int		   num_glyphs,
 				     cairo_scaled_font_t  *scaled_font)
 {
diff --git a/src/cairo-atsui-font.c b/src/cairo-atsui-font.c
index 973160d..2927caa 100644
--- a/src/cairo-atsui-font.c
+++ b/src/cairo-atsui-font.c
@@ -578,7 +578,7 @@ _cairo_atsui_font_old_show_glyphs (void	
 				   int			dest_y,
 				   unsigned int		width,
 				   unsigned int		height,
-				   const cairo_glyph_t *glyphs,
+				   cairo_glyph_t       *glyphs,
 				   int                 	num_glyphs)
 {
     cairo_atsui_font_t *font = abstract_font;
diff --git a/src/cairo-directfb-surface.c b/src/cairo-directfb-surface.c
index fc6cbef..46a4c7f 100644
--- a/src/cairo-directfb-surface.c
+++ b/src/cairo-directfb-surface.c
@@ -1450,7 +1450,7 @@ static cairo_int_status_t
 _cairo_directfb_surface_show_glyphs ( void                 *abstract_dst,
                                      cairo_operator_t      op,
                                      cairo_pattern_t      *pattern,
-                                     const cairo_glyph_t  *glyphs,
+                                     cairo_glyph_t	  *glyphs,
                                      int                   num_glyphs,
                                      cairo_scaled_font_t  *scaled_font)
 {
diff --git a/src/cairo-glitz-surface.c b/src/cairo-glitz-surface.c
index a579511..3b23691 100644
--- a/src/cairo-glitz-surface.c
+++ b/src/cairo-glitz-surface.c
@@ -1909,7 +1909,7 @@ _cairo_glitz_surface_old_show_glyphs (ca
 				      int		   dst_y,
 				      unsigned int	   width,
 				      unsigned int	   height,
-				      const cairo_glyph_t *glyphs,
+				      cairo_glyph_t       *glyphs,
 				      int		   num_glyphs)
 {
     cairo_glitz_surface_attributes_t	attributes;
diff --git a/src/cairo-gstate.c b/src/cairo-gstate.c
index d04c332..ab32545 100644
--- a/src/cairo-gstate.c
+++ b/src/cairo-gstate.c
@@ -65,7 +65,7 @@ static void
 _cairo_gstate_transform_glyphs_to_backend (cairo_gstate_t      *gstate,
                                            const cairo_glyph_t *glyphs,
                                            int                  num_glyphs,
-                                           cairo_glyph_t *transformed_glyphs);
+                                           cairo_glyph_t       *transformed_glyphs);
 
 /**
  * _cairo_gstate_create:
@@ -1447,7 +1447,7 @@ _cairo_gstate_set_font_face (cairo_gstat
 
 cairo_status_t
 _cairo_gstate_glyph_extents (cairo_gstate_t *gstate,
-			     cairo_glyph_t *glyphs,
+			     const cairo_glyph_t *glyphs,
 			     int num_glyphs,
 			     cairo_text_extents_t *extents)
 {
@@ -1507,10 +1507,10 @@ _cairo_gstate_show_glyphs (cairo_gstate_
 }
 
 cairo_status_t
-_cairo_gstate_glyph_path (cairo_gstate_t     *gstate,
-			  cairo_glyph_t	     *glyphs,
-			  int		      num_glyphs,
-			  cairo_path_fixed_t *path)
+_cairo_gstate_glyph_path (cairo_gstate_t      *gstate,
+			  const cairo_glyph_t *glyphs,
+			  int		       num_glyphs,
+			  cairo_path_fixed_t  *path)
 {
     cairo_status_t status;
     cairo_glyph_t *transformed_glyphs = NULL;
diff --git a/src/cairo-meta-surface.c b/src/cairo-meta-surface.c
index d6beaf0..a82ab8f 100644
--- a/src/cairo-meta-surface.c
+++ b/src/cairo-meta-surface.c
@@ -416,7 +416,7 @@ static cairo_int_status_t
 _cairo_meta_surface_show_glyphs (void			*abstract_surface,
 				 cairo_operator_t	 op,
 				 cairo_pattern_t	*source,
-				 const cairo_glyph_t	*glyphs,
+				 cairo_glyph_t		*glyphs,
 				 int			 num_glyphs,
 				 cairo_scaled_font_t	*scaled_font)
 {
diff --git a/src/cairo-nquartz-surface.c b/src/cairo-nquartz-surface.c
index 5e82616..15b3d61 100644
--- a/src/cairo-nquartz-surface.c
+++ b/src/cairo-nquartz-surface.c
@@ -1304,7 +1304,7 @@ static cairo_int_status_t
 _cairo_nquartz_surface_show_glyphs (void *abstract_surface,
 				    cairo_operator_t op,
 				    cairo_pattern_t *source,
-				    const cairo_glyph_t *glyphs,
+				    cairo_glyph_t *glyphs,
 				    int num_glyphs,
 				    cairo_scaled_font_t *scaled_font)
 {
diff --git a/src/cairo-paginated-surface.c b/src/cairo-paginated-surface.c
index d497778..b313ac1 100644
--- a/src/cairo-paginated-surface.c
+++ b/src/cairo-paginated-surface.c
@@ -437,7 +437,7 @@ static cairo_int_status_t
 _cairo_paginated_surface_show_glyphs (void			*abstract_surface,
 				      cairo_operator_t		 op,
 				      cairo_pattern_t		*source,
-				      const cairo_glyph_t	*glyphs,
+				      cairo_glyph_t		*glyphs,
 				      int			 num_glyphs,
 				      cairo_scaled_font_t	*scaled_font)
 {
diff --git a/src/cairo-pdf-surface.c b/src/cairo-pdf-surface.c
index 25d367e..a59cd99 100644
--- a/src/cairo-pdf-surface.c
+++ b/src/cairo-pdf-surface.c
@@ -2720,7 +2720,7 @@ static cairo_int_status_t
 _cairo_pdf_surface_show_glyphs (void			*abstract_surface,
 				cairo_operator_t	 op,
 				cairo_pattern_t		*source,
-				const cairo_glyph_t	*glyphs,
+				cairo_glyph_t		*glyphs,
 				int			 num_glyphs,
 				cairo_scaled_font_t	*scaled_font)
 {
diff --git a/src/cairo-ps-surface.c b/src/cairo-ps-surface.c
index 75fe83e..6d1afe9 100644
--- a/src/cairo-ps-surface.c
+++ b/src/cairo-ps-surface.c
@@ -2136,7 +2136,7 @@ static cairo_int_status_t
 _cairo_ps_surface_show_glyphs (void		     *abstract_surface,
 			       cairo_operator_t	      op,
 			       cairo_pattern_t	     *source,
-			       const cairo_glyph_t   *glyphs,
+			       cairo_glyph_t         *glyphs,
 			       int		      num_glyphs,
 			       cairo_scaled_font_t   *scaled_font)
 {
diff --git a/src/cairo-scaled-font.c b/src/cairo-scaled-font.c
index 0b060fd..b800cf9 100755
--- a/src/cairo-scaled-font.c
+++ b/src/cairo-scaled-font.c
@@ -698,7 +698,7 @@ cairo_scaled_font_text_extents (cairo_sc
  **/
 void
 cairo_scaled_font_glyph_extents (cairo_scaled_font_t   *scaled_font,
-				 cairo_glyph_t         *glyphs,
+				 const cairo_glyph_t   *glyphs,
 				 int                    num_glyphs,
 				 cairo_text_extents_t  *extents)
 {
@@ -891,7 +891,7 @@ _cairo_scaled_font_show_glyphs (cairo_sc
 				int			dest_y,
 				unsigned int		width,
 				unsigned int		height,
-				const cairo_glyph_t    *glyphs,
+				cairo_glyph_t	       *glyphs,
 				int                     num_glyphs)
 {
     cairo_status_t status;
diff --git a/src/cairo-surface-fallback-private.h b/src/cairo-surface-fallback-private.h
index 89a11cb..e0f83c4 100644
--- a/src/cairo-surface-fallback-private.h
+++ b/src/cairo-surface-fallback-private.h
@@ -74,7 +74,7 @@ cairo_private cairo_status_t
 _cairo_surface_fallback_show_glyphs (cairo_surface_t		*surface,
 				     cairo_operator_t		 op,
 				     cairo_pattern_t		*source,
-				     const cairo_glyph_t	*glyphs,
+				     cairo_glyph_t		*glyphs,
 				     int			 num_glyphs,
 				     cairo_scaled_font_t	*scaled_font);
 
diff --git a/src/cairo-surface-fallback.c b/src/cairo-surface-fallback.c
index 2d23411..02033c8 100644
--- a/src/cairo-surface-fallback.c
+++ b/src/cairo-surface-fallback.c
@@ -839,7 +839,7 @@ _cairo_surface_fallback_fill (cairo_surf
 
 typedef struct {
     cairo_scaled_font_t *font;
-    const cairo_glyph_t *glyphs;
+    cairo_glyph_t *glyphs;
     int num_glyphs;
 } cairo_show_glyphs_info_t;
 
@@ -907,7 +907,7 @@ cairo_status_t
 _cairo_surface_fallback_show_glyphs (cairo_surface_t		*surface,
 				     cairo_operator_t		 op,
 				     cairo_pattern_t		*source,
-				     const cairo_glyph_t	*glyphs,
+				     cairo_glyph_t		*glyphs,
 				     int			 num_glyphs,
 				     cairo_scaled_font_t	*scaled_font)
 {
diff --git a/src/cairo-surface.c b/src/cairo-surface.c
index dfcf39d..6690971 100644
--- a/src/cairo-surface.c
+++ b/src/cairo-surface.c
@@ -1795,7 +1795,7 @@ cairo_status_t
 _cairo_surface_show_glyphs (cairo_surface_t	*surface,
 			    cairo_operator_t	 op,
 			    cairo_pattern_t	*source,
-			    const cairo_glyph_t	*glyphs,
+			    cairo_glyph_t	*glyphs,
 			    int			 num_glyphs,
 			    cairo_scaled_font_t	*scaled_font)
 {
@@ -1873,7 +1873,7 @@ _cairo_surface_old_show_glyphs (cairo_sc
 				int			 dest_y,
 				unsigned int		 width,
 				unsigned int		 height,
-				const cairo_glyph_t	*glyphs,
+				cairo_glyph_t		*glyphs,
 				int			 num_glyphs)
 {
     cairo_status_t status;
diff --git a/src/cairo-svg-surface.c b/src/cairo-svg-surface.c
index 0ca0e72..573fb3c 100644
--- a/src/cairo-svg-surface.c
+++ b/src/cairo-svg-surface.c
@@ -1608,7 +1608,7 @@ static cairo_int_status_t
 _cairo_svg_surface_show_glyphs (void			*abstract_surface,
 				cairo_operator_t	 op,
 				cairo_pattern_t		*pattern,
-				const cairo_glyph_t	*glyphs,
+				cairo_glyph_t		*glyphs,
 				int			 num_glyphs,
 				cairo_scaled_font_t	*scaled_font)
 {
diff --git a/src/cairo-win32-font.c b/src/cairo-win32-font.c
index 58b4dd1..139a73b 100644
--- a/src/cairo-win32-font.c
+++ b/src/cairo-win32-font.c
@@ -1151,7 +1151,7 @@ _cairo_win32_scaled_font_show_glyphs (vo
 				      int			dest_y,
 				      unsigned int		width,
 				      unsigned int		height,
-				      const cairo_glyph_t      *glyphs,
+				      cairo_glyph_t	       *glyphs,
 				      int                 	num_glyphs)
 {
     cairo_win32_scaled_font_t *scaled_font = abstract_font;
diff --git a/src/cairo-win32-surface.c b/src/cairo-win32-surface.c
index a90f867..8b34549 100644
--- a/src/cairo-win32-surface.c
+++ b/src/cairo-win32-surface.c
@@ -1473,7 +1473,7 @@ static cairo_int_status_t
 _cairo_win32_surface_show_glyphs (void			*surface,
 				  cairo_operator_t	 op,
 				  cairo_pattern_t	*source,
-				  const cairo_glyph_t	*glyphs,
+				  cairo_glyph_t		*glyphs,
 				  int			 num_glyphs,
 				  cairo_scaled_font_t	*scaled_font)
 {
diff --git a/src/cairo-xcb-surface.c b/src/cairo-xcb-surface.c
index 9c34879..8b8ba1d 100644
--- a/src/cairo-xcb-surface.c
+++ b/src/cairo-xcb-surface.c
@@ -1574,7 +1574,7 @@ static cairo_int_status_t
 _cairo_xcb_surface_show_glyphs (void                *abstract_dst,
 				 cairo_operator_t     op,
 				 cairo_pattern_t     *src_pattern,
-				 const cairo_glyph_t *glyphs,
+				 cairo_glyph_t       *glyphs,
 				 int		      num_glyphs,
 				 cairo_scaled_font_t *scaled_font);
 
@@ -2260,7 +2260,7 @@ static cairo_int_status_t
 _cairo_xcb_surface_show_glyphs (void                *abstract_dst,
 				 cairo_operator_t     op,
 				 cairo_pattern_t     *src_pattern,
-				 const cairo_glyph_t *glyphs,
+				 cairo_glyph_t       *glyphs,
 				 int		      num_glyphs,
 				 cairo_scaled_font_t *scaled_font)
 {
diff --git a/src/cairo-xlib-surface.c b/src/cairo-xlib-surface.c
index 4e7f640..5482a2f 100644
--- a/src/cairo-xlib-surface.c
+++ b/src/cairo-xlib-surface.c
@@ -69,7 +69,7 @@ static cairo_int_status_t
 _cairo_xlib_surface_show_glyphs (void                *abstract_dst,
 				 cairo_operator_t     op,
 				 cairo_pattern_t     *src_pattern,
-				 const cairo_glyph_t *glyphs,
+				 cairo_glyph_t       *glyphs,
 				 int		      num_glyphs,
 				 cairo_scaled_font_t *scaled_font);
 
@@ -2689,7 +2689,7 @@ static cairo_int_status_t
 _cairo_xlib_surface_show_glyphs (void                *abstract_dst,
 				 cairo_operator_t     op,
 				 cairo_pattern_t     *src_pattern,
-				 const cairo_glyph_t *glyphs,
+				 cairo_glyph_t       *glyphs,
 				 int		      num_glyphs,
 				 cairo_scaled_font_t *scaled_font)
 {
diff --git a/src/cairo.c b/src/cairo.c
index b874777..7546d7a 100644
--- a/src/cairo.c
+++ b/src/cairo.c
@@ -2613,7 +2613,7 @@ cairo_text_extents (cairo_t             
  **/
 void
 cairo_glyph_extents (cairo_t                *cr,
-		     cairo_glyph_t          *glyphs,
+		     const cairo_glyph_t    *glyphs,
 		     int                    num_glyphs,
 		     cairo_text_extents_t   *extents)
 {
@@ -2749,7 +2749,7 @@ cairo_text_path  (cairo_t *cr, const cha
 }
 
 void
-cairo_glyph_path (cairo_t *cr, cairo_glyph_t *glyphs, int num_glyphs)
+cairo_glyph_path (cairo_t *cr, const cairo_glyph_t *glyphs, int num_glyphs)
 {
     if (cr->status)
 	return;
diff --git a/src/cairo.h b/src/cairo.h
index 1b599d5..5e58244 100644
--- a/src/cairo.h
+++ b/src/cairo.h
@@ -954,7 +954,7 @@ cairo_text_extents (cairo_t             
 
 cairo_public void
 cairo_glyph_extents (cairo_t               *cr,
-		     cairo_glyph_t         *glyphs,
+		     const cairo_glyph_t   *glyphs,
 		     int                   num_glyphs,
 		     cairo_text_extents_t  *extents);
 
@@ -962,7 +962,7 @@ cairo_public void
 cairo_text_path  (cairo_t *cr, const char *utf8);
 
 cairo_public void
-cairo_glyph_path (cairo_t *cr, cairo_glyph_t *glyphs, int num_glyphs);
+cairo_glyph_path (cairo_t *cr, const cairo_glyph_t *glyphs, int num_glyphs);
 
 /* Generic identifier for a font style */
 
@@ -1062,7 +1062,7 @@ cairo_scaled_font_text_extents (cairo_sc
 
 cairo_public void
 cairo_scaled_font_glyph_extents (cairo_scaled_font_t   *scaled_font,
-				 cairo_glyph_t         *glyphs,
+				 const cairo_glyph_t   *glyphs,
 				 int                   num_glyphs,
 				 cairo_text_extents_t  *extents);
 
diff --git a/src/cairoint.h b/src/cairoint.h
index e996a1c..b481d45 100755
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -632,7 +632,7 @@ struct _cairo_scaled_font_backend {
 			 int			 dest_y,
 			 unsigned int		 width,
 			 unsigned int		 height,
-			 const cairo_glyph_t	*glyphs,
+			 cairo_glyph_t		*glyphs,
 			 int			 num_glyphs);
 
     cairo_int_status_t
@@ -855,7 +855,7 @@ struct _cairo_surface_backend {
 				 int				 dest_y,
 				 unsigned int			 width,
 				 unsigned int			 height,
-				 const cairo_glyph_t		*glyphs,
+				 cairo_glyph_t			*glyphs,
 				 int				 num_glyphs);
 
     void
@@ -917,7 +917,7 @@ struct _cairo_surface_backend {
     (*show_glyphs)		(void			*surface,
 				 cairo_operator_t	 op,
 				 cairo_pattern_t	*source,
-				 const cairo_glyph_t	*glyphs,
+				 cairo_glyph_t		*glyphs,
 				 int			 num_glyphs,
 				 cairo_scaled_font_t	*scaled_font);
 
@@ -1428,7 +1428,7 @@ _cairo_gstate_text_to_glyphs (cairo_gsta
 
 cairo_private cairo_status_t
 _cairo_gstate_glyph_extents (cairo_gstate_t *gstate,
-			     cairo_glyph_t *glyphs,
+			     const cairo_glyph_t *glyphs,
 			     int num_glyphs,
 			     cairo_text_extents_t *extents);
 
@@ -1438,10 +1438,10 @@ _cairo_gstate_show_glyphs (cairo_gstate_
 			   int num_glyphs);
 
 cairo_private cairo_status_t
-_cairo_gstate_glyph_path (cairo_gstate_t     *gstate,
-			  cairo_glyph_t	     *glyphs,
-			  int		      num_glyphs,
-			  cairo_path_fixed_t *path);
+_cairo_gstate_glyph_path (cairo_gstate_t      *gstate,
+			  const cairo_glyph_t *glyphs,
+			  int		       num_glyphs,
+			  cairo_path_fixed_t  *path);
 
 cairo_private cairo_bool_t
 _cairo_operator_bounded_by_mask (cairo_operator_t op);
@@ -1685,12 +1685,6 @@ _cairo_scaled_font_text_to_glyphs (cairo
 				   int 		        *num_glyphs);
 
 cairo_private cairo_status_t
-_cairo_scaled_font_glyph_extents (cairo_scaled_font_t	*scaled_font,
-				  cairo_glyph_t 	*glyphs,
-				  int 			num_glyphs,
-				  cairo_text_extents_t *extents);
-
-cairo_private cairo_status_t
 _cairo_scaled_font_glyph_device_extents (cairo_scaled_font_t	 *scaled_font,
 					 const cairo_glyph_t	 *glyphs,
 					 int                      num_glyphs,
@@ -1707,7 +1701,7 @@ _cairo_scaled_font_show_glyphs (cairo_sc
 				int		     dest_y,
 				unsigned int	     width,
 				unsigned int	     height,
-				const cairo_glyph_t *glyphs,
+				cairo_glyph_t	    *glyphs,
 				int		     num_glyphs);
 
 cairo_private cairo_status_t
@@ -1858,7 +1852,7 @@ cairo_private cairo_status_t
 _cairo_surface_show_glyphs (cairo_surface_t	*surface,
 			    cairo_operator_t	 op,
 			    cairo_pattern_t	*source,
-			    const cairo_glyph_t	*glyphs,
+			    cairo_glyph_t	*glyphs,
 			    int			 num_glyphs,
 			    cairo_scaled_font_t	*scaled_font);
 
@@ -1957,7 +1951,7 @@ _cairo_surface_old_show_glyphs (cairo_sc
 				int			 dest_y,
 				unsigned int		 width,
 				unsigned int		 height,
-				const cairo_glyph_t	*glyphs,
+				cairo_glyph_t		*glyphs,
 				int			 num_glyphs);
 
 cairo_private cairo_status_t
diff --git a/src/test-meta-surface.c b/src/test-meta-surface.c
index d50119f..7939b6e 100644
--- a/src/test-meta-surface.c
+++ b/src/test-meta-surface.c
@@ -247,7 +247,7 @@ static cairo_int_status_t
 _test_meta_surface_show_glyphs (void			*abstract_surface,
 				cairo_operator_t	 op,
 				cairo_pattern_t		*source,
-				const cairo_glyph_t	*glyphs,
+				cairo_glyph_t		*glyphs,
 				int			 num_glyphs,
 				cairo_scaled_font_t	*scaled_font)
 {
diff --git a/src/test-paginated-surface.c b/src/test-paginated-surface.c
index 4548df5..544efcf 100644
--- a/src/test-paginated-surface.c
+++ b/src/test-paginated-surface.c
@@ -228,7 +228,7 @@ static cairo_int_status_t
 _test_paginated_surface_show_glyphs (void			*abstract_surface,
 				     cairo_operator_t		 op,
 				     cairo_pattern_t		*source,
-				     const cairo_glyph_t	*glyphs,
+				     cairo_glyph_t		*glyphs,
 				     int			 num_glyphs,
 				     cairo_scaled_font_t	*scaled_font)
 {
-- 
1.4.2.4

-------------- next part --------------
>From da60bc45f295b15c62089874fb30cedc1d70bcd2 Mon Sep 17 00:00:00 2001
From: Behdad Esfahbod <behdad at behdad.org>
Date: Mon, 11 Dec 2006 03:10:05 -0500
Subject: [PATCH] [cairoint] Define CAIRO_STACK_BUFFER_SIZE (defaults to 2kb)

This is the suggested size in bytes of buffers allocated on the stack per
function, mostly used for glyph rendering.  We typically use a local buffer on
the stack to avoid mallocing for small requests.  Requests that do not fit are
malloc()ed automatically.  The default value should be enough for about a
100-glyph cairo_show_glyphs() operation.
---
 src/cairoint.h |    7 +++++++
 1 files changed, 7 insertions(+), 0 deletions(-)

diff --git a/src/cairoint.h b/src/cairoint.h
index b481d45..c894372 100755
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -208,6 +208,13 @@ #ifndef M_PI
 #define M_PI 3.14159265358979323846
 #endif
 
+/* Size in bytes of buffer to use off the stack per functions.
+ * Mostly used by text functions.  For larger allocations, they'll
+ * malloc(). */
+#ifndef CAIRO_STACK_BUFFER_SIZE
+#define CAIRO_STACK_BUFFER_SIZE (512 * sizeof (int))
+#endif
+
 #define ASSERT_NOT_REACHED		\
 do {					\
     static const int NOT_REACHED = 0;	\
-- 
1.4.2.4

-------------- next part --------------
>From cace58c9ddd1e2d0e0fc3e528df7a77519f4515b Mon Sep 17 00:00:00 2001
From: Behdad Esfahbod <behdad at behdad.org>
Date: Mon, 11 Dec 2006 03:13:34 -0500
Subject: [PATCH] [cairo-gstate] Use a local buffer on the stack for small glyph operations

We duplicate the incoming glyph array for two reasons: 1) applying
transformations, and 2) to let the lower level functions have a glyph array
they can modify.  By using a 2kb array on the stack we can avoid malloc() for
requests of less than 100 glyphs.  The size of the array can be tuned by
setting CAIRO_STACK_BUFFER_SIZE.
---
 src/cairo-gstate.c |   30 +++++++++++++++++++++++-------
 1 files changed, 23 insertions(+), 7 deletions(-)

diff --git a/src/cairo-gstate.c b/src/cairo-gstate.c
index ab32545..dbe0e77 100644
--- a/src/cairo-gstate.c
+++ b/src/cairo-gstate.c
@@ -1464,6 +1464,7 @@ _cairo_gstate_glyph_extents (cairo_gstat
     return CAIRO_STATUS_SUCCESS;
 }
 
+#define STACK_GLYPHS_LEN ((int) (CAIRO_STACK_BUFFER_SIZE / sizeof (cairo_glyph_t)))
 cairo_status_t
 _cairo_gstate_show_glyphs (cairo_gstate_t *gstate,
 			   const cairo_glyph_t *glyphs,
@@ -1472,6 +1473,8 @@ _cairo_gstate_show_glyphs (cairo_gstate_
     cairo_status_t status;
     cairo_pattern_union_t source_pattern;
     cairo_glyph_t *transformed_glyphs;
+    cairo_glyph_t stack_transfored_glyphs[STACK_GLYPHS_LEN];
+
 
     if (gstate->source->status)
 	return gstate->source->status;
@@ -1484,9 +1487,13 @@ _cairo_gstate_show_glyphs (cairo_gstate_
     if (status)
 	return status;
 
-    transformed_glyphs = malloc (num_glyphs * sizeof(cairo_glyph_t));
-    if (transformed_glyphs == NULL)
-	return CAIRO_STATUS_NO_MEMORY;
+    if (num_glyphs <= STACK_GLYPHS_LEN) {
+	transformed_glyphs = stack_transfored_glyphs;
+    } else {
+	transformed_glyphs = malloc (num_glyphs * sizeof(cairo_glyph_t));
+	if (transformed_glyphs == NULL)
+	    return CAIRO_STATUS_NO_MEMORY;
+    }
 
     _cairo_gstate_transform_glyphs_to_backend (gstate, glyphs, num_glyphs,
                                                transformed_glyphs);
@@ -1501,7 +1508,9 @@ _cairo_gstate_show_glyphs (cairo_gstate_
 					 gstate->scaled_font);
 
     _cairo_pattern_fini (&source_pattern.base);
-    free (transformed_glyphs);
+
+    if (transformed_glyphs != stack_transfored_glyphs)
+      free (transformed_glyphs);
 
     return status;
 }
@@ -1513,13 +1522,17 @@ _cairo_gstate_glyph_path (cairo_gstate_t
 			  cairo_path_fixed_t  *path)
 {
     cairo_status_t status;
-    cairo_glyph_t *transformed_glyphs = NULL;
+    cairo_glyph_t *transformed_glyphs;
+    cairo_glyph_t stack_transfored_glyphs[STACK_GLYPHS_LEN];
 
     status = _cairo_gstate_ensure_scaled_font (gstate);
     if (status)
 	return status;
 
-    transformed_glyphs = malloc (num_glyphs * sizeof(cairo_glyph_t));
+    if (num_glyphs < STACK_GLYPHS_LEN)
+      transformed_glyphs = stack_transfored_glyphs;
+    else
+      transformed_glyphs = malloc (num_glyphs * sizeof(cairo_glyph_t));
     if (transformed_glyphs == NULL)
 	return CAIRO_STATUS_NO_MEMORY;
 
@@ -1530,9 +1543,12 @@ _cairo_gstate_glyph_path (cairo_gstate_t
 					    transformed_glyphs, num_glyphs,
 					    path);
 
-    free (transformed_glyphs);
+    if (transformed_glyphs != stack_transfored_glyphs)
+      free (transformed_glyphs);
+
     return status;
 }
+#undef STACK_GLYPHS_LEN
 
 cairo_status_t
 _cairo_gstate_set_antialias (cairo_gstate_t *gstate,
-- 
1.4.2.4

-------------- next part --------------
>From c5a606795e13fcb5889c7f710cc1afcf5f8ebc82 Mon Sep 17 00:00:00 2001
From: Behdad Esfahbod <behdad at behdad.org>
Date: Mon, 11 Dec 2006 03:16:50 -0500
Subject: [PATCH] Cache rounded glyph advance values

This is done in cairo_scaled_glyph_t->x/y_advance.  The value is mostly useful
for raster backends, for example to set as default advance of a glyph, and
later on optimize glyph positionings that use the default advance.
---
 src/cairo-scaled-font.c |   10 ++++++++++
 src/cairoint.h          |    2 ++
 2 files changed, 12 insertions(+), 0 deletions(-)

diff --git a/src/cairo-scaled-font.c b/src/cairo-scaled-font.c
index b800cf9..316c603 100755
--- a/src/cairo-scaled-font.c
+++ b/src/cairo-scaled-font.c
@@ -1211,6 +1211,7 @@ _cairo_scaled_glyph_set_metrics (cairo_s
     double hm, wm;
     double min_user_x = 0.0, max_user_x = 0.0, min_user_y = 0.0, max_user_y = 0.0;
     double min_device_x = 0.0, max_device_x = 0.0, min_device_y = 0.0, max_device_y = 0.0;
+    double device_x_advance, device_y_advance;
 
     for (hm = 0.0; hm <= 1.0; hm += 1.0)
 	for (wm = 0.0; wm <= 1.0; wm += 1.0) {
@@ -1259,10 +1260,19 @@ _cairo_scaled_glyph_set_metrics (cairo_s
 				     &scaled_glyph->metrics.x_advance,
 				     &scaled_glyph->metrics.y_advance);
 
+    device_x_advance = fs_metrics->x_advance;
+    device_y_advance = fs_metrics->y_advance;
+    cairo_matrix_transform_distance (&scaled_font->scale,
+				     &device_x_advance,
+				     &device_y_advance);
+
     scaled_glyph->bbox.p1.x = _cairo_fixed_from_double (min_device_x);
     scaled_glyph->bbox.p1.y = _cairo_fixed_from_double (min_device_y);
     scaled_glyph->bbox.p2.x = _cairo_fixed_from_double (max_device_x);
     scaled_glyph->bbox.p2.y = _cairo_fixed_from_double (max_device_y);
+
+    scaled_glyph->x_advance = _cairo_lround (device_x_advance);
+    scaled_glyph->y_advance = _cairo_lround (device_y_advance);
 }
 
 void
diff --git a/src/cairoint.h b/src/cairoint.h
index c894372..f855a41 100755
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -511,6 +511,8 @@ typedef struct _cairo_scaled_glyph {
     cairo_scaled_font_t	    *scaled_font;	/* font the glyph lives in */
     cairo_text_extents_t    metrics;		/* user-space metrics */
     cairo_box_t		    bbox;		/* device-space bounds */
+    int16_t                 x_advance;		/* device-space rounded X advance */
+    int16_t                 y_advance;		/* device-space rounded Y advance */
     cairo_image_surface_t   *surface;		/* device-space image */
     cairo_path_fixed_t	    *path;		/* device-space outline */
     void		    *surface_private;	/* for the surface backend */
-- 
1.4.2.4

-------------- next part --------------
>From d338ee97d697aade399e2b0cd6cf067011a7516e Mon Sep 17 00:00:00 2001
From: Behdad Esfahbod <behdad at behdad.org>
Date: Mon, 11 Dec 2006 03:31:10 -0500
Subject: [PATCH] [Xlib] Rewrite an optimized cairo_xlib_show_glyphs()

The old implementation was a very naive one that used to generate one XRender
glyph element per glyph.  That is, position glyphs individually.  This was
raised here:

  http://lists.freedesktop.org/archives/cairo/2006-December/008835.html

The new implmentation is a free rewriting of the Xft logic, that is,
compressing glyphs with "natural" advance into elements, but with various
optimizations and improvements.

In short, it works like this: glyphs are looped over, skipping those that are
not desired, and computing offset from "current position".  Whenever a glyph
has non-zero offsets from the current position, a new element should be
started.  All these are used to compute the request size in the render
protocol.  Whenever the request size may exceed the max request size, or at
the end, glyphs are flushed.  For this to work, we now set non-zero glyph
advances when sending glyphs to the server.

Notable optimizations and improvements include:

  - Reusing the input glyph array (with double glyph positions) as a working
    array to compute glyph offsets.

  - Reusing the input glyph array as the output glyph-index array to be passed
    to XRender.

  - Marking glyphs to be skipped as so, avoiding a copy of the glyph array,
    which is what the old code was doing.

  - Skip glyphs with positions "out-of-range".  That is, those with negative
    or greater than 16-bit positions.  Previously these were send over the
    wire, causing overflows in the server and as a result, mispositioned
    glyphs.

On my Fedora desktop on Pentium 4, it shows a 6% speedup on timetext test.
---
 src/cairo-xlib-surface.c |  462 ++++++++++++++++++++++++----------------------
 1 files changed, 242 insertions(+), 220 deletions(-)

diff --git a/src/cairo-xlib-surface.c b/src/cairo-xlib-surface.c
index 5482a2f..3554bb7 100644
--- a/src/cairo-xlib-surface.c
+++ b/src/cairo-xlib-surface.c
@@ -33,6 +33,7 @@
  *
  * Contributor(s):
  *	Carl D. Worth <cworth at cworth.org>
+ *	Behdad Esfahbod <behdad at behdad.org>
  */
 
 #include "cairoint.h"
@@ -2412,8 +2413,8 @@ _cairo_xlib_surface_add_glyph (Display *
     glyph_info.y = - _cairo_lround (glyph_surface->base.device_transform.y0);
     glyph_info.width = glyph_surface->width;
     glyph_info.height = glyph_surface->height;
-    glyph_info.xOff = 0;
-    glyph_info.yOff = 0;
+    glyph_info.xOff = scaled_glyph->x_advance;
+    glyph_info.yOff = scaled_glyph->y_advance;
 
     data = glyph_surface->data;
 
@@ -2496,194 +2497,280 @@ _cairo_xlib_surface_add_glyph (Display *
     return status;
 }
 
-#define N_STACK_BUF 1024
+typedef void (*cairo_xrender_composite_text_func_t)
+	      (Display                      *dpy,
+	       int                          op,
+	       Picture                      src,
+	       Picture                      dst,
+	       _Xconst XRenderPictFormat    *maskFormat,
+	       int                          xSrc,
+	       int                          ySrc,
+	       int                          xDst,
+	       int                          yDst,
+	       _Xconst XGlyphElt8           *elts,
+	       int                          nelt);
+
+/* Build a struct of the same size of cairo_glyph_t that can be used both as
+ * an input glyph with double coordinates, and as "working" glyph with
+ * integer from-current-point offsets. */
+typedef struct {
+  unsigned long index;
+  union {
+    struct {
+      double x;
+      double y;
+    } d;
+    struct {
+      int x;
+      int y;
+    } i;
+  } p;
+} cairo_xlib_glyph_t;
+
+#define STACK_ELTS_LEN ((int) (CAIRO_STACK_BUFFER_SIZE / sizeof (XGlyphElt8)))
 
 static cairo_status_t
-_cairo_xlib_surface_show_glyphs8  (cairo_xlib_surface_t *dst,
-                                   cairo_operator_t op,
-                                   cairo_xlib_surface_t *src,
-                                   int src_x_offset, int src_y_offset,
-                                   const cairo_glyph_t *glyphs,
-                                   int num_glyphs,
-                                   cairo_scaled_font_t *scaled_font)
+_cairo_xlib_surface_emit_glyphs_chunk (cairo_xlib_surface_t *dst,
+				       cairo_xlib_glyph_t *glyphs,
+				       int num_glyphs,
+				       int width,
+				       int num_elts,
+				       int num_out_glyphs,
+				       cairo_scaled_font_t *scaled_font,
+				       cairo_operator_t op,
+				       cairo_xlib_surface_t *src,
+				       cairo_surface_attributes_t *attributes)
 {
-    cairo_xlib_surface_font_private_t *font_private = scaled_font->surface_private;
-    XGlyphElt8 *elts = NULL;
-    XGlyphElt8 stack_elts [N_STACK_BUF];
+    /* Which XRenderCompositeText function to use */
+    cairo_xrender_composite_text_func_t composite_text_func;
+    int size;
 
-    char *chars = NULL;
-    char stack_chars [N_STACK_BUF];
+    /* Element buffer stuff */
+    XGlyphElt8 *elts;
+    XGlyphElt8 stack_elts[STACK_ELTS_LEN];
 
-    int i;
-    int thisX, thisY;
-    int lastX = 0, lastY = 0;
+    /* Reuse the input glyph array for output char generate */
+    char *char8 = (char *) glyphs;
+    unsigned short *char16 = (unsigned short *) glyphs;
+    unsigned int *char32 = (unsigned int *) glyphs;
 
-    /* Acquire arrays of suitable sizes. */
-    if (num_glyphs < N_STACK_BUF) {
-	elts = stack_elts;
-	chars = stack_chars;
-    } else {
-	elts = malloc (num_glyphs * sizeof (XGlyphElt8) +
-		       num_glyphs * sizeof (unsigned char));
-	if (elts == NULL)
-	    return CAIRO_STATUS_NO_MEMORY;
+    int i;
+    int nelt; /* Element index */
+    int n; /* Num output glyphs in current element */
+    int j; /* Num output glyphs so far */
 
-	chars = (char *) (elts + num_glyphs);
-    }
+    cairo_xlib_surface_font_private_t *font_private = scaled_font->surface_private;
 
-    for (i = 0; i < num_glyphs; ++i) {
-	chars[i] = glyphs[i].index;
-	elts[i].chars = &(chars[i]);
-	elts[i].nchars = 1;
-	elts[i].glyphset = font_private->glyphset;
-	thisX = _cairo_lround (glyphs[i].x);
-	thisY = _cairo_lround (glyphs[i].y);
-	elts[i].xOff = thisX - lastX;
-	elts[i].yOff = thisY - lastY;
-	lastX = thisX;
-	lastY = thisY;
+    switch (width) {
+    case 1:
+	/* don't cast the 8-variant, to catch possible mismatches */
+	composite_text_func =                                       XRenderCompositeText8;
+	size = sizeof (char);
+	break;
+    case 2:
+	composite_text_func = (cairo_xrender_composite_text_func_t) XRenderCompositeText16;
+	size = sizeof (unsigned short);
+	break;
+    default:
+    case 4:
+	composite_text_func = (cairo_xrender_composite_text_func_t) XRenderCompositeText32;
+	size = sizeof (unsigned int);
     }
 
-    XRenderCompositeText8  (dst->dpy,
-			    _render_operator (op),
-			    src->src_picture,
-			    dst->dst_picture,
-			    font_private->xrender_format,
-                            src_x_offset + elts[0].xOff, src_y_offset + elts[0].yOff,
-                            elts[0].xOff, elts[0].yOff,
-			    elts, num_glyphs);
+    /* Allocate element array */
+    if (num_elts <= STACK_ELTS_LEN) {
+      elts = stack_elts;
+    } else {
+      elts = malloc (num_elts * sizeof (XGlyphElt8));
+      if (elts == NULL)
+	  return CAIRO_STATUS_NO_MEMORY;
+    }
+
+    /* Fill them in */
+    nelt = 0;
+    n = 0;
+    j = 0;
+    for (i = 0; i < num_glyphs; i++) {
+
+      /* Skip glyphs marked so */
+      if (glyphs[i].index == (unsigned long) -1)
+	continue;
+
+      /* Start a new element for first output glyph, and for glyphs with
+       * unexpected position */
+      if (!j || glyphs[i].p.i.x || glyphs[i].p.i.y) {
+	  if (j) {
+	    elts[nelt].nchars = n;
+	    nelt++;
+	    n = 0;
+	  }
+	  elts[nelt].chars = char8 + size * j;
+	  elts[nelt].glyphset = font_private->glyphset;
+	  elts[nelt].xOff = glyphs[i].p.i.x;
+	  elts[nelt].yOff = glyphs[i].p.i.y;
+      }
+
+      switch (width) {
+      case 1: char8 [j] = (char)           glyphs[i].index; break;
+      case 2: char16[j] = (unsigned short) glyphs[i].index; break;
+      default:
+      case 4: char32[j] = (unsigned int)   glyphs[i].index; break;
+      }
+
+      n++;
+      j++;
+    }
+
+    if (n) {
+	elts[nelt].nchars = n;
+	nelt++;
+	n = 0;
+    }
+
+    composite_text_func (dst->dpy,
+			 _render_operator (op),
+			 src->src_picture,
+			 dst->dst_picture,
+			 font_private->xrender_format,
+			 attributes->x_offset + elts[0].xOff,
+			 attributes->y_offset + elts[0].yOff,
+			 elts[0].xOff, elts[0].yOff,
+			 (XGlyphElt8 *) elts, nelt);
 
     if (elts != stack_elts)
-	free (elts);
+      free (elts);
 
     return CAIRO_STATUS_SUCCESS;
 }
 
+#undef STACK_ELTS_LEN
+
 static cairo_status_t
-_cairo_xlib_surface_show_glyphs16 (cairo_xlib_surface_t *dst,
-                                   cairo_operator_t op,
-                                   cairo_xlib_surface_t *src,
-                                   int src_x_offset, int src_y_offset,
-                                   const cairo_glyph_t *glyphs,
-                                   int num_glyphs,
-                                   cairo_scaled_font_t *scaled_font)
+_cairo_xlib_surface_emit_glyphs (cairo_xlib_surface_t *dst,
+				 cairo_xlib_glyph_t *glyphs,
+				 int num_glyphs,
+				 cairo_scaled_font_t *scaled_font,
+				 cairo_operator_t op,
+				 cairo_xlib_surface_t *src,
+				 cairo_surface_attributes_t *attributes)
 {
-    cairo_xlib_surface_font_private_t *font_private = scaled_font->surface_private;
-    XGlyphElt16 *elts = NULL;
-    XGlyphElt16 stack_elts [N_STACK_BUF];
+    int i;
+    cairo_status_t status = CAIRO_STATUS_SUCCESS;
+    cairo_scaled_glyph_t *scaled_glyph;
+    cairo_fixed_t x = 0, y = 0;
 
-    unsigned short *chars = NULL;
-    unsigned short stack_chars [N_STACK_BUF];
+    unsigned long max_index = 0;
+    int width = 1;
+    int num_elts = 0;
+    int num_out_glyphs = 0;
 
-    int i;
-    int thisX, thisY;
-    int lastX = 0, lastY = 0;
+    int max_request_size = XMaxRequestSize (dst->dpy)
+			 - MAX (sz_xRenderCompositeGlyphs8Req,
+				MAX(sz_xRenderCompositeGlyphs16Req,
+				    sz_xRenderCompositeGlyphs32Req));
+    int request_size = 0;
 
-    /* Acquire arrays of suitable sizes. */
-    if (num_glyphs < N_STACK_BUF) {
-	elts = stack_elts;
-	chars = stack_chars;
-    } else {
-	elts = malloc (num_glyphs * sizeof (XGlyphElt16) +
-		       num_glyphs * sizeof (unsigned short));
-	if (elts == NULL)
-	    return CAIRO_STATUS_NO_MEMORY;
+    _cairo_xlib_surface_ensure_dst_picture (dst);
 
-	chars = (unsigned short *) (elts + num_glyphs);
-    }
+    for (i = 0; i < num_glyphs; i++) {
+	unsigned int this_x, this_y;
+	int old_width;
 
-    for (i = 0; i < num_glyphs; ++i) {
-	chars[i] = glyphs[i].index;
-	elts[i].chars = &(chars[i]);
-	elts[i].nchars = 1;
-	elts[i].glyphset = font_private->glyphset;
-	thisX = _cairo_lround (glyphs[i].x);
-	thisY = _cairo_lround (glyphs[i].y);
-	elts[i].xOff = thisX - lastX;
-	elts[i].yOff = thisY - lastY;
-	lastX = thisX;
-	lastY = thisY;
-    }
+	status = _cairo_scaled_glyph_lookup (scaled_font,
+					     glyphs[i].index,
+					     CAIRO_SCALED_GLYPH_INFO_SURFACE |
+					     CAIRO_SCALED_GLYPH_INFO_METRICS,
+					     &scaled_glyph);
+	if (status != CAIRO_STATUS_SUCCESS)
+	    return status;
 
-    XRenderCompositeText16 (dst->dpy,
-			    _render_operator (op),
-			    src->src_picture,
-			    dst->dst_picture,
-			    font_private->xrender_format,
-                            src_x_offset + elts[0].xOff, src_y_offset + elts[0].yOff,
-                            elts[0].xOff, elts[0].yOff,
-			    elts, num_glyphs);
+	this_x = _cairo_lround (glyphs[i].p.d.x);
+	this_y = _cairo_lround (glyphs[i].p.d.y);
 
-    if (elts != stack_elts)
-	free (elts);
+	/* We skip any initial size-zero glyphs to avoid an X server bug (present in at
+	 * least Xorg 7.1 without EXA) which stops rendering glyphs after the first
+	 * zero-size glyph. XXX Is this enough?
+	 *
+	 * We also skip any glyph that has a coordinate greater than 16-bit.
+	 * Those will overflow in the X server. XXX Correct?
+	 * This also catches negative positions, since this_x and this_y are
+	 * unsigned.
+	 */
+	if ((!num_out_glyphs && !(scaled_glyph->surface->width && scaled_glyph->surface->height)) ||
+	    (this_x >= 65536 || this_y >= 65536)) {
+	    glyphs[i].index = (unsigned long) -1;
+	    continue;
+	}
 
-    return CAIRO_STATUS_SUCCESS;
-}
+	old_width = width;
 
-static cairo_status_t
-_cairo_xlib_surface_show_glyphs32 (cairo_xlib_surface_t *dst,
-                                   cairo_operator_t op,
-                                   cairo_xlib_surface_t *src,
-                                   int src_x_offset, int src_y_offset,
-                                   const cairo_glyph_t *glyphs,
-                                   int num_glyphs,
-                                   cairo_scaled_font_t *scaled_font)
-{
-    cairo_xlib_surface_font_private_t *font_private = scaled_font->surface_private;
-    XGlyphElt32 *elts = NULL;
-    XGlyphElt32 stack_elts [N_STACK_BUF];
+	/* Update max glyph index */
+	if (glyphs[i].index > max_index) {
+	    max_index = glyphs[i].index;
+	    if (max_index >= 65536)
+	      width = 4;
+	    else if (max_index >= 256)
+	      width = 2;
+	    if (width != old_width)
+	      request_size += (width - old_width) * num_out_glyphs;
+	}
 
-    unsigned int *chars = NULL;
-    unsigned int stack_chars [N_STACK_BUF];
+	/* If we will pass the max request size by adding this glyph,
+	 * flush current glyphs.  Note that we account for a
+	 * possible element being added below. */
+	if (request_size + width > max_request_size - sz_xGlyphElt) {
+	    status = _cairo_xlib_surface_emit_glyphs_chunk (dst, glyphs, i,
+							    old_width, num_elts, num_out_glyphs,
+							    scaled_font, op, src, attributes);
+	    if (status != CAIRO_STATUS_SUCCESS)
+		return status;
+
+	    glyphs += i;
+	    num_glyphs -= i;
+	    i = 0;
+	    max_index = glyphs[i].index;
+	    width = max_index < 256 ? 1 : max_index < 65536 ? 2 : 4;
+	    request_size = 0;
+	    num_elts = 0;
+	    num_out_glyphs = 0;
+	    x = y = 0;
 
-    int i;
-    int thisX, thisY;
-    int lastX = 0, lastY = 0;
+	}
 
-    /* Acquire arrays of suitable sizes. */
-    if (num_glyphs < N_STACK_BUF) {
-	elts = stack_elts;
-	chars = stack_chars;
-    } else {
-	elts = malloc (num_glyphs * sizeof (XGlyphElt32) +
-		       num_glyphs * sizeof (unsigned int));
-	if (elts == NULL)
-	    return CAIRO_STATUS_NO_MEMORY;
+	/* Convert absolute glyph position to relative-to-current-point
+	 * position */
+	glyphs[i].p.i.x = this_x - x;
+	glyphs[i].p.i.y = this_y - y;
 
-	chars = (unsigned int *) (elts + num_glyphs);
-    }
+	/* Start a new element for the first glyph, or for any glyph that
+	 * has unexpected position */
+	if (!num_out_glyphs || glyphs[i].p.i.x || glyphs[i].p.i.y) {
+	    num_elts++;
+	    request_size += sz_xGlyphElt;
+	}
 
-    for (i = 0; i < num_glyphs; ++i) {
-	chars[i] = glyphs[i].index;
-	elts[i].chars = &(chars[i]);
-	elts[i].nchars = 1;
-	elts[i].glyphset = font_private->glyphset;
-	thisX = _cairo_lround (glyphs[i].x);
-	thisY = _cairo_lround (glyphs[i].y);
-	elts[i].xOff = thisX - lastX;
-	elts[i].yOff = thisY - lastY;
-	lastX = thisX;
-	lastY = thisY;
-    }
+	/* Send unsent glyphs to the server */
+	if (scaled_glyph->surface_private == NULL) {
+	    _cairo_xlib_surface_add_glyph (dst->dpy, scaled_font, scaled_glyph);
+	    scaled_glyph->surface_private = (void *) 1;
+	}
 
-    XRenderCompositeText32 (dst->dpy,
-			    _render_operator (op),
-			    src->src_picture,
-			    dst->dst_picture,
-			    font_private->xrender_format,
-                            src_x_offset + elts[0].xOff, src_y_offset + elts[0].yOff,
-                            elts[0].xOff, elts[0].yOff,
-			    elts, num_glyphs);
+	/* adjust current-position */
+	x = this_x + scaled_glyph->x_advance;
+	y = this_y + scaled_glyph->y_advance;
 
-    if (elts != stack_elts)
-	free (elts);
+	num_out_glyphs++;
+	request_size += width;
+    }
 
-    return CAIRO_STATUS_SUCCESS;
+    if (num_elts)
+	status = _cairo_xlib_surface_emit_glyphs_chunk (dst, glyphs, num_glyphs,
+							width, num_elts, num_out_glyphs,
+							scaled_font, op, src, attributes);
+
+    return status;
 }
 
-typedef cairo_status_t (*cairo_xlib_surface_show_glyphs_func_t)
-    (cairo_xlib_surface_t *, cairo_operator_t, cairo_xlib_surface_t *, int, int,
-     const cairo_glyph_t *, int, cairo_scaled_font_t *);
 
 static cairo_int_status_t
 _cairo_xlib_surface_show_glyphs (void                *abstract_dst,
@@ -2700,17 +2787,8 @@ _cairo_xlib_surface_show_glyphs (void   
     cairo_surface_attributes_t attributes;
     cairo_xlib_surface_t *src = NULL;
 
-    cairo_glyph_t *output_glyphs;
-    const cairo_glyph_t *glyphs_chunk;
-    int glyphs_remaining, chunk_size, max_chunk_size;
-    cairo_scaled_glyph_t *scaled_glyph;
     cairo_xlib_surface_font_private_t *font_private;
 
-    int i, o;
-    unsigned long max_index = 0;
-
-    cairo_xlib_surface_show_glyphs_func_t show_glyphs_func;
-
     cairo_pattern_union_t solid_pattern;
 
     if (!CAIRO_SURFACE_RENDER_HAS_COMPOSITE_TEXT (dst) || !dst->xrender_format)
@@ -2750,13 +2828,6 @@ _cairo_xlib_surface_show_glyphs (void   
 	(font_private != NULL && font_private->dpy != dst->dpy))
 	return CAIRO_INT_STATUS_UNSUPPORTED;
 
-    /* We make a copy of the glyphs so that we can elide any size-zero
-     * glyphs to workaround an X server bug, (present in at least Xorg
-     * 7.1 without EXA). */
-    output_glyphs = malloc (num_glyphs * sizeof (cairo_glyph_t));
-    if (output_glyphs == NULL)
-	return CAIRO_STATUS_NO_MEMORY;
-
     /* After passing all those tests, we're now committed to rendering
      * these glyphs or to fail trying. We first upload any glyphs to
      * the X server that it doesn't have already, then we draw
@@ -2814,60 +2885,11 @@ _cairo_xlib_surface_show_glyphs (void   
     if (status)
         goto BAIL;
 
-    /* Send all unsent glyphs to the server, and count the max of the glyph indices */
-    for (i = 0, o = 0; i < num_glyphs; i++) {
-	if (glyphs[i].index > max_index)
-	    max_index = glyphs[i].index;
-	status = _cairo_scaled_glyph_lookup (scaled_font,
-					     glyphs[i].index,
-					     CAIRO_SCALED_GLYPH_INFO_SURFACE,
-					     &scaled_glyph);
-	if (status != CAIRO_STATUS_SUCCESS)
-	    goto BAIL;
-	/* Don't put any size-zero glyphs into output_glyphs to avoid
-	 * an X server bug which stops rendering glyphs after the
-	 * first size-zero glyph. */
-	if (scaled_glyph->surface->width && scaled_glyph->surface->height) {
-	    output_glyphs[o++] = glyphs[i];
-	    if (scaled_glyph->surface_private == NULL) {
-		_cairo_xlib_surface_add_glyph (dst->dpy, scaled_font, scaled_glyph);
-		scaled_glyph->surface_private = (void *) 1;
-	    }
-	}
-    }
-    num_glyphs = o;
-
-    _cairo_xlib_surface_ensure_dst_picture (dst);
-
-    max_chunk_size = XMaxRequestSize (dst->dpy);
-    if (max_index < 256) {
-	max_chunk_size -= sz_xRenderCompositeGlyphs8Req;
-	show_glyphs_func = _cairo_xlib_surface_show_glyphs8;
-    } else if (max_index < 65536) {
-	max_chunk_size -= sz_xRenderCompositeGlyphs16Req;
-	show_glyphs_func = _cairo_xlib_surface_show_glyphs16;
-    } else {
-	max_chunk_size -= sz_xRenderCompositeGlyphs32Req;
-	show_glyphs_func = _cairo_xlib_surface_show_glyphs32;
-    }
-    max_chunk_size /= sz_xGlyphElt;
-
-    for (glyphs_remaining = num_glyphs, glyphs_chunk = output_glyphs;
-	 glyphs_remaining;
-	 glyphs_remaining -= chunk_size, glyphs_chunk += chunk_size)
-    {
-	chunk_size = MIN (glyphs_remaining, max_chunk_size);
-
-	status = show_glyphs_func (dst, op, src,
-                                   attributes.x_offset, attributes.y_offset,
-                                   glyphs_chunk, chunk_size, scaled_font);
-	if (status != CAIRO_STATUS_SUCCESS)
-	    break;
-    }
+    _cairo_xlib_surface_emit_glyphs (dst, (cairo_xlib_glyph_t *) glyphs, num_glyphs,
+				     scaled_font, op, src, &attributes);
 
   BAIL:
     _cairo_scaled_font_thaw_cache (scaled_font);
-    free (output_glyphs);
 
     if (src)
         _cairo_pattern_release_surface (src_pattern, &src->base, &attributes);
-- 
1.4.2.4



More information about the cairo mailing list