summaryrefslogtreecommitdiff
path: root/src/cairo-surface-subsurface.c
diff options
context:
space:
mode:
authorChris Wilson <chris@chris-wilson.co.uk>2010-04-28 14:26:21 +0100
committerChris Wilson <chris@chris-wilson.co.uk>2010-04-30 10:16:24 +0100
commit8ded35fd69ed0bbb07359c0278071a25af66571c (patch)
treee6b44acf234b3399306240600c29f470e6045e92 /src/cairo-surface-subsurface.c
parent5fc04bba9fa8ddda8cf7d7a97015f21a21429172 (diff)
downloadcairo-8ded35fd69ed0bbb07359c0278071a25af66571c.tar.gz
ps: Enable native encoding of subsurface patterns.
Carefully handle subsurfaces of a recording surface through the analysis and paginated surfaces so that we can generate a native pattern for the vector backends, demonstrated by the PostScript backend. Nothing remarkable, just a lot of bookkeeping to track the wrapped surface types and to apply the correct offsets when generating the subsurface pattern.
Diffstat (limited to 'src/cairo-surface-subsurface.c')
-rw-r--r--src/cairo-surface-subsurface.c101
1 files changed, 70 insertions, 31 deletions
diff --git a/src/cairo-surface-subsurface.c b/src/cairo-surface-subsurface.c
index 489573aa3..079f9edd7 100644
--- a/src/cairo-surface-subsurface.c
+++ b/src/cairo-surface-subsurface.c
@@ -36,17 +36,26 @@
#include "cairoint.h"
#include "cairo-error-private.h"
+#include "cairo-recording-surface-private.h"
#include "cairo-surface-offset-private.h"
#include "cairo-surface-subsurface-private.h"
+static const cairo_surface_backend_t _cairo_surface_subsurface_backend;
+
static cairo_status_t
_cairo_surface_subsurface_finish (void *abstract_surface)
{
cairo_surface_subsurface_t *surface = abstract_surface;
+ cairo_status_t status = CAIRO_STATUS_SUCCESS;
+
+ if (surface->owns_target) {
+ cairo_surface_finish (surface->target);
+ status = surface->target->status;
+ }
cairo_surface_destroy (surface->target);
- return CAIRO_STATUS_SUCCESS;
+ return status;
}
static cairo_surface_t *
@@ -284,6 +293,46 @@ _cairo_surface_subsurface_acquire_source_image (void *abstrac
struct extra *extra;
uint8_t *data;
+ if (surface->target->type == CAIRO_SURFACE_TYPE_RECORDING) {
+ cairo_recording_surface_t *meta = (cairo_recording_surface_t *) surface->target;
+ cairo_surface_t *snapshot;
+
+ snapshot = _cairo_surface_has_snapshot (&surface->base,
+ &_cairo_image_surface_backend);
+ if (snapshot != NULL) {
+ *image_out = (cairo_image_surface_t *) cairo_surface_reference (snapshot);
+ *extra_out = NULL;
+ return CAIRO_STATUS_SUCCESS;
+ }
+
+ if (! _cairo_surface_has_snapshot (&meta->base,
+ &_cairo_image_surface_backend))
+ {
+ image = (cairo_image_surface_t *)
+ _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_set_device_offset (&image->base,
+ -surface->extents.x,
+ -surface->extents.y);
+
+ status = _cairo_recording_surface_replay (&meta->base, &image->base);
+ if (unlikely (status)) {
+ cairo_surface_destroy (&image->base);
+ return status;
+ }
+
+ _cairo_surface_attach_snapshot (&surface->base, &image->base, NULL);
+
+ *image_out = image;
+ *extra_out = NULL;
+ return CAIRO_STATUS_SUCCESS;
+ }
+ }
+
extra = malloc (sizeof (struct extra));
if (unlikely (extra == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
@@ -344,10 +393,13 @@ _cairo_surface_subsurface_release_source_image (void *abstract
void *abstract_extra)
{
cairo_surface_subsurface_t *surface = abstract_surface;
- struct extra *extra = abstract_extra;
- _cairo_surface_release_source_image (surface->target, extra->image, extra->image_extra);
- free (extra);
+ if (abstract_extra != NULL) {
+ struct extra *extra = abstract_extra;
+
+ _cairo_surface_release_source_image (surface->target, extra->image, extra->image_extra);
+ free (extra);
+ }
cairo_surface_destroy (&image->base);
}
@@ -356,37 +408,23 @@ static cairo_surface_t *
_cairo_surface_subsurface_snapshot (void *abstract_surface)
{
cairo_surface_subsurface_t *surface = abstract_surface;
- cairo_image_surface_t *image, *clone;
- void *image_extra;
- cairo_status_t status;
+ cairo_surface_subsurface_t *snapshot;
- /* XXX Alternatively we could snapshot the target and return a subsurface
- * of that.
- */
+ snapshot = malloc (sizeof (cairo_surface_subsurface_t));
+ if (unlikely (snapshot == NULL))
+ return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
- status = _cairo_surface_acquire_source_image (surface->target, &image, &image_extra);
- if (unlikely (status))
- return _cairo_surface_create_in_error (status);
-
- clone = (cairo_image_surface_t *)
- _cairo_image_surface_create_with_pixman_format (NULL,
- image->pixman_format,
- surface->extents.width,
- surface->extents.height,
- 0);
- if (likely (clone->base.status == CAIRO_STATUS_SUCCESS)) {
- pixman_image_composite32 (PIXMAN_OP_SRC,
- image->pixman_image, NULL, clone->pixman_image,
- surface->extents.x, surface->extents.y,
- 0, 0,
- 0, 0,
- surface->extents.width, surface->extents.height);
- clone->base.is_clear = FALSE;
- }
+ _cairo_surface_init (&snapshot->base,
+ &_cairo_surface_subsurface_backend,
+ NULL, /* device */
+ surface->target->content);
+ snapshot->target = _cairo_surface_snapshot (surface->target);
+ snapshot->owns_target = TRUE;
- _cairo_surface_release_source_image (surface->target, image, image_extra);
+ snapshot->base.type = snapshot->target->type;
+ snapshot->extents = surface->extents;
- return &clone->base;
+ return &snapshot->base;
}
static const cairo_surface_backend_t _cairo_surface_subsurface_backend = {
@@ -486,6 +524,7 @@ cairo_surface_create_for_rectangle (cairo_surface_t *target,
}
surface->target = cairo_surface_reference (target);
+ surface->owns_target = FALSE;
return &surface->base;
}