[cairo-commit] 5 commits - src/cairo-image-surface.c src/cairo-surface.c src/cairo-surface-snapshot.c test/bilevel-image.c test/filter-nearest-offset.c test/mask-ctm.c test/mask-surface-ctm.c test/move-to-show-surface.c test/paint-repeat.c test/paint-source-alpha.c test/paint-with-alpha.c test/rgb24-ignore-alpha.c test/scale-down-source-surface-paint.c test/scale-source-surface-paint.c test/set-source.c test/smask.c test/smask-image-mask.c test/source-surface-scale-paint.c test/translate-show-surface.c test/zero-alpha.c

Chris Wilson ickle at kemper.freedesktop.org
Wed Apr 28 00:44:25 PDT 2010


 src/cairo-image-surface.c              |  161 +++++++++++++++++++++++++++------
 src/cairo-surface-snapshot.c           |   18 ++-
 src/cairo-surface.c                    |   24 ++++
 test/bilevel-image.c                   |    4 
 test/filter-nearest-offset.c           |    1 
 test/mask-ctm.c                        |    4 
 test/mask-surface-ctm.c                |    1 
 test/move-to-show-surface.c            |    2 
 test/paint-repeat.c                    |    1 
 test/paint-source-alpha.c              |    1 
 test/paint-with-alpha.c                |    1 
 test/rgb24-ignore-alpha.c              |    1 
 test/scale-down-source-surface-paint.c |    1 
 test/scale-source-surface-paint.c      |    1 
 test/set-source.c                      |    1 
 test/smask-image-mask.c                |    4 
 test/smask.c                           |    4 
 test/source-surface-scale-paint.c      |    1 
 test/translate-show-surface.c          |    1 
 test/zero-alpha.c                      |    1 
 20 files changed, 198 insertions(+), 35 deletions(-)

New commits:
commit d3c4349730be991db0c85094103c744fc2d94836
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Tue Apr 27 21:04:52 2010 +0100

    test: Mark surfaces as finished if the data goes out of scope.
    
    The issue being that as the on-stack data is being referenced via a
    zero-copy snapshot outside of the functions scope as the surface is only
    finished and the source written long after the draw() returns. The
    correct procedure is that the user must call cairo_surface_finish()
    prior to any surface becoming inaccessible. In this case, this triggers
    the snapshot to preserve a copy of the data whilst it is still valid.

diff --git a/test/bilevel-image.c b/test/bilevel-image.c
index 7435a2b..4feff0e 100644
--- a/test/bilevel-image.c
+++ b/test/bilevel-image.c
@@ -46,10 +46,12 @@ draw (cairo_t *cr, int width, int height)
 
     cairo_set_source_surface (cr, mask, 0, 0);
     cairo_pattern_set_filter (cairo_get_source (cr), CAIRO_FILTER_NEAREST);
-    cairo_surface_destroy (mask);
 
     cairo_paint (cr);
 
+    cairo_surface_finish (mask); /* data goes out of scope */
+    cairo_surface_destroy (mask);
+
     return CAIRO_TEST_SUCCESS;
 }
 
diff --git a/test/filter-nearest-offset.c b/test/filter-nearest-offset.c
index f22dcf1..4df6097 100644
--- a/test/filter-nearest-offset.c
+++ b/test/filter-nearest-offset.c
@@ -94,6 +94,7 @@ draw (cairo_t *cr, int width, int height)
 	}
     }
 
+    cairo_surface_finish (surface); /* data goes out of scope */
     cairo_surface_destroy (surface);
 
     return CAIRO_TEST_SUCCESS;
diff --git a/test/mask-ctm.c b/test/mask-ctm.c
index 7b3a394..205ab06 100644
--- a/test/mask-ctm.c
+++ b/test/mask-ctm.c
@@ -39,7 +39,6 @@ draw (cairo_t *cr, int width, int height)
     mask_surface = cairo_image_surface_create_for_data ((unsigned char *) data,
 							CAIRO_FORMAT_ARGB32, 2, 2, 8);
     mask = cairo_pattern_create_for_surface (mask_surface);
-    cairo_surface_destroy (mask_surface);
 
     cairo_set_source_rgb (cr, 1.0, 0, 0);
 
@@ -66,6 +65,9 @@ draw (cairo_t *cr, int width, int height)
 
     cairo_pattern_destroy (mask);
 
+    cairo_surface_finish (mask_surface); /* data goes out of scope */
+    cairo_surface_destroy (mask_surface);
+
     return CAIRO_TEST_SUCCESS;
 }
 
diff --git a/test/mask-surface-ctm.c b/test/mask-surface-ctm.c
index 50f6d01..064de3c 100644
--- a/test/mask-surface-ctm.c
+++ b/test/mask-surface-ctm.c
@@ -57,6 +57,7 @@ draw (cairo_t *cr, int width, int height)
     cairo_translate (cr, 2, 2);
     cairo_mask_surface (cr, mask, 4, 4);
 
+    cairo_surface_finish (mask); /* data goes out of scope */
     cairo_surface_destroy (mask);
 
     return CAIRO_TEST_SUCCESS;
diff --git a/test/move-to-show-surface.c b/test/move-to-show-surface.c
index 6caad1b..a52b468 100644
--- a/test/move-to-show-surface.c
+++ b/test/move-to-show-surface.c
@@ -62,6 +62,8 @@ draw (cairo_t *cr, int width, int height)
 	cairo_set_source_surface (cr, surface,
 				  i % 2, i / 2);
 	cairo_paint (cr);
+
+	cairo_surface_finish (surface); /* colors will go out of scope */
 	cairo_surface_destroy (surface);
     }
 
diff --git a/test/paint-repeat.c b/test/paint-repeat.c
index 35b383c..c48d84c 100644
--- a/test/paint-repeat.c
+++ b/test/paint-repeat.c
@@ -47,6 +47,7 @@ draw (cairo_t *cr, int width, int height)
     cairo_pattern_set_extend (cairo_get_source (cr), CAIRO_EXTEND_REPEAT);
     cairo_paint (cr);
 
+    cairo_surface_finish (surface); /* data will go out of scope */
     cairo_surface_destroy (surface);
 
     return CAIRO_TEST_SUCCESS;
diff --git a/test/paint-source-alpha.c b/test/paint-source-alpha.c
index 09e82b0..cb2d488 100644
--- a/test/paint-source-alpha.c
+++ b/test/paint-source-alpha.c
@@ -49,6 +49,7 @@ draw (cairo_t *cr, int width, int height)
     cairo_pattern_set_filter (cairo_get_source (cr), CAIRO_FILTER_NEAREST);
     cairo_paint (cr);
 
+    cairo_surface_finish (surface); /* data will go out of scope */
     cairo_surface_destroy (surface);
 
     return CAIRO_TEST_SUCCESS;
diff --git a/test/paint-with-alpha.c b/test/paint-with-alpha.c
index 678d313..19b9e44 100644
--- a/test/paint-with-alpha.c
+++ b/test/paint-with-alpha.c
@@ -49,6 +49,7 @@ draw (cairo_t *cr, int width, int height)
     cairo_pattern_set_filter (cairo_get_source (cr), CAIRO_FILTER_NEAREST);
     cairo_paint_with_alpha (cr, 0.5);
 
+    cairo_surface_finish (surface); /* data will go out of scope */
     cairo_surface_destroy (surface);
 
     return CAIRO_TEST_SUCCESS;
diff --git a/test/rgb24-ignore-alpha.c b/test/rgb24-ignore-alpha.c
index cd67ed3..1c9d57e 100644
--- a/test/rgb24-ignore-alpha.c
+++ b/test/rgb24-ignore-alpha.c
@@ -46,6 +46,7 @@ draw (cairo_t *cr, int width, int height)
     cairo_set_source_surface (cr, surface, 0, 0);
     cairo_paint (cr);
 
