[cairo-commit] 6 commits - src/cairo-clip-boxes.c src/cairo-clip.c src/cairo-clip-private.h src/cairo-image-surface.c src/cairo-recording-surface.c src/cairo-recording-surface-private.h src/cairo-surface-wrapper.c src/cairo-surface-wrapper-private.h test/Makefile.refs test/paint-with-alpha.c test/paint-with-alpha-clip.ref.png test/paint-with-alpha-clip.xlib.ref.png test/paint-with-alpha-solid-clip.ref.png test/partial-clip-text-bottom.ref.png test/partial-clip-text.c test/partial-clip-text-left.ref.png test/partial-clip-text.ps.ref.png test/partial-clip-text.quartz.ref.png test/partial-clip-text.ref.png test/partial-clip-text-right.ref.png test/partial-clip-text.svg.ref.png test/partial-clip-text-top.ps.ref.png test/partial-clip-text-top.quartz.ref.png test/partial-clip-text-top.ref.png test/partial-clip-text-top.svg.ref.png test/recording-surface-over.gl.argb32.ref.png test/recording-surface-over.image16.ref.png test/recording-surface-over.pdf.argb32.ref.png test/recording-surface -over.pdf.rgb24.ref.png test/recording-surface-over.ps.argb32.ref.png test/recording-surface-over.ps.rgb24.ref.png test/recording-surface-over.quartz.argb32.ref.png test/recording-surface-over.quartz.rgb24.ref.png test/recording-surface-over.rgb24.ref.png test/recording-surface-over.svg.argb32.ref.png test/recording-surface-over.svg.rgb24.ref.png test/recording-surface-over.xlib.argb32.ref.png test/recording-surface-over.xlib.rgb24.ref.png test/recording-surface-pattern.c test/recording-surface-pattern.gl.argb32.ref.png test/recording-surface-pattern.image16.ref.png test/recording-surface-pattern.pdf.argb32.ref.png test/recording-surface-pattern.pdf.rgb24.ref.png test/recording-surface-pattern.ps.argb32.ref.png test/recording-surface-pattern.ps.rgb24.ref.png test/recording-surface-pattern.quartz.argb32.ref.png test/recording-surface-pattern.quartz.rgb24.ref.png test/recording-surface-pattern.ref.png test/recording-surface-pattern.rgb24.ref.png test/recording-surface-pattern. svg.argb32.ref.png test/recording-surface-pattern.svg.rgb24.ref.png test/recording-surface-pattern.xlib.argb32.ref.png test/recording-surface-pattern.xlib.rgb24.ref.png

Chris Wilson ickle at kemper.freedesktop.org
Sat Jul 23 07:37:23 PDT 2011


 dev/null                                          |binary
 src/cairo-clip-boxes.c                            |   17 
 src/cairo-clip-private.h                          |   15 
 src/cairo-clip.c                                  |   67 ++
 src/cairo-image-surface.c                         |  589 +++++++++++++++-------
 src/cairo-recording-surface-private.h             |    6 
 src/cairo-recording-surface.c                     |   68 +-
 src/cairo-surface-wrapper-private.h               |   13 
 src/cairo-surface-wrapper.c                       |  190 ++++---
 test/Makefile.refs                                |   41 -
 test/paint-with-alpha-clip.ref.png                |binary
 test/paint-with-alpha-clip.xlib.ref.png           |binary
 test/paint-with-alpha-solid-clip.ref.png          |binary
 test/paint-with-alpha.c                           |   63 ++
 test/partial-clip-text-bottom.ref.png             |binary
 test/partial-clip-text-left.ref.png               |binary
 test/partial-clip-text-right.ref.png              |binary
 test/partial-clip-text-top.ps.ref.png             |binary
 test/partial-clip-text-top.quartz.ref.png         |binary
 test/partial-clip-text-top.ref.png                |binary
 test/partial-clip-text-top.svg.ref.png            |binary
 test/partial-clip-text.c                          |   86 ++-
 test/recording-surface-over.gl.argb32.ref.png     |binary
 test/recording-surface-over.image16.ref.png       |binary
 test/recording-surface-over.pdf.argb32.ref.png    |binary
 test/recording-surface-over.pdf.rgb24.ref.png     |binary
 test/recording-surface-over.ps.argb32.ref.png     |binary
 test/recording-surface-over.ps.rgb24.ref.png      |binary
 test/recording-surface-over.quartz.argb32.ref.png |binary
 test/recording-surface-over.quartz.rgb24.ref.png  |binary
 test/recording-surface-over.rgb24.ref.png         |binary
 test/recording-surface-over.svg.argb32.ref.png    |binary
 test/recording-surface-over.svg.rgb24.ref.png     |binary
 test/recording-surface-over.xlib.argb32.ref.png   |binary
 test/recording-surface-over.xlib.rgb24.ref.png    |binary
 test/recording-surface-pattern.c                  |  149 +++--
 36 files changed, 951 insertions(+), 353 deletions(-)

New commits:
commit 7e42276ffc52c417f8119517485b609ef7f7743e
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Sat Jul 23 15:13:42 2011 +0100

    image: Apply mask-opacity to clip boxes
    
    In the simple condition where the user is applying an opacity mask to a
    misaligned rectangle, we can treat it as a series of simpler composites
    by combining the opacity with the coverage of the box.
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/src/cairo-image-surface.c b/src/cairo-image-surface.c
index f727b84..e2e0e18 100644
--- a/src/cairo-image-surface.c
+++ b/src/cairo-image-surface.c
@@ -1882,25 +1882,23 @@ typedef cairo_status_t
 		      int				 dst_x,
 		      int				 dst_y,
 		      cairo_matrix_t			*dst_device_transform,
-		      const cairo_rectangle_int_t	*extents,
-		      cairo_region_t			*clip_region);
+		      const cairo_composite_rectangles_t	*extents);
 
 static pixman_image_t *
