summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris Wilson <chris@chris-wilson.co.uk>2011-08-14 00:25:15 +0100
committerChris Wilson <chris@chris-wilson.co.uk>2011-08-14 12:37:57 +0100
commit8a90b22897b6460b3396b9959383131039bd9ce2 (patch)
tree74752284a1a523a81b1d33634601655022fd82ba
parent7971c678f18b9a078dc921e8c9a9d8175038cd1c (diff)
subsurface+recording: handle recursion
Ouch, a nasty bug surfaces after rearranging code to fix the others. Another self-copy loop this time through a subsurface of a recording surface. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
-rw-r--r--src/cairo-recording-surface.c111
-rw-r--r--src/cairo-script-surface.c129
-rw-r--r--src/cairo-surface-snapshot.c12
-rw-r--r--src/cairo-surface-subsurface.c105
4 files changed, 238 insertions, 119 deletions
diff --git a/src/cairo-recording-surface.c b/src/cairo-recording-surface.c
index eb12624d..1b00c725 100644
--- a/src/cairo-recording-surface.c
+++ b/src/cairo-recording-surface.c
@@ -528,35 +528,118 @@ _cairo_recording_surface_acquire_source_image_transformed (void *abstract_s
return CAIRO_STATUS_SUCCESS;
}
+struct proxy {
+ cairo_surface_t base;
+ cairo_surface_t *image;
+};
+
+static cairo_status_t
+proxy_acquire_source_image (void *abstract_surface,
+ cairo_image_surface_t **image_out,
+ void **image_extra)
+{
+ struct proxy *proxy = abstract_surface;
+ return _cairo_surface_acquire_source_image (proxy->image, image_out, image_extra);
+}
+
+static void
+proxy_release_source_image (void *abstract_surface,
+ cairo_image_surface_t *image,
+ void *image_extra)
+{
+ struct proxy *proxy = abstract_surface;
+ _cairo_surface_release_source_image (proxy->image, image, image_extra);
+}
+
+static cairo_status_t
+proxy_finish (void *abstract_surface)
+{
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static const cairo_surface_backend_t proxy_backend = {
+ CAIRO_INTERNAL_SURFACE_TYPE_NULL,
+ proxy_finish,
+ NULL,
+
+ NULL, /* create similar */
+ NULL, /* create similar image */
+ NULL, /* map to image */
+ NULL, /* unmap image */
+
+ proxy_acquire_source_image,
+ proxy_release_source_image,
+};
+
+static cairo_surface_t *
+attach_proxy (cairo_surface_t *source,
+ cairo_surface_t *image)
+{
+ struct proxy *proxy;
+
+ proxy = malloc (sizeof (*proxy));
+ if (unlikely (proxy == NULL))
+ return _cairo_surface_create_in_error (CAIRO_STATUS_NO_MEMORY);
+
+ _cairo_surface_init (&proxy->base, &proxy_backend, NULL, image->content);
+
+ proxy->image = image;
+ _cairo_surface_attach_snapshot (source, &proxy->base, NULL);
+
+ return &proxy->base;
+}
+
+static void
+detach_proxy (cairo_surface_t *source,
+ cairo_surface_t *proxy)
+{
+ cairo_surface_finish (proxy);
+ cairo_surface_destroy (proxy);
+}
+
+static cairo_surface_t *
+get_proxy (cairo_surface_t *proxy)
+{
+ return ((struct proxy *)proxy)->image;
+}
+
static cairo_status_t
_cairo_recording_surface_acquire_source_image (void *abstract_surface,
cairo_image_surface_t **image_out,
void **image_extra)
{
- cairo_matrix_t identity;
- cairo_surface_t *image;
+ cairo_recording_surface_t *surface = abstract_surface;
+ cairo_surface_t *image, *proxy;
cairo_status_t status;
- image = _cairo_surface_has_snapshot (abstract_surface,
- &_cairo_image_surface_backend);
- if (image != NULL) {
- *image_out = (cairo_image_surface_t *) cairo_surface_reference (image);
+ proxy = _cairo_surface_has_snapshot (abstract_surface, &proxy_backend);
+ if (proxy != NULL) {
+ *image_out = (cairo_image_surface_t *)
+ cairo_surface_reference (get_proxy (proxy));
*image_extra = NULL;
return CAIRO_STATUS_SUCCESS;
}
- cairo_matrix_init_identity (&identity);
+ assert (! surface->unbounded);
+ image = _cairo_image_surface_create_with_content (surface->base.content,
+ surface->extents.width,
+ surface->extents.height);
+ if (unlikely (image->status))
+ return image->status;
- status =
- _cairo_recording_surface_acquire_source_image_transformed (abstract_surface, &identity, image_out, image_extra);
- if (unlikely (status))
+ /* Handle recursion by returning future reads from the current image */
+ proxy = attach_proxy (abstract_surface, image);
+ status = _cairo_recording_surface_replay (&surface->base, image);
+ detach_proxy (abstract_surface, proxy);
+
+ if (unlikely (status)) {
+ cairo_surface_destroy (image);
return status;
+ }
- _cairo_surface_attach_snapshot (abstract_surface,
- &(*image_out)->base,
- NULL);
+ *image_out = (cairo_image_surface_t *) image;
+ *image_extra = NULL;
return CAIRO_STATUS_SUCCESS;
-
}
static void
diff --git a/src/cairo-script-surface.c b/src/cairo-script-surface.c
index 2724f8f9..a93b0caf 100644
--- a/src/cairo-script-surface.c
+++ b/src/cairo-script-surface.c
@@ -1035,20 +1035,77 @@ _emit_mesh_pattern (cairo_script_surface_t *surface,
return CAIRO_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 ",
+ surface->base.unique_id);
+
+ _cairo_surface_attach_snapshot (source, &surface->base, detach_snapshot);
+ cairo_surface_destroy (&surface->base);
+}
+
static cairo_status_t
_emit_recording_surface_pattern (cairo_script_surface_t *surface,
cairo_recording_surface_t *source)
{
cairo_script_implicit_context_t old_cr;
+ cairo_script_context_t *ctx = to_context (surface);
cairo_script_surface_t *similar;
+ cairo_surface_t *snapshot;
cairo_rectangle_t r, *extents;
cairo_status_t status;
+ snapshot = _cairo_surface_has_snapshot (&source->base, &script_snapshot_backend);
+ if (snapshot) {
+ _cairo_output_stream_printf (ctx->stream, "s%d", snapshot->unique_id);
+ return CAIRO_INT_STATUS_SUCCESS;
+ }
+
extents = NULL;
if (_cairo_recording_surface_get_bounds (&source->base, &r))
extents = &r;
- similar = _cairo_script_surface_create_internal (to_context (surface),
+ similar = _cairo_script_surface_create_internal (ctx,
source->base.content,
extents,
NULL);
@@ -1057,21 +1114,24 @@ _emit_recording_surface_pattern (cairo_script_surface_t *surface,
similar->base.is_clear = TRUE;
- _cairo_output_stream_printf (to_context (surface)->stream,
- "//%s ",
+ _cairo_output_stream_printf (ctx->stream, "//%s ",
_content_to_string (source->base.content));
if (extents) {
- _cairo_output_stream_printf (to_context (surface)->stream,
- "[%f %f %f %f]",
+ _cairo_output_stream_printf (ctx->stream, "[%f %f %f %f]",
extents->x, extents->y,
extents->width, extents->height);
} else
- _cairo_output_stream_puts (to_context (surface)->stream, "[]");
- _cairo_output_stream_puts (to_context (surface)->stream,
- " record dup context\n");
+ _cairo_output_stream_puts (ctx->stream, "[]");
+ _cairo_output_stream_puts (ctx->stream, " record\n");
+
+ attach_snapshot (ctx, &source->base);
+
+ _cairo_output_stream_puts (ctx->stream, "dup context\n");
+
target_push (similar);
similar->emitted = TRUE;
+
old_cr = surface->cr;
_cairo_script_implicit_context_init (&surface->cr);
status = _cairo_recording_surface_replay (&source->base, &similar->base);
@@ -1085,7 +1145,7 @@ _emit_recording_surface_pattern (cairo_script_surface_t *surface,
cairo_list_del (&similar->operand.link);
assert (target_is_active (surface));
- _cairo_output_stream_puts (to_context (surface)->stream, "pop ");
+ _cairo_output_stream_puts (ctx->stream, "pop ");
cairo_surface_destroy (&similar->base);
return CAIRO_STATUS_SUCCESS;
@@ -1497,55 +1557,6 @@ _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)
@@ -1563,7 +1574,7 @@ _emit_surface_pattern (cairo_script_surface_t *surface,
snapshot = _cairo_surface_has_snapshot (source, &script_snapshot_backend);
if (snapshot) {
_cairo_output_stream_printf (ctx->stream,
- "s%d pattern",
+ "s%d pattern ",
snapshot->unique_id);
return CAIRO_INT_STATUS_SUCCESS;
}
diff --git a/src/cairo-surface-snapshot.c b/src/cairo-surface-snapshot.c
index 1e6455e8..adaf7e4c 100644
--- a/src/cairo-surface-snapshot.c
+++ b/src/cairo-surface-snapshot.c
@@ -60,6 +60,15 @@ _cairo_surface_snapshot_finish (void *abstract_surface)
}
static cairo_status_t
+_cairo_surface_snapshot_flush (void *abstract_surface)
+{
+ cairo_surface_snapshot_t *surface = abstract_surface;
+
+ cairo_surface_flush (surface->target);
+ return surface->target->status;
+}
+
+static cairo_status_t
_cairo_surface_snapshot_acquire_source_image (void *abstract_surface,
cairo_image_surface_t **image_out,
void **extra_out)
@@ -110,6 +119,9 @@ static const cairo_surface_backend_t _cairo_surface_snapshot_backend = {
NULL, /* copy_page */
NULL, /* show_page */
_cairo_surface_snapshot_get_extents,
+ NULL, /* old-show-glyphs */
+ NULL, /* get-font-options */
+ _cairo_surface_snapshot_flush,
};
static void
diff --git a/src/cairo-surface-subsurface.c b/src/cairo-surface-subsurface.c
index 2fa55401..b57c97b7 100644
--- a/src/cairo-surface-subsurface.c
+++ b/src/cairo-surface-subsurface.c
@@ -39,6 +39,7 @@
#include "cairo-image-surface-private.h"
#include "cairo-recording-surface-private.h"
#include "cairo-surface-offset-private.h"
+#include "cairo-surface-snapshot-private.h"
#include "cairo-surface-subsurface-private.h"
static const cairo_surface_backend_t _cairo_surface_subsurface_backend;
@@ -290,24 +291,6 @@ struct extra {
void *image_extra;
};
-static void
-cairo_surface_paint_to_target (cairo_surface_t *target,
- cairo_surface_subsurface_t *subsurface)
-{
- cairo_t *cr;
-
- cr = cairo_create (target);
-
- cairo_set_source_surface (cr,
- subsurface->target,
- - subsurface->extents.x,
- - subsurface->extents.y);
- cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
- cairo_paint (cr);
-
- cairo_destroy (cr);
-}
-
static cairo_status_t
_cairo_surface_subsurface_acquire_source_image (void *abstract_surface,
cairo_image_surface_t **image_out,
@@ -322,8 +305,7 @@ _cairo_surface_subsurface_acquire_source_image (void *abstrac
cairo_bool_t ret;
if (surface->target->type == CAIRO_SURFACE_TYPE_RECORDING) {
- cairo_recording_surface_t *meta = (cairo_recording_surface_t *) surface->target;
- cairo_surface_t *snapshot;
+ cairo_surface_t *meta, *snapshot;
snapshot = _cairo_surface_has_snapshot (&surface->base,
&_cairo_image_surface_backend);
@@ -333,17 +315,32 @@ _cairo_surface_subsurface_acquire_source_image (void *abstrac
return CAIRO_STATUS_SUCCESS;
}
- if (! _cairo_surface_has_snapshot (&meta->base,
- &_cairo_image_surface_backend))
- {
+ meta = surface->target;
+ if (surface->target->backend->type == CAIRO_INTERNAL_SURFACE_TYPE_SNAPSHOT)
+ meta = _cairo_surface_snapshot_get_target (meta);
+
+ if (! _cairo_surface_has_snapshot (meta, &_cairo_image_surface_backend)) {
+ cairo_surface_pattern_t pattern;
+
image = (cairo_image_surface_t *)
- _cairo_image_surface_create_with_content (meta->base.content,
+ _cairo_image_surface_create_with_content (meta->content,
surface->extents.width,
surface->extents.height);
if (unlikely (image->base.status))
return image->base.status;
- cairo_surface_paint_to_target (&image->base, surface);
+ _cairo_pattern_init_for_surface (&pattern, &image->base);
+ cairo_matrix_init_translate (&pattern.base.matrix,
+ -surface->extents.x, -surface->extents.y);
+ pattern.base.filter = CAIRO_FILTER_NEAREST;
+ status = _cairo_surface_paint (&image->base,
+ CAIRO_OPERATOR_SOURCE,
+ &pattern.base, NULL);
+ _cairo_pattern_fini (&pattern.base);
+ if (unlikely (status)) {
+ cairo_surface_destroy (&image->base);
+ return status;
+ }
_cairo_surface_attach_snapshot (&surface->base, &image->base, NULL);
@@ -387,6 +384,8 @@ _cairo_surface_subsurface_acquire_source_image (void *abstrac
image->base.is_clear = FALSE;
} else {
+ cairo_surface_pattern_t pattern;
+
image = (cairo_image_surface_t *)
_cairo_image_surface_create_with_pixman_format (NULL,
extra->image->pixman_format,
@@ -396,7 +395,18 @@ _cairo_surface_subsurface_acquire_source_image (void *abstrac
if (unlikely ((status = image->base.status)))
goto CLEANUP_IMAGE;
- cairo_surface_paint_to_target (&image->base, surface);
+ _cairo_pattern_init_for_surface (&pattern, &image->base);
+ cairo_matrix_init_translate (&pattern.base.matrix,
+ -surface->extents.x, -surface->extents.y);
+ pattern.base.filter = CAIRO_FILTER_NEAREST;
+ status = _cairo_surface_paint (&image->base,
+ CAIRO_OPERATOR_SOURCE,
+ &pattern.base, NULL);
+ _cairo_pattern_fini (&pattern.base);
+ if (unlikely (status)) {
+ cairo_surface_destroy (&image->base);
+ return status;
+ }
}
*image_out = image;
@@ -431,29 +441,32 @@ static cairo_surface_t *
_cairo_surface_subsurface_snapshot (void *abstract_surface)
{
cairo_surface_subsurface_t *surface = abstract_surface;
- cairo_surface_subsurface_t *snapshot;
-
- snapshot = malloc (sizeof (cairo_surface_subsurface_t));
- if (unlikely (snapshot == NULL))
- return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
+ cairo_surface_pattern_t pattern;
+ cairo_surface_t *clone;
+ cairo_status_t status;
- _cairo_surface_init (&snapshot->base,
- &_cairo_surface_subsurface_backend,
- NULL, /* device */
- surface->target->content);
- snapshot->target = _cairo_surface_snapshot (surface->target);
- if (unlikely (snapshot->target->status)) {
- cairo_status_t status;
-
- status = snapshot->target->status;
- free (snapshot);
- return _cairo_surface_create_in_error (status);
+ clone = _cairo_surface_create_similar_scratch (surface->target,
+ surface->target->content,
+ surface->extents.width,
+ surface->extents.height);
+ if (unlikely (clone->status))
+ return clone;
+
+ _cairo_pattern_init_for_surface (&pattern, surface->target);
+ cairo_matrix_init_translate (&pattern.base.matrix,
+ -surface->extents.x, -surface->extents.y);
+ pattern.base.filter = CAIRO_FILTER_NEAREST;
+ status = _cairo_surface_paint (clone,
+ CAIRO_OPERATOR_SOURCE,
+ &pattern.base, NULL);
+ _cairo_pattern_fini (&pattern.base);
+
+ if (unlikely (status)) {
+ cairo_surface_destroy (clone);
+ clone = _cairo_surface_create_in_error (status);
}
- snapshot->base.type = snapshot->target->type;
- snapshot->extents = surface->extents;
-
- return &snapshot->base;
+ return clone;
}
static cairo_t *