[cairo-commit] 9 commits - boilerplate/cairo-boilerplate.c boilerplate/cairo-boilerplate-pdf.c boilerplate/cairo-boilerplate-ps.c boilerplate/cairo-boilerplate-svg.c src/cairo-analysis-surface.c src/cairo.h src/cairo-image-surface.c src/cairoint.h src/cairo-paginated-surface.c src/cairo-pdf-surface.c src/cairo-ps-surface.c src/cairo-recording-surface.c src/cairo-recording-surface-private.h src/cairo-surface.c src/cairo-surface-private.h src/cairo-surface-snapshot.c src/cairo-surface-subsurface.c src/cairo-surface-subsurface-private.h src/cairo-surface-wrapper.c src/cairo-surface-wrapper-private.h src/cairo-vg-surface.c src/cairo-xcb-surface.c src/cairo-xcb-surface-core.c src/cairo-xcb-surface-render.c src/drm test/Makefile.am test/Makefile.sources test/subsurface.c test/subsurface.image16.ref.png test/subsurface-reflect.c test/subsurface-reflect.ref.png test/subsurface.ref.png test/subsurface-repeat.c test/subsurface-similar-repeat.c util/cairo-script util/cairo-trace

Chris Wilson ickle at kemper.freedesktop.org
Fri Apr 30 02:16:40 PDT 2010


 boilerplate/cairo-boilerplate-pdf.c        |    5 
 boilerplate/cairo-boilerplate-ps.c         |    5 
 boilerplate/cairo-boilerplate-svg.c        |    5 
 boilerplate/cairo-boilerplate.c            |   12 -
 src/cairo-analysis-surface.c               |   13 -
 src/cairo-image-surface.c                  |    4 
 src/cairo-paginated-surface.c              |    2 
 src/cairo-pdf-surface.c                    |  117 ++++++++--
 src/cairo-ps-surface.c                     |  121 +++++++++--
 src/cairo-recording-surface-private.h      |    1 
 src/cairo-recording-surface.c              |   18 -
 src/cairo-surface-private.h                |    7 
 src/cairo-surface-snapshot.c               |   31 ++
 src/cairo-surface-subsurface-private.h     |    4 
 src/cairo-surface-subsurface.c             |  140 +++++++++---
 src/cairo-surface-wrapper-private.h        |    7 
 src/cairo-surface-wrapper.c                |  314 +++++++++++++++++++++++------
 src/cairo-surface.c                        |  127 ++++-------
 src/cairo-vg-surface.c                     |    8 
 src/cairo-xcb-surface-core.c               |    6 
 src/cairo-xcb-surface-render.c             |   10 
 src/cairo-xcb-surface.c                    |   12 -
 src/cairo.h                                |   10 
 src/cairoint.h                             |    2 
 src/drm/cairo-drm-i915-shader.c            |   11 -
 src/drm/cairo-drm-i965-shader.c            |   11 -
 src/drm/cairo-drm-intel-surface.c          |    8 
 src/drm/cairo-drm-radeon-surface.c         |    8 
 test/Makefile.am                           |    1 
 test/Makefile.sources                      |    1 
 test/subsurface-reflect.c                  |   76 +++++++
 test/subsurface-reflect.ref.png            |binary
 test/subsurface-repeat.c                   |   10 
 test/subsurface-similar-repeat.c           |    5 
 test/subsurface.c                          |   11 -
 test/subsurface.image16.ref.png            |binary
 test/subsurface.ref.png                    |binary
 util/cairo-script/cairo-script-operators.c |   12 -
 util/cairo-trace/trace.c                   |   10 
 39 files changed, 820 insertions(+), 325 deletions(-)

New commits:
commit 5fe7c5842f3589efce765b3869c1dd55367a5aba
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Fri Apr 30 10:13:09 2010 +0100

    pdf; Emit subsurface patterns natively.
    
    Encode subsurface patterns into the PDF stream natively (when possible),
    similar to the cairo-ps backend.

diff --git a/src/cairo-pdf-surface.c b/src/cairo-pdf-surface.c
index 324a8d0..a76d289 100644
--- a/src/cairo-pdf-surface.c
+++ b/src/cairo-pdf-surface.c
@@ -53,6 +53,7 @@
 #include "cairo-paginated-private.h"
 #include "cairo-scaled-font-subsets-private.h"
 #include "cairo-surface-clipper-private.h"
+#include "cairo-surface-subsurface-private.h"
 #include "cairo-type3-glyph-surface-private.h"
 
 #include <time.h>