+    cairo_surface_finish (surface); /* colors will go out of scope */
     cairo_surface_destroy (surface);
 
     return CAIRO_TEST_SUCCESS;
diff --git a/test/scale-down-source-surface-paint.c b/test/scale-down-source-surface-paint.c
index 293cbda..8cf0e06 100644
--- a/test/scale-down-source-surface-paint.c
+++ b/test/scale-down-source-surface-paint.c
@@ -51,6 +51,7 @@ draw (cairo_t *cr, int width, int height)
     cairo_pattern_set_filter (cairo_get_source (cr), CAIRO_FILTER_NEAREST);
     cairo_paint (cr);
 
+    cairo_surface_finish (surface); /* data will go out of scope */
     cairo_surface_destroy (surface);
 
     return CAIRO_TEST_SUCCESS;
diff --git a/test/scale-source-surface-paint.c b/test/scale-source-surface-paint.c
index 1e36afd..0c0a3ac 100644
--- a/test/scale-source-surface-paint.c
+++ b/test/scale-source-surface-paint.c
@@ -46,6 +46,7 @@ draw (cairo_t *cr, int width, int height)
     cairo_pattern_set_filter (cairo_get_source (cr), CAIRO_FILTER_NEAREST);
     cairo_paint (cr);
 
+    cairo_surface_finish (surface); /* data will go out of scope */
     cairo_surface_destroy (surface);
 
     return CAIRO_TEST_SUCCESS;
diff --git a/test/set-source.c b/test/set-source.c
index f326103..7e54626 100644
--- a/test/set-source.c
+++ b/test/set-source.c
@@ -67,6 +67,7 @@ draw (cairo_t *cr, int width, int height)
     }
 
     cairo_pattern_destroy (pattern);
+    cairo_surface_finish (surface); /* data will go out of scope */
     cairo_surface_destroy (surface);
 
     return CAIRO_TEST_SUCCESS;
diff --git a/test/smask-image-mask.c b/test/smask-image-mask.c
index 1418721..3d8b5d5 100644
--- a/test/smask-image-mask.c
+++ b/test/smask-image-mask.c
@@ -63,7 +63,6 @@ draw (cairo_t *cr, int width, int height)
     mask2 = cairo_image_surface_create_for_data ((unsigned char *) data,
 						CAIRO_FORMAT_ARGB32, 2, 2, 8);
     pattern = cairo_pattern_create_for_surface (mask2);
-    cairo_surface_destroy (mask2);
     cairo_pattern_set_extend (pattern, CAIRO_EXTEND_REPEAT);
     cairo_mask (cr2, pattern);
     cairo_pattern_destroy (pattern);
@@ -72,6 +71,9 @@ draw (cairo_t *cr, int width, int height)
     cairo_mask_surface (cr, cairo_get_target (cr2), 0, 0);
     cairo_destroy (cr2);
 
+    cairo_surface_finish (mask2); /* data will go out of scope */
+    cairo_surface_destroy (mask2);
+
     return CAIRO_TEST_SUCCESS;
 }
 
diff --git a/test/smask.c b/test/smask.c
index d28caca..867fb69 100644
--- a/test/smask.c
+++ b/test/smask.c
@@ -71,7 +71,6 @@ draw (cairo_t *cr, int width, int height)
     mask2 = cairo_image_surface_create_for_data ((unsigned char *) data,
 						CAIRO_FORMAT_ARGB32, 2, 2, 8);
     pattern = cairo_pattern_create_for_surface (mask2);
-    cairo_surface_destroy (mask2);
     cairo_pattern_set_extend (pattern, CAIRO_EXTEND_REPEAT);
     cairo_mask (cr2, pattern);
     cairo_pattern_destroy (pattern);
@@ -110,6 +109,9 @@ draw (cairo_t *cr, int width, int height)
     cairo_mask_surface (cr, cairo_get_target (cr2), 0, 0);
     cairo_destroy (cr2);
 
+    cairo_surface_finish (mask2); /* data will go out of scope */
+    cairo_surface_destroy (mask2);
+
     return CAIRO_TEST_SUCCESS;
 }
 
diff --git a/test/source-surface-scale-paint.c b/test/source-surface-scale-paint.c
index 565a1ff..4ac6249 100644
--- a/test/source-surface-scale-paint.c
+++ b/test/source-surface-scale-paint.c
@@ -45,6 +45,7 @@ draw (cairo_t *cr, int width, int height)
     cairo_scale (cr, 2, 2);
     cairo_paint (cr);
 
+    cairo_surface_finish (surface); /* data will go out of scope */
     cairo_surface_destroy (surface);
 
     return CAIRO_TEST_SUCCESS;
diff --git a/test/translate-show-surface.c b/test/translate-show-surface.c
index bf084fe..9f7af8d 100644
--- a/test/translate-show-surface.c
+++ b/test/translate-show-surface.c
@@ -64,6 +64,7 @@ draw (cairo_t *cr, int width, int height)
 	    cairo_paint (cr);
 	}
 	cairo_restore (cr);
+	cairo_surface_finish (surface); /* colors will go out of scope */
 	cairo_surface_destroy (surface);
     }
 
diff --git a/test/zero-alpha.c b/test/zero-alpha.c
index 1c7c94b..0105cc8 100644
--- a/test/zero-alpha.c
+++ b/test/zero-alpha.c
@@ -81,6 +81,7 @@ draw (cairo_t *cr, int width, int height)
     for (i=0; i < REPS; i++)
 	cairo_paint (cr);
 
+    cairo_surface_finish (surface); /* zero will go out of scope */
     cairo_surface_destroy (surface);
 
     return CAIRO_TEST_SUCCESS;
commit a5f54e48e3136076f3c8c60fc068f6a2105d9a33
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Tue Apr 27 21:05:22 2010 +0100

    snapshot: The snapshot masquerades as the target surface type.
    
    Not wholly convinced this is a good idea, but it matches the behaviour
    of the other internal surface types.

diff --git a/src/cairo-surface-snapshot.c b/src/cairo-surface-snapshot.c
index 5e1ec74..4ad16aa 100644
--- a/src/cairo-surface-snapshot.c
+++ b/src/cairo-surface-snapshot.c
@@ -156,6 +156,7 @@ _cairo_surface_snapshot_copy_on_write (cairo_surface_t *surface)
 
     _cairo_surface_release_source_image (snapshot->target, image, extra);
     snapshot->target = snapshot->clone;
+    snapshot->base.type = snapshot->target->type;
 }
 
 /**
@@ -213,6 +214,7 @@ _cairo_surface_snapshot (cairo_surface_t *surface)
 			 &_cairo_surface_snapshot_backend,
 			 NULL, /* device */
 			 surface->content);
+    snapshot->base.type = surface->type;
 
     snapshot->target = surface;
     snapshot->clone = NULL;
commit 4a678afdf73d6f7b2b8a532ac7024976702c8aac
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Tue Apr 27 18:57:56 2010 +0100

    snapshot: Simply memcpy if the cloned image matches the original.

diff --git a/src/cairo-surface-snapshot.c b/src/cairo-surface-snapshot.c
index 4277f66..5e1ec74 100644
--- a/src/cairo-surface-snapshot.c
+++ b/src/cairo-surface-snapshot.c
@@ -136,12 +136,16 @@ _cairo_surface_snapshot_copy_on_write (cairo_surface_t *surface)
 							image->height,
 							0);
     if (likely (clone->base.status == CAIRO_STATUS_SUCCESS)) {
-	pixman_image_composite32 (PIXMAN_OP_SRC,
-                                  image->pixman_image, NULL, clone->pixman_image,
-                                  0, 0,
-                                  0, 0,
-                                  0, 0,
-                                  image->width, image->height);
+	if (clone->stride == image->stride) {
+	    memcpy (clone->data, image->data, image->stride * image->height);
+	} else {
+	    pixman_image_composite32 (PIXMAN_OP_SRC,
+				      image->pixman_image, NULL, clone->pixman_image,
+				      0, 0,
+				      0, 0,
+				      0, 0,
+				      image->width, image->height);
+	}
 	clone->base.is_clear = FALSE;
 
 	snapshot->clone = &clone->base;
commit b74cc0f6d5b71295c70d4c29e24ab252175f9a5b
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Tue Apr 27 18:57:00 2010 +0100

    image: Convert 1x1 samples into solid colors.
    
    If the sampled extents of the operation on an image surface is just a
    single pixel, we can safely convert to a solid color.

diff --git a/src/cairo-image-surface.c b/src/cairo-image-surface.c
index 6d11b23..7e0248b 100644
--- a/src/cairo-image-surface.c
+++ b/src/cairo-image-surface.c
@@ -1235,6 +1235,74 @@ sampled_area (const cairo_surface_pattern_t *pattern,
     return filter;
 }
 
+static uint16_t
+expand_channel (uint16_t v, uint32_t bits)
+{
+    int offset = 16 - bits;
+    while (offset > 0) {
+	v |= v >> bits;
+	offset -= bits;
+	bits += bits;
+    }
+    return v;
+}
+
+static pixman_image_t *
+_pixel_to_solid (cairo_image_surface_t *image, int x, int y)
+{
+    uint32_t pixel;
+    pixman_color_t color;
+
+    switch (image->format) {
+    default:
+    case CAIRO_FORMAT_INVALID:
+	ASSERT_NOT_REACHED;
+	return NULL;
+
+    case CAIRO_FORMAT_A1:
+	pixel = *(uint8_t *) (image->data + y * image->stride + x/8);
+	return pixel & (1 << (x&7)) ? _pixman_white_image () : _pixman_transparent_image ();
+
+    case CAIRO_FORMAT_A8:
+	color.alpha = *(uint8_t *) (image->data + y * image->stride + x);
+	color.alpha |= color.alpha << 8;
+	if (color.alpha == 0)
+	    return _pixman_transparent_image ();
+
+	color.red = color.green = color.blue = 0;
+	return pixman_image_create_solid_fill (&color);
+
+    case CAIRO_FORMAT_RGB16_565:
+	pixel = *(uint16_t *) (image->data + y * image->stride + 2 * x);
+	if (pixel == 0)
+	    return _pixman_black_image ();
+	if (pixel == 0xffff)
+	    return _pixman_white_image ();
+
+	color.alpha = 0xffff;
+	color.red = expand_channel ((pixel >> 11 & 0x1f) << 11, 5);
+	color.green = expand_channel ((pixel >> 5 & 0x3f) << 10, 6);
+	color.blue = expand_channel ((pixel & 0x1f) << 11, 5);
+	return pixman_image_create_solid_fill (&color);
+
+    case CAIRO_FORMAT_ARGB32:
+    case CAIRO_FORMAT_RGB24:
+	pixel = *(uint32_t *) (image->data + y * image->stride + 4 * x);
+	color.alpha = image->format == CAIRO_FORMAT_ARGB32 ? (pixel >> 24) | (pixel >> 16 & 0xff00) : 0xffff;
+	if (color.alpha == 0)
+	    return _pixman_transparent_image ();
+	if (pixel == 0xffffffff)
+	    return _pixman_white_image ();
+	if (color.alpha == 0xffff && (pixel & 0xffffff) == 0)
+	    return _pixman_black_image ();
+
+	color.red = (pixel >> 16 & 0xff) | (pixel >> 8 & 0xff00);
+	color.green = (pixel >> 8 & 0xff) | (pixel & 0xff00);
+	color.blue = (pixel & 0xff) | (pixel << 8 & 0xff00);
+	return pixman_image_create_solid_fill (&color);
+    }
+}
+
 static pixman_image_t *
 _pixman_image_for_surface (const cairo_surface_pattern_t *pattern,
 			   const cairo_rectangle_int_t *extents,
@@ -1271,6 +1339,21 @@ _pixman_image_for_surface (const cairo_surface_pattern_t *pattern,
 		extend = CAIRO_EXTEND_NONE;
 	    }
 
+	    if (sample.width == 1 && sample.height == 1) {
+		if (sample.x < 0 ||
+		    sample.y < 0 ||
+		    sample.x >= source->width ||
+		    sample.y >= source->height)
+		{
+		    if (extend == CAIRO_EXTEND_NONE)
+			return _pixman_transparent_image ();
+		}
+		else
+		{
+		    return _pixel_to_solid (source, sample.x, sample.y);
+		}
+	    }
+
 	    /* avoid allocating a 'pattern' image if we can reuse the original */
 	    if (extend == CAIRO_EXTEND_NONE &&
 		_cairo_matrix_is_translation (&pattern->base.matrix) &&
@@ -1295,14 +1378,25 @@ _pixman_image_for_surface (const cairo_surface_pattern_t *pattern,
 	    sub = (cairo_surface_subsurface_t *) source;
 	    source = (cairo_image_surface_t *) sub->target;
 
-	    if (sample.x >= sub->extents.x &&
-		sample.y >= sub->extents.y &&
-		sample.x + sample.width  <= sub->extents.x + sub->extents.width &&
-		sample.y + sample.height <= sub->extents.y + sub->extents.height)
+	    if (sample.x >= 0 &&
+		sample.y >= 0 &&
+		sample.x + sample.width  <= sub->extents.width &&
+		sample.y + sample.height <= sub->extents.height)
 	    {
 		is_contained = TRUE;
 	    }
 
+	    if (sample.width == 1 && sample.height == 1) {
+		if (is_contained) {
+		    return _pixel_to_solid (source,
+					    sub->extents.x + sample.x,
+					    sub->extents.y + sample.y);
+		} else {
+		    if (extend == CAIRO_EXTEND_NONE)
+			return _pixman_transparent_image ();
+		}
+	    }
+
 	    if (is_contained &&
 		_cairo_matrix_is_translation (&pattern->base.matrix) &&
 		_nearest_sample (filter, &tx, &ty))
@@ -1327,36 +1421,54 @@ _pixman_image_for_surface (const cairo_surface_pattern_t *pattern,
 
     if (pixman_image == NULL) {
 	struct acquire_source_cleanup *cleanup;
-	cairo_image_surface_t *source = (cairo_image_surface_t *) pattern->surface;
+	cairo_image_surface_t *image;
+	void *extra;
 	cairo_status_t status;
 
-	cleanup = malloc (sizeof (*cleanup));
-	if (unlikely (cleanup == NULL))
+	status = _cairo_surface_acquire_source_image (pattern->surface, &image, &extra);
+	if (unlikely (status))
 	    return NULL;
 
-	cleanup->surface = pattern->surface;
-	status = _cairo_surface_acquire_source_image (pattern->surface,
-						      &cleanup->image,
-						      &cleanup->image_extra);
-	if (unlikely (status)) {
-	    free (cleanup);
-	    return NULL;
+	if (sample.width == 1 && sample.height == 1) {
+	    if (sample.x < 0 ||
+		sample.y < 0 ||
+		sample.x >= image->width ||
+		sample.y >= image->height)
+	    {
+		if (extend == CAIRO_EXTEND_NONE) {
+		    pixman_image = _pixman_transparent_image ();
+		    _cairo_surface_release_source_image (pattern->surface, image, extra);
+		    return pixman_image;
+		}
+	    }
+	    else
+	    {
+		pixman_image = _pixel_to_solid (image, sample.x, sample.y);
+		_cairo_surface_release_source_image (pattern->surface, image, extra);
+		return pixman_image;
+	    }
 	}
 
-	source = cleanup->image;
-	pixman_image = pixman_image_create_bits (source->pixman_format,
-						 source->width,
-						 source->height,
-						 (uint32_t *) source->data,
-						 source->stride);
+	pixman_image = pixman_image_create_bits (image->pixman_format,
+						 image->width,
+						 image->height,
+						 (uint32_t *) image->data,
+						 image->stride);
 	if (unlikely (pixman_image == NULL)) {
-	    _cairo_surface_release_source_image (pattern->surface,
-						 cleanup->image,
-						 cleanup->image_extra);
-	    free (cleanup);
+	    _cairo_surface_release_source_image (pattern->surface, image, extra);
 	    return NULL;
 	}
 
+	cleanup = malloc (sizeof (*cleanup));
+	if (unlikely (cleanup == NULL)) {
+	    _cairo_surface_release_source_image (pattern->surface, image, extra);
+	    pixman_image_unref (pixman_image);
+	    return NULL;
+	}
+
+	cleanup->surface = pattern->surface;
+	cleanup->image = image;
+	cleanup->image_extra = extra;
 	pixman_image_set_destroy_function (pixman_image,
 					   _acquire_source_cleanup, cleanup);
     }
@@ -4241,7 +4353,6 @@ _cairo_image_surface_span_renderer_finish (void *abstract_renderer)
     if (src == NULL)
 	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
 
-
     pixman_image_composite32 (_pixman_operator (renderer->op),
                               src,
                               renderer->mask,
commit f5cf131a9d8984bd6b3403396beed2ffbc26bded
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Tue Apr 27 18:56:23 2010 +0100

    surface: skip OVER is the source is clear.
    
    If the source has no alpha, the OVER operation becomes DST, i.e. a
    no-op.

diff --git a/src/cairo-surface.c b/src/cairo-surface.c
index 8a59373..ddb1ffd 100644
--- a/src/cairo-surface.c
+++ b/src/cairo-surface.c
@@ -1926,6 +1926,12 @@ _cairo_surface_paint (cairo_surface_t	*surface,
     if (op == CAIRO_OPERATOR_CLEAR && surface->is_clear)
 	return CAIRO_STATUS_SUCCESS;
 
+    if (op == CAIRO_OPERATOR_OVER &&
+	_cairo_pattern_is_clear (source))
+    {
+	return CAIRO_STATUS_SUCCESS;
+    }
+
     status = _pattern_has_error (source);
     if (unlikely (status))
 	return status;
@@ -1971,6 +1977,12 @@ _cairo_surface_mask (cairo_surface_t		*surface,
 	return CAIRO_STATUS_SUCCESS;
     }
 
+    if (op == CAIRO_OPERATOR_OVER &&
+	_cairo_pattern_is_clear (source))
+    {
+	return CAIRO_STATUS_SUCCESS;
+    }
+
     status = _pattern_has_error (source);
     if (unlikely (status))
 	return status;
@@ -2097,6 +2109,12 @@ _cairo_surface_stroke (cairo_surface_t		*surface,
     if (op == CAIRO_OPERATOR_CLEAR && surface->is_clear)
 	return CAIRO_STATUS_SUCCESS;
 
+    if (op == CAIRO_OPERATOR_OVER &&
+	_cairo_pattern_is_clear (source))
+    {
+	return CAIRO_STATUS_SUCCESS;
+    }
+
     status = _pattern_has_error (source);
     if (unlikely (status))
 	return status;
@@ -2147,6 +2165,12 @@ _cairo_surface_fill (cairo_surface_t	*surface,
     if (op == CAIRO_OPERATOR_CLEAR && surface->is_clear)
 	return CAIRO_STATUS_SUCCESS;
 
+    if (op == CAIRO_OPERATOR_OVER &&
+	_cairo_pattern_is_clear (source))
+    {
+	return CAIRO_STATUS_SUCCESS;
+    }
+
     status = _pattern_has_error (source);
     if (unlikely (status))
 	return status;


More information about the cairo-commit mailing list