diff --git a/src/cairo-clip.c b/src/cairo-clip.c index cff8e40c9..308da326c 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 ecfc0f494..c24320b59 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 d067e28b6..4d05e629d 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 297c94728..7a4296638 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 60b1c2b14..b6db8cf1f 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 52cd69156..13c6d728d 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 82c56256b..a4a05dc70 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 dc96a041a..056ea4eca 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 df6659d88..6ca877b28 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 8cbea8782..dd05a2df6 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 395d818d7..883441c41 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 7251824b8..7aa80bdd7 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 9da13f928..ed534c123 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 4929db670..b55a05fd0 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 e720e88ec..94f352f21 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 9f3c0f13b..df9a9f2af 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) \