[cairo-commit] 4 commits - src/cairo-clip.c src/cairo-gstate.c src/cairo-gstate-private.h src/cairoint.h src/cairo-scaled-font.c test/half-coverage.c test/Makefile.am test/Makefile.sources test/partial-coverage.c test/partial-coverage-rectangles.ref.png test/partial-coverage-reference.ref.png test/partial-coverage-triangles.ref.png

Chris Wilson ickle at kemper.freedesktop.org
Thu Jun 10 05:15:35 PDT 2010


 src/cairo-clip.c                         |    1 
 src/cairo-gstate-private.h               |  310 +++++++++++++++++++++++++++++++
 src/cairo-gstate.c                       |   18 +
 src/cairo-scaled-font.c                  |  168 +++++++++++-----
 src/cairoint.h                           |  295 -----------------------------
 test/Makefile.am                         |    3 
 test/Makefile.sources                    |    1 
 test/half-coverage.c                     |   28 ++
 test/partial-coverage-rectangles.ref.png |binary
 test/partial-coverage-reference.ref.png  |binary
 test/partial-coverage-triangles.ref.png  |binary
 test/partial-coverage.c                  |  213 +++++++++++++++++++++
 12 files changed, 685 insertions(+), 352 deletions(-)

New commits:
commit 8d67186cb291cb877e52b987e2ac18c2a1175a57
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Thu Jun 10 11:36:58 2010 +0100

    gstate: Track whether the combination of ctm * device is identity.
    
    In the fairly common condition that both the ctm and the device
    transforms are identity, the function overhead of calling the matrix
    multiplication on the point overwhelmingly dominates.

diff --git a/src/cairo-clip.c b/src/cairo-clip.c
index 72eecfe..0c6cb74 100644
--- a/src/cairo-clip.c
+++ b/src/cairo-clip.c
@@ -43,6 +43,7 @@
 #include "cairo-clip-private.h"
 #include "cairo-error-private.h"
 #include "cairo-freed-pool-private.h"
+#include "cairo-gstate-private.h"
 #include "cairo-path-fixed-private.h"
 #include "cairo-composite-rectangles-private.h"
 #include "cairo-region-private.h"
diff --git a/src/cairo-gstate-private.h b/src/cairo-gstate-private.h
index f204980..e706024 100644
--- a/src/cairo-gstate-private.h
+++ b/src/cairo-gstate-private.h
@@ -63,10 +63,320 @@ struct _cairo_gstate {
     cairo_matrix_t ctm;
     cairo_matrix_t ctm_inverse;
     cairo_matrix_t source_ctm_inverse; /* At the time ->source was set */
+    cairo_bool_t is_identity;
 
     cairo_pattern_t *source;
 
     struct _cairo_gstate *next;
 };
 
