[cairo-commit] src/cairo-clip.c src/cairo-directfb-surface.c src/cairo-glitz-surface.c src/cairo-image-surface.c src/cairoint.h src/cairo-pattern.c src/cairo-quartz-surface.c src/cairo-surface.c src/cairo-surface-fallback.c src/cairo-surface-fallback-private.h src/cairo-win32-private.h src/cairo-win32-surface.c src/cairo-xcb-surface.c src/cairo-xlib-surface.c src/test-fallback-surface.c test/Makefile.am

Chris Wilson ickle at kemper.freedesktop.org
Fri Sep 26 18:20:54 PDT 2008


 src/cairo-clip.c                     |    6 ++++++
 src/cairo-directfb-surface.c         |   14 +++++++++-----
 src/cairo-glitz-surface.c            |   10 ++++++++++
 src/cairo-image-surface.c            |    3 +++
 src/cairo-pattern.c                  |   15 +++++++++++++--
 src/cairo-quartz-surface.c           |   10 +++++++++-
 src/cairo-surface-fallback-private.h |    2 ++
 src/cairo-surface-fallback.c         |    8 ++++++--
 src/cairo-surface.c                  |   24 ++++++++++++++++++------
 src/cairo-win32-private.h            |    2 ++
 src/cairo-win32-surface.c            |    8 ++++++--
 src/cairo-xcb-surface.c              |   18 ++++++++++++++----
 src/cairo-xlib-surface.c             |   21 +++++++++++++++------
 src/cairoint.h                       |   11 +++++++++--
 src/test-fallback-surface.c          |    4 ++++
 test/Makefile.am                     |    1 -
 16 files changed, 126 insertions(+), 31 deletions(-)

New commits:
commit 5b97ee65259cafb335c1a2c53f1a55dfcb175e20
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Sat Sep 27 00:18:07 2008 +0100

    Allow cloning sub-regions of similar surfaces.
    
    Previously the rule for clone_similar() was that the returned surface
    had exactly the same size as the original, but only the contents within
    the region of interest needed to be copied. This caused failures for very
    large images in the xlib-backend (see test/large-source).
    
    The obvious solution to allow cloning only the region of interest seemed
    to be to simply set the device offset on the cloned surface. However, this
    fails as a) nothing respects the device offset on the surface at that
    layer in the compositing stack and b) possibly returning references to the
    original source surface provides further confusion by mixing in another
    source of device offset.
    
    The second method was to add extra out parameters so that the
    device offset could be returned separately and, for example, mixed into
    the pattern matrix. Not as elegant, a couple of extra warts to the
    interface, but it works - one less XFAIL...

diff --git a/src/cairo-clip.c b/src/cairo-clip.c
index cff8e40..308da32 100644
--- a/src/cairo-clip.c
+++ b/src/cairo-clip.c
@@ -690,16 +690,22 @@ _cairo_clip_init_deep_copy (cairo_clip_t    *clip,
         }
 
         if (other->surface) {
+	    int dx, dy;
             status = _cairo_surface_clone_similar (target, other->surface,
 					           0,
 						   0,
 						   other->surface_rect.width,
 						   other->surface_rect.height,
+						   &dx, &dy,
 						   &clip->surface);
 	    if (status)
 		goto BAIL;
 
             clip->surface_rect = other->surface_rect;
+
+	    /* src offset was 0, so we expect an exact replica of the surface */
+	    assert (dx == 0);
+	    assert (dy == 0);
         }
 
         if (other->path) {
diff --git a/src/cairo-directfb-surface.c b/src/cairo-directfb-surface.c
index ecfc0f4..c24320b 100644
--- a/src/cairo-directfb-surface.c
+++ b/src/cairo-directfb-surface.c
@@ -616,6 +616,8 @@ _cairo_directfb_surface_clone_similar (void             *abstract_surface,
                                        int               src_y,
                                        int               width,
                                        int               height,
+                                       int              *device_offset_x,
+                                       int              *device_offset_y,
                                        cairo_surface_t **clone_out)
 {
     cairo_directfb_surface_t *surface = abstract_surface;
@@ -625,9 +627,10 @@ _cairo_directfb_surface_clone_similar (void             *abstract_surface,
                 "%s( surface=%p, src=%p ).\n", __FUNCTION__, surface, src);
 
     if (src->backend == surface->base.backend) {
-        cairo_surface_reference (src);
-        *clone_out = src;
-         
+	*device_offset_x = 0;
+	*device_offset_y = 0;
+	*clone_out = cairo_surface_reference (src);
+
         return CAIRO_STATUS_SUCCESS;
     }
     else if (_cairo_surface_is_image (src)) {
@@ -685,9 +688,10 @@ _cairo_directfb_surface_clone_similar (void             *abstract_surface,
         }
         
         clone->dfbsurface->Unlock (clone->dfbsurface);
-        
+
+	*device_offset_x = 0;
+	*device_offset_y = 0;
         *clone_out = &clone->base;
-                
         return CAIRO_STATUS_SUCCESS;
     }
     
diff --git a/src/cairo-glitz-surface.c b/src/cairo-glitz-surface.c
index d067e28..4d05e62 100644
--- a/src/cairo-glitz-surface.c
+++ b/src/cairo-glitz-surface.c
@@ -511,6 +511,8 @@ _cairo_glitz_surface_clone_similar (void	    *abstract_surface,
 				    int              src_y,
 				    int              width,
 				    int              height,
+				    int              *device_offset_x,
+				    int              *device_offset_y,
 				    cairo_surface_t **clone_out)
 {
     cairo_glitz_surface_t *surface = abstract_surface;
@@ -522,6 +524,8 @@ _cairo_glitz_surface_clone_similar (void	    *abstract_surface,
 
     if (src->backend == surface->base.backend)
     {
+	*device_offset_x = 0;
+	*device_offset_y = 0;
 	*clone_out = cairo_surface_reference (src);
 
 	return CAIRO_STATUS_SUCCESS;
@@ -2244,6 +2248,7 @@ _cairo_glitz_surface_old_show_glyphs (cairo_scaled_font_t *scaled_font,
 	    if (!glyph_private || !glyph_private->area)
 	    {
 		int glyph_width, glyph_height;
+		int device_offset_x, device_offset_y;
 
 		image = &scaled_glyphs[i]->surface->base;
 		glyph_width = scaled_glyphs[i]->surface->width;
@@ -2255,11 +2260,16 @@ _cairo_glitz_surface_old_show_glyphs (cairo_scaled_font_t *scaled_font,
 							0,
 							glyph_width,
 							glyph_height,
+							&device_offset_x,
+							&device_offset_y
 							(cairo_surface_t **)
 							&clone);
 		if (status)
 		    goto UNLOCK;
 
+		assert (device_offset_x = 0);
+		assert (device_offset_y = 0);
+
 		x_offset = scaled_glyphs[i]->surface->base.device_transform.x0;
 		y_offset = scaled_glyphs[i]->surface->base.device_transform.y0;
 		x1 = _cairo_lround (glyphs[i].x - x_offset);
diff --git a/src/cairo-image-surface.c b/src/cairo-image-surface.c
index 297c947..7a42966 100644
--- a/src/cairo-image-surface.c
+++ b/src/cairo-image-surface.c
@@ -779,11 +779,14 @@ _cairo_image_surface_clone_similar (void		*abstract_surface,
 				    int                  src_y,
 				    int                  width,
 				    int                  height,
+				    int                 *device_offset_x,
+				    int                 *device_offset_y,
 				    cairo_surface_t    **clone_out)
 {
     cairo_image_surface_t *surface = abstract_surface;
 
     if (src->backend == surface->base.backend) {
+	*device_offset_x = *device_offset_y = 0;
 	*clone_out = cairo_surface_reference (src);
 
 	return CAIRO_STATUS_SUCCESS;
diff --git a/src/cairo-pattern.c b/src/cairo-pattern.c
index 60b1c2b..b6db8cf 100644
--- a/src/cairo-pattern.c
+++ b/src/cairo-pattern.c
@@ -1247,6 +1247,7 @@ _cairo_pattern_acquire_surface_for_gradient (cairo_gradient_pattern_t *pattern,
     pixman_gradient_stop_t pixman_stops_static[2];
     pixman_gradient_stop_t *pixman_stops = pixman_stops_static;
     unsigned int i;
+    int device_offset_x, device_offset_y;
 
     if (pattern->n_stops > ARRAY_LENGTH(pixman_stops_static)) {
 	pixman_stops = _cairo_malloc_ab (pattern->n_stops, sizeof(pixman_gradient_stop_t));
@@ -1396,7 +1397,10 @@ _cairo_pattern_acquire_surface_for_gradient (cairo_gradient_pattern_t *pattern,
     pixman_image_unref (pixman_image);
 
     status = _cairo_surface_clone_similar (dst, &image->base,
-					   0, 0, width, height, out);
+					   0, 0, width, height,
+					   &device_offset_x,
+					   &device_offset_y,
+					   out);
 
     cairo_surface_destroy (&image->base);
 
@@ -1829,7 +1833,14 @@ _cairo_pattern_acquire_surface_for_surface (cairo_surface_pattern_t   *pattern,
 	}
 
 	status = _cairo_surface_clone_similar (dst, pattern->surface,
-					       x, y, width, height, out);
+					       x, y, width, height,
+					       &x, &y, out);
+	if (status == CAIRO_STATUS_SUCCESS && (x != 0 || y != 0)) {
+	    cairo_matrix_t m;
+
+	    cairo_matrix_init_translate (&m, -x, -y);
+	    cairo_matrix_multiply (&attr->matrix, &attr->matrix, &m);
+	}
     }
 
     return status;
diff --git a/src/cairo-quartz-surface.c b/src/cairo-quartz-surface.c
index 52cd691..13c6d72 100644
--- a/src/cairo-quartz-surface.c
+++ b/src/cairo-quartz-surface.c
@@ -1580,6 +1580,8 @@ _cairo_quartz_surface_clone_similar (void *abstract_surface,
 				     int              src_y,
 				     int              width,
 				     int              height,
+				     int             *device_offset_x,
+				     int             *device_offset_y,
 				     cairo_surface_t **clone_out)
 {
     cairo_quartz_surface_t *new_surface = NULL;
@@ -1598,6 +1600,8 @@ _cairo_quartz_surface_clone_similar (void *abstract_surface,
 	*clone_out = (cairo_surface_t*)
 	    _cairo_quartz_surface_create_internal (NULL, CAIRO_CONTENT_COLOR_ALPHA,
 						   width, height);
+	*device_offset_x = 0;
+	*device_offset_y = 0;
 	return CAIRO_STATUS_SUCCESS;
     }
 
@@ -1608,6 +1612,8 @@ _cairo_quartz_surface_clone_similar (void *abstract_surface,
 	    *clone_out = (cairo_surface_t*)
 		_cairo_quartz_surface_create_internal (NULL, CAIRO_CONTENT_COLOR_ALPHA,
 						       qsurf->extents.width, qsurf->extents.height);
+	    *device_offset_x = 0;
+	    *device_offset_y = 0;
 	    return CAIRO_STATUS_SUCCESS;
 	}
     }
@@ -1646,7 +1652,9 @@ _cairo_quartz_surface_clone_similar (void *abstract_surface,
 
     CGImageRelease (quartz_image);
 
-FINISH:    
+FINISH:
+    *device_offset_x = src_x;
+    *device_offset_y = src_y;
     *clone_out = (cairo_surface_t*) new_surface;
 
     return CAIRO_STATUS_SUCCESS;
diff --git a/src/cairo-surface-fallback-private.h b/src/cairo-surface-fallback-private.h
index 82c5625..a4a05dc 100644
--- a/src/cairo-surface-fallback-private.h
+++ b/src/cairo-surface-fallback-private.h
@@ -124,6 +124,8 @@ _cairo_surface_fallback_clone_similar (cairo_surface_t  *surface,
 				       int               src_y,
 				       int               width,
 				       int               height,
+				       int              *device_offset_x,
+				       int              *device_offset_y,
 				       cairo_surface_t **clone_out);
 
 #endif
diff --git a/src/cairo-surface-fallback.c b/src/cairo-surface-fallback.c
index dc96a04..056ea4e 100644
--- a/src/cairo-surface-fallback.c
+++ b/src/cairo-surface-fallback.c
@@ -1251,6 +1251,8 @@ _cairo_surface_fallback_clone_similar (cairo_surface_t	*surface,
 				       int		 src_y,
 				       int		 width,
 				       int		 height,
+				       int		*device_offset_x,
+				       int		*device_offset_y,
 				       cairo_surface_t **clone_out)
 {
     cairo_status_t status;
@@ -1280,9 +1282,11 @@ _cairo_surface_fallback_clone_similar (cairo_surface_t	*surface,
     status = cairo_status (cr);
     cairo_destroy (cr);
 
-    if (status == CAIRO_STATUS_SUCCESS)
+    if (status == CAIRO_STATUS_SUCCESS) {
+	*device_offset_x = src_x;
+	*device_offset_y = src_y;
 	*clone_out = new_surface;
-    else
+    } else
 	cairo_surface_destroy (new_surface);
 
     return status;
diff --git a/src/cairo-surface.c b/src/cairo-surface.c
index df6659d..6ca877b 100644
--- a/src/cairo-surface.c
+++ b/src/cairo-surface.c
@@ -1127,6 +1127,8 @@ _cairo_surface_clone_similar (cairo_surface_t  *surface,
 			      int               src_y,
 			      int               width,
 			      int               height,
+			      int              *device_offset_x,
+			      int              *device_offset_y,
 			      cairo_surface_t **clone_out)
 {
     cairo_status_t status = CAIRO_INT_STATUS_UNSUPPORTED;
@@ -1140,8 +1142,12 @@ _cairo_surface_clone_similar (cairo_surface_t  *surface,
 	return _cairo_error (CAIRO_STATUS_SURFACE_FINISHED);
 
     if (surface->backend->clone_similar) {
-	status = surface->backend->clone_similar (surface, src, src_x, src_y,
-						  width, height, clone_out);
+	status = surface->backend->clone_similar (surface, src,
+						  src_x, src_y,
+						  width, height,
+						  device_offset_x,
+						  device_offset_y,
+						  clone_out);
 
 	if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
 	    /* If we failed, try again with an image surface */
@@ -1151,6 +1157,8 @@ _cairo_surface_clone_similar (cairo_surface_t  *surface,
 		    surface->backend->clone_similar (surface, &image->base,
 						     src_x, src_y,
 						     width, height,
+						     device_offset_x,
+						     device_offset_y,
 						     clone_out);
 
 		_cairo_surface_release_source_image (src, image, image_extra);
@@ -1161,8 +1169,12 @@ _cairo_surface_clone_similar (cairo_surface_t  *surface,
     /* If we're still unsupported, hit our fallback path to get a clone */
     if (status == CAIRO_INT_STATUS_UNSUPPORTED)
 	status =
-	    _cairo_surface_fallback_clone_similar (surface, src, src_x, src_y,
-						   width, height, clone_out);
+	    _cairo_surface_fallback_clone_similar (surface, src,
+						   src_x, src_y,
+						   width, height,
+						   device_offset_x,
+						   device_offset_y,
+						   clone_out);
 
     /* We should never get UNSUPPORTED here, so if we have an error, bail. */
     if (status)
@@ -1171,8 +1183,8 @@ _cairo_surface_clone_similar (cairo_surface_t  *surface,
     /* Update the clone's device_transform (which the underlying surface
      * backend knows nothing about) */
     if (*clone_out != src) {
-        (*clone_out)->device_transform = src->device_transform;
-        (*clone_out)->device_transform_inverse = src->device_transform_inverse;
+	(*clone_out)->device_transform = src->device_transform;
+	(*clone_out)->device_transform_inverse = src->device_transform_inverse;
     }
 
     return status;
diff --git a/src/cairo-win32-private.h b/src/cairo-win32-private.h
index 8cbea87..dd05a2d 100644
--- a/src/cairo-win32-private.h
+++ b/src/cairo-win32-private.h
@@ -160,6 +160,8 @@ _cairo_win32_surface_clone_similar (void *abstract_surface,
 				    int src_y,
 				    int width,
 				    int height,
+				    int *device_offset_x,
+				    int *device_offset_y,
 				    cairo_surface_t **clone_out);
 
 static inline void
diff --git a/src/cairo-win32-surface.c b/src/cairo-win32-surface.c
index 395d818..883441c 100644
--- a/src/cairo-win32-surface.c
+++ b/src/cairo-win32-surface.c
@@ -443,6 +443,8 @@ _cairo_win32_surface_clone_similar (void *abstract_surface,
 				    int src_y,
 				    int width,
 				    int height,
+				    int *device_offset_x,
+				    int *device_offset_y,
 				    cairo_surface_t **clone_out)
 {
     cairo_content_t src_content;
@@ -470,9 +472,11 @@ _cairo_win32_surface_clone_similar (void *abstract_surface,
 
     _cairo_pattern_fini (&pattern.base);
 
-    if (status == CAIRO_STATUS_SUCCESS)
+    if (status == CAIRO_STATUS_SUCCESS) {
+	*device_offset_x = src_x;
+	*device_offset_y = src_y;
 	*clone_out = new_surface;
-    else
+    } else
 	cairo_surface_destroy (new_surface);
 
     return status;
diff --git a/src/cairo-xcb-surface.c b/src/cairo-xcb-surface.c
index 7251824..7aa80bd 100644
--- a/src/cairo-xcb-surface.c
+++ b/src/cairo-xcb-surface.c
@@ -695,6 +695,8 @@ _cairo_xcb_surface_clone_similar (void			*abstract_surface,
 				  int                    src_y,
 				  int                    width,
 				  int                    height,
+				  int                   *device_offset_x,
+				  int                   *device_offset_y,
 				  cairo_surface_t     **clone_out)
 {
     cairo_xcb_surface_t *surface = abstract_surface;
@@ -704,6 +706,8 @@ _cairo_xcb_surface_clone_similar (void			*abstract_surface,
 	cairo_xcb_surface_t *xcb_src = (cairo_xcb_surface_t *)src;
 
 	if (_cairo_xcb_surface_same_screen(surface, xcb_src)) {
+	    *device_offset_x = 0;
+	    *device_offset_y = 0;
 	    *clone_out = cairo_surface_reference (src);
 
 	    return CAIRO_STATUS_SUCCESS;
@@ -716,14 +720,20 @@ _cairo_xcb_surface_clone_similar (void			*abstract_surface,
 	    return surface->base.status;
 
 	clone = (cairo_xcb_surface_t *)
-	    _cairo_xcb_surface_create_similar (surface, content,
-					       image_src->width, image_src->height);
+	    _cairo_xcb_surface_create_similar (surface, content, width, height);
 	if (clone->base.status)
 	    return clone->base.status;
 
-	_draw_image_surface (clone, image_src, src_x, src_y,
-			     width, height, src_x, src_y);
+	status = _draw_image_surface (clone, image_src,
+		                      src_x, src_y,
+		                      width, height, x, y);
+	if (status) {
+	    cairo_surface_destroy (&clone->base);
+	    return status;
+	}
 
+	*device_offset_x = src_x;
+	*device_offset_y = src_y;
 	*clone_out = &clone->base;
 
 	return CAIRO_STATUS_SUCCESS;
diff --git a/src/cairo-xlib-surface.c b/src/cairo-xlib-surface.c
index 9da13f9..ed534c1 100644
--- a/src/cairo-xlib-surface.c
+++ b/src/cairo-xlib-surface.c
@@ -1134,6 +1134,8 @@ _cairo_xlib_surface_clone_similar (void			*abstract_surface,
 				   int                   src_y,
 				   int                   width,
 				   int                   height,
+				   int                  *device_offset_x,
+				   int                  *device_offset_y,
 				   cairo_surface_t     **clone_out)
 {
     cairo_xlib_surface_t *surface = abstract_surface;
@@ -1146,6 +1148,8 @@ _cairo_xlib_surface_clone_similar (void			*abstract_surface,
 	cairo_xlib_surface_t *xlib_src = (cairo_xlib_surface_t *)src;
 
 	if (_cairo_xlib_surface_same_screen (surface, xlib_src)) {
+	    *device_offset_x = 0;
+	    *device_offset_y = 0;
 	    *clone_out = cairo_surface_reference (src);
 
 	    return CAIRO_STATUS_SUCCESS;
@@ -1156,25 +1160,30 @@ _cairo_xlib_surface_clone_similar (void			*abstract_surface,
 	if (! CAIRO_FORMAT_VALID (image_src->format))
 	    return CAIRO_INT_STATUS_UNSUPPORTED;
 
-	if (image_src->width > XLIB_COORD_MAX || image_src->height > XLIB_COORD_MAX)
-	    return CAIRO_STATUS_NO_MEMORY;
+	if (width > XLIB_COORD_MAX || height > XLIB_COORD_MAX)
+	    return _cairo_error (CAIRO_STATUS_NO_MEMORY);
 
 	clone = (cairo_xlib_surface_t *)
-	    _cairo_xlib_surface_create_similar_with_format (surface, image_src->format,
-						image_src->width, image_src->height);
+	    _cairo_xlib_surface_create_similar_with_format (surface,
+		                                            image_src->format,
+							    width, height);
 	if (clone == NULL)
 	    return CAIRO_INT_STATUS_UNSUPPORTED;
 
 	if (clone->base.status)
 	    return clone->base.status;
 
-	status = _draw_image_surface (clone, image_src, src_x, src_y,
-			              width, height, src_x, src_y);
+	status = _draw_image_surface (clone, image_src,
+				      src_x, src_y,
+			              width, height,
+				      0, 0);
 	if (status) {
 	    cairo_surface_destroy (&clone->base);
 	    return status;
 	}
 
+	*device_offset_x = src_x;
+	*device_offset_y = src_y;
 	*clone_out = &clone->base;
 
 	return CAIRO_STATUS_SUCCESS;
diff --git a/src/cairoint.h b/src/cairoint.h
index 4929db6..b55a05f 100644
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -551,9 +551,12 @@ struct _cairo_surface_backend {
      * 1. It is as compatible as possible with @surface (in terms of
      *    efficiency)
      *
-     * 2. It has the same size as @src
+     * 2. It has the same contents as @src within the given rectangle.
      *
-     * 3. It has the same contents as @src within the given rectangle.
+     * 3. The offset of the similar surface with respect to the original
+     *    surface is returned in the device transform vector.
+     *    - if you clone the entire surface, this vector is zero.
+     *    - if you clone (src_x, src_y)x(w, h) the vector is (src_x, src_y);
      */
     cairo_warn cairo_status_t
     (*clone_similar)            (void                   *surface,
@@ -562,6 +565,8 @@ struct _cairo_surface_backend {
 				 int                     src_y,
 				 int                     width,
 				 int                     height,
+				 int                    *device_offset_x,
+				 int                    *device_offset_y,
 				 cairo_surface_t       **clone_out);
 
     /* XXX: dst should be the first argument for consistency */
@@ -1819,6 +1824,8 @@ _cairo_surface_clone_similar (cairo_surface_t  *surface,
 			      int               src_y,
 			      int               width,
 			      int               height,
+			      int              *device_offset_x,
+			      int              *device_offset_y,
 			      cairo_surface_t **clone_out);
 
 cairo_private cairo_surface_t *
diff --git a/src/test-fallback-surface.c b/src/test-fallback-surface.c
index e720e88..94f352f 100644
--- a/src/test-fallback-surface.c
+++ b/src/test-fallback-surface.c
@@ -176,11 +176,15 @@ _test_fallback_surface_clone_similar (void		  *abstract_surface,
 				      int                  src_y,
 				      int                  width,
 				      int                  height,
+				      int                 *device_offset_x,
+				      int                 *device_offset_y,
 				      cairo_surface_t    **clone_out)
 {
     test_fallback_surface_t *surface = abstract_surface;
 
     if (src->backend == surface->base.backend) {
+	*device_offset_x = 0;
+	*device_offset_y = 0;
 	*clone_out = cairo_surface_reference (src);
 
 	return CAIRO_STATUS_SUCCESS;
diff --git a/test/Makefile.am b/test/Makefile.am
index 9f3c0f1..df9a9f2 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -908,7 +908,6 @@ device-offset-scale$(EXEEXT)			\
 extend-pad$(EXEEXT)				\
 filter-nearest-offset$(EXEEXT)			\
 filter-bilinear-extents$(EXEEXT)		\
-large-source$(EXEEXT)				\
 long-lines$(EXEEXT)				\
 miter-precision$(EXEEXT)			\
 operator$(EXEEXT)				\


More information about the cairo-commit mailing list