mirror of
https://gitlab.freedesktop.org/cairo/cairo.git
synced 2025-12-29 04:30:11 +01:00
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...
This commit is contained in:
parent
7f3a48f90b
commit
5b97ee6525
16 changed files with 126 additions and 31 deletions
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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 *
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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) \
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue