[cairo-commit] 15 commits - boilerplate/cairo-boilerplate-getopt.c boilerplate/cairo-boilerplate-getopt.h perf/cairo-perf.c perf/cairo-perf.h src/cairo-analysis-surface.c src/cairo.c src/cairo-clip.c src/cairo-glitz-surface.c src/cairo-gstate.c src/cairo-hull.c src/cairoint.h src/cairo-path-stroke.c src/cairo-pattern.c src/cairo-pen.c src/cairo-polygon.c src/cairo-private.h src/cairo-ps-surface.c src/cairo-quartz-surface.c src/cairo-surface-fallback.c src/cairo-types-private.h src/cairo-win32-printing-surface.c src/cairo-win32-surface.c src/cairo-xcb-surface.c src/cairo-xlib-surface.c src/check-def.sh

Chris Wilson ickle at kemper.freedesktop.org
Fri Jun 13 23:13:39 PDT 2008


 boilerplate/cairo-boilerplate-getopt.c |    2 
 boilerplate/cairo-boilerplate-getopt.h |    2 
 perf/cairo-perf.c                      |   30 +++----
 perf/cairo-perf.h                      |    3 
 src/cairo-analysis-surface.c           |   56 +++++++++++--
 src/cairo-clip.c                       |    4 
 src/cairo-glitz-surface.c              |    4 
 src/cairo-gstate.c                     |   66 ++++-----------
 src/cairo-hull.c                       |   40 ++++-----
 src/cairo-path-stroke.c                |   41 +++++----
 src/cairo-pattern.c                    |  114 ++++++++++++---------------
 src/cairo-pen.c                        |   71 ++++++++++------
 src/cairo-polygon.c                    |   19 +---
 src/cairo-private.h                    |    1 
 src/cairo-ps-surface.c                 |    4 
 src/cairo-quartz-surface.c             |    6 -
 src/cairo-surface-fallback.c           |   24 ++---
 src/cairo-types-private.h              |    7 -
 src/cairo-win32-printing-surface.c     |    5 -
 src/cairo-win32-surface.c              |    4 
 src/cairo-xcb-surface.c                |    4 
 src/cairo-xlib-surface.c               |  139 ++++++++++++++++++++++++---------
 src/cairo.c                            |   25 +++--
 src/cairoint.h                         |    4 
 src/check-def.sh                       |    2 
 25 files changed, 389 insertions(+), 288 deletions(-)

New commits:
commit f2ea46edf4cec3d59f56d90c6f12b0896715022d
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Thu Oct 11 22:51:09 2007 +0100

    [cairo-xlib-surface] Optimize away clip that covers the entire surface.
    
    Replace a clip rectangle that covers the entire surface with no
    clipping as this is quite a common operation when toolkits (i.e. GTK+)
    clear surfaces before drawing and avoids a redundant
    XRenderSetClipRectangles.

