[cairo-commit] 4 commits - src/cairo-ft-font.c src/cairo-gl-glyphs.c src/cairo-gl-surface.c src/cairo-gstate.c src/cairo.h src/cairo-image-surface.c src/cairoint.h src/cairo-pattern.c src/cairo-pdf-surface.c src/cairo-scaled-font.c src/cairo-surface.c src/cairo-surface-private.h src/cairo-svg-surface.c src/cairo-types-private.h src/cairo-win32-font.c src/cairo-xlib-surface.c src/cairo-xlib-surface-private.h

Chris Wilson ickle at kemper.freedesktop.org
Wed Oct 21 03:39:44 PDT 2009


 src/cairo-ft-font.c              |    5 -
 src/cairo-gl-glyphs.c            |   23 ++++++--
 src/cairo-gl-surface.c           |   66 +++++++++++++++++--------
 src/cairo-gstate.c               |   17 ++++--
 src/cairo-image-surface.c        |  102 ++++++++++++++++-----------------------
 src/cairo-pattern.c              |   22 ++++++--
 src/cairo-pdf-surface.c          |   10 ++-
 src/cairo-scaled-font.c          |   14 +++--
 src/cairo-surface-private.h      |    6 +-
 src/cairo-surface.c              |   66 ++++++++++++++++++++++---
 src/cairo-svg-surface.c          |   10 ++-
 src/cairo-types-private.h        |   71 +++++++++++++++++++++++++++
 src/cairo-win32-font.c           |   10 +--
 src/cairo-xlib-surface-private.h |    1 
 src/cairo-xlib-surface.c         |   43 +++++++++++++---
 src/cairo.h                      |    9 +++
 src/cairoint.h                   |   70 --------------------------
 17 files changed, 342 insertions(+), 203 deletions(-)

New commits:
commit df357f26ff72571acb840715efa4930054d4fdbe
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Fri Oct 16 16:48:54 2009 +0100

    Support component-alpha.
    
    Within our code base we carried a few hacks to utilize the component
    alpha capabilities of pixman, whilst not supporting the concept for our
    own masks. Thus we were setting it upon the pixman_image_t that we
    passed around through code that was blissfully unaware and indeed the
    component-alpha property was forgotten (e.g. upgrading glyph masks).
    
    The real issue is that without explicit support that a pattern carries
    subpixel masking information, that information is lost when using that
    pattern with composite. Again we can look at the example of compositing
    a sub-pixel glyph mask onto a remote xlib surface for further failure.

diff --git a/src/cairo-ft-font.c b/src/cairo-ft-font.c
index 036bfa0..05f6562 100644
--- a/src/cairo-ft-font.c
+++ b/src/cairo-ft-font.c
@@ -802,7 +802,6 @@ _get_bitmap_surface (FT_Bitmap		     *bitmap,
     int width, height, stride;
     unsigned char *data;
     int format = CAIRO_FORMAT_A8;
-    cairo_bool_t subpixel = FALSE;
 
     width = bitmap->width;
     height = bitmap->rows;
@@ -970,7 +969,6 @@ _get_bitmap_surface (FT_Bitmap		     *bitmap,
 	    data = data_rgba;
 	    stride = stride_rgba;
 	    format = CAIRO_FORMAT_ARGB32;
-	    subpixel = TRUE;
 	    break;
 	}
 	}
@@ -993,9 +991,6 @@ _get_bitmap_surface (FT_Bitmap		     *bitmap,
 	return (*surface)->base.status;
     }
 
-    if (subpixel)
-	pixman_image_set_component_alpha ((*surface)->pixman_image, TRUE);
-
     _cairo_image_surface_assume_ownership_of_data ((*surface));
 
     _cairo_debug_check_image_surface_is_defined (&(*surface)->base);