+/* cairo-gstate.c */
+cairo_private cairo_status_t
+_cairo_gstate_init (cairo_gstate_t  *gstate,
+		    cairo_surface_t *target);
+
+cairo_private void
+_cairo_gstate_fini (cairo_gstate_t *gstate);
+
+cairo_private cairo_status_t
+_cairo_gstate_save (cairo_gstate_t **gstate, cairo_gstate_t **freelist);
+
+cairo_private cairo_status_t
+_cairo_gstate_restore (cairo_gstate_t **gstate, cairo_gstate_t **freelist);
+
+cairo_private cairo_bool_t
+_cairo_gstate_is_redirected (cairo_gstate_t *gstate);
+
+cairo_private cairo_status_t
+_cairo_gstate_redirect_target (cairo_gstate_t *gstate, cairo_surface_t *child);
+
+cairo_private cairo_surface_t *
+_cairo_gstate_get_target (cairo_gstate_t *gstate);
+
+cairo_private cairo_surface_t *
+_cairo_gstate_get_parent_target (cairo_gstate_t *gstate);
+
+cairo_private cairo_surface_t *
+_cairo_gstate_get_original_target (cairo_gstate_t *gstate);
+
+cairo_private cairo_clip_t *
+_cairo_gstate_get_clip (cairo_gstate_t *gstate);
+
+cairo_private cairo_status_t
+_cairo_gstate_set_source (cairo_gstate_t *gstate, cairo_pattern_t *source);
+
+cairo_private cairo_pattern_t *
+_cairo_gstate_get_source (cairo_gstate_t *gstate);
+
+cairo_private cairo_status_t
+_cairo_gstate_set_operator (cairo_gstate_t *gstate, cairo_operator_t op);
+
+cairo_private cairo_operator_t
+_cairo_gstate_get_operator (cairo_gstate_t *gstate);
+
+cairo_private cairo_status_t
+_cairo_gstate_set_tolerance (cairo_gstate_t *gstate, double tolerance);
+
+cairo_private double
+_cairo_gstate_get_tolerance (cairo_gstate_t *gstate);
+
+cairo_private cairo_status_t
+_cairo_gstate_set_fill_rule (cairo_gstate_t *gstate, cairo_fill_rule_t fill_rule);
+
+cairo_private cairo_fill_rule_t
+_cairo_gstate_get_fill_rule (cairo_gstate_t *gstate);
+
+cairo_private cairo_status_t
+_cairo_gstate_set_line_width (cairo_gstate_t *gstate, double width);
+
+cairo_private double
+_cairo_gstate_get_line_width (cairo_gstate_t *gstate);
+
+cairo_private cairo_status_t
+_cairo_gstate_set_line_cap (cairo_gstate_t *gstate, cairo_line_cap_t line_cap);
+
+cairo_private cairo_line_cap_t
+_cairo_gstate_get_line_cap (cairo_gstate_t *gstate);
+
+cairo_private cairo_status_t
+_cairo_gstate_set_line_join (cairo_gstate_t *gstate, cairo_line_join_t line_join);
+
+cairo_private cairo_line_join_t
+_cairo_gstate_get_line_join (cairo_gstate_t *gstate);
+
+cairo_private cairo_status_t
+_cairo_gstate_set_dash (cairo_gstate_t *gstate, const double *dash, int num_dashes, double offset);
+
+cairo_private void
+_cairo_gstate_get_dash (cairo_gstate_t *gstate, double *dash, int *num_dashes, double *offset);
+
+cairo_private cairo_status_t
+_cairo_gstate_set_miter_limit (cairo_gstate_t *gstate, double limit);
+
+cairo_private double
+_cairo_gstate_get_miter_limit (cairo_gstate_t *gstate);
+
+cairo_private void
+_cairo_gstate_get_matrix (cairo_gstate_t *gstate, cairo_matrix_t *matrix);
+
+cairo_private cairo_status_t
+_cairo_gstate_translate (cairo_gstate_t *gstate, double tx, double ty);
+
+cairo_private cairo_status_t
+_cairo_gstate_scale (cairo_gstate_t *gstate, double sx, double sy);
+
+cairo_private cairo_status_t
+_cairo_gstate_rotate (cairo_gstate_t *gstate, double angle);
+
+cairo_private cairo_status_t
+_cairo_gstate_transform (cairo_gstate_t	      *gstate,
+			 const cairo_matrix_t *matrix);
+
+cairo_private cairo_status_t
+_cairo_gstate_set_matrix (cairo_gstate_t       *gstate,
+			  const cairo_matrix_t *matrix);
+
+cairo_private void
+_cairo_gstate_identity_matrix (cairo_gstate_t *gstate);
+
+cairo_private void
+_cairo_gstate_user_to_device (cairo_gstate_t *gstate, double *x, double *y);
+
+cairo_private void
+_cairo_gstate_user_to_device_distance (cairo_gstate_t *gstate, double *dx, double *dy);
+
+cairo_private void
+_cairo_gstate_device_to_user (cairo_gstate_t *gstate, double *x, double *y);
+
+cairo_private void
+_cairo_gstate_device_to_user_distance (cairo_gstate_t *gstate, double *dx, double *dy);
+
+cairo_private void
+_do_cairo_gstate_user_to_backend (cairo_gstate_t *gstate, double *x, double *y);
+
+static inline void
+_cairo_gstate_user_to_backend (cairo_gstate_t *gstate, double *x, double *y)
+{
+    if (! gstate->is_identity)
+	_do_cairo_gstate_user_to_backend (gstate, x, y);
+}
+
+cairo_private void
+_do_cairo_gstate_backend_to_user (cairo_gstate_t *gstate, double *x, double *y);
+
+static inline void
+_cairo_gstate_backend_to_user (cairo_gstate_t *gstate, double *x, double *y)
+{
+    if (! gstate->is_identity)
+	_do_cairo_gstate_backend_to_user (gstate, x, y);
+}
+
+cairo_private void
+_cairo_gstate_backend_to_user_rectangle (cairo_gstate_t *gstate,
+                                         double *x1, double *y1,
+                                         double *x2, double *y2,
+                                         cairo_bool_t *is_tight);
+
+cairo_private void
+_cairo_gstate_path_extents (cairo_gstate_t     *gstate,
+			    cairo_path_fixed_t *path,
+			    double *x1, double *y1,
+			    double *x2, double *y2);
+
+cairo_private cairo_status_t
+_cairo_gstate_paint (cairo_gstate_t *gstate);
+
+cairo_private cairo_status_t
+_cairo_gstate_mask (cairo_gstate_t  *gstate,
+		    cairo_pattern_t *mask);
+
+cairo_private cairo_status_t
+_cairo_gstate_stroke (cairo_gstate_t *gstate, cairo_path_fixed_t *path);
+
+cairo_private cairo_status_t
+_cairo_gstate_fill (cairo_gstate_t *gstate, cairo_path_fixed_t *path);
+
+cairo_private cairo_status_t
+_cairo_gstate_copy_page (cairo_gstate_t *gstate);
+
+cairo_private cairo_status_t
+_cairo_gstate_show_page (cairo_gstate_t *gstate);
+
+cairo_private cairo_status_t
+_cairo_gstate_stroke_extents (cairo_gstate_t	 *gstate,
+			      cairo_path_fixed_t *path,
+                              double *x1, double *y1,
+			      double *x2, double *y2);
+
+cairo_private cairo_status_t
+_cairo_gstate_fill_extents (cairo_gstate_t     *gstate,
+			    cairo_path_fixed_t *path,
+                            double *x1, double *y1,
+			    double *x2, double *y2);
+
+cairo_private cairo_status_t
+_cairo_gstate_in_stroke (cairo_gstate_t	    *gstate,
+			 cairo_path_fixed_t *path,
+			 double		     x,
+			 double		     y,
+			 cairo_bool_t	    *inside_ret);
+
+cairo_private cairo_bool_t
+_cairo_gstate_in_fill (cairo_gstate_t	  *gstate,
+		       cairo_path_fixed_t *path,
+		       double		   x,
+		       double		   y);
+
+cairo_private cairo_bool_t
+_cairo_gstate_in_clip (cairo_gstate_t	  *gstate,
+		       double		   x,
+		       double		   y);
+
+cairo_private cairo_status_t
+_cairo_gstate_clip (cairo_gstate_t *gstate, cairo_path_fixed_t *path);
+
+cairo_private cairo_status_t
+_cairo_gstate_reset_clip (cairo_gstate_t *gstate);
+
+cairo_private cairo_bool_t
+_cairo_gstate_clip_extents (cairo_gstate_t *gstate,
+		            double         *x1,
+		            double         *y1,
+			    double         *x2,
+			    double         *y2);
+
+cairo_private cairo_rectangle_list_t*
+_cairo_gstate_copy_clip_rectangle_list (cairo_gstate_t *gstate);
+
+cairo_private cairo_status_t
+_cairo_gstate_show_surface (cairo_gstate_t	*gstate,
+			    cairo_surface_t	*surface,
+			    double		 x,
+			    double		 y,
+			    double		width,
+			    double		height);
+
+cairo_private cairo_status_t
+_cairo_gstate_select_font_face (cairo_gstate_t *gstate,
+				const char *family,
+				cairo_font_slant_t slant,
+				cairo_font_weight_t weight);
+
+cairo_private cairo_status_t
+_cairo_gstate_set_font_size (cairo_gstate_t *gstate,
+			     double          size);
+
+cairo_private void
+_cairo_gstate_get_font_matrix (cairo_gstate_t *gstate,
+			       cairo_matrix_t *matrix);
+
+cairo_private cairo_status_t
+_cairo_gstate_set_font_matrix (cairo_gstate_t	    *gstate,
+			       const cairo_matrix_t *matrix);
+
+cairo_private void
+_cairo_gstate_get_font_options (cairo_gstate_t       *gstate,
+				cairo_font_options_t *options);
+
+cairo_private void
+_cairo_gstate_set_font_options (cairo_gstate_t	           *gstate,
+				const cairo_font_options_t *options);
+
+cairo_private cairo_status_t
+_cairo_gstate_get_font_face (cairo_gstate_t     *gstate,
+			     cairo_font_face_t **font_face);
+
+cairo_private cairo_status_t
+_cairo_gstate_get_scaled_font (cairo_gstate_t       *gstate,
+			       cairo_scaled_font_t **scaled_font);
+
+cairo_private cairo_status_t
+_cairo_gstate_get_font_extents (cairo_gstate_t *gstate,
+				cairo_font_extents_t *extents);
+
+cairo_private cairo_status_t
+_cairo_gstate_set_font_face (cairo_gstate_t    *gstate,
+			     cairo_font_face_t *font_face);
+
+cairo_private cairo_status_t
+_cairo_gstate_text_to_glyphs (cairo_gstate_t	         *gstate,
+			      double		          x,
+			      double		          y,
+			      const char	         *utf8,
+			      int		          utf8_len,
+			      cairo_glyph_t	        **glyphs,
+			      int		         *num_glyphs,
+			      cairo_text_cluster_t      **clusters,
+			      int		         *num_clusters,
+			      cairo_text_cluster_flags_t *cluster_flags);
+
+cairo_private cairo_status_t
+_cairo_gstate_glyph_extents (cairo_gstate_t *gstate,
+			     const cairo_glyph_t *glyphs,
+			     int num_glyphs,
+			     cairo_text_extents_t *extents);
+
+cairo_private cairo_status_t
+_cairo_gstate_show_text_glyphs (cairo_gstate_t		   *gstate,
+				const char		   *utf8,
+				int			    utf8_len,
+				const cairo_glyph_t	   *glyphs,
+				int			    num_glyphs,
+				const cairo_text_cluster_t *clusters,
+				int			    num_clusters,
+			        cairo_text_cluster_flags_t  cluster_flags);
+
+cairo_private cairo_status_t
+_cairo_gstate_glyph_path (cairo_gstate_t      *gstate,
+			  const cairo_glyph_t *glyphs,
+			  int		       num_glyphs,
+			  cairo_path_fixed_t  *path);
+
+cairo_private cairo_status_t
+_cairo_gstate_set_antialias (cairo_gstate_t *gstate,
+			     cairo_antialias_t antialias);
+
+cairo_private cairo_antialias_t
+_cairo_gstate_get_antialias (cairo_gstate_t *gstate);
+
 #endif /* CAIRO_GSTATE_PRIVATE_H */