diff --git a/src/cairo-xlib-surface.c b/src/cairo-xlib-surface.c
index 619486c..8b1cdfe 100644
--- a/src/cairo-xlib-surface.c
+++ b/src/cairo-xlib-surface.c
@@ -1979,8 +1979,9 @@ _cairo_xlib_surface_set_clip_region (void           *abstract_surface,
 				     cairo_region_t *region)
 {
     cairo_xlib_surface_t *surface = abstract_surface;
+    cairo_bool_t had_clip_rects = surface->have_clip_rects;
 
-    if (surface->have_clip_rects == FALSE && region == NULL)
+    if (had_clip_rects == FALSE && region == NULL)
 	return CAIRO_STATUS_SUCCESS;
 
     if (surface->clip_rects != surface->embedded_clip_rects) {
@@ -2046,9 +2047,24 @@ _cairo_xlib_surface_set_clip_region (void           *abstract_surface,
 	surface->have_clip_rects = TRUE;
 	surface->clip_rects = rects;
 	surface->num_clip_rects = n_boxes;
+
+	/* Discard the trivial clip rectangle that covers the entire surface */
+	if (n_boxes == 1 &&
+	    rects[0].x == 0 &&
+	    rects[0].y == 0 &&
+	    rects[0].width  == surface->width &&
+	    rects[0].height == surface->height)
+	{
+	    surface->have_clip_rects = FALSE;
+	    surface->num_clip_rects = 0;
+
+	    if (! had_clip_rects)
+		goto DONE;
+	}
     }
 
     surface->clip_dirty = CAIRO_XLIB_SURFACE_CLIP_DIRTY_ALL;
+  DONE:
 
     return CAIRO_STATUS_SUCCESS;
 }
commit b06bd9379a9841da1d1448534c320fb45e6d6d83
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Wed May 28 20:32:40 2008 +0100

    [cairo-xlib-surface] Handle a NULL visual along core FillRectangles path.
    
    It is possible for an XRender capable surface to use
    _cairo_xlib_surface_solid_fill_rectangle() if the surface
    HAS_CREATE_PICTURE() && ! HAS_FILL_RECTANGLES(), in which case we need to
    handle the surface having no associated visual.
    
    Fixes test/xlib-expose-event.

diff --git a/src/cairo-xlib-surface.c b/src/cairo-xlib-surface.c
index 8cc24c3..619486c 100644
--- a/src/cairo-xlib-surface.c
+++ b/src/cairo-xlib-surface.c
@@ -1626,7 +1626,7 @@ _cairo_xlib_surface_solid_fill_rectangles (cairo_xlib_surface_t    *surface,
     int b = color->blue_short  >> 8;
     int i;
 
-    if (surface->visual->class == TrueColor) {
+    if (surface->visual == NULL || surface->visual->class == TrueColor) {
 	_characterize_field (surface->a_mask, &a_width, &a_shift);
 	_characterize_field (surface->r_mask, &r_width, &r_shift);
 	_characterize_field (surface->g_mask, &g_width, &g_shift);
commit db32e5ffcc9b06aab623987ecb3b64b9aaf8eca2
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Wed May 28 17:44:35 2008 +0100

    [check-def.sh] Ignore magic PPC symbols
    
    It appears that the PowerPC Linux ABI specifies a number of magic
    functions for register saves and restores which currently appear as
    exported symbols in the shared object. Ignore them.

diff --git a/src/check-def.sh b/src/check-def.sh
index a7ea2a5..04880e1 100755
--- a/src/check-def.sh
+++ b/src/check-def.sh
@@ -37,7 +37,7 @@ for def in $defs; do
 
 	{
 		echo EXPORTS
-		eval $get_cairo_syms | grep -v '^_cairo_test_\|^_fini\|^_init' | sort -u
+		eval $get_cairo_syms | grep -v '^_cairo_test_\|^_fini\|^_init\|^_save[fg]pr\|^_rest[fg]pr' | sort -u
 		# cheat: copy the last line from the def file!
 		tail -n1 "$def"
 	} | diff "$def" - || stat=1
commit ad9a334e2c86ec3745d45f4d1f113999a731ed70
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Wed May 28 15:42:09 2008 +0100

    Allocate the correct pattern type on the stack.
    
    Instead of allocating the union of all possible pattern types, just
    allocate the specific pattern as used by the function in order to trim
    the stack space consumption and flag potential misuse.

diff --git a/src/cairo-clip.c b/src/cairo-clip.c
index c3ed08b..3cee398 100644
--- a/src/cairo-clip.c
+++ b/src/cairo-clip.c
@@ -274,13 +274,13 @@ _cairo_clip_combine_to_surface (cairo_clip_t                  *clip,
 				int                           dst_y,
 				const cairo_rectangle_int_t *extents)
 {
-    cairo_pattern_union_t pattern;
+    cairo_surface_pattern_t pattern;
     cairo_status_t status;
 
     if (clip->all_clipped)
 	return CAIRO_STATUS_SUCCESS;
 
-    _cairo_pattern_init_for_surface (&pattern.surface, clip->surface);
+    _cairo_pattern_init_for_surface (&pattern, clip->surface);
 
     status = _cairo_surface_composite (op,
 				       &pattern.base,
diff --git a/src/cairo-glitz-surface.c b/src/cairo-glitz-surface.c
index 592dd13..44e560c 100644
--- a/src/cairo-glitz-surface.c
+++ b/src/cairo-glitz-surface.c
@@ -958,7 +958,7 @@ _cairo_glitz_pattern_acquire_surfaces (cairo_pattern_t	                *src,
 				       cairo_glitz_surface_attributes_t *mattr)
 {
     cairo_int_status_t	  status;
-    cairo_pattern_union_t tmp;
+    cairo_solid_pattern_t tmp;
 
     /* If src and mask are both solid, then the mask alpha can be
      * combined into src and mask can be ignored. */
@@ -977,7 +977,7 @@ _cairo_glitz_pattern_acquire_surfaces (cairo_pattern_t	                *src,
 	combined = src_solid->color;
 	_cairo_color_multiply_alpha (&combined, mask_solid->color.alpha);
 
-	_cairo_pattern_init_solid (&tmp.solid, &combined,
+	_cairo_pattern_init_solid (&tmp, &combined,
 				   CAIRO_COLOR_IS_OPAQUE (&combined) ?
 				   CAIRO_CONTENT_COLOR :
 				   CAIRO_CONTENT_COLOR_ALPHA);
diff --git a/src/cairo-ps-surface.c b/src/cairo-ps-surface.c
index 3f4b3bf..a4266d2 100644
--- a/src/cairo-ps-surface.c
+++ b/src/cairo-ps-surface.c
@@ -1688,7 +1688,7 @@ _cairo_ps_surface_flatten_image_transparency (cairo_ps_surface_t    *surface,
 {
     const cairo_color_t *background_color;
     cairo_surface_t *opaque;
-    cairo_pattern_union_t pattern;
+    cairo_surface_pattern_t pattern;
     cairo_status_t status;
 
     if (surface->content == CAIRO_CONTENT_COLOR_ALPHA)
@@ -1702,7 +1702,7 @@ _cairo_ps_surface_flatten_image_transparency (cairo_ps_surface_t    *surface,
     if (opaque->status)
 	return opaque->status;
 
-    _cairo_pattern_init_for_surface (&pattern.surface, &image->base);
+    _cairo_pattern_init_for_surface (&pattern, &image->base);
 
     status = _cairo_surface_fill_rectangle (opaque,
 					    CAIRO_OPERATOR_SOURCE,
diff --git a/src/cairo-quartz-surface.c b/src/cairo-quartz-surface.c
index 75fb13f..84d8702 100644
--- a/src/cairo-quartz-surface.c
+++ b/src/cairo-quartz-surface.c
@@ -2155,7 +2155,7 @@ _cairo_quartz_surface_mask_with_generic (cairo_quartz_surface_t *surface,
     cairo_surface_t *gradient_surf = NULL;
     cairo_t *gradient_surf_cr = NULL;
 
-    cairo_pattern_union_t surface_pattern;
+    cairo_surface_pattern_t surface_pattern;
     cairo_int_status_t status;
 
     /* Render the gradient to a surface */
@@ -2172,9 +2172,9 @@ _cairo_quartz_surface_mask_with_generic (cairo_quartz_surface_t *surface,
     if (status)
 	goto BAIL;
 
-    _cairo_pattern_init_for_surface (&surface_pattern.surface, gradient_surf);
+    _cairo_pattern_init_for_surface (&surface_pattern, gradient_surf);
 
-    status = _cairo_quartz_surface_mask_with_surface (surface, op, source, &surface_pattern.surface);
+    status = _cairo_quartz_surface_mask_with_surface (surface, op, source, &surface_pattern);
 
     _cairo_pattern_fini (&surface_pattern.base);
 
diff --git a/src/cairo-surface-fallback.c b/src/cairo-surface-fallback.c
index f84be7a..eb5a23c 100644
--- a/src/cairo-surface-fallback.c
+++ b/src/cairo-surface-fallback.c
@@ -358,7 +358,7 @@ _clip_and_composite (cairo_clip_t                  *clip,
 		     cairo_surface_t               *dst,
 		     const cairo_rectangle_int_t   *extents)
 {
-    cairo_pattern_union_t solid_pattern;
+    cairo_solid_pattern_t solid_pattern;
     cairo_status_t status;
 
     if (_cairo_rectangle_empty (extents))
@@ -366,7 +366,7 @@ _clip_and_composite (cairo_clip_t                  *clip,
 	return CAIRO_STATUS_SUCCESS;
 
     if (op == CAIRO_OPERATOR_CLEAR) {
-	_cairo_pattern_init_solid (&solid_pattern.solid, CAIRO_COLOR_WHITE,
+	_cairo_pattern_init_solid (&solid_pattern, CAIRO_COLOR_WHITE,
 				   CAIRO_CONTENT_COLOR);
 	src = &solid_pattern.base;
 	op = CAIRO_OPERATOR_DEST_OUT;
@@ -415,14 +415,14 @@ _composite_trap_region (cairo_clip_t            *clip,
 			cairo_rectangle_int_t   *extents)
 {
     cairo_status_t status;
-    cairo_pattern_union_t solid_pattern;
-    cairo_pattern_union_t mask;
+    cairo_solid_pattern_t solid_pattern;
+    cairo_surface_pattern_t mask;
     int num_rects = _cairo_region_num_boxes (trap_region);
     unsigned int clip_serial;
     cairo_surface_t *clip_surface = clip ? clip->surface : NULL;
 
     if (clip_surface && op == CAIRO_OPERATOR_CLEAR) {
-	_cairo_pattern_init_solid (&solid_pattern.solid, CAIRO_COLOR_WHITE,
+	_cairo_pattern_init_solid (&solid_pattern, CAIRO_COLOR_WHITE,
 				   CAIRO_CONTENT_COLOR);
 	src = &solid_pattern.base;
 	op = CAIRO_OPERATOR_DEST_OUT;
@@ -444,7 +444,7 @@ _composite_trap_region (cairo_clip_t            *clip,
     }
 
     if (clip_surface)
-	_cairo_pattern_init_for_surface (&mask.surface, clip_surface);
+	_cairo_pattern_init_for_surface (&mask, clip_surface);
 
     status = _cairo_surface_composite (op,
 				       src,
@@ -487,13 +487,13 @@ _composite_traps_draw_func (void                          *closure,
 			    const cairo_rectangle_int_t   *extents)
 {
     cairo_composite_traps_info_t *info = closure;
-    cairo_pattern_union_t pattern;
+    cairo_solid_pattern_t pattern;
     cairo_status_t status;
 
     if (dst_x != 0 || dst_y != 0)
 	_cairo_traps_translate (info->traps, - dst_x, - dst_y);
 
-    _cairo_pattern_init_solid (&pattern.solid, CAIRO_COLOR_WHITE,
+    _cairo_pattern_init_solid (&pattern, CAIRO_COLOR_WHITE,
 			       CAIRO_CONTENT_COLOR);
     if (!src)
 	src = &pattern.base;
@@ -929,7 +929,7 @@ _cairo_surface_old_show_glyphs_draw_func (void                          *closure
 					  const cairo_rectangle_int_t *extents)
 {
     cairo_show_glyphs_info_t *glyph_info = closure;
-    cairo_pattern_union_t pattern;
+    cairo_solid_pattern_t pattern;
     cairo_status_t status;
 
     /* Modifying the glyph array is fine because we know that this function
@@ -946,7 +946,7 @@ _cairo_surface_old_show_glyphs_draw_func (void                          *closure
 	}
     }
 
-    _cairo_pattern_init_solid (&pattern.solid, CAIRO_COLOR_WHITE,
+    _cairo_pattern_init_solid (&pattern, CAIRO_COLOR_WHITE,
 			       CAIRO_CONTENT_COLOR);
     if (!src)
 	src = &pattern.base;
@@ -1032,7 +1032,7 @@ _cairo_surface_fallback_snapshot (cairo_surface_t *surface)
 {
     cairo_surface_t *snapshot;
     cairo_status_t status;
-    cairo_pattern_union_t pattern;
+    cairo_surface_pattern_t pattern;
     cairo_image_surface_t *image;
     void *image_extra;
 
@@ -1050,7 +1050,7 @@ _cairo_surface_fallback_snapshot (cairo_surface_t *surface)
 	return snapshot;
     }
 
-    _cairo_pattern_init_for_surface (&pattern.surface, &image->base);
+    _cairo_pattern_init_for_surface (&pattern, &image->base);
 
     status = _cairo_surface_composite (CAIRO_OPERATOR_SOURCE,
 			               &pattern.base,
diff --git a/src/cairo-win32-printing-surface.c b/src/cairo-win32-printing-surface.c
index 2c2ca21..0846daa 100644
--- a/src/cairo-win32-printing-surface.c
+++ b/src/cairo-win32-printing-surface.c
@@ -494,7 +494,6 @@ _cairo_win32_printing_surface_paint_image_pattern (cairo_win32_surface_t   *surf
     cairo_image_surface_t *image;
     void *image_extra;
     cairo_surface_t *opaque_surface;
-    cairo_pattern_union_t opaque_pattern;
     cairo_image_surface_t *opaque_image = NULL;
     BITMAPINFO bi;
     cairo_matrix_t m;
@@ -538,6 +537,8 @@ _cairo_win32_printing_surface_paint_image_pattern (cairo_win32_surface_t   *surf
     }
 
     if (image->format != CAIRO_FORMAT_RGB24) {
+	cairo_surface_pattern_t opaque_pattern;
+
 	opaque_surface = cairo_image_surface_create (CAIRO_FORMAT_RGB24,
 						     image->width,
 						     image->height);
@@ -546,7 +547,7 @@ _cairo_win32_printing_surface_paint_image_pattern (cairo_win32_surface_t   *surf
 	    goto FINISH3;
 	}
 
-	_cairo_pattern_init_for_surface (&opaque_pattern.surface, &image->base);
+	_cairo_pattern_init_for_surface (&opaque_pattern, &image->base);
 
 	status = _cairo_surface_fill_rectangle (opaque_surface,
 				                CAIRO_OPERATOR_SOURCE,
diff --git a/src/cairo-win32-surface.c b/src/cairo-win32-surface.c
index 7574a06..d090ffb 100644
--- a/src/cairo-win32-surface.c
+++ b/src/cairo-win32-surface.c
@@ -446,7 +446,7 @@ _cairo_win32_surface_clone_similar (void *abstract_surface,
     cairo_content_t src_content;
     cairo_surface_t *new_surface;
     cairo_status_t status;
-    cairo_pattern_union_t pattern;
+    cairo_surface_pattern_t pattern;
 
     src_content = cairo_surface_get_content(src);
     new_surface =
@@ -455,7 +455,7 @@ _cairo_win32_surface_clone_similar (void *abstract_surface,
     if (cairo_surface_status(new_surface))
 	return cairo_surface_status(new_surface);
 
-    _cairo_pattern_init_for_surface (&pattern.surface, src);
+    _cairo_pattern_init_for_surface (&pattern, src);
 
     status = _cairo_surface_composite (CAIRO_OPERATOR_SOURCE,
 				       &pattern.base,
diff --git a/src/cairo-xcb-surface.c b/src/cairo-xcb-surface.c
index 9bd9d72..7251824 100644
--- a/src/cairo-xcb-surface.c
+++ b/src/cairo-xcb-surface.c
@@ -2332,7 +2332,7 @@ _cairo_xcb_surface_show_glyphs (void                *abstract_dst,
 
     cairo_xcb_surface_show_glyphs_func_t show_glyphs_func;
 
-    cairo_pattern_union_t solid_pattern;
+    cairo_solid_pattern_t solid_pattern;
 
     if (!CAIRO_SURFACE_RENDER_HAS_COMPOSITE_TEXT (dst) || dst->xrender_format.id == XCB_NONE)
 	return CAIRO_INT_STATUS_UNSUPPORTED;
@@ -2395,7 +2395,7 @@ _cairo_xcb_surface_show_glyphs (void                *abstract_dst,
      * so PictOpClear was never used with CompositeText before.
      */
     if (op == CAIRO_OPERATOR_CLEAR) {
-	_cairo_pattern_init_solid (&solid_pattern.solid, CAIRO_COLOR_WHITE,
+	_cairo_pattern_init_solid (&solid_pattern, CAIRO_COLOR_WHITE,
 				   CAIRO_CONTENT_COLOR);
 	src_pattern = &solid_pattern.base;
 	op = CAIRO_OPERATOR_DEST_OUT;
diff --git a/src/cairo-xlib-surface.c b/src/cairo-xlib-surface.c
index 1453082..8cc24c3 100644
--- a/src/cairo-xlib-surface.c
+++ b/src/cairo-xlib-surface.c
@@ -3586,7 +3586,7 @@ _cairo_xlib_surface_show_glyphs (void                *abstract_dst,
 
     cairo_xlib_surface_font_private_t *font_private;
 
-    cairo_pattern_union_t solid_pattern;
+    cairo_solid_pattern_t solid_pattern;
 
     if (!CAIRO_SURFACE_RENDER_HAS_COMPOSITE_TEXT (dst) || !dst->xrender_format)
 	return CAIRO_INT_STATUS_UNSUPPORTED;
@@ -3642,7 +3642,7 @@ _cairo_xlib_surface_show_glyphs (void                *abstract_dst,
      * so PictOpClear was never used with CompositeText before.
      */
     if (op == CAIRO_OPERATOR_CLEAR) {
-	_cairo_pattern_init_solid (&solid_pattern.solid, CAIRO_COLOR_WHITE,
+	_cairo_pattern_init_solid (&solid_pattern, CAIRO_COLOR_WHITE,
 				   CAIRO_CONTENT_COLOR);
 	src_pattern = &solid_pattern.base;
 	op = CAIRO_OPERATOR_DEST_OUT;
diff --git a/src/cairo.c b/src/cairo.c
index ec2616a..75f4dd8 100644
--- a/src/cairo.c
+++ b/src/cairo.c
@@ -1985,7 +1985,7 @@ cairo_paint_with_alpha (cairo_t *cr,
 {
     cairo_status_t status;
     cairo_color_t color;
-    cairo_pattern_union_t pattern;
+    cairo_solid_pattern_t pattern;
 
     if (cr->status)
 	return;
@@ -2000,7 +2000,7 @@ cairo_paint_with_alpha (cairo_t *cr,
     }
 
     _cairo_color_init_rgba (&color, 1., 1., 1., alpha);
-    _cairo_pattern_init_solid (&pattern.solid, &color, CAIRO_CONTENT_ALPHA);
+    _cairo_pattern_init_solid (&pattern, &color, CAIRO_CONTENT_ALPHA);
 
     status = _cairo_gstate_mask (cr->gstate, &pattern.base);
     if (status)
commit 74c1e9b5455cd14bfc077a5be2d45a47df666cd4
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Sat May 10 08:11:54 2008 +0100

    Trivial warning fixes to silence the compiler.

diff --git a/src/cairo-analysis-surface.c b/src/cairo-analysis-surface.c
index c19de4b..0ac37f0 100644
--- a/src/cairo-analysis-surface.c
+++ b/src/cairo-analysis-surface.c
@@ -759,6 +759,50 @@ _return_success (void)
     return CAIRO_STATUS_SUCCESS;
 }
 
+/* These typedefs are just to silence the compiler... */
+typedef cairo_int_status_t
+(*_set_clip_region_func)	(void			*surface,
+				 cairo_region_t		*region);
+typedef cairo_int_status_t
+(*_paint_func)			(void			*surface,
+			         cairo_operator_t	 op,
+				 cairo_pattern_t	*source);
+
+typedef cairo_int_status_t
+(*_mask_func)			(void			*surface,
+			         cairo_operator_t	 op,
+				 cairo_pattern_t	*source,
+				 cairo_pattern_t	*mask);
+
+typedef cairo_int_status_t
+(*_stroke_func)			(void			*surface,
+			         cairo_operator_t	 op,
+				 cairo_pattern_t	*source,
+				 cairo_path_fixed_t	*path,
+				 cairo_stroke_style_t	*style,
+				 cairo_matrix_t		*ctm,
+				 cairo_matrix_t		*ctm_inverse,
+				 double			 tolerance,
+				 cairo_antialias_t	 antialias);
+
+typedef cairo_int_status_t
+(*_fill_func)			(void			*surface,
+			         cairo_operator_t	 op,
+				 cairo_pattern_t	*source,
+				 cairo_path_fixed_t	*path,
+				 cairo_fill_rule_t	 fill_rule,
+				 double			 tolerance,
+				 cairo_antialias_t	 antialias);
+
+typedef cairo_int_status_t
+(*_show_glyphs_func)		(void			*surface,
+			         cairo_operator_t	 op,
+				 cairo_pattern_t	*source,
+				 cairo_glyph_t		*glyphs,
+				 int			 num_glyphs,
+				 cairo_scaled_font_t	*scaled_font,
+				 int			*remaining_glyphs);
+
 static const cairo_surface_backend_t cairo_null_surface_backend = {
     CAIRO_INTERNAL_SURFACE_TYPE_NULL,
 
@@ -774,7 +818,7 @@ static const cairo_surface_backend_t cairo_null_surface_backend = {
     NULL, /* composite_trapezoids */
     NULL, /* copy_page */
     NULL, /* show_page */
-    _return_success, /* set_clip_region */
+    (_set_clip_region_func) _return_success, /* set_clip_region */
     NULL, /* intersect_clip_path */
     NULL, /* get_extents */
     NULL, /* old_show_glyphs */
@@ -783,11 +827,11 @@ static const cairo_surface_backend_t cairo_null_surface_backend = {
     NULL, /* mark_dirty_rectangle */
     NULL, /* scaled_font_fini */
     NULL, /* scaled_glyph_fini */
-    _return_success, /* paint */
-    _return_success, /* mask */
-    _return_success, /* stroke */
-    _return_success, /* fill */
-    _return_success, /* show_glyphs */
+    (_paint_func) _return_success,	    /* paint */
+    (_mask_func) _return_success,	    /* mask */
+    (_stroke_func) _return_success,	    /* stroke */
+    (_fill_func) _return_success,	    /* fill */
+    (_show_glyphs_func) _return_success,    /* show_glyphs */
     NULL  /* snapshot */
 };
 
diff --git a/src/cairo-xlib-surface.c b/src/cairo-xlib-surface.c
index 562703e..1453082 100644
--- a/src/cairo-xlib-surface.c
+++ b/src/cairo-xlib-surface.c
@@ -1616,14 +1616,14 @@ _cairo_xlib_surface_solid_fill_rectangles (cairo_xlib_surface_t    *surface,
 					   cairo_rectangle_int_t   *rects,
 					   int			   num_rects)
 {
-    XGCValues gcv;
     GC xgc;
+    XGCValues gcv;
     int a_width=0, r_width=0, g_width=0, b_width=0;
     int a_shift=0, r_shift=0, g_shift=0, b_shift=0;
     int a = color->alpha_short >> 8;
-    int r = color->red_short >> 8;
+    int r = color->red_short   >> 8;
     int g = color->green_short >> 8;
-    int b = color->blue_short >> 8;
+    int b = color->blue_short  >> 8;
     int i;
 
     if (surface->visual->class == TrueColor) {
@@ -1651,9 +1651,8 @@ _cairo_xlib_surface_solid_fill_rectangles (cairo_xlib_surface_t    *surface,
 					       _field_from_8 (b, 3, 0)];
     }
 
-    xgc = XCreateGC (surface->dpy, surface->drawable, GCForeground,
-			&gcv);
-    if (!xgc)
+    xgc = XCreateGC (surface->dpy, surface->drawable, GCForeground, &gcv);
+    if (xgc == NULL)
 	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
 
     for (i = 0; i < num_rects; i++) {
@@ -1661,7 +1660,7 @@ _cairo_xlib_surface_solid_fill_rectangles (cairo_xlib_surface_t    *surface,
 			rects[i].x, rects[i].y,
 			rects[i].width, rects[i].height);
     }
-    XFreeGC(surface->dpy, xgc);
+    XFreeGC (surface->dpy, xgc);
 
     return CAIRO_STATUS_SUCCESS;
 }
@@ -1681,13 +1680,15 @@ _cairo_xlib_surface_fill_rectangles (void		     *abstract_surface,
 
     _cairo_xlib_display_notify (surface->screen_info->display);
 
-    if (!CAIRO_SURFACE_RENDER_HAS_FILL_RECTANGLE (surface)) {
+    if (! CAIRO_SURFACE_RENDER_HAS_FILL_RECTANGLE (surface)) {
 	if (op == CAIRO_OPERATOR_CLEAR ||
-	   ((op == CAIRO_OPERATOR_SOURCE || op == CAIRO_OPERATOR_OVER) &&
-	    CAIRO_COLOR_IS_OPAQUE(color))) {
-	    return _cairo_xlib_surface_solid_fill_rectangles(surface, color,
-							     rects, num_rects);
+	    ((op == CAIRO_OPERATOR_SOURCE || op == CAIRO_OPERATOR_OVER) &&
+	     CAIRO_COLOR_IS_OPAQUE (color)))
+	{
+	    return _cairo_xlib_surface_solid_fill_rectangles (surface, color,
+							      rects, num_rects);
 	}
+
 	return CAIRO_INT_STATUS_UNSUPPORTED;
     }
 
commit b235050316256b15f9547f2f587847c6a561c76c
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Fri May 9 11:26:39 2008 +0100

    [cairo-pattern] Generate an opaque solid colour if alpha >= 1.
    
    If the user supplies an alpha value of >= 1 to
    cairo_pattern_create_rgba(), substitute a call to
    cairo_pattern_create_rgb() instead.

diff --git a/src/cairo-pattern.c b/src/cairo-pattern.c
index b14a2de..89e92ca 100644
--- a/src/cairo-pattern.c
+++ b/src/cairo-pattern.c
@@ -449,6 +449,9 @@ cairo_pattern_create_rgba (double red, double green, double blue,
 {
     cairo_color_t color;
 
+    if (alpha >= 1.0)
+	return cairo_pattern_create_rgb (red, green, blue);
+
     _cairo_restrict_value (&red,   0.0, 1.0);
     _cairo_restrict_value (&green, 0.0, 1.0);
     _cairo_restrict_value (&blue,  0.0, 1.0);
commit 40e1aa60f2c0cd8c4b897c8e9806d1750632b43d
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Thu May 8 20:48:19 2008 +0100

    [cairo-pattern] Try to repaint the evicted surface from the solid surface cache.
    
    Behdad Esfahbod complained that commit
    8457374c9cf350841a7c16f1ef1657aeb354e5c9 overwhelmed the function with
    added complexity and arbitrary limited a backend to one-quarter of the
    cache. The elegant solution, he outlined, was to look at the surface that
    would be evicted and if possible repaint it, instead of creating a
    replacement. This not only simplifies the code, reduces the number of
    checks performed to find a match (or victim) and allows the cache to be
    naturally shared between the various backends.

diff --git a/src/cairo-pattern.c b/src/cairo-pattern.c
index 1e4c8c2..b14a2de 100644
--- a/src/cairo-pattern.c
+++ b/src/cairo-pattern.c
@@ -1403,8 +1403,6 @@ _cairo_pattern_acquire_surface_for_solid (cairo_solid_pattern_t	     *pattern,
 
     cairo_surface_t *surface;
     cairo_status_t   status;
-    char is_similar[MAX_SURFACE_CACHE_SIZE];
-    int count;
 
     CAIRO_MUTEX_LOCK (_cairo_pattern_solid_surface_cache_lock);
 
@@ -1421,77 +1419,68 @@ _cairo_pattern_acquire_surface_for_solid (cairo_solid_pattern_t	     *pattern,
 	goto DONE;
     }
 
-    count = 0;
     for (i = 0 ; i < solid_surface_cache.size; i++) {
-	const struct _cairo_pattern_solid_surface_cache *cache;
-
-	cache = &solid_surface_cache.cache[i];
-
-	if (CAIRO_REFERENCE_COUNT_GET_VALUE (&cache->surface->ref_count) != 1)
-	    continue;
-
-	if (! _cairo_surface_is_similar (cache->surface, dst, pattern->content))
-	    continue;
-
-	is_similar[count++] = i;
-
-	if (! _cairo_color_equal (&cache->color, &pattern->color))
-	    continue;
-
-	status = _cairo_surface_reset (cache->surface);
-	if (status)
-	    goto UNLOCK;
+	if (_cairo_pattern_solid_surface_matches (&solid_surface_cache.cache[i],
+		                                  pattern,
+						  dst))
+	{
+	    status = _cairo_surface_reset (solid_surface_cache.cache[i].surface);
+	    if (status)
+		goto UNLOCK;
 
-	goto DONE;
+	    goto DONE;
+	}
     }
 
-    /* Choose a surface to re-use (but only if we have an ample supply) */
-    if (i == MAX_SURFACE_CACHE_SIZE && count > MAX_SURFACE_CACHE_SIZE / 4) {
-	i = is_similar[rand () % count];
+    /* Choose a surface to repaint/evict */
+    surface = NULL;
+    if (solid_surface_cache.size == MAX_SURFACE_CACHE_SIZE) {
+	i = rand () % MAX_SURFACE_CACHE_SIZE;
 	surface = solid_surface_cache.cache[i].surface;
 
-	status = _cairo_surface_reset (surface);
-	if (status)
-	    goto UNLOCK;
-
-	status = _cairo_surface_paint (surface,
-		                       CAIRO_OPERATOR_SOURCE,
-				       &pattern->base);
-	if (status)
-	    goto UNLOCK;
-
-	goto SAVE;
+	if (CAIRO_REFERENCE_COUNT_GET_VALUE (&surface->ref_count) == 1 &&
+	    _cairo_surface_is_similar (surface, dst, pattern->content))
+	{
+	    status = _cairo_surface_reset (surface);
+	    if (status)
+		goto UNLOCK;
+
+	    status = _cairo_surface_paint (surface,
+					   CAIRO_OPERATOR_SOURCE,
+					   &pattern->base);
+	    if (status)
+		goto UNLOCK;
+	} else {
+	    /* Unable to reuse, evict */
+	    cairo_surface_destroy (surface);
+	    surface = NULL;
+	}
     }
 
-    /* Not cached, need to create new */
-    surface = _cairo_surface_create_similar_solid (dst,
-	                                           pattern->content,
-						   1, 1,
-						   &pattern->color,
-						   &pattern->base);
-    if (surface->status) {
-	status = surface->status;
-	goto UNLOCK;
-    }
+    if (surface == NULL) {
+	/* Not cached, need to create new */
+	surface = _cairo_surface_create_similar_solid (dst,
+						       pattern->content,
+						       1, 1,
+						       &pattern->color,
+						       &pattern->base);
+	if (surface->status) {
+	    status = surface->status;
+	    goto UNLOCK;
+	}
 
-    if (! _cairo_surface_is_similar (surface, dst, pattern->content)) {
-	/* in the rare event of a substitute surface being returned (e.g.
-	 * malloc failure) don't cache the fallback surface */
-	*out = surface;
-	goto NOCACHE;
+	if (! _cairo_surface_is_similar (surface, dst, pattern->content)) {
+	    /* in the rare event of a substitute surface being returned (e.g.
+	     * malloc failure) don't cache the fallback surface */
+	    *out = surface;
+	    goto NOCACHE;
+	}
     }
 
-    /* Cache new */
-    if (solid_surface_cache.size < MAX_SURFACE_CACHE_SIZE) {
-	solid_surface_cache.size++;
-    } else {
-	i = rand () % MAX_SURFACE_CACHE_SIZE;
-
-	/* Evict old */
-	cairo_surface_destroy (solid_surface_cache.cache[i].surface);
-    }
+    /* Increment after recursion by _cairo_surface_create_similar_solid() */
+    if (solid_surface_cache.size < MAX_SURFACE_CACHE_SIZE)
+	i = solid_surface_cache.size++;
 
-SAVE:
     solid_surface_cache.cache[i].color   = pattern->color;
     solid_surface_cache.cache[i].surface = surface;
 
commit ea79af728c2ac9c8ca8536010bb2b92cf366ab70
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Thu May 8 17:23:44 2008 +0100

    [cairo-xlib] Scan for a glyphset to match a pending free glyph.
    
    In order to avoid re-rasterising a glyph that is pending an
    XRenderFreeGlyph, we first scan all glyphsets and their arrays of
    pending_free_glyphs for a matching glyph. The additional cost of
    scanning the extra arrays should be negligble as most fonts will only
    have the single array (which we would scan anyway) but we potentially
    save an expensive rasterisation and short-lived image surface.
    
    (As suggested by Behdad Esfahbod.)

diff --git a/src/cairo-xlib-surface.c b/src/cairo-xlib-surface.c
index 0c29968..562703e 100644
--- a/src/cairo-xlib-surface.c
+++ b/src/cairo-xlib-surface.c
@@ -2990,6 +2990,71 @@ _cairo_xlib_scaled_font_get_glyphset_info_for_format (cairo_scaled_font_t *scale
     return glyphset_info;
 }
 
+static cairo_bool_t
+_cairo_xlib_glyphset_info_has_pending_free_glyph (
+				cairo_xlib_font_glyphset_info_t *glyphset_info,
+				unsigned long glyph_index)
+{
+    if (glyphset_info->pending_free_glyphs != NULL) {
+	cairo_xlib_font_glyphset_free_glyphs_t *to_free;
+	int i;
+
+	to_free = glyphset_info->pending_free_glyphs;
+	for (i = 0; i < to_free->glyph_count; i++) {
+	    if (to_free->glyph_indices[i] == glyph_index) {
+		to_free->glyph_count--;
+		memmove (&to_free->glyph_indices[i],
+			 &to_free->glyph_indices[i+1],
+			 (to_free->glyph_count - i) * sizeof (to_free->glyph_indices[0]));
+		return TRUE;
+	    }
+	}
+    }
+
+    return FALSE;
+}
+
+static cairo_xlib_font_glyphset_info_t *
+_cairo_xlib_scaled_font_get_glyphset_info_for_pending_free_glyph (
+					       cairo_scaled_font_t *scaled_font,
+					       unsigned long glyph_index,
+					       cairo_image_surface_t *surface)
+{
+    cairo_xlib_surface_font_private_t *font_private;
+    int i;
+
+    font_private = scaled_font->surface_private;
+    if (font_private == NULL)
+	return NULL;
+
+    if (surface != NULL) {
+	switch (surface->format) {
+	default:
+	case CAIRO_FORMAT_RGB24:
+	case CAIRO_FORMAT_ARGB32: i = GLYPHSET_INDEX_ARGB32; break;
+	case CAIRO_FORMAT_A8:     i = GLYPHSET_INDEX_A8;     break;
+	case CAIRO_FORMAT_A1:     i = GLYPHSET_INDEX_A1;     break;
+	}
+	if (_cairo_xlib_glyphset_info_has_pending_free_glyph (
+						&font_private->glyphset_info[i],
+						glyph_index))
+	{
+	    return &font_private->glyphset_info[i];
+	}
+    } else {
+	for (i = 0; i < NUM_GLYPHSETS; i++) {
+	    if (_cairo_xlib_glyphset_info_has_pending_free_glyph (
+						&font_private->glyphset_info[i],
+						glyph_index))
+	    {
+		return &font_private->glyphset_info[i];
+	    }
+	}
+    }
+
+    return NULL;
+}
+
 static cairo_status_t
 _cairo_xlib_surface_add_glyph (Display *dpy,
 			       cairo_scaled_font_t   *scaled_font,
@@ -3006,6 +3071,13 @@ _cairo_xlib_surface_add_glyph (Display *dpy,
 
     glyph_index = _cairo_scaled_glyph_index (scaled_glyph);
 
+    /* check to see if we have a pending XRenderFreeGlyph for this glyph */
+    glyphset_info = _cairo_xlib_scaled_font_get_glyphset_info_for_pending_free_glyph (scaled_font, glyph_index, glyph_surface);
+    if (glyphset_info != NULL) {
+	_cairo_xlib_scaled_glyph_set_glyphset_info (scaled_glyph, glyphset_info);
+	return CAIRO_STATUS_SUCCESS;
+    }
+
     if (!glyph_surface) {
 	status = _cairo_scaled_glyph_lookup (scaled_font,
 					     glyph_index,
@@ -3042,23 +3114,6 @@ _cairo_xlib_surface_add_glyph (Display *dpy,
 	    return CAIRO_INT_STATUS_UNSUPPORTED;
     }
 
-    /* check to see if we have a pending XRenderFreeGlyph for this glyph */
-    if (glyphset_info->pending_free_glyphs != NULL) {
-	cairo_xlib_font_glyphset_free_glyphs_t *to_free;
-	int i;
-
-	to_free = glyphset_info->pending_free_glyphs;
-	for (i = 0; i < to_free->glyph_count; i++) {
-	    if (to_free->glyph_indices[i] == glyph_index) {
-		to_free->glyph_count--;
-		memmove (&to_free->glyph_indices[i],
-			 &to_free->glyph_indices[i+1],
-			 (to_free->glyph_count - i) * sizeof (to_free->glyph_indices[0]));
-		goto DONE;
-	    }
-	}
-    }
-
     /* If the glyph surface has zero height or width, we create
      * a clear 1x1 surface, to avoid various X server bugs.
      */
@@ -3195,7 +3250,6 @@ _cairo_xlib_surface_add_glyph (Display *dpy,
     if (data != glyph_surface->data)
 	free (data);
 
- DONE:
     _cairo_xlib_scaled_glyph_set_glyphset_info (scaled_glyph, glyphset_info);
 
  BAIL:
commit c2963fa6c1f6da2117663d69505efb3bf2cc4145
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Thu May 8 09:02:12 2008 +0100

    [cairo-boilerplate] Silence compiler warning.
    
    Mark the optstr argument as const to silence a compiler warning in
    cairo-perf.

diff --git a/boilerplate/cairo-boilerplate-getopt.c b/boilerplate/cairo-boilerplate-getopt.c
index 6591598..be66ac2 100644
--- a/boilerplate/cairo-boilerplate-getopt.c
+++ b/boilerplate/cairo-boilerplate-getopt.c
@@ -94,7 +94,7 @@ static int permute_argv_once()
 }
 
 
-int _cairo_getopt(int argc, char** argv, char* optstr)
+int _cairo_getopt(int argc, char** argv, const char* optstr)
 {
 	int c = 0;
 
diff --git a/boilerplate/cairo-boilerplate-getopt.h b/boilerplate/cairo-boilerplate-getopt.h
index 6ed780c..74bce14 100644
--- a/boilerplate/cairo-boilerplate-getopt.h
+++ b/boilerplate/cairo-boilerplate-getopt.h
@@ -48,7 +48,7 @@ extern int optind;
 extern int opterr;
 extern int optopt;
 
-int _cairo_getopt(int argc, char** argv, char* optstr);
+int _cairo_getopt(int argc, char** argv, const char* optstr);
 
 
 #ifdef __cplusplus
commit ac44817c4a8464ed5c665cc8b20d1463cf8a5de3
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Thu May 8 09:00:56 2008 +0100

    [cairo-perf] Only allocate arrays once.
    
    Store the array of times on the cairo_perf_t context to avoid
    reallocating it for every perf-case.

diff --git a/perf/cairo-perf.c b/perf/cairo-perf.c
index bfc0240..a710f84 100644
--- a/perf/cairo-perf.c
+++ b/perf/cairo-perf.c
@@ -169,7 +169,7 @@ cairo_perf_run (cairo_perf_t		*perf,
 	first_run = FALSE;
     }
 
-    times = xmalloc (perf->iterations * sizeof (cairo_perf_ticks_t));
+    times = perf->times;
 
     has_similar = cairo_perf_has_similar (perf);
     for (similar = 0; similar <= has_similar; similar++) {
@@ -199,7 +199,7 @@ cairo_perf_run (cairo_perf_t		*perf,
 			    _content_to_string (perf->target->content, similar),
 			    name, perf->size,
 			    cairo_perf_ticks_per_second () / 1000.0);
-		printf (" %lld", times[i]);
+		printf (" %lld", (long long) times[i]);
 	    } else if (! perf->exact_iterations) {
 		if (i > 0) {
 		    _cairo_stats_compute (&stats, times, i+1);
@@ -226,7 +226,7 @@ cairo_perf_run (cairo_perf_t		*perf,
 		    name, perf->size);
 
 	    printf ("%10lld %#8.3f %#8.3f %#5.2f%% %3d\n",
-		    stats.min_ticks,
+		    (long long) stats.min_ticks,
 		    (stats.min_ticks * 1000.0) / cairo_perf_ticks_per_second (),
 		    (stats.median_ticks * 1000.0) / cairo_perf_ticks_per_second (),
 		    stats.std_dev * 100.0, stats.iterations);
@@ -234,7 +234,6 @@ cairo_perf_run (cairo_perf_t		*perf,
 
 	perf->test_number++;
     }
-    free (times);
 }
 
 static void
@@ -344,8 +343,10 @@ check_cpu_affinity(void)
 }
 
 static void
-cairo_perf_fini (void)
+cairo_perf_fini (cairo_perf_t *perf)
 {
+    cairo_boilerplate_free_targets (perf->targets);
+    free (perf->times);
     cairo_debug_reset_static_data ();
 #if HAVE_FCFINI
     FcFini ();
@@ -356,10 +357,9 @@ cairo_perf_fini (void)
 int
 main (int argc, char *argv[])
 {
-    int i, j, num_targets;
+    int i, j;
     cairo_perf_case_t *perf_case;
     cairo_perf_t perf;
-    cairo_boilerplate_target_t **targets;
     cairo_surface_t *surface;
 
     parse_options (&perf, argc, argv);
@@ -377,10 +377,11 @@ main (int argc, char *argv[])
             stderr);
     }
 
-    targets = cairo_boilerplate_get_targets (&num_targets, NULL);
+    perf.targets = cairo_boilerplate_get_targets (&perf.num_targets, NULL);
+    perf.times = xmalloc (perf.iterations * sizeof (cairo_perf_ticks_t));
 
-    for (i = 0; i < num_targets; i++) {
-        cairo_boilerplate_target_t *target = targets[i];
+    for (i = 0; i < perf.num_targets; i++) {
+        cairo_boilerplate_target_t *target = perf.targets[i];
 
 	if (! target_is_measurable (target))
 	    continue;
@@ -405,8 +406,7 @@ main (int argc, char *argv[])
 		    fprintf (stderr,
 			     "Error: Failed to create target surface: %s\n",
 			     target->name);
-		    cairo_boilerplate_free_targets (targets);
-		    cairo_perf_fini ();
+		    cairo_perf_fini (&perf);
 		    exit (1);
 		}
 
@@ -420,8 +420,7 @@ main (int argc, char *argv[])
 		if (cairo_status (perf.cr)) {
 		    fprintf (stderr, "Error: Test left cairo in an error state: %s\n",
 			     cairo_status_to_string (cairo_status (perf.cr)));
-		    cairo_boilerplate_free_targets (targets);
-		    cairo_perf_fini ();
+		    cairo_perf_fini (&perf);
 		    exit (1);
 		}
 
@@ -434,8 +433,7 @@ main (int argc, char *argv[])
 	}
     }
 
-    cairo_boilerplate_free_targets (targets);
-    cairo_perf_fini ();
+    cairo_perf_fini (&perf);
 
     return 0;
 }
diff --git a/perf/cairo-perf.h b/perf/cairo-perf.h
index 1ada06d..753f045 100644
--- a/perf/cairo-perf.h
+++ b/perf/cairo-perf.h
@@ -71,6 +71,9 @@ typedef struct _cairo_perf {
     unsigned int num_names;
 
     /* Stuff used internally */
+    cairo_perf_ticks_t *times;
+    cairo_boilerplate_target_t **targets;
+    int num_targets;
     cairo_boilerplate_target_t *target;
     unsigned int test_number;
     unsigned int size;
commit 335ed745898a3e110a4ffd1abd8f55edfb407639
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Wed May 7 09:34:49 2008 +0100

    Enlarge the embedded arrays to eliminate frequent allocations.
    
    Enlarge the embedded arrays of edges and points for cairo_polygon_t and
    cairo_spline_t respectively, such that the frequent allocations are
    eliminated whilst running a firefox3 benchmark.

diff --git a/src/cairo-polygon.c b/src/cairo-polygon.c
index 125d54d..1653f95 100644
--- a/src/cairo-polygon.c
+++ b/src/cairo-polygon.c
@@ -48,8 +48,8 @@ _cairo_polygon_init (cairo_polygon_t *polygon)
 
     polygon->num_edges = 0;
 
-    polygon->edges_size = 0;
-    polygon->edges = NULL;
+    polygon->edges = polygon->edges_embedded;
+    polygon->edges_size = ARRAY_LENGTH (polygon->edges_embedded);
 
     polygon->has_current_point = FALSE;
 }
@@ -79,26 +79,17 @@ _cairo_polygon_grow (cairo_polygon_t *polygon)
 {
     cairo_edge_t *new_edges;
     int old_size = polygon->edges_size;
-    int embedded_size = ARRAY_LENGTH (polygon->edges_embedded);
-    int new_size = 2 * MAX (old_size, 16);
-
-    /* we have a local buffer at polygon->edges_embedded.  try to fulfill the request
-     * from there. */
-    if (old_size < embedded_size) {
-	polygon->edges = polygon->edges_embedded;
-	polygon->edges_size = embedded_size;
-	return CAIRO_STATUS_SUCCESS;
-    }
+    int new_size = 2 * old_size;
 
     assert (polygon->num_edges <= polygon->edges_size);
 
     if (polygon->edges == polygon->edges_embedded) {
 	new_edges = _cairo_malloc_ab (new_size, sizeof (cairo_edge_t));
-	if (new_edges)
+	if (new_edges != NULL)
 	    memcpy (new_edges, polygon->edges, old_size * sizeof (cairo_edge_t));
     } else {
 	new_edges = _cairo_realloc_ab (polygon->edges,
-	       	                       new_size, sizeof (cairo_edge_t));
+		                       new_size, sizeof (cairo_edge_t));
     }
 
     if (new_edges == NULL)
diff --git a/src/cairo-types-private.h b/src/cairo-types-private.h
index 5bb9b58..0b66df2 100644
--- a/src/cairo-types-private.h
+++ b/src/cairo-types-private.h
@@ -255,7 +255,7 @@ typedef struct _cairo_polygon {
     int num_edges;
     int edges_size;
     cairo_edge_t *edges;
-    cairo_edge_t  edges_embedded[8];
+    cairo_edge_t  edges_embedded[32];
 } cairo_polygon_t;
 
 typedef struct _cairo_spline_knots {
@@ -270,7 +270,7 @@ typedef struct _cairo_spline {
     int num_points;
     int points_size;
     cairo_point_t *points;
-    cairo_point_t  points_embedded[8];
+    cairo_point_t  points_embedded[64];
 } cairo_spline_t;
 
 typedef struct _cairo_pen_vertex {
commit 963ff0b9485dbd4b3d5d1a65f6cdd73b170a6a79
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Wed May 7 09:32:29 2008 +0100

    [cairo-pen] Embed a small array of vertices into cairo_pen_t.
    
    Eliminate allocation of the vertex array for the common cases.

diff --git a/src/cairo-pen.c b/src/cairo-pen.c
index 37456d9..4a882d5 100644
--- a/src/cairo-pen.c
+++ b/src/cairo-pen.c
@@ -45,15 +45,6 @@ _cairo_pen_compute_slopes (cairo_pen_t *pen);
 static void
 _cairo_pen_stroke_spline_half (cairo_pen_t *pen, cairo_spline_t *spline, cairo_direction_t dir, cairo_polygon_t *polygon);
 
-void
-_cairo_pen_init_empty (cairo_pen_t *pen)
-{
-    pen->radius = 0;
-    pen->tolerance = 0;
-    pen->vertices = NULL;
-    pen->num_vertices = 0;
-}
-
 cairo_status_t
 _cairo_pen_init (cairo_pen_t	*pen,
 		 double		 radius,
@@ -78,10 +69,14 @@ _cairo_pen_init (cairo_pen_t	*pen,
 						    radius,
 						    ctm);
 
-    pen->vertices = _cairo_malloc_ab (pen->num_vertices,
-	                              sizeof (cairo_pen_vertex_t));
-    if (pen->vertices == NULL)
-	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+    if (pen->num_vertices > ARRAY_LENGTH (pen->vertices_embedded)) {
+	pen->vertices = _cairo_malloc_ab (pen->num_vertices,
+					  sizeof (cairo_pen_vertex_t));
+	if (pen->vertices == NULL)
+	    return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+    } else {
+	pen->vertices = pen->vertices_embedded;
+    }
 
     /*
      * Compute pen coordinates.  To generate the right ellipse, compute points around
@@ -107,10 +102,11 @@ _cairo_pen_init (cairo_pen_t	*pen,
 void
 _cairo_pen_fini (cairo_pen_t *pen)
 {
-    free (pen->vertices);
-    pen->vertices = NULL;
+    if (pen->vertices != pen->vertices_embedded)
+	free (pen->vertices);
 
-    _cairo_pen_init_empty (pen);
+    pen->vertices = pen->vertices_embedded;
+    pen->num_vertices = 0;
 }
 
 cairo_status_t
@@ -118,13 +114,17 @@ _cairo_pen_init_copy (cairo_pen_t *pen, cairo_pen_t *other)
 {
     *pen = *other;
 
+    pen->vertices = pen->vertices_embedded;
     if (pen->num_vertices) {
-	pen->vertices = _cairo_malloc_ab (pen->num_vertices,
-	       	                          sizeof (cairo_pen_vertex_t));
-	if (pen->vertices == NULL)
-	    return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+	if (pen->num_vertices > ARRAY_LENGTH (pen->vertices_embedded)) {
+	    pen->vertices = _cairo_malloc_ab (pen->num_vertices,
+					      sizeof (cairo_pen_vertex_t));
+	    if (pen->vertices == NULL)
+		return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+	}
 
-	memcpy (pen->vertices, other->vertices, pen->num_vertices * sizeof (cairo_pen_vertex_t));
+	memcpy (pen->vertices, other->vertices,
+		pen->num_vertices * sizeof (cairo_pen_vertex_t));
     }
 
     return CAIRO_STATUS_SUCCESS;
@@ -133,18 +133,35 @@ _cairo_pen_init_copy (cairo_pen_t *pen, cairo_pen_t *other)
 cairo_status_t
 _cairo_pen_add_points (cairo_pen_t *pen, cairo_point_t *point, int num_points)
 {
-    cairo_pen_vertex_t *vertices;
     cairo_status_t status;
     int num_vertices;
     int i;
 
     num_vertices = pen->num_vertices + num_points;
-    vertices = _cairo_realloc_ab (pen->vertices,
-	                          num_vertices, sizeof (cairo_pen_vertex_t));
-    if (vertices == NULL)
-	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+    if (num_vertices > ARRAY_LENGTH (pen->vertices_embedded) ||
+	pen->vertices != pen->vertices_embedded)
+    {
+	cairo_pen_vertex_t *vertices;
+
+	if (pen->vertices == pen->vertices_embedded) {
+	    vertices = _cairo_malloc_ab (num_vertices,
+		                         sizeof (cairo_pen_vertex_t));
+	    if (vertices == NULL)
+		return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+
+	    memcpy (vertices, pen->vertices,
+		    pen->num_vertices * sizeof (cairo_pen_vertex_t));
+	} else {
+	    vertices = _cairo_realloc_ab (pen->vertices,
+					  num_vertices,
+					  sizeof (cairo_pen_vertex_t));
+	    if (vertices == NULL)
+		return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+	}
+
+	pen->vertices = vertices;
+    }
 
-    pen->vertices = vertices;
     pen->num_vertices = num_vertices;
 
     /* initialize new vertices */
diff --git a/src/cairo-types-private.h b/src/cairo-types-private.h
index 6869c9f..5bb9b58 100644
--- a/src/cairo-types-private.h
+++ b/src/cairo-types-private.h
@@ -284,8 +284,9 @@ typedef struct _cairo_pen {
     double radius;
     double tolerance;
 
-    cairo_pen_vertex_t *vertices;
     int num_vertices;
+    cairo_pen_vertex_t *vertices;
+    cairo_pen_vertex_t  vertices_embedded[32];
 } cairo_pen_t;
 
 typedef struct _cairo_color cairo_color_t;
commit d9b2e8f0045dcde8beafed7fe08728ae15194ffa
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Wed May 7 09:20:17 2008 +0100

    [cairo-path-stroke] Avoid allocation for single rectangle.
    
    The most common case for path stroking is a single rectangle, so embed
    sufficient segments into the stroker to avoid an extra allocation.

diff --git a/src/cairo-path-stroke.c b/src/cairo-path-stroke.c
index 3032df5..d72ccf3 100644
--- a/src/cairo-path-stroke.c
+++ b/src/cairo-path-stroke.c
@@ -1191,9 +1191,10 @@ typedef struct _cairo_rectilinear_stroker
     cairo_point_t current_point;
     cairo_point_t first_point;
     cairo_bool_t open_sub_path;
-    cairo_line_t *segments;
-    int segments_size;
     int num_segments;
+    int segments_size;
+    cairo_line_t *segments;
+    cairo_line_t segments_embedded[8]; /* common case is a single rectangle */
 } cairo_rectilinear_stroker_t;
 
 static void
@@ -1206,15 +1207,16 @@ _cairo_rectilinear_stroker_init (cairo_rectilinear_stroker_t	*stroker,
 	_cairo_fixed_from_double (stroke_style->line_width / 2.0);
     stroker->traps = traps;
     stroker->open_sub_path = FALSE;
-    stroker->segments = NULL;
-    stroker->segments_size = 0;
+    stroker->segments = stroker->segments_embedded;
+    stroker->segments_size = ARRAY_LENGTH (stroker->segments_embedded);
     stroker->num_segments = 0;
 }
 
 static void
 _cairo_rectilinear_stroker_fini (cairo_rectilinear_stroker_t	*stroker)
 {
-    free (stroker->segments);
+    if (stroker->segments != stroker->segments_embedded)
+	free (stroker->segments);
 }
 
 static cairo_status_t
@@ -1222,18 +1224,24 @@ _cairo_rectilinear_stroker_add_segment (cairo_rectilinear_stroker_t	*stroker,
 					cairo_point_t			*p1,
 					cairo_point_t			*p2)
 {
-    int new_size;
-    cairo_line_t *new_segments;
 
     if (stroker->num_segments == stroker->segments_size) {
-	new_size = stroker->segments_size * 2;
-	/* Common case is one rectangle of exactly 4 segments. */
-	if (new_size == 0)
-	    new_size = 4;
-	new_segments = _cairo_realloc_ab (stroker->segments,
-	       	                          new_size, sizeof (cairo_line_t));
-	if (new_segments == NULL)
-	    return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+	int new_size = stroker->segments_size * 2;
+	cairo_line_t *new_segments;
+
+	if (stroker->segments == stroker->segments_embedded) {
+	    new_segments = _cairo_malloc_ab (new_size, sizeof (cairo_line_t));
+	    if (new_segments == NULL)
+		return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+
+	    memcpy (new_segments, stroker->segments,
+		    stroker->num_segments * sizeof (cairo_line_t));
+	} else {
+	    new_segments = _cairo_realloc_ab (stroker->segments,
+					      new_size, sizeof (cairo_line_t));
+	    if (new_segments == NULL)
+		return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+	}
 
 	stroker->segments_size = new_size;
 	stroker->segments = new_segments;
@@ -1390,8 +1398,7 @@ _cairo_rectilinear_stroker_line_to (void		*closure,
     if (a->x == b->x && a->y == b->y)
 	return CAIRO_STATUS_SUCCESS;
 
-    status = _cairo_rectilinear_stroker_add_segment (stroker,
-						     a, b);
+    status = _cairo_rectilinear_stroker_add_segment (stroker, a, b);
 
     stroker->current_point = *point;
     stroker->open_sub_path = TRUE;
commit ba6b2d092ab45e9d28ab5c016315458d1ad670ff
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Wed May 7 09:18:30 2008 +0100

    [cairo-hull] Attempt to allocate vertices on stack.
    
    First try to allocate the vertices using an on-stack array, otherwise, if
    we need more vertices than can be accomodated, fallback to using a heap
    array.

diff --git a/src/cairo-hull.c b/src/cairo-hull.c
index ccdb34d..77ee790 100644
--- a/src/cairo-hull.c
+++ b/src/cairo-hull.c
@@ -36,22 +36,20 @@
 
 #include "cairoint.h"
 
-typedef struct cairo_hull
-{
+typedef struct cairo_hull {
     cairo_point_t point;
     cairo_slope_t slope;
     int discard;
     int id;
 } cairo_hull_t;
 
-static cairo_status_t
-_cairo_hull_create (cairo_pen_vertex_t	     *vertices,
-	            int			      num_vertices,
-		    cairo_hull_t	    **out)
+static void
+_cairo_hull_init (cairo_hull_t			*hull,
+	          cairo_pen_vertex_t		*vertices,
+		  int				 num_vertices)
 {
-    int i;
-    cairo_hull_t *hull;
     cairo_point_t *p, *extremum, tmp;
+    int i;
 
     extremum = &vertices[0].point;
     for (i = 1; i < num_vertices; i++) {
@@ -64,10 +62,6 @@ _cairo_hull_create (cairo_pen_vertex_t	     *vertices,
     *extremum = vertices[0].point;
     vertices[0].point = tmp;
 
-    hull = _cairo_malloc_ab (num_vertices, sizeof (cairo_hull_t));
-    if (hull == NULL)
-	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
-
     for (i = 0; i < num_vertices; i++) {
 	hull[i].point = vertices[i].point;
 	_cairo_slope_init (&hull[i].slope, &hull[0].point, &hull[i].point);
@@ -82,9 +76,6 @@ _cairo_hull_create (cairo_pen_vertex_t	     *vertices,
 	if (i != 0 && hull[i].slope.dx == 0 && hull[i].slope.dy == 0)
 	    hull[i].discard = 1;
     }
-
-    *out = hull;
-    return CAIRO_STATUS_SUCCESS;
 }
 
 static int
@@ -196,13 +187,19 @@ _cairo_hull_to_pen (cairo_hull_t *hull, cairo_pen_vertex_t *vertices, int *num_v
 cairo_status_t
 _cairo_hull_compute (cairo_pen_vertex_t *vertices, int *num_vertices)
 {
-    cairo_status_t status;
-    cairo_hull_t *hull = NULL;
+    cairo_hull_t hull_stack[CAIRO_STACK_ARRAY_LENGTH (cairo_hull_t)];
+    cairo_hull_t *hull;
     int num_hull = *num_vertices;
 
-    status = _cairo_hull_create (vertices, num_hull, &hull);
-    if (status)
-	return status;
+    if (num_hull > ARRAY_LENGTH (hull_stack)) {
+	hull = _cairo_malloc_ab (num_hull, sizeof (cairo_hull_t));
+	if (hull == NULL)
+	    return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+    } else {
+	hull = hull_stack;
+    }
+
+    _cairo_hull_init (hull, vertices, num_hull);
 
     qsort (hull + 1, num_hull - 1,
 	   sizeof (cairo_hull_t), _cairo_hull_vertex_compare);
@@ -211,7 +208,8 @@ _cairo_hull_compute (cairo_pen_vertex_t *vertices, int *num_vertices)
 
     _cairo_hull_to_pen (hull, vertices, num_vertices);
 
-    free (hull);
+    if (hull != hull_stack)
+	free (hull);
 
     return CAIRO_STATUS_SUCCESS;
 }
commit b2eadb94f8e34d7c997b5ccfbca4d21e173fdd56
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Tue Apr 29 11:56:21 2008 +0100

    [cairo] Cache freed gstates.
    
    Reduce the malloc pressure from frequent cairo_save()/cairo_restore() by
    caching the freed gstates in a list on the context.

diff --git a/src/cairo-gstate.c b/src/cairo-gstate.c
index 5479231..7b12073 100644
--- a/src/cairo-gstate.c
+++ b/src/cairo-gstate.c
@@ -204,47 +204,6 @@ _cairo_gstate_fini (cairo_gstate_t *gstate)
     gstate->source = NULL;
 }
 
-static void
-_cairo_gstate_destroy (cairo_gstate_t *gstate)
-{
-    _cairo_gstate_fini (gstate);
-    free (gstate);
-}
-
-/**
- * _cairo_gstate_clone:
- * @other: a #cairo_gstate_t to be copied, not %NULL.
- *
- * Create a new #cairo_gstate_t setting all graphics state parameters
- * to the same values as contained in @other. gstate->next will be set
- * to %NULL and may be used by the caller to chain #cairo_gstate_t
- * objects together.
- *
- * Return value: a new #cairo_gstate_t or %NULL if there is insufficient
- * memory.
- **/
-static cairo_status_t
-_cairo_gstate_clone (cairo_gstate_t *other, cairo_gstate_t **out)
-{
-    cairo_status_t status;
-    cairo_gstate_t *gstate;
-
-    assert (other != NULL);
-
-    gstate = malloc (sizeof (cairo_gstate_t));
-    if (gstate == NULL)
-	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
-
-    status = _cairo_gstate_init_copy (gstate, other);
-    if (status) {
-	free (gstate);
-	return status;
-    }
-
-    *out = gstate;
-    return CAIRO_STATUS_SUCCESS;
-}
-
 /**
  * _cairo_gstate_save:
  * @gstate: input/output gstate pointer
@@ -254,14 +213,25 @@ _cairo_gstate_clone (cairo_gstate_t *other, cairo_gstate_t **out)
  * copy into @gstate.  _cairo_gstate_restore() reverses this.
  **/
 cairo_status_t
-_cairo_gstate_save (cairo_gstate_t **gstate)
+_cairo_gstate_save (cairo_gstate_t **gstate, cairo_gstate_t **freelist)
 {
-    cairo_gstate_t *top = NULL;
+    cairo_gstate_t *top;
     cairo_status_t status;
 
-    status = _cairo_gstate_clone (*gstate, &top);
-    if (status)
+    top = *freelist;
+    if (top == NULL) {
+	top = malloc (sizeof (cairo_gstate_t));
+	if (top == NULL)
+	    return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+    } else
+	*freelist = top->next;
+
+    status = _cairo_gstate_init_copy (top, *gstate);
+    if (status) {
+	top->next = *freelist;
+	*freelist = top;
 	return status;
+    }
 
     top->next = *gstate;
     *gstate = top;
@@ -276,7 +246,7 @@ _cairo_gstate_save (cairo_gstate_t **gstate)
  * Reverses the effects of one _cairo_gstate_save() call.
  **/
 cairo_status_t
-_cairo_gstate_restore (cairo_gstate_t **gstate)
+_cairo_gstate_restore (cairo_gstate_t **gstate, cairo_gstate_t **freelist)
 {
     cairo_gstate_t *top;
 
@@ -286,7 +256,9 @@ _cairo_gstate_restore (cairo_gstate_t **gstate)
 
     *gstate = top->next;
 
-    _cairo_gstate_destroy (top);
+    _cairo_gstate_fini (top);
+    top->next = *freelist;
+    *freelist = top;
 
     return CAIRO_STATUS_SUCCESS;
 }
diff --git a/src/cairo-private.h b/src/cairo-private.h
index a5faec8..43bd223 100644
--- a/src/cairo-private.h
+++ b/src/cairo-private.h
@@ -49,6 +49,7 @@ struct _cairo {
 
     cairo_gstate_t *gstate;
     cairo_gstate_t  gstate_tail[1];
+    cairo_gstate_t *gstate_freelist;
 
     cairo_path_fixed_t path[1];
 };
diff --git a/src/cairo.c b/src/cairo.c
index e001e70..ec2616a 100644
--- a/src/cairo.c
+++ b/src/cairo.c
@@ -52,7 +52,8 @@ static const cairo_t _cairo_nil = {
   {{				/* gstate_tail */
     0
   }},
-  {{ 				/* path */
+  NULL,				/* gstate_freelist */
+  {{				/* path */
     { 0, 0 },			/* last_move_point */
     { 0, 0 },			/* current point */
     FALSE,			/* has_current_point */
@@ -205,6 +206,7 @@ cairo_create (cairo_surface_t *target)
     _cairo_path_fixed_init (cr->path);
 
     cr->gstate = cr->gstate_tail;
+    cr->gstate_freelist = NULL;
     status = _cairo_gstate_init (cr->gstate, target);
 
     if (status)
@@ -260,11 +262,16 @@ cairo_destroy (cairo_t *cr)
 	return;
 
     while (cr->gstate != cr->gstate_tail) {
-	if (_cairo_gstate_restore (&cr->gstate))
+	if (_cairo_gstate_restore (&cr->gstate, &cr->gstate_freelist))
 	    break;
     }
 
     _cairo_gstate_fini (cr->gstate);
+    while (cr->gstate_freelist != NULL) {
+	cairo_gstate_t *gstate = cr->gstate_freelist;
+	cr->gstate_freelist = gstate->next;
+	free (gstate);
+    }
 
     _cairo_path_fixed_fini (cr->path);
 
@@ -371,10 +378,9 @@ cairo_save (cairo_t *cr)
     if (cr->status)
 	return;
 
-    status = _cairo_gstate_save (&cr->gstate);
-    if (status) {
+    status = _cairo_gstate_save (&cr->gstate, &cr->gstate_freelist);
+    if (status)
 	_cairo_set_error (cr, status);
-    }
 }
 slim_hidden_def(cairo_save);
 
@@ -394,10 +400,9 @@ cairo_restore (cairo_t *cr)
     if (cr->status)
 	return;
 
-    status = _cairo_gstate_restore (&cr->gstate);
-    if (status) {
+    status = _cairo_gstate_restore (&cr->gstate, &cr->gstate_freelist);
+    if (status)
 	_cairo_set_error (cr, status);
-    }
 }
 slim_hidden_def(cairo_restore);
 
diff --git a/src/cairoint.h b/src/cairoint.h
old mode 100755
new mode 100644
index b52b040..218afc0
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -952,10 +952,10 @@ cairo_private void
 _cairo_gstate_fini (cairo_gstate_t *gstate);
 
 cairo_private cairo_status_t
-_cairo_gstate_save (cairo_gstate_t **gstate);
+_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_restore (cairo_gstate_t **gstate, cairo_gstate_t **freelist);
 
 cairo_private cairo_bool_t
 _cairo_gstate_is_redirected (cairo_gstate_t *gstate);


More information about the cairo-commit mailing list