-_create_composite_mask_pattern (cairo_clip_t                  *clip,
+_create_composite_mask_pattern (cairo_composite_rectangles_t *extents,
 				image_draw_func_t              draw_func,
 				void                          *draw_closure,
-				cairo_image_surface_t         *dst,
-				const cairo_rectangle_int_t   *extents)
+				cairo_image_surface_t         *dst)
 {
-    cairo_region_t *clip_region = _cairo_clip_get_region (clip);
-    cairo_bool_t need_clip_surface = ! _cairo_clip_is_region (clip);
+    cairo_region_t *clip_region = _cairo_clip_get_region (extents->clip);
+    cairo_bool_t need_clip_surface = ! _cairo_clip_is_region (extents->clip);
     pixman_image_t *mask;
     cairo_status_t status;
 
     if (clip_region != NULL && cairo_region_num_rectangles (clip_region) == 1)
 	clip_region = NULL;
 
-    mask = pixman_image_create_bits (PIXMAN_a8, extents->width, extents->height,
+    mask = pixman_image_create_bits (PIXMAN_a8, extents->bounded.width, extents->bounded.height,
 				     NULL, 0);
     if (unlikely (mask == NULL))
 	return NULL;
@@ -1909,9 +1907,9 @@ _create_composite_mask_pattern (cairo_clip_t                  *clip,
     if (clip_region != NULL) {
 	pixman_bool_t ret;
 
-	pixman_region32_translate (&clip_region->rgn, -extents->x, -extents->y);
+	pixman_region32_translate (&clip_region->rgn, -extents->bounded.x, -extents->bounded.y);
 	ret = pixman_image_set_clip_region32 (mask, &clip_region->rgn);
-	pixman_region32_translate (&clip_region->rgn, extents->x, extents->y);
+	pixman_region32_translate (&clip_region->rgn, extents->bounded.x, extents->bounded.y);
 
 	if (! ret) {
 	    pixman_image_unref (mask);
@@ -1922,9 +1920,9 @@ _create_composite_mask_pattern (cairo_clip_t                  *clip,
     status = draw_func (draw_closure,
 			mask, PIXMAN_a8,
 			CAIRO_OPERATOR_ADD, NULL,
-			extents->x, extents->y,
+			extents->bounded.x, extents->bounded.y,
 			&dst->base.device_transform,
-			extents, NULL);
+			extents);
     if (unlikely (status)) {
 	pixman_image_unref (mask);
 	return NULL;
@@ -1941,8 +1939,9 @@ _create_composite_mask_pattern (cairo_clip_t                  *clip,
 
 	pixman_image_ref (mask);
 
-	status = _cairo_clip_combine_with_surface (clip, tmp,
-						   extents->x, extents->y);
+	status = _cairo_clip_combine_with_surface (extents->clip, tmp,
+						   extents->bounded.x,
+						   extents->bounded.y);
 	cairo_surface_destroy (tmp);
 	if (unlikely (status)) {
 	    pixman_image_unref (mask);
@@ -1960,17 +1959,16 @@ _create_composite_mask_pattern (cairo_clip_t                  *clip,
  * us to combine the clip with the mask
  */
 static cairo_status_t
-_clip_and_composite_with_mask (cairo_clip_t                  *clip,
+_clip_and_composite_with_mask (cairo_composite_rectangles_t *extents,
 			       cairo_operator_t               op,
 			       const cairo_pattern_t         *pattern,
 			       image_draw_func_t              draw_func,
 			       void                          *draw_closure,
-			       cairo_image_surface_t         *dst,
-			       const cairo_rectangle_int_t   *extents)
+			       cairo_image_surface_t         *dst)
 {
     pixman_image_t *mask;
 
-    mask = _create_composite_mask_pattern (clip, draw_func, draw_closure, dst, extents);
+    mask = _create_composite_mask_pattern (extents, draw_func, draw_closure, dst);
     if (unlikely (mask == NULL))
 	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
 
@@ -1979,8 +1977,8 @@ _clip_and_composite_with_mask (cairo_clip_t                  *clip,
 	    pixman_image_composite32 (_pixman_operator (op),
                                       mask, NULL, dst->pixman_image,
                                       0, 0, 0, 0,
-                                      extents->x,      extents->y,
-                                      extents->width,  extents->height);
+                                      extents->bounded.x,      extents->bounded.y,
+                                      extents->bounded.width,  extents->bounded.height);
 	} else {
 	    pixman_image_t *src;
 
@@ -1993,15 +1991,15 @@ _clip_and_composite_with_mask (cairo_clip_t                  *clip,
 	    pixman_image_composite32 (_pixman_operator (op),
                                       src, mask, dst->pixman_image,
                                       0, 0, 0, 0,
-                                      extents->x,      extents->y,
-                                      extents->width,  extents->height);
+                                      extents->bounded.x,      extents->bounded.y,
+                                      extents->bounded.width,  extents->bounded.height);
 	    pixman_image_unref (src);
 	}
     } else {
 	pixman_image_t *src;
 	int src_x, src_y;
 
-	src = _pixman_image_for_pattern (pattern, FALSE, extents,
+	src = _pixman_image_for_pattern (pattern, FALSE, &extents->bounded,
 					 &dst->base.device_transform,
 					 &src_x, &src_y);
 	if (unlikely (src == NULL)) {
@@ -2011,10 +2009,10 @@ _clip_and_composite_with_mask (cairo_clip_t                  *clip,
 
 	pixman_image_composite32 (_pixman_operator (op),
                                   src, mask, dst->pixman_image,
-                                  extents->x + src_x,  extents->y + src_y,
+                                  extents->bounded.x + src_x,  extents->bounded.y + src_y,
                                   0, 0,
-                                  extents->x,          extents->y,
-                                  extents->width,      extents->height);
+                                  extents->bounded.x,          extents->bounded.y,
+                                  extents->bounded.width,      extents->bounded.height);
 	pixman_image_unref (src);
     }
 
@@ -2027,13 +2025,12 @@ _clip_and_composite_with_mask (cairo_clip_t                  *clip,
  * in two pieces and combine them together.
  */
 static cairo_status_t
-_clip_and_composite_combine (cairo_clip_t                  *clip,
+_clip_and_composite_combine (cairo_composite_rectangles_t	*extents,
 			     cairo_operator_t               op,
 			     const cairo_pattern_t         *src,
 			     image_draw_func_t              draw_func,
 			     void                          *draw_closure,
-			     cairo_image_surface_t               *dst,
-			     const cairo_rectangle_int_t   *extents)
+			     cairo_image_surface_t               *dst)
 {
     pixman_image_t *tmp;
     cairo_surface_t *clip_surface;
@@ -2041,7 +2038,8 @@ _clip_and_composite_combine (cairo_clip_t                  *clip,
     cairo_status_t status;
 
     tmp  = pixman_image_create_bits (dst->pixman_format,
-				     extents->width, extents->height,
+				     extents->bounded.width,
+				     extents->bounded.height,
 				     NULL, 0);
     if (unlikely (tmp == NULL))
 	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
@@ -2050,31 +2048,34 @@ _clip_and_composite_combine (cairo_clip_t                  *clip,
 	status = (*draw_func) (draw_closure,
 			       tmp, dst->pixman_format,
 			       CAIRO_OPERATOR_ADD, NULL,
-			       extents->x, extents->y,
+			       extents->bounded.x, extents->bounded.y,
 			       &dst->base.device_transform,
-			       extents, NULL);
+			       extents);
     } else {
 	/* Initialize the temporary surface from the destination surface */
 	if (! dst->base.is_clear) {
 	    pixman_image_composite32 (PIXMAN_OP_SRC,
                                       dst->pixman_image, NULL, tmp,
-                                      extents->x, extents->y,
+                                      extents->bounded.x,
+				      extents->bounded.y,
                                       0, 0,
                                       0, 0,
-                                      extents->width, extents->height);
+                                      extents->bounded.width,
+				      extents->bounded.height);
 	}
 
 	status = (*draw_func) (draw_closure,
 			       tmp, dst->pixman_format,
 			       op, src,
-			       extents->x, extents->y,
+			       extents->bounded.x, extents->bounded.y,
 			       &dst->base.device_transform,
-			       extents, NULL);
+			       extents);
     }
     if (unlikely (status))
 	goto CLEANUP_SURFACE;
 
-    clip_surface = _cairo_clip_get_surface (clip, &dst->base, &clip_x, &clip_y);
+    clip_surface = _cairo_clip_get_surface (extents->clip, &dst->base,
+					    &clip_x, &clip_y);
     if (unlikely (clip_surface->status))
 	goto CLEANUP_SURFACE;
 
@@ -2085,20 +2086,20 @@ _clip_and_composite_combine (cairo_clip_t                  *clip,
                                   ((cairo_image_surface_t *) clip_surface)->pixman_image,
                                   dst->pixman_image,
                                   0, 0,
-                                  extents->x - clip_x,
-                                  extents->y - clip_y,
-                                  extents->x, extents->y,
-                                  extents->width, extents->height);
+                                  extents->bounded.x - clip_x,
+                                  extents->bounded.y - clip_y,
+                                  extents->bounded.x, extents->bounded.y,
+                                  extents->bounded.width, extents->bounded.height);
 #else
 	/* Punch the clip out of the destination */
 	pixman_image_composite32 (PIXMAN_OP_OUT_REVERSE,
                                   ((cairo_image_surface_t *) clip_surface)->pixman_image,
                                   NULL, dst->pixman_image,
-                                  extents->x - clip_x,
-                                  extents->y - clip_y,
+                                  extents->bounded.x - clip_x,
+                                  extents->bounded.y - clip_y,
                                   0, 0,
-                                  extents->x, extents->y,
-                                  extents->width, extents->height);
+                                  extents->bounded.x, extents->bounded.y,
+                                  extents->bounded.width, extents->bounded.height);
 
 	/* Now add the two results together */
 	pixman_image_composite32 (PIXMAN_OP_ADD,
@@ -2106,10 +2107,10 @@ _clip_and_composite_combine (cairo_clip_t                  *clip,
                                   ((cairo_image_surface_t *) clip_surface)->pixman_image,
                                   dst->pixman_image,
                                   0, 0,
-                                  extents->x - clip_x,
-                                  extents->y - clip_y,
-                                  extents->x, extents->y,
-                                  extents->width, extents->height);
+                                  extents->bounded.x - clip_x,
+                                  extents->bounded.y - clip_y,
+                                  extents->bounded.x, extents->bounded.y,
+                                  extents->bounded.width, extents->bounded.height);
 #endif
     } else {
 	pixman_image_composite32 (PIXMAN_OP_SRC,
@@ -2117,10 +2118,10 @@ _clip_and_composite_combine (cairo_clip_t                  *clip,
                                   ((cairo_image_surface_t *) clip_surface)->pixman_image,
                                   dst->pixman_image,
                                   0, 0,
-                                  extents->x - clip_x,
-                                  extents->y - clip_y,
-                                  extents->x, extents->y,
-                                  extents->width, extents->height);
+                                  extents->bounded.x - clip_x,
+                                  extents->bounded.y - clip_y,
+                                  extents->bounded.x, extents->bounded.y,
+                                  extents->bounded.width, extents->bounded.height);
     }
 
  CLEANUP_SURFACE:
@@ -2133,12 +2134,11 @@ _clip_and_composite_combine (cairo_clip_t                  *clip,
  * defined as (src IN mask IN clip) ADD (dst OUT (mask IN clip))
  */
 static cairo_status_t
-_clip_and_composite_source (cairo_clip_t                  *clip,
+_clip_and_composite_source (cairo_composite_rectangles_t  *extents,
 			    const cairo_pattern_t         *pattern,
 			    image_draw_func_t              draw_func,
 			    void                          *draw_closure,
-			    cairo_image_surface_t         *dst,
-			    const cairo_rectangle_int_t   *extents)
+			    cairo_image_surface_t         *dst)
 {
     pixman_image_t *mask, *src;
     int src_x, src_y;
@@ -2149,24 +2149,25 @@ _clip_and_composite_source (cairo_clip_t                  *clip,
 	status = draw_func (draw_closure,
 			    dst->pixman_image, dst->pixman_format,
 			    CAIRO_OPERATOR_SOURCE, NULL,
-			    extents->x, extents->y,
+			    extents->bounded.x, extents->bounded.y,
 			    &dst->base.device_transform,
-			    extents, NULL);
+			    extents);
 	if (unlikely (status))
 	    return status;
 
-	if (! _cairo_clip_is_region (clip))
-	    status = _cairo_clip_combine_with_surface (clip, &dst->base, 0, 0);
+	if (! _cairo_clip_is_region (extents->clip))
+	    status = _cairo_clip_combine_with_surface (extents->clip,
+						       &dst->base, 0, 0);
 
 	return status;
     }
 
     /* Create a surface that is mask IN clip */
-    mask = _create_composite_mask_pattern (clip, draw_func, draw_closure, dst, extents);
+    mask = _create_composite_mask_pattern (extents, draw_func, draw_closure, dst);
     if (unlikely (mask == NULL))
 	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
 
-    src = _pixman_image_for_pattern (pattern, FALSE, extents,
+    src = _pixman_image_for_pattern (pattern, FALSE, &extents->bounded,
 				     &dst->base.device_transform,
 				     &src_x, &src_y);
     if (unlikely (src == NULL)) {
@@ -2178,33 +2179,33 @@ _clip_and_composite_source (cairo_clip_t                  *clip,
 #if PIXMAN_HAS_OP_LERP
 	pixman_image_composite32 (PIXMAN_OP_LERP,
                                   src, mask, dst->pixman_image,
-                                  extents->x + src_x, extents->y + src_y,
+                                  extents->bounded.x + src_x, extents->bounded.y + src_y,
                                   0, 0,
-                                  extents->x,     extents->y,
-                                  extents->width, extents->height);
+                                  extents->bounded.x,     extents->bounded.y,
+                                  extents->bounded.width, extents->bounded.height);
 #else
 	/* Compute dest' = dest OUT (mask IN clip) */
 	pixman_image_composite32 (PIXMAN_OP_OUT_REVERSE,
                                   mask, NULL, dst->pixman_image,
                                   0, 0, 0, 0,
-                                  extents->x,     extents->y,
-                                  extents->width, extents->height);
+                                  extents->bounded.x,     extents->bounded.y,
+                                  extents->bounded.width, extents->bounded.height);
 
 	/* Now compute (src IN (mask IN clip)) ADD dest' */
 	pixman_image_composite32 (PIXMAN_OP_ADD,
                                   src, mask, dst->pixman_image,
-                                  extents->x + src_x, extents->y + src_y,
+                                  extents->bounded.x + src_x, extents->bounded.y + src_y,
                                   0, 0,
-                                  extents->x,     extents->y,
-                                  extents->width, extents->height);
+                                  extents->bounded.x,     extents->bounded.y,
+                                  extents->bounded.width, extents->bounded.height);
 #endif
     } else {
 	pixman_image_composite32 (PIXMAN_OP_SRC,
                                   src, mask, dst->pixman_image,
-                                  extents->x + src_x, extents->y + src_y,
+                                  extents->bounded.x + src_x, extents->bounded.y + src_y,
                                   0, 0,
-                                  extents->x,     extents->y,
-                                  extents->width, extents->height);
+                                  extents->bounded.x,     extents->bounded.y,
+                                  extents->bounded.width, extents->bounded.height);
     }
 
     pixman_image_unref (src);
@@ -2274,9 +2275,8 @@ _clip_and_composite (cairo_image_surface_t	*dst,
     }
 
     if (op == CAIRO_OPERATOR_SOURCE) {
-	status = _clip_and_composite_source (extents->clip, src,
-					     draw_func, draw_closure,
-					     dst, &extents->bounded);
+	status = _clip_and_composite_source (extents, src,
+					     draw_func, draw_closure, dst);
     } else {
 	if (op == CAIRO_OPERATOR_CLEAR) {
 	    src = NULL;
@@ -2285,13 +2285,13 @@ _clip_and_composite (cairo_image_surface_t	*dst,
 
 	if (need_clip & NEED_CLIP_SURFACE) {
 	    if (extents->is_bounded) {
-		status = _clip_and_composite_with_mask (extents->clip, op, src,
+		status = _clip_and_composite_with_mask (extents, op, src,
 							draw_func, draw_closure,
-							dst, &extents->bounded);
+							dst);
 	    } else {
-		status = _clip_and_composite_combine (extents->clip, op, src,
+		status = _clip_and_composite_combine (extents, op, src,
 						      draw_func, draw_closure,
-						      dst, &extents->bounded);
+						      dst);
 	    }
 	} else {
 	    status = draw_func (draw_closure,
@@ -2299,8 +2299,7 @@ _clip_and_composite (cairo_image_surface_t	*dst,
 				op, src,
 				0, 0,
 				&dst->base.device_transform,
-				&extents->bounded,
-				clip_region);
+				extents);
 	}
     }
 
@@ -2416,9 +2415,8 @@ _composite_traps (void                          *closure,
 		  const cairo_pattern_t         *pattern,
 		  int                            dst_x,
 		  int                            dst_y,
-		  cairo_matrix_t 		*dst_device_transform,
-		  const cairo_rectangle_int_t   *extents,
-		  cairo_region_t		*clip_region)
+		  cairo_matrix_t		*dst_device_transform,
+		  const cairo_composite_rectangles_t   *extents)
 {
     composite_traps_info_t *info = closure;
     pixman_image_t *src, *mask;
@@ -2442,26 +2440,28 @@ _composite_traps (void                          *closure,
 	return CAIRO_STATUS_SUCCESS;
     }
 
-    src = _pixman_image_for_pattern (pattern, FALSE, extents,
+    src = _pixman_image_for_pattern (pattern, FALSE, &extents->bounded,
 				     dst_device_transform,
 				     &src_x, &src_y);
     if (unlikely (src == NULL))
 	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
 
-    mask = pixman_image_create_bits (format, extents->width, extents->height,
+    mask = pixman_image_create_bits (format,
+				     extents->bounded.width,
+				     extents->bounded.height,
 				     NULL, 0);
     if (unlikely (mask == NULL)) {
 	status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
 	goto CLEANUP_SOURCE;
     }
 
-    _pixman_image_add_traps (mask, extents->x, extents->y, info);
+    _pixman_image_add_traps (mask, extents->bounded.x, extents->bounded.y, info);
     pixman_image_composite32 (_pixman_operator (op),
                               src, mask, dst,
-                              extents->x + src_x, extents->y + src_y,
+                              extents->bounded.x + src_x, extents->bounded.y + src_y,
                               0, 0,
-                              extents->x - dst_x, extents->y - dst_y,
-                              extents->width, extents->height);
+                              extents->bounded.x - dst_x, extents->bounded.y - dst_y,
+                              extents->bounded.width, extents->bounded.height);
 
     pixman_image_unref (mask);
 
@@ -3308,8 +3308,7 @@ _composite_mask (void				*closure,
 		 int				 dst_x,
 		 int				 dst_y,
 		 cairo_matrix_t			*dst_device_transform,
-		 const cairo_rectangle_int_t	*extents,
-		 cairo_region_t			*clip_region)
+		 const cairo_composite_rectangles_t	*extents)
 {
     const cairo_pattern_t *mask_pattern = closure;
     pixman_image_t *src, *mask = NULL;
@@ -3317,13 +3316,13 @@ _composite_mask (void				*closure,
     int mask_x = 0, mask_y = 0;
 
     if (src_pattern != NULL) {
-	src = _pixman_image_for_pattern (src_pattern, FALSE, extents,
+	src = _pixman_image_for_pattern (src_pattern, FALSE, &extents->bounded,
 					 dst_device_transform,
 					 &src_x, &src_y);
 	if (unlikely (src == NULL))
 	    return _cairo_error (CAIRO_STATUS_NO_MEMORY);
 
-	mask = _pixman_image_for_pattern (mask_pattern, TRUE, extents,
+	mask = _pixman_image_for_pattern (mask_pattern, TRUE, &extents->bounded,
 					  dst_device_transform,
 					  &mask_x, &mask_y);
 	if (unlikely (mask == NULL)) {
@@ -3334,7 +3333,7 @@ _composite_mask (void				*closure,
 	if (mask_pattern->has_component_alpha)
 	    pixman_image_set_component_alpha (mask, TRUE);
     } else {
-	src = _pixman_image_for_pattern (mask_pattern, FALSE, extents,
+	src = _pixman_image_for_pattern (mask_pattern, FALSE, &extents->bounded,
 					 dst_device_transform,
 					 &src_x, &src_y);
 	if (unlikely (src == NULL))
@@ -3342,10 +3341,10 @@ _composite_mask (void				*closure,
     }
 
     pixman_image_composite32 (_pixman_operator (op), src, mask, dst,
-                              extents->x + src_x,  extents->y + src_y,
-                              extents->x + mask_x, extents->y + mask_y,
-                              extents->x - dst_x,  extents->y - dst_y,
-                              extents->width,      extents->height);
+                              extents->bounded.x + src_x,  extents->bounded.y + src_y,
+                              extents->bounded.x + mask_x, extents->bounded.y + mask_y,
+                              extents->bounded.x - dst_x,  extents->bounded.y - dst_y,
+                              extents->bounded.width,      extents->bounded.height);
 
     if (mask != NULL)
 	pixman_image_unref (mask);
@@ -3354,6 +3353,151 @@ _composite_mask (void				*closure,
     return CAIRO_STATUS_SUCCESS;
 }
 
+static void do_unaligned_row(void (*blt)(void *closure,
+					 int16_t x, int16_t y,
+					 int16_t w, int16_t h,
+					 uint16_t coverage),
+			     void *closure,
+			     const cairo_box_t *b,
+			     int tx, int y, int h,
+			     uint16_t coverage)
+{
+    int x1 = _cairo_fixed_integer_part (b->p1.x) - tx;
+    int x2 = _cairo_fixed_integer_part (b->p2.x) - tx;
+    if (x2 > x1) {
+	if (! _cairo_fixed_is_integer (b->p1.x)) {
+	    blt(closure, x1, y, 1, h,
+		coverage * (256 - _cairo_fixed_fractional_part (b->p1.x)));
+	    x1++;
+	}
+
+	if (x2 > x1)
+	    blt(closure, x1, y, x2-x1, h, (coverage << 8) - (coverage >> 8));
+
+	if (! _cairo_fixed_is_integer (b->p2.x))
+	    blt(closure, x2, y, 1, h,
+		coverage * _cairo_fixed_fractional_part (b->p2.x));
+    } else
+	blt(closure, x1, y, 1, h,
+	    coverage * (b->p2.x - b->p1.x));
+}
+
+static void do_unaligned_box(void (*blt)(void *closure,
+					 int16_t x, int16_t y,
+					 int16_t w, int16_t h,
+					 uint16_t coverage),
+			     void *closure,
+			     const cairo_box_t *b, int tx, int ty)
+{
+    int y1 = _cairo_fixed_integer_part (b->p1.y) - ty;
+    int y2 = _cairo_fixed_integer_part (b->p2.y) - ty;
+    if (y2 > y1) {
+	if (! _cairo_fixed_is_integer (b->p1.y)) {
+	    do_unaligned_row(blt, closure, b, tx, y1, 1,
+			     256 - _cairo_fixed_fractional_part (b->p1.y));
+	    y1++;
+	}
+
+	if (y2 > y1)
+	    do_unaligned_row(blt, closure, b, tx, y1, y2-y1, 256);
+
+	if (! _cairo_fixed_is_integer (b->p2.y))
+	    do_unaligned_row(blt, closure, b, tx, y2, 1,
+			     _cairo_fixed_fractional_part (b->p2.y));
+    } else
+	do_unaligned_row(blt, closure, b, tx, y1, 1,
+			 b->p2.y - b->p1.y);
+}
+
+struct composite_opacity_info {
+    uint8_t op;
+    pixman_image_t *dst;
+    pixman_image_t *src;
+    int src_x, src_y;
+    double opacity;
+};
+
+static void composite_opacity(void *closure,
+			      int16_t x, int16_t y,
+			      int16_t w, int16_t h,
+			      uint16_t coverage)
+{
+    struct composite_opacity_info *info = closure;
+    pixman_color_t color;
+    pixman_image_t *mask;
+
+    color.red   = 0;
+    color.green = 0;
+    color.blue  = 0;
+    color.alpha = coverage * info->opacity;
+
+    mask = pixman_image_create_solid_fill (&color);
+    if (mask == NULL)
+	return;
+
+    if (info->src) {
+	pixman_image_composite32 (info->op,
+				  info->src,
+				  mask,
+				  info->dst,
+				  x + info->src_x,  y + info->src_y,
+				  0,                 0,
+				  x,                 y,
+				  w,                 h);
+    } else {
+	pixman_image_composite32 (info->op,
+				  mask,
+				  NULL,
+				  info->dst,
+				  0, 0,
+				  0, 0,
+				  x, y,
+				  w, h);
+    }
+
+    pixman_image_unref (mask);
+}
+
+static cairo_status_t
+_composite_opacity_boxes (void				*closure,
+			  pixman_image_t		*dst,
+			  pixman_format_code_t		 dst_format,
+			  cairo_operator_t		 op,
+			  const cairo_pattern_t		*src_pattern,
+			  int				 dst_x,
+			  int				 dst_y,
+			  cairo_matrix_t		*dst_device_transform,
+			  const cairo_composite_rectangles_t	*extents)
+{
+    const cairo_solid_pattern_t *mask_pattern = closure;
+    struct composite_opacity_info info;
+    int i;
+
+    info.op = _pixman_operator (op);
+    info.dst = dst;
+
+    if (src_pattern != NULL) {
+	info.src = _pixman_image_for_pattern (src_pattern, TRUE, &extents->bounded,
+					      dst_device_transform,
+					      &info.src_x, &info.src_y);
+	if (unlikely (info.src == NULL))
+	    return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+    } else
+	info.src = NULL;
+
+    info.opacity = mask_pattern->color.alpha;
+
+    /* XXX for lots of boxes create a clip region for the fully opaque areas */
+    for (i = 0; i < extents->clip->num_boxes; i++)
+	do_unaligned_box(composite_opacity, &info,
+			 &extents->clip->boxes[i], dst_x, dst_y);
+    if (info.src)
+	pixman_image_unref (info.src);
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+
 static cairo_int_status_t
 _cairo_image_surface_mask (void				*abstract_surface,
 			   cairo_operator_t		 op,
@@ -3371,9 +3515,18 @@ _cairo_image_surface_mask (void				*abstract_surface,
     if (unlikely (status))
 	return status;
 
-    status = _clip_and_composite (surface, op, source,
-				  _composite_mask, (void *) mask,
-				  &extents, need_bounded_clip (&extents));
+    if (mask->type == CAIRO_PATTERN_TYPE_SOLID &&
+	extents.clip->path == NULL &&
+	! _cairo_clip_is_region (extents.clip))
+    {
+	status = _clip_and_composite (surface, op, source,
+				      _composite_opacity_boxes, (void *) mask,
+				      &extents, need_bounded_clip (&extents));
+    } else {
+	status = _clip_and_composite (surface, op, source,
+				      _composite_mask, (void *) mask,
+				      &extents, need_bounded_clip (&extents));
+    }
 
     _cairo_composite_rectangles_fini (&extents);
 
@@ -3396,8 +3549,7 @@ _composite_spans (void                          *closure,
 		  int                            dst_x,
 		  int                            dst_y,
 		  cairo_matrix_t		*dst_device_transform,
-		  const cairo_rectangle_int_t   *extents,
-		  cairo_region_t		*clip_region)
+		  const cairo_composite_rectangles_t   *extents)
 {
     uint8_t mask_buf[CAIRO_STACK_BUFFER_SIZE];
     composite_spans_info_t *info = closure;
@@ -3409,19 +3561,20 @@ _composite_spans (void                          *closure,
     cairo_scan_converter_t *converter;
 #endif
     pixman_image_t *mask;
+    const cairo_rectangle_int_t *r = &extents->bounded;
     cairo_status_t status;
 
 #if USE_BOTOR_SCAN_CONVERTER
-    box.p1.x = _cairo_fixed_from_int (extents->x);
-    box.p1.y = _cairo_fixed_from_int (extents->y);
-    box.p2.x = _cairo_fixed_from_int (extents->x + extents->width);
-    box.p2.y = _cairo_fixed_from_int (extents->y + extents->height);
+    box.p1.x = _cairo_fixed_from_int (r->x);
+    box.p1.y = _cairo_fixed_from_int (r->y);
+    box.p2.x = _cairo_fixed_from_int (r->x + r->width);
+    box.p2.y = _cairo_fixed_from_int (r->y + r->height);
     _cairo_botor_scan_converter_init (&converter, &box, info->fill_rule);
     status = converter.base.add_polygon (&converter.base, info->polygon);
 #else
-    converter = _cairo_tor_scan_converter_create (extents->x, extents->y,
-						  extents->x + extents->width,
-						  extents->y + extents->height,
+    converter = _cairo_tor_scan_converter_create (r->x, r->y,
+						  r->x + r->width,
+						  r->y + r->height,
 						  info->fill_rule);
     status = converter->add_polygon (converter, info->polygon);
 #endif
@@ -3440,17 +3593,17 @@ _composite_spans (void                          *closure,
     }
     else
     {
-	int stride = CAIRO_STRIDE_FOR_WIDTH_BPP (extents->width, 8);
+	int stride = CAIRO_STRIDE_FOR_WIDTH_BPP (r->width, 8);
 	uint8_t *data = mask_buf;
 
-	if (extents->height * stride <= (int) sizeof (mask_buf))
-	    memset (data, 0, extents->height * stride);
+	if (r->height * stride <= (int) sizeof (mask_buf))
+	    memset (data, 0, r->height * stride);
 	else
 	    data = NULL, stride = 0;
 
 	mask = pixman_image_create_bits (PIXMAN_a8,
-					 extents->width,
-					 extents->height,
+					 r->width,
+					 r->height,
 					 (uint32_t *) data,
 					 stride);
 	if (unlikely (mask == NULL)) {
@@ -3463,7 +3616,7 @@ _composite_spans (void                          *closure,
     renderer.mask_stride = pixman_image_get_stride (mask);
     renderer.mask_data = (uint8_t *) pixman_image_get_data (mask);
     if (dst != NULL)
-	renderer.mask_data -= extents->y * renderer.mask_stride + extents->x;
+	renderer.mask_data -= r->y * renderer.mask_stride + r->x;
     else
 	renderer.mask_data -= dst_y * renderer.mask_stride + dst_x;
 
@@ -3479,7 +3632,7 @@ _composite_spans (void                          *closure,
 	pixman_image_t *src;
 	int src_x, src_y;
 
-	src = _pixman_image_for_pattern (pattern, FALSE, extents,
+	src = _pixman_image_for_pattern (pattern, FALSE, r,
 					 dst_device_transform,
 					 &src_x, &src_y);
 	if (unlikely (src == NULL)) {
@@ -3488,10 +3641,10 @@ _composite_spans (void                          *closure,
 	}
 
 	pixman_image_composite32 (_pixman_operator (op), src, mask, dst,
-                                  extents->x + src_x, extents->y + src_y,
+                                  r->x + src_x, r->y + src_y,
                                   0, 0, /* mask.x, mask.y */
-                                  extents->x - dst_x, extents->y - dst_y,
-                                  extents->width, extents->height);
+                                  r->x - dst_x, r->y - dst_y,
+                                  r->width, r->height);
 	pixman_image_unref (src);
     }
 
@@ -3703,8 +3856,7 @@ _composite_glyphs_via_mask (void			*closure,
 			    int				 dst_x,
 			    int				 dst_y,
 			    cairo_matrix_t		*dst_device_transform,
-			    const cairo_rectangle_int_t	*extents,
-			    cairo_region_t		*clip_region)
+			    const cairo_composite_rectangles_t	*extents)
 {
     composite_glyphs_info_t *info = closure;
     cairo_scaled_font_t *font = info->font;
@@ -3718,7 +3870,7 @@ _composite_glyphs_via_mask (void			*closure,
     int src_x, src_y;
     int i;
 
-    src = _pixman_image_for_pattern (pattern, FALSE, extents,
+    src = _pixman_image_for_pattern (pattern, FALSE, &extents->bounded,
 				     dst_device_transform,
 				     &src_x, &src_y);
     if (unlikely (src == NULL))
@@ -3754,7 +3906,8 @@ _composite_glyphs_via_mask (void			*closure,
 	if (mask == NULL) {
 	    mask_format = glyph_surface->pixman_format;
 	    mask = pixman_image_create_bits (mask_format,
-					     extents->width, extents->height,
+					     extents->bounded.width,
+					     extents->bounded.height,
 					     NULL, 0);
 	    if (unlikely (mask == NULL)) {
 		status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
@@ -3775,7 +3928,8 @@ _composite_glyphs_via_mask (void			*closure,
 
 	    mask_format = glyph_surface->pixman_format;
 	    new_mask = pixman_image_create_bits (mask_format,
-						 extents->width, extents->height,
+						 extents->bounded.width,
+						 extents->bounded.height,
 						 NULL, 0);
 	    if (unlikely (new_mask == NULL)) {
 		status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
@@ -3785,7 +3939,8 @@ _composite_glyphs_via_mask (void			*closure,
 	    pixman_image_composite32 (PIXMAN_OP_SRC,
                                       white, mask, new_mask,
                                       0, 0, 0, 0, 0, 0,
-                                      extents->width, extents->height);
+                                      extents->bounded.width,
+				      extents->bounded.height);
 
 	    pixman_image_unref (mask);
 	    mask = new_mask;
@@ -3803,14 +3958,14 @@ _composite_glyphs_via_mask (void			*closure,
 	    pixman_image_composite32 (PIXMAN_OP_ADD,
                                       glyph_surface->pixman_image, NULL, mask,
                                       0, 0, 0, 0,
-                                      x - extents->x, y - extents->y,
+                                      x - extents->bounded.x, y - extents->bounded.y,
                                       glyph_surface->width,
                                       glyph_surface->height);
 	} else {
 	    pixman_image_composite32 (PIXMAN_OP_ADD,
                                       white, glyph_surface->pixman_image, mask,
                                       0, 0, 0, 0,
-                                      x - extents->x, y - extents->y,
+                                      x - extents->bounded.x, y - extents->bounded.y,
                                       glyph_surface->width,
                                       glyph_surface->height);
 	}
@@ -3818,10 +3973,10 @@ _composite_glyphs_via_mask (void			*closure,
 
     pixman_image_composite32 (_pixman_operator (op),
                               src, mask, dst,
-                              extents->x + src_x, extents->y + src_y,
+                              extents->bounded.x + src_x, extents->bounded.y + src_y,
                               0, 0,
-                              extents->x - dst_x, extents->y - dst_y,
-                              extents->width,     extents->height);
+                              extents->bounded.x - dst_x, extents->bounded.y - dst_y,
+                              extents->bounded.width,     extents->bounded.height);
 
 CLEANUP:
     _cairo_scaled_font_thaw_cache (font);
@@ -3842,8 +3997,7 @@ _composite_glyphs (void				*closure,
 		   int				 dst_x,
 		   int				 dst_y,
 		   cairo_matrix_t		*dst_device_transform,
-		   const cairo_rectangle_int_t	*extents,
-		   cairo_region_t		*clip_region)
+		   const cairo_composite_rectangles_t	*extents)
 {
     composite_glyphs_info_t *info = closure;
     cairo_scaled_glyph_t *glyph_cache[64];
@@ -3854,7 +4008,7 @@ _composite_glyphs (void				*closure,
     int i;
 
     if (pattern != NULL) {
-	src = _pixman_image_for_pattern (pattern, FALSE, extents,
+	src = _pixman_image_for_pattern (pattern, FALSE, &extents->bounded,
 					 dst_device_transform,
 					 &src_x, &src_y);
 	src_x -= dst_x;
@@ -3902,18 +4056,18 @@ _composite_glyphs (void				*closure,
 			       glyph_surface->base.device_transform.y0);
 
 	    x1 = x;
-	    if (x1 < extents->x)
-		x1 = extents->x;
+	    if (x1 < extents->bounded.x)
+		x1 = extents->bounded.x;
 	    x2 = x + glyph_surface->width;
-	    if (x2 > extents->x + extents->width)
-		x2 = extents->x + extents->width;
+	    if (x2 > extents->bounded.x + extents->bounded.width)
+		x2 = extents->bounded.x + extents->bounded.width;
 
 	    y1 = y;
-	    if (y1 < extents->y)
-		y1 = extents->y;
+	    if (y1 < extents->bounded.y)
+		y1 = extents->bounded.y;
 	    y2 = y + glyph_surface->height;
-	    if (y2 > extents->y + extents->height)
-		y2 = extents->y + extents->height;
+	    if (y2 > extents->bounded.y + extents->bounded.height)
+		y2 = extents->bounded.y + extents->bounded.height;
 
 	    pixman_image_composite32 (pixman_op,
                                       src, glyph_surface->pixman_image, dst,
@@ -4295,8 +4449,7 @@ _cairo_image_surface_composite_trapezoids (cairo_operator_t	op,
 			       &source_pattern.base,
 			       0, 0,
 			       &dst->base.device_transform,
-			       &extents.bounded,
-			       clip_region);
+			       &extents);
 
     if (status == CAIRO_STATUS_SUCCESS && ! extents.is_bounded)
 	status = _cairo_image_surface_fixup_unbounded (dst, &extents, NULL);
commit a30a7402f73485dabdb6a016178247f9844017a1
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Sat Jul 23 12:19:17 2011 +0100

    image: replay the recording surface directly onto the target
    
    백현기 reported a use-case where he was recording an entire web-page
    onto the recording surface, in order to facilitate panning. In this
    scenario, where there may be lots of similar surfaces within the
    recording we generate thousands of unused snapshot-images bloating
    memory usage and impairing performance.
    
    Under the right conditions we can replay directly onto the destination
    which not only bypasses the snapshots but also skips the following
    resampling.
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/src/cairo-clip-boxes.c b/src/cairo-clip-boxes.c
index 95ed265..98d1a18 100644
--- a/src/cairo-clip-boxes.c
+++ b/src/cairo-clip-boxes.c
@@ -560,3 +560,20 @@ _cairo_clip_to_boxes (cairo_clip_t *clip,
     return CAIRO_STATUS_SUCCESS;
 
 }
+
+cairo_clip_t *
+_cairo_clip_from_boxes (const cairo_boxes_t *boxes)
+{
+    cairo_clip_t *clip = _cairo_clip_create ();
+    if (clip == NULL)
+	return _cairo_clip_set_all_clipped (clip);
+
+    /* XXX cow-boxes? */
+    clip->boxes = _cairo_boxes_to_array (boxes, &clip->num_boxes, TRUE);
+    if (clip->boxes == NULL)
+	return _cairo_clip_set_all_clipped (clip);
+
+    _cairo_boxes_extents (boxes, &clip->extents);
+
+    return clip;
+}
diff --git a/src/cairo-clip-private.h b/src/cairo-clip-private.h
index 2ad53ef..7f44bdf 100644
--- a/src/cairo-clip-private.h
+++ b/src/cairo-clip-private.h
@@ -116,6 +116,18 @@ _cairo_clip_copy_intersect_rectangle (const cairo_clip_t       *clip,
 }
 
 cairo_private cairo_clip_t *
+_cairo_clip_intersect_clip (cairo_clip_t *clip,
+			    const cairo_clip_t *other);
+
+static inline cairo_clip_t *
+_cairo_clip_copy_intersect_clip (const cairo_clip_t *clip,
+				 const cairo_clip_t *other)
+{
+    return _cairo_clip_intersect_clip (_cairo_clip_copy (clip), other);
+}
+
+
+cairo_private cairo_clip_t *
 _cairo_clip_intersect_box (cairo_clip_t       *clip,
 			   const cairo_box_t *box);
 
@@ -151,6 +163,9 @@ cairo_private cairo_status_t
 _cairo_clip_to_boxes (cairo_clip_t *clip,
 		      cairo_boxes_t *boxes);
 
+cairo_private cairo_clip_t *
+_cairo_clip_from_boxes (const cairo_boxes_t *boxes);
+
 cairo_private cairo_region_t *
 _cairo_clip_get_region (const cairo_clip_t *clip);
 
diff --git a/src/cairo-clip.c b/src/cairo-clip.c
index e5979d5..99336bd 100644
--- a/src/cairo-clip.c
+++ b/src/cairo-clip.c
@@ -250,14 +250,14 @@ _cairo_clip_intersect_path (cairo_clip_t       *clip,
     if (clip == NULL) {
 	clip = _cairo_clip_create ();
 	if (unlikely (clip == NULL))
-		return _cairo_clip_set_all_clipped (clip);
+	    return _cairo_clip_set_all_clipped (clip);
 
 	clip->extents = extents;
     }
 
     clip_path = _cairo_clip_path_create (clip);
     if (unlikely (clip_path == NULL))
-	    return _cairo_clip_set_all_clipped (clip);
+	return _cairo_clip_set_all_clipped (clip);
 
     status = _cairo_path_fixed_init_copy (&clip_path->path, path);
     if (unlikely (status))
@@ -267,7 +267,70 @@ _cairo_clip_intersect_path (cairo_clip_t       *clip,
     clip_path->tolerance = tolerance;
     clip_path->antialias = antialias;
 
+    if (clip->region) {
+	cairo_region_destroy (clip->region);
+	clip->region = NULL;
+    }
+
+    clip->is_region = FALSE;
+    return clip;
+}
+
+static cairo_clip_t *
+_cairo_clip_intersect_clip_path (cairo_clip_t *clip,
+				 const cairo_clip_path_t *clip_path)
+{
+    if (clip_path->prev)
+	clip = _cairo_clip_intersect_clip_path (clip, clip_path->prev);
+
+    return _cairo_clip_intersect_path (clip,
+				       &clip_path->path,
+				       clip_path->fill_rule,
+				       clip_path->tolerance,
+				       clip_path->antialias);
+}
+
+cairo_clip_t *
+_cairo_clip_intersect_clip (cairo_clip_t *clip,
+			    const cairo_clip_t *other)
+{
+    if (_cairo_clip_is_all_clipped (clip))
+	return clip;
+
+    if (other == NULL)
+	return clip;
+
+    if (clip == NULL)
+	return _cairo_clip_copy (other);
+
+    if (_cairo_clip_is_all_clipped (other))
+	return _cairo_clip_set_all_clipped (clip);
+
+    if (! _cairo_rectangle_intersect (&clip->extents, &other->extents))
+	return _cairo_clip_set_all_clipped (clip);
+
+    if (other->num_boxes) {
+	cairo_boxes_t boxes;
+
+	_cairo_boxes_init_for_array (&boxes, other->boxes, other->num_boxes);
+	clip = _cairo_clip_intersect_boxes (clip, &boxes);
+    }
+
+    if (! _cairo_clip_is_all_clipped (clip)) {
+	if (other->path) {
+	    if (clip->path == NULL)
+		clip->path = _cairo_clip_path_reference (other->path);
+	    else
+		clip = _cairo_clip_intersect_clip_path (clip, other->path);
+	}
+    }
+
+    if (clip->region) {
+	cairo_region_destroy (clip->region);
+	clip->region = NULL;
+    }
     clip->is_region = FALSE;
+
     return clip;
 }
 
diff --git a/src/cairo-image-surface.c b/src/cairo-image-surface.c
index a03e1ab..f727b84 100644
--- a/src/cairo-image-surface.c
+++ b/src/cairo-image-surface.c
@@ -44,6 +44,7 @@
 #include "cairo-composite-rectangles-private.h"
 #include "cairo-default-context-private.h"
 #include "cairo-error-private.h"
+#include "cairo-recording-surface-private.h"
 #include "cairo-region-private.h"
 #include "cairo-pattern-private.h"
 #include "cairo-scaled-font-private.h"
@@ -2878,6 +2879,27 @@ _composite_unaligned_boxes (cairo_image_surface_t *dst,
     return status;
 }
 
+static cairo_bool_t
+is_recording_pattern (const cairo_pattern_t *pattern)
+{
+    const cairo_surface_pattern_t *surface_pattern;
+
+    if (pattern->type != CAIRO_PATTERN_TYPE_SURFACE)
+	return FALSE;
+
+   surface_pattern = (const cairo_surface_pattern_t *) pattern;
+   return _cairo_surface_is_recording (surface_pattern->surface);
+}
+
+static cairo_surface_t *
+pattern_get_surface (const cairo_pattern_t *pattern)
+{
+    const cairo_surface_pattern_t *surface_pattern;
+
+   surface_pattern = (const cairo_surface_pattern_t *) pattern;
+   return surface_pattern->surface;
+}
+
 static cairo_status_t
 _composite_boxes (cairo_image_surface_t *dst,
 		  cairo_operator_t op,
@@ -2916,6 +2938,47 @@ _composite_boxes (cairo_image_surface_t *dst,
 	}
     }
 
+    /* Are we just copying a recording surface? */
+    if (! need_clip_mask &&
+	op == CAIRO_OPERATOR_SOURCE &&
+	pattern->extend == CAIRO_EXTEND_NONE && /* or if sample is contained */
+	is_recording_pattern (pattern))
+    {
+	cairo_clip_t *recording_clip;
+
+	/* first clear the area about to be overwritten */
+	if (! dst->base.is_clear) {
+	    for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
+		cairo_box_t *box = chunk->base;
+
+		for (i = 0; i < chunk->count; i++) {
+		    int x1 = _cairo_fixed_integer_round_down (box[i].p1.x);
+		    int y1 = _cairo_fixed_integer_round_down (box[i].p1.y);
+		    int x2 = _cairo_fixed_integer_round_down (box[i].p2.x);
+		    int y2 = _cairo_fixed_integer_round_down (box[i].p2.y);
+
+		    if (x2 == x1 || y2 == y1)
+			continue;
+
+		    pixman_fill ((uint32_t *) dst->data,
+				 dst->stride / sizeof (uint32_t),
+				 PIXMAN_FORMAT_BPP (dst->pixman_format),
+				 x1, y1, x2 - x1, y2 - y1,
+				 0);
+		}
+	    }
+	}
+
+	recording_clip = _cairo_clip_from_boxes (boxes);
+	status = _cairo_recording_surface_replay_with_clip (pattern_get_surface (pattern),
+							    &pattern->matrix,
+							    &dst->base,
+							    recording_clip);
+	_cairo_clip_destroy (recording_clip);
+
+	return status;
+    }
+
     status = CAIRO_STATUS_SUCCESS;
     if (! need_clip_mask &&
 	pattern_to_pixel ((cairo_solid_pattern_t *) pattern, op, dst->pixman_format,
@@ -4476,7 +4539,6 @@ _cairo_image_surface_coerce (cairo_image_surface_t *surface)
 {
     return _cairo_image_surface_coerce_to_format (surface,
 		                                  _cairo_format_from_content (surface->base.content));
-        
 }
 
 /* A convenience function for when one needs to coerce an image
diff --git a/src/cairo-recording-surface-private.h b/src/cairo-recording-surface-private.h
index a901e7b..cc23d80 100644
--- a/src/cairo-recording-surface-private.h
+++ b/src/cairo-recording-surface-private.h
@@ -145,6 +145,12 @@ _cairo_recording_surface_replay (cairo_surface_t *surface,
 				 cairo_surface_t *target);
 
 cairo_private cairo_status_t
+_cairo_recording_surface_replay_with_clip (cairo_surface_t *surface,
+					   const cairo_matrix_t *surface_transform,
+					   cairo_surface_t *target,
+					   const cairo_clip_t *target_clip);
+
+cairo_private cairo_status_t
 _cairo_recording_surface_replay_and_create_regions (cairo_surface_t *surface,
 						    cairo_surface_t *target);
 cairo_private cairo_status_t
diff --git a/src/cairo-recording-surface.c b/src/cairo-recording-surface.c
index ea5ee01..96c71fd 100644
--- a/src/cairo-recording-surface.c
+++ b/src/cairo-recording-surface.c
@@ -251,14 +251,6 @@ _cairo_recording_surface_acquire_source_image_transformed (void			   *abstract_s
     double width;
     double height;
 
-    image = _cairo_surface_has_snapshot (&surface->base,
-					 &_cairo_image_surface_backend);
-    if (image != NULL) {
-	*image_out = (cairo_image_surface_t *) cairo_surface_reference (image);
-	*image_extra = NULL;
-	return CAIRO_STATUS_SUCCESS;
-    }
-
     width = surface->extents.width * device_transform->xx;
     height = surface->extents.height * device_transform->yy;
     image = _cairo_image_surface_create_with_content (surface->content,
@@ -278,8 +270,6 @@ _cairo_recording_surface_acquire_source_image_transformed (void			   *abstract_s
 	return status;
     }
 
-    _cairo_surface_attach_snapshot (&surface->base, image, NULL);
-
     *image_out = (cairo_image_surface_t *) image;
     *image_extra = NULL;
     return CAIRO_STATUS_SUCCESS;
@@ -291,11 +281,29 @@ _cairo_recording_surface_acquire_source_image (void			 *abstract_surface,
 					       void			**image_extra)
 {
     cairo_matrix_t identity;
+    cairo_surface_t *image;
+    cairo_status_t status;
+
+    image = _cairo_surface_has_snapshot (abstract_surface,
+					 &_cairo_image_surface_backend);
+    if (image != NULL) {
+	*image_out = (cairo_image_surface_t *) cairo_surface_reference (image);
+	*image_extra = NULL;
+	return CAIRO_STATUS_SUCCESS;
+    }
 
     cairo_matrix_init_identity (&identity);
 
-    return _cairo_recording_surface_acquire_source_image_transformed (
-	abstract_surface, &identity, image_out, image_extra);
+    status =
+	_cairo_recording_surface_acquire_source_image_transformed (abstract_surface, &identity, image_out, image_extra);
+    if (unlikely (status))
+	return status;
+
+    _cairo_surface_attach_snapshot (abstract_surface,
+				    &(*image_out)->base,
+				    NULL);
+    return CAIRO_STATUS_SUCCESS;
+
 }
 
 static void
@@ -817,7 +825,9 @@ _cairo_recording_surface_get_path (cairo_surface_t    *surface,
 static cairo_status_t
 _cairo_recording_surface_replay_internal (cairo_surface_t	     *surface,
 					  const cairo_rectangle_int_t *surface_extents,
+					  const cairo_matrix_t *surface_transform,
 					  cairo_surface_t	     *target,
+					  const cairo_clip_t *target_clip,
 					  cairo_recording_replay_type_t type,
 					  cairo_recording_region_type_t region)
 {
@@ -843,6 +853,8 @@ _cairo_recording_surface_replay_internal (cairo_surface_t	     *surface,
 
     _cairo_surface_wrapper_init (&wrapper, target);
     _cairo_surface_wrapper_set_extents (&wrapper, surface_extents);
+    _cairo_surface_wrapper_set_inverse_transform (&wrapper, surface_transform);
+    _cairo_surface_wrapper_set_clip (&wrapper, target_clip);
 
     recording_surface = (cairo_recording_surface_t *) surface;
     status = CAIRO_STATUS_SUCCESS;
@@ -854,7 +866,8 @@ _cairo_recording_surface_replay_internal (cairo_surface_t	     *surface,
 	cairo_command_t *command = elements[i];
 	cairo_clip_t *clip = command->header.clip;
 
-	if (type == CAIRO_RECORDING_REPLAY && region != CAIRO_RECORDING_REGION_ALL) {
+	if (type == CAIRO_RECORDING_REPLAY &&
+	    region != CAIRO_RECORDING_REGION_ALL) {
 	    if (command->header.region != region)
 		continue;
         }
@@ -881,7 +894,6 @@ _cairo_recording_surface_replay_internal (cairo_surface_t	     *surface,
 	    break;
 
 	case CAIRO_COMMAND_STROKE:
-	{
 	    status = _cairo_surface_wrapper_stroke (&wrapper,
 						    command->header.op,
 						    &command->stroke.source.base,
@@ -893,7 +905,7 @@ _cairo_recording_surface_replay_internal (cairo_surface_t	     *surface,
 						    command->stroke.antialias,
 						    clip);
 	    break;
-	}
+
 	case CAIRO_COMMAND_FILL:
 	{
 	    cairo_command_t *stroke_command;
@@ -945,6 +957,7 @@ _cairo_recording_surface_replay_internal (cairo_surface_t	     *surface,
 	    }
 	    break;
 	}
+
 	case CAIRO_COMMAND_SHOW_TEXT_GLYPHS:
 	{
 	    cairo_glyph_t *glyphs = command->show_text_glyphs.glyphs;
@@ -975,6 +988,7 @@ _cairo_recording_surface_replay_internal (cairo_surface_t	     *surface,
 	    free (glyphs_copy);
 	    break;
 	}
+
 	default:
 	    ASSERT_NOT_REACHED;
 	}
@@ -1017,8 +1031,20 @@ cairo_status_t
 _cairo_recording_surface_replay (cairo_surface_t *surface,
 				 cairo_surface_t *target)
 {
-    return _cairo_recording_surface_replay_internal (surface, NULL,
-						     target,
+    return _cairo_recording_surface_replay_internal (surface, NULL, NULL,
+						     target, NULL,
+						     CAIRO_RECORDING_REPLAY,
+						     CAIRO_RECORDING_REGION_ALL);
+}
+
+cairo_status_t
+_cairo_recording_surface_replay_with_clip (cairo_surface_t *surface,
+					   const cairo_matrix_t *surface_transform,
+					   cairo_surface_t *target,
+					   const cairo_clip_t *target_clip)
+{
+    return _cairo_recording_surface_replay_internal (surface, NULL, surface_transform,
+						     target, target_clip,
 						     CAIRO_RECORDING_REPLAY,
 						     CAIRO_RECORDING_REGION_ALL);
 }
@@ -1033,8 +1059,8 @@ cairo_status_t
 _cairo_recording_surface_replay_and_create_regions (cairo_surface_t *surface,
 						    cairo_surface_t *target)
 {
-    return _cairo_recording_surface_replay_internal (surface, NULL,
-						     target,
+    return _cairo_recording_surface_replay_internal (surface, NULL, NULL,
+						     target, NULL,
 						     CAIRO_RECORDING_CREATE_REGIONS,
 						     CAIRO_RECORDING_REGION_ALL);
 }
@@ -1045,8 +1071,8 @@ _cairo_recording_surface_replay_region (cairo_surface_t          *surface,
 					cairo_surface_t          *target,
 					cairo_recording_region_type_t  region)
 {
-    return _cairo_recording_surface_replay_internal (surface, surface_extents,
-						     target,
+    return _cairo_recording_surface_replay_internal (surface, surface_extents, NULL,
+						     target, NULL,
 						     CAIRO_RECORDING_REPLAY,
 						     region);
 }
diff --git a/src/cairo-surface-wrapper-private.h b/src/cairo-surface-wrapper-private.h
index b3d3a55..97ac809 100644
--- a/src/cairo-surface-wrapper-private.h
+++ b/src/cairo-surface-wrapper-private.h
@@ -46,8 +46,13 @@ CAIRO_BEGIN_DECLS
 struct _cairo_surface_wrapper {
     cairo_surface_t *target;
 
+    cairo_matrix_t transform;
+
     cairo_bool_t has_extents;
     cairo_rectangle_int_t extents;
+    const cairo_clip_t *clip;
+
+    cairo_bool_t needs_transform;
 };
 
 cairo_private void
@@ -59,6 +64,14 @@ _cairo_surface_wrapper_set_extents (cairo_surface_wrapper_t *wrapper,
 				    const cairo_rectangle_int_t *extents);
 
 cairo_private void
+_cairo_surface_wrapper_set_inverse_transform (cairo_surface_wrapper_t *wrapper,
+					      const cairo_matrix_t *transform);
+
+cairo_private void
+_cairo_surface_wrapper_set_clip (cairo_surface_wrapper_t *wrapper,
+				 const cairo_clip_t *clip);
+
+cairo_private void
 _cairo_surface_wrapper_fini (cairo_surface_wrapper_t *wrapper);
 
 cairo_private cairo_status_t
diff --git a/src/cairo-surface-wrapper.c b/src/cairo-surface-wrapper.c
index 9e746f9..8dc40f8 100644
--- a/src/cairo-surface-wrapper.c
+++ b/src/cairo-surface-wrapper.c
@@ -54,18 +54,6 @@ _copy_transformed_pattern (cairo_pattern_t *pattern,
 	_cairo_pattern_transform (pattern, ctm_inverse);
 }
 
-static inline cairo_bool_t
-_cairo_surface_wrapper_needs_device_transform (cairo_surface_wrapper_t *wrapper)
-{
-    return ! _cairo_matrix_is_identity (&wrapper->target->device_transform);
-}
-
-static cairo_bool_t
-_cairo_surface_wrapper_needs_extents_transform (cairo_surface_wrapper_t *wrapper)
-{
-    return wrapper->has_extents && (wrapper->extents.x | wrapper->extents.y);
-}
-
 cairo_status_t
 _cairo_surface_wrapper_acquire_source_image (cairo_surface_wrapper_t *wrapper,
 					     cairo_image_surface_t  **image_out,
@@ -86,6 +74,24 @@ _cairo_surface_wrapper_release_source_image (cairo_surface_wrapper_t *wrapper,
     _cairo_surface_release_source_image (wrapper->target, image, image_extra);
 }
 
+static void
+_cairo_surface_wrapper_get_transform (cairo_surface_wrapper_t *wrapper,
+				      cairo_matrix_t *m)
+{
+    cairo_matrix_init_identity (m);
+
+    if (wrapper->has_extents && (wrapper->extents.x || wrapper->extents.y))
+	cairo_matrix_translate (m, -wrapper->extents.x, -wrapper->extents.y);
+
+    if (! _cairo_matrix_is_identity (&wrapper->transform))
+	cairo_matrix_multiply (m, &wrapper->transform, m);
+
+
+    if (! _cairo_matrix_is_identity (&wrapper->target->device_transform))
+	cairo_matrix_multiply (m, &wrapper->target->device_transform, m);
+}
+
+
 cairo_status_t
 _cairo_surface_wrapper_paint (cairo_surface_wrapper_t *wrapper,
 			      cairo_operator_t	 op,
@@ -108,21 +114,15 @@ _cairo_surface_wrapper_paint (cairo_surface_wrapper_t *wrapper,
 	goto FINISH;
     }
 
-    if (_cairo_surface_wrapper_needs_device_transform (wrapper) ||
-	_cairo_surface_wrapper_needs_extents_transform (wrapper))
-    {
+    if (wrapper->needs_transform) {
 	cairo_matrix_t m;
 
-	cairo_matrix_init_identity (&m);
-
-	if (_cairo_surface_wrapper_needs_extents_transform (wrapper))
-	    cairo_matrix_translate (&m, -wrapper->extents.x, -wrapper->extents.y);
-
-	if (_cairo_surface_wrapper_needs_device_transform (wrapper))
-	    cairo_matrix_multiply (&m, &wrapper->target->device_transform, &m);
+	_cairo_surface_wrapper_get_transform (wrapper, &m);
 
 	/* XXX */
-	dev_clip = _cairo_clip_copy_with_translation (clip, wrapper->extents.x, wrapper->extents.y);
+	dev_clip = _cairo_clip_copy_with_translation (dev_clip,
+						      wrapper->extents.x,
+						      wrapper->extents.y);
 
 	status = cairo_matrix_invert (&m);
 	assert (status == CAIRO_STATUS_SUCCESS);
@@ -131,6 +131,9 @@ _cairo_surface_wrapper_paint (cairo_surface_wrapper_t *wrapper,
 	source = &source_copy.base;
     }
 
+    if (wrapper->clip)
+	dev_clip = _cairo_clip_copy_intersect_clip (dev_clip, wrapper->clip);
+
     status = _cairo_surface_paint (wrapper->target, op, source, dev_clip);
 
   FINISH:
@@ -164,21 +167,14 @@ _cairo_surface_wrapper_mask (cairo_surface_wrapper_t *wrapper,
 	goto FINISH;
     }
 
-    if (_cairo_surface_wrapper_needs_device_transform (wrapper) ||
-	_cairo_surface_wrapper_needs_extents_transform (wrapper))
-    {
+    if (wrapper->needs_transform) {
 	cairo_matrix_t m;
 
-	cairo_matrix_init_identity (&m);
-
-	if (_cairo_surface_wrapper_needs_extents_transform (wrapper))
-	    cairo_matrix_translate (&m, -wrapper->extents.x, -wrapper->extents.y);
+	_cairo_surface_wrapper_get_transform (wrapper, &m);
 
-	if (_cairo_surface_wrapper_needs_device_transform (wrapper))
-	    cairo_matrix_multiply (&m, &wrapper->target->device_transform, &m);
-
-	/* XXX */
-	dev_clip = _cairo_clip_copy_with_translation (clip, wrapper->extents.x, wrapper->extents.y);
+	dev_clip = _cairo_clip_copy_with_translation (dev_clip,
+						      wrapper->extents.x,
+						      wrapper->extents.y);
 
 	status = cairo_matrix_invert (&m);
 	assert (status == CAIRO_STATUS_SUCCESS);
@@ -190,6 +186,9 @@ _cairo_surface_wrapper_mask (cairo_surface_wrapper_t *wrapper,
 	mask = &mask_copy.base;
     }
 
+    if (wrapper->clip)
+	dev_clip = _cairo_clip_copy_intersect_clip (dev_clip, wrapper->clip);
+
     status = _cairo_surface_mask (wrapper->target, op, source, mask, dev_clip);
 
   FINISH:
@@ -230,18 +229,10 @@ _cairo_surface_wrapper_stroke (cairo_surface_wrapper_t *wrapper,
 	goto FINISH;
     }
 
-    if (_cairo_surface_wrapper_needs_device_transform (wrapper) ||
-	_cairo_surface_wrapper_needs_extents_transform (wrapper))
-    {
+    if (wrapper->needs_transform) {
 	cairo_matrix_t m;
 
-	cairo_matrix_init_identity (&m);
-
-	if (_cairo_surface_wrapper_needs_extents_transform (wrapper))
-	    cairo_matrix_translate (&m, -wrapper->extents.x, -wrapper->extents.y);
-
-	if (_cairo_surface_wrapper_needs_device_transform (wrapper))
-	    cairo_matrix_multiply (&m, &wrapper->target->device_transform, &m);
+	_cairo_surface_wrapper_get_transform (wrapper, &m);
 
 	status = _cairo_path_fixed_init_copy (&path_copy, dev_path);
 	if (unlikely (status))
@@ -251,7 +242,9 @@ _cairo_surface_wrapper_stroke (cairo_surface_wrapper_t *wrapper,
 	dev_path = &path_copy;
 
 	/* XXX */
-	dev_clip = _cairo_clip_copy_with_translation (clip, wrapper->extents.x, wrapper->extents.y);
+	dev_clip = _cairo_clip_copy_with_translation (dev_clip,
+						      wrapper->extents.x,
+						      wrapper->extents.y);
 
 	cairo_matrix_multiply (&dev_ctm, &dev_ctm, &m);
 
@@ -264,6 +257,9 @@ _cairo_surface_wrapper_stroke (cairo_surface_wrapper_t *wrapper,
 	source = &source_copy.base;
     }
 
+    if (wrapper->clip)
+	dev_clip = _cairo_clip_copy_intersect_clip (dev_clip, wrapper->clip);
+
     status = _cairo_surface_stroke (wrapper->target, op, source,
 				    dev_path, stroke_style,
 				    &dev_ctm, &dev_ctm_inverse,
@@ -316,18 +312,10 @@ _cairo_surface_wrapper_fill_stroke (cairo_surface_wrapper_t *wrapper,
 	goto FINISH;
     }
 
-    if (_cairo_surface_wrapper_needs_device_transform (wrapper) ||
-	_cairo_surface_wrapper_needs_extents_transform (wrapper))
-    {
+    if (wrapper->needs_transform) {
 	cairo_matrix_t m;
 
-	cairo_matrix_init_identity (&m);
-
-	if (_cairo_surface_wrapper_needs_extents_transform (wrapper))
-	    cairo_matrix_translate (&m, -wrapper->extents.x, -wrapper->extents.y);
-
-	if (_cairo_surface_wrapper_needs_device_transform (wrapper))
-	    cairo_matrix_multiply (&m, &wrapper->target->device_transform, &m);
+	_cairo_surface_wrapper_get_transform (wrapper, &m);
 
 	status = _cairo_path_fixed_init_copy (&path_copy, dev_path);
 	if (unlikely (status))
@@ -337,7 +325,9 @@ _cairo_surface_wrapper_fill_stroke (cairo_surface_wrapper_t *wrapper,
 	dev_path = &path_copy;
 
 	/* XXX */
-	dev_clip = _cairo_clip_copy_with_translation (clip, wrapper->extents.x, wrapper->extents.y);
+	dev_clip = _cairo_clip_copy_with_translation (dev_clip,
+						      wrapper->extents.x,
+						      wrapper->extents.y);
 
 	cairo_matrix_multiply (&dev_ctm, &dev_ctm, &m);
 
@@ -353,6 +343,9 @@ _cairo_surface_wrapper_fill_stroke (cairo_surface_wrapper_t *wrapper,
 	fill_source = &fill_source_copy.base;
     }
 
+    if (wrapper->clip)
+	dev_clip = _cairo_clip_copy_intersect_clip (dev_clip, wrapper->clip);
+
     status = _cairo_surface_fill_stroke (wrapper->target,
 					 fill_op, fill_source, fill_rule,
 					 fill_tolerance, fill_antialias,
@@ -399,18 +392,10 @@ _cairo_surface_wrapper_fill (cairo_surface_wrapper_t	*wrapper,
 	goto FINISH;
     }
 
-    if (_cairo_surface_wrapper_needs_device_transform (wrapper) ||
-	_cairo_surface_wrapper_needs_extents_transform (wrapper))
-    {
+    if (wrapper->needs_transform) {
 	cairo_matrix_t m;
 
-	cairo_matrix_init_identity (&m);
-
-	if (_cairo_surface_wrapper_needs_extents_transform (wrapper))
-	    cairo_matrix_translate (&m, -wrapper->extents.x, -wrapper->extents.y);
-
-	if (_cairo_surface_wrapper_needs_device_transform (wrapper))
-	    cairo_matrix_multiply (&m, &wrapper->target->device_transform, &m);
+	_cairo_surface_wrapper_get_transform (wrapper, &m);
 
 	status = _cairo_path_fixed_init_copy (&path_copy, dev_path);
 	if (unlikely (status))
@@ -420,7 +405,9 @@ _cairo_surface_wrapper_fill (cairo_surface_wrapper_t	*wrapper,
 	dev_path = &path_copy;
 
 	/* XXX */
-	dev_clip = _cairo_clip_copy_with_translation (clip, wrapper->extents.x, wrapper->extents.y);
+	dev_clip = _cairo_clip_copy_with_translation (dev_clip,
+						      wrapper->extents.x,
+						      wrapper->extents.y);
 
 	status = cairo_matrix_invert (&m);
 	assert (status == CAIRO_STATUS_SUCCESS);
@@ -429,6 +416,9 @@ _cairo_surface_wrapper_fill (cairo_surface_wrapper_t	*wrapper,
 	source = &source_copy.base;
     }
 
+    if (wrapper->clip)
+	dev_clip = _cairo_clip_copy_intersect_clip (dev_clip, wrapper->clip);
+
     status = _cairo_surface_fill (wrapper->target, op, source,
 				  dev_path, fill_rule,
 				  tolerance, antialias,
@@ -477,22 +467,16 @@ _cairo_surface_wrapper_show_text_glyphs (cairo_surface_wrapper_t *wrapper,
 	goto FINISH;
     }
 
-    if (_cairo_surface_wrapper_needs_device_transform (wrapper) ||
-	_cairo_surface_wrapper_needs_extents_transform (wrapper))
-    {
+    if (wrapper->needs_transform) {
 	cairo_matrix_t m;
 	int i;
 
-	cairo_matrix_init_identity (&m);
-
-	if (_cairo_surface_wrapper_needs_extents_transform (wrapper))
-	    cairo_matrix_translate (&m, -wrapper->extents.x, -wrapper->extents.y);
-
-	if (_cairo_surface_wrapper_needs_device_transform (wrapper))
-	    cairo_matrix_multiply (&m, &wrapper->target->device_transform, &m);
+	_cairo_surface_wrapper_get_transform (wrapper, &m);
 
 	/* XXX */
-	dev_clip = _cairo_clip_copy_with_translation (clip, wrapper->extents.x, wrapper->extents.y);
+	dev_clip = _cairo_clip_copy_with_translation (dev_clip,
+						      wrapper->extents.x,
+						      wrapper->extents.y);
 
 	dev_glyphs = _cairo_malloc_ab (num_glyphs, sizeof (cairo_glyph_t));
 	if (dev_glyphs == NULL) {
@@ -512,6 +496,9 @@ _cairo_surface_wrapper_show_text_glyphs (cairo_surface_wrapper_t *wrapper,
 	source = &source_copy.base;
     }
 
+    if (wrapper->clip)
+	dev_clip = _cairo_clip_copy_intersect_clip (dev_clip, wrapper->clip);
+
     status = _cairo_surface_show_text_glyphs (wrapper->target, op, source,
 					      utf8, utf8_len,
 					      dev_glyphs, num_glyphs,
@@ -555,6 +542,15 @@ _cairo_surface_wrapper_get_extents (cairo_surface_wrapper_t *wrapper,
     }
 }
 
+static cairo_bool_t
+_cairo_surface_wrapper_needs_device_transform (cairo_surface_wrapper_t *wrapper)
+{
+    return
+	(wrapper->has_extents && (wrapper->extents.x | wrapper->extents.y)) ||
+	! _cairo_matrix_is_identity (&wrapper->transform) ||
+	! _cairo_matrix_is_identity (&wrapper->target->device_transform);
+}
+
 void
 _cairo_surface_wrapper_set_extents (cairo_surface_wrapper_t *wrapper,
 				    const cairo_rectangle_int_t *extents)
@@ -565,6 +561,38 @@ _cairo_surface_wrapper_set_extents (cairo_surface_wrapper_t *wrapper,
     } else {
 	wrapper->has_extents = FALSE;
     }
+
+    wrapper->needs_transform =
+	_cairo_surface_wrapper_needs_device_transform (wrapper);
+}
+
+void
+_cairo_surface_wrapper_set_inverse_transform (cairo_surface_wrapper_t *wrapper,
+					      const cairo_matrix_t *transform)
+{
+    cairo_status_t status;
+
+    if (transform == NULL || _cairo_matrix_is_identity (transform)) {
+	cairo_matrix_init_identity (&wrapper->transform);
+
+	wrapper->needs_transform =
+	    _cairo_surface_wrapper_needs_device_transform (wrapper);
+    } else {
+	wrapper->transform = *transform;
+	status = cairo_matrix_invert (&wrapper->transform);
+	/* should always be invertible unless given pathological input */
+	assert (status == CAIRO_STATUS_SUCCESS);
+
+	wrapper->needs_transform = TRUE;
+    }
+
+}
+
+void
+_cairo_surface_wrapper_set_clip (cairo_surface_wrapper_t *wrapper,
+				 const cairo_clip_t *clip)
+{
+    wrapper->clip = clip;
 }
 
 void
@@ -590,8 +618,12 @@ void
 _cairo_surface_wrapper_init (cairo_surface_wrapper_t *wrapper,
 			     cairo_surface_t *target)
 {
+    _cairo_surface_wrapper_set_inverse_transform (wrapper, NULL);
+
     wrapper->target = cairo_surface_reference (target);
     wrapper->has_extents = FALSE;
+    wrapper->needs_transform =
+	! _cairo_matrix_is_identity (&wrapper->target->device_transform);
 }
 
 void
commit bff8e22eb6b7faeac04ca585cb739e7880a3335c
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Sat Jul 23 14:11:42 2011 +0100

    image: Fix partial clipping of text
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/src/cairo-image-surface.c b/src/cairo-image-surface.c
index d7e8b82..a03e1ab 100644
--- a/src/cairo-image-surface.c
+++ b/src/cairo-image-surface.c
@@ -2212,25 +2212,59 @@ _clip_and_composite_source (cairo_clip_t                  *clip,
     return CAIRO_STATUS_SUCCESS;
 }
 
+enum {
+    NEED_CLIP_REGION = 0x1,
+    NEED_CLIP_SURFACE = 0x2,
+    FORCE_CLIP_REGION = 0x4,
+};
+
+static cairo_bool_t
+need_bounded_clip (cairo_composite_rectangles_t *extents)
+{
+    unsigned int flags = NEED_CLIP_REGION;
+    if (! _cairo_clip_is_region (extents->clip))
+	flags |= NEED_CLIP_SURFACE;
+    return flags;
+}
+
+static cairo_bool_t
+need_unbounded_clip (cairo_composite_rectangles_t *extents)
+{
+    unsigned int flags = 0;
+    if (! extents->is_bounded) {
+	flags |= NEED_CLIP_REGION;
+	if (! _cairo_clip_is_region (extents->clip))
+	    flags |= NEED_CLIP_SURFACE;
+    }
+    if (extents->clip->path != NULL)
+	flags |= NEED_CLIP_SURFACE;
+    return flags;
+}
+
+
 static cairo_status_t
 _clip_and_composite (cairo_image_surface_t	*dst,
 		     cairo_operator_t		 op,
 		     const cairo_pattern_t	*src,
 		     image_draw_func_t		 draw_func,
 		     void			*draw_closure,
-		     cairo_composite_rectangles_t*extents)
+		     cairo_composite_rectangles_t*extents,
+		     unsigned int need_clip)
 {
-    cairo_region_t *clip_region = _cairo_clip_get_region (extents->clip);
-    cairo_bool_t need_clip_surface = ! _cairo_clip_is_region (extents->clip);
+    cairo_region_t *clip_region = NULL;
     cairo_status_t status;
 
-    if (cairo_region_num_rectangles (clip_region) == 1)
-	clip_region = NULL;
-
-    if (clip_region != NULL) {
-	status = _cairo_image_surface_set_clip_region (dst, clip_region);
-	if (unlikely (status))
-	    return status;
+    if (need_clip & NEED_CLIP_REGION) {
+	clip_region = _cairo_clip_get_region (extents->clip);
+	if ((need_clip & FORCE_CLIP_REGION) == 0 &&
+	    cairo_region_contains_rectangle (clip_region,
+					     &extents->unbounded) == CAIRO_REGION_OVERLAP_IN)
+	    clip_region = NULL;
+	if (clip_region != NULL) {
+	    status = _cairo_image_surface_set_clip_region (dst, clip_region);
+	    if (unlikely (status))
+		return status;
+	}
     }
 
     if (reduce_alpha_op (dst, op, src)) {
@@ -2248,7 +2282,7 @@ _clip_and_composite (cairo_image_surface_t	*dst,
 	    op = CAIRO_OPERATOR_DEST_OUT;
 	}
 
-	if (need_clip_surface) {
+	if (need_clip & NEED_CLIP_SURFACE) {
 	    if (extents->is_bounded) {
 		status = _clip_and_composite_with_mask (extents->clip, op, src,
 							draw_func, draw_closure,
@@ -2271,7 +2305,7 @@ _clip_and_composite (cairo_image_surface_t	*dst,
 
     if (status == CAIRO_STATUS_SUCCESS && ! extents->is_bounded) {
 	status = _cairo_image_surface_fixup_unbounded (dst, extents,
-						       need_clip_surface ? extents->clip : NULL);
+						       need_clip & NEED_CLIP_SURFACE ? extents->clip : NULL);
     }
 
     if (clip_region != NULL)
@@ -3011,7 +3045,7 @@ _clip_and_composite_boxes (cairo_image_surface_t *dst,
     info.antialias = CAIRO_ANTIALIAS_DEFAULT;
     status = _clip_and_composite (dst, op, src,
 				  _composite_traps, &info,
-				  extents);
+				  extents, need_unbounded_clip (extents));
 
     _cairo_traps_fini (&traps);
     return status;
@@ -3160,7 +3194,7 @@ _clip_and_composite_trapezoids (cairo_image_surface_t *dst,
     info.antialias = antialias;
     return _clip_and_composite (dst, op, src,
 				_composite_traps, &info,
-				extents);
+				extents, need_unbounded_clip (extents));
 }
 
 /* high level image interface */
@@ -3276,7 +3310,7 @@ _cairo_image_surface_mask (void				*abstract_surface,
 
     status = _clip_and_composite (surface, op, source,
 				  _composite_mask, (void *) mask,
-				  &extents);
+				  &extents, need_bounded_clip (&extents));
 
     _cairo_composite_rectangles_fini (&extents);
 
@@ -3449,7 +3483,7 @@ _clip_and_composite_polygon (cairo_image_surface_t *dst,
 
 	status = _clip_and_composite (dst, op, src,
 				      _composite_spans, &info,
-				      extents);
+				      extents, need_unbounded_clip (extents));
     } else {
 	cairo_traps_t traps;
 
@@ -3744,7 +3778,7 @@ _composite_glyphs (void				*closure,
 		   const cairo_pattern_t	*pattern,
 		   int				 dst_x,
 		   int				 dst_y,
-		   cairo_matrix_t 		*dst_device_transform,
+		   cairo_matrix_t		*dst_device_transform,
 		   const cairo_rectangle_int_t	*extents,
 		   cairo_region_t		*clip_region)
 {
@@ -3848,6 +3882,7 @@ _cairo_image_surface_glyphs (void			*abstract_surface,
     composite_glyphs_info_t glyph_info;
     cairo_status_t status;
     cairo_bool_t overlap;
+    unsigned int flags;
 
     status = _cairo_composite_rectangles_init_for_glyphs (&extents,
 							  surface->width,
@@ -3864,10 +3899,19 @@ _cairo_image_surface_glyphs (void			*abstract_surface,
     glyph_info.glyphs = glyphs;
     glyph_info.num_glyphs = num_glyphs;
 
+    flags = 0;
+    if (extents.mask.width > extents.unbounded.width ||
+	extents.mask.height > extents.unbounded.height)
+    {
+	flags |= FORCE_CLIP_REGION;
+    }
     status = _clip_and_composite (surface, op, source,
-				  overlap || extents.is_bounded == 0 ? _composite_glyphs_via_mask : _composite_glyphs,
+				  overlap || extents.is_bounded == 0 ?
+				  _composite_glyphs_via_mask :
+				  _composite_glyphs,
 				  &glyph_info,
-				  &extents);
+				  &extents,
+				  need_bounded_clip (&extents) | flags);
 
     _cairo_composite_rectangles_fini (&extents);
 
commit c2dada9722df2aa56a625679ea21f1356b33c758
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Sat Jul 23 15:32:40 2011 +0100

    test: Add a paint-with-alpha variant to test clip-boxes fast path
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/test/Makefile.refs b/test/Makefile.refs
index 47cce6b..9374cc6 100644
--- a/test/Makefile.refs
+++ b/test/Makefile.refs
@@ -865,6 +865,9 @@ REFERENCE_IMAGES = \
 	paint-source-alpha.image16.ref.png \
 	paint-source-alpha.ref.png \
 	paint-source-alpha.svg.ref.png \
+	paint-with-alpha-clip.ref.png \
+	paint-with-alpha-clip.xlib.ref.png \
+	paint-with-alpha-solid-clip.ref.png \
 	paint-with-alpha.image16.ref.png \
 	paint-with-alpha.ref.png \
 	paint-with-alpha.svg.ref.png \
@@ -1002,7 +1005,6 @@ REFERENCE_IMAGES = \
 	recording-surface-over.svg.rgb24.ref.png \
 	recording-surface-over.xlib.argb32.ref.png \
 	recording-surface-over.xlib.rgb24.ref.png \
-	recording-surface-pattern.ref.png \
 	rectangle-rounding-error.ref.png \
 	rectilinear-dash.quartz.xfail.png \
 	rectilinear-dash.ref.png \
diff --git a/test/paint-with-alpha-clip.ref.png b/test/paint-with-alpha-clip.ref.png
new file mode 100644
index 0000000..c8c0bde
Binary files /dev/null and b/test/paint-with-alpha-clip.ref.png differ
diff --git a/test/paint-with-alpha-clip.xlib.ref.png b/test/paint-with-alpha-clip.xlib.ref.png
new file mode 100644
index 0000000..704c70a
Binary files /dev/null and b/test/paint-with-alpha-clip.xlib.ref.png differ
diff --git a/test/paint-with-alpha-solid-clip.ref.png b/test/paint-with-alpha-solid-clip.ref.png
new file mode 100644
index 0000000..59d226d
Binary files /dev/null and b/test/paint-with-alpha-solid-clip.ref.png differ
diff --git a/test/paint-with-alpha.c b/test/paint-with-alpha.c
index 19b9e44..e827bb9 100644
--- a/test/paint-with-alpha.c
+++ b/test/paint-with-alpha.c
@@ -26,23 +26,62 @@
 
 #include "cairo-test.h"
 
+static uint32_t data[16] = {
+    0xffffffff, 0xffffffff,		0xffff0000, 0xffff0000,
+    0xffffffff, 0xffffffff,		0xffff0000, 0xffff0000,
+
+    0xff00ff00, 0xff00ff00,		0xff0000ff, 0xff0000ff,
+    0xff00ff00, 0xff00ff00,		0xff0000ff, 0xff0000ff
+};
 static cairo_test_status_t
 draw (cairo_t *cr, int width, int height)
 {
     cairo_surface_t *surface;
-    uint32_t data[16] = {
-	0xffffffff, 0xffffffff,		0xffff0000, 0xffff0000,
-	0xffffffff, 0xffffffff,		0xffff0000, 0xffff0000,
 
-	0xff00ff00, 0xff00ff00,		0xff0000ff, 0xff0000ff,
-	0xff00ff00, 0xff00ff00,		0xff0000ff, 0xff0000ff
-    };
+    surface = cairo_image_surface_create_for_data ((unsigned char *) data,
+						   CAIRO_FORMAT_RGB24, 4, 4, 16);
+
+    cairo_test_paint_checkered (cr);
+
+    cairo_scale (cr, 4, 4);
+
+    cairo_set_source_surface (cr, surface, 2 , 2);
+    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;
+}
+
+static cairo_test_status_t
+draw_solid_clip (cairo_t *cr, int width, int height)
+{
+    cairo_test_paint_checkered (cr);
+
+    cairo_rectangle (cr, 2.5, 2.5, 27, 27);
+    cairo_clip (cr);
+
+    cairo_set_source_rgb (cr, 1., 0.,0.);
+    cairo_paint_with_alpha (cr, 0.5);
+
+    return CAIRO_TEST_SUCCESS;
+}
+
+static cairo_test_status_t
+draw_clip (cairo_t *cr, int width, int height)
+{
+    cairo_surface_t *surface;
 
     surface = cairo_image_surface_create_for_data ((unsigned char *) data,
 						   CAIRO_FORMAT_RGB24, 4, 4, 16);
 
     cairo_test_paint_checkered (cr);
 
+    cairo_rectangle (cr, 10.5, 10.5, 11, 11);
+    cairo_clip (cr);
+
     cairo_scale (cr, 4, 4);
 
     cairo_set_source_surface (cr, surface, 2 , 2);
@@ -61,3 +100,15 @@ CAIRO_TEST (paint_with_alpha,
 	    NULL, /* requirements */
 	    32, 32,
 	    NULL, draw)
+CAIRO_TEST (paint_with_alpha_solid_clip,
+	    "Simple test of cairo_paint_with_alpha+unaligned clip",
+	    "paint, alpha, clip", /* keywords */
+	    NULL, /* requirements */
+	    32, 32,
+	    NULL, draw_solid_clip)
+CAIRO_TEST (paint_with_alpha_clip,
+	    "Simple test of cairo_paint_with_alpha+unaligned clip",
+	    "paint, alpha, clip", /* keywords */
+	    NULL, /* requirements */
+	    32, 32,
+	    NULL, draw_clip)
commit 5de02329370257290404dae244cb14ac544140d7
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Sat Jul 23 14:22:19 2011 +0100

    test: Extend recording-surface-pattern to include a SOURCE operator test
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/test/Makefile.refs b/test/Makefile.refs
index 4de6382..47cce6b 100644
--- a/test/Makefile.refs
+++ b/test/Makefile.refs
@@ -989,20 +989,20 @@ REFERENCE_IMAGES = \
 	random-intersections-nonzero.quartz.ref.png \
 	random-intersections-nonzero.ref.png \
 	random-intersections-nonzero.xlib.ref.png \
-	recording-surface-pattern.gl.argb32.ref.png \
-	recording-surface-pattern.image16.ref.png \
-	recording-surface-pattern.pdf.argb32.ref.png \
-	recording-surface-pattern.pdf.rgb24.ref.png \
-	recording-surface-pattern.ps.argb32.ref.png \
-	recording-surface-pattern.ps.rgb24.ref.png \
-	recording-surface-pattern.quartz.argb32.ref.png \
-	recording-surface-pattern.quartz.rgb24.ref.png \
+	recording-surface-over.gl.argb32.ref.png \
+	recording-surface-over.image16.ref.png \
+	recording-surface-over.pdf.argb32.ref.png \
+	recording-surface-over.pdf.rgb24.ref.png \
+	recording-surface-over.ps.argb32.ref.png \
+	recording-surface-over.ps.rgb24.ref.png \
+	recording-surface-over.quartz.argb32.ref.png \
+	recording-surface-over.quartz.rgb24.ref.png \
+	recording-surface-over.rgb24.ref.png \
+	recording-surface-over.svg.argb32.ref.png \
+	recording-surface-over.svg.rgb24.ref.png \
+	recording-surface-over.xlib.argb32.ref.png \
+	recording-surface-over.xlib.rgb24.ref.png \
 	recording-surface-pattern.ref.png \
-	recording-surface-pattern.rgb24.ref.png \
-	recording-surface-pattern.svg.argb32.ref.png \
-	recording-surface-pattern.svg.rgb24.ref.png \
-	recording-surface-pattern.xlib.argb32.ref.png \
-	recording-surface-pattern.xlib.rgb24.ref.png \
 	rectangle-rounding-error.ref.png \
 	rectilinear-dash.quartz.xfail.png \
 	rectilinear-dash.ref.png \
diff --git a/test/recording-surface-over.gl.argb32.ref.png b/test/recording-surface-over.gl.argb32.ref.png
new file mode 100644
index 0000000..50e6f5a
Binary files /dev/null and b/test/recording-surface-over.gl.argb32.ref.png differ
diff --git a/test/recording-surface-over.image16.ref.png b/test/recording-surface-over.image16.ref.png
new file mode 100644
index 0000000..0202893
Binary files /dev/null and b/test/recording-surface-over.image16.ref.png differ
diff --git a/test/recording-surface-over.pdf.argb32.ref.png b/test/recording-surface-over.pdf.argb32.ref.png
new file mode 100644
index 0000000..a06386b
Binary files /dev/null and b/test/recording-surface-over.pdf.argb32.ref.png differ
diff --git a/test/recording-surface-over.pdf.rgb24.ref.png b/test/recording-surface-over.pdf.rgb24.ref.png
new file mode 100644
index 0000000..bf69f9e
Binary files /dev/null and b/test/recording-surface-over.pdf.rgb24.ref.png differ
diff --git a/test/recording-surface-over.ps.argb32.ref.png b/test/recording-surface-over.ps.argb32.ref.png
new file mode 100644
index 0000000..ac66323
Binary files /dev/null and b/test/recording-surface-over.ps.argb32.ref.png differ
diff --git a/test/recording-surface-over.ps.rgb24.ref.png b/test/recording-surface-over.ps.rgb24.ref.png
new file mode 100644
index 0000000..fab3382
Binary files /dev/null and b/test/recording-surface-over.ps.rgb24.ref.png differ
diff --git a/test/recording-surface-over.quartz.argb32.ref.png b/test/recording-surface-over.quartz.argb32.ref.png
new file mode 100644
index 0000000..09d9559
Binary files /dev/null and b/test/recording-surface-over.quartz.argb32.ref.png differ
diff --git a/test/recording-surface-over.quartz.rgb24.ref.png b/test/recording-surface-over.quartz.rgb24.ref.png
new file mode 100644
index 0000000..96aff40
Binary files /dev/null and b/test/recording-surface-over.quartz.rgb24.ref.png differ
diff --git a/test/recording-surface-over.rgb24.ref.png b/test/recording-surface-over.rgb24.ref.png
new file mode 100644
index 0000000..2de298d
Binary files /dev/null and b/test/recording-surface-over.rgb24.ref.png differ
diff --git a/test/recording-surface-over.svg.argb32.ref.png b/test/recording-surface-over.svg.argb32.ref.png
new file mode 100644
index 0000000..ff4154d
Binary files /dev/null and b/test/recording-surface-over.svg.argb32.ref.png differ
diff --git a/test/recording-surface-over.svg.rgb24.ref.png b/test/recording-surface-over.svg.rgb24.ref.png
new file mode 100644
index 0000000..d2d5372
Binary files /dev/null and b/test/recording-surface-over.svg.rgb24.ref.png differ
diff --git a/test/recording-surface-over.xlib.argb32.ref.png b/test/recording-surface-over.xlib.argb32.ref.png
new file mode 100644
index 0000000..d612250
Binary files /dev/null and b/test/recording-surface-over.xlib.argb32.ref.png differ
diff --git a/test/recording-surface-over.xlib.rgb24.ref.png b/test/recording-surface-over.xlib.rgb24.ref.png
new file mode 100644
index 0000000..0a57b44
Binary files /dev/null and b/test/recording-surface-over.xlib.rgb24.ref.png differ
diff --git a/test/recording-surface-pattern.c b/test/recording-surface-pattern.c
index c8768f9..5a5fee2 100644
--- a/test/recording-surface-pattern.c
+++ b/test/recording-surface-pattern.c
@@ -37,66 +37,74 @@
 /* This test is designed to test painting a recording surface pattern with
  * CAIRO_EXTEND_NONE and a non identity pattern matrix.
  */
+static cairo_pattern_t *create_pattern (cairo_t *target)
+{
+    cairo_surface_t *surface;
+    cairo_pattern_t *pattern;
+    cairo_t *cr;
+
+    surface = cairo_surface_create_similar (cairo_get_group_target (target),
+					    CAIRO_CONTENT_COLOR_ALPHA,
+					    PAT_WIDTH, PAT_HEIGHT);
+    cr = cairo_create (surface);
+    cairo_surface_destroy (surface);
+
+    cairo_set_source_rgba (cr, 1, 0, 1, 0.5);
+    cairo_rectangle (cr, PAT_WIDTH/6.0, PAT_HEIGHT/6.0, PAT_WIDTH/4.0, PAT_HEIGHT/4.0);
+    cairo_fill (cr);
+
+    cairo_set_source_rgba (cr, 0, 1, 1, 0.5);
+    cairo_rectangle (cr, PAT_WIDTH/2.0, PAT_HEIGHT/2.0, PAT_WIDTH/4.0, PAT_HEIGHT/4.0);
+    cairo_fill (cr);
+
+    cairo_set_line_width (cr, 1);
+    cairo_move_to (cr, PAT_WIDTH/6.0, 0);
+    cairo_line_to (cr, 0, 0);
+    cairo_line_to (cr, 0, PAT_HEIGHT/6.0);
+    cairo_set_source_rgb (cr, 1, 0, 0);
+    cairo_stroke (cr);
+    cairo_move_to (cr, PAT_WIDTH/6.0, PAT_HEIGHT);
+    cairo_line_to (cr, 0, PAT_HEIGHT);
+    cairo_line_to (cr, 0, 5*PAT_HEIGHT/6.0);
+    cairo_set_source_rgb (cr, 0, 1, 0);
+    cairo_stroke (cr);
+    cairo_move_to (cr, 5*PAT_WIDTH/6.0, 0);
+    cairo_line_to (cr, PAT_WIDTH, 0);
+    cairo_line_to (cr, PAT_WIDTH, PAT_HEIGHT/6.0);
+    cairo_set_source_rgb (cr, 0, 0, 1);
+    cairo_stroke (cr);
+    cairo_move_to (cr, 5*PAT_WIDTH/6.0, PAT_HEIGHT);
+    cairo_line_to (cr, PAT_WIDTH, PAT_HEIGHT);
+    cairo_line_to (cr, PAT_WIDTH, 5*PAT_HEIGHT/6.0);
+    cairo_set_source_rgb (cr, 1, 1, 0);
+    cairo_stroke (cr);
+
+    cairo_set_source_rgb (cr, 0.5, 0.5, 0.5);
+    cairo_set_line_width (cr, PAT_WIDTH/10.0);
+
+    cairo_move_to (cr, 0,         PAT_HEIGHT/4.0);
+    cairo_line_to (cr, PAT_WIDTH, PAT_HEIGHT/4.0);
+    cairo_stroke (cr);
+
+    cairo_move_to (cr, PAT_WIDTH/4.0,         0);
+    cairo_line_to (cr, PAT_WIDTH/4.0, PAT_WIDTH);
+    cairo_stroke (cr);
+
+    pattern = cairo_pattern_create_for_surface (cairo_get_target (cr));
+    cairo_destroy (cr);
+
+    return pattern;
+}
 
 static cairo_test_status_t
-draw (cairo_t *cr, int width, int height)
+over (cairo_t *cr, int width, int height)
 {
-    cairo_surface_t *pat_surface;
     cairo_pattern_t *pattern;
     cairo_matrix_t   mat;
-    cairo_t *cr2;
 
     cairo_translate (cr, PAD, PAD);
 
-    pat_surface = cairo_surface_create_similar (cairo_get_group_target (cr),
-						CAIRO_CONTENT_COLOR_ALPHA,
-						PAT_WIDTH, PAT_HEIGHT);
-    cr2 = cairo_create (pat_surface);
-    cairo_surface_destroy (pat_surface);
-
-    cairo_set_source_rgba (cr2, 1, 0, 1, 0.5);
-    cairo_rectangle (cr2, PAT_WIDTH/6.0, PAT_HEIGHT/6.0, PAT_WIDTH/4.0, PAT_HEIGHT/4.0);
-    cairo_fill (cr2);
-
-    cairo_set_source_rgba (cr2, 0, 1, 1, 0.5);
-    cairo_rectangle (cr2, PAT_WIDTH/2.0, PAT_HEIGHT/2.0, PAT_WIDTH/4.0, PAT_HEIGHT/4.0);
-    cairo_fill (cr2);
-
-    cairo_set_line_width (cr2, 1);
-    cairo_move_to (cr2, PAT_WIDTH/6.0, 0);
-    cairo_line_to (cr2, 0, 0);
-    cairo_line_to (cr2, 0, PAT_HEIGHT/6.0);
-    cairo_set_source_rgb (cr2, 1, 0, 0);
-    cairo_stroke (cr2);
-    cairo_move_to (cr2, PAT_WIDTH/6.0, PAT_HEIGHT);
-    cairo_line_to (cr2, 0, PAT_HEIGHT);
-    cairo_line_to (cr2, 0, 5*PAT_HEIGHT/6.0);
-    cairo_set_source_rgb (cr2, 0, 1, 0);
-    cairo_stroke (cr2);
-    cairo_move_to (cr2, 5*PAT_WIDTH/6.0, 0);
-    cairo_line_to (cr2, PAT_WIDTH, 0);
-    cairo_line_to (cr2, PAT_WIDTH, PAT_HEIGHT/6.0);
-    cairo_set_source_rgb (cr2, 0, 0, 1);
-    cairo_stroke (cr2);
-    cairo_move_to (cr2, 5*PAT_WIDTH/6.0, PAT_HEIGHT);
-    cairo_line_to (cr2, PAT_WIDTH, PAT_HEIGHT);
-    cairo_line_to (cr2, PAT_WIDTH, 5*PAT_HEIGHT/6.0);
-    cairo_set_source_rgb (cr2, 1, 1, 0);
-    cairo_stroke (cr2);
-
-    cairo_set_source_rgb (cr2, 0.5, 0.5, 0.5);
-    cairo_set_line_width (cr2, PAT_WIDTH/10.0);
-
-    cairo_move_to (cr2, 0,         PAT_HEIGHT/4.0);
-    cairo_line_to (cr2, PAT_WIDTH, PAT_HEIGHT/4.0);
-    cairo_stroke (cr2);
-
-    cairo_move_to (cr2, PAT_WIDTH/4.0,         0);
-    cairo_line_to (cr2, PAT_WIDTH/4.0, PAT_WIDTH);
-    cairo_stroke (cr2);
-
-    pattern = cairo_pattern_create_for_surface (cairo_get_target (cr2));
-    cairo_destroy (cr2);
+    pattern = create_pattern (cr);
 
     cairo_matrix_init_identity (&mat);
     cairo_matrix_scale (&mat, 2, 1.5);
@@ -113,9 +121,42 @@ draw (cairo_t *cr, int width, int height)
     return CAIRO_TEST_SUCCESS;
 }
 
-CAIRO_TEST (recording_surface_pattern,
+static cairo_test_status_t
+source (cairo_t *cr, int width, int height)
+{
+    cairo_pattern_t *pattern;
+    cairo_matrix_t   mat;
+
+    cairo_translate (cr, PAD, PAD);
+
+    pattern = create_pattern (cr);
+
+    cairo_matrix_init_identity (&mat);
+    cairo_matrix_scale (&mat, 2, 1.5);
+    cairo_matrix_rotate (&mat, 1);
+    cairo_matrix_translate (&mat, -PAT_WIDTH/4.0, -PAT_WIDTH/2.0);
+    cairo_pattern_set_matrix (pattern, &mat);
+    cairo_pattern_set_extend (pattern, CAIRO_EXTEND_NONE);
+
+    cairo_set_source (cr, pattern);
+    cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
+    cairo_paint (cr);
+
+    cairo_pattern_destroy (pattern);
+
+    return CAIRO_TEST_SUCCESS;
+}
+
+CAIRO_TEST (recording_surface_over,
+	    "Paint recording surface pattern with non identity pattern matrix",
+	    "recording", /* keywords */
+	    NULL, /* requirements */
+	    WIDTH, HEIGHT,
+	    NULL, over)
+
+CAIRO_TEST (recording_surface_source,
 	    "Paint recording surface pattern with non identity pattern matrix",
 	    "recording", /* keywords */
 	    NULL, /* requirements */
 	    WIDTH, HEIGHT,
-	    NULL, draw)
+	    NULL, source)
diff --git a/test/recording-surface-pattern.gl.argb32.ref.png b/test/recording-surface-pattern.gl.argb32.ref.png
deleted file mode 100644
index 50e6f5a..0000000
Binary files a/test/recording-surface-pattern.gl.argb32.ref.png and /dev/null differ
diff --git a/test/recording-surface-pattern.image16.ref.png b/test/recording-surface-pattern.image16.ref.png
deleted file mode 100644
index 0202893..0000000
Binary files a/test/recording-surface-pattern.image16.ref.png and /dev/null differ
diff --git a/test/recording-surface-pattern.pdf.argb32.ref.png b/test/recording-surface-pattern.pdf.argb32.ref.png
deleted file mode 100644
index a06386b..0000000
Binary files a/test/recording-surface-pattern.pdf.argb32.ref.png and /dev/null differ
diff --git a/test/recording-surface-pattern.pdf.rgb24.ref.png b/test/recording-surface-pattern.pdf.rgb24.ref.png
deleted file mode 100644
index bf69f9e..0000000
Binary files a/test/recording-surface-pattern.pdf.rgb24.ref.png and /dev/null differ
diff --git a/test/recording-surface-pattern.ps.argb32.ref.png b/test/recording-surface-pattern.ps.argb32.ref.png
deleted file mode 100644
index ac66323..0000000
Binary files a/test/recording-surface-pattern.ps.argb32.ref.png and /dev/null differ
diff --git a/test/recording-surface-pattern.ps.rgb24.ref.png b/test/recording-surface-pattern.ps.rgb24.ref.png
deleted file mode 100644
index fab3382..0000000
Binary files a/test/recording-surface-pattern.ps.rgb24.ref.png and /dev/null differ
diff --git a/test/recording-surface-pattern.quartz.argb32.ref.png b/test/recording-surface-pattern.quartz.argb32.ref.png
deleted file mode 100644
index 09d9559..0000000
Binary files a/test/recording-surface-pattern.quartz.argb32.ref.png and /dev/null differ
diff --git a/test/recording-surface-pattern.quartz.rgb24.ref.png b/test/recording-surface-pattern.quartz.rgb24.ref.png
deleted file mode 100644
index 96aff40..0000000
Binary files a/test/recording-surface-pattern.quartz.rgb24.ref.png and /dev/null differ
diff --git a/test/recording-surface-pattern.ref.png b/test/recording-surface-pattern.ref.png
deleted file mode 100644
index 7f9c56c..0000000
Binary files a/test/recording-surface-pattern.ref.png and /dev/null differ
diff --git a/test/recording-surface-pattern.rgb24.ref.png b/test/recording-surface-pattern.rgb24.ref.png
deleted file mode 100644
index 2de298d..0000000
Binary files a/test/recording-surface-pattern.rgb24.ref.png and /dev/null differ
diff --git a/test/recording-surface-pattern.svg.argb32.ref.png b/test/recording-surface-pattern.svg.argb32.ref.png
deleted file mode 100644
index ff4154d..0000000
Binary files a/test/recording-surface-pattern.svg.argb32.ref.png and /dev/null differ
diff --git a/test/recording-surface-pattern.svg.rgb24.ref.png b/test/recording-surface-pattern.svg.rgb24.ref.png
deleted file mode 100644
index d2d5372..0000000
Binary files a/test/recording-surface-pattern.svg.rgb24.ref.png and /dev/null differ
diff --git a/test/recording-surface-pattern.xlib.argb32.ref.png b/test/recording-surface-pattern.xlib.argb32.ref.png
deleted file mode 100644
index d612250..0000000
Binary files a/test/recording-surface-pattern.xlib.argb32.ref.png and /dev/null differ
diff --git a/test/recording-surface-pattern.xlib.rgb24.ref.png b/test/recording-surface-pattern.xlib.rgb24.ref.png
deleted file mode 100644
index 0a57b44..0000000
Binary files a/test/recording-surface-pattern.xlib.rgb24.ref.png and /dev/null differ
commit abd8fcc833eedc916addbd688a40303e4c78affd
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Sat Jul 23 14:11:12 2011 +0100

    test: Expand partial-clip-text
    
    Test partial clipping along each edge.
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/test/Makefile.refs b/test/Makefile.refs
index 1c0945b..4de6382 100644
--- a/test/Makefile.refs
+++ b/test/Makefile.refs
@@ -869,10 +869,13 @@ REFERENCE_IMAGES = \
 	paint-with-alpha.ref.png \
 	paint-with-alpha.svg.ref.png \
 	paint.ref.png \
-	partial-clip-text.ps.ref.png \
-	partial-clip-text.quartz.ref.png \
-	partial-clip-text.ref.png \
-	partial-clip-text.svg.ref.png \
+	partial-clip-text-bottom.ref.png \
+	partial-clip-text-left.ref.png \
+	partial-clip-text-right.ref.png \
+	partial-clip-text-top.ps.ref.png \
+	partial-clip-text-top.quartz.ref.png \
+	partial-clip-text-top.ref.png \
+	partial-clip-text-top.svg.ref.png \
 	partial-coverage-half-reference.ref.png \
 	partial-coverage-half-triangles.ref.png \
 	partial-coverage-intersecting-quads.ref.png \
diff --git a/test/partial-clip-text-bottom.ref.png b/test/partial-clip-text-bottom.ref.png
new file mode 100644
index 0000000..bb31331
Binary files /dev/null and b/test/partial-clip-text-bottom.ref.png differ
diff --git a/test/partial-clip-text-left.ref.png b/test/partial-clip-text-left.ref.png
new file mode 100644
index 0000000..ee1358f
Binary files /dev/null and b/test/partial-clip-text-left.ref.png differ
diff --git a/test/partial-clip-text-right.ref.png b/test/partial-clip-text-right.ref.png
new file mode 100644
index 0000000..5853a72
Binary files /dev/null and b/test/partial-clip-text-right.ref.png differ
diff --git a/test/partial-clip-text-top.ps.ref.png b/test/partial-clip-text-top.ps.ref.png
new file mode 100644
index 0000000..049bba5
Binary files /dev/null and b/test/partial-clip-text-top.ps.ref.png differ
diff --git a/test/partial-clip-text-top.quartz.ref.png b/test/partial-clip-text-top.quartz.ref.png
new file mode 100644
index 0000000..33ac283
Binary files /dev/null and b/test/partial-clip-text-top.quartz.ref.png differ
diff --git a/test/partial-clip-text-top.ref.png b/test/partial-clip-text-top.ref.png
new file mode 100644
index 0000000..afe2d3e
Binary files /dev/null and b/test/partial-clip-text-top.ref.png differ
diff --git a/test/partial-clip-text-top.svg.ref.png b/test/partial-clip-text-top.svg.ref.png
new file mode 100644
index 0000000..dc3fc58
Binary files /dev/null and b/test/partial-clip-text-top.svg.ref.png differ
diff --git a/test/partial-clip-text.c b/test/partial-clip-text.c
index f467a5f..4d8bae0 100644
--- a/test/partial-clip-text.c
+++ b/test/partial-clip-text.c
@@ -26,25 +26,95 @@
 
 #include "cairo-test.h"
 
-static cairo_test_status_t
-draw (cairo_t *cr, int width, int height)
+#define HEIGHT 15
+#define WIDTH 40
+
+static void background (cairo_t *cr)
 {
      cairo_set_source_rgb( cr, 0, 0, 0 );
      cairo_paint (cr);
+}
 
-     cairo_rectangle (cr, 0, 0, 40, 5);
-     cairo_clip (cr);
-
+static void text (cairo_t *cr)
+{
      cairo_move_to (cr, 0, 12);
      cairo_set_source_rgb (cr, 1, 1, 1);
      cairo_show_text (cr, "CAIRO");
+}
+
+static cairo_test_status_t
+top (cairo_t *cr, int width, int height)
+{
+     background (cr);
+
+     cairo_rectangle (cr, 0, 0, WIDTH, 5);
+     cairo_clip (cr);
+
+     text (cr);
 
      return CAIRO_TEST_SUCCESS;
 }
 
-CAIRO_TEST (partial_clip_text,
+static cairo_test_status_t
+bottom (cairo_t *cr, int width, int height)
+{
+     background (cr);
+
+     cairo_rectangle (cr, 0, HEIGHT-5, WIDTH, 5);
+     cairo_clip (cr);
+
+     text (cr);
+
+     return CAIRO_TEST_SUCCESS;
+}
+
+static cairo_test_status_t
+left (cairo_t *cr, int width, int height)
+{
+     background (cr);
+
+     cairo_rectangle (cr, 0, 0, 10, HEIGHT);
+     cairo_clip (cr);
+
+     text (cr);
+
+     return CAIRO_TEST_SUCCESS;
+}
+
+static cairo_test_status_t
+right (cairo_t *cr, int width, int height)
+{
+     background (cr);
+
+     cairo_rectangle (cr, WIDTH-10, 0, 10, HEIGHT);
+     cairo_clip (cr);
+
+     text (cr);
+
+     return CAIRO_TEST_SUCCESS;
+}
+
+CAIRO_TEST (partial_clip_text_top,
+	    "Tests drawing text through a single, partial clip.",
+	    "clip, text", /* keywords */
+	    NULL, /* requirements */
+	    WIDTH, HEIGHT,
+	    NULL, top)
+CAIRO_TEST (partial_clip_text_bottom,
+	    "Tests drawing text through a single, partial clip.",
+	    "clip, text", /* keywords */
+	    NULL, /* requirements */
+	    WIDTH, HEIGHT,
+	    NULL, bottom)
+CAIRO_TEST (partial_clip_text_left,
+	    "Tests drawing text through a single, partial clip.",
+	    "clip, text", /* keywords */
+	    NULL, /* requirements */
+	    WIDTH, HEIGHT,
+	    NULL, left)
+CAIRO_TEST (partial_clip_text_right,
 	    "Tests drawing text through a single, partial clip.",
 	    "clip, text", /* keywords */
 	    NULL, /* requirements */
-	    40, 15,
-	    NULL, draw)
+	    WIDTH, HEIGHT,
+	    NULL, right)
diff --git a/test/partial-clip-text.ps.ref.png b/test/partial-clip-text.ps.ref.png
deleted file mode 100644
index 049bba5..0000000
Binary files a/test/partial-clip-text.ps.ref.png and /dev/null differ
diff --git a/test/partial-clip-text.quartz.ref.png b/test/partial-clip-text.quartz.ref.png
deleted file mode 100644
index 33ac283..0000000
Binary files a/test/partial-clip-text.quartz.ref.png and /dev/null differ
diff --git a/test/partial-clip-text.ref.png b/test/partial-clip-text.ref.png
deleted file mode 100644
index 6deaf75..0000000
Binary files a/test/partial-clip-text.ref.png and /dev/null differ
diff --git a/test/partial-clip-text.svg.ref.png b/test/partial-clip-text.svg.ref.png
deleted file mode 100644
index dc3fc58..0000000
Binary files a/test/partial-clip-text.svg.ref.png and /dev/null differ


More information about the cairo-commit mailing list