[cairo-commit] 4 commits - src/cairo-analysis-surface.c src/cairo-composite-rectangles.c src/cairo-composite-rectangles-private.h src/cairo-directfb-surface.c src/cairo-error-private.h src/cairo-gl-surface.c src/cairo.h src/cairo-image-surface.c src/cairoint.h src/cairo-os2-surface.c src/cairo-paginated-surface.c src/cairo-pdf-surface.c src/cairo-ps-surface.c src/cairo-quartz-image-surface.c src/cairo-recording-surface.c src/cairo-rectangle.c src/cairo-script-surface.c src/cairo-surface.c src/cairo-surface-fallback.c src/cairo-surface-snapshot.c src/cairo-surface-subsurface.c src/cairo-surface-wrapper.c src/cairo-svg-surface.c src/cairo-tee-surface.c src/cairo-type3-glyph-surface.c src/cairo-vg-surface.c src/cairo-win32-printing-surface.c src/cairo-win32-surface.c src/cairo-xcb-private.h src/cairo-xcb-surface.c src/cairo-xcb-surface-core.c src/cairo-xcb-surface-render.c src/cairo-xlib-surface.c src/cairo-xml-surface.c src/test-fallback16-surface.c src/test-fallback-surface.c src/te st-null-surface.c src/test-paginated-surface.c src/test-wrapping-surface.c test/Makefile.sources test/map-all-to-image.ref.png test/map-bit-to-image.ref.png test/map-to-image.c test/map-to-image-fill.ref.png util/cairo-script util/cairo-trace

Chris Wilson ickle at kemper.freedesktop.org
Tue Jul 26 08:46:36 PDT 2011


 src/cairo-analysis-surface.c               |   12 
 src/cairo-composite-rectangles-private.h   |   24 -
 src/cairo-composite-rectangles.c           |   33 --
 src/cairo-directfb-surface.c               |    7 
 src/cairo-error-private.h                  |    9 
 src/cairo-gl-surface.c                     |    5 
 src/cairo-image-surface.c                  |   93 ++++--
 src/cairo-os2-surface.c                    |    6 
 src/cairo-paginated-surface.c              |    7 
 src/cairo-pdf-surface.c                    |   49 +--
 src/cairo-ps-surface.c                     |   36 +-
 src/cairo-quartz-image-surface.c           |    7 
 src/cairo-recording-surface.c              |   28 -
 src/cairo-rectangle.c                      |   10 
 src/cairo-script-surface.c                 |    7 
 src/cairo-surface-fallback.c               |   19 -
 src/cairo-surface-snapshot.c               |    5 
 src/cairo-surface-subsurface.c             |   80 +++++
 src/cairo-surface-wrapper.c                |    6 
 src/cairo-surface.c                        |  182 ++++++++++++
 src/cairo-svg-surface.c                    |    7 
 src/cairo-tee-surface.c                    |    7 
 src/cairo-type3-glyph-surface.c            |    7 
 src/cairo-vg-surface.c                     |    5 
 src/cairo-win32-printing-surface.c         |    7 
 src/cairo-win32-surface.c                  |   66 ++++
 src/cairo-xcb-private.h                    |   13 
 src/cairo-xcb-surface-core.c               |    2 
 src/cairo-xcb-surface-render.c             |   31 +-
 src/cairo-xcb-surface.c                    |  424 +++++++++++++----------------
 src/cairo-xlib-surface.c                   |  133 ++++-----
 src/cairo-xml-surface.c                    |    6 
 src/cairo.h                                |   93 +++---
 src/cairoint.h                             |   40 +-
 src/test-fallback-surface.c                |    6 
 src/test-fallback16-surface.c              |    6 
 src/test-null-surface.c                    |    6 
 src/test-paginated-surface.c               |    6 
 src/test-wrapping-surface.c                |    6 
 test/Makefile.sources                      |    1 
 test/map-all-to-image.ref.png              |binary
 test/map-bit-to-image.ref.png              |binary
 test/map-to-image-fill.ref.png             |binary
 test/map-to-image.c                        |  126 ++++++++
 util/cairo-script/cairo-script-operators.c |   96 ++++++
 util/cairo-trace/trace.c                   |   92 ++++++
 46 files changed, 1302 insertions(+), 509 deletions(-)