diff --git a/src/cairo-gstate.c b/src/cairo-gstate.c
index 119bc07..f7a32ae 100644
--- a/src/cairo-gstate.c
+++ b/src/cairo-gstate.c
@@ -105,6 +105,7 @@ _cairo_gstate_init (cairo_gstate_t  *gstate,
     gstate->parent_target = NULL;
     gstate->original_target = cairo_surface_reference (target);
 
+    gstate->is_identity = _cairo_matrix_is_identity (&gstate->target->device_transform);
     cairo_matrix_init_identity (&gstate->ctm);
     gstate->ctm_inverse = gstate->ctm;
     gstate->source_ctm_inverse = gstate->ctm;
@@ -170,6 +171,7 @@ _cairo_gstate_init_copy (cairo_gstate_t *gstate, cairo_gstate_t *other)
     gstate->parent_target = NULL;
     gstate->original_target = cairo_surface_reference (other->original_target);
 
+    gstate->is_identity = other->is_identity;
     gstate->ctm = other->ctm;
     gstate->ctm_inverse = other->ctm_inverse;
     gstate->source_ctm_inverse = other->source_ctm_inverse;
@@ -306,6 +308,7 @@ _cairo_gstate_redirect_target (cairo_gstate_t *gstate, cairo_surface_t *child)
     /* Now set up our new target; we overwrite gstate->target directly,
      * since its ref is now owned by gstate->parent_target */
     gstate->target = cairo_surface_reference (child);
+    gstate->is_identity &= _cairo_matrix_is_identity (&child->device_transform);
 
     /* The clip is in surface backend coordinates for the previous target;
      * translate it into the child's backend coordinates. */
@@ -608,6 +611,7 @@ _cairo_gstate_translate (cairo_gstate_t *gstate, double tx, double ty)
 
     cairo_matrix_init_translate (&tmp, tx, ty);
     cairo_matrix_multiply (&gstate->ctm, &tmp, &gstate->ctm);
+    gstate->is_identity = FALSE;
 
     /* paranoid check against gradual numerical instability */
     if (! _cairo_matrix_is_invertible (&gstate->ctm))
@@ -633,6 +637,7 @@ _cairo_gstate_scale (cairo_gstate_t *gstate, double sx, double sy)
 
     cairo_matrix_init_scale (&tmp, sx, sy);
     cairo_matrix_multiply (&gstate->ctm, &tmp, &gstate->ctm);
+    gstate->is_identity = FALSE;
 
     /* paranoid check against gradual numerical instability */
     if (! _cairo_matrix_is_invertible (&gstate->ctm))
@@ -659,6 +664,7 @@ _cairo_gstate_rotate (cairo_gstate_t *gstate, double angle)
 
     cairo_matrix_init_rotate (&tmp, angle);
     cairo_matrix_multiply (&gstate->ctm, &tmp, &gstate->ctm);
+    gstate->is_identity = FALSE;
 
     /* paranoid check against gradual numerical instability */
     if (! _cairo_matrix_is_invertible (&gstate->ctm))
@@ -692,6 +698,7 @@ _cairo_gstate_transform (cairo_gstate_t	      *gstate,
 
     cairo_matrix_multiply (&gstate->ctm, matrix, &gstate->ctm);
     cairo_matrix_multiply (&gstate->ctm_inverse, &gstate->ctm_inverse, &tmp);
+    gstate->is_identity = FALSE;
 
     /* paranoid check against gradual numerical instability */
     if (! _cairo_matrix_is_invertible (&gstate->ctm))
@@ -712,12 +719,18 @@ _cairo_gstate_set_matrix (cairo_gstate_t       *gstate,
     if (! _cairo_matrix_is_invertible (matrix))
 	return _cairo_error (CAIRO_STATUS_INVALID_MATRIX);
 
+    if (_cairo_matrix_is_identity (matrix)) {
+	_cairo_gstate_identity_matrix (gstate);
+	return CAIRO_STATUS_SUCCESS;
+    }
+
     _cairo_gstate_unset_scaled_font (gstate);
 
     gstate->ctm = *matrix;
     gstate->ctm_inverse = *matrix;
     status = cairo_matrix_invert (&gstate->ctm_inverse);
     assert (status == CAIRO_STATUS_SUCCESS);
+    gstate->is_identity = FALSE;
 
     return CAIRO_STATUS_SUCCESS;
 }
@@ -732,6 +745,7 @@ _cairo_gstate_identity_matrix (cairo_gstate_t *gstate)
 
     cairo_matrix_init_identity (&gstate->ctm);
     cairo_matrix_init_identity (&gstate->ctm_inverse);
+    gstate->is_identity = _cairo_matrix_is_identity (&gstate->target->device_transform);
 }
 
 void
@@ -761,14 +775,14 @@ _cairo_gstate_device_to_user_distance (cairo_gstate_t *gstate,
 }
 
 void
-_cairo_gstate_user_to_backend (cairo_gstate_t *gstate, double *x, double *y)
+_do_cairo_gstate_user_to_backend (cairo_gstate_t *gstate, double *x, double *y)
 {
     cairo_matrix_transform_point (&gstate->ctm, x, y);
     cairo_matrix_transform_point (&gstate->target->device_transform, x, y);
 }
 
 void
-_cairo_gstate_backend_to_user (cairo_gstate_t *gstate, double *x, double *y)
+_do_cairo_gstate_backend_to_user (cairo_gstate_t *gstate, double *x, double *y)
 {
     cairo_matrix_transform_point (&gstate->target->device_transform_inverse, x, y);
     cairo_matrix_transform_point (&gstate->ctm_inverse, x, y);
diff --git a/src/cairoint.h b/src/cairoint.h
index d8df10c..522dd12 100644
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -956,301 +956,6 @@ _cairo_lround (double d) cairo_const;
 cairo_private uint16_t
 _cairo_half_from_float (float f) cairo_const;
 
-/* cairo-gstate.c */
-cairo_private cairo_status_t
-_cairo_gstate_init (cairo_gstate_t  *gstate,
-		    cairo_surface_t *target);
-
-cairo_private void
-_cairo_gstate_fini (cairo_gstate_t *gstate);
-
-cairo_private cairo_status_t
-_cairo_gstate_save (cairo_gstate_t **gstate, cairo_gstate_t **freelist);
-
-cairo_private cairo_status_t
-_cairo_gstate_restore (cairo_gstate_t **gstate, cairo_gstate_t **freelist);
-
-cairo_private cairo_bool_t
-_cairo_gstate_is_redirected (cairo_gstate_t *gstate);
-
-cairo_private cairo_status_t
-_cairo_gstate_redirect_target (cairo_gstate_t *gstate, cairo_surface_t *child);
-
-cairo_private cairo_surface_t *
-_cairo_gstate_get_target (cairo_gstate_t *gstate);
-
-cairo_private cairo_surface_t *
-_cairo_gstate_get_parent_target (cairo_gstate_t *gstate);
-
-cairo_private cairo_surface_t *
-_cairo_gstate_get_original_target (cairo_gstate_t *gstate);
-
-cairo_private cairo_clip_t *
-_cairo_gstate_get_clip (cairo_gstate_t *gstate);
-
-cairo_private cairo_status_t
-_cairo_gstate_set_source (cairo_gstate_t *gstate, cairo_pattern_t *source);
-
-cairo_private cairo_pattern_t *
-_cairo_gstate_get_source (cairo_gstate_t *gstate);
-
-cairo_private cairo_status_t
-_cairo_gstate_set_operator (cairo_gstate_t *gstate, cairo_operator_t op);
-
-cairo_private cairo_operator_t
-_cairo_gstate_get_operator (cairo_gstate_t *gstate);
-
-cairo_private cairo_status_t
-_cairo_gstate_set_tolerance (cairo_gstate_t *gstate, double tolerance);
-
-cairo_private double
-_cairo_gstate_get_tolerance (cairo_gstate_t *gstate);
-
-cairo_private cairo_status_t
-_cairo_gstate_set_fill_rule (cairo_gstate_t *gstate, cairo_fill_rule_t fill_rule);
-
-cairo_private cairo_fill_rule_t
-_cairo_gstate_get_fill_rule (cairo_gstate_t *gstate);
-
-cairo_private cairo_status_t
-_cairo_gstate_set_line_width (cairo_gstate_t *gstate, double width);
-
-cairo_private double
-_cairo_gstate_get_line_width (cairo_gstate_t *gstate);
-
-cairo_private cairo_status_t
-_cairo_gstate_set_line_cap (cairo_gstate_t *gstate, cairo_line_cap_t line_cap);
-
-cairo_private cairo_line_cap_t
-_cairo_gstate_get_line_cap (cairo_gstate_t *gstate);
-
-cairo_private cairo_status_t
-_cairo_gstate_set_line_join (cairo_gstate_t *gstate, cairo_line_join_t line_join);
-
-cairo_private cairo_line_join_t
-_cairo_gstate_get_line_join (cairo_gstate_t *gstate);
-
-cairo_private cairo_status_t
-_cairo_gstate_set_dash (cairo_gstate_t *gstate, const double *dash, int num_dashes, double offset);
-
-cairo_private void
-_cairo_gstate_get_dash (cairo_gstate_t *gstate, double *dash, int *num_dashes, double *offset);
-
-cairo_private cairo_status_t
-_cairo_gstate_set_miter_limit (cairo_gstate_t *gstate, double limit);
-
-cairo_private double
-_cairo_gstate_get_miter_limit (cairo_gstate_t *gstate);
-
-cairo_private void
-_cairo_gstate_get_matrix (cairo_gstate_t *gstate, cairo_matrix_t *matrix);
-
-cairo_private cairo_status_t
-_cairo_gstate_translate (cairo_gstate_t *gstate, double tx, double ty);
-
-cairo_private cairo_status_t
-_cairo_gstate_scale (cairo_gstate_t *gstate, double sx, double sy);
-
-cairo_private cairo_status_t
-_cairo_gstate_rotate (cairo_gstate_t *gstate, double angle);
-
-cairo_private cairo_status_t
-_cairo_gstate_transform (cairo_gstate_t	      *gstate,
-			 const cairo_matrix_t *matrix);
-
-cairo_private cairo_status_t
-_cairo_gstate_set_matrix (cairo_gstate_t       *gstate,
-			  const cairo_matrix_t *matrix);
-
-cairo_private void
-_cairo_gstate_identity_matrix (cairo_gstate_t *gstate);
-
-cairo_private void
-_cairo_gstate_user_to_device (cairo_gstate_t *gstate, double *x, double *y);
-
-cairo_private void
-_cairo_gstate_user_to_device_distance (cairo_gstate_t *gstate, double *dx, double *dy);
-
-cairo_private void
-_cairo_gstate_device_to_user (cairo_gstate_t *gstate, double *x, double *y);
-
-cairo_private void
-_cairo_gstate_device_to_user_distance (cairo_gstate_t *gstate, double *dx, double *dy);
-
-cairo_private void
-_cairo_gstate_user_to_backend (cairo_gstate_t *gstate, double *x, double *y);
-
-cairo_private void
-_cairo_gstate_backend_to_user (cairo_gstate_t *gstate, double *x, double *y);
-
-cairo_private void
-_cairo_gstate_backend_to_user_rectangle (cairo_gstate_t *gstate,
-                                         double *x1, double *y1,
-                                         double *x2, double *y2,
-                                         cairo_bool_t *is_tight);
-
-cairo_private void
-_cairo_gstate_path_extents (cairo_gstate_t     *gstate,
-			    cairo_path_fixed_t *path,
-			    double *x1, double *y1,
-			    double *x2, double *y2);
-
-cairo_private cairo_status_t
-_cairo_gstate_paint (cairo_gstate_t *gstate);
-
-cairo_private cairo_status_t
-_cairo_gstate_mask (cairo_gstate_t  *gstate,
-		    cairo_pattern_t *mask);
-
-cairo_private cairo_status_t
-_cairo_gstate_stroke (cairo_gstate_t *gstate, cairo_path_fixed_t *path);
-
-cairo_private cairo_status_t
-_cairo_gstate_fill (cairo_gstate_t *gstate, cairo_path_fixed_t *path);
-
-cairo_private cairo_status_t
-_cairo_gstate_copy_page (cairo_gstate_t *gstate);
-
-cairo_private cairo_status_t
-_cairo_gstate_show_page (cairo_gstate_t *gstate);
-
-cairo_private cairo_status_t
-_cairo_gstate_stroke_extents (cairo_gstate_t	 *gstate,
-			      cairo_path_fixed_t *path,
-                              double *x1, double *y1,
-			      double *x2, double *y2);
-
-cairo_private cairo_status_t
-_cairo_gstate_fill_extents (cairo_gstate_t     *gstate,
-			    cairo_path_fixed_t *path,
-                            double *x1, double *y1,
-			    double *x2, double *y2);
-
-cairo_private cairo_status_t
-_cairo_gstate_in_stroke (cairo_gstate_t	    *gstate,
-			 cairo_path_fixed_t *path,
-			 double		     x,
-			 double		     y,
-			 cairo_bool_t	    *inside_ret);
-
-cairo_private cairo_bool_t
-_cairo_gstate_in_fill (cairo_gstate_t	  *gstate,
-		       cairo_path_fixed_t *path,
-		       double		   x,
-		       double		   y);
-
-cairo_private cairo_bool_t
-_cairo_gstate_in_clip (cairo_gstate_t	  *gstate,
-		       double		   x,
-		       double		   y);
-
-cairo_private cairo_status_t
-_cairo_gstate_clip (cairo_gstate_t *gstate, cairo_path_fixed_t *path);
-
-cairo_private cairo_status_t
-_cairo_gstate_reset_clip (cairo_gstate_t *gstate);
-
-cairo_private cairo_bool_t
-_cairo_gstate_clip_extents (cairo_gstate_t *gstate,
-		            double         *x1,
-		            double         *y1,
-			    double         *x2,
-			    double         *y2);
-
-cairo_private cairo_rectangle_list_t*
-_cairo_gstate_copy_clip_rectangle_list (cairo_gstate_t *gstate);
-
-cairo_private cairo_status_t
-_cairo_gstate_show_surface (cairo_gstate_t	*gstate,
-			    cairo_surface_t	*surface,
-			    double		 x,
-			    double		 y,
-			    double		width,
-			    double		height);
-
-cairo_private cairo_status_t
-_cairo_gstate_select_font_face (cairo_gstate_t *gstate,
-				const char *family,
-				cairo_font_slant_t slant,
-				cairo_font_weight_t weight);
-
-cairo_private cairo_status_t
-_cairo_gstate_set_font_size (cairo_gstate_t *gstate,
-			     double          size);
-
-cairo_private void
-_cairo_gstate_get_font_matrix (cairo_gstate_t *gstate,
-			       cairo_matrix_t *matrix);
-
-cairo_private cairo_status_t
-_cairo_gstate_set_font_matrix (cairo_gstate_t	    *gstate,
-			       const cairo_matrix_t *matrix);
-
-cairo_private void
-_cairo_gstate_get_font_options (cairo_gstate_t       *gstate,
-				cairo_font_options_t *options);
-
-cairo_private void
-_cairo_gstate_set_font_options (cairo_gstate_t	           *gstate,
-				const cairo_font_options_t *options);
-
-cairo_private cairo_status_t
-_cairo_gstate_get_font_face (cairo_gstate_t     *gstate,
-			     cairo_font_face_t **font_face);
-
-cairo_private cairo_status_t
-_cairo_gstate_get_scaled_font (cairo_gstate_t       *gstate,
-			       cairo_scaled_font_t **scaled_font);
-
-cairo_private cairo_status_t
-_cairo_gstate_get_font_extents (cairo_gstate_t *gstate,
-				cairo_font_extents_t *extents);
-
-cairo_private cairo_status_t
-_cairo_gstate_set_font_face (cairo_gstate_t    *gstate,
-			     cairo_font_face_t *font_face);
-
-cairo_private cairo_status_t
-_cairo_gstate_text_to_glyphs (cairo_gstate_t	         *gstate,
-			      double		          x,
-			      double		          y,
-			      const char	         *utf8,
-			      int		          utf8_len,
-			      cairo_glyph_t	        **glyphs,
-			      int		         *num_glyphs,
-			      cairo_text_cluster_t      **clusters,
-			      int		         *num_clusters,
-			      cairo_text_cluster_flags_t *cluster_flags);
-
-cairo_private cairo_status_t
-_cairo_gstate_glyph_extents (cairo_gstate_t *gstate,
-			     const cairo_glyph_t *glyphs,
-			     int num_glyphs,
-			     cairo_text_extents_t *extents);
-
-cairo_private cairo_status_t
-_cairo_gstate_show_text_glyphs (cairo_gstate_t		   *gstate,
-				const char		   *utf8,
-				int			    utf8_len,
-				const cairo_glyph_t	   *glyphs,
-				int			    num_glyphs,
-				const cairo_text_cluster_t *clusters,
-				int			    num_clusters,
-			        cairo_text_cluster_flags_t  cluster_flags);
-
-cairo_private cairo_status_t
-_cairo_gstate_glyph_path (cairo_gstate_t      *gstate,
-			  const cairo_glyph_t *glyphs,
-			  int		       num_glyphs,
-			  cairo_path_fixed_t  *path);
-
-cairo_private cairo_status_t
-_cairo_gstate_set_antialias (cairo_gstate_t *gstate,
-			     cairo_antialias_t antialias);
-
-cairo_private cairo_antialias_t
-_cairo_gstate_get_antialias (cairo_gstate_t *gstate);
-
 cairo_private cairo_bool_t
 _cairo_operator_bounded_by_mask (cairo_operator_t op) cairo_const;
 
commit 1349728d1ef63ed562a3fd0ee3c0a89aaba77616
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Thu Jun 10 11:26:12 2010 +0100

    test: Add partial coverage.
    
    Another experiment in measuring consistency of rasterisation stratagems
    across the backends.

diff --git a/test/Makefile.am b/test/Makefile.am
index 0b9eb7e..8403adf 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -862,6 +862,9 @@ REFERENCE_IMAGES = \
 	paint-with-alpha.ref.png \
 	paint-with-alpha.svg.ref.png \
 	paint.ref.png \
+	partial-coverage-rectangles.ref.png \
+	partial-coverage-reference.ref.png \
+	partial-coverage-triangles.ref.png \
 	pass-through.ref.png \
 	pass-through.rgb24.ref.png \
 	path-append.image16.ref.png \
diff --git a/test/Makefile.sources b/test/Makefile.sources
index 9bc00af..6d11ade 100644
--- a/test/Makefile.sources
+++ b/test/Makefile.sources
@@ -175,6 +175,7 @@ test_sources = \
 	paint-repeat.c					\
 	paint-source-alpha.c				\
 	paint-with-alpha.c				\
+	partial-coverage.c				\
 	path-append.c					\
 	path-stroke-twice.c				\
 	path-precision.c				\
diff --git a/test/partial-coverage-rectangles.ref.png b/test/partial-coverage-rectangles.ref.png
new file mode 100644
index 0000000..9e4a6fe
Binary files /dev/null and b/test/partial-coverage-rectangles.ref.png differ
diff --git a/test/partial-coverage-reference.ref.png b/test/partial-coverage-reference.ref.png
new file mode 100644
index 0000000..9e4a6fe
Binary files /dev/null and b/test/partial-coverage-reference.ref.png differ
diff --git a/test/partial-coverage-triangles.ref.png b/test/partial-coverage-triangles.ref.png
new file mode 100644
index 0000000..9e4a6fe
Binary files /dev/null and b/test/partial-coverage-triangles.ref.png differ
diff --git a/test/partial-coverage.c b/test/partial-coverage.c
new file mode 100644
index 0000000..9df87d4
--- /dev/null
+++ b/test/partial-coverage.c
@@ -0,0 +1,213 @@
+/*
+ * Copyright 2010 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Author: Chris Wilson <chris at chris-wilson.co.uk>
+ */
+
+#include "cairo-test.h"
+
+/* Test the sampling stratagems of the rasterisers by creating pixels
+ * containing minute holes and seeing how close to the expected
+ * coverage each rasteriser approaches.
+ */
+
+#define SIZE 64
+
+#include "../src/cairo-fixed-type-private.h"
+#define SAMPLE (1 << CAIRO_FIXED_FRAC_BITS)
+
+static uint32_t state;
+
+static uint32_t
+hars_petruska_f54_1_random (void)
+{
+#define rol(x,k) ((x << k) | (x >> (32-k)))
+    return state = (state ^ rol (state, 5) ^ rol (state, 24)) + 0x37798849;
+#undef rol
+}
+
+static double
+uniform_random (void)
+{
+    return hars_petruska_f54_1_random() / (double) UINT32_MAX;
+}
+
+/* coverage is given in [0,65535] */
+static void
+compute_occupancy (uint8_t *occupancy, int coverage)
+{
+    int i, c;
+
+    if (coverage < SAMPLE*SAMPLE/2) {
+	memset (occupancy, 0, SAMPLE*SAMPLE);
+	for (i = c = 0; i < SAMPLE*SAMPLE; i++) {
+	    if ((SAMPLE*SAMPLE - i) * uniform_random() < coverage - c) {
+		occupancy[i] = 0xff;
+		if (++c == coverage)
+		    return;
+	    }
+	}
+    } else {
+	coverage = SAMPLE*SAMPLE - coverage;
+	memset (occupancy, 0xff, SAMPLE*SAMPLE);
+	for (i = c = 0; i < SAMPLE*SAMPLE; i++) {
+	    if ((SAMPLE*SAMPLE - i) * uniform_random() < coverage - c) {
+		occupancy[i] = 0;
+		if (++c == coverage)
+		    return;
+	    }
+	}
+    }
+}
+
+static cairo_test_status_t
+reference (cairo_t *cr, int width, int height)
+{
+    int i;
+
+    cairo_set_source_rgb (cr, 0.0, 0.0, 0.0);
+    cairo_paint (cr);
+
+    for (i = 0; i < SIZE*SIZE; i++) {
+	cairo_set_source_rgba (cr, 1., 1., 1.,
+			       i / (double) (SIZE * SIZE));
+	cairo_rectangle (cr, i % SIZE, i / SIZE, 1, 1);
+	cairo_fill (cr);
+    }
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_test_status_t
+rectangles (cairo_t *cr, int width, int height)
+{
+    uint8_t *occupancy;
+    int i, j, channel;
+
+    state = 0x12345678;
+    occupancy = xmalloc (SAMPLE*SAMPLE);
+
+    cairo_set_source_rgb (cr, 0.0, 0.0, 0.0);
+    cairo_paint (cr);
+
+    cairo_set_operator (cr, CAIRO_OPERATOR_ADD);
+    for (channel = 0; channel < 3; channel++) {
+	switch (channel) {
+	default:
+	case 0: cairo_set_source_rgb (cr, 1.0, 0.0, 0.0); break;
+	case 1: cairo_set_source_rgb (cr, 0.0, 1.0, 0.0); break;
+	case 2: cairo_set_source_rgb (cr, 0.0, 0.0, 1.0); break;
+	}
+
+	for (i = 0; i < SIZE*SIZE; i++) {
+	    int xs, ys;
+
+	    compute_occupancy (occupancy, SAMPLE*SAMPLE * i / (SIZE * SIZE));
+
+	    xs = i % SIZE * SAMPLE;
+	    ys = i / SIZE * SAMPLE;
+	    for (j = 0; j < SAMPLE*SAMPLE; j++) {
+		if (occupancy[j]) {
+		    cairo_rectangle (cr,
+				     (j % SAMPLE + xs) / (double) SAMPLE,
+				     (j / SAMPLE + ys) / (double) SAMPLE,
+				     1 / (double) SAMPLE,
+				     1 / (double) SAMPLE);
+		}
+	    }
+	    cairo_fill (cr);
+	}
+    }
+
+    free (occupancy);
+
+    return CAIRO_TEST_SUCCESS;
+}
+
+static cairo_test_status_t
+triangles (cairo_t *cr, int width, int height)
+{
+    uint8_t *occupancy;
+    int i, j, channel;
+
+    state = 0x12345678;
+    occupancy = xmalloc (SAMPLE*SAMPLE);
+
+    cairo_set_source_rgb (cr, 0.0, 0.0, 0.0);
+    cairo_paint (cr);
+
+    cairo_set_operator (cr, CAIRO_OPERATOR_ADD);
+    for (channel = 0; channel < 3; channel++) {
+	switch (channel) {
+	default:
+	case 0: cairo_set_source_rgb (cr, 1.0, 0.0, 0.0); break;
+	case 1: cairo_set_source_rgb (cr, 0.0, 1.0, 0.0); break;
+	case 2: cairo_set_source_rgb (cr, 0.0, 0.0, 1.0); break;
+	}
+
+	for (i = 0; i < SIZE*SIZE; i++) {
+	    int xs, ys;
+
+	    compute_occupancy (occupancy, SAMPLE*SAMPLE * i / (SIZE * SIZE));
+
+	    xs = i % SIZE * SAMPLE;
+	    ys = i / SIZE * SAMPLE;
+	    for (j = 0; j < SAMPLE*SAMPLE; j++) {
+		if (occupancy[j]) {
+		    int x = j % SAMPLE + xs;
+		    int y = j / SAMPLE + ys;
+		    cairo_move_to (cr, x / (double) SAMPLE, y / (double) SAMPLE);
+		    cairo_line_to (cr, (x+1) / (double) SAMPLE, (y+1) / (double) SAMPLE);
+		    cairo_line_to (cr, (x+1) / (double) SAMPLE, y / (double) SAMPLE);
+		    cairo_close_path (cr);
+		}
+	    }
+	    cairo_fill (cr);
+	}
+    }
+
+    free (occupancy);
+
+    return CAIRO_TEST_SUCCESS;
+}
+
+CAIRO_TEST (partial_coverage_rectangles,
+	    "Check the fidelity of the rasterisation.",
+	    "coverage raster", /* keywords */
+	    "raster", /* requirements */
+	    SIZE, SIZE,
+	    NULL, rectangles)
+
+CAIRO_TEST (partial_coverage_triangles,
+	    "Check the fidelity of the rasterisation.",
+	    "coverage raster", /* keywords */
+	    "raster", /* requirements */
+	    SIZE, SIZE,
+	    NULL, triangles)
+
+CAIRO_TEST (partial_coverage_reference,
+	    "Check the fidelity of this test.",
+	    "coverage raster", /* keywords */
+	    "raster", /* requirements */
+	    SIZE, SIZE,
+	    NULL, reference)
commit 486118361ad0c2e68fa9f6b44ddb10e84d237eca
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Thu Jun 10 11:28:26 2010 +0100

    test: Fix half-coverage colouration.
    
    Hmm, red over red makes the test pointless. The test still remains of
    highly dubious quality, as it primarily serves as a rendercheck more
    than a test of Cairo. The best hope for this test is that it inspires a
    better one.
    
    And incorporate the notes made by Joonas.

diff --git a/test/half-coverage.c b/test/half-coverage.c
index e7880ec..8dc9784 100644
--- a/test/half-coverage.c
+++ b/test/half-coverage.c
@@ -41,6 +41,7 @@ rectangles (cairo_t *cr, int width, int height)
 
     cairo_set_source_rgb (cr, 1.0, 0.0, 0.0);
     cairo_paint (cr);
+    cairo_set_source_rgb (cr, 1.0, 1.0, 1.0);
 
     for (i = 1; i <= SIZE; i++) {
 	int x, y;
@@ -52,6 +53,14 @@ rectangles (cairo_t *cr, int width, int height)
 	cairo_scale (cr, 1./SIZE, 1./SIZE);
 	for (x = -i; x < SIZE*WIDTH; x += 2*i) {
 	    for (y = -i; y < SIZE*HEIGHT; y += 2*i) {
+		/* Add a little tile composed of two non-overlapping squares
+		 *   +--+
+		 *   |  |
+		 *   |__|__
+		 *      |  |
+		 *      |  |
+		 *      +--+
+		 */
 		cairo_rectangle (cr, x, y, i, i);
 		cairo_rectangle (cr, x+i, y+i, i, i);
 	    }
@@ -72,6 +81,7 @@ triangles (cairo_t *cr, int width, int height)
 
     cairo_set_source_rgb (cr, 1.0, 0.0, 0.0);
     cairo_paint (cr);
+    cairo_set_source_rgb (cr, 1.0, 1.0, 1.0);
 
     for (i = 1; i <= SIZE; i++) {
 	int x, y;
@@ -83,22 +93,38 @@ triangles (cairo_t *cr, int width, int height)
 	cairo_scale (cr, 1./SIZE, 1./SIZE);
 	for (x = -i; x < SIZE*WIDTH; x += 2*i) {
 	    for (y = -i; y < SIZE*HEIGHT; y += 2*i) {
-		/* add internal edges just for fun */
+		/* Add a tile composed of four non-overlapping
+		 * triangles.  The plus and minus signs inside the
+		 * triangles denote the orientation of the triangle's
+		 * edges: + for clockwise and - for anticlockwise.
+		 *
+		 *   +-----+
+		 *    \-|+/
+		 *     \|/
+		 *     /|\
+		 *    /-|-\
+		 *   +-----+
+		 */
+
+		/* top left triangle */
 		cairo_move_to (cr, x, y);
 		cairo_line_to (cr, x+i, y+i);
 		cairo_line_to (cr, x+i, y);
 		cairo_close_path (cr);
 
+		/* top right triangle */
 		cairo_move_to (cr, x+i, y);
 		cairo_line_to (cr, x+2*i, y);
 		cairo_line_to (cr, x+i, y+i);
 		cairo_close_path (cr);
 
+		/* bottom left triangle */
 		cairo_move_to (cr, x+i, y+i);
 		cairo_line_to (cr, x, y+2*i);
 		cairo_line_to (cr, x+i, y+2*i);
 		cairo_close_path (cr);
 
+		/* bottom right triangle */
 		cairo_move_to (cr, x+i, y+i);
 		cairo_line_to (cr, x+i, y+2*i);
 		cairo_line_to (cr, x+2*i, y+2*i);
commit 5cb764850f7c405085739647bac2809045e7cdf3
Author: Dmitri Vorobiev <dmitri.vorobiev at movial.com>
Date:   Wed Jun 9 19:20:27 2010 +0300

    scaled-font: optimize cairo_scaled_font_text_to_glyphs()
    
    This patch serves two purposes. First, it factors out the heavy part
    of the cairo_scaled_font_text_to_glyphs() routine thus allowing GCC
    to better optimize the cache cleanup loop. Keeping the look-up table
    indices in a separate array speeds up array initialization even further.
    
    Second, this patch introduces a shortcut for the case when the string
    to be rendered consists of a single character. In this case, caching is
    not necessary at all.
    
    We have a benchmark that uses Cairo to render a large amount of random
    strings of consisting of printable ASCII characters. Below are Oprofile
    results collected while running this benchmark. It is easy to see that
    the heavy part becomes noticeably lighter.
    
    Before:
    
    Profiling through timer interrupt
    samples  %        app name                 symbol name
    198755   13.5580  libcairo.so.2.10907.0    cairo_scaled_font_text_to_glyphs
    88580     6.0424  libcairo.so.2.10907.0    _cairo_scaled_glyph_lookup
    81127     5.5340  libcairo.so.2.10907.0    _cairo_hash_table_lookup
    68186     4.6513  libcairo.so.2.10907.0    cairo_scaled_font_glyph_extents
    47145     3.2160  libcairo.so.2.10907.0    _composite_glyphs_via_mask
    46327     3.1602  libcairo.so.2.10907.0    _cairo_scaled_font_glyph_device_extents
    44817     3.0572  libcairo.so.2.10907.0    _composite_glyphs
    40431     2.7580  libcairo.so.2.10907.0    .plt
    
    After (note that cairo_scaled_font_text_to_glyphs_internal_single() was inlined):
    
    Profiling through timer interrupt
    samples  %        app name                 symbol name
    107264    7.6406  libcairo.so.2.10907.0    cairo_scaled_font_text_to_glyphs_internal_multiple
    87888     6.2604  libcairo.so.2.10907.0    _cairo_scaled_glyph_lookup
    79011     5.6281  libcairo.so.2.10907.0    _cairo_hash_table_lookup
    71723     5.1090  libcairo.so.2.10907.0    cairo_scaled_font_glyph_extents
    48084     3.4251  libcairo.so.2.10907.0    _composite_glyphs_via_mask
    46636     3.3220  libcairo.so.2.10907.0    _cairo_scaled_font_glyph_device_extents
    44740     3.1869  libcairo.so.2.10907.0    _composite_glyphs
    42472     3.0254  libc-2.8.so              _int_malloc
    39194     2.7919  libcairo.so.2.10907.0    _cairo_gstate_transform_glyphs_to_backend
    38614     2.7506  libcairo.so.2.10907.0    .plt
    37063     2.6401  libcairo.so.2.10907.0    _cairo_ft_ucs4_to_index
    36856     2.6253  libc-2.8.so              random
    36376     2.5911  libcairo.so.2.10907.0    _cairo_scaled_glyphs_equal
    34545     2.4607  libcairo.so.2.10907.0    cairo_matrix_transform_point
    31690     2.2573  libc-2.8.so              malloc
    29395     2.0939  libcairo.so.2.10907.0    _cairo_matrix_is_identity
    26142     1.8621  libcairo.so.2.10907.0    _cairo_utf8_to_ucs4
    24406     1.7385  libc-2.8.so              free
    24059     1.7138  libcairo.so.2.10907.0    cairo_scaled_font_text_to_glyphs
    
    [ickle: slightly amended for stylistic consistency.]

diff --git a/src/cairo-scaled-font.c b/src/cairo-scaled-font.c
index f928c08..d70c555 100644
--- a/src/cairo-scaled-font.c
+++ b/src/cairo-scaled-font.c
@@ -1570,6 +1570,106 @@ ZERO_EXTENTS:
 }
 slim_hidden_def (cairo_scaled_font_glyph_extents);
 
+#define GLYPH_LUT_SIZE 256
+static cairo_status_t
+cairo_scaled_font_text_to_glyphs_internal_multiple (cairo_scaled_font_t		 *scaled_font,
+						    double			  x,
+						    double			  y,
+						    const char			 *utf8,
+						    cairo_glyph_t		 *glyphs,
+						    cairo_text_cluster_t	**clusters,
+						    int				  num_chars)
+{
+    struct glyph_lut_elt {
+	unsigned long index;
+	double x_advance;
+	double y_advance;
+    } glyph_lut[GLYPH_LUT_SIZE];
+    uint32_t glyph_lut_unicode[GLYPH_LUT_SIZE];
+    cairo_status_t status;
+    const char *p;
+    int i;
+
+    for (i = 0; i < GLYPH_LUT_SIZE; i++)
+	glyph_lut_unicode[i] = ~0U;
+
+    p = utf8;
+    for (i = 0; i < num_chars; i++) {
+	int idx, num_bytes;
+	uint32_t unicode;
+	cairo_scaled_glyph_t *scaled_glyph;
+	struct glyph_lut_elt *glyph_slot;
+
+	num_bytes = _cairo_utf8_get_char_validated (p, &unicode);
+	p += num_bytes;
+
+	glyphs[i].x = x;
+	glyphs[i].y = y;
+
+	idx = unicode % ARRAY_LENGTH (glyph_lut);
+	glyph_slot = &glyph_lut[idx];
+	if (glyph_lut_unicode[idx] == unicode) {
+	    glyphs[i].index = glyph_slot->index;
+	    x += glyph_slot->x_advance;
+	    y += glyph_slot->y_advance;
+	} else {
+	    unsigned long g;
+
+	    g = scaled_font->backend->ucs4_to_index (scaled_font, unicode);
+	    status = _cairo_scaled_glyph_lookup (scaled_font,
+						 g,
+						 CAIRO_SCALED_GLYPH_INFO_METRICS,
+						 &scaled_glyph);
+	    if (unlikely (status))
+		return status;
+
+	    x += scaled_glyph->metrics.x_advance;
+	    y += scaled_glyph->metrics.y_advance;
+
+	    glyph_lut_unicode[idx] = unicode;
+	    glyph_slot->index = g;
+	    glyph_slot->x_advance = scaled_glyph->metrics.x_advance;
+	    glyph_slot->y_advance = scaled_glyph->metrics.y_advance;
+
+	    glyphs[i].index = g;
+	}
+
+	if (clusters) {
+	    (*clusters)[i].num_bytes  = num_bytes;
+	    (*clusters)[i].num_glyphs = 1;
+	}
+    }
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+cairo_scaled_font_text_to_glyphs_internal_single (cairo_scaled_font_t	 *scaled_font,
+						  double		  x,
+						  double		  y,
+						  const char		 *utf8,
+						  cairo_glyph_t		 *glyphs,
+						  cairo_text_cluster_t	**clusters,
+						  int			  num_chars)
+{
+    uint32_t unicode;
+    int num_bytes;
+
+    glyphs[0].x = x;
+    glyphs[0].y = y;
+
+    num_bytes = _cairo_utf8_get_char_validated (utf8, &unicode);
+    glyphs[0].index =
+	scaled_font->backend->ucs4_to_index (scaled_font, unicode);
+
+    if (clusters) {
+	(*clusters)[0].num_bytes  = num_bytes;
+	(*clusters)[0].num_glyphs = 1;
+    }
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
 /**
  * cairo_scaled_font_text_to_glyphs:
  * @x: X position to place first glyph
@@ -1717,18 +1817,10 @@ cairo_scaled_font_text_to_glyphs (cairo_scaled_font_t   *scaled_font,
 				  int		        *num_clusters,
 				  cairo_text_cluster_flags_t *cluster_flags)
 {
-    int i;
     int num_chars = 0;
-    const char *p;
     cairo_status_t status;
     cairo_glyph_t *orig_glyphs;
     cairo_text_cluster_t *orig_clusters;
-    struct glyph_lut_elt {
-	uint32_t unicode;
-	unsigned long index;
-	double x_advance;
-	double y_advance;
-    } glyph_lut[256];
 
     status = scaled_font->status;
     if (unlikely (status))
@@ -1866,52 +1958,20 @@ cairo_scaled_font_text_to_glyphs (cairo_scaled_font_t   *scaled_font,
 	*num_clusters = num_chars;
     }
 
-    for (i = 0; i < ARRAY_LENGTH (glyph_lut); i++)
-	glyph_lut[i].unicode = ~0U;
-
-    p = utf8;
-    for (i = 0; i < num_chars; i++) {
-	int num_bytes;
-	uint32_t unicode;
-	cairo_scaled_glyph_t *scaled_glyph;
-	struct glyph_lut_elt *glyph_slot;
-
-	num_bytes = _cairo_utf8_get_char_validated (p, &unicode);
-	p += num_bytes;
-
-	(*glyphs)[i].x = x;
-	(*glyphs)[i].y = y;
-
-	glyph_slot = &glyph_lut[unicode % ARRAY_LENGTH (glyph_lut)];
-	if (glyph_slot->unicode == unicode) {
-	    (*glyphs)[i].index = glyph_slot->index;
-	    x += glyph_slot->x_advance;
-	    y += glyph_slot->y_advance;
-	} else {
-	    (*glyphs)[i].index =
-		(*scaled_font->backend->ucs4_to_index) (scaled_font, unicode);
-
-	    status = _cairo_scaled_glyph_lookup (scaled_font,
-						 (*glyphs)[i].index,
-						 CAIRO_SCALED_GLYPH_INFO_METRICS,
-						 &scaled_glyph);
-	    if (unlikely (status))
-		goto DONE;
-
-	    x += scaled_glyph->metrics.x_advance;
-	    y += scaled_glyph->metrics.y_advance;
-
-	    glyph_slot->unicode = unicode;
-	    glyph_slot->index = (*glyphs)[i].index;
-	    glyph_slot->x_advance = scaled_glyph->metrics.x_advance;
-	    glyph_slot->y_advance = scaled_glyph->metrics.y_advance;
-	}
-
-	if (clusters) {
-	    (*clusters)[i].num_bytes  = num_bytes;
-	    (*clusters)[i].num_glyphs = 1;
-	}
-    }
+    if (num_chars > 1)
+	status = cairo_scaled_font_text_to_glyphs_internal_multiple (scaled_font,
+								     x, y,
+								     utf8,
+								     *glyphs,
+								     clusters,
+								     num_chars);
+    else
+	status = cairo_scaled_font_text_to_glyphs_internal_single (scaled_font,
+								   x, y,
+								   utf8,
+								   *glyphs,
+								   clusters,
+								   num_chars);
 
  DONE: /* error that should be logged on scaled_font happened */
     _cairo_scaled_font_thaw_cache (scaled_font);


More information about the cairo-commit mailing list