@@ -1051,18 +1052,26 @@ _get_source_surface_size (cairo_surface_t         *source,
     const unsigned char *mime_data;
     unsigned int mime_data_length;
 
-    if (_cairo_surface_is_recording (source)) {
-	cairo_recording_surface_t *recording_surface = (cairo_recording_surface_t *) source;
-	cairo_box_t bbox;
+    if (source->type == CAIRO_SURFACE_TYPE_RECORDING) {
+	if (source->backend->type == CAIRO_INTERNAL_SURFACE_TYPE_SUBSURFACE) {
+	     cairo_surface_subsurface_t *sub = (cairo_surface_subsurface_t *) source;
 
-	status = _cairo_recording_surface_get_bbox (recording_surface, &bbox, NULL);
-	if (unlikely (status))
-	    return status;
+	    *width  = sub->extents.width;
+	    *height = sub->extents.height;
+
+	} else {
+	    cairo_recording_surface_t *recording_surface = (cairo_recording_surface_t *) source;
+	    cairo_box_t bbox;
 
-	_cairo_box_round_to_rectangle (&bbox, &extents);
+	    status = _cairo_recording_surface_get_bbox (recording_surface, &bbox, NULL);
+	    if (unlikely (status))
+		return status;
 
-	*width = extents.width;
-	*height = extents.height;
+	    _cairo_box_round_to_rectangle (&bbox, &extents);
+
+	    *width = extents.width;
+	    *height = extents.height;
+	}
 	return CAIRO_STATUS_SUCCESS;
     }
 
@@ -2243,13 +2252,79 @@ _cairo_pdf_surface_emit_recording_surface (cairo_pdf_surface_t  *surface,
 }
 
 static cairo_status_t
+_cairo_pdf_surface_emit_recording_subsurface (cairo_pdf_surface_t  *surface,
+					      cairo_surface_t      *recording_surface,
+					      const cairo_rectangle_int_t *extents,
+					      cairo_pdf_resource_t  resource)
+{
+    double old_width, old_height;
+    cairo_paginated_mode_t old_paginated_mode;
+    cairo_status_t status;
+    int alpha = 0;
+
+    old_width = surface->width;
+    old_height = surface->height;
+    old_paginated_mode = surface->paginated_mode;
+
+    _cairo_pdf_surface_set_size_internal (surface,
+					  extents->width,
+					  extents->height);
+    /* Patterns are emitted after fallback images. The paginated mode
+     * needs to be set to _RENDER while the recording surface is replayed
+     * back to this surface.
+     */
+    surface->paginated_mode = CAIRO_PAGINATED_MODE_RENDER;
+    _cairo_pdf_group_resources_clear (&surface->resources);
+    status = _cairo_pdf_surface_open_content_stream (surface, &resource, TRUE);
+    if (unlikely (status))
+	return status;
+
+    if (cairo_surface_get_content (recording_surface) == CAIRO_CONTENT_COLOR) {
+	status = _cairo_pdf_surface_add_alpha (surface, 1.0, &alpha);
+	if (unlikely (status))
+	    return status;
+
+	_cairo_output_stream_printf (surface->output,
+				     "q /a%d gs 0 0 0 rg 0 0 %f %f re f Q\n",
+				     alpha,
+				     surface->width,
+				     surface->height);
+    }
+
+    status = _cairo_recording_surface_replay_region (recording_surface,
+						     extents,
+						     &surface->base,
+						     CAIRO_RECORDING_REGION_NATIVE);
+    assert (status != CAIRO_INT_STATUS_UNSUPPORTED);
+    if (unlikely (status))
+	return status;
+
+    status = _cairo_pdf_surface_close_content_stream (surface);
+
+    _cairo_pdf_surface_set_size_internal (surface,
+					  old_width,
+					  old_height);
+    surface->paginated_mode = old_paginated_mode;
+
+    return status;
+}
+
+static cairo_status_t
 _cairo_pdf_surface_emit_surface (cairo_pdf_surface_t        *surface,
 				 cairo_pdf_source_surface_t *src_surface)
 {
-    if (_cairo_surface_is_recording (src_surface->surface)) {
-	return _cairo_pdf_surface_emit_recording_surface (surface,
-						     src_surface->surface,
-						     src_surface->hash_entry->surface_res);
+    if (src_surface->surface->type == CAIRO_SURFACE_TYPE_RECORDING) {
+	if (src_surface->surface->backend->type == CAIRO_INTERNAL_SURFACE_TYPE_SUBSURFACE) {
+	    cairo_surface_subsurface_t *sub = (cairo_surface_subsurface_t *) src_surface->surface;
+	    return _cairo_pdf_surface_emit_recording_subsurface (surface,
+								 sub->target,
+								 &sub->extents,
+								 src_surface->hash_entry->surface_res);
+	} else {
+	    return _cairo_pdf_surface_emit_recording_surface (surface,
+							      src_surface->surface,
+							      src_surface->hash_entry->surface_res);
+	}
     } else {
 	return _cairo_pdf_surface_emit_image_surface (surface,
 						      src_surface->surface,
@@ -2276,7 +2351,7 @@ _cairo_pdf_surface_emit_surface_pattern (cairo_pdf_surface_t	*surface,
     char draw_surface[200];
 
     if (pattern->base.extend == CAIRO_EXTEND_PAD &&
-	 ! _cairo_surface_is_recording (pattern->surface))
+	pattern->surface->type != CAIRO_SURFACE_TYPE_RECORDING)
     {
 	status = _cairo_pdf_surface_emit_padded_image_surface (surface,
 							       pdf_pattern,
@@ -2407,7 +2482,7 @@ _cairo_pdf_surface_emit_surface_pattern (cairo_pdf_surface_t	*surface,
     if (unlikely (status))
 	return status;
 
-    if (_cairo_surface_is_recording (pattern->surface)) {
+    if (pattern->surface->type == CAIRO_SURFACE_TYPE_RECORDING) {
 	snprintf(draw_surface,
 		 sizeof (draw_surface),
 		 "/x%d Do\n",
@@ -3278,7 +3353,7 @@ _cairo_pdf_surface_paint_surface_pattern (cairo_pdf_surface_t     *surface,
     cairo_matrix_multiply (&pdf_p2d, &cairo_p2d, &pdf_p2d);
     cairo_matrix_translate (&pdf_p2d, 0.0, height);
     cairo_matrix_scale (&pdf_p2d, 1.0, -1.0);
-    if (! _cairo_surface_is_recording (source->surface))
+    if (source->surface->type != CAIRO_SURFACE_TYPE_RECORDING)
 	cairo_matrix_scale (&pdf_p2d, width, height);
 
     status = _cairo_pdf_operators_flush (&surface->pdf_operators);
@@ -5076,7 +5151,7 @@ _surface_pattern_supported (cairo_surface_pattern_t *pattern)
 {
     cairo_extend_t extend;
 
-    if (_cairo_surface_is_recording (pattern->surface))
+    if (pattern->surface->type == CAIRO_SURFACE_TYPE_RECORDING)
 	return TRUE;
 
     if (pattern->surface->backend->acquire_source_image == NULL)
@@ -5216,7 +5291,7 @@ _cairo_pdf_surface_analyze_operation (cairo_pdf_surface_t  *surface,
 	if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE) {
 	    cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *) pattern;
 
-	    if ( _cairo_surface_is_recording (surface_pattern->surface)) {
+	    if (surface_pattern->surface->type == CAIRO_SURFACE_TYPE_RECORDING) {
 		if (pattern->extend == CAIRO_EXTEND_PAD)
 		    return CAIRO_INT_STATUS_UNSUPPORTED;
 		else
@@ -5234,7 +5309,7 @@ _cairo_pdf_surface_analyze_operation (cairo_pdf_surface_t  *surface,
 	if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE) {
 	    cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *) pattern;
 
-	    if (_cairo_surface_is_recording (surface_pattern->surface)) {
+	    if (surface_pattern->surface->type == CAIRO_SURFACE_TYPE_RECORDING) {
 		if (_cairo_pattern_is_opaque (pattern, extents)) {
 		    return CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN;
 		} else {
commit 8ded35fd69ed0bbb07359c0278071a25af66571c
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Wed Apr 28 14:26:21 2010 +0100

    ps: Enable native encoding of subsurface patterns.
    
    Carefully handle subsurfaces of a recording surface through the analysis
    and paginated surfaces so that we can generate a native pattern for the
    vector backends, demonstrated by the PostScript backend.
    
    Nothing remarkable, just a lot of bookkeeping to track the wrapped
    surface types and to apply the correct offsets when generating the
    subsurface pattern.

diff --git a/src/cairo-analysis-surface.c b/src/cairo-analysis-surface.c
index f2cbfb2..5d554aa 100644
--- a/src/cairo-analysis-surface.c
+++ b/src/cairo-analysis-surface.c
@@ -40,6 +40,7 @@
 #include "cairo-error-private.h"
 #include "cairo-paginated-private.h"
 #include "cairo-recording-surface-private.h"
+#include "cairo-surface-subsurface-private.h"
 #include "cairo-region-private.h"
 
 typedef struct {
@@ -100,10 +101,11 @@ _analyze_recording_surface_pattern (cairo_analysis_surface_t *surface,
     cairo_bool_t old_has_ctm;
     cairo_matrix_t old_ctm, p2d;
     cairo_status_t status;
+    cairo_surface_t *source;
 
     assert (pattern->type == CAIRO_PATTERN_TYPE_SURFACE);
     surface_pattern = (const cairo_surface_pattern_t *) pattern;
-    assert (_cairo_surface_is_recording (surface_pattern->surface));
+    assert (surface_pattern->surface->type == CAIRO_SURFACE_TYPE_RECORDING);
 
     old_ctm = surface->ctm;
     old_has_ctm = surface->has_ctm;
@@ -115,8 +117,13 @@ _analyze_recording_surface_pattern (cairo_analysis_surface_t *surface,
     cairo_matrix_multiply (&surface->ctm, &p2d, &surface->ctm);
     surface->has_ctm = ! _cairo_matrix_is_identity (&surface->ctm);
 
-    status = _cairo_recording_surface_replay_and_create_regions (surface_pattern->surface,
-							    &surface->base);
+    source = surface_pattern->surface;
+    if (source->backend->type == CAIRO_INTERNAL_SURFACE_TYPE_SUBSURFACE) {
+	cairo_surface_subsurface_t *sub = (cairo_surface_subsurface_t *) source;
+	source = sub->target;
+    }
+
+    status = _cairo_recording_surface_replay_and_create_regions (source, &surface->base);
 
     surface->ctm = old_ctm;
     surface->has_ctm = old_has_ctm;
diff --git a/src/cairo-paginated-surface.c b/src/cairo-paginated-surface.c
index 4cb8503..a2c61dd 100644
--- a/src/cairo-paginated-surface.c
+++ b/src/cairo-paginated-surface.c
@@ -362,6 +362,7 @@ _paint_page (cairo_paginated_surface_t *surface)
 		                              CAIRO_PAGINATED_MODE_RENDER);
 
 	status = _cairo_recording_surface_replay_region (surface->recording_surface,
+							 NULL,
 							 surface->target,
 							 CAIRO_RECORDING_REGION_NATIVE);
 	assert (status != CAIRO_INT_STATUS_UNSUPPORTED);
diff --git a/src/cairo-pdf-surface.c b/src/cairo-pdf-surface.c
index 2f25bd5..324a8d0 100644
--- a/src/cairo-pdf-surface.c
+++ b/src/cairo-pdf-surface.c
@@ -2224,7 +2224,9 @@ _cairo_pdf_surface_emit_recording_surface (cairo_pdf_surface_t  *surface,
 				     surface->height);
     }
 
-    status = _cairo_recording_surface_replay_region (recording_surface, &surface->base,
+    status = _cairo_recording_surface_replay_region (recording_surface,
+						     NULL,
+						     &surface->base,
 						     CAIRO_RECORDING_REGION_NATIVE);
     assert (status != CAIRO_INT_STATUS_UNSUPPORTED);
     if (unlikely (status))
diff --git a/src/cairo-ps-surface.c b/src/cairo-ps-surface.c
index abc169e..422e232 100644
--- a/src/cairo-ps-surface.c
+++ b/src/cairo-ps-surface.c
@@ -64,6 +64,7 @@
 #include "cairo-paginated-private.h"
 #include "cairo-recording-surface-private.h"
 #include "cairo-surface-clipper-private.h"
+#include "cairo-surface-subsurface-private.h"
 #include "cairo-output-stream-private.h"
 #include "cairo-type3-glyph-surface-private.h"
 #include "cairo-image-info-private.h"
@@ -1642,7 +1643,7 @@ _cairo_ps_surface_analyze_surface_pattern_transparency (cairo_ps_surface_t
 static cairo_bool_t
 surface_pattern_supported (const cairo_surface_pattern_t *pattern)
 {
-    if (_cairo_surface_is_recording (pattern->surface))
+    if (pattern->surface->type == CAIRO_SURFACE_TYPE_RECORDING)
 	return TRUE;
 
     if (pattern->surface->backend->acquire_source_image == NULL)
@@ -1753,7 +1754,7 @@ _cairo_ps_surface_analyze_operation (cairo_ps_surface_t    *surface,
     if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE) {
 	cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *) pattern;
 
-	if ( _cairo_surface_is_recording (surface_pattern->surface)) {
+	if (surface_pattern->surface->type == CAIRO_SURFACE_TYPE_RECORDING) {
 	    if (pattern->extend == CAIRO_EXTEND_PAD)
 		return CAIRO_INT_STATUS_UNSUPPORTED;
 	    else
@@ -2431,7 +2432,81 @@ _cairo_ps_surface_emit_recording_surface (cairo_ps_surface_t *surface,
 				     surface->page_bbox.height);
     }
 
-    status = _cairo_recording_surface_replay_region (recording_surface, &surface->base,
+    status = _cairo_recording_surface_replay_region (recording_surface,
+						     NULL,
+						     &surface->base,
+						     CAIRO_RECORDING_REGION_NATIVE);
+    assert (status != CAIRO_INT_STATUS_UNSUPPORTED);
+    if (unlikely (status))
+	return status;
+
+    status = _cairo_pdf_operators_flush (&surface->pdf_operators);
+    if (unlikely (status))
+	return status;
+
+    _cairo_output_stream_printf (surface->stream, "  Q\n");
+    surface->content = old_content;
+    surface->width = old_width;
+    surface->height = old_height;
+    surface->page_bbox = old_page_bbox;
+    surface->current_pattern_is_solid_color = FALSE;
+    _cairo_pdf_operators_reset (&surface->pdf_operators);
+    surface->cairo_to_ps = old_cairo_to_ps;
+
+    _cairo_pdf_operators_set_cairo_to_pdf_matrix (&surface->pdf_operators,
+						  &surface->cairo_to_ps);
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_ps_surface_emit_recording_subsurface (cairo_ps_surface_t *surface,
+					     cairo_surface_t    *recording_surface,
+					     const cairo_rectangle_int_t *extents)
+{
+    double old_width, old_height;
+    cairo_matrix_t old_cairo_to_ps;
+    cairo_content_t old_content;
+    cairo_rectangle_int_t old_page_bbox;
+    cairo_status_t status;
+
+    old_content = surface->content;
+    old_width = surface->width;
+    old_height = surface->height;
+    old_page_bbox = surface->page_bbox;
+    old_cairo_to_ps = surface->cairo_to_ps;
+
+#if DEBUG_PS
+    _cairo_output_stream_printf (surface->stream,
+				 "%% _cairo_ps_surface_emit_recording_subsurface (%d, %d), (%d, %d)\n",
+				 extents->x, extents->y,
+				 extents->width, extents->height);
+#endif
+
+    surface->page_bbox.x = surface->page_bbox.y = 0;
+    surface->page_bbox.width = surface->width  = extents->width;
+    surface->page_bbox.height = surface->height = extents->height;
+
+    surface->current_pattern_is_solid_color = FALSE;
+    _cairo_pdf_operators_reset (&surface->pdf_operators);
+    cairo_matrix_init (&surface->cairo_to_ps, 1, 0, 0, -1, 0, surface->height);
+    _cairo_pdf_operators_set_cairo_to_pdf_matrix (&surface->pdf_operators,
+						  &surface->cairo_to_ps);
+    _cairo_output_stream_printf (surface->stream, "  q\n");
+
+    if (recording_surface->content == CAIRO_CONTENT_COLOR) {
+	surface->content = CAIRO_CONTENT_COLOR;
+	_cairo_output_stream_printf (surface->stream,
+				     "  0 g %d %d %d %d rectfill\n",
+				     surface->page_bbox.x,
+				     surface->page_bbox.y,
+				     surface->page_bbox.width,
+				     surface->page_bbox.height);
+    }
+
+    status = _cairo_recording_surface_replay_region (recording_surface,
+						     extents,
+						     &surface->base,
 						     CAIRO_RECORDING_REGION_NATIVE);
     assert (status != CAIRO_INT_STATUS_UNSUPPORTED);
     if (unlikely (status))
@@ -2515,18 +2590,25 @@ _cairo_ps_surface_acquire_surface (cairo_ps_surface_t      *surface,
     surface->acquired_image = NULL;
     surface->image = NULL;
 
-    if (_cairo_surface_is_recording (pattern->surface)) {
-	cairo_recording_surface_t *recording_surface = (cairo_recording_surface_t *) pattern->surface;
-	cairo_box_t bbox;
-	cairo_rectangle_int_t extents;
+    if (pattern->surface->type == CAIRO_SURFACE_TYPE_RECORDING) {
+	if (pattern->surface->backend->type == CAIRO_INTERNAL_SURFACE_TYPE_SUBSURFACE) {
+	    cairo_surface_subsurface_t *sub = (cairo_surface_subsurface_t *) pattern->surface;
 
-	status = _cairo_recording_surface_get_bbox (recording_surface, &bbox, NULL);
-	if (unlikely (status))
-	    return status;
+	    *width  = sub->extents.width;
+	    *height = sub->extents.height;
+	} else {
+	    cairo_recording_surface_t *recording_surface = (cairo_recording_surface_t *) pattern->surface;
+	    cairo_box_t bbox;
+	    cairo_rectangle_int_t extents;
+
+	    status = _cairo_recording_surface_get_bbox (recording_surface, &bbox, NULL);
+	    if (unlikely (status))
+		return status;
 
-	_cairo_box_round_to_rectangle (&bbox, &extents);
-	*width = extents.width;
-	*height =extents.height;
+	    _cairo_box_round_to_rectangle (&bbox, &extents);
+	    *width  = extents.width;
+	    *height = extents.height;
+	}
 	return CAIRO_STATUS_SUCCESS;
     } else {
 	status = _cairo_surface_acquire_source_image (pattern->surface,
@@ -2596,10 +2678,15 @@ _cairo_ps_surface_emit_surface (cairo_ps_surface_t      *surface,
 {
     cairo_status_t status;
 
-    if (_cairo_surface_is_recording (pattern->surface)) {
-	cairo_surface_t *recording_surface = pattern->surface;
+    if (pattern->surface->type == CAIRO_SURFACE_TYPE_RECORDING) {
+	cairo_surface_t *source = pattern->surface;
 
-	status = _cairo_ps_surface_emit_recording_surface (surface, recording_surface);
+	if (source->backend->type == CAIRO_INTERNAL_SURFACE_TYPE_SUBSURFACE) {
+	    cairo_surface_subsurface_t *sub = (cairo_surface_subsurface_t *) source;
+	    status = _cairo_ps_surface_emit_recording_subsurface (surface, sub->target, &sub->extents);
+	} else {
+	    status = _cairo_ps_surface_emit_recording_surface (surface, source);
+	}
     } else {
 	if (pattern->base.extend != CAIRO_EXTEND_PAD) {
 	    status = _cairo_ps_surface_emit_jpeg_image (surface, pattern->surface,
@@ -2622,7 +2709,7 @@ _cairo_ps_surface_release_surface (cairo_ps_surface_t      *surface,
     if (surface->image != surface->acquired_image)
 	cairo_surface_destroy (&surface->image->base);
 
-    if (! _cairo_surface_is_recording (pattern->surface)) {
+    if (pattern->surface->type != CAIRO_SURFACE_TYPE_RECORDING) {
 	_cairo_surface_release_source_image (pattern->surface,
 					     surface->acquired_image,
 					     surface->image_extra);
diff --git a/src/cairo-recording-surface-private.h b/src/cairo-recording-surface-private.h
index 569304d..4a5c9db 100644
--- a/src/cairo-recording-surface-private.h
+++ b/src/cairo-recording-surface-private.h
@@ -157,6 +157,7 @@ _cairo_recording_surface_replay_and_create_regions (cairo_surface_t *surface,
 						    cairo_surface_t *target);
 cairo_private cairo_status_t
 _cairo_recording_surface_replay_region (cairo_surface_t			*surface,
+					const cairo_rectangle_int_t *surface_extents,
 					cairo_surface_t			*target,
 					cairo_recording_region_type_t	region);
 
diff --git a/src/cairo-recording-surface.c b/src/cairo-recording-surface.c
index 099fdd5..35fe6b1 100644
--- a/src/cairo-recording-surface.c
+++ b/src/cairo-recording-surface.c
@@ -786,6 +786,7 @@ _cairo_recording_surface_get_path (cairo_surface_t    *surface,
 #define _clip(c) ((c)->header.clip.path ? &(c)->header.clip : NULL)
 static cairo_status_t
 _cairo_recording_surface_replay_internal (cairo_surface_t	     *surface,
+					  const cairo_rectangle_int_t *surface_extents,
 					  cairo_surface_t	     *target,
 					  cairo_recording_replay_type_t type,
 					  cairo_recording_region_type_t region)
@@ -802,13 +803,17 @@ _cairo_recording_surface_replay_internal (cairo_surface_t	     *surface,
     if (unlikely (target->status))
 	return _cairo_surface_set_error (surface, target->status);
 
+    assert (_cairo_surface_is_recording (surface));
+
     _cairo_surface_wrapper_init (&wrapper, target);
+    _cairo_surface_wrapper_set_extents (&wrapper, surface_extents);
 
     recording_surface = (cairo_recording_surface_t *) surface;
     status = CAIRO_STATUS_SUCCESS;
 
     num_elements = recording_surface->commands.num_elements;
     elements = _cairo_array_index (&recording_surface->commands, 0);
+
     for (i = recording_surface->replay_start_idx; i < num_elements; i++) {
 	cairo_command_t *command = elements[i];
 
@@ -975,7 +980,7 @@ cairo_status_t
 _cairo_recording_surface_replay (cairo_surface_t *surface,
 				 cairo_surface_t *target)
 {
-    return _cairo_recording_surface_replay_internal (surface,
+    return _cairo_recording_surface_replay_internal (surface, NULL,
 						     target,
 						     CAIRO_RECORDING_REPLAY,
 						     CAIRO_RECORDING_REGION_ALL);
@@ -991,7 +996,7 @@ 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,
+    return _cairo_recording_surface_replay_internal (surface, NULL,
 						     target,
 						     CAIRO_RECORDING_CREATE_REGIONS,
 						     CAIRO_RECORDING_REGION_ALL);
@@ -999,10 +1004,11 @@ _cairo_recording_surface_replay_and_create_regions (cairo_surface_t *surface,
 
 cairo_status_t
 _cairo_recording_surface_replay_region (cairo_surface_t          *surface,
+					const cairo_rectangle_int_t *surface_extents,
 					cairo_surface_t          *target,
 					cairo_recording_region_type_t  region)
 {
-    return _cairo_recording_surface_replay_internal (surface,
+    return _cairo_recording_surface_replay_internal (surface, surface_extents,
 						     target,
 						     CAIRO_RECORDING_REPLAY,
 						     region);
diff --git a/src/cairo-surface-private.h b/src/cairo-surface-private.h
index 5609290..bc03119 100644
--- a/src/cairo-surface-private.h
+++ b/src/cairo-surface-private.h
@@ -86,8 +86,10 @@ struct _cairo_surface {
     /* A "snapshot" surface is immutable. See _cairo_surface_snapshot. */
     cairo_surface_t *snapshot_of;
     cairo_surface_func_t snapshot_detach;
-    /* current snapshots of this surface, or place upon snapshot list */
+    /* current snapshots of this surface*/
     cairo_list_t snapshots;
+    /* place upon snapshot list */
+    cairo_list_t snapshot;
 
     /*
      * Surface font options, falling back to backend's default options,
diff --git a/src/cairo-surface-subsurface-private.h b/src/cairo-surface-subsurface-private.h
index 528dab7..6410abd 100644
--- a/src/cairo-surface-subsurface-private.h
+++ b/src/cairo-surface-subsurface-private.h
@@ -41,8 +41,10 @@
 struct _cairo_surface_subsurface {
     cairo_surface_t base;
 
-    cairo_surface_t *target;
     cairo_rectangle_int_t extents;
+
+    cairo_surface_t *target;
+    cairo_bool_t owns_target;
 };
 
 #endif /* CAIRO_SURFACE_SUBSURFACE_PRIVATE_H */
diff --git a/src/cairo-surface-subsurface.c b/src/cairo-surface-subsurface.c
index 489573a..079f9ed 100644
--- a/src/cairo-surface-subsurface.c
+++ b/src/cairo-surface-subsurface.c
@@ -36,17 +36,26 @@
 #include "cairoint.h"
 
 #include "cairo-error-private.h"
+#include "cairo-recording-surface-private.h"
 #include "cairo-surface-offset-private.h"
 #include "cairo-surface-subsurface-private.h"
 
+static const cairo_surface_backend_t _cairo_surface_subsurface_backend;
+
 static cairo_status_t
 _cairo_surface_subsurface_finish (void *abstract_surface)
 {
     cairo_surface_subsurface_t *surface = abstract_surface;
+    cairo_status_t status = CAIRO_STATUS_SUCCESS;
+
+    if (surface->owns_target) {
+	cairo_surface_finish (surface->target);
+	status = surface->target->status;
+    }
 
     cairo_surface_destroy (surface->target);
 
-    return CAIRO_STATUS_SUCCESS;
+    return status;
 }
 
 static cairo_surface_t *
@@ -284,6 +293,46 @@ _cairo_surface_subsurface_acquire_source_image (void                    *abstrac
     struct extra *extra;
     uint8_t *data;
 
+    if (surface->target->type == CAIRO_SURFACE_TYPE_RECORDING) {
+	cairo_recording_surface_t *meta = (cairo_recording_surface_t *) surface->target;
+	cairo_surface_t *snapshot;
+
+	snapshot = _cairo_surface_has_snapshot (&surface->base,
+						&_cairo_image_surface_backend);
+	if (snapshot != NULL) {
+	    *image_out = (cairo_image_surface_t *) cairo_surface_reference (snapshot);
+	    *extra_out = NULL;
+	    return CAIRO_STATUS_SUCCESS;
+	}
+
+	if (! _cairo_surface_has_snapshot (&meta->base,
+					   &_cairo_image_surface_backend))
+	{
+	    image = (cairo_image_surface_t *)
+		_cairo_image_surface_create_with_content (meta->content,
+							  surface->extents.width,
+							  surface->extents.height);
+	    if (unlikely (image->base.status))
+		return image->base.status;
+
+	    cairo_surface_set_device_offset (&image->base,
+					     -surface->extents.x,
+					     -surface->extents.y);
+
+	    status = _cairo_recording_surface_replay (&meta->base, &image->base);
+	    if (unlikely (status)) {
+		cairo_surface_destroy (&image->base);
+		return status;
+	    }
+
+	    _cairo_surface_attach_snapshot (&surface->base, &image->base, NULL);
+
+	    *image_out = image;
+	    *extra_out = NULL;
+	    return CAIRO_STATUS_SUCCESS;
+	}
+    }
+
     extra = malloc (sizeof (struct extra));
     if (unlikely (extra == NULL))
 	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
@@ -344,10 +393,13 @@ _cairo_surface_subsurface_release_source_image (void                   *abstract
 						void                   *abstract_extra)
 {
     cairo_surface_subsurface_t *surface = abstract_surface;
-    struct extra *extra = abstract_extra;
 
-    _cairo_surface_release_source_image (surface->target, extra->image, extra->image_extra);
-    free (extra);
+    if (abstract_extra != NULL) {
+	struct extra *extra = abstract_extra;
+
+	_cairo_surface_release_source_image (surface->target, extra->image, extra->image_extra);
+	free (extra);
+    }
 
     cairo_surface_destroy (&image->base);
 }
@@ -356,37 +408,23 @@ static cairo_surface_t *
 _cairo_surface_subsurface_snapshot (void *abstract_surface)
 {
     cairo_surface_subsurface_t *surface = abstract_surface;
-    cairo_image_surface_t *image, *clone;
-    void *image_extra;
-    cairo_status_t status;
+    cairo_surface_subsurface_t *snapshot;
 
-    /* XXX Alternatively we could snapshot the target and return a subsurface
-     * of that.
-     */
+    snapshot = malloc (sizeof (cairo_surface_subsurface_t));
+    if (unlikely (snapshot == NULL))
+	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
 
-    status = _cairo_surface_acquire_source_image (surface->target, &image, &image_extra);
-    if (unlikely (status))
-	return _cairo_surface_create_in_error (status);
-
-    clone = (cairo_image_surface_t *)
-	_cairo_image_surface_create_with_pixman_format (NULL,
-							image->pixman_format,
-							surface->extents.width,
-							surface->extents.height,
-							0);
-    if (likely (clone->base.status == CAIRO_STATUS_SUCCESS)) {
-	pixman_image_composite32 (PIXMAN_OP_SRC,
-				  image->pixman_image, NULL, clone->pixman_image,
-				  surface->extents.x, surface->extents.y,
-				  0, 0,
-				  0, 0,
-				  surface->extents.width, surface->extents.height);
-	clone->base.is_clear = FALSE;
-    }
+    _cairo_surface_init (&snapshot->base,
+			 &_cairo_surface_subsurface_backend,
+			 NULL, /* device */
+			 surface->target->content);
+    snapshot->target = _cairo_surface_snapshot (surface->target);
+    snapshot->owns_target = TRUE;
 
-    _cairo_surface_release_source_image (surface->target, image, image_extra);
+    snapshot->base.type = snapshot->target->type;
+    snapshot->extents = surface->extents;
 
-    return &clone->base;
+    return &snapshot->base;
 }
 
 static const cairo_surface_backend_t _cairo_surface_subsurface_backend = {
@@ -486,6 +524,7 @@ cairo_surface_create_for_rectangle (cairo_surface_t *target,
     }
 
     surface->target = cairo_surface_reference (target);
+    surface->owns_target = FALSE;
 
     return &surface->base;
 }
diff --git a/src/cairo-surface-wrapper-private.h b/src/cairo-surface-wrapper-private.h
index f0864c5..39dad2b 100644
--- a/src/cairo-surface-wrapper-private.h
+++ b/src/cairo-surface-wrapper-private.h
@@ -46,7 +46,8 @@ CAIRO_BEGIN_DECLS
 struct _cairo_surface_wrapper {
     cairo_surface_t *target;
 
-    /* any other information? */
+    cairo_bool_t has_extents;
+    cairo_rectangle_int_t extents;
 };
 
 cairo_private void
@@ -54,6 +55,10 @@ _cairo_surface_wrapper_init (cairo_surface_wrapper_t *wrapper,
 			     cairo_surface_t *target);
 
 cairo_private void
+_cairo_surface_wrapper_set_extents (cairo_surface_wrapper_t *wrapper,
+				    const cairo_rectangle_int_t *extents);
+
+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 c0d9672..39e90f0 100644
--- a/src/cairo-surface-wrapper.c
+++ b/src/cairo-surface-wrapper.c
@@ -71,6 +71,12 @@ _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,
@@ -100,30 +106,58 @@ _cairo_surface_wrapper_paint (cairo_surface_wrapper_t *wrapper,
     cairo_status_t status;
     cairo_clip_t clip_copy, *dev_clip = clip;
     cairo_pattern_union_t source_copy;
+    cairo_clip_t target_clip;
 
     if (unlikely (wrapper->target->status))
 	return wrapper->target->status;
 
-    if (clip && clip->all_clipped)
-	return CAIRO_STATUS_SUCCESS;
+    if (wrapper->has_extents) {
+	_cairo_clip_init_copy (&target_clip, clip);
+	status = _cairo_clip_rectangle (&target_clip, &wrapper->extents);
+	if (unlikely (status))
+	    goto FINISH;
+
+	dev_clip = clip = &target_clip;
+    }
+
+    if (clip && clip->all_clipped) {
+	status = CAIRO_STATUS_SUCCESS;
+	goto FINISH;
+    }
+
+    if (_cairo_surface_wrapper_needs_device_transform (wrapper) ||
+	_cairo_surface_wrapper_needs_extents_transform (wrapper))
+    {
+	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);
 
-    if (_cairo_surface_wrapper_needs_device_transform (wrapper)) {
 	if (clip != NULL) {
-	    status = _cairo_clip_init_copy_transformed (&clip_copy, clip,
-							&wrapper->target->device_transform);
+	    status = _cairo_clip_init_copy_transformed (&clip_copy, clip, &m);
 	    if (unlikely (status))
 		goto FINISH;
 
 	    dev_clip = &clip_copy;
 	}
 
-	_copy_transformed_pattern (&source_copy.base, source, &wrapper->target->device_transform_inverse);
+	status = cairo_matrix_invert (&m);
+	assert (status == CAIRO_STATUS_SUCCESS);
+
+	_copy_transformed_pattern (&source_copy.base, source, &m);
 	source = &source_copy.base;
     }
 
     status = _cairo_surface_paint (wrapper->target, op, source, dev_clip);
 
   FINISH:
+    if (wrapper->has_extents)
+	_cairo_clip_reset (&target_clip);
     if (dev_clip != clip)
 	_cairo_clip_reset (dev_clip);
     return status;
@@ -140,33 +174,61 @@ _cairo_surface_wrapper_mask (cairo_surface_wrapper_t *wrapper,
     cairo_clip_t clip_copy, *dev_clip = clip;
     cairo_pattern_union_t source_copy;
     cairo_pattern_union_t mask_copy;
+    cairo_clip_t target_clip;
 
     if (unlikely (wrapper->target->status))
 	return wrapper->target->status;
 
-    if (clip && clip->all_clipped)
-	return CAIRO_STATUS_SUCCESS;
+    if (wrapper->has_extents) {
+	_cairo_clip_init_copy (&target_clip, clip);
+	status = _cairo_clip_rectangle (&target_clip, &wrapper->extents);
+	if (unlikely (status))
+	    goto FINISH;
+
+	dev_clip = clip = &target_clip;
+    }
+
+    if (clip && clip->all_clipped) {
+	status = CAIRO_STATUS_SUCCESS;
+	goto FINISH;
+    }
+
+    if (_cairo_surface_wrapper_needs_device_transform (wrapper) ||
+	_cairo_surface_wrapper_needs_extents_transform (wrapper))
+    {
+	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);
 
-    if (_cairo_surface_wrapper_needs_device_transform (wrapper)) {
 	if (clip != NULL) {
-	    status = _cairo_clip_init_copy_transformed (&clip_copy, clip,
-							&wrapper->target->device_transform);
+	    status = _cairo_clip_init_copy_transformed (&clip_copy, clip, &m);
 	    if (unlikely (status))
 		goto FINISH;
 
 	    dev_clip = &clip_copy;
 	}
 
-	_copy_transformed_pattern (&source_copy.base, source, &wrapper->target->device_transform_inverse);
+	status = cairo_matrix_invert (&m);
+	assert (status == CAIRO_STATUS_SUCCESS);
+
+	_copy_transformed_pattern (&source_copy.base, source, &m);
 	source = &source_copy.base;
 
-	_copy_transformed_pattern (&mask_copy.base, mask, &wrapper->target->device_transform_inverse);
+	_copy_transformed_pattern (&mask_copy.base, mask, &m);
 	mask = &mask_copy.base;
     }
 
     status = _cairo_surface_mask (wrapper->target, op, source, mask, dev_clip);
 
   FINISH:
+    if (wrapper->has_extents)
+	_cairo_clip_reset (&target_clip);
     if (dev_clip != clip)
 	_cairo_clip_reset (dev_clip);
     return status;
@@ -190,38 +252,65 @@ _cairo_surface_wrapper_stroke (cairo_surface_wrapper_t *wrapper,
     cairo_matrix_t dev_ctm = *ctm;
     cairo_matrix_t dev_ctm_inverse = *ctm_inverse;
     cairo_pattern_union_t source_copy;
+    cairo_clip_t target_clip;
 
     if (unlikely (wrapper->target->status))
 	return wrapper->target->status;
 
-    if (clip && clip->all_clipped)
-	return CAIRO_STATUS_SUCCESS;
+    if (wrapper->has_extents) {
+	_cairo_clip_init_copy (&target_clip, clip);
+	status = _cairo_clip_rectangle (&target_clip, &wrapper->extents);
+	if (unlikely (status))
+	    goto FINISH;
+
+	dev_clip = clip = &target_clip;
+    }
+
+    if (clip && clip->all_clipped) {
+	status = CAIRO_STATUS_SUCCESS;
+	goto FINISH;
+    }
+
+    if (_cairo_surface_wrapper_needs_device_transform (wrapper) ||
+	_cairo_surface_wrapper_needs_extents_transform (wrapper))
+    {
+	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);
 
-    if (_cairo_surface_wrapper_needs_device_transform (wrapper)) {
 	status = _cairo_path_fixed_init_copy (&path_copy, dev_path);
 	if (unlikely (status))
 	    goto FINISH;
 
-	_cairo_path_fixed_transform (&path_copy, &wrapper->target->device_transform);
+	_cairo_path_fixed_transform (&path_copy, &m);
 	dev_path = &path_copy;
 
 	if (clip != NULL) {
-	    status = _cairo_clip_init_copy_transformed (&clip_copy, clip,
-							&wrapper->target->device_transform);
+	    status = _cairo_clip_init_copy_transformed (&clip_copy, clip, &m);
 	    if (unlikely (status))
 		goto FINISH;
 
 	    dev_clip = &clip_copy;
 	}
 
-	cairo_matrix_multiply (&dev_ctm, &dev_ctm, &wrapper->target->device_transform);
-	cairo_matrix_multiply (&dev_ctm_inverse,
-			       &wrapper->target->device_transform_inverse,
-			       &dev_ctm_inverse);
+	cairo_matrix_multiply (&dev_ctm, &dev_ctm, &m);
+
+	status = cairo_matrix_invert (&m);
+	assert (status == CAIRO_STATUS_SUCCESS);
 
-	_copy_transformed_pattern (&source_copy.base, source, &wrapper->target->device_transform_inverse);
+	cairo_matrix_multiply (&dev_ctm_inverse, &m, &dev_ctm_inverse);
+
+	_copy_transformed_pattern (&source_copy.base, source, &m);
 	source = &source_copy.base;
-    } else {
+    }
+    else
+    {
 	if (clip != NULL) {
 	    dev_clip = &clip_copy;
 	    _cairo_clip_init_copy (&clip_copy, clip);
@@ -237,6 +326,8 @@ _cairo_surface_wrapper_stroke (cairo_surface_wrapper_t *wrapper,
  FINISH:
     if (dev_path != path)
 	_cairo_path_fixed_fini (dev_path);
+    if (wrapper->has_extents)
+	_cairo_clip_reset (&target_clip);
     if (dev_clip != clip)
 	_cairo_clip_reset (dev_clip);
     return status;
@@ -266,41 +357,68 @@ _cairo_surface_wrapper_fill_stroke (cairo_surface_wrapper_t *wrapper,
     cairo_matrix_t dev_ctm_inverse = *stroke_ctm_inverse;
     cairo_pattern_union_t stroke_source_copy;
     cairo_pattern_union_t fill_source_copy;
+    cairo_clip_t target_clip;
 
     if (unlikely (wrapper->target->status))
 	return wrapper->target->status;
 
-    if (clip && clip->all_clipped)
-	return CAIRO_STATUS_SUCCESS;
+    if (wrapper->has_extents) {
+	_cairo_clip_init_copy (&target_clip, clip);
+	status = _cairo_clip_rectangle (&target_clip, &wrapper->extents);
+	if (unlikely (status))
+	    goto FINISH;
+
+	dev_clip = clip = &target_clip;
+    }
+
+    if (clip && clip->all_clipped) {
+	status = CAIRO_STATUS_SUCCESS;
+	goto FINISH;
+    }
+
+    if (_cairo_surface_wrapper_needs_device_transform (wrapper) ||
+	_cairo_surface_wrapper_needs_extents_transform (wrapper))
+    {
+	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);
 
-    if (_cairo_surface_wrapper_needs_device_transform (wrapper)) {
 	status = _cairo_path_fixed_init_copy (&path_copy, dev_path);
 	if (unlikely (status))
 	    goto FINISH;
 
-	_cairo_path_fixed_transform (&path_copy, &wrapper->target->device_transform);
+	_cairo_path_fixed_transform (&path_copy, &m);
 	dev_path = &path_copy;
 
 	if (clip != NULL) {
-	    status = _cairo_clip_init_copy_transformed (&clip_copy, clip,
-							&wrapper->target->device_transform);
+	    status = _cairo_clip_init_copy_transformed (&clip_copy, clip, &m);
 	    if (unlikely (status))
 		goto FINISH;
 
 	    dev_clip = &clip_copy;
 	}
 
-	cairo_matrix_multiply (&dev_ctm, &dev_ctm, &wrapper->target->device_transform);
-	cairo_matrix_multiply (&dev_ctm_inverse,
-			       &wrapper->target->device_transform_inverse,
-			       &dev_ctm_inverse);
+	cairo_matrix_multiply (&dev_ctm, &dev_ctm, &m);
 
-	_copy_transformed_pattern (&stroke_source_copy.base, stroke_source, &wrapper->target->device_transform_inverse);
+	status = cairo_matrix_invert (&m);
+	assert (status == CAIRO_STATUS_SUCCESS);
+
+	cairo_matrix_multiply (&dev_ctm_inverse, &m, &dev_ctm_inverse);
+
+	_copy_transformed_pattern (&stroke_source_copy.base, stroke_source, &m);
 	stroke_source = &stroke_source_copy.base;
 
-	_copy_transformed_pattern (&fill_source_copy.base, fill_source, &wrapper->target->device_transform_inverse);
+	_copy_transformed_pattern (&fill_source_copy.base, fill_source, &m);
 	fill_source = &fill_source_copy.base;
-    } else {
+    }
+    else
+    {
 	if (clip != NULL) {
 	    dev_clip = &clip_copy;
 	    _cairo_clip_init_copy (&clip_copy, clip);
@@ -320,6 +438,8 @@ _cairo_surface_wrapper_fill_stroke (cairo_surface_wrapper_t *wrapper,
   FINISH:
     if (dev_path != path)
 	_cairo_path_fixed_fini (dev_path);
+    if (wrapper->has_extents)
+	_cairo_clip_reset (&target_clip);
     if (dev_clip != clip)
 	_cairo_clip_reset (dev_clip);
     return status;
@@ -339,33 +459,61 @@ _cairo_surface_wrapper_fill (cairo_surface_wrapper_t	*wrapper,
     cairo_path_fixed_t path_copy, *dev_path = path;
     cairo_clip_t clip_copy, *dev_clip = clip;
     cairo_pattern_union_t source_copy;
+    cairo_clip_t target_clip;
 
     if (unlikely (wrapper->target->status))
 	return wrapper->target->status;
 
-    if (clip && clip->all_clipped)
-	return CAIRO_STATUS_SUCCESS;
+    if (wrapper->has_extents) {
+	_cairo_clip_init_copy (&target_clip, clip);
+	status = _cairo_clip_rectangle (&target_clip, &wrapper->extents);
+	if (unlikely (status))
+	    goto FINISH;
+
+	dev_clip = clip = &target_clip;
+    }
+
+    if (clip && clip->all_clipped) {
+	status = CAIRO_STATUS_SUCCESS;
+	goto FINISH;
+    }
+
+    if (_cairo_surface_wrapper_needs_device_transform (wrapper) ||
+	_cairo_surface_wrapper_needs_extents_transform (wrapper))
+    {
+	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);
 
-    if (_cairo_surface_wrapper_needs_device_transform (wrapper)) {
 	status = _cairo_path_fixed_init_copy (&path_copy, dev_path);
 	if (unlikely (status))
 	    goto FINISH;
 
-	_cairo_path_fixed_transform (&path_copy, &wrapper->target->device_transform);
+	_cairo_path_fixed_transform (&path_copy, &m);
 	dev_path = &path_copy;
 
 	if (clip != NULL) {
-	    status = _cairo_clip_init_copy_transformed (&clip_copy, clip,
-							&wrapper->target->device_transform);
+	    status = _cairo_clip_init_copy_transformed (&clip_copy, clip, &m);
 	    if (unlikely (status))
 		goto FINISH;
 
 	    dev_clip = &clip_copy;
 	}
 
-	_copy_transformed_pattern (&source_copy.base, source, &wrapper->target->device_transform_inverse);
+	status = cairo_matrix_invert (&m);
+	assert (status == CAIRO_STATUS_SUCCESS);
+
+	_copy_transformed_pattern (&source_copy.base, source, &m);
 	source = &source_copy.base;
-    } else {
+    }
+    else
+    {
 	if (clip != NULL) {
 	    dev_clip = &clip_copy;
 	    _cairo_clip_init_copy (&clip_copy, clip);
@@ -380,6 +528,8 @@ _cairo_surface_wrapper_fill (cairo_surface_wrapper_t	*wrapper,
  FINISH:
     if (dev_path != path)
 	_cairo_path_fixed_fini (dev_path);
+    if (wrapper->has_extents)
+	_cairo_clip_reset (&target_clip);
     if (dev_clip != clip)
 	_cairo_clip_reset (dev_clip);
     return status;
@@ -403,6 +553,7 @@ _cairo_surface_wrapper_show_text_glyphs (cairo_surface_wrapper_t *wrapper,
     cairo_clip_t clip_copy, *dev_clip = clip;
     cairo_glyph_t *dev_glyphs = glyphs;
     cairo_pattern_union_t source_copy;
+    cairo_clip_t target_clip;
 
     if (unlikely (wrapper->target->status))
 	return wrapper->target->status;
@@ -410,15 +561,36 @@ _cairo_surface_wrapper_show_text_glyphs (cairo_surface_wrapper_t *wrapper,
     if (glyphs == NULL || num_glyphs == 0)
 	return CAIRO_STATUS_SUCCESS;
 
-    if (clip && clip->all_clipped)
-	return CAIRO_STATUS_SUCCESS;
+    if (wrapper->has_extents) {
+	_cairo_clip_init_copy (&target_clip, clip);
+	status = _cairo_clip_rectangle (&target_clip, &wrapper->extents);
+	if (unlikely (status))
+	    goto FINISH;
+
+	dev_clip = clip = &target_clip;
+    }
+
+    if (clip && clip->all_clipped) {
+	status = CAIRO_STATUS_SUCCESS;
+	goto FINISH;
+    }
 
-    if (_cairo_surface_wrapper_needs_device_transform (wrapper)) {
+    if (_cairo_surface_wrapper_needs_device_transform (wrapper) ||
+	_cairo_surface_wrapper_needs_extents_transform (wrapper))
+    {
+	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);
+
 	if (clip != NULL) {
-	    status = _cairo_clip_init_copy_transformed (&clip_copy, clip,
-							&wrapper->target->device_transform);
+	    status = _cairo_clip_init_copy_transformed (&clip_copy, clip, &m);
 	    if (unlikely (status))
 		goto FINISH;
 
@@ -433,14 +605,17 @@ _cairo_surface_wrapper_show_text_glyphs (cairo_surface_wrapper_t *wrapper,
 
 	for (i = 0; i < num_glyphs; i++) {
 	    dev_glyphs[i] = glyphs[i];
-	    cairo_matrix_transform_point (&wrapper->target->device_transform,
-					  &dev_glyphs[i].x,
-					  &dev_glyphs[i].y);
+	    cairo_matrix_transform_point (&m, &dev_glyphs[i].x, &dev_glyphs[i].y);
 	}
 
-	_copy_transformed_pattern (&source_copy.base, source, &wrapper->target->device_transform_inverse);
+	status = cairo_matrix_invert (&m);
+	assert (status == CAIRO_STATUS_SUCCESS);
+
+	_copy_transformed_pattern (&source_copy.base, source, &m);
 	source = &source_copy.base;
-    } else {
+    }
+    else
+    {
 	if (clip != NULL) {
 	    dev_clip = &clip_copy;
 	    _cairo_clip_init_copy (&clip_copy, clip);
@@ -454,9 +629,12 @@ _cairo_surface_wrapper_show_text_glyphs (cairo_surface_wrapper_t *wrapper,
 					      cluster_flags,
 					      scaled_font,
 					      dev_clip);
+
  FINISH:
     if (dev_clip != clip)
 	_cairo_clip_reset (dev_clip);
+    if (wrapper->has_extents)
+	_cairo_clip_reset (&target_clip);
     if (dev_glyphs != glyphs)
 	free (dev_glyphs);
     return status;
@@ -476,7 +654,28 @@ cairo_bool_t
 _cairo_surface_wrapper_get_extents (cairo_surface_wrapper_t *wrapper,
 				    cairo_rectangle_int_t   *extents)
 {
-    return _cairo_surface_get_extents (wrapper->target, extents);
+    if (wrapper->has_extents) {
+	if (_cairo_surface_get_extents (wrapper->target, extents))
+	    _cairo_rectangle_intersect (extents, &wrapper->extents);
+	else
+	    *extents = wrapper->extents;
+
+	return TRUE;
+    } else {
+	return _cairo_surface_get_extents (wrapper->target, extents);
+    }
+}
+
+void
+_cairo_surface_wrapper_set_extents (cairo_surface_wrapper_t *wrapper,
+				    const cairo_rectangle_int_t *extents)
+{
+    if (extents != NULL) {
+	wrapper->extents = *extents;
+	wrapper->has_extents = TRUE;
+    } else {
+	wrapper->has_extents = FALSE;
+    }
 }
 
 void
@@ -503,6 +702,7 @@ _cairo_surface_wrapper_init (cairo_surface_wrapper_t *wrapper,
 			     cairo_surface_t *target)
 {
     wrapper->target = cairo_surface_reference (target);
+    wrapper->has_extents = FALSE;
 }
 
 void
diff --git a/src/cairo-surface.c b/src/cairo-surface.c
index 804f38e..a59c1ec 100644
--- a/src/cairo-surface.c
+++ b/src/cairo-surface.c
@@ -69,6 +69,7 @@ const cairo_surface_t name = {					\
     NULL,				/* snapshot_of */	\
     NULL,				/* snapshot_detach */	\
     { NULL, NULL },			/* snapshots */		\
+    { NULL, NULL },			/* snapshot */		\
     { CAIRO_ANTIALIAS_DEFAULT,		/* antialias */		\
       CAIRO_SUBPIXEL_ORDER_DEFAULT,	/* subpixel_order */	\
       CAIRO_HINT_STYLE_DEFAULT,		/* hint_style */	\
@@ -258,13 +259,10 @@ _cairo_surface_detach_mime_data (cairo_surface_t *surface)
 static void
 _cairo_surface_detach_snapshots (cairo_surface_t *surface)
 {
-    if (surface->snapshot_of != NULL)
-	return;
-
     while (_cairo_surface_has_snapshots (surface)) {
 	_cairo_surface_detach_snapshot (cairo_list_first_entry (&surface->snapshots,
 								cairo_surface_t,
-								snapshots));
+								snapshot));
     }
 }
 
@@ -274,7 +272,7 @@ _cairo_surface_detach_snapshot (cairo_surface_t *snapshot)
     assert (snapshot->snapshot_of != NULL);
 
     snapshot->snapshot_of = NULL;
-    cairo_list_del (&snapshot->snapshots);
+    cairo_list_del (&snapshot->snapshot);
 
     if (snapshot->snapshot_detach != NULL)
 	snapshot->snapshot_detach (snapshot);
@@ -288,7 +286,6 @@ _cairo_surface_attach_snapshot (cairo_surface_t *surface,
 				 cairo_surface_func_t detach_func)
 {
     assert (surface != snapshot);
-    assert (surface->snapshot_of == NULL);
     assert (snapshot->snapshot_of != surface);
 
     cairo_surface_reference (snapshot);
@@ -299,7 +296,7 @@ _cairo_surface_attach_snapshot (cairo_surface_t *surface,
     snapshot->snapshot_of = surface;
     snapshot->snapshot_detach = detach_func;
 
-    cairo_list_add (&snapshot->snapshots, &surface->snapshots);
+    cairo_list_add (&snapshot->snapshot, &surface->snapshots);
 
     assert (_cairo_surface_has_snapshot (surface, snapshot->backend) == snapshot);
 }
@@ -311,7 +308,7 @@ _cairo_surface_has_snapshot (cairo_surface_t *surface,
     cairo_surface_t *snapshot;
 
     cairo_list_foreach_entry (snapshot, cairo_surface_t,
-			      &surface->snapshots, snapshots)
+			      &surface->snapshots, snapshot)
     {
 	/* XXX is_similar? */
 	if (snapshot->backend == backend)
diff --git a/test/Makefile.am b/test/Makefile.am
index 94d2906..0d2283c 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -1070,6 +1070,7 @@ REFERENCE_IMAGES = \
 	stroke-image.xlib.ref.png \
 	subsurface.ref.png \
 	subsurface.image16.ref.png \
+	subsurface-reflect.ref.png \
 	subsurface-repeat.ref.png \
 	subsurface-similar-repeat.ref.png \
 	surface-pattern-big-scale-down.ref.png \
diff --git a/test/Makefile.sources b/test/Makefile.sources
index bf73d8e..4224786 100644
--- a/test/Makefile.sources
+++ b/test/Makefile.sources
@@ -227,6 +227,7 @@ test_sources = \
 	spline-decomposition.c				\
 	subsurface.c                                    \
 	subsurface-repeat.c                             \
+	subsurface-reflect.c                            \
 	subsurface-similar-repeat.c                     \
 	surface-finish-twice.c				\
 	surface-pattern.c				\
diff --git a/test/subsurface-reflect.c b/test/subsurface-reflect.c
new file mode 100644
index 0000000..e7ddbac
--- /dev/null
+++ b/test/subsurface-reflect.c
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2009 Intel Corporation
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without
+ * fee, provided that the above copyright notice appear in all copies
+ * and that both that copyright notice and this permission notice
+ * appear in supporting documentation, and that the name of
+ * Intel not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior
+ * permission. Intel makes no representations about the
+ * suitability of this software for any purpose.  It is provided "as
+ * is" without express or implied warranty.
+ *
+ * INTEL CORPORATION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL INTEL CORPORATION BE LIABLE FOR ANY SPECIAL,
+ * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
+ * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author: Chris Wilson <chris at chris-wilson.co.uk>
+ */
+
+#include "cairo-test.h"
+
+static cairo_test_status_t
+draw (cairo_t *cr, int width, int height)
+{
+    cairo_surface_t *region;
+    cairo_t *cr_region;
+
+    cairo_set_source_rgb (cr, .5, .5, .5);
+    cairo_paint (cr);
+
+    /* fill the centre */
+    region = cairo_surface_create_for_rectangle (cairo_get_target (cr),
+						 20, 20, 20, 20);
+    cr_region = cairo_create (region);
+    cairo_surface_destroy (region);
+
+    cairo_set_source_rgb (cr_region, 1, 1, 1);
+    cairo_rectangle (cr_region, 0, 0, 10, 10);
+    cairo_fill (cr_region);
+
+    cairo_set_source_rgb (cr_region, 1, 0, 0);
+    cairo_rectangle (cr_region, 10, 0, 10, 10);
+    cairo_fill (cr_region);
+
+    cairo_set_source_rgb (cr_region, 0, 1, 0);
+    cairo_rectangle (cr_region, 0, 10, 10, 10);
+    cairo_fill (cr_region);
+
+    cairo_set_source_rgb (cr_region, 0, 0, 1);
+    cairo_rectangle (cr_region, 10, 10, 10, 10);
+    cairo_fill (cr_region);
+
+    cairo_set_source_surface (cr, cairo_get_target (cr_region), 20, 20);
+    cairo_destroy (cr_region);
+
+    /* reflect the pattern around the outside, but do not overwrite...*/
+    cairo_pattern_set_extend (cairo_get_source (cr), CAIRO_EXTEND_REFLECT);
+    cairo_rectangle (cr, 0, 0, width, height);
+    cairo_rectangle (cr, 20, 40, 20, -20);
+    cairo_fill (cr);
+
+    return CAIRO_TEST_SUCCESS;
+}
+
+CAIRO_TEST (subsurface_reflect,
+	    "Tests source clipping with reflect",
+	    "subsurface, reflect", /* keywords */
+	    NULL, /* requirements */
+	    60, 60,
+	    NULL, draw)
diff --git a/test/subsurface-reflect.ref.png b/test/subsurface-reflect.ref.png
new file mode 100644
index 0000000..55643f4
Binary files /dev/null and b/test/subsurface-reflect.ref.png differ
diff --git a/test/subsurface-repeat.c b/test/subsurface-repeat.c
index 849c0df..84e25f4 100644
--- a/test/subsurface-repeat.c
+++ b/test/subsurface-repeat.c
@@ -36,7 +36,7 @@ draw (cairo_t *cr, int width, int height)
 
     /* fill the centre */
     region = cairo_surface_create_for_rectangle (cairo_get_target (cr),
-                                                 0, 0, 20, 20);
+						 20, 20, 20, 20);
     cr_region = cairo_create (region);
     cairo_surface_destroy (region);
 
@@ -58,8 +58,12 @@ draw (cairo_t *cr, int width, int height)
 
     cairo_set_source_surface (cr, cairo_get_target (cr_region), 20, 20);
     cairo_destroy (cr_region);
+
+    /* repeat the pattern around the outside, but do not overwrite...*/
     cairo_pattern_set_extend (cairo_get_source (cr), CAIRO_EXTEND_REPEAT);
-    cairo_paint (cr);
+    cairo_rectangle (cr, 0, 0, width, height);
+    cairo_rectangle (cr, 20, 40, 20, -20);
+    cairo_fill (cr);
 
     return CAIRO_TEST_SUCCESS;
 }
diff --git a/test/subsurface-similar-repeat.c b/test/subsurface-similar-repeat.c
index 492bc77..5f17b49 100644
--- a/test/subsurface-similar-repeat.c
+++ b/test/subsurface-similar-repeat.c
@@ -40,6 +40,7 @@ draw (cairo_t *cr, int width, int height)
 					    60, 60);
     cr_region = cairo_create (similar);
     cairo_surface_destroy (similar);
+
     cairo_set_source_rgb (cr_region, .5, .5, .0);
     cairo_paint (cr_region);
     similar = cairo_surface_reference (cairo_get_target (cr_region));
@@ -48,6 +49,7 @@ draw (cairo_t *cr, int width, int height)
     /* fill the centre */
     region = cairo_surface_create_for_rectangle (similar, 20, 20, 20, 20);
     cairo_surface_destroy (similar);
+
     cr_region = cairo_create (region);
     cairo_surface_destroy (region);
 
@@ -69,6 +71,7 @@ draw (cairo_t *cr, int width, int height)
 
     cairo_set_source_surface (cr, cairo_get_target (cr_region), 20, 20);
     cairo_destroy (cr_region);
+
     cairo_pattern_set_extend (cairo_get_source (cr), CAIRO_EXTEND_REPEAT);
     cairo_paint (cr);
 
diff --git a/test/subsurface.c b/test/subsurface.c
index 3ccc469..d79d3d1 100644
--- a/test/subsurface.c
+++ b/test/subsurface.c
@@ -63,6 +63,11 @@ draw (cairo_t *cr, int width, int height)
 
     for (i = 0; i < 5; i++) {
 	cairo_set_source_surface (cr, region[5-i-1], 20 * i, 20);
+	cairo_paint (cr);
+    }
+
+    for (i = 0; i < 5; i++) {
+	cairo_set_source_surface (cr, region[5-i-1], 20 * i, 40);
 	cairo_paint_with_alpha (cr, .5);
     }
 
@@ -76,5 +81,5 @@ CAIRO_TEST (subsurface,
 	    "Tests clipping of both source and destination using subsurfaces",
 	    "subsurface", /* keywords */
 	    NULL, /* requirements */
-	    100, 40,
+	    100, 60,
 	    NULL, draw)
diff --git a/test/subsurface.image16.ref.png b/test/subsurface.image16.ref.png
index 1320248..ba9b7ed 100644
Binary files a/test/subsurface.image16.ref.png and b/test/subsurface.image16.ref.png differ
diff --git a/test/subsurface.ref.png b/test/subsurface.ref.png
index 54fc0d0..ceaf3f7 100644
Binary files a/test/subsurface.ref.png and b/test/subsurface.ref.png differ
commit 5fc04bba9fa8ddda8cf7d7a97015f21a21429172
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Thu Apr 29 21:51:29 2010 +0100

    paginated: Call surface finish explicitly on recording surface
    
    During show_page() when we destroy the recording surface after emitting
    the page, ensure that we actually call cairo_surface_finish() to dispose
    of any self-referential reference leaks.

diff --git a/src/cairo-paginated-surface.c b/src/cairo-paginated-surface.c
index 686acd0..4cb8503 100644
--- a/src/cairo-paginated-surface.c
+++ b/src/cairo-paginated-surface.c
@@ -472,6 +472,7 @@ _cairo_paginated_surface_show_page (void *abstract_surface)
     if (unlikely (status))
 	return status;
 
+    cairo_surface_finish (surface->recording_surface);
     status = surface->recording_surface->status;
     if (unlikely (status))
 	return status;
commit 3ae57234644c3756785c551beffe584f837b0273
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Thu Apr 29 21:50:22 2010 +0100

    boilerplate: Ensure that the recording surfaces are finished.
    
    Be paranoid and explicitly call finish to cleanup self-referential leaks
    when using paginated/recording surfaces.

diff --git a/boilerplate/cairo-boilerplate-pdf.c b/boilerplate/cairo-boilerplate-pdf.c
index d45e6ca..8459f58 100644
--- a/boilerplate/cairo-boilerplate-pdf.c
+++ b/boilerplate/cairo-boilerplate-pdf.c
@@ -137,6 +137,7 @@ _cairo_boilerplate_pdf_finish_surface (cairo_surface_t		*surface)
 	if (status)
 	    return status;
 
+	cairo_surface_finish (surface);
 	status = cairo_surface_status (surface);
 	if (status)
 	    return status;
@@ -204,8 +205,10 @@ static void
 _cairo_boilerplate_pdf_cleanup (void *closure)
 {
     pdf_target_closure_t *ptc = closure;
-    if (ptc->target)
+    if (ptc->target) {
+	cairo_surface_finish (ptc->target);
 	cairo_surface_destroy (ptc->target);
+    }
     free (ptc->filename);
     free (ptc);
 }
diff --git a/boilerplate/cairo-boilerplate-ps.c b/boilerplate/cairo-boilerplate-ps.c
index a0a5447..20452d8 100644
--- a/boilerplate/cairo-boilerplate-ps.c
+++ b/boilerplate/cairo-boilerplate-ps.c
@@ -197,6 +197,7 @@ _cairo_boilerplate_ps_finish_surface (cairo_surface_t		*surface)
 	if (status)
 	    return status;
 
+	cairo_surface_finish (surface);
 	status = cairo_surface_status (surface);
 	if (status)
 	    return status;
@@ -269,8 +270,10 @@ static void
 _cairo_boilerplate_ps_cleanup (void *closure)
 {
     ps_target_closure_t *ptc = closure;
-    if (ptc->target)
+    if (ptc->target) {
+	cairo_surface_finish (ptc->target);
 	cairo_surface_destroy (ptc->target);
+    }
     free (ptc->filename);
     free (ptc);
 }
diff --git a/boilerplate/cairo-boilerplate-svg.c b/boilerplate/cairo-boilerplate-svg.c
index 43305da..583f9a1 100644
--- a/boilerplate/cairo-boilerplate-svg.c
+++ b/boilerplate/cairo-boilerplate-svg.c
@@ -170,6 +170,7 @@ _cairo_boilerplate_svg_finish_surface (cairo_surface_t		*surface)
 	if (status)
 	    return status;
 
+	cairo_surface_finish (surface);
 	status = cairo_surface_status (surface);
 	if (status)
 	    return status;
@@ -241,8 +242,10 @@ static void
 _cairo_boilerplate_svg_cleanup (void *closure)
 {
     svg_target_closure_t *ptc = closure;
-    if (ptc->target)
+    if (ptc->target) {
+	cairo_surface_finish (ptc->target);
 	cairo_surface_destroy (ptc->target);
+    }
     free (ptc->filename);
     free (ptc);
 }
diff --git a/boilerplate/cairo-boilerplate.c b/boilerplate/cairo-boilerplate.c
index e0bf51a..062c99e 100644
--- a/boilerplate/cairo-boilerplate.c
+++ b/boilerplate/cairo-boilerplate.c
@@ -180,13 +180,11 @@ _cairo_boilerplate_recording_create_surface (const char		     *name,
 {
     cairo_rectangle_t extents;
 
-    *closure = NULL;
-
     extents.x = 0;
     extents.y = 0;
     extents.width = width;
     extents.height = height;
-    return cairo_recording_surface_create (content, &extents);
+    return *closure = cairo_recording_surface_create (content, &extents);
 }
 #endif
 
@@ -353,7 +351,8 @@ static const cairo_boilerplate_target_t builtin_targets[] = {
 	NULL, NULL,
 	_cairo_boilerplate_get_image_surface,
 	cairo_surface_write_to_png,
-	NULL, NULL,
+	(cairo_boilerplate_cleanup_t) cairo_surface_finish,
+	NULL,
 	FALSE, FALSE, TRUE
     },
     {
@@ -364,7 +363,8 @@ static const cairo_boilerplate_target_t builtin_targets[] = {
 	NULL, NULL,
 	_cairo_boilerplate_get_image_surface,
 	cairo_surface_write_to_png,
-	NULL, NULL,
+	(cairo_boilerplate_cleanup_t) cairo_surface_finish,
+	NULL,
 	FALSE, FALSE, TRUE
     },
 #endif
commit f08cc311af1248b39c3e757ef192515ed8506862
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Thu Apr 29 20:34:56 2010 +0100

    boilerplate: Destroy the redundant image reference
    
    When using a script surface to record the recording surface, we replace
    the local reference to the image surface.

diff --git a/boilerplate/cairo-boilerplate.c b/boilerplate/cairo-boilerplate.c
index cc08280..e0bf51a 100644
--- a/boilerplate/cairo-boilerplate.c
+++ b/boilerplate/cairo-boilerplate.c
@@ -223,6 +223,8 @@ _cairo_boilerplate_get_image_surface (cairo_surface_t *src,
 	    cairo_device_t *ctx;
 	    char *filename;
 
+            cairo_surface_destroy (surface);
+
 	    xasprintf (&filename, "%s.out.trace", test_name);
 	    ctx = cairo_script_create (filename);
 	    surface = cairo_script_surface_create_for_target (ctx, image);
commit ab2776c9a16134c50b48fd202263421ec0f466e7
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Thu Apr 29 18:50:32 2010 +0100

    snapshot: Attach the backend generated snapshot to the target
    
    Cache the result of snapshotting using the backend vfunc in the normal
    manner by attaching the snapshot to the target. This should reduce
    resource usage in these cases.

diff --git a/src/cairo-surface-snapshot.c b/src/cairo-surface-snapshot.c
index 02c79c1..20cc6b9 100644
--- a/src/cairo-surface-snapshot.c
+++ b/src/cairo-surface-snapshot.c
@@ -196,9 +196,28 @@ _cairo_surface_snapshot (cairo_surface_t *surface)
     if (surface->backend->snapshot != NULL) {
 	cairo_surface_t *snap;
 
-	snap = surface->backend->snapshot (surface);
+	snap = _cairo_surface_has_snapshot (surface, surface->backend);
 	if (snap != NULL)
+	    return cairo_surface_reference (snap);
+
+	snap = surface->backend->snapshot (surface);
+	if (snap != NULL) {
+	    if (unlikely (snap->status))
+		return snap;
+
+	    status = _cairo_surface_copy_mime_data (snap, surface);
+	    if (unlikely (status)) {
+		cairo_surface_destroy (snap);
+		return _cairo_surface_create_in_error (status);
+	    }
+
+	    snap->device_transform = surface->device_transform;
+	    snap->device_transform_inverse = surface->device_transform_inverse;
+
+	    _cairo_surface_attach_snapshot (surface, snap, NULL);
+
 	    return snap;
+	}
     }
 
     snapshot = (cairo_surface_snapshot_t *)
commit 07122f37d11eabe62bc9c81ccbf71bbe8b7a1005
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Thu Apr 29 15:19:18 2010 +0100

    surface: Convert snapshots from an array to a double-linked list.
    
    Saves the memory allocation for the array, and the overhead of
    maintaining the area for both insertions and more importantly deletes.

diff --git a/src/cairo-recording-surface.c b/src/cairo-recording-surface.c
index 7a931ee..099fdd5 100644
--- a/src/cairo-recording-surface.c
+++ b/src/cairo-recording-surface.c
@@ -269,11 +269,7 @@ _cairo_recording_surface_acquire_source_image (void			 *abstract_surface,
 	return status;
     }
 
-    status = _cairo_surface_attach_snapshot (&surface->base, image, NULL);
-    if (unlikely (status)) {
-	cairo_surface_destroy (image);
-	return status;
-    }
+    _cairo_surface_attach_snapshot (&surface->base, image, NULL);
 
     *image_out = (cairo_image_surface_t *) image;
     *image_extra = NULL;
diff --git a/src/cairo-surface-private.h b/src/cairo-surface-private.h
index e7a3da4..5609290 100644
--- a/src/cairo-surface-private.h
+++ b/src/cairo-surface-private.h
@@ -41,6 +41,7 @@
 #include "cairo.h"
 
 #include "cairo-types-private.h"
+#include "cairo-list-private.h"
 #include "cairo-reference-count-private.h"
 #include "cairo-clip-private.h"
 
@@ -85,8 +86,8 @@ struct _cairo_surface {
     /* A "snapshot" surface is immutable. See _cairo_surface_snapshot. */
     cairo_surface_t *snapshot_of;
     cairo_surface_func_t snapshot_detach;
-    /* current snapshots of this surface */
-    cairo_array_t snapshots;
+    /* current snapshots of this surface, or place upon snapshot list */
+    cairo_list_t snapshots;
 
     /*
      * Surface font options, falling back to backend's default options,
diff --git a/src/cairo-surface-snapshot.c b/src/cairo-surface-snapshot.c
index 4ad16aa..02c79c1 100644
--- a/src/cairo-surface-snapshot.c
+++ b/src/cairo-surface-snapshot.c
@@ -228,13 +228,9 @@ _cairo_surface_snapshot (cairo_surface_t *surface)
     snapshot->base.device_transform = surface->device_transform;
     snapshot->base.device_transform_inverse = surface->device_transform_inverse;
 
-    status = _cairo_surface_attach_snapshot (surface,
-					     &snapshot->base,
-					     _cairo_surface_snapshot_copy_on_write);
-    if (unlikely (status)) {
-	cairo_surface_destroy (&snapshot->base);
-	return _cairo_surface_create_in_error (status);
-    }
+    _cairo_surface_attach_snapshot (surface,
+				    &snapshot->base,
+				    _cairo_surface_snapshot_copy_on_write);
 
     return &snapshot->base;
 }
diff --git a/src/cairo-surface.c b/src/cairo-surface.c
index ddb1ffd..804f38e 100644
--- a/src/cairo-surface.c
+++ b/src/cairo-surface.c
@@ -68,11 +68,7 @@ const cairo_surface_t name = {					\
     0.0,				/* y_fallback_resolution */	\
     NULL,				/* snapshot_of */	\
     NULL,				/* snapshot_detach */	\
-    { 0,	/* size */					\
-      0,	/* num_elements */				\
-      0,	/* element_size */				\
-      NULL,	/* elements */					\
-    },					/* snapshots */		\
+    { NULL, NULL },			/* snapshots */		\
     { CAIRO_ANTIALIAS_DEFAULT,		/* antialias */		\
       CAIRO_SUBPIXEL_ORDER_DEFAULT,	/* subpixel_order */	\
       CAIRO_HINT_STYLE_DEFAULT,		/* hint_style */	\
@@ -240,30 +236,7 @@ cairo_surface_get_device (cairo_surface_t *surface)
 static cairo_bool_t
 _cairo_surface_has_snapshots (cairo_surface_t *surface)
 {
-    return surface->snapshots.num_elements != 0;
-}
-
-static void
-_cairo_surface_detach_snapshots (cairo_surface_t *surface)
-{
-    cairo_surface_t **snapshots;
-    unsigned int i;
-
-    if (! _cairo_surface_has_snapshots (surface))
-	return;
-
-    snapshots = _cairo_array_index (&surface->snapshots, 0);
-    for (i = 0; i < surface->snapshots.num_elements; i++) {
-	snapshots[i]->snapshot_of = NULL;
-
-	if (snapshots[i]->snapshot_detach != NULL)
-	    snapshots[i]->snapshot_detach (snapshots[i]);
-
-	cairo_surface_destroy (snapshots[i]);
-    }
-    surface->snapshots.num_elements = 0;
-
-    assert (! _cairo_surface_has_snapshots (surface));
+    return ! cairo_list_is_empty (&surface->snapshots);
 }
 
 static cairo_bool_t
@@ -282,14 +255,43 @@ _cairo_surface_detach_mime_data (cairo_surface_t *surface)
     _cairo_user_data_array_init (&surface->mime_data);
 }
 
-cairo_status_t
-_cairo_surface_attach_snapshot (cairo_surface_t *surface,
-				cairo_surface_t *snapshot,
-				cairo_surface_func_t detach_func)
+static void
+_cairo_surface_detach_snapshots (cairo_surface_t *surface)
 {
-    cairo_status_t status;
+    if (surface->snapshot_of != NULL)
+	return;
+
+    while (_cairo_surface_has_snapshots (surface)) {
+	_cairo_surface_detach_snapshot (cairo_list_first_entry (&surface->snapshots,
+								cairo_surface_t,
+								snapshots));
+    }
+}
 
+void
+_cairo_surface_detach_snapshot (cairo_surface_t *snapshot)
+{
+    assert (snapshot->snapshot_of != NULL);
+
+    snapshot->snapshot_of = NULL;
+    cairo_list_del (&snapshot->snapshots);
+
+    if (snapshot->snapshot_detach != NULL)
+	snapshot->snapshot_detach (snapshot);
+
+    cairo_surface_destroy (snapshot);
+}
+
+void
+_cairo_surface_attach_snapshot (cairo_surface_t *surface,
+				 cairo_surface_t *snapshot,
+				 cairo_surface_func_t detach_func)
+{
     assert (surface != snapshot);
+    assert (surface->snapshot_of == NULL);
+    assert (snapshot->snapshot_of != surface);
+
+    cairo_surface_reference (snapshot);
 
     if (snapshot->snapshot_of != NULL)
 	_cairo_surface_detach_snapshot (snapshot);
@@ -297,61 +299,28 @@ _cairo_surface_attach_snapshot (cairo_surface_t *surface,
     snapshot->snapshot_of = surface;
     snapshot->snapshot_detach = detach_func;
 
-    status = _cairo_array_append (&surface->snapshots, &snapshot);
-    if (unlikely (status))
-	return status;
+    cairo_list_add (&snapshot->snapshots, &surface->snapshots);
 
-    cairo_surface_reference (snapshot);
-    return CAIRO_STATUS_SUCCESS;
+    assert (_cairo_surface_has_snapshot (surface, snapshot->backend) == snapshot);
 }
 
 cairo_surface_t *
 _cairo_surface_has_snapshot (cairo_surface_t *surface,
 			     const cairo_surface_backend_t *backend)
 {
-    cairo_surface_t **snapshots;
-    unsigned int i;
+    cairo_surface_t *snapshot;
 
-    /* XXX is_similar? */
-    snapshots = _cairo_array_index (&surface->snapshots, 0);
-    for (i = 0; i < surface->snapshots.num_elements; i++) {
-	if (snapshots[i]->backend == backend)
-	    return snapshots[i];
+    cairo_list_foreach_entry (snapshot, cairo_surface_t,
+			      &surface->snapshots, snapshots)
+    {
+	/* XXX is_similar? */
+	if (snapshot->backend == backend)
+	    return snapshot;
     }
 
     return NULL;
 }
 
-void
-_cairo_surface_detach_snapshot (cairo_surface_t *snapshot)
-{
-    cairo_surface_t *surface;
-    cairo_surface_t **snapshots;
-    unsigned int i;
-
-    assert (snapshot->snapshot_of != NULL);
-    surface = snapshot->snapshot_of;
-
-    snapshots = _cairo_array_index (&surface->snapshots, 0);
-    for (i = 0; i < surface->snapshots.num_elements; i++) {
-	if (snapshots[i] == snapshot)
-	    break;
-    }
-    assert (i < surface->snapshots.num_elements);
-
-    surface->snapshots.num_elements--;
-    memmove (&snapshots[i],
-	     &snapshots[i+1],
-	     sizeof (cairo_surface_t *)*(surface->snapshots.num_elements - i));
-
-    snapshot->snapshot_of = NULL;
-
-    if (snapshot->snapshot_detach != NULL)
-	snapshot->snapshot_detach (snapshot);
-
-    cairo_surface_destroy (snapshot);
-}
-
 static cairo_bool_t
 _cairo_surface_is_writable (cairo_surface_t *surface)
 {
@@ -403,7 +372,7 @@ _cairo_surface_init (cairo_surface_t			*surface,
     surface->x_fallback_resolution = CAIRO_SURFACE_FALLBACK_RESOLUTION_DEFAULT;
     surface->y_fallback_resolution = CAIRO_SURFACE_FALLBACK_RESOLUTION_DEFAULT;
 
-    _cairo_array_init (&surface->snapshots, sizeof (cairo_surface_t *));
+    cairo_list_init (&surface->snapshots);
     surface->snapshot_of = NULL;
 
     surface->has_font_options = FALSE;
@@ -630,7 +599,6 @@ cairo_surface_destroy (cairo_surface_t *surface)
 
     _cairo_user_data_array_fini (&surface->user_data);
     _cairo_user_data_array_fini (&surface->mime_data);
-    _cairo_array_fini (&surface->snapshots);
 
     free (surface);
 }
@@ -1532,11 +1500,7 @@ _cairo_recording_surface_clone_similar (cairo_surface_t  *surface,
 	    return status;
 	}
 
-	status = _cairo_surface_attach_snapshot (src, similar, NULL);
-	if (unlikely (status)) {
-	    cairo_surface_destroy (similar);
-	    return status;
-	}
+	_cairo_surface_attach_snapshot (src, similar, NULL);
 
 	src_x = src_y = 0;
     }
diff --git a/src/cairo-vg-surface.c b/src/cairo-vg-surface.c
index 169379a..1aa4fe2 100644
--- a/src/cairo-vg-surface.c
+++ b/src/cairo-vg-surface.c
@@ -982,12 +982,8 @@ _vg_setup_surface_source (cairo_vg_context_t *context,
 	return status;
     }
 
-    status = _cairo_surface_attach_snapshot (spat->surface, &clone->base,
-					     _vg_surface_remove_from_cache);
-    if (unlikely (status)) {
-	cairo_surface_destroy (&clone->base);
-	return status;
-    }
+    _cairo_surface_attach_snapshot (spat->surface, &clone->base,
+				    _vg_surface_remove_from_cache);
 
 DONE:
     cairo_surface_destroy (&context->source->base);
diff --git a/src/cairo-xcb-surface-core.c b/src/cairo-xcb-surface-core.c
index d609996..2a903a0 100644
--- a/src/cairo-xcb-surface-core.c
+++ b/src/cairo-xcb-surface-core.c
@@ -405,11 +405,7 @@ _cairo_xcb_surface_pixmap (cairo_xcb_surface_t *target,
     if (unlikely (pixmap->base.status))
 	return pixmap;
 
-    status = _cairo_surface_attach_snapshot (source, &pixmap->base, NULL);
-    if (unlikely (status)) {
-	cairo_surface_destroy (&pixmap->base);
-	return (cairo_xcb_pixmap_t *) _cairo_surface_create_in_error (status);
-    }
+    _cairo_surface_attach_snapshot (source, &pixmap->base, NULL);
 
     if (pattern->base.extend != CAIRO_EXTEND_NONE) {
 	if (extents->x < 0 || extents->y < 0 ||
diff --git a/src/cairo-xcb-surface-render.c b/src/cairo-xcb-surface-render.c
index 55a3ec8..5ea02e8 100644
--- a/src/cairo-xcb-surface-render.c
+++ b/src/cairo-xcb-surface-render.c
@@ -1367,13 +1367,9 @@ _cairo_xcb_surface_picture (cairo_xcb_surface_t *target,
 	return (cairo_xcb_picture_t *) _cairo_surface_create_in_error (status);
     }
 
-    status = _cairo_surface_attach_snapshot (source,
-					     &picture->base,
-					     cairo_surface_finish);
-    if (unlikely (status)) {
-	cairo_surface_destroy (&picture->base);
-	return (cairo_xcb_picture_t *) _cairo_surface_create_in_error (status);
-    }
+    _cairo_surface_attach_snapshot (source,
+				    &picture->base,
+				    cairo_surface_finish);
 
 setup_picture:
     filter = pattern->base.filter;
diff --git a/src/cairo-xcb-surface.c b/src/cairo-xcb-surface.c
index 9945adc..f21d580 100644
--- a/src/cairo-xcb-surface.c
+++ b/src/cairo-xcb-surface.c
@@ -553,11 +553,7 @@ _cairo_xcb_surface_acquire_source_image (void *abstract_surface,
     if (unlikely (status))
 	return status;
 
-    status = _cairo_surface_attach_snapshot (&surface->base, &image->base, NULL);
-    if (unlikely (status)) {
-	cairo_surface_destroy (&image->base);
-	return status;
-    }
+    _cairo_surface_attach_snapshot (&surface->base, &image->base, NULL);
 
 DONE:
     *image_out = image;
@@ -704,9 +700,9 @@ _cairo_xcb_surface_flush (void *abstract_surface)
 	}
 
 	if (status == CAIRO_STATUS_SUCCESS) {
-	    status = _cairo_surface_attach_snapshot (&surface->base,
-						     surface->fallback,
-						     cairo_surface_finish);
+	    _cairo_surface_attach_snapshot (&surface->base,
+					    surface->fallback,
+					    cairo_surface_finish);
 	}
     }
 
diff --git a/src/cairoint.h b/src/cairoint.h
index 5deb973..96fd714 100644
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -2033,7 +2033,7 @@ _cairo_surface_clone_similar (cairo_surface_t  *surface,
 cairo_private cairo_surface_t *
 _cairo_surface_snapshot (cairo_surface_t *surface);
 
-cairo_private cairo_status_t
+cairo_private void
 _cairo_surface_attach_snapshot (cairo_surface_t *surface,
 				cairo_surface_t *snapshot,
 				cairo_surface_func_t detach_func);
diff --git a/src/drm/cairo-drm-i915-shader.c b/src/drm/cairo-drm-i915-shader.c
index f216c29..4a7c6b9 100644
--- a/src/drm/cairo-drm-i915-shader.c
+++ b/src/drm/cairo-drm-i915-shader.c
@@ -1281,17 +1281,16 @@ i915_surface_clone (i915_device_t *device,
     if (unlikely (clone->intel.drm.base.status))
 	return clone->intel.drm.base.status;
 
-    status = _cairo_surface_attach_snapshot (&image->base,
-					     &clone->intel.drm.base,
-					     intel_surface_detach_snapshot);
-    if (likely (status == CAIRO_STATUS_SUCCESS))
-	status = intel_snapshot_cache_insert (&device->intel, &clone->intel);
-
+    status = intel_snapshot_cache_insert (&device->intel, &clone->intel);
     if (unlikely (status)) {
 	cairo_surface_destroy (&clone->intel.drm.base);
 	return status;
     }
 
+    _cairo_surface_attach_snapshot (&image->base,
+				    &clone->intel.drm.base,
+				    intel_surface_detach_snapshot);
+
     *clone_out = clone;
     return CAIRO_STATUS_SUCCESS;
 }
diff --git a/src/drm/cairo-drm-i965-shader.c b/src/drm/cairo-drm-i965-shader.c
index d76726c..377b478 100644
--- a/src/drm/cairo-drm-i965-shader.c
+++ b/src/drm/cairo-drm-i965-shader.c
@@ -282,17 +282,16 @@ i965_surface_clone (i965_device_t *device,
 	return status;
     }
 
-    status = _cairo_surface_attach_snapshot (&image->base,
-					     &clone->intel.drm.base,
-					     intel_surface_detach_snapshot);
-    if (likely (status == CAIRO_STATUS_SUCCESS))
-	status = intel_snapshot_cache_insert (&device->intel, &clone->intel);
-
+    status = intel_snapshot_cache_insert (&device->intel, &clone->intel);
     if (unlikely (status)) {
 	cairo_surface_destroy (&clone->intel.drm.base);
 	return status;
     }
 
+    _cairo_surface_attach_snapshot (&image->base,
+				    &clone->intel.drm.base,
+				    intel_surface_detach_snapshot);
+
     *clone_out = clone;
     return CAIRO_STATUS_SUCCESS;
 }
diff --git a/src/drm/cairo-drm-intel-surface.c b/src/drm/cairo-drm-intel-surface.c
index bfe181b..9b06c22 100644
--- a/src/drm/cairo-drm-intel-surface.c
+++ b/src/drm/cairo-drm-intel-surface.c
@@ -90,13 +90,7 @@ intel_surface_acquire_source_image (void *abstract_surface,
     if (unlikely (status))
 	return status;
 
-    status = _cairo_surface_attach_snapshot (&surface->drm.base,
-	                                     image,
-	                                     cairo_surface_destroy);
-    if (unlikely (status)) {
-	cairo_surface_destroy (image);
-	return status;
-    }
+     _cairo_surface_attach_snapshot (&surface->drm.base, image, cairo_surface_destroy);
 
 DONE:
     *image_out = (cairo_image_surface_t *) cairo_surface_reference (image);
diff --git a/src/drm/cairo-drm-radeon-surface.c b/src/drm/cairo-drm-radeon-surface.c
index 2a5fb10..df95d8c 100644
--- a/src/drm/cairo-drm-radeon-surface.c
+++ b/src/drm/cairo-drm-radeon-surface.c
@@ -106,13 +106,7 @@ radeon_surface_acquire_source_image (void *abstract_surface,
     if (unlikely (status))
 	return status;
 
-    status = _cairo_surface_attach_snapshot (&surface->base.base,
-	                                     image,
-	                                     cairo_surface_destroy);
-    if (unlikely (status)) {
-	cairo_surface_destroy (image);
-	return status;
-    }
+    _cairo_surface_attach_snapshot (&surface->base.base, image, cairo_surface_destroy);
 
 DONE:
     *image_out = (cairo_image_surface_t *) cairo_surface_reference (image);
commit 4cb733c28551f4a34cd4a225b8d797a55bf9b977
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Thu Apr 29 12:04:44 2010 +0100

    image: Simplify translation of pattern matrix for composite_trapezoids()

diff --git a/src/cairo-image-surface.c b/src/cairo-image-surface.c
index b2b69d3..68775d7 100644
--- a/src/cairo-image-surface.c
+++ b/src/cairo-image-surface.c
@@ -4202,7 +4202,6 @@ _cairo_image_surface_composite_trapezoids (cairo_operator_t	op,
     cairo_image_surface_t	*dst = abstract_dst;
     cairo_composite_rectangles_t extents;
     cairo_pattern_union_t        source_pattern;
-    cairo_matrix_t               translate;
     composite_traps_info_t	 info;
     cairo_status_t		 status;
 
@@ -4249,8 +4248,7 @@ _cairo_image_surface_composite_trapezoids (cairo_operator_t	op,
     }
 
     _cairo_pattern_init_static_copy (&source_pattern.base, pattern);
-    cairo_matrix_init_translate (&translate, src_x, src_y);
-    _cairo_pattern_transform (&source_pattern.base, &translate);
+    cairo_matrix_translate (&source_pattern.base.matrix, src_x, src_y);
 
     info.traps = traps;
     info.num_traps = num_traps;
commit 3940b0e91c274de0cf2fca4b34d4025b92965c19
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Thu Apr 29 17:29:13 2010 +0100

    subsurface: s/region/rectangle/
    
    After a renewed discussion, it was pointed out that the API in Cairo was
    not restrictive and by using doubles we would be consisted with the rest
    of the API. Thus prompting the name change to
    
      cairo_surface_create_for_rectangle()
    
    similar to cairo_rectangle().
    
    And document the public API.

diff --git a/src/cairo-surface-subsurface.c b/src/cairo-surface-subsurface.c
index 3d6d4a5..489573a 100644
--- a/src/cairo-surface-subsurface.c
+++ b/src/cairo-surface-subsurface.c
@@ -422,10 +422,34 @@ static const cairo_surface_backend_t _cairo_surface_subsurface_backend = {
     _cairo_surface_subsurface_snapshot,
 };
 
+/**
+ * cairo_surface_create_for_rectangle:
+ * @target: an existing surface for which the sub-surface will point to
+ * @x: the x-origin of the sub-surface from the top-left of the target surface (in device-space units)
+ * @y: the y-origin of the sub-surface from the top-left of the target surface (in device-space units)
+ * @width: width of the sub-surface (in device-space units)
+ * @height: height of the sub-surface (in device-space units)
+ *
+ * Create a new surface that is a rectangle within the target surface.
+ * All operations drawn to this surface are then clipped and translated
+ * onto the target surface. Nothing drawn via this sub-surface outside of
+ * its bounds is drawn onto the target surface, making this a useful method
+ * for passing constrained child surfaces to library routines that draw
+ * directly onto the parent surface, i.e. with no further backend allocations,
+ * double buffering or copies.
+ *
+ * Return value: a pointer to the newly allocated surface. The caller
+ * owns the surface and should call cairo_surface_destroy() when done
+ * with it.
+ *
+ * This function always returns a valid pointer, but it will return a
+ * pointer to a "nil" surface if @other is already in an error state
+ * or any other error occurs.
+ **/
 cairo_surface_t *
-cairo_surface_create_for_region (cairo_surface_t *target,
-				 int x, int y,
-				 int width, int height)
+cairo_surface_create_for_rectangle (cairo_surface_t *target,
+				    double x, double y,
+				    double width, double height)
 {
     cairo_surface_subsurface_t *surface;
     cairo_rectangle_int_t target_extents;
@@ -444,10 +468,11 @@ cairo_surface_create_for_region (cairo_surface_t *target,
 			 target->content);
     surface->base.type = target->type;
 
-    surface->extents.x = x;
-    surface->extents.y = y;
-    surface->extents.width = width;
-    surface->extents.height = height;
+    /* XXX forced integer alignment */
+    surface->extents.x = ceil (x);
+    surface->extents.y = ceil (y);
+    surface->extents.width = floor (x + width) - surface->extents.x;
+    surface->extents.height = floor (y + height) - surface->extents.y;
 
     if (_cairo_surface_get_extents (target, &target_extents))
         is_empty = _cairo_rectangle_intersect (&surface->extents, &target_extents);
diff --git a/src/cairo.h b/src/cairo.h
index 529a6f5..a2d37f9 100644
--- a/src/cairo.h
+++ b/src/cairo.h
@@ -2049,11 +2049,11 @@ cairo_surface_create_similar (cairo_surface_t  *other,
 			      int		height);
 
 cairo_public cairo_surface_t *
-cairo_surface_create_for_region (cairo_surface_t	*target,
-				 int			 x,
-				 int			 y,
-				 int			 width,
-				 int			 height);
+cairo_surface_create_for_rectangle (cairo_surface_t	*target,
+                                    double		 x,
+                                    double		 y,
+                                    double		 width,
+                                    double		 height);
 
 cairo_public cairo_surface_t *
 cairo_surface_reference (cairo_surface_t *surface);
diff --git a/test/subsurface-repeat.c b/test/subsurface-repeat.c
index 59c3c54..849c0df 100644
--- a/test/subsurface-repeat.c
+++ b/test/subsurface-repeat.c
@@ -35,8 +35,8 @@ draw (cairo_t *cr, int width, int height)
     cairo_paint (cr);
 
     /* fill the centre */
-    region = cairo_surface_create_for_region (cairo_get_target (cr),
-					      0, 0, 20, 20);
+    region = cairo_surface_create_for_rectangle (cairo_get_target (cr),
+                                                 0, 0, 20, 20);
     cr_region = cairo_create (region);
     cairo_surface_destroy (region);
 
diff --git a/test/subsurface-similar-repeat.c b/test/subsurface-similar-repeat.c
index ad63cc8..492bc77 100644
--- a/test/subsurface-similar-repeat.c
+++ b/test/subsurface-similar-repeat.c
@@ -46,7 +46,7 @@ draw (cairo_t *cr, int width, int height)
     cairo_destroy (cr_region);
 
     /* fill the centre */
-    region = cairo_surface_create_for_region (similar, 20, 20, 20, 20);
+    region = cairo_surface_create_for_rectangle (similar, 20, 20, 20, 20);
     cairo_surface_destroy (similar);
     cr_region = cairo_create (region);
     cairo_surface_destroy (region);
diff --git a/test/subsurface.c b/test/subsurface.c
index f325888..3ccc469 100644
--- a/test/subsurface.c
+++ b/test/subsurface.c
@@ -41,8 +41,8 @@ draw (cairo_t *cr, int width, int height)
 	cairo_text_extents_t extents;
 	char buf[2] = { text[i], '\0' };
 
-	region[i] = cairo_surface_create_for_region (cairo_get_target (cr),
-						     20 * i, 0, 20, 20);
+        region[i] = cairo_surface_create_for_rectangle (cairo_get_target (cr),
+                                                        20 * i, 0, 20, 20);
 
 	cr_region = cairo_create (region[i]);
 	cairo_surface_destroy (region[i]);
diff --git a/util/cairo-script/cairo-script-operators.c b/util/cairo-script/cairo-script-operators.c
index d1685e5..754a27e 100644
--- a/util/cairo-script/cairo-script-operators.c
+++ b/util/cairo-script/cairo-script-operators.c
@@ -5277,22 +5277,22 @@ static csi_status_t
 _subsurface (csi_t *ctx)
 {
     csi_object_t obj;
-    long x, y, width, height;
+    double x, y, width, height;
     cairo_surface_t *target;
     csi_status_t status;
 
     check (5);
 
-    status = _csi_ostack_get_integer (ctx, 0, &height);
+    status = _csi_ostack_get_number (ctx, 0, &height);
     if (_csi_unlikely (status))
 	return status;
-    status = _csi_ostack_get_integer (ctx, 1, &width);
+    status = _csi_ostack_get_number (ctx, 1, &width);
     if (_csi_unlikely (status))
 	return status;
-    status = _csi_ostack_get_integer (ctx, 2, &y);
+    status = _csi_ostack_get_number (ctx, 2, &y);
     if (_csi_unlikely (status))
 	return status;
-    status = _csi_ostack_get_integer (ctx, 3, &x);
+    status = _csi_ostack_get_number (ctx, 3, &x);
     if (_csi_unlikely (status))
 	return status;
     status = _csi_ostack_get_surface (ctx, 4, &target);
@@ -5300,7 +5300,7 @@ _subsurface (csi_t *ctx)
 	return status;
 
     obj.type = CSI_OBJECT_TYPE_SURFACE;
-    obj.datum.surface = cairo_surface_create_for_region (target, x, y, width, height);
+    obj.datum.surface = cairo_surface_create_for_rectangle (target, x, y, width, height);
     pop (5);
     return push (&obj);
 }
diff --git a/util/cairo-trace/trace.c b/util/cairo-trace/trace.c
index 01eadf4..5a0a44a 100644
--- a/util/cairo-trace/trace.c
+++ b/util/cairo-trace/trace.c
@@ -3495,16 +3495,16 @@ cairo_surface_create_similar (cairo_surface_t *other,
 }
 
 cairo_surface_t *
-cairo_surface_create_for_region (cairo_surface_t *target,
-				 int x, int y,
-				 int width, int height)
+cairo_surface_create_for_rectangle (cairo_surface_t *target,
+                                    double x, double y,
+                                    double width, double height)
 {
     cairo_surface_t *ret;
     long surface_id;
 
     _enter_trace ();
 
-    ret = DLCALL (cairo_surface_create_for_region, target, x, y, width, height);
+    ret = DLCALL (cairo_surface_create_for_rectangle, target, x, y, width, height);
     surface_id = _create_surface_id (ret);
 
     _emit_line_info ();
@@ -3518,7 +3518,7 @@ cairo_surface_create_for_region (cairo_surface_t *target,
 	    _trace_printf ("dup ");
 	else
 	    _trace_printf ("%d index ", current_stack_depth - obj->operand - 1);
-	_trace_printf ("%d %d %d %d subsurface %% s%ld\n",
+	_trace_printf ("%f %f %f %f subsurface %% s%ld\n",
 		       x, y, width, height,
 		       surface_id);
 


More information about the cairo-commit mailing list