New commits:
commit b492b69d4f6e4fba41558b1ca066203c4e88c856
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Tue Jul 26 16:37:29 2011 +0100

    wrapper: translate the clip by the device transform
    
    A stepping stone, the translation was accidentally dropped when
    changing the clipping to be performed first.
    
    Fixes twin.
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/src/cairo-surface-wrapper.c b/src/cairo-surface-wrapper.c
index d2fead8..9ed5620 100644
--- a/src/cairo-surface-wrapper.c
+++ b/src/cairo-surface-wrapper.c
@@ -126,6 +126,12 @@ _cairo_surface_wrapper_get_clip (cairo_surface_wrapper_t *wrapper,
 	copy = _cairo_clip_translate (copy,
 				      -wrapper->extents.x,
 				      -wrapper->extents.y);
+    if (! _cairo_matrix_is_identity (&wrapper->target->device_transform)) {
+	/* XXX */
+	copy = _cairo_clip_translate (copy,
+				      wrapper->target->device_transform.x0,
+				      wrapper->target->device_transform.y0);
+    }
     if (wrapper->clip)
 	copy = _cairo_clip_intersect_clip (copy, wrapper->clip);
 
commit 91faf9c1cf79f44b48c0f14d2d551a68bf38b5a5
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Tue Jul 26 15:50:32 2011 +0100

    composite: Pass unbounded extents to initialisation
    
    For an unbounded surface we cannot assume (0, 0, surface_width,
    surface_height) as that is wrong and causes the operation to appear
    clipped.
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/src/cairo-composite-rectangles-private.h b/src/cairo-composite-rectangles-private.h
index 62244b2..777279b 100644
--- a/src/cairo-composite-rectangles-private.h
+++ b/src/cairo-composite-rectangles-private.h
@@ -62,22 +62,22 @@ struct _cairo_composite_rectangles {
 
 cairo_private cairo_int_status_t
 _cairo_composite_rectangles_init_for_paint (cairo_composite_rectangles_t *extents,
-					 int surface_width, int surface_height,
-					 cairo_operator_t	 op,
-					 const cairo_pattern_t	*source,
-					 const cairo_clip_t		*clip);
+					    const cairo_rectangle_int_t *unbounded,
+					    cairo_operator_t	 op,
+					    const cairo_pattern_t	*source,
+					    const cairo_clip_t		*clip);
 
 cairo_private cairo_int_status_t
 _cairo_composite_rectangles_init_for_mask (cairo_composite_rectangles_t *extents,
-					int surface_width, int surface_height,
-					cairo_operator_t	 op,
-					const cairo_pattern_t	*source,
-					const cairo_pattern_t	*mask,
-					const cairo_clip_t		*clip);
+					   const cairo_rectangle_int_t *unbounded,
+					   cairo_operator_t	 op,
+					   const cairo_pattern_t	*source,
+					   const cairo_pattern_t	*mask,
+					   const cairo_clip_t		*clip);
 
 cairo_private cairo_int_status_t
 _cairo_composite_rectangles_init_for_stroke (cairo_composite_rectangles_t *extents,
-					     int surface_width, int surface_height,
+					     const cairo_rectangle_int_t *unbounded,
 					     cairo_operator_t	 op,
 					     const cairo_pattern_t	*source,
 					     const cairo_path_fixed_t	*path,
@@ -87,7 +87,7 @@ _cairo_composite_rectangles_init_for_stroke (cairo_composite_rectangles_t *exten
 
 cairo_private cairo_int_status_t
 _cairo_composite_rectangles_init_for_fill (cairo_composite_rectangles_t *extents,
-					   int surface_width, int surface_height,
+					   const cairo_rectangle_int_t *unbounded,
 					   cairo_operator_t	 op,
 					   const cairo_pattern_t	*source,
 					   const cairo_path_fixed_t	*path,
@@ -95,7 +95,7 @@ _cairo_composite_rectangles_init_for_fill (cairo_composite_rectangles_t *extents
 
 cairo_private cairo_int_status_t
 _cairo_composite_rectangles_init_for_glyphs (cairo_composite_rectangles_t *extents,
-					     int surface_width, int surface_height,
+					     const cairo_rectangle_int_t *unbounded,
 					     cairo_operator_t		 op,
 					     const cairo_pattern_t	*source,
 					     cairo_scaled_font_t	*scaled_font,
diff --git a/src/cairo-composite-rectangles.c b/src/cairo-composite-rectangles.c
index 881d264..0598ba6 100644
--- a/src/cairo-composite-rectangles.c
+++ b/src/cairo-composite-rectangles.c
@@ -48,19 +48,17 @@ void _cairo_composite_rectangles_fini (cairo_composite_rectangles_t *extents)
 
 static inline cairo_bool_t
 _cairo_composite_rectangles_init (cairo_composite_rectangles_t *extents,
-				  int width, int height,
+				  const cairo_rectangle_int_t *unbounded,
 				  cairo_operator_t op,
 				  const cairo_pattern_t *source,
 				  const cairo_clip_t *clip)
 {
-    extents->unbounded.x = extents->unbounded.y = 0;
-    extents->unbounded.width  = width;
-    extents->unbounded.height = height;
     extents->clip = NULL;
 
     if (_cairo_clip_is_all_clipped (clip))
 	return FALSE;
 
+    extents->unbounded = *unbounded;
     if (clip != NULL) {
 	if (! _cairo_rectangle_intersect (&extents->unbounded,
 					  _cairo_clip_get_extents (clip)))
@@ -81,13 +79,12 @@ _cairo_composite_rectangles_init (cairo_composite_rectangles_t *extents,
 
 cairo_int_status_t
 _cairo_composite_rectangles_init_for_paint (cairo_composite_rectangles_t *extents,
-					    int surface_width, int surface_height,
+					    const cairo_rectangle_int_t *unbounded,
 					    cairo_operator_t		 op,
 					    const cairo_pattern_t	*source,
 					    const cairo_clip_t		*clip)
 {
-    if (! _cairo_composite_rectangles_init (extents,
-					    surface_width, surface_height,
+    if (! _cairo_composite_rectangles_init (extents, unbounded,
 					    op, source, clip))
     {
 	return CAIRO_INT_STATUS_NOTHING_TO_DO;
@@ -124,7 +121,7 @@ _cairo_composite_rectangles_intersect (cairo_composite_rectangles_t *extents,
 
 cairo_int_status_t
 _cairo_composite_rectangles_intersect_mask_extents (cairo_composite_rectangles_t *extents,
-					      const cairo_box_t *box)
+						    const cairo_box_t *box)
 {
     cairo_rectangle_int_t mask;
     cairo_int_status_t status;
@@ -154,14 +151,13 @@ _cairo_composite_rectangles_intersect_mask_extents (cairo_composite_rectangles_t
 
 cairo_int_status_t
 _cairo_composite_rectangles_init_for_mask (cairo_composite_rectangles_t *extents,
-					   int surface_width, int surface_height,
+					   const cairo_rectangle_int_t *unbounded,
 					   cairo_operator_t		 op,
 					   const cairo_pattern_t	*source,
 					   const cairo_pattern_t	*mask,
 					   const cairo_clip_t		*clip)
 {
-    if (! _cairo_composite_rectangles_init (extents,
-					    surface_width, surface_height,
+    if (! _cairo_composite_rectangles_init (extents, unbounded,
 					    op, source, clip))
     {
 	return CAIRO_INT_STATUS_NOTHING_TO_DO;
@@ -174,7 +170,7 @@ _cairo_composite_rectangles_init_for_mask (cairo_composite_rectangles_t *extents
 
 cairo_int_status_t
 _cairo_composite_rectangles_init_for_stroke (cairo_composite_rectangles_t *extents,
-					     int surface_width, int surface_height,
+					     const cairo_rectangle_int_t *unbounded,
 					     cairo_operator_t		 op,
 					     const cairo_pattern_t	*source,
 					     const cairo_path_fixed_t		*path,
@@ -182,8 +178,7 @@ _cairo_composite_rectangles_init_for_stroke (cairo_composite_rectangles_t *exten
 					     const cairo_matrix_t	*ctm,
 					     const cairo_clip_t		*clip)
 {
-    if (! _cairo_composite_rectangles_init (extents,
-					    surface_width, surface_height,
+    if (! _cairo_composite_rectangles_init (extents, unbounded,
 					    op, source, clip))
     {
 	return CAIRO_INT_STATUS_NOTHING_TO_DO;
@@ -196,14 +191,13 @@ _cairo_composite_rectangles_init_for_stroke (cairo_composite_rectangles_t *exten
 
 cairo_int_status_t
 _cairo_composite_rectangles_init_for_fill (cairo_composite_rectangles_t *extents,
-					   int surface_width, int surface_height,
+					   const cairo_rectangle_int_t *unbounded,
 					   cairo_operator_t		 op,
 					   const cairo_pattern_t	*source,
 					   const cairo_path_fixed_t		*path,
 					   const cairo_clip_t		*clip)
 {
-    if (! _cairo_composite_rectangles_init (extents,
-					    surface_width, surface_height,
+    if (! _cairo_composite_rectangles_init (extents, unbounded,
 					    op, source, clip))
     {
 	return CAIRO_INT_STATUS_NOTHING_TO_DO;
@@ -216,7 +210,7 @@ _cairo_composite_rectangles_init_for_fill (cairo_composite_rectangles_t *extents
 
 cairo_int_status_t
 _cairo_composite_rectangles_init_for_glyphs (cairo_composite_rectangles_t *extents,
-					     int surface_width, int surface_height,
+					     const cairo_rectangle_int_t *unbounded,
 					     cairo_operator_t		 op,
 					     const cairo_pattern_t	*source,
 					     cairo_scaled_font_t	*scaled_font,
@@ -227,8 +221,7 @@ _cairo_composite_rectangles_init_for_glyphs (cairo_composite_rectangles_t *exten
 {
     cairo_status_t status;
 
-    if (! _cairo_composite_rectangles_init (extents,
-					    surface_width, surface_height,
+    if (! _cairo_composite_rectangles_init (extents, unbounded,
 					    op, source, clip))
     {
 	return CAIRO_INT_STATUS_NOTHING_TO_DO;
diff --git a/src/cairo-image-surface.c b/src/cairo-image-surface.c
index 369f172..3eb4e05 100644
--- a/src/cairo-image-surface.c
+++ b/src/cairo-image-surface.c
@@ -3291,6 +3291,19 @@ _clip_and_composite_trapezoids (cairo_image_surface_t *dst,
 }
 
 /* high level image interface */
+static cairo_bool_t
+_cairo_image_surface_get_extents (void			  *abstract_surface,
+				  cairo_rectangle_int_t   *rectangle)
+{
+    cairo_image_surface_t *surface = abstract_surface;
+
+    rectangle->x = 0;
+    rectangle->y = 0;
+    rectangle->width  = surface->width;
+    rectangle->height = surface->height;
+
+    return TRUE;
+}
 
 static cairo_int_status_t
 _cairo_image_surface_paint (void			*abstract_surface,
@@ -3299,13 +3312,13 @@ _cairo_image_surface_paint (void			*abstract_surface,
 			    const cairo_clip_t		*clip)
 {
     cairo_image_surface_t *surface = abstract_surface;
+    cairo_rectangle_int_t unbounded;
     cairo_composite_rectangles_t extents;
     cairo_status_t status;
     cairo_boxes_t boxes;
 
-    status = _cairo_composite_rectangles_init_for_paint (&extents,
-							 surface->width,
-							 surface->height,
+    _cairo_image_surface_get_extents (surface, &unbounded);
+    status = _cairo_composite_rectangles_init_for_paint (&extents, &unbounded,
 							 op, source,
 							 clip);
     if (unlikely (status))
@@ -3537,10 +3550,11 @@ _cairo_image_surface_mask (void				*abstract_surface,
 {
     cairo_image_surface_t *surface = abstract_surface;
     cairo_composite_rectangles_t extents;
+    cairo_rectangle_int_t unbounded;
     cairo_status_t status;
 
-    status = _cairo_composite_rectangles_init_for_mask (&extents,
-							surface->width, surface->height,
+    _cairo_image_surface_get_extents (surface, &unbounded);
+    status = _cairo_composite_rectangles_init_for_mask (&extents, &unbounded,
 							op, source, mask, clip);
     if (unlikely (status))
 	return status;
@@ -3770,11 +3784,11 @@ _cairo_image_surface_stroke (void			*abstract_surface,
 {
     cairo_image_surface_t *surface = abstract_surface;
     cairo_composite_rectangles_t extents;
+    cairo_rectangle_int_t unbounded;
     cairo_int_status_t status;
 
-    status = _cairo_composite_rectangles_init_for_stroke (&extents,
-							  surface->width,
-							  surface->height,
+    _cairo_image_surface_get_extents (surface, &unbounded);
+    status = _cairo_composite_rectangles_init_for_stroke (&extents, &unbounded,
 							  op, source,
 							  path, style, ctm,
 							  clip);
@@ -3833,11 +3847,11 @@ _cairo_image_surface_fill (void				*abstract_surface,
 {
     cairo_image_surface_t *surface = abstract_surface;
     cairo_composite_rectangles_t extents;
+    cairo_rectangle_int_t unbounded;
     cairo_status_t status;
 
-    status = _cairo_composite_rectangles_init_for_fill (&extents,
-							surface->width,
-							surface->height,
+    _cairo_image_surface_get_extents (surface, &unbounded);
+    status = _cairo_composite_rectangles_init_for_fill (&extents, &unbounded,
 							op, source, path,
 							clip);
     if (unlikely (status))
@@ -4131,14 +4145,14 @@ _cairo_image_surface_glyphs (void			*abstract_surface,
 {
     cairo_image_surface_t *surface = abstract_surface;
     cairo_composite_rectangles_t extents;
+    cairo_rectangle_int_t unbounded;
     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,
-							  surface->height,
+    _cairo_image_surface_get_extents (surface, &unbounded);
+    status = _cairo_composite_rectangles_init_for_glyphs (&extents, &unbounded,
 							  op, source,
 							  scaled_font,
 							  glyphs, num_glyphs,
@@ -4171,20 +4185,6 @@ _cairo_image_surface_glyphs (void			*abstract_surface,
     return status;
 }
 
-static cairo_bool_t
-_cairo_image_surface_get_extents (void			  *abstract_surface,
-				  cairo_rectangle_int_t   *rectangle)
-{
-    cairo_image_surface_t *surface = abstract_surface;
-
-    rectangle->x = 0;
-    rectangle->y = 0;
-    rectangle->width  = surface->width;
-    rectangle->height = surface->height;
-
-    return TRUE;
-}
-
 static void
 _cairo_image_surface_get_font_options (void                  *abstract_surface,
 				       cairo_font_options_t  *options)
diff --git a/src/cairo-pdf-surface.c b/src/cairo-pdf-surface.c
index e6535cb..2411f6d 100644
--- a/src/cairo-pdf-surface.c
+++ b/src/cairo-pdf-surface.c
@@ -127,6 +127,10 @@
  * PDF files and is a multi-page vector surface backend.
  */
 
+static cairo_bool_t
+_cairo_pdf_surface_get_extents (void		        *abstract_surface,
+				cairo_rectangle_int_t   *rectangle);
+
 /**
  * CAIRO_HAS_PDF_SURFACE:
  *
@@ -5750,10 +5754,11 @@ _cairo_pdf_surface_paint (void			*abstract_surface,
     cairo_pdf_smask_group_t *group;
     cairo_pdf_resource_t pattern_res, gstate_res;
     cairo_composite_rectangles_t extents;
+    cairo_rectangle_int_t unbounded;
     cairo_int_status_t status;
 
-    status = _cairo_composite_rectangles_init_for_paint (&extents,
-							 surface->width, surface->height,
+    _cairo_pdf_surface_get_extents (surface, &unbounded);
+    status = _cairo_composite_rectangles_init_for_paint (&extents, &unbounded,
 							 op, source, clip);
     if (unlikely (status)) {
 	if (status == CAIRO_INT_STATUS_NOTHING_TO_DO)
@@ -5866,10 +5871,11 @@ _cairo_pdf_surface_mask (void			*abstract_surface,
     cairo_pdf_surface_t *surface = abstract_surface;
     cairo_pdf_smask_group_t *group;
     cairo_composite_rectangles_t extents;
+    cairo_rectangle_int_t unbounded;
     cairo_int_status_t status;
 
-    status = _cairo_composite_rectangles_init_for_mask (&extents,
-							surface->width, surface->height,
+    _cairo_pdf_surface_get_extents (surface, &unbounded);
+    status = _cairo_composite_rectangles_init_for_mask (&extents, &unbounded,
 							op, source, mask, clip);
     if (unlikely (status)) {
 	if (status == CAIRO_INT_STATUS_NOTHING_TO_DO)
@@ -5980,11 +5986,11 @@ _cairo_pdf_surface_stroke (void			*abstract_surface,
     cairo_pdf_smask_group_t *group;
     cairo_pdf_resource_t pattern_res, gstate_res;
     cairo_composite_rectangles_t extents;
+    cairo_rectangle_int_t unbounded;
     cairo_int_status_t status;
 
-    status = _cairo_composite_rectangles_init_for_stroke (&extents,
-							  surface->width,
-							  surface->height,
+    _cairo_pdf_surface_get_extents (surface, &unbounded);
+    status = _cairo_composite_rectangles_init_for_stroke (&extents, &unbounded,
 							  op, source,
 							  path, style, ctm,
 							  clip);
@@ -6110,10 +6116,10 @@ _cairo_pdf_surface_fill (void			*abstract_surface,
     cairo_pdf_smask_group_t *group;
     cairo_pdf_resource_t pattern_res, gstate_res;
     cairo_composite_rectangles_t extents;
+    cairo_rectangle_int_t unbounded;
 
-    status = _cairo_composite_rectangles_init_for_fill (&extents,
-							surface->width,
-							surface->height,
+    _cairo_pdf_surface_get_extents (surface, &unbounded);
+    status = _cairo_composite_rectangles_init_for_fill (&extents, &unbounded,
 							op, source, path,
 							clip);
     if (unlikely (status)) {
@@ -6267,6 +6273,7 @@ _cairo_pdf_surface_fill_stroke (void			*abstract_surface,
     cairo_int_status_t status;
     cairo_pdf_resource_t fill_pattern_res, stroke_pattern_res, gstate_res;
     cairo_composite_rectangles_t extents;
+    cairo_rectangle_int_t unbounded;
 
     /* During analysis we return unsupported and let the _fill and
      * _stroke functions that are on the fallback path do the analysis
@@ -6298,9 +6305,8 @@ _cairo_pdf_surface_fill_stroke (void			*abstract_surface,
     if (unlikely (status))
 	return status;
 
-    status = _cairo_composite_rectangles_init_for_fill (&extents,
-							surface->width,
-							surface->height,
+    _cairo_pdf_surface_get_extents (surface, &unbounded);
+    status = _cairo_composite_rectangles_init_for_fill (&extents, &unbounded,
 							fill_op, fill_source, path,
 							clip);
     if (unlikely (status)) {
@@ -6329,9 +6335,7 @@ _cairo_pdf_surface_fill_stroke (void			*abstract_surface,
 
     assert (gstate_res.id == 0);
 
-    status = _cairo_composite_rectangles_init_for_stroke (&extents,
-							  surface->width,
-							  surface->height,
+    status = _cairo_composite_rectangles_init_for_stroke (&extents, &unbounded,
 							  stroke_op, stroke_source,
 							  path, stroke_style, stroke_ctm,
 							  clip);
@@ -6416,12 +6420,12 @@ _cairo_pdf_surface_show_text_glyphs (void			*abstract_surface,
     cairo_pdf_smask_group_t *group;
     cairo_pdf_resource_t pattern_res, gstate_res;
     cairo_composite_rectangles_t extents;
+    cairo_rectangle_int_t unbounded;
     cairo_bool_t overlap;
     cairo_int_status_t status;
 
-    status = _cairo_composite_rectangles_init_for_glyphs (&extents,
-							  surface->width,
-							  surface->height,
+    _cairo_pdf_surface_get_extents (surface, &unbounded);
+    status = _cairo_composite_rectangles_init_for_glyphs (&extents, &unbounded,
 							  op, source,
 							  scaled_font,
 							  glyphs, num_glyphs,
diff --git a/src/cairo-ps-surface.c b/src/cairo-ps-surface.c
index 1e7ddeb..4b8ce80 100644
--- a/src/cairo-ps-surface.c
+++ b/src/cairo-ps-surface.c
@@ -110,6 +110,10 @@
 static const cairo_surface_backend_t cairo_ps_surface_backend;
 static const cairo_paginated_surface_backend_t cairo_ps_surface_paginated_backend;
 
+static cairo_bool_t
+_cairo_ps_surface_get_extents (void		       *abstract_surface,
+			       cairo_rectangle_int_t   *rectangle);
+
 static void
 _cairo_ps_surface_release_surface (cairo_ps_surface_t      *surface,
 				   cairo_surface_pattern_t *pattern);
@@ -3556,15 +3560,16 @@ static cairo_int_status_t
 _cairo_ps_surface_paint (void			*abstract_surface,
 			 cairo_operator_t	 op,
 			 const cairo_pattern_t	*source,
-			 const cairo_clip_t		*clip)
+			 const cairo_clip_t	*clip)
 {
     cairo_ps_surface_t *surface = abstract_surface;
     cairo_output_stream_t *stream = surface->stream;
     cairo_composite_rectangles_t extents;
+    cairo_rectangle_int_t unbounded;
     cairo_status_t status;
 
-    status = _cairo_composite_rectangles_init_for_paint (&extents,
-							 surface->width, surface->height,
+    _cairo_ps_surface_get_extents (surface, &unbounded);
+    status = _cairo_composite_rectangles_init_for_paint (&extents, &unbounded,
 							 op, source, clip);
     if (unlikely (status))
 	return status;
@@ -3625,11 +3630,11 @@ _cairo_ps_surface_stroke (void			*abstract_surface,
 {
     cairo_ps_surface_t *surface = abstract_surface;
     cairo_composite_rectangles_t extents;
+    cairo_rectangle_int_t unbounded;
     cairo_int_status_t status;
 
-    status = _cairo_composite_rectangles_init_for_stroke (&extents,
-							  surface->width,
-							  surface->height,
+    _cairo_ps_surface_get_extents (surface, &unbounded);
+    status = _cairo_composite_rectangles_init_for_stroke (&extents, &unbounded,
 							  op, source,
 							  path, style, ctm,
 							  clip);
@@ -3687,11 +3692,11 @@ _cairo_ps_surface_fill (void		*abstract_surface,
 {
     cairo_ps_surface_t *surface = abstract_surface;
     cairo_composite_rectangles_t extents;
+    cairo_rectangle_int_t unbounded;
     cairo_int_status_t status;
 
-    status = _cairo_composite_rectangles_init_for_fill (&extents,
-							surface->width,
-							surface->height,
+    _cairo_ps_surface_get_extents (surface, &unbounded);
+    status = _cairo_composite_rectangles_init_for_fill (&extents, &unbounded,
 							op, source, path,
 							clip);
     if (unlikely (status))
@@ -3771,12 +3776,12 @@ _cairo_ps_surface_show_glyphs (void		     *abstract_surface,
 {
     cairo_ps_surface_t *surface = abstract_surface;
     cairo_composite_rectangles_t extents;
+    cairo_rectangle_int_t unbounded;
     cairo_bool_t overlap;
     cairo_status_t status;
 
-    status = _cairo_composite_rectangles_init_for_glyphs (&extents,
-							  surface->width,
-							  surface->height,
+    _cairo_ps_surface_get_extents (surface, &unbounded);
+    status = _cairo_composite_rectangles_init_for_glyphs (&extents, &unbounded,
 							  op, source,
 							  scaled_font,
 							  glyphs, num_glyphs,
diff --git a/src/cairo-recording-surface.c b/src/cairo-recording-surface.c
index 1ce3e22..3de8fe1 100644
--- a/src/cairo-recording-surface.c
+++ b/src/cairo-recording-surface.c
@@ -359,9 +359,7 @@ _cairo_recording_surface_paint (void			  *abstract_surface,
     const cairo_rectangle_int_t *extents;
 
     extents = _cairo_recording_surface_extents (surface);
-    status = _cairo_composite_rectangles_init_for_paint (&composite,
-							 extents->width,
-							 extents->height,
+    status = _cairo_composite_rectangles_init_for_paint (&composite, extents,
 							 op, source,
 							 clip);
     if (unlikely (status))
@@ -420,9 +418,7 @@ _cairo_recording_surface_mask (void			*abstract_surface,
     const cairo_rectangle_int_t *extents;
 
     extents = _cairo_recording_surface_extents (surface);
-    status = _cairo_composite_rectangles_init_for_mask (&composite,
-							extents->width,
-							extents->height,
+    status = _cairo_composite_rectangles_init_for_mask (&composite, extents,
 							op, source, mask,
 							clip);
     if (unlikely (status))
@@ -486,9 +482,7 @@ _cairo_recording_surface_stroke (void			*abstract_surface,
     const cairo_rectangle_int_t *extents;
 
     extents = _cairo_recording_surface_extents (surface);
-    status = _cairo_composite_rectangles_init_for_stroke (&composite,
-							  extents->width,
-							  extents->height,
+    status = _cairo_composite_rectangles_init_for_stroke (&composite, extents,
 							  op, source,
 							  path, style, ctm,
 							  clip);
@@ -562,9 +556,7 @@ _cairo_recording_surface_fill (void			*abstract_surface,
     const cairo_rectangle_int_t *extents;
 
     extents = _cairo_recording_surface_extents (surface);
-    status = _cairo_composite_rectangles_init_for_fill (&composite,
-							extents->width,
-							extents->height,
+    status = _cairo_composite_rectangles_init_for_fill (&composite, extents,
 							op, source, path,
 							clip);
     if (unlikely (status))
@@ -640,9 +632,7 @@ _cairo_recording_surface_show_text_glyphs (void				*abstract_surface,
     const cairo_rectangle_int_t *extents;
 
     extents = _cairo_recording_surface_extents (surface);
-    status = _cairo_composite_rectangles_init_for_glyphs (&composite,
-							  extents->width,
-							  extents->height,
+    status = _cairo_composite_rectangles_init_for_glyphs (&composite, extents,
 							  op, source,
 							  scaled_font,
 							  glyphs, num_glyphs,
@@ -961,7 +951,6 @@ _cairo_recording_surface_replay_internal (cairo_recording_surface_t	*surface,
 	return CAIRO_STATUS_SUCCESS;
 
     assert (_cairo_surface_is_recording (&surface->base));
-    surface = (cairo_recording_surface_t *) surface;
 
     _cairo_surface_wrapper_init (&wrapper, target);
     if (surface_extents)
diff --git a/src/cairo-surface-fallback.c b/src/cairo-surface-fallback.c
index 21966fe..bd03274 100644
--- a/src/cairo-surface-fallback.c
+++ b/src/cairo-surface-fallback.c
@@ -829,9 +829,7 @@ _cairo_surface_fallback_paint (cairo_surface_t		*surface,
     if (!_cairo_surface_get_extents (surface, &rect))
         ASSERT_NOT_REACHED;
 
-    status = _cairo_composite_rectangles_init_for_paint (&extents,
-							 rect.width,
-							 rect.height,
+    status = _cairo_composite_rectangles_init_for_paint (&extents, &rect,
 							 op, source,
 							 clip);
     if (unlikely (status))
@@ -918,8 +916,7 @@ _cairo_surface_fallback_mask (cairo_surface_t		*surface,
     if (!_cairo_surface_get_extents (surface, &rect))
         ASSERT_NOT_REACHED;
 
-    status = _cairo_composite_rectangles_init_for_mask (&extents,
-							rect.width, rect.height,
+    status = _cairo_composite_rectangles_init_for_mask (&extents, &rect,
 							op, source, mask, clip);
     if (unlikely (status))
 	return status;
@@ -956,9 +953,7 @@ _cairo_surface_fallback_stroke (cairo_surface_t		*surface,
     if (!_cairo_surface_get_extents (surface, &rect))
         ASSERT_NOT_REACHED;
 
-    status = _cairo_composite_rectangles_init_for_stroke (&extents,
-							  rect.width,
-							  rect.height,
+    status = _cairo_composite_rectangles_init_for_stroke (&extents, &rect,
 							  op, source,
 							  path, stroke_style, ctm,
 							  clip);
@@ -1039,9 +1034,7 @@ _cairo_surface_fallback_fill (cairo_surface_t		*surface,
     if (!_cairo_surface_get_extents (surface, &rect))
         ASSERT_NOT_REACHED;
 
-    status = _cairo_composite_rectangles_init_for_fill (&extents,
-							rect.width,
-							rect.height,
+    status = _cairo_composite_rectangles_init_for_fill (&extents, &rect,
 							op, source, path,
 							clip);
     if (unlikely (status))
@@ -1187,9 +1180,7 @@ _cairo_surface_fallback_show_glyphs (cairo_surface_t		*surface,
     if (!_cairo_surface_get_extents (surface, &rect))
         ASSERT_NOT_REACHED;
 
-    status = _cairo_composite_rectangles_init_for_glyphs (&extents,
-							  rect.width,
-							  rect.height,
+    status = _cairo_composite_rectangles_init_for_glyphs (&extents, &rect,
 							  op, source,
 							  scaled_font,
 							  glyphs, num_glyphs,
diff --git a/src/cairo-xcb-private.h b/src/cairo-xcb-private.h
index 5b3e2b4..d9f443c 100644
--- a/src/cairo-xcb-private.h
+++ b/src/cairo-xcb-private.h
@@ -373,6 +373,10 @@ _cairo_xcb_surface_create_internal (cairo_xcb_screen_t		*screen,
 				    int				 width,
 				    int				 height);
 
+cairo_private cairo_bool_t
+_cairo_xcb_surface_get_extents (void *abstract_surface,
+				cairo_rectangle_int_t *extents);
+
 cairo_private cairo_int_status_t
 _cairo_xcb_surface_cairo_paint (cairo_xcb_surface_t	*surface,
 				cairo_operator_t	 op,
diff --git a/src/cairo-xcb-surface-render.c b/src/cairo-xcb-surface-render.c
index d8c1172..d7c677f 100644
--- a/src/cairo-xcb-surface-render.c
+++ b/src/cairo-xcb-surface-render.c
@@ -3371,6 +3371,7 @@ _cairo_xcb_surface_render_paint (cairo_xcb_surface_t	*surface,
 				 const cairo_clip_t	*clip)
 {
     cairo_composite_rectangles_t extents;
+    cairo_rectangle_int_t unbounded;
     cairo_boxes_t boxes;
     cairo_status_t status;
 
@@ -3401,9 +3402,8 @@ _cairo_xcb_surface_render_paint (cairo_xcb_surface_t	*surface,
 	return CAIRO_STATUS_SUCCESS;
     }
 
-    status = _cairo_composite_rectangles_init_for_paint (&extents,
-							 surface->width,
-							 surface->height,
+    _cairo_xcb_surface_get_extents (surface, &unbounded);
+    status = _cairo_composite_rectangles_init_for_paint (&extents, &unbounded,
 							 op, source,
 							 clip);
     if (unlikely (status))
@@ -3428,6 +3428,7 @@ _cairo_xcb_surface_render_mask (cairo_xcb_surface_t	*surface,
 				const cairo_clip_t	*clip)
 {
     cairo_composite_rectangles_t extents;
+    cairo_rectangle_int_t unbounded;
     cairo_status_t status;
 
     if (unlikely (! _operator_is_supported (surface->connection->flags, op)))
@@ -3436,8 +3437,8 @@ _cairo_xcb_surface_render_mask (cairo_xcb_surface_t	*surface,
     if ((surface->connection->flags & CAIRO_XCB_RENDER_HAS_COMPOSITE) == 0)
 	return CAIRO_INT_STATUS_UNSUPPORTED;
 
-    status = _cairo_composite_rectangles_init_for_mask (&extents,
-							surface->width, surface->height,
+    _cairo_xcb_surface_get_extents (surface, &unbounded);
+    status = _cairo_composite_rectangles_init_for_mask (&extents, &unbounded,
 							op, source, mask, clip);
     if (unlikely (status))
 	return status;
@@ -3573,6 +3574,7 @@ _cairo_xcb_surface_render_stroke (cairo_xcb_surface_t	*surface,
 				  const cairo_clip_t		*clip)
 {
     cairo_composite_rectangles_t extents;
+    cairo_rectangle_int_t unbounded;
     cairo_int_status_t status;
 
     if (unlikely (! _operator_is_supported (surface->connection->flags, op)))
@@ -3584,9 +3586,8 @@ _cairo_xcb_surface_render_stroke (cairo_xcb_surface_t	*surface,
 	return CAIRO_INT_STATUS_UNSUPPORTED;
     }
 
-    status = _cairo_composite_rectangles_init_for_stroke (&extents,
-							  surface->width,
-							  surface->height,
+    _cairo_xcb_surface_get_extents (surface, &unbounded);
+    status = _cairo_composite_rectangles_init_for_stroke (&extents, &unbounded,
 							  op, source,
 							  path, style, ctm,
 							  clip);
@@ -3724,6 +3725,7 @@ _cairo_xcb_surface_render_fill (cairo_xcb_surface_t	*surface,
 			       const cairo_clip_t	*clip)
 {
     cairo_composite_rectangles_t extents;
+    cairo_rectangle_int_t unbounded;
     cairo_int_status_t status;
 
     if (unlikely (! _operator_is_supported (surface->connection->flags, op)))
@@ -3735,9 +3737,8 @@ _cairo_xcb_surface_render_fill (cairo_xcb_surface_t	*surface,
 	return CAIRO_INT_STATUS_UNSUPPORTED;
     }
 
-    status = _cairo_composite_rectangles_init_for_fill (&extents,
-							surface->width,
-							surface->height,
+    _cairo_xcb_surface_get_extents (surface, &unbounded);
+    status = _cairo_composite_rectangles_init_for_fill (&extents, &unbounded,
 							op, source, path,
 							clip);
     if (unlikely (status))
@@ -4710,6 +4711,7 @@ _cairo_xcb_surface_render_glyphs (cairo_xcb_surface_t	*surface,
 				  const cairo_clip_t	*clip)
 {
     cairo_composite_rectangles_t extents;
+    cairo_rectangle_int_t unbounded;
     cairo_int_status_t status;
     cairo_bool_t overlap;
 
@@ -4719,9 +4721,8 @@ _cairo_xcb_surface_render_glyphs (cairo_xcb_surface_t	*surface,
     if ((surface->connection->flags & (CAIRO_XCB_RENDER_HAS_COMPOSITE_GLYPHS | CAIRO_XCB_RENDER_HAS_COMPOSITE)) == 0)
 	return CAIRO_INT_STATUS_UNSUPPORTED;
 
-    status = _cairo_composite_rectangles_init_for_glyphs (&extents,
-							  surface->width,
-							  surface->height,
+    _cairo_xcb_surface_get_extents (surface, &unbounded);
+    status = _cairo_composite_rectangles_init_for_glyphs (&extents, &unbounded,
 							  op, source,
 							  scaled_font,
 							  glyphs, num_glyphs,
diff --git a/src/cairo-xcb-surface.c b/src/cairo-xcb-surface.c
index 827041e..fb42306 100644
--- a/src/cairo-xcb-surface.c
+++ b/src/cairo-xcb-surface.c
@@ -511,7 +511,7 @@ _cairo_xcb_surface_release_source_image (void *abstract_surface,
     cairo_surface_destroy (&image->base);
 }
 
-static cairo_bool_t
+cairo_bool_t
 _cairo_xcb_surface_get_extents (void *abstract_surface,
 				cairo_rectangle_int_t *extents)
 {
commit a69335a84eb9225b477cc8c753470eb3805b852c
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Fri Jul 22 00:36:03 2011 +0100

    API: map-to-image and create-similar-image
    
    A common requirement is the fast upload of pixel data. In order to
    allocate the most appropriate image buffer, we need knowledge of the
    destination. The most obvious example is that we could use a
    shared-memory region for the image to avoid the transfer cost of
    uploading the pixels to the X server. Similarly, gl, win32, quartz...
    
    The other side of the equation is that for manual modification of a
    remote surface, it would be more efficient if we can create a similar
    image to reduce the transfer costs. This strategy is already followed
    for the destination fallbacks and this merely exposes the same
    capability for the application fallbacks.
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/src/cairo-analysis-surface.c b/src/cairo-analysis-surface.c
index 3cb4311..459bc81 100644
--- a/src/cairo-analysis-surface.c
+++ b/src/cairo-analysis-surface.c
@@ -643,10 +643,14 @@ _cairo_analysis_surface_show_text_glyphs (void			    *abstract_surface,
 
 static const cairo_surface_backend_t cairo_analysis_surface_backend = {
     CAIRO_INTERNAL_SURFACE_TYPE_ANALYSIS,
+
+    _cairo_analysis_surface_finish,
     NULL,
 
     NULL, /* create_similar */
-    _cairo_analysis_surface_finish,
+    NULL, /* create_similar_image */
+    NULL, /* map_to_image */
+    NULL, /* unmap */
     NULL, /* acquire_source_image */
     NULL, /* release_source_image */
     NULL, /* acquire_dest_image */
@@ -842,10 +846,14 @@ typedef cairo_int_status_t
 
 static const cairo_surface_backend_t cairo_null_surface_backend = {
     CAIRO_INTERNAL_SURFACE_TYPE_NULL,
+    NULL, /* finish */
+
     _cairo_default_context_create, /* XXX */
 
     NULL, /* create_similar */
-    NULL, /* finish */
+    NULL, /* create similar image */
+    NULL, /* map to image */
+    NULL, /* unmap image*/
     NULL, /* acquire_source_image */
     NULL, /* release_source_image */
     NULL, /* acquire_dest_image */
diff --git a/src/cairo-directfb-surface.c b/src/cairo-directfb-surface.c
index 6117907..4f9bbc4 100644
--- a/src/cairo-directfb-surface.c
+++ b/src/cairo-directfb-surface.c
@@ -1829,10 +1829,15 @@ _cairo_directfb_surface_is_similar (void *surface_a, void *surface_b)
 static cairo_surface_backend_t
 _cairo_directfb_surface_backend = {
          CAIRO_SURFACE_TYPE_DIRECTFB, /*type*/
+        _cairo_directfb_surface_finish, /*finish*/
+
 	 _cairo_default_context_create,
 
         _cairo_directfb_surface_create_similar,/*create_similar*/
-        _cairo_directfb_surface_finish, /*finish*/
+	NULL, /* create similar image */
+	NULL, /* map to image */
+	NULL, /* unmap image */
+
         _cairo_directfb_surface_acquire_source_image,/*acquire_source_image*/
         _cairo_directfb_surface_release_source_image,/*release_source_image*/
         _cairo_directfb_surface_acquire_dest_image,/*acquire_dest_image*/
diff --git a/src/cairo-error-private.h b/src/cairo-error-private.h
index 953e8af..5f517d4 100644
--- a/src/cairo-error-private.h
+++ b/src/cairo-error-private.h
@@ -41,6 +41,8 @@
 #include "cairo.h"
 #include "cairo-compiler-private.h"
 
+#include <assert.h>
+
 CAIRO_BEGIN_DECLS
 
 enum _cairo_int_status {
@@ -100,6 +102,13 @@ enum _cairo_int_status {
 #define _cairo_int_status_is_error(status) \
     (status != CAIRO_INT_STATUS_SUCCESS && status <= CAIRO_INT_STATUS_LAST_STATUS)
 
+static inline cairo_status_t
+_cairo_public_status (cairo_int_status_t status)
+{
+    assert (status <= CAIRO_INT_STATUS_LAST_STATUS);
+    return status;
+}
+
 cairo_private cairo_status_t
 _cairo_error (cairo_status_t status);
 
diff --git a/src/cairo-gl-surface.c b/src/cairo-gl-surface.c
index 95707dd..7d27ecd 100644
--- a/src/cairo-gl-surface.c
+++ b/src/cairo-gl-surface.c
@@ -1764,10 +1764,13 @@ _cairo_gl_surface_fill (void			*abstract_surface,
 
 const cairo_surface_backend_t _cairo_gl_surface_backend = {
     CAIRO_SURFACE_TYPE_GL,
+    _cairo_gl_surface_finish,
     _cairo_default_context_create,
 
     _cairo_gl_surface_create_similar,
-    _cairo_gl_surface_finish,
+    NULL, /* similar image */
+    NULL, /* map to image */
+    NULL, /* unmap image */
 
     _cairo_gl_surface_acquire_source_image,
     _cairo_gl_surface_release_source_image,
diff --git a/src/cairo-image-surface.c b/src/cairo-image-surface.c
index c14aac0..369f172 100644
--- a/src/cairo-image-surface.c
+++ b/src/cairo-image-surface.c
@@ -728,6 +728,36 @@ _cairo_image_surface_create_similar (void	       *abstract_other,
 						     width, height);
 }
 
+static cairo_surface_t *
+_cairo_image_surface_map_to_image (void *abstract_other,
+				   const cairo_rectangle_int_t *extents)
+{
+    cairo_image_surface_t *other = abstract_other;
+    cairo_surface_t *surface;
+    uint8_t *data;
+
+    data = other->data;
+    data += extents->y * other->stride;
+    data += extents->x * PIXMAN_FORMAT_BPP (other->pixman_format)/ 8;
+
+    surface =
+	_cairo_image_surface_create_with_pixman_format (data,
+							other->pixman_format,
+							extents->width,
+							extents->height,
+							other->stride);
+
+    cairo_surface_set_device_offset (surface, -extents->x, -extents->y);
+    return surface;
+}
+
+static cairo_int_status_t
+_cairo_image_surface_unmap_image (void *abstract_surface,
+				  cairo_image_surface_t *image)
+{
+    return CAIRO_INT_STATUS_SUCCESS;
+}
+
 static cairo_status_t
 _cairo_image_surface_finish (void *abstract_surface)
 {
@@ -4655,10 +4685,15 @@ _cairo_surface_is_image (const cairo_surface_t *surface)
 
 const cairo_surface_backend_t _cairo_image_surface_backend = {
     CAIRO_SURFACE_TYPE_IMAGE,
+    _cairo_image_surface_finish,
+
     _cairo_default_context_create,
 
     _cairo_image_surface_create_similar,
-    _cairo_image_surface_finish,
+    NULL, /* create similar image */
+    _cairo_image_surface_map_to_image,
+    _cairo_image_surface_unmap_image,
+
     _cairo_image_surface_acquire_source_image,
     _cairo_image_surface_release_source_image,
     _cairo_image_surface_acquire_dest_image,
diff --git a/src/cairo-os2-surface.c b/src/cairo-os2-surface.c
index c8a5458..ba46b22 100644
--- a/src/cairo-os2-surface.c
+++ b/src/cairo-os2-surface.c
@@ -1439,10 +1439,14 @@ _cairo_os2_surface_mark_dirty_rectangle (void *surface,
 
 static const cairo_surface_backend_t cairo_os2_surface_backend = {
     CAIRO_SURFACE_TYPE_OS2,
+    _cairo_os2_surface_finish,
     _cairo_default_context_create,
 
     NULL, /* create_similar */
-    _cairo_os2_surface_finish,
+    NULL, /* create_similar_image */
+    NULL, /* map_to_image */
+    NULL, /* unmap_image */
+
     _cairo_os2_surface_acquire_source_image,
     _cairo_os2_surface_release_source_image,
     _cairo_os2_surface_acquire_dest_image,
diff --git a/src/cairo-paginated-surface.c b/src/cairo-paginated-surface.c
index 1f05a8d..5fe3439 100644
--- a/src/cairo-paginated-surface.c
+++ b/src/cairo-paginated-surface.c
@@ -649,10 +649,15 @@ _cairo_paginated_context_create (void *target)
 
 static const cairo_surface_backend_t cairo_paginated_surface_backend = {
     CAIRO_INTERNAL_SURFACE_TYPE_PAGINATED,
+    _cairo_paginated_surface_finish,
+
     _cairo_paginated_context_create,
 
     _cairo_paginated_surface_create_similar,
-    _cairo_paginated_surface_finish,
+    NULL, /* create simlar image */
+    NULL, /* map to image */
+    NULL, /* unmap image */
+
     _cairo_paginated_surface_acquire_source_image,
     _cairo_paginated_surface_release_source_image,
     NULL, /* acquire_dest_image */
diff --git a/src/cairo-pdf-surface.c b/src/cairo-pdf-surface.c
index 8bfa556..e6535cb 100644
--- a/src/cairo-pdf-surface.c
+++ b/src/cairo-pdf-surface.c
@@ -6567,10 +6567,15 @@ _cairo_pdf_surface_set_paginated_mode (void			*abstract_surface,
 
 static const cairo_surface_backend_t cairo_pdf_surface_backend = {
     CAIRO_SURFACE_TYPE_PDF,
+    _cairo_pdf_surface_finish,
+
     _cairo_default_context_create,
 
     NULL, /* create similar: handled by wrapper */
-    _cairo_pdf_surface_finish,
+    NULL, /* create similar image */
+    NULL, /* map to image */
+    NULL, /* unmap image */
+
     NULL, /* acquire_source_image */
     NULL, /* release_source_image */
     NULL, /* acquire_dest_image */
diff --git a/src/cairo-ps-surface.c b/src/cairo-ps-surface.c
index 3a54a90..1e7ddeb 100644
--- a/src/cairo-ps-surface.c
+++ b/src/cairo-ps-surface.c
@@ -3932,10 +3932,15 @@ _cairo_ps_surface_supports_fine_grained_fallbacks (void	    *abstract_surface)
 
 static const cairo_surface_backend_t cairo_ps_surface_backend = {
     CAIRO_SURFACE_TYPE_PS,
+    _cairo_ps_surface_finish,
+
     _cairo_default_context_create,
 
     NULL, /* create similar: handled by wrapper */
-    _cairo_ps_surface_finish,
+    NULL, /* create similar image */
+    NULL, /* map to image */
+    NULL, /* unmap image */
+
     NULL, /* acquire_source_image */
     NULL, /* release_source_image */
     NULL, /* acquire_dest_image */
diff --git a/src/cairo-quartz-image-surface.c b/src/cairo-quartz-image-surface.c
index 2d0058e..bbe5fa7 100644
--- a/src/cairo-quartz-image-surface.c
+++ b/src/cairo-quartz-image-surface.c
@@ -160,10 +160,15 @@ _cairo_quartz_image_surface_flush (void *asurface)
 
 static const cairo_surface_backend_t cairo_quartz_image_surface_backend = {
     CAIRO_SURFACE_TYPE_QUARTZ_IMAGE,
+    _cairo_quartz_image_surface_finish,
+
     _cairo_default_context_create,
 
     _cairo_quartz_image_surface_create_similar,
-    _cairo_quartz_image_surface_finish,
+    NULL, /* create_similar_image */
+    NULL, /* map_to_image */
+    NULL, /* unmap_image */
+
     _cairo_quartz_image_surface_acquire_source_image,
     NULL, /* release_source_image */
     _cairo_quartz_image_surface_acquire_dest_image,
diff --git a/src/cairo-recording-surface.c b/src/cairo-recording-surface.c
index 16cc5c1..1ce3e22 100644
--- a/src/cairo-recording-surface.c
+++ b/src/cairo-recording-surface.c
@@ -805,10 +805,15 @@ _cairo_surface_is_recording (const cairo_surface_t *surface)
 
 static const cairo_surface_backend_t cairo_recording_surface_backend = {
     CAIRO_SURFACE_TYPE_RECORDING,
+    _cairo_recording_surface_finish,
+
     _cairo_default_context_create,
 
     _cairo_recording_surface_create_similar,
-    _cairo_recording_surface_finish,
+    NULL, /* create similar image */
+    NULL, /* map to image */
+    NULL, /* unmap image */
+
     _cairo_recording_surface_acquire_source_image,
     _cairo_recording_surface_release_source_image,
     NULL, /* acquire_dest_image */
diff --git a/src/cairo-rectangle.c b/src/cairo-rectangle.c
index b0b6d9e..edad369 100644
--- a/src/cairo-rectangle.c
+++ b/src/cairo-rectangle.c
@@ -298,3 +298,13 @@ _cairo_box_add_curve_to (cairo_box_t *extents,
 	assert (status == CAIRO_STATUS_SUCCESS);
     }
 }
+
+void
+_cairo_rectangle_int_from_double (cairo_rectangle_int_t *recti,
+				  const cairo_rectangle_t *rectf)
+{
+	recti->x = floor (rectf->x);
+	recti->y = floor (rectf->y);
+	recti->width  = ceil (rectf->x + rectf->width) - floor (rectf->x);
+	recti->height = ceil (rectf->y + rectf->height) - floor (rectf->y);
+}
diff --git a/src/cairo-script-surface.c b/src/cairo-script-surface.c
index 6f46320..3aa1f61 100644
--- a/src/cairo-script-surface.c
+++ b/src/cairo-script-surface.c
@@ -3409,10 +3409,15 @@ _cairo_script_surface_get_extents (void *abstract_surface,
 static const cairo_surface_backend_t
 _cairo_script_surface_backend = {
     CAIRO_SURFACE_TYPE_SCRIPT,
+    _cairo_script_surface_finish,
+
     _cairo_default_context_create,
 
     _cairo_script_surface_create_similar,
-    _cairo_script_surface_finish,
+    NULL, /* create similar image */
+    NULL, /* map to image */
+    NULL, /* unmap image */
+
     _cairo_script_surface_acquire_source_image,
     _cairo_script_surface_release_source_image,
     NULL, /* acquire_dest_image */
diff --git a/src/cairo-surface-snapshot.c b/src/cairo-surface-snapshot.c
index 757ec1e..c88d015 100644
--- a/src/cairo-surface-snapshot.c
+++ b/src/cairo-surface-snapshot.c
@@ -89,10 +89,13 @@ _cairo_surface_snapshot_get_extents (void                  *abstract_surface,
 
 static const cairo_surface_backend_t _cairo_surface_snapshot_backend = {
     CAIRO_INTERNAL_SURFACE_TYPE_SNAPSHOT,
+    _cairo_surface_snapshot_finish,
     NULL,
 
     NULL, /* create similar */
-    _cairo_surface_snapshot_finish,
+    NULL, /* create similar image  */
+    NULL, /* map to image */
+    NULL, /* unmap image  */
 
     _cairo_surface_snapshot_acquire_source_image,
     _cairo_surface_snapshot_release_source_image,
diff --git a/src/cairo-surface-subsurface.c b/src/cairo-surface-subsurface.c
index 143c78e..cdefd56 100644
--- a/src/cairo-surface-subsurface.c
+++ b/src/cairo-surface-subsurface.c
@@ -61,6 +61,48 @@ _cairo_surface_subsurface_create_similar (void *other,
     return surface->target->backend->create_similar (surface->target, content, width, height);
 }
 
+static cairo_surface_t *
+_cairo_surface_subsurface_create_similar_image (void *other,
+						cairo_format_t format,
+						int width, int height)
+{
+    cairo_surface_subsurface_t *surface = other;
+    return surface->target->backend->create_similar_image (surface->target,
+							   format,
+							   width, height);
+}
+
+static cairo_surface_t *
+_cairo_surface_subsurface_map_to_image (void *abstract_surface,
+					const cairo_rectangle_int_t *extents)
+{
+    cairo_surface_subsurface_t *surface = abstract_surface;
+    cairo_rectangle_int_t target_extents;
+
+    if (surface->target->backend->map_to_image == NULL)
+	return NULL;
+
+    target_extents.x = extents->x + surface->extents.x;
+    target_extents.y = extents->y + surface->extents.y;
+    target_extents.width  = extents->width;
+    target_extents.height = extents->height;
+
+    return surface->target->backend->map_to_image (surface->target,
+						   &target_extents);
+}
+
+static cairo_int_status_t
+_cairo_surface_subsurface_unmap_image (void *abstract_surface,
+				       cairo_image_surface_t *image)
+{
+    cairo_surface_subsurface_t *surface = abstract_surface;
+
+    if (surface->target->backend->unmap_image == NULL)
+	return CAIRO_INT_STATUS_UNSUPPORTED;
+
+    return surface->target->backend->unmap_image (surface->target, image);
+}
+
 static cairo_int_status_t
 _cairo_surface_subsurface_paint (void *abstract_surface,
 				 cairo_operator_t op,
@@ -426,10 +468,14 @@ _cairo_surface_subsurface_create_context(void *target)
 
 static const cairo_surface_backend_t _cairo_surface_subsurface_backend = {
     CAIRO_SURFACE_TYPE_SUBSURFACE,
+    _cairo_surface_subsurface_finish,
+
     _cairo_surface_subsurface_create_context,
 
     _cairo_surface_subsurface_create_similar,
-    _cairo_surface_subsurface_finish,
+    _cairo_surface_subsurface_create_similar_image,
+    _cairo_surface_subsurface_map_to_image,
+    _cairo_surface_subsurface_unmap_image,
 
     _cairo_surface_subsurface_acquire_source_image,
     _cairo_surface_subsurface_release_source_image,
@@ -533,4 +579,36 @@ cairo_surface_create_for_rectangle (cairo_surface_t *target,
 
     return &surface->base;
 }
+
+cairo_surface_t *
+_cairo_surface_create_for_rectangle_int (cairo_surface_t *target,
+					 cairo_rectangle_int_t *extents)
+{
+    cairo_surface_subsurface_t *surface;
+
+    if (unlikely (target->status))
+	return _cairo_surface_create_in_error (target->status);
+    if (unlikely (target->finished))
+	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_SURFACE_FINISHED));
+
+    assert (target->backend->type != CAIRO_SURFACE_TYPE_SUBSURFACE);
+
+    surface = malloc (sizeof (cairo_surface_subsurface_t));
+    if (unlikely (surface == NULL))
+	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
+
+    assert (_cairo_matrix_is_translation (&target->device_transform));
+
+    _cairo_surface_init (&surface->base,
+			 &_cairo_surface_subsurface_backend,
+			 NULL, /* device */
+			 target->content);
+
+    surface->extents = *extents;
+    surface->extents.x += target->device_transform.x0;
+    surface->extents.y += target->device_transform.y0;
+    surface->target = cairo_surface_reference (target);
+
+    return &surface->base;
+}
 /* XXX observe mark-dirty */
diff --git a/src/cairo-surface.c b/src/cairo-surface.c
index 1f9028d..b6a9489 100644
--- a/src/cairo-surface.c
+++ b/src/cairo-surface.c
@@ -519,6 +519,188 @@ cairo_surface_create_similar (cairo_surface_t  *other,
     return surface;
 }
 
+
+/**
+ * cairo_surface_create_similar_image:
+ * @other: an existing surface used to select the preference of the new surface
+ * @format: the format for the new surface
+ * @width: width of the new surface, (in device-space units)
+ * @height: height of the new surface (in device-space units)
+ *
+ * Create a new image surface that is as compatible as possible for uploading
+ * to and the use in conjunction with an existing surface.
+ *
+ * Initially the surface contents are all 0 (transparent if contents
+ * have transparency, black otherwise.)
+ *
+ * Return value: a pointer to the newly allocated image 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_similar_image (cairo_surface_t  *other,
+				    cairo_format_t    format,
+				    int		width,
+				    int		height)
+{
+    if (other->status)
+	return _cairo_surface_create_in_error (other->status);
+    if (unlikely (other->finished))
+	return _cairo_surface_create_in_error (CAIRO_STATUS_SURFACE_FINISHED);
+
+    if (unlikely (width < 0 || height < 0))
+	return _cairo_surface_create_in_error (CAIRO_STATUS_INVALID_SIZE);
+    if (unlikely (! CAIRO_FORMAT_VALID (format)))
+	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_FORMAT));
+
+    if (other->backend->create_similar_image)
+	return other->backend->create_similar_image (other,
+						    format, width, height);
+
+    return cairo_image_surface_create (format, width, height);
+}
+
+/**
+ * cairo_surface_map_to_image:
+ * @surface: an existing surface used to extract the image from
+ * @extents: limit the extraction to an rectangular region
+ *
+ * Returns an image surface that is the most efficient mechanism for
+ * modifying the backing store of the target surface. The region retrieved
+ * may be limited to the @extents or %NULL for the whole surface
+ *
+ * Note, the use of the original surface as a target or source whilst it is
+ * mapped is undefined. The result of mapping the surface multiple times is
+ * undefined.
+ *
+ * Return value: a pointer to the newly allocated image 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_map_to_image (cairo_surface_t  *surface,
+			    const cairo_rectangle_t *extents)
+{
+    cairo_rectangle_int_t rect;
+    cairo_surface_t *image;
+
+    if (unlikely (surface->status))
+	return _cairo_surface_create_in_error (surface->status);
+    if (unlikely (surface->finished))
+	return _cairo_surface_create_in_error (CAIRO_STATUS_SURFACE_FINISHED);
+
+    if (extents == NULL) {
+	if (unlikely (! surface->backend->get_extents (surface, &rect)))
+	    return _cairo_surface_create_in_error (CAIRO_STATUS_INVALID_SIZE);
+    } else {
+	_cairo_rectangle_int_from_double (&rect, extents);
+    }
+
+    image = NULL;
+    if (surface->backend->map_to_image)
+	image = surface->backend->map_to_image (surface, &rect);
+
+    if (image == NULL) {
+	cairo_surface_pattern_t pattern;
+	cairo_status_t status;
+
+	image = cairo_image_surface_create (_cairo_format_from_content (surface->content),
+					    rect.width, rect.height);
+	cairo_surface_set_device_offset (image, -rect.y, -rect.y);
+
+	_cairo_pattern_init_for_surface (&pattern, surface);
+	pattern.base.filter = CAIRO_FILTER_NEAREST;
+
+	status = _cairo_surface_paint (image,
+				       CAIRO_OPERATOR_SOURCE,
+				       &pattern.base,
+				       NULL);
+
+	_cairo_pattern_fini (&pattern.base);
+
+	if (unlikely (status)) {
+	    cairo_surface_destroy (image);
+	    image = _cairo_surface_create_in_error (status);
+	}
+    }
+
+    return image;
+}
+
+/**
+ * cairo_surface_unmap_image:
+ * @surface: an existing surface used to extract the image from
+ * @image: the currently mapped image
+ *
+ * Unmaps the image surface as returned from #cairo_surface_map_to_image().
+ * Returns an image surface that is the most efficient mechanism for
+ * modifying the backing store of the target surface. The region retrieved
+ * may be limited to the @extents or %NULL for the whole surface
+ *
+ * Return value: a pointer to the newly allocated image 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.
+ **/
+void
+cairo_surface_unmap_image (cairo_surface_t *surface,
+			   cairo_surface_t *image)
+{
+    cairo_int_status_t status;
+
+    if (unlikely (surface->status)) {
+	status = surface->status;
+	goto error;
+    }
+    if (unlikely (surface->finished)) {
+	status = _cairo_error (CAIRO_STATUS_SURFACE_FINISHED);
+	goto error;
+    }
+
+    if (unlikely (image->status)) {
+	status = image->status;
+	goto error;
+    }
+    if (unlikely (image->finished)) {
+	status = _cairo_error (CAIRO_STATUS_SURFACE_FINISHED);
+	goto error;
+    }
+
+    status = CAIRO_INT_STATUS_UNSUPPORTED;
+    if (surface->backend->unmap_image)
+	status = surface->backend->unmap_image (surface, image);
+    if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
+	cairo_surface_pattern_t pattern;
+
+	_cairo_pattern_init_for_surface (&pattern, image);
+	pattern.base.filter = CAIRO_FILTER_NEAREST;
+
+	status = _cairo_surface_paint (surface,
+				       CAIRO_OPERATOR_SOURCE,
+				       &pattern.base,
+				       NULL);
+
+	_cairo_pattern_fini (&pattern.base);
+    }
+
+error:
+    cairo_surface_finish (image);
+    cairo_surface_destroy (image);
+    if (status)
+	_cairo_status_set_error (&surface->status, status);
+}
+
 cairo_surface_t *
 _cairo_surface_create_similar_solid (cairo_surface_t	 *other,
 				     cairo_content_t	  content,
diff --git a/src/cairo-svg-surface.c b/src/cairo-svg-surface.c
index e5ddb7e..66d0fc2 100644
--- a/src/cairo-svg-surface.c
+++ b/src/cairo-svg-surface.c
@@ -2575,10 +2575,15 @@ _cairo_svg_surface_get_font_options (void                  *abstract_surface,
 
 static const cairo_surface_backend_t cairo_svg_surface_backend = {
 	CAIRO_SURFACE_TYPE_SVG,
+	_cairo_svg_surface_finish,
+
 	_cairo_default_context_create,
 
 	NULL, /* create_similar: handled by wrapper */
-	_cairo_svg_surface_finish,
+	NULL, /* create_similar_image */
+	NULL, /* map to image */
+	NULL, /* unmap image */
+
 	NULL, /* acquire_source_image */
 	NULL, /* release_source_image */
 	NULL, /* acquire_dest_image */
diff --git a/src/cairo-tee-surface.c b/src/cairo-tee-surface.c
index 40f8aa3..834f140 100644
--- a/src/cairo-tee-surface.c
+++ b/src/cairo-tee-surface.c
@@ -396,10 +396,15 @@ _cairo_tee_surface_show_text_glyphs (void		    *abstract_surface,
 
 static const cairo_surface_backend_t cairo_tee_surface_backend = {
     CAIRO_SURFACE_TYPE_TEE,
+    _cairo_tee_surface_finish,
+
     _cairo_default_context_create, /* XXX */
 
     _cairo_tee_surface_create_similar,
-    _cairo_tee_surface_finish,
+    NULL, /* create similar image */
+    NULL, /* map to image */
+    NULL, /* unmap image */
+
     _cairo_tee_surface_acquire_source_image,
     _cairo_tee_surface_release_source_image,
     NULL, NULL, /* dest_image */
diff --git a/src/cairo-type3-glyph-surface.c b/src/cairo-type3-glyph-surface.c
index bad0d3b..93c3a6a 100644
--- a/src/cairo-type3-glyph-surface.c
+++ b/src/cairo-type3-glyph-surface.c
@@ -322,10 +322,15 @@ _cairo_type3_glyph_surface_show_glyphs (void		     *abstract_surface,
 
 static const cairo_surface_backend_t cairo_type3_glyph_surface_backend = {
     CAIRO_INTERNAL_SURFACE_TYPE_TYPE3_GLYPH,
+    _cairo_type3_glyph_surface_finish,
+
     _cairo_default_context_create,
 
     NULL, /* _cairo_type3_glyph_surface_create_similar */
-    _cairo_type3_glyph_surface_finish,
+    NULL, /* _cairo_type3_glyph_surface_create_similar_image */
+    NULL, /* _cairo_type3_glyph_surface_create_map_to_image */
+    NULL, /* _cairo_type3_glyph_surface_create_unmap_image */
+
     NULL, /* acquire_source_image */
     NULL, /* release_source_image */
     NULL, /* acquire_dest_image */
diff --git a/src/cairo-vg-surface.c b/src/cairo-vg-surface.c
index eccf129..392ed0b 100644
--- a/src/cairo-vg-surface.c
+++ b/src/cairo-vg-surface.c
@@ -1548,10 +1548,13 @@ _vg_surface_finish (void *abstract_surface)
 
 static const cairo_surface_backend_t cairo_vg_surface_backend = {
     CAIRO_SURFACE_TYPE_VG,
+    _vg_surface_finish,
     _cairo_default_context_create, /* XXX */
 
     _vg_surface_create_similar,
-    _vg_surface_finish,
+    NULL, /* create similar image */
+    NULL, /* map to image */
+    NULL, /* unmap image */
 
     _vg_surface_acquire_source_image,
     _vg_surface_release_source_image,
diff --git a/src/cairo-win32-printing-surface.c b/src/cairo-win32-printing-surface.c
index a5d2787..71d1b5e 100644
--- a/src/cairo-win32-printing-surface.c
+++ b/src/cairo-win32-printing-surface.c
@@ -1862,10 +1862,15 @@ _cairo_surface_is_win32_printing (cairo_surface_t *surface)
 
 static const cairo_surface_backend_t cairo_win32_printing_surface_backend = {
     CAIRO_SURFACE_TYPE_WIN32_PRINTING,
+    _cairo_win32_surface_finish,
+
     _cairo_default_context_create,
 
     _cairo_win32_printing_surface_create_similar,
-    _cairo_win32_surface_finish,
+    NULL, /* create similar image */
+    NULL, /* map to image */
+    NULL, /* unmap image */
+
     NULL, /* acquire_source_image */
     NULL, /* release_source_image */
     NULL, /* acquire_dest_image */
diff --git a/src/cairo-win32-surface.c b/src/cairo-win32-surface.c
index cb2b95b..e203542 100644
--- a/src/cairo-win32-surface.c
+++ b/src/cairo-win32-surface.c
@@ -549,6 +549,65 @@ _cairo_win32_surface_get_subimage (cairo_win32_surface_t  *surface,
     return CAIRO_STATUS_SUCCESS;
 }
 
+static cairo_surface_t *
+_cairo_win32_surface_map_to_image (void                    *abstract_surface,
+				   const cairo_rectangle_int_t   *extents)
+{
+    cairo_win32_surface_t *surface = abstract_surface;
+    cairo_win32_surface_t *local = NULL;
+    cairo_status_t status;
+
+    if (surface->image) {
+	GdiFlush();
+	return _cairo_surface_create_for_rectangle_int (surface->image,
+							extents);
+    }
+
+    status = _cairo_win32_surface_get_subimage (abstract_surface,
+						extents->x,
+						extents->y,
+						extents->width,
+						extents->height,
+						&local);
+    if (unlikely (status))
+	return _cairo_surface_create_in_error (status);
+
+    status = _cairo_surface_set_user_data (&local->image->user_data,
+					   (const cairo_user_data_key_t *)surface->image,
+					   local, NULL);
+    if (unlikely (status)) {
+	cairo_surface_destroy (&local->base);
+	return _cairo_surface_create_in_error (status);
+    }
+
+    cairo_surface_set_device_offset (local->image, -extents->x, -extents->y);
+    return local->image;
+}
+
+static cairo_int_status_t
+_cairo_win32_surface_release_unmap_image (void                    *abstract_surface,
+					  cairo_image_surface_t   *image)
+{
+    cairo_win32_surface_t *surface = abstract_surface;
+    cairo_win32_surface_t *local;
+
+    local = _cairo_surface_set_user_data (&image->base.user_data,
+					   (const cairo_user_data_key_t *)surface->image);
+    if (!local)
+	return CAIRO_INT_STATUS_SUCCESS;
+
+    if (!BitBlt (surface->dc,
+		 image->device_transform.x0,
+		 image->device_transform.y0,
+		 image->width, image->height,
+		 local->dc,
+		 0, 0,
+		 SRCCOPY))
+	_cairo_win32_print_gdi_error ("_cairo_win32_surface_release_dest_image");
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
 static cairo_status_t
 _cairo_win32_surface_acquire_source_image (void                    *abstract_surface,
 					   cairo_image_surface_t  **image_out,
@@ -2087,10 +2146,15 @@ _cairo_win32_surface_create_span_renderer (cairo_operator_t	 op,
 
 static const cairo_surface_backend_t cairo_win32_surface_backend = {
     CAIRO_SURFACE_TYPE_WIN32,
+    _cairo_win32_surface_finish,
+
     _cairo_default_context_create,
 
     _cairo_win32_surface_create_similar,
-    _cairo_win32_surface_finish,
+    NULL,
+    _cairo_win32_surface_map_to_image,
+    _cairo_win32_surface_unmap_image,
+
     _cairo_win32_surface_acquire_source_image,
     _cairo_win32_surface_release_source_image,
     _cairo_win32_surface_acquire_dest_image,
diff --git a/src/cairo-xcb-private.h b/src/cairo-xcb-private.h
index a80ed14..5b3e2b4 100644
--- a/src/cairo-xcb-private.h
+++ b/src/cairo-xcb-private.h
@@ -83,7 +83,7 @@ struct _cairo_xcb_shm_info {
 
 struct _cairo_xcb_surface {
     cairo_surface_t base;
-    cairo_surface_t *fallback;
+    cairo_image_surface_t *fallback;
 
     cairo_xcb_connection_t *connection;
     cairo_xcb_screen_t *screen;
@@ -353,9 +353,10 @@ _cairo_xcb_screen_lookup_radial_picture (cairo_xcb_screen_t *screen,
 					 const cairo_radial_pattern_t *radial);
 
 cairo_private cairo_surface_t *
-_cairo_xcb_surface_create_similar_image (cairo_xcb_surface_t *other,
-					 cairo_content_t content,
-					 int width, int height);
+_cairo_xcb_surface_create_similar_image (void *abstrct_other,
+					 cairo_format_t format,
+					 int width,
+					 int height);
 
 cairo_private cairo_surface_t *
 _cairo_xcb_surface_create_similar (void			*abstract_other,
diff --git a/src/cairo-xcb-surface-core.c b/src/cairo-xcb-surface-core.c
index 1a2bcad..c3c0953 100644
--- a/src/cairo-xcb-surface-core.c
+++ b/src/cairo-xcb-surface-core.c
@@ -74,8 +74,6 @@ _cairo_xcb_pixmap_finish (void *abstract_surface)
 
 static const cairo_surface_backend_t _cairo_xcb_pixmap_backend = {
     CAIRO_SURFACE_TYPE_XCB,
-    NULL,
-    NULL,
     _cairo_xcb_pixmap_finish,
 };
 
diff --git a/src/cairo-xcb-surface-render.c b/src/cairo-xcb-surface-render.c
index f0f3564..d8c1172 100644
--- a/src/cairo-xcb-surface-render.c
+++ b/src/cairo-xcb-surface-render.c
@@ -101,8 +101,6 @@ _cairo_xcb_picture_finish (void *abstract_surface)
 
 static const cairo_surface_backend_t _cairo_xcb_picture_backend = {
     CAIRO_SURFACE_TYPE_XCB,
-    NULL,
-    NULL,
     _cairo_xcb_picture_finish,
 };
 
diff --git a/src/cairo-xcb-surface.c b/src/cairo-xcb-surface.c
index 66e25a5..827041e 100644
--- a/src/cairo-xcb-surface.c
+++ b/src/cairo-xcb-surface.c
@@ -73,98 +73,6 @@ slim_hidden_proto (cairo_xcb_surface_create_with_xrender_format);
  * This macro can be used to conditionally compile backend-specific code.
  */
 
-#if CAIRO_HAS_XCB_SHM_FUNCTIONS
-static cairo_status_t
-_cairo_xcb_surface_create_similar_shm (cairo_xcb_surface_t *other,
-				       pixman_format_code_t pixman_format,
-				       int width, int height,
-				       cairo_surface_t **out)
-{
-    size_t size, stride;
-    cairo_xcb_shm_info_t *shm_info;
-    cairo_status_t status;
-    cairo_surface_t *image;
-
-    stride = CAIRO_STRIDE_FOR_WIDTH_BPP (width, PIXMAN_FORMAT_BPP (pixman_format));
-    size = stride * height;
-    if (size < CAIRO_XCB_SHM_SMALL_IMAGE)
-	return CAIRO_INT_STATUS_UNSUPPORTED;
-
-    status = _cairo_xcb_connection_allocate_shm_info (other->connection,
-						      size, &shm_info);
-    if (unlikely (status))
-	return status;
-
-    image = _cairo_image_surface_create_with_pixman_format (shm_info->mem,
-							    pixman_format,
-							    width, height,
-							    stride);
-    status = image->status;
-    if (unlikely (status)) {
-	_cairo_xcb_shm_info_destroy (shm_info);
-	return status;
-    }
-
-    status = _cairo_user_data_array_set_data (&image->user_data,
-					      (const cairo_user_data_key_t *) other->connection,
-					      shm_info,
-					      (cairo_destroy_func_t) _cairo_xcb_shm_info_destroy);
-    if (unlikely (status)) {
-	cairo_surface_destroy (image);
-	_cairo_xcb_shm_info_destroy (shm_info);
-	return status;
-    }
-
-    *out = image;
-    return CAIRO_STATUS_SUCCESS;
-}
-#endif
-
-cairo_surface_t *
-_cairo_xcb_surface_create_similar_image (cairo_xcb_surface_t *other,
-					 cairo_content_t content,
-					 int width, int height)
-{
-    cairo_surface_t *image = NULL;
-    pixman_format_code_t pixman_format;
-
-    /* XXX choose pixman_format from connection->image_formats */
-    switch (content) {
-    case CAIRO_CONTENT_ALPHA:
-	pixman_format = PIXMAN_a8;
-	break;
-    case CAIRO_CONTENT_COLOR:
-	pixman_format = PIXMAN_x8r8g8b8;
-	break;
-    default:
-	ASSERT_NOT_REACHED;
-    case CAIRO_CONTENT_COLOR_ALPHA:
-	pixman_format = PIXMAN_a8r8g8b8;
-	break;
-    }
-
-#if CAIRO_HAS_XCB_SHM_FUNCTIONS
-    if (other->connection->flags & CAIRO_XCB_HAS_SHM) {
-	cairo_status_t status;
-
-	status = _cairo_xcb_surface_create_similar_shm (other,
-							pixman_format,
-							width, height,
-							&image);
-	/* Ignore errors and fall through */
-    }
-#endif
-
-    if (image == NULL) {
-	image = _cairo_image_surface_create_with_pixman_format (NULL,
-								pixman_format,
-								width, height,
-								0);
-    }
-
-    return image;
-}
-
 cairo_surface_t *
 _cairo_xcb_surface_create_similar (void			*abstract_other,
 				   cairo_content_t	 content,
@@ -181,10 +89,13 @@ _cairo_xcb_surface_create_similar (void			*abstract_other,
 		 height > XLIB_COORD_MAX ||
 		 width  <= 0 ||
 		 height <= 0))
-	return _cairo_xcb_surface_create_similar_image (other, content, width, height);
+	return cairo_image_surface_create (_cairo_format_from_content (content),
+					   width, height);
 
     if ((other->connection->flags & CAIRO_XCB_HAS_RENDER) == 0)
-	return _cairo_xcb_surface_create_similar_image (other, content, width, height);
+	return _cairo_xcb_surface_create_similar_image (other,
+							_cairo_format_from_content (content),
+							width, height);
 
     connection = other->connection;
     status = _cairo_xcb_connection_acquire (connection);
@@ -246,6 +157,64 @@ _cairo_xcb_surface_create_similar (void			*abstract_other,
     return &surface->base;
 }
 
+cairo_surface_t *
+_cairo_xcb_surface_create_similar_image (void			*abstract_other,
+					 cairo_format_t		 format,
+					 int			 width,
+					 int			 height)
+{
+    cairo_xcb_surface_t *other = abstract_other;
+    cairo_xcb_connection_t *connection = other->connection;
+
+#if CAIRO_HAS_XCB_SHM_FUNCTIONS
+    cairo_surface_t *image;
+    cairo_xcb_shm_info_t *shm_info;
+    cairo_status_t status;
+    size_t stride;
+    pixman_format_code_t pixman_format;
+
+    if (unlikely(width > XLIB_COORD_MAX || height > XLIB_COORD_MAX))
+	return cairo_image_surface_create (format, width, height);
+
+    if ((connection->flags & CAIRO_XCB_HAS_SHM) == 0)
+	return cairo_image_surface_create (format, width, height);
+
+    pixman_format = _cairo_format_to_pixman_format_code (format);
+
+    stride = CAIRO_STRIDE_FOR_WIDTH_BPP (width,
+					 PIXMAN_FORMAT_BPP (pixman_format));
+    status = _cairo_xcb_connection_allocate_shm_info (connection,
+						      stride * height,
+						      &shm_info);
+    if (unlikely (status))
+	return _cairo_surface_create_in_error (status);
+
+    image = _cairo_image_surface_create_with_pixman_format (shm_info->mem,
+							    pixman_format,
+							    width,
+							    height,
+							    stride);
+    if (unlikely (image->status)) {
+	_cairo_xcb_shm_info_destroy (shm_info);
+	return image;
+    }
+
+    status = _cairo_user_data_array_set_data (&image->user_data,
+					      (const cairo_user_data_key_t *) connection,
+					      shm_info,
+					      (cairo_destroy_func_t) _cairo_xcb_shm_info_destroy);
+    if (unlikely (status)) {
+	cairo_surface_destroy (image);
+	_cairo_xcb_shm_info_destroy (shm_info);
+	return _cairo_surface_create_in_error (status);
+    }
+
+    return image;
+#else
+    return cairo_image_surface_create (format, width, height);
+#endif
+}
+
 static cairo_status_t
 _cairo_xcb_surface_finish (void *abstract_surface)
 {
@@ -253,8 +222,8 @@ _cairo_xcb_surface_finish (void *abstract_surface)
     cairo_status_t status;
 
     if (surface->fallback != NULL) {
-	cairo_surface_finish (surface->fallback);
-	cairo_surface_destroy (surface->fallback);
+	cairo_surface_finish (&surface->fallback->base);
+	cairo_surface_destroy (&surface->fallback->base);
     }
 
     cairo_list_del (&surface->link);
@@ -283,144 +252,142 @@ _destroy_image (pixman_image_t *image, void *data)
 }
 
 #if CAIRO_HAS_XCB_SHM_FUNCTIONS
-static cairo_int_status_t
-_cairo_xcb_surface_create_shm_image (cairo_xcb_surface_t *target,
-				     cairo_image_surface_t **image_out,
+static cairo_surface_t *
+_cairo_xcb_surface_create_shm_image (cairo_xcb_connection_t *connection,
+				     pixman_format_code_t pixman_format,
+				     int width, int height,
 				     cairo_xcb_shm_info_t **shm_info_out)
 {
-    cairo_image_surface_t *image;
+    cairo_surface_t *image;
     cairo_xcb_shm_info_t *shm_info;
     cairo_status_t status;
-    size_t size, stride;
+    size_t stride;
 
-    if ((target->connection->flags & CAIRO_XCB_HAS_SHM) == 0)
-	return CAIRO_INT_STATUS_UNSUPPORTED;
+    *shm_info_out = NULL;
 
-    stride = CAIRO_STRIDE_FOR_WIDTH_BPP (target->width,
-					 PIXMAN_FORMAT_BPP (target->pixman_format));
-    size = stride * target->height;
-    if (size < CAIRO_XCB_SHM_SMALL_IMAGE) {
-	target->connection->flags &= ~CAIRO_XCB_HAS_SHM;
-	return CAIRO_INT_STATUS_UNSUPPORTED;
-    }
-
-    status = _cairo_xcb_connection_allocate_shm_info (target->screen->connection,
-						      size, &shm_info);
+    stride = CAIRO_STRIDE_FOR_WIDTH_BPP (width,
+					 PIXMAN_FORMAT_BPP (pixman_format));
+    status = _cairo_xcb_connection_allocate_shm_info (connection,
+						      stride * height,
+						      &shm_info);
     if (unlikely (status))
-	return status;
+	return _cairo_surface_create_in_error (status);
 
-    image = (cairo_image_surface_t *)
-	_cairo_image_surface_create_with_pixman_format (shm_info->mem,
-							target->pixman_format,
-							target->width,
-							target->height,
-							stride);
-    status = image->base.status;
-    if (unlikely (status)) {
+    image = _cairo_image_surface_create_with_pixman_format (shm_info->mem,
+							    pixman_format,
+							    width, height,
+							    stride);
+    if (unlikely (image->status)) {
 	_cairo_xcb_shm_info_destroy (shm_info);
-	return status;
+	return image;
     }
 
-    status = _cairo_user_data_array_set_data (&image->base.user_data,
-					      (const cairo_user_data_key_t *) target->connection,
+    status = _cairo_user_data_array_set_data (&image->user_data,
+					      (const cairo_user_data_key_t *) connection,
 					      shm_info,
 					      (cairo_destroy_func_t) _cairo_xcb_shm_info_destroy);
     if (unlikely (status)) {
-	cairo_surface_destroy (&image->base);
+	cairo_surface_destroy (image);
 	_cairo_xcb_shm_info_destroy (shm_info);
-	return status;
+	return _cairo_surface_create_in_error (status);
     }
 
-    *image_out = image;
     *shm_info_out = shm_info;
-    return CAIRO_STATUS_SUCCESS;
+    return image;
 }
 #endif
 
-static cairo_status_t
-_get_shm_image (cairo_xcb_surface_t     *surface,
-		cairo_image_surface_t  **image_out)
+static cairo_image_surface_t *
+_get_shm_image (cairo_xcb_surface_t *surface,
+		int x, int y,
+		int width, int height)
 {
 #if CAIRO_HAS_XCB_SHM_FUNCTIONS
-    cairo_image_surface_t *image;
     cairo_xcb_shm_info_t *shm_info;
+    cairo_surface_t *image;
     cairo_status_t status;
 
-    status = _cairo_xcb_surface_create_shm_image (surface, &image, &shm_info);
-    if (unlikely (status))
-	return status;
+    if ((surface->connection->flags & CAIRO_XCB_HAS_SHM) == 0)
+	return NULL;
 
-    if (! surface->base.is_clear) {
-	status = _cairo_xcb_connection_shm_get_image (surface->connection,
-						      surface->drawable,
-						      0, 0,
-						      surface->width,
-						      surface->height,
-						      shm_info->shm,
-						      shm_info->offset);
-	if (unlikely (status))
-	    return status;
-    } else {
-	memset (image->data, 0, image->stride * image->height);
+    image = _cairo_xcb_surface_create_shm_image (surface->connection,
+						 surface->pixman_format,
+						 width, height,
+						 &shm_info);
+    if (unlikely (image == NULL || image->status))
+	goto done;
+
+    status = _cairo_xcb_connection_shm_get_image (surface->connection,
+						  surface->drawable,
+						  x, y,
+						  width, height,
+						  shm_info->shm,
+						  shm_info->offset);
+    if (unlikely (status)) {
+	cairo_surface_destroy (image);
+	image = _cairo_surface_create_in_error (status);
     }
 
-    *image_out = image;
-    return CAIRO_STATUS_SUCCESS;
+done:
+    return (cairo_image_surface_t *) image;
 #else
-    return CAIRO_INT_STATUS_UNSUPPORTED;
+    return NULL;;
 #endif
 }
 
-static cairo_status_t
+static cairo_image_surface_t *
 _get_image (cairo_xcb_surface_t		 *surface,
 	    cairo_bool_t		  use_shm,
-	    cairo_image_surface_t	**image_out)
+	    int x, int y,
+	    int width, int height)
 {
     cairo_image_surface_t *image;
     cairo_xcb_connection_t *connection;
     xcb_get_image_reply_t *reply;
     cairo_int_status_t status;
 
-    if (surface->base.is_clear || surface->deferred_clear) {
-	cairo_color_t color;
-
-	color = surface->deferred_clear_color;
+    if (surface->deferred_clear) {
 	image = (cairo_image_surface_t *)
 	    _cairo_image_surface_create_with_pixman_format (NULL,
 							    surface->pixman_format,
-							    surface->width,
-							    surface->height,
+							    width, height,
 							    0);
-
-	if (surface->deferred_clear && color.alpha > 0) {
-	    cairo_t *cr = cairo_create (&image->base);
-	    cairo_set_source_rgba (cr, color.red, color.green,
-				   color.blue, color.alpha);
-	    cairo_paint (cr);
-	    cairo_destroy (cr);
+	if (surface->deferred_clear_color.alpha_short > 0x00ff) {
+	    cairo_solid_pattern_t solid;
+
+	    _cairo_pattern_init_solid (&solid, &surface->deferred_clear_color);
+	    status = _cairo_surface_paint (&image->base,
+					   CAIRO_OPERATOR_SOURCE,
+					   &solid.base,
+					   NULL);
+	    if (unlikely (status)) {
+		cairo_surface_destroy (&image->base);
+		image = (cairo_image_surface_t *)
+		    _cairo_surface_create_in_error (status);
+	    }
 	}
-	*image_out = image;
-	return image->base.status;
+	return image;
     }
 
     connection = surface->connection;
 
     status = _cairo_xcb_connection_acquire (connection);
     if (unlikely (status))
-	return status;
+	return (cairo_image_surface_t *) _cairo_surface_create_in_error (status);
 
     if (use_shm) {
-	status = _get_shm_image (surface, image_out);
-	if (status != CAIRO_INT_STATUS_UNSUPPORTED)
-	    goto FAIL;
+	image = _get_shm_image (surface, x, y, width, height);
+	if (image) {
+	    _cairo_xcb_connection_release (connection);
+	    return image;
+	}
     }
 
     if (surface->use_pixmap == 0) {
 	status = _cairo_xcb_connection_get_image (connection,
 						  surface->drawable,
-						  0, 0,
-						  surface->width,
-						  surface->height,
+						  x, y,
+						  width, height,
 						  &reply);
 	if (unlikely (status))
 	    goto FAIL;
@@ -445,25 +412,22 @@ _get_image (cairo_xcb_surface_t		 *surface,
 	pixmap = _cairo_xcb_connection_create_pixmap (connection,
 						      surface->depth,
 						      surface->drawable,
-						      surface->width,
-						      surface->height);
+						      width, height);
 
 	/* XXX IncludeInferiors? */
 	_cairo_xcb_connection_copy_area (connection,
 					 surface->drawable,
 					 pixmap, gc,
+					 x, y,
 					 0, 0,
-					 0, 0,
-					 surface->width,
-					 surface->height);
+					 width, height);
 
 	_cairo_xcb_screen_put_gc (surface->screen, surface->depth, gc);
 
 	status = _cairo_xcb_connection_get_image (connection,
 						  pixmap,
 						  0, 0,
-						  surface->width,
-						  surface->height,
+						  width, height,
 						  &reply);
 	_cairo_xcb_connection_free_pixmap (connection, pixmap);
 
@@ -484,9 +448,8 @@ _get_image (cairo_xcb_surface_t		 *surface,
 	_cairo_image_surface_create_with_pixman_format
 	(xcb_get_image_data (reply),
 	 surface->pixman_format,
-	 surface->width,
-	 surface->height,
-	 CAIRO_STRIDE_FOR_WIDTH_BPP (surface->width,
+	 width, height,
+	 CAIRO_STRIDE_FOR_WIDTH_BPP (width,
 				     PIXMAN_FORMAT_BPP (surface->pixman_format)));
     status = image->base.status;
     if (unlikely (status)) {
@@ -500,12 +463,11 @@ _get_image (cairo_xcb_surface_t		 *surface,
 
     _cairo_xcb_connection_release (connection);
 
-    *image_out = image;
-    return CAIRO_STATUS_SUCCESS;
+    return image;
 
 FAIL:
     _cairo_xcb_connection_release (connection);
-    return status;
+    return (cairo_image_surface_t *) _cairo_surface_create_in_error (status);
 }
 
 static cairo_status_t
@@ -515,10 +477,9 @@ _cairo_xcb_surface_acquire_source_image (void *abstract_surface,
 {
     cairo_xcb_surface_t *surface = abstract_surface;
     cairo_image_surface_t *image;
-    cairo_status_t status;
 
     if (surface->fallback != NULL) {
-	image = (cairo_image_surface_t *) cairo_surface_reference (surface->fallback);
+	image = (cairo_image_surface_t *) cairo_surface_reference (&surface->fallback->base);
 	goto DONE;
     }
 
@@ -530,9 +491,9 @@ _cairo_xcb_surface_acquire_source_image (void *abstract_surface,
 	goto DONE;
     }
 
-    status = _get_image (surface, FALSE, &image);
-    if (unlikely (status))
-	return status;
+    image = _get_image (surface, FALSE, 0, 0, surface->width, surface->height);
+    if (unlikely (image->base.status))
+	return image->base.status;
 
     _cairo_surface_attach_snapshot (&surface->base, &image->base, NULL);
 
@@ -588,7 +549,8 @@ _put_shm_image (cairo_xcb_surface_t    *surface,
 					 surface->drawable,
 					 gc,
 					 surface->width, surface->height,
-					 0, 0,
+					 image->base.device_transform_inverse.x0,
+					 image->base.device_transform_inverse.y0,
 					 image->width, image->height,
 					 0, 0,
 					 image->depth,
@@ -616,8 +578,6 @@ _put_image (cairo_xcb_surface_t    *surface,
     if (image->pixman_format == surface->pixman_format) {
 	xcb_gcontext_t gc;
 
-	assert (image->width == surface->width);
-	assert (image->height == surface->height);
 	assert (image->depth == surface->depth);
 	assert (image->stride == (int) CAIRO_STRIDE_FOR_WIDTH_BPP (image->width, PIXMAN_FORMAT_BPP (image->pixman_format)));
 
@@ -630,7 +590,8 @@ _put_image (cairo_xcb_surface_t    *surface,
 	    _cairo_xcb_connection_put_image (surface->connection,
 					     surface->drawable, gc,
 					     image->width, image->height,
-					     0, 0,
+					     image->base.device_transform_inverse.x0,
+					     image->base.device_transform_inverse.y0,
 					     image->depth,
 					     image->stride,
 					     image->data);
@@ -662,43 +623,56 @@ _cairo_xcb_surface_flush (void *abstract_surface)
 
     status = surface->base.status;
     if (status == CAIRO_STATUS_SUCCESS && ! surface->base.finished) {
-	status = cairo_surface_status (surface->fallback);
+	status = cairo_surface_status (&surface->fallback->base);
 
 	if (status == CAIRO_STATUS_SUCCESS) {
-	    status = _put_image (surface,
-				 (cairo_image_surface_t *) surface->fallback);
+	    status = _put_image (surface, surface->fallback);
 	}
 
 	if (status == CAIRO_STATUS_SUCCESS) {
 	    _cairo_surface_attach_snapshot (&surface->base,
-					    surface->fallback,
+					    &surface->fallback->base,
 					    cairo_surface_finish);
 	}
     }
 
-    cairo_surface_destroy (surface->fallback);
+    cairo_surface_destroy (&surface->fallback->base);
     surface->fallback = NULL;
 
     return status;
 }
 
 static cairo_surface_t *
-_cairo_xcb_surface_map_to_image (cairo_xcb_surface_t *surface)
+_cairo_xcb_surface_map_to_image (void *abstract_surface,
+				 const cairo_rectangle_int_t *extents)
 {
-    cairo_status_t status;
+    cairo_xcb_surface_t *surface = abstract_surface;
     cairo_image_surface_t *image;
 
-    status = _get_image (surface, TRUE, &image);
-    if (unlikely (status))
-	return _cairo_surface_create_in_error (status);
-
-    /* If we had a pending clear, _get_image applied that */
-    surface->deferred_clear = FALSE;
+    image = _get_image (surface, TRUE,
+			extents->x, extents->y,
+			extents->width, extents->height);
+    if (unlikely (image->base.status))
+	return &image->base;
 
+    cairo_surface_set_device_offset (&image->base, -extents->x, -extents->y);
     return &image->base;
 }
 
 static cairo_int_status_t
+_cairo_xcb_surface_unmap (void *abstract_surface,
+			  cairo_image_surface_t *image)
+{
+    return _put_image (abstract_surface, image);
+}
+
+static cairo_image_surface_t *
+_cairo_xcb_surface_fallback (cairo_xcb_surface_t *surface)
+{
+    return _get_image (surface, TRUE, 0, 0, surface->width, surface->height);
+}
+
+static cairo_int_status_t
 _cairo_xcb_surface_paint (void			*abstract_surface,
 			  cairo_operator_t	 op,
 			  const cairo_pattern_t	*source,
@@ -716,10 +690,10 @@ _cairo_xcb_surface_paint (void			*abstract_surface,
 	if (status != CAIRO_INT_STATUS_UNSUPPORTED)
 	    return status;
 
-	surface->fallback = _cairo_xcb_surface_map_to_image (surface);
+	surface->fallback = _cairo_xcb_surface_fallback (surface);
     }
 
-    return _cairo_surface_paint (surface->fallback, op, source, clip);
+    return _cairo_surface_paint (&surface->fallback->base, op, source, clip);
 }
 
 static cairo_int_status_t
@@ -743,10 +717,10 @@ _cairo_xcb_surface_mask (void			*abstract_surface,
 	if (status != CAIRO_INT_STATUS_UNSUPPORTED)
 	    return status;
 
-	surface->fallback = _cairo_xcb_surface_map_to_image (surface);
+	surface->fallback = _cairo_xcb_surface_fallback (surface);
     }
 
-    return _cairo_surface_mask (surface->fallback,
+    return _cairo_surface_mask (&surface->fallback->base,
 				op, source, mask,
 				clip);
 }
@@ -785,10 +759,10 @@ _cairo_xcb_surface_stroke (void				*abstract_surface,
 	if (status != CAIRO_INT_STATUS_UNSUPPORTED)
 	    return status;
 
-	surface->fallback = _cairo_xcb_surface_map_to_image (surface);
+	surface->fallback = _cairo_xcb_surface_fallback (surface);
     }
 
-    return _cairo_surface_stroke (surface->fallback,
+    return _cairo_surface_stroke (&surface->fallback->base,
 				  op, source,
 				  path, style,
 				  ctm, ctm_inverse,
@@ -824,10 +798,10 @@ _cairo_xcb_surface_fill (void			*abstract_surface,
 	if (status != CAIRO_INT_STATUS_UNSUPPORTED)
 	    return status;
 
-	surface->fallback = _cairo_xcb_surface_map_to_image (surface);
+	surface->fallback = _cairo_xcb_surface_fallback (surface);
     }
 
-    return _cairo_surface_fill (surface->fallback,
+    return _cairo_surface_fill (&surface->fallback->base,
 				op, source,
 				path, fill_rule,
 				tolerance, antialias,
@@ -864,10 +838,10 @@ _cairo_xcb_surface_glyphs (void				*abstract_surface,
 	if (status != CAIRO_INT_STATUS_UNSUPPORTED)
 	    return status;
 
-	surface->fallback = _cairo_xcb_surface_map_to_image (surface);
+	surface->fallback = _cairo_xcb_surface_fallback (surface);
     }
 
-    return _cairo_surface_show_text_glyphs (surface->fallback,
+    return _cairo_surface_show_text_glyphs (&surface->fallback->base,
 					    op, source,
 					    NULL, 0,
 					    glyphs, num_glyphs,
@@ -878,12 +852,18 @@ _cairo_xcb_surface_glyphs (void				*abstract_surface,
 
 const cairo_surface_backend_t _cairo_xcb_surface_backend = {
     CAIRO_SURFACE_TYPE_XCB,
+    _cairo_xcb_surface_finish,
     _cairo_default_context_create,
 
     _cairo_xcb_surface_create_similar,
-    _cairo_xcb_surface_finish,
+    _cairo_xcb_surface_create_similar_image,
+
+    _cairo_xcb_surface_map_to_image,
+    _cairo_xcb_surface_unmap,
+
     _cairo_xcb_surface_acquire_source_image,
     _cairo_xcb_surface_release_source_image,
+
     NULL, NULL, NULL, /* dest acquire/release/clone */
 
     NULL, /* composite */
diff --git a/src/cairo-xlib-surface.c b/src/cairo-xlib-surface.c
index 46ca63f..9c46a20 100644
--- a/src/cairo-xlib-surface.c
+++ b/src/cairo-xlib-surface.c
@@ -815,51 +815,37 @@ static const int8_t dither_pattern[4][4] = {
 #undef X
 
 
-static cairo_status_t
+static cairo_surface_t *
 _get_image_surface (cairo_xlib_surface_t    *surface,
-		    cairo_rectangle_int_t   *interest_rect,
-		    cairo_image_surface_t  **image_out,
-		    cairo_rectangle_int_t   *image_rect)
+		    const cairo_rectangle_int_t *extents)
 {
     cairo_int_status_t status;
     cairo_image_surface_t *image = NULL;
     XImage *ximage;
-    cairo_rectangle_int_t extents;
     pixman_format_code_t pixman_format;
     cairo_format_masks_t xlib_masks;
     cairo_xlib_display_t *display;
 
-    extents.x = 0;
-    extents.y = 0;
-    extents.width  = surface->width;
-    extents.height = surface->height;
-
-    if (interest_rect) {
-	if (! _cairo_rectangle_intersect (&extents, interest_rect)) {
-	    *image_out = NULL;
-	    return CAIRO_STATUS_SUCCESS;
-	}
-    }
+    assert (extents->x >= 0);
+    assert (extents->y >= 0);
+    assert (extents->x + extents->width <= surface->width);
+    assert (extents->y + extents->height <= surface->height);
 
     status = _cairo_xlib_display_acquire (surface->base.device, &display);
     if (status)
-        return status;
-
-    if (image_rect)
-	*image_rect = extents;
+        return _cairo_surface_create_in_error (status);
 
     /* XXX: This should try to use the XShm extension if available */
 
-    if (surface->use_pixmap == 0)
-    {
+    if (surface->use_pixmap == 0) {
 	cairo_xlib_error_func_t old_handler;
 
 	old_handler = XSetErrorHandler (_noop_error_handler);
 
 	ximage = XGetImage (display->display,
 			    surface->drawable,
-			    extents.x, extents.y,
-			    extents.width, extents.height,
+			    extents->x, extents->y,
+			    extents->width, extents->height,
 			    AllPlanes, ZPixmap);
 
 	XSetErrorHandler (old_handler);
@@ -869,9 +855,7 @@ _get_image_surface (cairo_xlib_surface_t    *surface,
 	 */
 	if (!ximage)
 	    surface->use_pixmap = CAIRO_ASSUME_PIXMAP;
-    }
-    else
-    {
+    } else {
 	surface->use_pixmap--;
 	ximage = NULL;
     }
@@ -892,18 +876,18 @@ _get_image_surface (cairo_xlib_surface_t    *surface,
 
 	pixmap = XCreatePixmap (display->display,
 				surface->drawable,
-				extents.width, extents.height,
+				extents->width, extents->height,
 				surface->depth);
 	if (pixmap) {
 	    XCopyArea (display->display, surface->drawable, pixmap, gc,
-		       extents.x, extents.y,
-		       extents.width, extents.height,
+		       extents->x, extents->y,
+		       extents->width, extents->height,
 		       0, 0);
 
 	    ximage = XGetImage (display->display,
 				pixmap,
 				0, 0,
-				extents.width, extents.height,
+				extents->width, extents->height,
 				AllPlanes, ZPixmap);
 
 	    XFreePixmap (display->display, pixmap);
@@ -1016,8 +1000,8 @@ _get_image_surface (cairo_xlib_surface_t    *surface,
 	data = cairo_image_surface_get_data (&image->base);
 	rowstride = cairo_image_surface_get_stride (&image->base) >> 2;
 	row = (uint32_t *) data;
-	x0 = extents.x + surface->base.device_transform.x0;
-	y0 = extents.y + surface->base.device_transform.y0;
+	x0 = extents->x + surface->base.device_transform.x0;
+	y0 = extents->y + surface->base.device_transform.y0;
 	for (y = 0, y_off = y0 % ARRAY_LENGTH (dither_pattern);
 	     y < ximage->height;
 	     y++, y_off = (y_off+1) % ARRAY_LENGTH (dither_pattern)) {
@@ -1052,13 +1036,11 @@ _get_image_surface (cairo_xlib_surface_t    *surface,
     cairo_device_release (&display->base);
 
     if (unlikely (status)) {
-	if (image) {
-	    cairo_surface_destroy (&image->base);
-	    image = NULL;
-	}
+	cairo_surface_destroy (&image->base);
+	return _cairo_surface_create_in_error (status);
     }
-    *image_out = image;
-    return status;
+
+    return &image->base;
 }
 
 static void
@@ -1391,31 +1373,29 @@ _cairo_xlib_surface_acquire_source_image (void                    *abstract_surf
 					  void                   **image_extra)
 {
     cairo_xlib_surface_t *surface = abstract_surface;
-    cairo_image_surface_t *image;
-    cairo_status_t status;
+    cairo_rectangle_int_t extents;
 
-    status = _get_image_surface (surface, NULL, &image, NULL);
-    if (unlikely (status))
-	return status;
+    extents.x = extents.y = 0;
+    extents.width = surface->width;
+    extents.height = surface->width;
 
-    *image_out = image;
     *image_extra = NULL;
-
-    return CAIRO_STATUS_SUCCESS;
+    *image_out = (cairo_image_surface_t*)_get_image_surface (surface, &extents);
+    return (*image_out)->base.status;
 }
 
 static cairo_surface_t *
 _cairo_xlib_surface_snapshot (void *abstract_surface)
 {
     cairo_xlib_surface_t *surface = abstract_surface;
-    cairo_image_surface_t *image;
-    cairo_status_t status;
+    cairo_rectangle_int_t extents;
 
-    status = _get_image_surface (surface, NULL, &image, NULL);
-    if (unlikely (status))
-	return _cairo_surface_create_in_error (status);
+    extents.x = extents.y = 0;
+    extents.width = surface->width;
+    extents.height = surface->width;
 
-    return &image->base;
+    /* XXX notice the duplication */
+    return _get_image_surface (surface, &extents);
 }
 
 static void
@@ -1426,6 +1406,29 @@ _cairo_xlib_surface_release_source_image (void                   *abstract_surfa
     cairo_surface_destroy (&image->base);
 }
 
+static cairo_surface_t *
+_cairo_xlib_surface_map_to_image (void                    *abstract_surface,
+				  const cairo_rectangle_int_t   *extents)
+{
+    cairo_surface_t *image;
+
+    image = _get_image_surface (abstract_surface, extents);
+    cairo_surface_set_device_offset (image, -extents->y, -extents->y);
+
+    return image;
+}
+
+static cairo_int_status_t
+_cairo_xlib_surface_unmap_image (void *abstract_surface,
+				 cairo_image_surface_t *image)
+{
+    return _draw_image_surface (abstract_surface, image,
+				0, 0,
+				image->width, image->height,
+				image->base.device_transform_inverse.x0,
+				image->base.device_transform_inverse.y0);
+}
+
 static cairo_status_t
 _cairo_xlib_surface_acquire_dest_image (void                    *abstract_surface,
 					cairo_rectangle_int_t   *interest_rect,
@@ -1433,18 +1436,12 @@ _cairo_xlib_surface_acquire_dest_image (void                    *abstract_surfac
 					cairo_rectangle_int_t   *image_rect_out,
 					void                   **image_extra)
 {
-    cairo_xlib_surface_t *surface = abstract_surface;
-    cairo_image_surface_t *image;
-    cairo_status_t status;
-
-    status = _get_image_surface (surface, interest_rect, &image, image_rect_out);
-    if (unlikely (status))
-	return status;
-
-    *image_out = image;
+    if (image_rect_out)
+	*image_rect_out = *interest_rect;
     *image_extra = NULL;
-
-    return CAIRO_STATUS_SUCCESS;
+    *image_out = (cairo_image_surface_t *)
+	_get_image_surface (abstract_surface, interest_rect);
+    return (*image_out)->base.status;
 }
 
 static void
@@ -3138,12 +3135,18 @@ _cairo_xlib_surface_is_similar (void		*surface_a,
 
 static const cairo_surface_backend_t cairo_xlib_surface_backend = {
     CAIRO_SURFACE_TYPE_XLIB,
+    _cairo_xlib_surface_finish,
+
     _cairo_default_context_create,
 
     _cairo_xlib_surface_create_similar,
-    _cairo_xlib_surface_finish,
+    NULL, //_cairo_xlib_surface_create_similar_image, /* XXX shm */
+    _cairo_xlib_surface_map_to_image,
+    _cairo_xlib_surface_unmap_image,
+
     _cairo_xlib_surface_acquire_source_image,
     _cairo_xlib_surface_release_source_image,
+
     _cairo_xlib_surface_acquire_dest_image,
     _cairo_xlib_surface_release_dest_image,
     _cairo_xlib_surface_clone_similar,
diff --git a/src/cairo-xml-surface.c b/src/cairo-xml-surface.c
index 1a6b01d..d909a94 100644
--- a/src/cairo-xml-surface.c
+++ b/src/cairo-xml-surface.c
@@ -991,10 +991,14 @@ _cairo_xml_surface_glyphs (void			    *abstract_surface,
 static const cairo_surface_backend_t
 _cairo_xml_surface_backend = {
     CAIRO_SURFACE_TYPE_XML,
+    NULL,
     _cairo_default_context_create,
 
     _cairo_xml_surface_create_similar,
-    NULL,
+    NULL, /* create_similar_image */
+    NULL, /* map_to_image */
+    NULL, /* unmap_image */
+
     NULL, NULL, /* source image */
     NULL, NULL, /* dst image */
     NULL, /* clone_similar */
diff --git a/src/cairo.h b/src/cairo.h
index ba35de4..1eb30d7 100644
--- a/src/cairo.h
+++ b/src/cairo.h
@@ -354,6 +354,46 @@ typedef enum _cairo_content {
 } cairo_content_t;
 
 /**
+ * cairo_format_t:
+ * @CAIRO_FORMAT_INVALID: no such format exists or is supported.
+ * @CAIRO_FORMAT_ARGB32: each pixel is a 32-bit quantity, with
+ *   alpha in the upper 8 bits, then red, then green, then blue.
+ *   The 32-bit quantities are stored native-endian. Pre-multiplied
+ *   alpha is used. (That is, 50% transparent red is 0x80800000,
+ *   not 0x80ff0000.)
+ * @CAIRO_FORMAT_RGB24: each pixel is a 32-bit quantity, with
+ *   the upper 8 bits unused. Red, Green, and Blue are stored
+ *   in the remaining 24 bits in that order.
+ * @CAIRO_FORMAT_A8: each pixel is a 8-bit quantity holding
+ *   an alpha value.
+ * @CAIRO_FORMAT_A1: each pixel is a 1-bit quantity holding
+ *   an alpha value. Pixels are packed together into 32-bit
+ *   quantities. The ordering of the bits matches the
+ *   endianess of the platform. On a big-endian machine, the
+ *   first pixel is in the uppermost bit, on a little-endian
+ *   machine the first pixel is in the least-significant bit.
+ * @CAIRO_FORMAT_RGB16_565: each pixel is a 16-bit quantity
+ *   with red in the upper 5 bits, then green in the middle
+ *   6 bits, and blue in the lower 5 bits.
+ * @CAIRO_FORMAT_RGB30: like RGB24 but with 10bpc
+ *
+ * #cairo_format_t is used to identify the memory format of
+ * image data.
+ *
+ * New entries may be added in future versions.
+ **/
+typedef enum _cairo_format {
+    CAIRO_FORMAT_INVALID   = -1,
+    CAIRO_FORMAT_ARGB32    = 0,
+    CAIRO_FORMAT_RGB24     = 1,
+    CAIRO_FORMAT_A8        = 2,
+    CAIRO_FORMAT_A1        = 3,
+    CAIRO_FORMAT_RGB16_565 = 4,
+    CAIRO_FORMAT_RGB30     = 5
+} cairo_format_t;
+
+
+/**
  * cairo_write_func_t:
  * @closure: the output closure
  * @data: the buffer containing the data to write
@@ -2034,6 +2074,20 @@ cairo_surface_create_similar (cairo_surface_t  *other,
 			      int		height);
 
 cairo_public cairo_surface_t *
+cairo_surface_create_similar_image (cairo_surface_t  *other,
+				    cairo_format_t    format,
+				    int		width,
+				    int		height);
+
+cairo_public cairo_surface_t *
+cairo_surface_map_to_image (cairo_surface_t  *surface,
+			    const cairo_rectangle_t *extents);
+
+cairo_public void
+cairo_surface_unmap_image (cairo_surface_t *surface,
+			   cairo_surface_t *image);
+
+cairo_public cairo_surface_t *
 cairo_surface_create_for_rectangle (cairo_surface_t	*target,
                                     double		 x,
                                     double		 y,
@@ -2234,45 +2288,6 @@ cairo_surface_has_show_text_glyphs (cairo_surface_t *surface);
 
 /* Image-surface functions */
 
-/**
- * cairo_format_t:
- * @CAIRO_FORMAT_INVALID: no such format exists or is supported.
- * @CAIRO_FORMAT_ARGB32: each pixel is a 32-bit quantity, with
- *   alpha in the upper 8 bits, then red, then green, then blue.
- *   The 32-bit quantities are stored native-endian. Pre-multiplied
- *   alpha is used. (That is, 50% transparent red is 0x80800000,
- *   not 0x80ff0000.)
- * @CAIRO_FORMAT_RGB24: each pixel is a 32-bit quantity, with
- *   the upper 8 bits unused. Red, Green, and Blue are stored
- *   in the remaining 24 bits in that order.
- * @CAIRO_FORMAT_A8: each pixel is a 8-bit quantity holding
- *   an alpha value.
- * @CAIRO_FORMAT_A1: each pixel is a 1-bit quantity holding
- *   an alpha value. Pixels are packed together into 32-bit
- *   quantities. The ordering of the bits matches the
- *   endianess of the platform. On a big-endian machine, the
- *   first pixel is in the uppermost bit, on a little-endian
- *   machine the first pixel is in the least-significant bit.
- * @CAIRO_FORMAT_RGB16_565: each pixel is a 16-bit quantity
- *   with red in the upper 5 bits, then green in the middle
- *   6 bits, and blue in the lower 5 bits.
- * @CAIRO_FORMAT_RGB30: like RGB24 but with 10bpc
- *
- * #cairo_format_t is used to identify the memory format of
- * image data.
- *
- * New entries may be added in future versions.
- **/
-typedef enum _cairo_format {
-    CAIRO_FORMAT_INVALID   = -1,
-    CAIRO_FORMAT_ARGB32    = 0,
-    CAIRO_FORMAT_RGB24     = 1,
-    CAIRO_FORMAT_A8        = 2,
-    CAIRO_FORMAT_A1        = 3,
-    CAIRO_FORMAT_RGB16_565 = 4,
-    CAIRO_FORMAT_RGB30     = 5
-} cairo_format_t;
-
 cairo_public cairo_surface_t *
 cairo_image_surface_create (cairo_format_t	format,
 			    int			width,
diff --git a/src/cairoint.h b/src/cairoint.h
index a0ed444..3928eb0 100644
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -310,6 +310,10 @@ _cairo_rectangle_intersects (const cairo_rectangle_int_t *dst,
 	     src->y + (int) src->height <= dst->y);
 }
 
+cairo_private void
+_cairo_rectangle_int_from_double (cairo_rectangle_int_t *recti,
+				  const cairo_rectangle_t *rectf);
+
 /* Extends the dst rectangle to also contain src.
  * If one of the rectangles is empty, the result is undefined
  */
@@ -650,6 +654,9 @@ extern const cairo_private struct _cairo_font_face_backend _cairo_quartz_font_fa
 struct _cairo_surface_backend {
     cairo_surface_type_t type;
 
+    cairo_warn cairo_status_t
+    (*finish)			(void			*surface);
+
     cairo_t *
     (*create_context)		(void			*surface);
 
@@ -658,9 +665,18 @@ struct _cairo_surface_backend {
 				 cairo_content_t	 content,
 				 int			 width,
 				 int			 height);
+    cairo_surface_t *
+    (*create_similar_image)	(void			*surface,
+				 cairo_format_t		format,
+				 int			 width,
+				 int			 height);
 
-    cairo_warn cairo_status_t
-    (*finish)			(void			*surface);
+    cairo_surface_t *
+    (*map_to_image)		(void			*surface,
+				 const cairo_rectangle_int_t  *extents);
+    cairo_int_status_t
+    (*unmap_image)		(void			*surface,
+				 cairo_image_surface_t	*image);
 
     cairo_warn cairo_status_t
     (*acquire_source_image)	(void                    *abstract_surface,
@@ -1620,6 +1636,10 @@ _cairo_surface_create_similar_scratch (cairo_surface_t *other,
 				       int		height);
 
 cairo_private cairo_surface_t *
+_cairo_surface_create_for_rectangle_int (cairo_surface_t *target,
+					 cairo_rectangle_int_t *extents);
+
+cairo_private cairo_surface_t *
 _cairo_surface_create_similar_solid (cairo_surface_t	    *other,
 				     cairo_content_t	     content,
 				     int		     width,
diff --git a/src/test-fallback-surface.c b/src/test-fallback-surface.c
index 5695dc9..1dce221 100644
--- a/src/test-fallback-surface.c
+++ b/src/test-fallback-surface.c
@@ -208,10 +208,14 @@ _test_fallback_surface_get_extents (void		  *abstract_surface,
 
 static const cairo_surface_backend_t test_fallback_surface_backend = {
     CAIRO_INTERNAL_SURFACE_TYPE_TEST_FALLBACK,
+    _test_fallback_surface_finish,
     _cairo_default_context_create,
 
     _test_fallback_surface_create_similar,
-    _test_fallback_surface_finish,
+    NULL, /* create similar image */
+    NULL, /* map_to_image */
+    NULL, /* unmap_image */
+
     _test_fallback_surface_acquire_source_image,
     _test_fallback_surface_release_source_image,
     _test_fallback_surface_acquire_dest_image,
diff --git a/src/test-fallback16-surface.c b/src/test-fallback16-surface.c
index 2f4da5b..5ec501a 100644
--- a/src/test-fallback16-surface.c
+++ b/src/test-fallback16-surface.c
@@ -205,10 +205,14 @@ _test_fallback16_surface_get_extents (void		  *abstract_surface,
 
 static const cairo_surface_backend_t test_fallback16_surface_backend = {
     CAIRO_INTERNAL_SURFACE_TYPE_TEST_FALLBACK,
+    _test_fallback16_surface_finish,
     _cairo_default_context_create,
 
     _test_fallback16_surface_create_similar,
-    _test_fallback16_surface_finish,
+    NULL, /* create similar image */
+    NULL, /* map to image */
+    NULL, /* unmap image */
+
     _test_fallback16_surface_acquire_source_image,
     _test_fallback16_surface_release_source_image,
     _test_fallback16_surface_acquire_dest_image,
diff --git a/src/test-null-surface.c b/src/test-null-surface.c
index a71ce8b..1eae89c 100644
--- a/src/test-null-surface.c
+++ b/src/test-null-surface.c
@@ -134,10 +134,14 @@ _cairo_null_surface_has_show_text_glyphs (void *surface)
 
 static const cairo_surface_backend_t null_surface_backend = {
     CAIRO_INTERNAL_SURFACE_TYPE_NULL,
+    NULL, /* finish */
     _cairo_default_context_create,
 
     _cairo_null_surface_create_similar,
-    NULL, /* finish */
+    NULL, /* create similar image */
+    NULL, /* map_to_image */
+    NULL, /* unmap image */
+
     NULL, /* acquire_source_image */
     NULL, /* release_source_image */
     NULL, /* acquire_dest_image */
diff --git a/src/test-paginated-surface.c b/src/test-paginated-surface.c
index 7736282..1e95c5f 100644
--- a/src/test-paginated-surface.c
+++ b/src/test-paginated-surface.c
@@ -241,13 +241,17 @@ _test_paginated_surface_set_paginated_mode (void			*abstract_surface,
 
 static const cairo_surface_backend_t test_paginated_surface_backend = {
     CAIRO_INTERNAL_SURFACE_TYPE_TEST_PAGINATED,
+    _test_paginated_surface_finish,
     _cairo_default_context_create,
 
     /* Since we are a paginated user, we get to regard most of the
      * surface backend interface as historical cruft and ignore it. */
 
     NULL, /* create_similar */
-    _test_paginated_surface_finish,
+    NULL, /* create similar image */
+    NULL, /* map to image */
+    NULL, /* unmap image */
+
     NULL, /* acquire_source_image */
     NULL, /* release_source_image */
     NULL, /* acquire_dest_image */
diff --git a/src/test-wrapping-surface.c b/src/test-wrapping-surface.c
index cef7055..7552886 100644
--- a/src/test-wrapping-surface.c
+++ b/src/test-wrapping-surface.c
@@ -235,10 +235,14 @@ _test_wrapping_surface_show_text_glyphs (void			    *abstract_surface,
 
 static const cairo_surface_backend_t test_wrapping_surface_backend = {
     CAIRO_INTERNAL_SURFACE_TYPE_TEST_WRAPPING,
+    _test_wrapping_surface_finish,
     _cairo_default_context_create,
 
     _test_wrapping_surface_create_similar,
-    _test_wrapping_surface_finish,
+    NULL, /* create similar image */
+    NULL, /* map to image */
+    NULL, /* unmap image */
+
     _test_wrapping_surface_acquire_source_image,
     _test_wrapping_surface_release_source_image,
     NULL, NULL, /* dest_image */
diff --git a/test/Makefile.sources b/test/Makefile.sources
index d1658bb..783897d 100644
--- a/test/Makefile.sources
+++ b/test/Makefile.sources
@@ -167,6 +167,7 @@ test_sources = \
 	linear-uniform.c				\
 	long-dashed-lines.c				\
 	long-lines.c					\
+	map-to-image.c					\
 	mask.c						\
 	mask-alpha.c					\
 	mask-ctm.c					\
diff --git a/test/map-all-to-image.ref.png b/test/map-all-to-image.ref.png
new file mode 100644
index 0000000..c56d969
Binary files /dev/null and b/test/map-all-to-image.ref.png differ
diff --git a/test/map-bit-to-image.ref.png b/test/map-bit-to-image.ref.png
new file mode 100644
index 0000000..b42dcb6
Binary files /dev/null and b/test/map-bit-to-image.ref.png differ
diff --git a/test/map-to-image-fill.ref.png b/test/map-to-image-fill.ref.png
new file mode 100644
index 0000000..c2893e0
Binary files /dev/null and b/test/map-to-image-fill.ref.png differ
diff --git a/test/map-to-image.c b/test/map-to-image.c
new file mode 100644
index 0000000..8528fa0
--- /dev/null
+++ b/test/map-to-image.c
@@ -0,0 +1,126 @@
+/*
+ * Copyright © 2011 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Author: Chris Wilson <chris at chris-wilson.co.uk>
+ */
+
+#include "cairo-test.h"
+
+#define WIDTH	3
+#define HEIGHT	3
+
+/* A single, black pixel */
+static const uint32_t black_pixel = 0xff000000;
+
+static cairo_test_status_t
+all (cairo_t *cr, int width, int height)
+{
+    cairo_surface_t *surface;
+    uint8_t *data;
+    int stride;
+    int i, j;
+
+    /* Fill background white */
+    cairo_set_source_rgb (cr, 1, 1, 1);
+    cairo_paint (cr);
+
+    surface = cairo_surface_map_to_image (cairo_get_target (cr), NULL);
+    cairo_surface_flush (surface);
+    stride = cairo_image_surface_get_stride (surface);
+    data = cairo_image_surface_get_data (surface);
+    if (data) {
+	    for (j = 0; j < HEIGHT; j++)
+		    for (i = 0; i < WIDTH; i++)
+			    *(uint32_t *)(data + j * stride + 4*i) = black_pixel;
+    }
+    cairo_surface_mark_dirty (surface);
+    cairo_surface_unmap_image (cairo_get_target (cr), surface);
+
+    return CAIRO_TEST_SUCCESS;
+}
+
+static cairo_test_status_t
+bit (cairo_t *cr, int width, int height)
+{
+    cairo_surface_t *surface;
+    cairo_rectangle_t extents;
+    uint8_t *data;
+
+    extents.x = extents.y = extents.width = extents.height = 1;
+
+    /* Fill background white */
+    cairo_set_source_rgb (cr, 1, 1, 1);
+    cairo_paint (cr);
+
+    surface = cairo_surface_map_to_image (cairo_get_target (cr), &extents);
+    cairo_surface_flush (surface);
+    data = cairo_image_surface_get_data (surface);
+    if (data)
+	    *(uint32_t *)data = black_pixel;
+    cairo_surface_mark_dirty (surface);
+    cairo_surface_unmap_image (cairo_get_target (cr), surface);
+
+    return CAIRO_TEST_SUCCESS;
+}
+
+static cairo_test_status_t
+fill (cairo_t *cr, int width, int height)
+{
+    cairo_surface_t *surface;
+    cairo_rectangle_t extents;
+    cairo_t *cr2;
+
+    extents.x = extents.y = extents.width = extents.height = 1;
+
+    /* Fill background white */
+    cairo_set_source_rgb (cr, 1, 1, 1);
+    cairo_paint (cr);
+
+    surface = cairo_surface_map_to_image (cairo_get_target (cr), &extents);
+    cr2 = cairo_create (surface);
+    cairo_set_source_rgb (cr2, 1, 0, 0);
+    cairo_paint (cr2);
+    cairo_destroy (cr2);
+    cairo_surface_unmap_image (cairo_get_target (cr), surface);
+
+    return CAIRO_TEST_SUCCESS;
+}
+
+CAIRO_TEST (map_all_to_image,
+	    "Test maping a surface to an image and modifying it externally",
+	    "image", /* keywords */
+	    "target=raster", /* requirements */
+	    WIDTH, HEIGHT,
+	    NULL, all)
+CAIRO_TEST (map_bit_to_image,
+	    "Test maping a surface to an image and modifying it externally",
+	    "image", /* keywords */
+	    "target=raster", /* requirements */
+	    WIDTH, HEIGHT,
+	    NULL, bit)
+CAIRO_TEST (map_to_image_fill,
+	    "Test maping a surface to an image and modifying it externally",
+	    "image", /* keywords */
+	    "target=raster", /* requirements */
+	    WIDTH, HEIGHT,
+	    NULL, fill)
diff --git a/util/cairo-script/cairo-script-operators.c b/util/cairo-script/cairo-script-operators.c
index ef96e44..a45201f 100644
--- a/util/cairo-script/cairo-script-operators.c
+++ b/util/cairo-script/cairo-script-operators.c
@@ -3620,6 +3620,67 @@ _matrix (csi_t *ctx)
 }
 
 static csi_status_t
+_map_to_image (csi_t *ctx)
+{
+    csi_object_t obj;
+    csi_array_t *array;
+    csi_status_t status;
+    cairo_rectangle_t extents;
+    cairo_rectangle_t *r;
+    cairo_surface_t *surface;
+
+    check (2);
+
+    status = _csi_ostack_get_array (ctx, 0, &array);
+    if (_csi_unlikely (status))
+	return status;
+
+    status = _csi_ostack_get_surface (ctx, 1, &surface);
+    if (_csi_unlikely (status))
+	return status;
+
+    switch (array->stack.len) {
+    case 0:
+	r = NULL;
+    case 4:
+	extents.x = _csi_object_as_real (&array->stack.objects[0]);
+	extents.y = _csi_object_as_real (&array->stack.objects[1]);
+	extents.width = _csi_object_as_real (&array->stack.objects[2]);
+	extents.height = _csi_object_as_real (&array->stack.objects[3]);
+	r = &extents;
+	break;
+    default:
+	return _csi_error (CSI_STATUS_INVALID_SCRIPT);
+    }
+
+    obj.type = CSI_OBJECT_TYPE_SURFACE;
+    obj.datum.surface = cairo_surface_map_to_image (surface, r);
+    pop (2);
+    return push (&obj);
+}
+
+static csi_status_t
+_unmap_image (csi_t *ctx)
+{
+    cairo_surface_t *surface, *image;
+    csi_status_t status;
+
+    check (2);
+
+    status = _csi_ostack_get_surface (ctx, 0, &image);
+    if (_csi_unlikely (status))
+	return status;
+    status = _csi_ostack_get_surface (ctx, 1, &surface);
+    if (_csi_unlikely (status))
+	return status;
+
+    cairo_surface_unmap_image (surface, image);
+
+    pop (2);
+    return CSI_STATUS_SUCCESS;
+}
+
+static csi_status_t
 _mesh (csi_t *ctx)
 {
     csi_object_t obj;
@@ -5521,6 +5582,38 @@ _similar (csi_t *ctx)
 }
 
 static csi_status_t
+_similar_image (csi_t *ctx)
+{
+    csi_object_t obj;
+    long format;
+    double width, height;
+    cairo_surface_t *other;
+    csi_status_t status;
+
+    check (4);
+
+    status = _csi_ostack_get_number (ctx, 0, &height);
+    if (_csi_unlikely (status))
+	return status;
+    status = _csi_ostack_get_number (ctx, 1, &width);
+    if (_csi_unlikely (status))
+	return status;
+    status = _csi_ostack_get_integer (ctx, 2, &format);
+    if (_csi_unlikely (status))
+	return status;
+    status = _csi_ostack_get_surface (ctx, 3, &other);
+    if (_csi_unlikely (status))
+	return status;
+
+    obj.type = CSI_OBJECT_TYPE_SURFACE;
+    obj.datum.surface = cairo_surface_create_similar_image (other,
+							    format,
+							    width, height);
+    pop (4);
+    return push (&obj);
+}
+
+static csi_status_t
 _subsurface (csi_t *ctx)
 {
     csi_object_t obj;
@@ -6301,6 +6394,7 @@ _defs[] = {
     { "lt", _lt },
     { "m", _move_to },
     { "M", _rel_move_to },
+    { "map-to-image", _map_to_image },
     { "mark", _mark },
     { "mask", _mask },
     { "matrix", _matrix },
@@ -6381,6 +6475,7 @@ _defs[] = {
     { "show-text-glyphs", _show_text_glyphs },
     { "show-page", _show_page },
     { "similar", _similar },
+    { "similar-image", _similar_image },
     { "sin", NULL },
     { "sqrt", NULL },
     { "sub", _sub },
@@ -6399,6 +6494,7 @@ _defs[] = {
     { "true", _true },
     { "type", NULL },
     { "undef", _undef },
+    { "unmap-image", _unmap_image },
     { "unset", _unset },
     { "user-to-device", NULL },
     { "user-to-device-distance", NULL },
diff --git a/util/cairo-trace/trace.c b/util/cairo-trace/trace.c
index 9c59b1d..9337a3b 100644
--- a/util/cairo-trace/trace.c
+++ b/util/cairo-trace/trace.c
@@ -3511,6 +3511,98 @@ cairo_surface_create_similar (cairo_surface_t *other,
 }
 
 cairo_surface_t *
+cairo_surface_create_similar_image (cairo_surface_t *other,
+				    cairo_format_t format,
+				    int width, int height)
+{
+    cairo_surface_t *ret;
+
+    _enter_trace ();
+
+    ret = DLCALL (cairo_surface_create_similar_image,
+		  other, format, width, height);
+
+    _emit_line_info ();
+    if (other != NULL && _write_lock ()) {
+	Object *other_obj = _get_object(SURFACE, other);
+	Object *new_obj = _create_surface (ret);
+
+	if (other_obj->defined)
+	    _trace_printf ("s%ld ", other_obj->token);
+	else if (current_stack_depth == other_obj->operand + 1)
+	    _trace_printf ("dup ");
+	else
+	    _trace_printf ("%d index ",
+			   current_stack_depth - other_obj->operand - 1);
+	_trace_printf ("s%ld //%s %d %d similar-image %% s%ld\n",
+		       _get_surface_id (other),
+		       _format_to_string (format),
+		       width, height,
+		       new_obj->token);
+
+	_push_object (new_obj);
+	_write_unlock ();
+    }
+
+    _exit_trace ();
+    return ret;
+}
+
+cairo_surface_t *
+cairo_surface_map_to_image (cairo_surface_t *surface,
+			    const cairo_rectangle_t *extents)
+{
+    cairo_surface_t *ret;
+
+    _enter_trace ();
+
+    ret = DLCALL (cairo_surface_map_to_image, surface, extents);
+
+    _emit_line_info ();
+    if (_write_lock ()) {
+	Object *obj = _create_surface (ret);
+
+	if (extents) {
+	    _trace_printf ("[ %f %f %f %f ] map-to-image dup /s%ld exch def\n",
+			   extents->x, extents->y,
+			   extents->width,
+			   extents->height,
+			   obj->token);
+	    obj->width = extents->width;
+	    obj->height = extents->height;
+	} else {
+	    _trace_printf ("[ ] map-to-image dup /s%ld exch def\n",
+			   obj->token);
+	}
+	obj->defined = TRUE;
+	_push_object (obj);
+	_write_unlock ();
+    }
+
+    _exit_trace ();
+    return ret;
+}
+
+void
+cairo_surface_unmap_image (cairo_surface_t *surface,
+			   cairo_surface_t *image)
+{
+    _enter_trace ();
+
+    _emit_line_info ();
+    if (_write_lock ()) {
+	_trace_printf ("/s%ld /s%ld  unmap-image\n",
+		       _get_surface_id (surface),
+		       _get_surface_id (image));
+	_write_unlock ();
+    }
+
+    DLCALL (cairo_surface_unmap_image, surface, image);
+
+    _exit_trace ();
+}
+
+cairo_surface_t *
 cairo_surface_create_for_rectangle (cairo_surface_t *target,
                                     double x, double y,
                                     double width, double height)
commit c6812c6a3679c3b8b9584e119e0d7fd93e09ae49
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Tue Jul 26 12:00:53 2011 +0100

    rectangle: speed up the is-intersecting test.
    
    cut'n'paste before coffee.
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/src/cairoint.h b/src/cairoint.h
index d31d62a..a0ed444 100644
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -304,18 +304,10 @@ static inline cairo_bool_t
 _cairo_rectangle_intersects (const cairo_rectangle_int_t *dst,
 			     const cairo_rectangle_int_t *src)
 {
-    int v1, v2;
-
-    v1 = MAX (dst->x, src->x);
-    v2 = MIN (dst->x + (int) dst->width,  src->x + (int) src->width);
-
-    if (v1 >= v2)
-	return FALSE;
-
-    v1 = MAX (dst->y, src->y);
-    v2 = MIN (dst->y + (int) dst->height, src->y + (int) src->height);
-
-    return v1 < v2;
+    return !(src->x >= dst->x + (int) dst->width ||
+	     src->x + (int) src->width <= dst->x ||
+	     src->y >= dst->y + (int) dst->height ||
+	     src->y + (int) src->height <= dst->y);
 }
 
 /* Extends the dst rectangle to also contain src.


More information about the cairo-commit mailing list