diff --git a/src/cairo-gl-glyphs.c b/src/cairo-gl-glyphs.c
index ff599d8..4370fdb 100644
--- a/src/cairo-gl-glyphs.c
+++ b/src/cairo-gl-glyphs.c
@@ -341,6 +341,7 @@ _render_glyphs (cairo_gl_surface_t	*dst,
 		int			 num_glyphs,
 		const cairo_rectangle_int_t *glyph_extents,
 		cairo_scaled_font_t	*scaled_font,
+		cairo_bool_t		*has_component_alpha,
 		cairo_region_t		*clip_region,
 		int			*remaining_glyphs)
 {
@@ -353,6 +354,8 @@ _render_glyphs (cairo_gl_surface_t	*dst,
     int i = 0;
     GLuint vbo = 0;
 
+    *has_component_alpha = FALSE;
+
     status = _cairo_gl_operand_init (&composite_setup.src, source, dst,
 				     glyph_extents->x, glyph_extents->y,
 				     dst_x, dst_y,
@@ -376,6 +379,7 @@ _render_glyphs (cairo_gl_surface_t	*dst,
     glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
     glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
 
+    /* XXX component alpha */
     glTexEnvi (GL_TEXTURE_ENV, GL_SRC1_RGB, GL_TEXTURE1);
     glTexEnvi (GL_TEXTURE_ENV, GL_SRC1_ALPHA, GL_TEXTURE1);
     glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_ALPHA);
@@ -466,6 +470,10 @@ _render_glyphs (cairo_gl_surface_t	*dst,
 	    glBindTexture (GL_TEXTURE_2D, cache->tex);
 
 	    last_format = scaled_glyph->surface->format;
+	    if (last_format == CAIRO_FORMAT_ARGB32)
+		*has_component_alpha = TRUE;
+
+	    /* XXX component alpha */
 	}
 
 	if (scaled_glyph->surface_private == NULL) {
@@ -545,10 +553,11 @@ _cairo_gl_surface_show_glyphs_via_mask (cairo_gl_surface_t	*dst,
     cairo_surface_t *mask;
     cairo_status_t status;
     cairo_solid_pattern_t solid;
+    cairo_bool_t has_component_alpha;
     int i;
 
     mask = cairo_gl_surface_create (dst->ctx,
-	                            CAIRO_CONTENT_ALPHA,
+	                            CAIRO_CONTENT_COLOR_ALPHA,
 				    glyph_extents->width,
 				    glyph_extents->height);
     if (unlikely (mask->status))
@@ -559,15 +568,17 @@ _cairo_gl_surface_show_glyphs_via_mask (cairo_gl_surface_t	*dst,
 	glyphs[i].y -= glyph_extents->y;
     }
 
-    _cairo_pattern_init_solid (&solid, CAIRO_COLOR_WHITE, CAIRO_CONTENT_ALPHA);
+    _cairo_pattern_init_solid (&solid, CAIRO_COLOR_WHITE, CAIRO_CONTENT_COLOR_ALPHA);
     status = _render_glyphs ((cairo_gl_surface_t *) mask, 0, 0,
-	                     CAIRO_OPERATOR_ADD, &solid.base,
+	                     CAIRO_OPERATOR_SOURCE, &solid.base,
 	                     glyphs, num_glyphs, glyph_extents,
-			     scaled_font, NULL, remaining_glyphs);
+			     scaled_font, &has_component_alpha,
+			     NULL, remaining_glyphs);
     if (likely (status == CAIRO_STATUS_SUCCESS)) {
 	cairo_surface_pattern_t mask_pattern;
 
 	_cairo_pattern_init_for_surface (&mask_pattern, mask);
+	mask_pattern.base.has_component_alpha = has_component_alpha;
 	cairo_matrix_init_translate (&mask_pattern.base.matrix,
 		                     -glyph_extents->x, -glyph_extents->y);
 	status = _cairo_surface_mask (&dst->base, op,
@@ -601,6 +612,7 @@ _cairo_gl_surface_show_glyphs (void			*abstract_dst,
     cairo_region_t *clip_region = NULL;
     cairo_solid_pattern_t solid_pattern;
     cairo_bool_t overlap, use_mask = FALSE;
+    cairo_bool_t has_component_alpha;
     cairo_status_t status;
 
     if (! GLEW_ARB_vertex_buffer_object)
@@ -712,7 +724,8 @@ _cairo_gl_surface_show_glyphs (void			*abstract_dst,
     return _render_glyphs (dst, extents.x, extents.y,
 	                   op, source,
 			   glyphs, num_glyphs, &extents,
-			   scaled_font, clip_region, remaining_glyphs);
+			   scaled_font, &has_component_alpha,
+			   clip_region, remaining_glyphs);
 
 EMPTY:
     *remaining_glyphs = 0;
diff --git a/src/cairo-gl-surface.c b/src/cairo-gl-surface.c
index 29bf950..07b6d4d 100644
--- a/src/cairo-gl-surface.c
+++ b/src/cairo-gl-surface.c
@@ -1004,6 +1004,7 @@ _cairo_gl_pattern_surface_texture_setup (cairo_gl_composite_operand_t *operand,
     operand->operand.texture.tex = gl_surface->tex;
     operand->operand.texture.surface = NULL;
     attributes->matrix = src->base.matrix;
+    attributes->has_component_alpha = src->base.has_component_alpha;
     attributes->extend = src->base.extend;
     attributes->filter = src->base.filter;
     /* Demote the filter if we're doing a 1:1 mapping of pixels. */
@@ -1257,7 +1258,7 @@ _cairo_gl_set_src_operand (cairo_gl_context_t *ctx,
     switch (setup->src.type) {
     case OPERAND_CONSTANT:
 	_cairo_gl_set_tex_combine_constant_color (ctx, 0,
-	    setup->src.operand.constant.color);
+						  setup->src.operand.constant.color);
 	break;
     case OPERAND_TEXTURE:
 	_cairo_gl_set_texture_surface (0, setup->src.operand.texture.tex,
@@ -1317,6 +1318,13 @@ _cairo_gl_surface_composite (cairo_operator_t		  op,
     if (! _cairo_gl_operator_is_supported (op))
 	return CAIRO_INT_STATUS_UNSUPPORTED;
 
+    /* XXX: There is no sane way of expressing ComponentAlpha using
+     * fixed-function combiners and every possible operator. Look at the
+     * EXA drivers for the more appropriate fallback conditions.
+     */
+    if (mask && mask->has_component_alpha)
+	return CAIRO_INT_STATUS_UNSUPPORTED;
+
     memset (&setup, 0, sizeof (setup));
 
     status = _cairo_gl_operand_init (&setup.src, src, dst,
@@ -1327,9 +1335,6 @@ _cairo_gl_surface_composite (cairo_operator_t		  op,
 	return status;
     src_attributes = &setup.src.operand.texture.attributes;
 
-    if (mask != NULL && _cairo_pattern_is_opaque (mask))
-	mask = NULL;
-
     if (mask != NULL) {
 	status = _cairo_gl_operand_init (&setup.mask, mask, dst,
 					 mask_x, mask_y,
@@ -1352,13 +1357,13 @@ _cairo_gl_surface_composite (cairo_operator_t		  op,
 	switch (setup.mask.type) {
 	case OPERAND_CONSTANT:
 	    _cairo_gl_set_tex_combine_constant_color (ctx, 1,
-		setup.mask.operand.constant.color);
+						      setup.mask.operand.constant.color);
 	    break;
+
 	case OPERAND_TEXTURE:
 	    _cairo_gl_set_texture_surface (1, setup.mask.operand.texture.tex,
 					   mask_attributes);
 
-	    /* IN: dst.argb = src.argb * mask.aaaa */
 	    glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
 	    glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE);
 	    glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_MODULATE);
@@ -1368,6 +1373,7 @@ _cairo_gl_surface_composite (cairo_operator_t		  op,
 	    glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
 	    glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
 
+	    /* IN: dst.argb = src.argb * mask.aaaa */
 	    glTexEnvi (GL_TEXTURE_ENV, GL_SRC1_RGB, GL_TEXTURE1);
 	    glTexEnvi (GL_TEXTURE_ENV, GL_SRC1_ALPHA, GL_TEXTURE1);
 	    glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_ALPHA);
diff --git a/src/cairo-gstate.c b/src/cairo-gstate.c
index 7ee88d6..86e20bc 100644
--- a/src/cairo-gstate.c
+++ b/src/cairo-gstate.c
@@ -1002,17 +1002,22 @@ _cairo_gstate_mask (cairo_gstate_t  *gstate,
     _cairo_gstate_copy_transformed_source (gstate, &source_pattern.base);
     _cairo_gstate_copy_transformed_mask (gstate, &mask_pattern.base, mask);
 
-    /* XXX: This optimization assumes that there is no color
-     * information in mask, so this will need to change if we
-     * support RENDER-style 4-channel masks.
-     */
     if (source_pattern.type == CAIRO_PATTERN_TYPE_SOLID &&
 	mask_pattern.type == CAIRO_PATTERN_TYPE_SOLID)
     {
 	cairo_color_t combined;
 
-	combined = source_pattern.solid.color;
-	_cairo_color_multiply_alpha (&combined, mask_pattern.solid.color.alpha);
+	if (mask_pattern.base.has_component_alpha) {
+#define M(R, A, B, c) R.c = A.c * B.c
+	    M(combined, source_pattern.solid.color, mask_pattern.solid.color, red);
+	    M(combined, source_pattern.solid.color, mask_pattern.solid.color, green);
+	    M(combined, source_pattern.solid.color, mask_pattern.solid.color, blue);
+	    M(combined, source_pattern.solid.color, mask_pattern.solid.color, alpha);
+#undef M
+	} else {
+	    combined = source_pattern.solid.color;
+	    _cairo_color_multiply_alpha (&combined, mask_pattern.solid.color.alpha);
+	}
 
 	_cairo_pattern_init_solid (&source_pattern.solid, &combined,
 				   source_pattern.solid.content |
diff --git a/src/cairo-image-surface.c b/src/cairo-image-surface.c
index d4b607e..b0a26bf 100644
--- a/src/cairo-image-surface.c
+++ b/src/cairo-image-surface.c
@@ -931,36 +931,63 @@ _cairo_image_surface_set_filter (cairo_image_surface_t *surface,
 }
 
 static cairo_status_t
-_cairo_image_surface_set_attributes (cairo_image_surface_t      *surface,
-				     cairo_surface_attributes_t *attributes,
-				     double xc, double yc)
+_cairo_image_surface_set_extend (cairo_image_surface_t *surface,
+				 cairo_extend_t extend)
 {
-    cairo_int_status_t status;
-
-    status = _cairo_image_surface_set_matrix (surface, &attributes->matrix,
-					      xc, yc);
-    if (unlikely (status))
-	return status;
+    pixman_repeat_t pixman_repeat;
 
-    switch (attributes->extend) {
+    switch (extend) {
     case CAIRO_EXTEND_NONE:
-        pixman_image_set_repeat (surface->pixman_image, PIXMAN_REPEAT_NONE);
+	pixman_repeat = PIXMAN_REPEAT_NONE;
 	break;
     case CAIRO_EXTEND_REPEAT:
-        pixman_image_set_repeat (surface->pixman_image, PIXMAN_REPEAT_NORMAL);
+	pixman_repeat = PIXMAN_REPEAT_NORMAL;
 	break;
     case CAIRO_EXTEND_REFLECT:
-        pixman_image_set_repeat (surface->pixman_image, PIXMAN_REPEAT_REFLECT);
+	pixman_repeat = PIXMAN_REPEAT_REFLECT;
 	break;
     case CAIRO_EXTEND_PAD:
-        pixman_image_set_repeat (surface->pixman_image, PIXMAN_REPEAT_PAD);
+	pixman_repeat = PIXMAN_REPEAT_PAD;
 	break;
     }
 
+    pixman_image_set_repeat (surface->pixman_image, pixman_repeat);
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_image_surface_set_component_alpha (cairo_image_surface_t *surface,
+					  cairo_bool_t ca)
+{
+    pixman_image_set_component_alpha (surface->pixman_image, ca);
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_image_surface_set_attributes (cairo_image_surface_t      *surface,
+				     cairo_surface_attributes_t *attributes,
+				     double xc, double yc)
+{
+    cairo_int_status_t status;
+
+    status = _cairo_image_surface_set_matrix (surface, &attributes->matrix,
+					      xc, yc);
+    if (unlikely (status))
+	return status;
+
     status = _cairo_image_surface_set_filter (surface, attributes->filter);
     if (unlikely (status))
 	return status;
 
+    status = _cairo_image_surface_set_extend (surface, attributes->extend);
+    if (unlikely (status))
+	return status;
+
+    status = _cairo_image_surface_set_component_alpha (surface,
+						       attributes->has_component_alpha);
+    if (unlikely (status))
+	return status;
+
     return CAIRO_STATUS_SUCCESS;
 }
 
diff --git a/src/cairo-pattern.c b/src/cairo-pattern.c
index d72867a..a566183 100644
--- a/src/cairo-pattern.c
+++ b/src/cairo-pattern.c
@@ -129,6 +129,8 @@ _cairo_pattern_init (cairo_pattern_t *pattern, cairo_pattern_type_t type)
 
     pattern->filter    = CAIRO_FILTER_DEFAULT;
 
+    pattern->has_component_alpha = FALSE;
+
     cairo_matrix_init_identity (&pattern->matrix);
 }
 
@@ -1522,6 +1524,7 @@ _cairo_pattern_acquire_surface_for_gradient (const cairo_gradient_pattern_t *pat
 	attr->matrix = matrix;
 	attr->extend = pattern->base.extend;
 	attr->filter = CAIRO_FILTER_NEAREST;
+	attr->has_component_alpha = pattern->base.has_component_alpha;
 
 	*out = &image->base;
 
@@ -1615,6 +1618,7 @@ _cairo_pattern_acquire_surface_for_gradient (const cairo_gradient_pattern_t *pat
     cairo_matrix_init_identity (&attr->matrix);
     attr->extend = repeat ? CAIRO_EXTEND_REPEAT : CAIRO_EXTEND_NONE;
     attr->filter = CAIRO_FILTER_NEAREST;
+    attr->has_component_alpha = pattern->base.has_component_alpha;
 
     return status;
 }
@@ -1759,6 +1763,7 @@ NOCACHE:
     cairo_matrix_init_identity (&attribs->matrix);
     attribs->extend = CAIRO_EXTEND_REPEAT;
     attribs->filter = CAIRO_FILTER_NEAREST;
+    attribs->has_component_alpha = pattern->base.has_component_alpha;
 
     status = CAIRO_STATUS_SUCCESS;
 
@@ -1845,6 +1850,9 @@ _cairo_pattern_is_opaque (const cairo_pattern_t *abstract_pattern)
 {
     const cairo_pattern_union_t *pattern;
 
+    if (abstract_pattern->has_component_alpha)
+	return FALSE;
+
     pattern = (cairo_pattern_union_t *) abstract_pattern;
     switch (pattern->base.type) {
     case CAIRO_PATTERN_TYPE_SOLID:
@@ -1953,6 +1961,7 @@ _cairo_pattern_acquire_surface_for_surface (const cairo_surface_pattern_t   *pat
     attr->matrix = pattern->base.matrix;
     attr->extend = pattern->base.extend;
     attr->filter = _cairo_pattern_analyze_filter (&pattern->base, &pad);
+    attr->has_component_alpha = pattern->base.has_component_alpha;
 
     attr->x_offset = attr->y_offset = tx = ty = 0;
     if (_cairo_matrix_is_integer_translation (&attr->matrix, &tx, &ty)) {
@@ -2370,11 +2379,10 @@ _cairo_pattern_acquire_surfaces (const cairo_pattern_t	    *src,
     /* If src and mask are both solid, then the mask alpha can be
      * combined into src and mask can be ignored. */
 
-    /* XXX: This optimization assumes that there is no color
-     * information in mask, so this will need to change when we
-     * support RENDER-style 4-channel masks. */
     if (src->type == CAIRO_PATTERN_TYPE_SOLID &&
-	mask && mask->type == CAIRO_PATTERN_TYPE_SOLID)
+	mask &&
+	! mask->has_component_alpha &&
+	mask->type == CAIRO_PATTERN_TYPE_SOLID)
     {
 	cairo_color_t combined;
 	cairo_solid_pattern_t *src_solid = (cairo_solid_pattern_t *) src;
@@ -2651,6 +2659,9 @@ _cairo_pattern_hash (const cairo_pattern_t *pattern)
 				  &pattern->filter, sizeof (pattern->filter));
 	hash = _cairo_hash_bytes (hash,
 				  &pattern->extend, sizeof (pattern->extend));
+	hash = _cairo_hash_bytes (hash,
+				  &pattern->has_component_alpha,
+				  sizeof (pattern->has_component_alpha));
     }
 
     switch (pattern->type) {
@@ -2808,6 +2819,9 @@ _cairo_pattern_equal (const cairo_pattern_t *a, const cairo_pattern_t *b)
     if (a->type != b->type)
 	return FALSE;
 
+    if (a->has_component_alpha != b->has_component_alpha)
+	return FALSE;
+
     if (a->type != CAIRO_PATTERN_TYPE_SOLID) {
 	if (memcmp (&a->matrix, &b->matrix, sizeof (cairo_matrix_t)))
 	    return FALSE;
diff --git a/src/cairo-pdf-surface.c b/src/cairo-pdf-surface.c
index 896980a..60ebfe5 100644
--- a/src/cairo-pdf-surface.c
+++ b/src/cairo-pdf-surface.c
@@ -5433,9 +5433,13 @@ _cairo_pdf_surface_mask	(void			*abstract_surface,
 	if (_cairo_status_is_error (source_status))
 	    return source_status;
 
-	mask_status = _cairo_pdf_surface_analyze_operation (surface, op, mask);
-	if (_cairo_status_is_error (mask_status))
-	    return mask_status;
+	if (mask->has_component_alpha) {
+	    mask_status = CAIRO_INT_STATUS_UNSUPPORTED;
+	} else {
+	    mask_status = _cairo_pdf_surface_analyze_operation (surface, op, mask);
+	    if (_cairo_status_is_error (mask_status))
+		return mask_status;
+	}
 
 	return _cairo_analysis_surface_merge_status (source_status,
 						     mask_status);
diff --git a/src/cairo-scaled-font.c b/src/cairo-scaled-font.c
index 199ad39..179844f 100644
--- a/src/cairo-scaled-font.c
+++ b/src/cairo-scaled-font.c
@@ -2169,8 +2169,10 @@ _cairo_scaled_font_show_glyphs (cairo_scaled_font_t	*scaled_font,
 	    }
 
 	    _cairo_pattern_init_for_surface (&mask_pattern, mask);
-
-	    status = _cairo_surface_composite (CAIRO_OPERATOR_ADD,
+	    /* Note that we only upgrade masks, i.e. A1 -> A8 -> ARGB32, so there is
+	     * never any component alpha here.
+	     */
+	    status = _cairo_surface_composite (CAIRO_OPERATOR_SOURCE,
 					       &white_pattern.base,
 					       &mask_pattern.base,
 					       new_mask,
@@ -2203,6 +2205,8 @@ _cairo_scaled_font_show_glyphs (cairo_scaled_font_t	*scaled_font,
 
 	    _cairo_pattern_init_for_surface (&glyph_pattern,
 					     &glyph_surface->base);
+	    if (mask_format == CAIRO_FORMAT_ARGB32)
+		glyph_pattern.base.has_component_alpha = TRUE;
 
 	    status = _cairo_surface_composite (CAIRO_OPERATOR_ADD,
 					       &white_pattern.base,
@@ -2222,11 +2226,9 @@ _cairo_scaled_font_show_glyphs (cairo_scaled_font_t	*scaled_font,
 	}
     }
 
-    if (mask_format == CAIRO_FORMAT_ARGB32) {
-	pixman_image_set_component_alpha (((cairo_image_surface_t*) mask)->
-					  pixman_image, TRUE);
-    }
     _cairo_pattern_init_for_surface (&mask_pattern, mask);
+    if (mask_format == CAIRO_FORMAT_ARGB32)
+	mask_pattern.base.has_component_alpha = TRUE;
 
     status = _cairo_surface_composite (op, pattern, &mask_pattern.base,
 				       surface,
diff --git a/src/cairo-svg-surface.c b/src/cairo-svg-surface.c
index 26ae3d9..6277af1 100644
--- a/src/cairo-svg-surface.c
+++ b/src/cairo-svg-surface.c
@@ -2262,9 +2262,13 @@ _cairo_svg_surface_mask (void		    *abstract_surface,
 	if (_cairo_status_is_error (source_status))
 	    return source_status;
 
-	mask_status = _cairo_svg_surface_analyze_operation (surface, op, mask);
-	if (_cairo_status_is_error (mask_status))
-	    return mask_status;
+	if (mask->has_component_alpha) {
+	    mask_status = CAIRO_INT_STATUS_UNSUPPORTED;
+	} else {
+	    mask_status = _cairo_svg_surface_analyze_operation (surface, op, mask);
+	    if (_cairo_status_is_error (mask_status))
+		return mask_status;
+	}
 
 	return _cairo_analysis_surface_merge_status (source_status,
 						     mask_status);
diff --git a/src/cairo-types-private.h b/src/cairo-types-private.h
index 82754cf..16b27c2 100644
--- a/src/cairo-types-private.h
+++ b/src/cairo-types-private.h
@@ -340,4 +340,75 @@ struct _cairo_mime_data {
     void *closure;
 };
 
+struct _cairo_pattern {
+    cairo_pattern_type_t	type;
+    cairo_reference_count_t	ref_count;
+    cairo_status_t		status;
+    cairo_user_data_array_t	user_data;
+
+    cairo_matrix_t		matrix;
+    cairo_filter_t		filter;
+    cairo_extend_t		extend;
+
+    cairo_bool_t		has_component_alpha;
+};
+
+struct _cairo_solid_pattern {
+    cairo_pattern_t base;
+    cairo_color_t color;
+    cairo_content_t content;
+};
+
+typedef struct _cairo_surface_pattern {
+    cairo_pattern_t base;
+
+    cairo_surface_t *surface;
+} cairo_surface_pattern_t;
+
+typedef struct _cairo_gradient_stop {
+    double offset;
+    cairo_color_t color;
+} cairo_gradient_stop_t;
+
+typedef struct _cairo_gradient_pattern {
+    cairo_pattern_t base;
+
+    unsigned int	    n_stops;
+    unsigned int	    stops_size;
+    cairo_gradient_stop_t  *stops;
+    cairo_gradient_stop_t   stops_embedded[2];
+} cairo_gradient_pattern_t;
+
+typedef struct _cairo_linear_pattern {
+    cairo_gradient_pattern_t base;
+
+    cairo_point_t p1;
+    cairo_point_t p2;
+} cairo_linear_pattern_t;
+
+typedef struct _cairo_radial_pattern {
+    cairo_gradient_pattern_t base;
+
+    cairo_point_t c1;
+    cairo_fixed_t r1;
+    cairo_point_t c2;
+    cairo_fixed_t r2;
+} cairo_radial_pattern_t;
+
+typedef union {
+    cairo_gradient_pattern_t base;
+
+    cairo_linear_pattern_t linear;
+    cairo_radial_pattern_t radial;
+} cairo_gradient_pattern_union_t;
+
+typedef union {
+    cairo_pattern_type_t	    type;
+    cairo_pattern_t		    base;
+
+    cairo_solid_pattern_t	    solid;
+    cairo_surface_pattern_t	    surface;
+    cairo_gradient_pattern_union_t  gradient;
+} cairo_pattern_union_t;
+
 #endif /* CAIRO_TYPES_PRIVATE_H */
diff --git a/src/cairo-win32-font.c b/src/cairo-win32-font.c
index 216c751..7a86cc8 100644
--- a/src/cairo-win32-font.c
+++ b/src/cairo-win32-font.c
@@ -1437,10 +1437,6 @@ _cairo_win32_scaled_font_show_glyphs (void			*abstract_font,
 		_invert_argb32_mask (tmp_surface);
 
 	    mask_surface = &tmp_surface->base;
-
-	    /* XXX: Hacky, should expose this in cairo_image_surface */
-	    pixman_image_set_component_alpha (((cairo_image_surface_t *)tmp_surface->image)->pixman_image, TRUE);
-
 	} else {
 	    mask_surface = _compute_a8_mask (tmp_surface);
 	    cairo_surface_destroy (&tmp_surface->base);
@@ -1454,6 +1450,10 @@ _cairo_win32_scaled_font_show_glyphs (void			*abstract_font,
 	 * destination
 	 */
 	_cairo_pattern_init_for_surface (&mask, mask_surface);
+	cairo_surface_destroy (mask_surface);
+
+	if (scaled_font->quality == CLEARTYPE_QUALITY)
+	    mask.base.has_component_alpha = TRUE;
 
 	status = _cairo_surface_composite (op, pattern,
 					   &mask.base,
@@ -1466,8 +1466,6 @@ _cairo_win32_scaled_font_show_glyphs (void			*abstract_font,
 
 	_cairo_pattern_fini (&mask.base);
 
-	cairo_surface_destroy (mask_surface);
-
 	return status;
     }
 }
diff --git a/src/cairo-xlib-surface-private.h b/src/cairo-xlib-surface-private.h
index 92107e7..b30848d 100644
--- a/src/cairo-xlib-surface-private.h
+++ b/src/cairo-xlib-surface-private.h
@@ -95,6 +95,7 @@ struct _cairo_xlib_surface {
     XRenderPictFormat *xrender_format;
     cairo_filter_t filter;
     cairo_extend_t extend;
+    cairo_bool_t has_component_alpha;
     XTransform xtransform;
 
     uint32_t a_mask;
diff --git a/src/cairo-xlib-surface.c b/src/cairo-xlib-surface.c
index 994a4f9..8965373 100644
--- a/src/cairo-xlib-surface.c
+++ b/src/cairo-xlib-surface.c
@@ -1539,11 +1539,11 @@ _cairo_xlib_surface_set_filter (cairo_xlib_surface_t *surface,
 }
 
 static cairo_status_t
-_cairo_xlib_surface_set_repeat (cairo_xlib_surface_t *surface,
-				cairo_extend_t extend)
+_cairo_xlib_surface_set_repeat (cairo_xlib_surface_t	*surface,
+				cairo_extend_t		 extend,
+				unsigned long		*mask,
+				XRenderPictureAttributes *pa)
 {
-    XRenderPictureAttributes pa;
-    unsigned long	     mask;
     int repeat;
 
     if (surface->extend == extend)
@@ -1573,12 +1573,26 @@ _cairo_xlib_surface_set_repeat (cairo_xlib_surface_t *surface,
 	return CAIRO_INT_STATUS_UNSUPPORTED;
     }
 
-    mask = CPRepeat;
-    pa.repeat = repeat;
+    *mask |= CPRepeat;
+    pa->repeat = repeat;
 
-    XRenderChangePicture (surface->dpy, surface->src_picture, mask, &pa);
     surface->extend = extend;
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_xlib_surface_set_component_alpha (cairo_xlib_surface_t *surface,
+					 cairo_bool_t		ca,
+					 unsigned long		*mask,
+					 XRenderPictureAttributes *pa)
+{
+    if (surface->has_component_alpha == ca)
+	return CAIRO_STATUS_SUCCESS;
 
+    *mask |= CPComponentAlpha;
+    pa->component_alpha = ca;
+
+    surface->has_component_alpha = ca;
     return CAIRO_STATUS_SUCCESS;
 }
 
@@ -1589,6 +1603,8 @@ _cairo_xlib_surface_set_attributes (cairo_xlib_surface_t	    *surface,
 				    double			     yc)
 {
     cairo_int_status_t status;
+    XRenderPictureAttributes pa;
+    unsigned long mask = 0;
 
     _cairo_xlib_surface_ensure_src_picture (surface);
 
@@ -1597,7 +1613,14 @@ _cairo_xlib_surface_set_attributes (cairo_xlib_surface_t	    *surface,
     if (unlikely (status))
 	return status;
 
-    status = _cairo_xlib_surface_set_repeat (surface, attributes->extend);
+    status = _cairo_xlib_surface_set_repeat (surface, attributes->extend,
+					     &mask, &pa);
+    if (unlikely (status))
+	return status;
+
+    status = _cairo_xlib_surface_set_component_alpha (surface,
+						      attributes->has_component_alpha,
+						      &mask, &pa);
     if (unlikely (status))
 	return status;
 
@@ -1605,6 +1628,9 @@ _cairo_xlib_surface_set_attributes (cairo_xlib_surface_t	    *surface,
     if (unlikely (status))
 	return status;
 
+    if (mask)
+	XRenderChangePicture (surface->dpy, surface->src_picture, mask, &pa);
+
     return CAIRO_STATUS_SUCCESS;
 }
 
@@ -2946,6 +2972,7 @@ found:
     surface->depth = depth;
     surface->filter = CAIRO_FILTER_NEAREST;
     surface->extend = CAIRO_EXTEND_NONE;
+    surface->has_component_alpha = FALSE;
     surface->xtransform = identity;
 
     surface->clip_region = NULL;
diff --git a/src/cairoint.h b/src/cairoint.h
index fc1046e..c309f3d 100644
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -871,81 +871,14 @@ extern const cairo_private cairo_surface_backend_t _cairo_image_surface_backend;
 #define CAIRO_EXTEND_GRADIENT_DEFAULT CAIRO_EXTEND_PAD
 #define CAIRO_FILTER_DEFAULT CAIRO_FILTER_GOOD
 
-struct _cairo_pattern {
-    cairo_pattern_type_t	type;
-    cairo_reference_count_t	ref_count;
-    cairo_status_t		status;
-    cairo_user_data_array_t	user_data;
-
-    cairo_matrix_t		matrix;
-    cairo_filter_t		filter;
-    cairo_extend_t		extend;
-};
-
-struct _cairo_solid_pattern {
-    cairo_pattern_t base;
-    cairo_color_t color;
-    cairo_content_t content;
-};
-
 extern const cairo_private cairo_solid_pattern_t _cairo_pattern_black;
 
-typedef struct _cairo_surface_pattern {
-    cairo_pattern_t base;
-
-    cairo_surface_t *surface;
-} cairo_surface_pattern_t;
-
-typedef struct _cairo_gradient_stop {
-    double offset;
-    cairo_color_t color;
-} cairo_gradient_stop_t;
-
-typedef struct _cairo_gradient_pattern {
-    cairo_pattern_t base;
-
-    unsigned int	    n_stops;
-    unsigned int	    stops_size;
-    cairo_gradient_stop_t  *stops;
-    cairo_gradient_stop_t   stops_embedded[2];
-} cairo_gradient_pattern_t;
-
-typedef struct _cairo_linear_pattern {
-    cairo_gradient_pattern_t base;
-
-    cairo_point_t p1;
-    cairo_point_t p2;
-} cairo_linear_pattern_t;
-
-typedef struct _cairo_radial_pattern {
-    cairo_gradient_pattern_t base;
-
-    cairo_point_t c1;
-    cairo_fixed_t r1;
-    cairo_point_t c2;
-    cairo_fixed_t r2;
-} cairo_radial_pattern_t;
-
-typedef union {
-    cairo_gradient_pattern_t base;
-
-    cairo_linear_pattern_t linear;
-    cairo_radial_pattern_t radial;
-} cairo_gradient_pattern_union_t;
-
-typedef union {
-    cairo_pattern_type_t	    type;
-    cairo_pattern_t		    base;
-
-    cairo_solid_pattern_t	    solid;
-    cairo_surface_pattern_t	    surface;
-    cairo_gradient_pattern_union_t  gradient;
-} cairo_pattern_union_t;
 
 typedef struct _cairo_surface_attributes {
     cairo_matrix_t matrix;
     cairo_extend_t extend;
     cairo_filter_t filter;
+    cairo_bool_t has_component_alpha;
     int		   x_offset;
     int		   y_offset;
     void	   *extra;
commit f0cd20e6cec445eb627c2708c2230c8bad1b64ce
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Wed Oct 21 10:36:27 2009 +0100

    [gl] Do not clear internal surfaces.
    
    Create a scratch surface that will be initialised as required for
    internal use. External surfaces, i.e. those returned to the user, are
    cleared as normal.

diff --git a/src/cairo-gl-surface.c b/src/cairo-gl-surface.c
index 5d4853d..29bf950 100644
--- a/src/cairo-gl-surface.c
+++ b/src/cairo-gl-surface.c
@@ -450,28 +450,20 @@ _cairo_gl_surface_init (cairo_gl_context_t *ctx,
     surface->height = height;
 }
 
-cairo_surface_t *
-cairo_gl_surface_create (cairo_gl_context_t   *ctx,
-			 cairo_content_t	content,
-			 int			width,
-			 int			height)
+static cairo_surface_t *
+_cairo_gl_surface_create_scratch (cairo_gl_context_t   *ctx,
+				  cairo_content_t	content,
+				  int			width,
+				  int			height)
 {
     cairo_gl_surface_t *surface;
     GLenum err, format;
     cairo_status_t status;
 
-    if (!CAIRO_CONTENT_VALID (content))
-	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_CONTENT));
-
-    if (ctx == NULL) {
-	return cairo_image_surface_create (_cairo_format_from_content (content),
-					   width, height);
-    }
     if (ctx->status)
 	return _cairo_surface_create_in_error (ctx->status);
 
-    if (width > ctx->max_framebuffer_size || height > ctx->max_framebuffer_size)
-	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_SIZE));
+    assert (width <= ctx->max_framebuffer_size && height <= ctx->max_framebuffer_size);
 
     surface = calloc (1, sizeof (cairo_gl_surface_t));
     if (unlikely (surface == NULL))
@@ -520,6 +512,30 @@ cairo_gl_surface_create (cairo_gl_context_t   *ctx,
     if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
 	fprintf (stderr, "destination is framebuffer incomplete\n");
 
+    return &surface->base;
+}
+
+cairo_surface_t *
+cairo_gl_surface_create (cairo_gl_context_t   *ctx,
+			 cairo_content_t	content,
+			 int			width,
+			 int			height)
+{
+    cairo_gl_surface_t *surface;
+
+    if (!CAIRO_CONTENT_VALID (content))
+	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_CONTENT));
+
+    if (ctx == NULL) {
+	return cairo_image_surface_create (_cairo_format_from_content (content),
+					   width, height);
+    }
+
+    surface = (cairo_gl_surface_t *)
+	_cairo_gl_surface_create_scratch (ctx, content, width, height);
+    if (unlikely (surface->base.status))
+	return &surface->base;
+
     /* Cairo surfaces start out initialized to transparent (black) */
     ctx = _cairo_gl_context_acquire (surface->ctx);
     _cairo_gl_set_destination (surface);
@@ -611,7 +627,7 @@ _cairo_gl_surface_create_similar (void		 *abstract_surface,
     if (height < 1)
 	height = 1;
 
-    return cairo_gl_surface_create (surface->ctx, content, width, height);
+    return _cairo_gl_surface_create_scratch (surface->ctx, content, width, height);
 }
 
 cairo_status_t
commit 7c9ebd4a852ad709e57ed48b9610db00de79de7e
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Wed Oct 21 09:04:30 2009 +0100

    Make the surface->is_clear logic common
    
    A nasty surprise whilst profiling is that performing redundant clear
    operations is extremely painful. We can mitigate this somewhat by
    tracking the cleared state of surfaces and skipping repeated attempts to
    clear a surface.

diff --git a/src/cairo-gl-surface.c b/src/cairo-gl-surface.c
index 64ae29b..5d4853d 100644
--- a/src/cairo-gl-surface.c
+++ b/src/cairo-gl-surface.c
@@ -527,6 +527,8 @@ cairo_gl_surface_create (cairo_gl_context_t   *ctx,
     glClear (GL_COLOR_BUFFER_BIT);
     _cairo_gl_context_release (ctx);
 
+    surface->base.is_clear = TRUE;
+
     return &surface->base;
 }
 slim_hidden_def (cairo_gl_surface_create);
diff --git a/src/cairo-image-surface.c b/src/cairo-image-surface.c
index 4dbc2fe..d4b607e 100644
--- a/src/cairo-image-surface.c
+++ b/src/cairo-image-surface.c
@@ -190,7 +190,6 @@ _cairo_image_surface_create_for_pixman_image (pixman_image_t		*pixman_image,
     surface->height = height;
     surface->stride = pixman_image_get_stride (pixman_image);
     surface->depth = pixman_image_get_depth (pixman_image);
-    surface->is_clear = FALSE;
 
     surface->clip_region = NULL;
 
@@ -393,7 +392,7 @@ _cairo_image_surface_create_with_pixman_format (unsigned char		*data,
     }
 
     /* we can not make any assumptions about the initial state of user data */
-    ((cairo_image_surface_t *) surface)->is_clear = data == NULL;
+    surface->is_clear = data == NULL;
     return surface;
 }
 
@@ -1154,8 +1153,6 @@ _cairo_image_surface_composite (cairo_operator_t	 op,
 	_cairo_pattern_release_surface (mask_pattern, &mask->base, &mask_attr);
 
     _cairo_pattern_release_surface (src_pattern, &src->base, &src_attr);
-    if (op != CAIRO_OPERATOR_CLEAR)
-	dst->is_clear = FALSE;
 
     return status;
 }
@@ -1214,9 +1211,6 @@ _cairo_image_surface_fill_rectangles (void		      *abstract_surface,
     if (pixman_rects != stack_rects)
 	free (pixman_rects);
 
-    if (op != CAIRO_OPERATOR_CLEAR)
-	surface->is_clear = FALSE;
-
     return status;
 }
 
@@ -1345,9 +1339,6 @@ _cairo_image_surface_composite_trapezoids (cairo_operator_t	op,
 
     pixman_image_unref (mask);
 
-    if (op != CAIRO_OPERATOR_CLEAR)
-	dst->is_clear = FALSE;
-
     if (! _cairo_operator_bounded_by_mask (op)) {
 	status = _cairo_surface_composite_shape_fixup_unbounded (&dst->base,
 								 &attributes,
@@ -1506,9 +1497,6 @@ _cairo_image_surface_span_renderer_finish (void *abstract_renderer)
 		rects->width, rects->height,
 		dst->clip_region);
 	}
-
-	if (renderer->op != CAIRO_OPERATOR_CLEAR)
-	    dst->is_clear = FALSE;
     }
     if (status != CAIRO_STATUS_SUCCESS)
 	return _cairo_span_renderer_set_error (abstract_renderer,
@@ -1615,35 +1603,6 @@ _cairo_image_surface_get_font_options (void                  *abstract_surface,
     cairo_font_options_set_hint_metrics (options, CAIRO_HINT_METRICS_ON);
 }
 
-static cairo_status_t
-_cairo_image_surface_mark_dirty_rectangle (void *abstract_surface,
-					   int x, int y,
-					   int width, int height)
-{
-    cairo_image_surface_t *surface = abstract_surface;
-    surface->is_clear = FALSE;
-    return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_int_status_t
-_cairo_image_surface_paint (void *abstract_surface,
-			    cairo_operator_t	 op,
-			    const cairo_pattern_t *source,
-			    cairo_clip_t	    *clip)
-{
-    /* we know that surfaces are calloc, so ignore any redundant clears */
-    if (op == CAIRO_OPERATOR_CLEAR && clip == NULL) {
-	cairo_image_surface_t *surface = abstract_surface;
-
-	if (surface->is_clear)
-	    return CAIRO_STATUS_SUCCESS;
-
-	surface->is_clear = TRUE;
-    }
-
-    return CAIRO_INT_STATUS_UNSUPPORTED;
-}
-
 /**
  * _cairo_surface_is_image:
  * @surface: a #cairo_surface_t
@@ -1678,11 +1637,11 @@ const cairo_surface_backend_t _cairo_image_surface_backend = {
     NULL, /* old_show_glyphs */
     _cairo_image_surface_get_font_options,
     NULL, /* flush */
-    _cairo_image_surface_mark_dirty_rectangle,
+    NULL, /* mark dirty */
     NULL, /* font_fini */
     NULL, /* glyph_fini */
 
-    _cairo_image_surface_paint,
+    NULL, /* paint */
     NULL, /* mask */
     NULL, /* stroke */
     NULL, /* fill */
diff --git a/src/cairo-surface-private.h b/src/cairo-surface-private.h
index 5c80d43..994df0e 100644
--- a/src/cairo-surface-private.h
+++ b/src/cairo-surface-private.h
@@ -58,9 +58,12 @@ struct _cairo_surface {
 
     cairo_reference_count_t ref_count;
     cairo_status_t status;
-    cairo_bool_t finished;
     unsigned int unique_id;
 
+    unsigned finished : 1;
+    unsigned is_clear : 1;
+    unsigned has_font_options : 1;
+
     cairo_user_data_array_t user_data;
     cairo_user_data_array_t mime_data;
 
@@ -89,7 +92,6 @@ struct _cairo_surface {
      * and set using _cairo_surface_set_font_options(), and propagated by
      * cairo_surface_create_similar().
      */
-    cairo_bool_t has_font_options;
     cairo_font_options_t font_options;
 };
 
diff --git a/src/cairo-surface.c b/src/cairo-surface.c
index e080c31..aaab313 100644
--- a/src/cairo-surface.c
+++ b/src/cairo-surface.c
@@ -51,8 +51,10 @@ const cairo_surface_t name = {					\
     CAIRO_CONTENT_COLOR,		/* content */		\
     CAIRO_REFERENCE_COUNT_INVALID,	/* ref_count */		\
     status,				/* status */		\
-    FALSE,				/* finished */		\
     0,					/* unique id */		\
+    FALSE,				/* finished */		\
+    TRUE,				/* is_clear */		\
+    FALSE,				/* has_font_options */	\
     { 0, 0, 0, NULL, },			/* user_data */		\
     { 0, 0, 0, NULL, },			/* mime_data */         \
     { 1.0, 0.0, 0.0, 1.0, 0.0, 0.0 },   /* device_transform */	\
@@ -68,7 +70,6 @@ const cairo_surface_t name = {					\
       0,	/* element_size */				\
       NULL,	/* elements */					\
     },					/* snapshots */		\
-    FALSE,				/* has_font_options */	\
     { CAIRO_ANTIALIAS_DEFAULT,		/* antialias */		\
       CAIRO_SUBPIXEL_ORDER_DEFAULT,	/* subpixel_order */	\
       CAIRO_HINT_STYLE_DEFAULT,		/* hint_style */	\
@@ -343,8 +344,9 @@ _cairo_surface_init (cairo_surface_t			*surface,
 
     CAIRO_REFERENCE_COUNT_INIT (&surface->ref_count, 1);
     surface->status = CAIRO_STATUS_SUCCESS;
-    surface->finished = FALSE;
     surface->unique_id = _cairo_surface_allocate_unique_id ();
+    surface->finished = FALSE;
+    surface->is_clear = FALSE;
 
     _cairo_user_data_array_init (&surface->user_data);
     _cairo_user_data_array_init (&surface->mime_data);
@@ -1030,6 +1032,8 @@ cairo_surface_mark_dirty_rectangle (cairo_surface_t *surface,
      * call mark_dirty()). */
     assert (! _cairo_surface_has_snapshots (surface));
 
+    surface->is_clear = FALSE;
+
     if (surface->backend->mark_dirty_rectangle != NULL) {
 	/* XXX: FRAGILE: We're ignoring the scaling component of
 	 * device_transform here. I don't know what the right thing to
@@ -1924,6 +1928,14 @@ _cairo_surface_paint (cairo_surface_t	*surface,
     if (clip && clip->all_clipped)
 	return CAIRO_STATUS_SUCCESS;
 
+    if (op == CAIRO_OPERATOR_CLEAR) {
+	if (surface->is_clear)
+	    return CAIRO_STATUS_SUCCESS;
+
+	if (clip == NULL)
+	    surface->is_clear = TRUE;
+    }
+
     _cairo_surface_begin_modification (surface);
 
     if (surface->backend->paint != NULL) {
@@ -1935,6 +1947,8 @@ _cairo_surface_paint (cairo_surface_t	*surface,
     status = _cairo_surface_fallback_paint (surface, op, source, clip);
 
  FINISH:
+    surface->is_clear &= op == CAIRO_OPERATOR_CLEAR;
+
     return _cairo_surface_set_error (surface, status);
 }
 
@@ -1953,6 +1967,16 @@ _cairo_surface_mask (cairo_surface_t		*surface,
     if (clip && clip->all_clipped)
 	return CAIRO_STATUS_SUCCESS;
 
+    if (op == CAIRO_OPERATOR_CLEAR && surface->is_clear)
+	return CAIRO_STATUS_SUCCESS;
+
+    /* If the mask is blank, this is just an expensive no-op */
+    if (mask->type == CAIRO_PATTERN_TYPE_SURFACE) {
+	const cairo_surface_pattern_t *spattern = (cairo_surface_pattern_t *) mask;
+	if (spattern->surface->is_clear)
+	    return CAIRO_STATUS_SUCCESS;
+    }
+
     _cairo_surface_begin_modification (surface);
 
     if (surface->backend->mask != NULL) {
@@ -1964,6 +1988,8 @@ _cairo_surface_mask (cairo_surface_t		*surface,
     status = _cairo_surface_fallback_mask (surface, op, source, mask, clip);
 
  FINISH:
+    surface->is_clear &= op == CAIRO_OPERATOR_CLEAR;
+
     return _cairo_surface_set_error (surface, status);
 }
 
@@ -1992,6 +2018,13 @@ _cairo_surface_fill_stroke (cairo_surface_t	    *surface,
     if (clip && clip->all_clipped)
 	return CAIRO_STATUS_SUCCESS;
 
+    if (surface->is_clear &&
+	fill_op == CAIRO_OPERATOR_CLEAR &&
+	stroke_op == CAIRO_OPERATOR_CLEAR)
+    {
+	return CAIRO_STATUS_SUCCESS;
+    }
+
     _cairo_surface_begin_modification (surface);
 
     if (surface->backend->fill_stroke) {
@@ -2009,23 +2042,27 @@ _cairo_surface_fill_stroke (cairo_surface_t	    *surface,
 						clip);
 
 	if (status != CAIRO_INT_STATUS_UNSUPPORTED)
-	    return _cairo_surface_set_error (surface, status);
+	    goto FINISH;
     }
 
     status = _cairo_surface_fill (surface, fill_op, fill_source, path,
 				  fill_rule, fill_tolerance, fill_antialias,
 				  clip);
     if (unlikely (status))
-	return _cairo_surface_set_error (surface, status);
+	goto FINISH;
 
     status = _cairo_surface_stroke (surface, stroke_op, stroke_source, path,
 				    stroke_style, stroke_ctm, stroke_ctm_inverse,
 				    stroke_tolerance, stroke_antialias,
 				    clip);
     if (unlikely (status))
-	return _cairo_surface_set_error (surface, status);
+	goto FINISH;
 
-    return CAIRO_STATUS_SUCCESS;
+  FINISH:
+    surface->is_clear &= fill_op == CAIRO_OPERATOR_CLEAR;
+    surface->is_clear &= stroke_op == CAIRO_OPERATOR_CLEAR;
+
+    return _cairo_surface_set_error (surface, status);
 }
 
 cairo_status_t
@@ -2048,6 +2085,9 @@ _cairo_surface_stroke (cairo_surface_t		*surface,
     if (clip && clip->all_clipped)
 	return CAIRO_STATUS_SUCCESS;
 
+    if (op == CAIRO_OPERATOR_CLEAR && surface->is_clear)
+	return CAIRO_STATUS_SUCCESS;
+
     _cairo_surface_begin_modification (surface);
 
     if (surface->backend->stroke != NULL) {
@@ -2068,6 +2108,8 @@ _cairo_surface_stroke (cairo_surface_t		*surface,
 					     clip);
 
  FINISH:
+    surface->is_clear &= op == CAIRO_OPERATOR_CLEAR;
+
     return _cairo_surface_set_error (surface, status);
 }
 
@@ -2089,6 +2131,9 @@ _cairo_surface_fill (cairo_surface_t	*surface,
     if (clip && clip->all_clipped)
 	return CAIRO_STATUS_SUCCESS;
 
+    if (op == CAIRO_OPERATOR_CLEAR && surface->is_clear)
+	return CAIRO_STATUS_SUCCESS;
+
     _cairo_surface_begin_modification (surface);
 
     if (surface->backend->fill != NULL) {
@@ -2107,6 +2152,8 @@ _cairo_surface_fill (cairo_surface_t	*surface,
 					   clip);
 
  FINISH:
+    surface->is_clear &= op == CAIRO_OPERATOR_CLEAR;
+
     return _cairo_surface_set_error (surface, status);
 }
 
@@ -2408,6 +2455,9 @@ _cairo_surface_show_text_glyphs (cairo_surface_t	    *surface,
     if (clip && clip->all_clipped)
 	return CAIRO_STATUS_SUCCESS;
 
+    if (op == CAIRO_OPERATOR_CLEAR && surface->is_clear)
+	return CAIRO_STATUS_SUCCESS;
+
     _cairo_surface_begin_modification (surface);
 
     if (_cairo_surface_has_device_transform (surface) &&
@@ -2504,6 +2554,8 @@ _cairo_surface_show_text_glyphs (cairo_surface_t	    *surface,
     if (dev_scaled_font != scaled_font)
 	cairo_scaled_font_destroy (dev_scaled_font);
 
+    surface->is_clear &= op == CAIRO_OPERATOR_CLEAR;
+
     return _cairo_surface_set_error (surface, status);
 }
 
diff --git a/src/cairoint.h b/src/cairoint.h
index b913913..fc1046e 100644
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -861,7 +861,6 @@ struct _cairo_image_surface {
     pixman_image_t *pixman_image;
     cairo_region_t *clip_region;
 
-    unsigned is_clear : 1;
     unsigned owns_data : 1;
     unsigned transparency : 2;
 };
commit 723055722f1d9a133fe9e78bb19165f2c7be720e
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Wed Oct 21 10:40:51 2009 +0100

    [doc] Add comments on when surfaces are cleared on construction.
    
    Or perhaps, more importantly, when the contents are left unmodified.

diff --git a/src/cairo.h b/src/cairo.h
index c239dea..a43eae8 100644
--- a/src/cairo.h
+++ b/src/cairo.h
@@ -132,6 +132,15 @@ typedef struct _cairo cairo_t;
  * creates a bitmap image in memory.
  * The type of a surface can be queried with cairo_surface_get_type().
  *
+ * The initial contents of a surface after creation depend upon the manner
+ * of its creation. If cairo creates the surface and backing storage for
+ * the user, it will be initially cleared; for example,
+ * cairo_image_surface_create() and cairo_surface_create_similar().
+ * Alternatively, if the user passes in a reference to some backing storage
+ * and asks cairo to wrap that in a #cairo_surface_t, then the contents are
+ * not modified; for example, cairo_image_surface_create_for_data() and
+ * cairo_xlib_surface_create().
+ *
  * Memory management of #cairo_surface_t is done with
  * cairo_surface_reference() and cairo_surface_destroy().
  **/


More information about the cairo-commit mailing list