mirror of
https://gitlab.freedesktop.org/cairo/cairo.git
synced 2026-01-21 20:04:46 +01:00
snapshot: Defer acquisition
Fixes 'xlib-expose-event' but triggers an infinite loop in self-copy. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
This commit is contained in:
parent
79aa04fd50
commit
99fa5ff6c2
7 changed files with 181 additions and 93 deletions
|
|
@ -41,6 +41,7 @@
|
|||
#include "cairo-error-private.h"
|
||||
#include "cairo-paginated-private.h"
|
||||
#include "cairo-recording-surface-private.h"
|
||||
#include "cairo-surface-snapshot-private.h"
|
||||
#include "cairo-surface-subsurface-private.h"
|
||||
#include "cairo-region-private.h"
|
||||
|
||||
|
|
@ -119,6 +120,8 @@ _analyze_recording_surface_pattern (cairo_analysis_surface_t *surface,
|
|||
surface->has_ctm = ! _cairo_matrix_is_identity (&surface->ctm);
|
||||
|
||||
source = surface_pattern->surface;
|
||||
if (source->backend->type == CAIRO_INTERNAL_SURFACE_TYPE_SNAPSHOT)
|
||||
source = _cairo_surface_snapshot_get_target (source);
|
||||
if (source->backend->type == CAIRO_SURFACE_TYPE_SUBSURFACE) {
|
||||
cairo_surface_subsurface_t *sub = (cairo_surface_subsurface_t *) source;
|
||||
source = sub->target;
|
||||
|
|
|
|||
|
|
@ -737,6 +737,36 @@ _cairo_image_surface_create_similar (void *abstract_other,
|
|||
width, height);
|
||||
}
|
||||
|
||||
static cairo_surface_t *
|
||||
_cairo_image_surface_snapshot (void *abstract_surface)
|
||||
{
|
||||
cairo_image_surface_t *image = abstract_surface;
|
||||
cairo_image_surface_t *clone;
|
||||
|
||||
clone = (cairo_image_surface_t *)
|
||||
_cairo_image_surface_create_with_pixman_format (NULL,
|
||||
image->pixman_format,
|
||||
image->width,
|
||||
image->height,
|
||||
0);
|
||||
if (unlikely (clone->base.status))
|
||||
return &clone->base;
|
||||
|
||||
if (clone->stride == image->stride) {
|
||||
memcpy (clone->data, image->data, clone->stride * clone->height);
|
||||
} else {
|
||||
pixman_image_composite32 (PIXMAN_OP_SRC,
|
||||
image->pixman_image, NULL, clone->pixman_image,
|
||||
0, 0,
|
||||
0, 0,
|
||||
0, 0,
|
||||
image->width, image->height);
|
||||
}
|
||||
clone->base.is_clear = FALSE;
|
||||
return &clone->base;
|
||||
}
|
||||
|
||||
|
||||
static cairo_surface_t *
|
||||
_cairo_image_surface_map_to_image (void *abstract_other,
|
||||
const cairo_rectangle_int_t *extents)
|
||||
|
|
@ -4823,8 +4853,7 @@ const cairo_surface_backend_t _cairo_image_surface_backend = {
|
|||
_cairo_image_surface_stroke,
|
||||
_cairo_image_surface_fill,
|
||||
_cairo_image_surface_glyphs,
|
||||
NULL, /* show_text_glyphs */
|
||||
NULL, /* snapshot */
|
||||
_cairo_image_surface_snapshot,
|
||||
NULL, /* is_similar */
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -56,6 +56,7 @@
|
|||
#include "cairo-paginated-private.h"
|
||||
#include "cairo-scaled-font-subsets-private.h"
|
||||
#include "cairo-surface-clipper-private.h"
|
||||
#include "cairo-surface-snapshot-private.h"
|
||||
#include "cairo-surface-subsurface-private.h"
|
||||
#include "cairo-type3-glyph-surface-private.h"
|
||||
|
||||
|
|
@ -1110,9 +1111,13 @@ _get_source_surface_size (cairo_surface_t *source,
|
|||
*height = sub->extents.height;
|
||||
|
||||
} else {
|
||||
cairo_recording_surface_t *recording_surface = (cairo_recording_surface_t *) source;
|
||||
cairo_recording_surface_t *recording_surface;
|
||||
cairo_box_t bbox;
|
||||
|
||||
if (source->backend->type == CAIRO_INTERNAL_SURFACE_TYPE_SNAPSHOT)
|
||||
source = _cairo_surface_snapshot_get_target (source);
|
||||
|
||||
recording_surface = (cairo_recording_surface_t *) source;
|
||||
status = _cairo_recording_surface_get_bbox (recording_surface, &bbox, NULL);
|
||||
if (unlikely (status))
|
||||
return status;
|
||||
|
|
@ -2366,7 +2371,7 @@ BAIL:
|
|||
|
||||
static cairo_status_t
|
||||
_cairo_pdf_surface_emit_recording_surface (cairo_pdf_surface_t *surface,
|
||||
cairo_surface_t *recording_surface,
|
||||
cairo_surface_t *source,
|
||||
cairo_pdf_resource_t resource)
|
||||
{
|
||||
double old_width, old_height;
|
||||
|
|
@ -2376,7 +2381,11 @@ _cairo_pdf_surface_emit_recording_surface (cairo_pdf_surface_t *surface,
|
|||
cairo_int_status_t status;
|
||||
int alpha = 0;
|
||||
|
||||
is_bounded = _cairo_surface_get_extents (recording_surface, &recording_extents);
|
||||
if (source->backend->type == CAIRO_INTERNAL_SURFACE_TYPE_SNAPSHOT)
|
||||
source = _cairo_surface_snapshot_get_target (source);
|
||||
|
||||
is_bounded = _cairo_surface_get_extents (source,
|
||||
&recording_extents);
|
||||
assert (is_bounded);
|
||||
|
||||
old_width = surface->width;
|
||||
|
|
@ -2396,7 +2405,7 @@ _cairo_pdf_surface_emit_recording_surface (cairo_pdf_surface_t *surface,
|
|||
if (unlikely (status))
|
||||
return status;
|
||||
|
||||
if (cairo_surface_get_content (recording_surface) == CAIRO_CONTENT_COLOR) {
|
||||
if (cairo_surface_get_content (source) == CAIRO_CONTENT_COLOR) {
|
||||
status = _cairo_pdf_surface_add_alpha (surface, 1.0, &alpha);
|
||||
if (unlikely (status))
|
||||
return status;
|
||||
|
|
@ -2408,7 +2417,7 @@ _cairo_pdf_surface_emit_recording_surface (cairo_pdf_surface_t *surface,
|
|||
surface->height);
|
||||
}
|
||||
|
||||
status = _cairo_recording_surface_replay_region (recording_surface,
|
||||
status = _cairo_recording_surface_replay_region (source,
|
||||
NULL,
|
||||
&surface->base,
|
||||
CAIRO_RECORDING_REGION_NATIVE);
|
||||
|
|
|
|||
|
|
@ -1280,6 +1280,31 @@ _undef (void *data)
|
|||
free (def);
|
||||
}
|
||||
|
||||
static cairo_status_t
|
||||
attach_undef_tag (cairo_script_context_t *ctx, cairo_surface_t *surface)
|
||||
{
|
||||
struct def *tag;
|
||||
cairo_status_t status;
|
||||
|
||||
tag = malloc (sizeof (*tag));
|
||||
if (unlikely (tag == NULL))
|
||||
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
|
||||
|
||||
tag->ctx = ctx;
|
||||
tag->tag = surface->unique_id;
|
||||
tag->user_data = &surface->user_data;
|
||||
cairo_list_add (&tag->link, &ctx->defines);
|
||||
status = _cairo_user_data_array_set_data (&surface->user_data,
|
||||
(cairo_user_data_key_t *) ctx,
|
||||
tag, _undef);
|
||||
if (unlikely (status)) {
|
||||
free (tag);
|
||||
return status;
|
||||
}
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static cairo_int_status_t
|
||||
_emit_image_surface (cairo_script_surface_t *surface,
|
||||
cairo_image_surface_t *image)
|
||||
|
|
@ -1290,7 +1315,6 @@ _emit_image_surface (cairo_script_surface_t *surface,
|
|||
cairo_int_status_t status, status2;
|
||||
const uint8_t *mime_data;
|
||||
unsigned long mime_data_length;
|
||||
struct def *tag;
|
||||
|
||||
if (_cairo_user_data_array_get_data (&image->base.user_data,
|
||||
(cairo_user_data_key_t *) ctx))
|
||||
|
|
@ -1384,21 +1408,9 @@ _emit_image_surface (cairo_script_surface_t *surface,
|
|||
cairo_surface_destroy (&clone->base);
|
||||
}
|
||||
|
||||
tag = malloc (sizeof (*tag));
|
||||
if (unlikely (tag == NULL))
|
||||
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
|
||||
|
||||
tag->ctx = ctx;
|
||||
tag->tag = image->base.unique_id;
|
||||
tag->user_data = &image->base.user_data;
|
||||
cairo_list_add (&tag->link, &ctx->defines);
|
||||
status = _cairo_user_data_array_set_data (&image->base.user_data,
|
||||
(cairo_user_data_key_t *) ctx,
|
||||
tag, _undef);
|
||||
if (unlikely (status)) {
|
||||
free (tag);
|
||||
status = attach_undef_tag (ctx, &image->base);
|
||||
if (unlikely (status))
|
||||
return status;
|
||||
}
|
||||
|
||||
_cairo_output_stream_printf (ctx->stream,
|
||||
"dup /s%u exch def ",
|
||||
|
|
@ -1443,21 +1455,15 @@ static cairo_int_status_t
|
|||
_emit_image_surface_pattern (cairo_script_surface_t *surface,
|
||||
cairo_surface_t *source)
|
||||
{
|
||||
cairo_surface_t *snapshot;
|
||||
cairo_image_surface_t *image;
|
||||
cairo_status_t status;
|
||||
void *extra;
|
||||
|
||||
/* XXX keeping a copy is nasty, but we want to hook into the surface's
|
||||
* lifetime. Using a snapshot is a convenient method.
|
||||
*/
|
||||
snapshot = _cairo_surface_snapshot (source);
|
||||
status = _cairo_surface_acquire_source_image (snapshot, &image, &extra);
|
||||
status = _cairo_surface_acquire_source_image (source, &image, &extra);
|
||||
if (likely (status == CAIRO_STATUS_SUCCESS)) {
|
||||
status = _emit_image_surface (surface, image);
|
||||
_cairo_surface_release_source_image (snapshot, image, extra);
|
||||
_cairo_surface_release_source_image (source, image, extra);
|
||||
}
|
||||
cairo_surface_destroy (snapshot);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
|
@ -1492,19 +1498,82 @@ _emit_subsurface_pattern (cairo_script_surface_t *surface,
|
|||
return CAIRO_INT_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
struct script_snapshot {
|
||||
cairo_surface_t base;
|
||||
};
|
||||
|
||||
static cairo_status_t
|
||||
script_snapshot_finish (void *abstract_surface)
|
||||
{
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static const cairo_surface_backend_t script_snapshot_backend = {
|
||||
CAIRO_SURFACE_TYPE_SCRIPT,
|
||||
script_snapshot_finish,
|
||||
};
|
||||
|
||||
static void
|
||||
detach_snapshot (cairo_surface_t *abstract_surface)
|
||||
{
|
||||
cairo_script_surface_t *surface = (cairo_script_surface_t *)abstract_surface;
|
||||
cairo_script_context_t *ctx = to_context (surface);
|
||||
|
||||
_cairo_output_stream_printf (ctx->stream,
|
||||
"/s%d undef\n ",
|
||||
surface->base.unique_id);
|
||||
}
|
||||
|
||||
static void
|
||||
attach_snapshot (cairo_script_context_t *ctx,
|
||||
cairo_surface_t *source)
|
||||
{
|
||||
struct script_snapshot *surface;
|
||||
|
||||
surface = malloc (sizeof (*surface));
|
||||
if (unlikely (surface == NULL))
|
||||
return;
|
||||
|
||||
_cairo_surface_init (&surface->base,
|
||||
&script_snapshot_backend,
|
||||
&ctx->base,
|
||||
source->content);
|
||||
|
||||
_cairo_output_stream_printf (ctx->stream,
|
||||
"dup /s%d exch def\n ",
|
||||
surface->base.unique_id);
|
||||
|
||||
_cairo_surface_attach_snapshot (source, &surface->base, detach_snapshot);
|
||||
cairo_surface_destroy (&surface->base);
|
||||
}
|
||||
|
||||
static cairo_int_status_t
|
||||
_emit_surface_pattern (cairo_script_surface_t *surface,
|
||||
const cairo_pattern_t *pattern)
|
||||
{
|
||||
cairo_script_context_t *ctx = to_context (surface);
|
||||
cairo_surface_pattern_t *surface_pattern;
|
||||
cairo_surface_t *source;
|
||||
cairo_surface_t *source, *snapshot;
|
||||
cairo_surface_t *take_snapshot = NULL;
|
||||
cairo_int_status_t status;
|
||||
|
||||
surface_pattern = (cairo_surface_pattern_t *) pattern;
|
||||
source = surface_pattern->surface;
|
||||
|
||||
if (source->backend->type == CAIRO_INTERNAL_SURFACE_TYPE_SNAPSHOT)
|
||||
source = ((cairo_surface_snapshot_t *) source)->target;
|
||||
if (source->backend->type == CAIRO_INTERNAL_SURFACE_TYPE_SNAPSHOT) {
|
||||
snapshot = _cairo_surface_has_snapshot (source, &script_snapshot_backend);
|
||||
if (snapshot) {
|
||||
_cairo_output_stream_printf (ctx->stream,
|
||||
"s%d pattern",
|
||||
snapshot->unique_id);
|
||||
return CAIRO_INT_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
if (_cairo_surface_snapshot_is_reused (source))
|
||||
take_snapshot = source;
|
||||
|
||||
source = _cairo_surface_snapshot_get_target (source);
|
||||
}
|
||||
|
||||
switch ((int) source->backend->type) {
|
||||
case CAIRO_SURFACE_TYPE_RECORDING:
|
||||
|
|
@ -1523,7 +1592,10 @@ _emit_surface_pattern (cairo_script_surface_t *surface,
|
|||
if (unlikely (status))
|
||||
return status;
|
||||
|
||||
_cairo_output_stream_puts (to_context (surface)->stream, "pattern");
|
||||
if (take_snapshot)
|
||||
attach_snapshot (ctx, take_snapshot);
|
||||
|
||||
_cairo_output_stream_puts (ctx->stream, "pattern");
|
||||
return CAIRO_INT_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
|
@ -1797,6 +1869,8 @@ _emit_path (cairo_script_surface_t *surface,
|
|||
double x2 = _cairo_fixed_to_double (box.p2.x);
|
||||
double y2 = _cairo_fixed_to_double (box.p2.y);
|
||||
|
||||
assert (x1 > -9999);
|
||||
|
||||
_cairo_output_stream_printf (ctx->stream,
|
||||
" %f %f %f %f rectangle",
|
||||
x1, y1, x2 - x1, y2 - y1);
|
||||
|
|
|
|||
|
|
@ -45,4 +45,16 @@ struct _cairo_surface_snapshot {
|
|||
cairo_surface_t *clone;
|
||||
};
|
||||
|
||||
static inline cairo_bool_t
|
||||
_cairo_surface_snapshot_is_reused (cairo_surface_t *surface)
|
||||
{
|
||||
return CAIRO_REFERENCE_COUNT_GET_VALUE (&surface->ref_count) > 2;
|
||||
}
|
||||
|
||||
static inline cairo_surface_t *
|
||||
_cairo_surface_snapshot_get_target (cairo_surface_t *surface)
|
||||
{
|
||||
return ((cairo_surface_snapshot_t *) surface)->target;
|
||||
}
|
||||
|
||||
#endif /* CAIRO_SURFACE_SNAPSHOT_PRIVATE_H */
|
||||
|
|
|
|||
|
|
@ -117,7 +117,7 @@ _cairo_surface_snapshot_copy_on_write (cairo_surface_t *surface)
|
|||
{
|
||||
cairo_surface_snapshot_t *snapshot = (cairo_surface_snapshot_t *) surface;
|
||||
cairo_image_surface_t *image;
|
||||
cairo_image_surface_t *clone;
|
||||
cairo_surface_t *clone;
|
||||
void *extra;
|
||||
cairo_status_t status;
|
||||
|
||||
|
|
@ -127,41 +127,26 @@ _cairo_surface_snapshot_copy_on_write (cairo_surface_t *surface)
|
|||
* been lost.
|
||||
*/
|
||||
|
||||
if (snapshot->target->backend->snapshot != NULL) {
|
||||
clone = snapshot->target->backend->snapshot (snapshot->target);
|
||||
if (clone != NULL)
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* XXX copy to a similar surface, leave acquisition till later? */
|
||||
status = _cairo_surface_acquire_source_image (snapshot->target, &image, &extra);
|
||||
if (unlikely (status)) {
|
||||
snapshot->target = _cairo_surface_create_in_error (status);
|
||||
status = _cairo_surface_set_error (surface, status);
|
||||
return;
|
||||
}
|
||||
|
||||
clone = (cairo_image_surface_t *)
|
||||
_cairo_image_surface_create_with_pixman_format (NULL,
|
||||
image->pixman_format,
|
||||
image->width,
|
||||
image->height,
|
||||
0);
|
||||
if (likely (clone->base.status == CAIRO_STATUS_SUCCESS)) {
|
||||
if (clone->stride == image->stride) {
|
||||
memcpy (clone->data, image->data, image->stride * image->height);
|
||||
} else {
|
||||
pixman_image_composite32 (PIXMAN_OP_SRC,
|
||||
image->pixman_image, NULL, clone->pixman_image,
|
||||
0, 0,
|
||||
0, 0,
|
||||
0, 0,
|
||||
image->width, image->height);
|
||||
}
|
||||
clone->base.is_clear = FALSE;
|
||||
|
||||
snapshot->clone = &clone->base;
|
||||
} else {
|
||||
snapshot->clone = &clone->base;
|
||||
status = _cairo_surface_set_error (surface, clone->base.status);
|
||||
}
|
||||
|
||||
clone = image->base.backend->snapshot (&image->base);
|
||||
_cairo_surface_release_source_image (snapshot->target, image, extra);
|
||||
snapshot->target = snapshot->clone;
|
||||
snapshot->base.type = snapshot->target->type;
|
||||
|
||||
done:
|
||||
status = _cairo_surface_set_error (surface, clone->status);
|
||||
snapshot->target = snapshot->clone = clone;
|
||||
snapshot->base.type = clone->type;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -192,38 +177,14 @@ _cairo_surface_snapshot (cairo_surface_t *surface)
|
|||
if (unlikely (surface->status))
|
||||
return _cairo_surface_create_in_error (surface->status);
|
||||
|
||||
if (surface->finished)
|
||||
if (unlikely (surface->finished))
|
||||
return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_SURFACE_FINISHED));
|
||||
|
||||
if (surface->snapshot_of != NULL)
|
||||
return cairo_surface_reference (surface);
|
||||
|
||||
if (surface->backend->snapshot != NULL) {
|
||||
cairo_surface_t *snap;
|
||||
|
||||
snap = _cairo_surface_has_snapshot (surface, surface->backend);
|
||||
if (snap != NULL)
|
||||
return cairo_surface_reference (snap);
|
||||
|
||||
snap = surface->backend->snapshot (surface);
|
||||
if (snap != NULL) {
|
||||
if (unlikely (snap->status))
|
||||
return snap;
|
||||
|
||||
status = _cairo_surface_copy_mime_data (snap, surface);
|
||||
if (unlikely (status)) {
|
||||
cairo_surface_destroy (snap);
|
||||
return _cairo_surface_create_in_error (status);
|
||||
}
|
||||
|
||||
snap->device_transform = surface->device_transform;
|
||||
snap->device_transform_inverse = surface->device_transform_inverse;
|
||||
|
||||
_cairo_surface_attach_snapshot (surface, snap, NULL);
|
||||
|
||||
return snap;
|
||||
}
|
||||
}
|
||||
if (surface->backend == &_cairo_surface_snapshot_backend)
|
||||
return cairo_surface_reference (surface);
|
||||
|
||||
snapshot = (cairo_surface_snapshot_t *)
|
||||
_cairo_surface_has_snapshot (surface, &_cairo_surface_snapshot_backend);
|
||||
|
|
|
|||
|
|
@ -328,12 +328,12 @@ _cairo_surface_detach_snapshot (cairo_surface_t *snapshot)
|
|||
{
|
||||
assert (snapshot->snapshot_of != NULL);
|
||||
|
||||
snapshot->snapshot_of = NULL;
|
||||
cairo_list_del (&snapshot->snapshot);
|
||||
|
||||
if (snapshot->snapshot_detach != NULL)
|
||||
snapshot->snapshot_detach (snapshot);
|
||||
|
||||
snapshot->snapshot_of = NULL;
|
||||
cairo_list_del (&snapshot->snapshot);
|
||||
|
||||
cairo_surface_destroy (snapshot);
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue