summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris Wilson <chris@chris-wilson.co.uk>2011-07-23 12:19:17 +0100
committerChris Wilson <chris@chris-wilson.co.uk>2011-07-23 15:33:14 +0100
commita30a7402f73485dabdb6a016178247f9844017a1 (patch)
tree54a047cbed002b2ff4c83a305019b503314da882
parentbff8e22eb6b7faeac04ca585cb739e7880a3335c (diff)
image: replay the recording surface directly onto the target
백현기 reported a use-case where he was recording an entire web-page onto the recording surface, in order to facilitate panning. In this scenario, where there may be lots of similar surfaces within the recording we generate thousands of unused snapshot-images bloating memory usage and impairing performance. Under the right conditions we can replay directly onto the destination which not only bypasses the snapshots but also skips the following resampling. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
-rw-r--r--src/cairo-clip-boxes.c17
-rw-r--r--src/cairo-clip-private.h15
-rw-r--r--src/cairo-clip.c67
-rw-r--r--src/cairo-image-surface.c64
-rw-r--r--src/cairo-recording-surface-private.h6
-rw-r--r--src/cairo-recording-surface.c68
-rw-r--r--src/cairo-surface-wrapper-private.h13
-rw-r--r--src/cairo-surface-wrapper.c190
8 files changed, 337 insertions, 103 deletions
diff --git a/src/cairo-clip-boxes.c b/src/cairo-clip-boxes.c
index 95ed265bf..98d1a18b0 100644
--- a/src/cairo-clip-boxes.c
+++ b/src/cairo-clip-boxes.c
@@ -560,3 +560,20 @@ _cairo_clip_to_boxes (cairo_clip_t *clip,
return CAIRO_STATUS_SUCCESS;
}
+
+cairo_clip_t *
+_cairo_clip_from_boxes (const cairo_boxes_t *boxes)
+{
+ cairo_clip_t *clip = _cairo_clip_create ();
+ if (clip == NULL)
+ return _cairo_clip_set_all_clipped (clip);
+
+ /* XXX cow-boxes? */
+ clip->boxes = _cairo_boxes_to_array (boxes, &clip->num_boxes, TRUE);
+ if (clip->boxes == NULL)
+ return _cairo_clip_set_all_clipped (clip);
+
+ _cairo_boxes_extents (boxes, &clip->extents);
+
+ return clip;
+}
diff --git a/src/cairo-clip-private.h b/src/cairo-clip-private.h
index 2ad53efdc..7f44bdfc8 100644
--- a/src/cairo-clip-private.h
+++ b/src/cairo-clip-private.h
@@ -116,6 +116,18 @@ _cairo_clip_copy_intersect_rectangle (const cairo_clip_t *clip,
}
cairo_private cairo_clip_t *
+_cairo_clip_intersect_clip (cairo_clip_t *clip,
+ const cairo_clip_t *other);
+
+static inline cairo_clip_t *
+_cairo_clip_copy_intersect_clip (const cairo_clip_t *clip,
+ const cairo_clip_t *other)
+{
+ return _cairo_clip_intersect_clip (_cairo_clip_copy (clip), other);
+}
+
+
+cairo_private cairo_clip_t *
_cairo_clip_intersect_box (cairo_clip_t *clip,
const cairo_box_t *box);
@@ -151,6 +163,9 @@ cairo_private cairo_status_t
_cairo_clip_to_boxes (cairo_clip_t *clip,
cairo_boxes_t *boxes);
+cairo_private cairo_clip_t *
+_cairo_clip_from_boxes (const cairo_boxes_t *boxes);
+
cairo_private cairo_region_t *
_cairo_clip_get_region (const cairo_clip_t *clip);
diff --git a/src/cairo-clip.c b/src/cairo-clip.c
index e5979d525..99336bd7c 100644
--- a/src/cairo-clip.c
+++ b/src/cairo-clip.c
@@ -250,14 +250,14 @@ _cairo_clip_intersect_path (cairo_clip_t *clip,
if (clip == NULL) {
clip = _cairo_clip_create ();
if (unlikely (clip == NULL))
- return _cairo_clip_set_all_clipped (clip);
+ return _cairo_clip_set_all_clipped (clip);
clip->extents = extents;
}
clip_path = _cairo_clip_path_create (clip);
if (unlikely (clip_path == NULL))
- return _cairo_clip_set_all_clipped (clip);
+ return _cairo_clip_set_all_clipped (clip);
status = _cairo_path_fixed_init_copy (&clip_path->path, path);
if (unlikely (status))
@@ -267,7 +267,70 @@ _cairo_clip_intersect_path (cairo_clip_t *clip,
clip_path->tolerance = tolerance;
clip_path->antialias = antialias;
+ if (clip->region) {
+ cairo_region_destroy (clip->region);
+ clip->region = NULL;
+ }
+
+ clip->is_region = FALSE;
+ return clip;
+}
+
+static cairo_clip_t *
+_cairo_clip_intersect_clip_path (cairo_clip_t *clip,
+ const cairo_clip_path_t *clip_path)
+{
+ if (clip_path->prev)
+ clip = _cairo_clip_intersect_clip_path (clip, clip_path->prev);
+
+ return _cairo_clip_intersect_path (clip,
+ &clip_path->path,
+ clip_path->fill_rule,
+ clip_path->tolerance,
+ clip_path->antialias);
+}
+
+cairo_clip_t *
+_cairo_clip_intersect_clip (cairo_clip_t *clip,
+ const cairo_clip_t *other)
+{
+ if (_cairo_clip_is_all_clipped (clip))
+ return clip;
+
+ if (other == NULL)
+ return clip;
+
+ if (clip == NULL)
+ return _cairo_clip_copy (other);
+
+ if (_cairo_clip_is_all_clipped (other))
+ return _cairo_clip_set_all_clipped (clip);
+
+ if (! _cairo_rectangle_intersect (&clip->extents, &other->extents))
+ return _cairo_clip_set_all_clipped (clip);
+
+ if (other->num_boxes) {
+ cairo_boxes_t boxes;
+
+ _cairo_boxes_init_for_array (&boxes, other->boxes, other->num_boxes);
+ clip = _cairo_clip_intersect_boxes (clip, &boxes);
+ }
+
+ if (! _cairo_clip_is_all_clipped (clip)) {
+ if (other->path) {
+ if (clip->path == NULL)
+ clip->path = _cairo_clip_path_reference (other->path);
+ else
+ clip = _cairo_clip_intersect_clip_path (clip, other->path);
+ }
+ }
+
+ if (clip->region) {
+ cairo_region_destroy (clip->region);
+ clip->region = NULL;
+ }
clip->is_region = FALSE;
+
return clip;
}
diff --git a/src/cairo-image-surface.c b/src/cairo-image-surface.c
index a03e1abb1..f727b84ac 100644
--- a/src/cairo-image-surface.c
+++ b/src/cairo-image-surface.c
@@ -44,6 +44,7 @@
#include "cairo-composite-rectangles-private.h"
#include "cairo-default-context-private.h"
#include "cairo-error-private.h"
+#include "cairo-recording-surface-private.h"
#include "cairo-region-private.h"
#include "cairo-pattern-private.h"
#include "cairo-scaled-font-private.h"
@@ -2878,6 +2879,27 @@ _composite_unaligned_boxes (cairo_image_surface_t *dst,
return status;
}
+static cairo_bool_t
+is_recording_pattern (const cairo_pattern_t *pattern)
+{
+ const cairo_surface_pattern_t *surface_pattern;
+
+ if (pattern->type != CAIRO_PATTERN_TYPE_SURFACE)
+ return FALSE;
+
+ surface_pattern = (const cairo_surface_pattern_t *) pattern;
+ return _cairo_surface_is_recording (surface_pattern->surface);
+}
+
+static cairo_surface_t *
+pattern_get_surface (const cairo_pattern_t *pattern)
+{
+ const cairo_surface_pattern_t *surface_pattern;
+
+ surface_pattern = (const cairo_surface_pattern_t *) pattern;
+ return surface_pattern->surface;
+}
+
static cairo_status_t
_composite_boxes (cairo_image_surface_t *dst,
cairo_operator_t op,
@@ -2916,6 +2938,47 @@ _composite_boxes (cairo_image_surface_t *dst,
}
}
+ /* Are we just copying a recording surface? */
+ if (! need_clip_mask &&
+ op == CAIRO_OPERATOR_SOURCE &&
+ pattern->extend == CAIRO_EXTEND_NONE && /* or if sample is contained */
+ is_recording_pattern (pattern))
+ {
+ cairo_clip_t *recording_clip;
+
+ /* first clear the area about to be overwritten */
+ if (! dst->base.is_clear) {
+ for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
+ cairo_box_t *box = chunk->base;
+
+ for (i = 0; i < chunk->count; i++) {
+ int x1 = _cairo_fixed_integer_round_down (box[i].p1.x);
+ int y1 = _cairo_fixed_integer_round_down (box[i].p1.y);
+ int x2 = _cairo_fixed_integer_round_down (box[i].p2.x);
+ int y2 = _cairo_fixed_integer_round_down (box[i].p2.y);
+
+ if (x2 == x1 || y2 == y1)
+ continue;
+
+ pixman_fill ((uint32_t *) dst->data,
+ dst->stride / sizeof (uint32_t),
+ PIXMAN_FORMAT_BPP (dst->pixman_format),
+ x1, y1, x2 - x1, y2 - y1,
+ 0);
+ }
+ }
+ }
+
+ recording_clip = _cairo_clip_from_boxes (boxes);
+ status = _cairo_recording_surface_replay_with_clip (pattern_get_surface (pattern),
+ &pattern->matrix,
+ &dst->base,
+ recording_clip);
+ _cairo_clip_destroy (recording_clip);
+
+ return status;
+ }
+
status = CAIRO_STATUS_SUCCESS;
if (! need_clip_mask &&
pattern_to_pixel ((cairo_solid_pattern_t *) pattern, op, dst->pixman_format,
@@ -4476,7 +4539,6 @@ _cairo_image_surface_coerce (cairo_image_surface_t *surface)
{
return _cairo_image_surface_coerce_to_format (surface,
_cairo_format_from_content (surface->base.content));
-
}
/* A convenience function for when one needs to coerce an image
diff --git a/src/cairo-recording-surface-private.h b/src/cairo-recording-surface-private.h
index a901e7b14..cc23d80c6 100644
--- a/src/cairo-recording-surface-private.h
+++ b/src/cairo-recording-surface-private.h
@@ -145,6 +145,12 @@ _cairo_recording_surface_replay (cairo_surface_t *surface,
cairo_surface_t *target);
cairo_private cairo_status_t
+_cairo_recording_surface_replay_with_clip (cairo_surface_t *surface,
+ const cairo_matrix_t *surface_transform,
+ cairo_surface_t *target,
+ const cairo_clip_t *target_clip);
+
+cairo_private cairo_status_t
_cairo_recording_surface_replay_and_create_regions (cairo_surface_t *surface,
cairo_surface_t *target);
cairo_private cairo_status_t
diff --git a/src/cairo-recording-surface.c b/src/cairo-recording-surface.c
index ea5ee0178..96c71fd49 100644
--- a/src/cairo-recording-surface.c
+++ b/src/cairo-recording-surface.c
@@ -251,14 +251,6 @@ _cairo_recording_surface_acquire_source_image_transformed (void *abstract_s
double width;
double height;
- image = _cairo_surface_has_snapshot (&surface->base,
- &_cairo_image_surface_backend);
- if (image != NULL) {
- *image_out = (cairo_image_surface_t *) cairo_surface_reference (image);
- *image_extra = NULL;
- return CAIRO_STATUS_SUCCESS;
- }
-
width = surface->extents.width * device_transform->xx;
height = surface->extents.height * device_transform->yy;
image = _cairo_image_surface_create_with_content (surface->content,
@@ -278,8 +270,6 @@ _cairo_recording_surface_acquire_source_image_transformed (void *abstract_s
return status;
}
- _cairo_surface_attach_snapshot (&surface->base, image, NULL);
-
*image_out = (cairo_image_surface_t *) image;
*image_extra = NULL;
return CAIRO_STATUS_SUCCESS;
@@ -291,11 +281,29 @@ _cairo_recording_surface_acquire_source_image (void *abstract_surface,
void **image_extra)
{
cairo_matrix_t identity;
+ cairo_surface_t *image;
+ 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);
+ *image_extra = NULL;
+ return CAIRO_STATUS_SUCCESS;
+ }
cairo_matrix_init_identity (&identity);
- return _cairo_recording_surface_acquire_source_image_transformed (
- abstract_surface, &identity, image_out, image_extra);
+ status =
+ _cairo_recording_surface_acquire_source_image_transformed (abstract_surface, &identity, image_out, image_extra);
+ if (unlikely (status))
+ return status;
+
+ _cairo_surface_attach_snapshot (abstract_surface,
+ &(*image_out)->base,
+ NULL);
+ return CAIRO_STATUS_SUCCESS;
+
}
static void
@@ -817,7 +825,9 @@ _cairo_recording_surface_get_path (cairo_surface_t *surface,
static cairo_status_t
_cairo_recording_surface_replay_internal (cairo_surface_t *surface,
const cairo_rectangle_int_t *surface_extents,
+ const cairo_matrix_t *surface_transform,
cairo_surface_t *target,
+ const cairo_clip_t *target_clip,
cairo_recording_replay_type_t type,
cairo_recording_region_type_t region)
{
@@ -843,6 +853,8 @@ _cairo_recording_surface_replay_internal (cairo_surface_t *surface,
_cairo_surface_wrapper_init (&wrapper, target);
_cairo_surface_wrapper_set_extents (&wrapper, surface_extents);
+ _cairo_surface_wrapper_set_inverse_transform (&wrapper, surface_transform);
+ _cairo_surface_wrapper_set_clip (&wrapper, target_clip);
recording_surface = (cairo_recording_surface_t *) surface;
status = CAIRO_STATUS_SUCCESS;
@@ -854,7 +866,8 @@ _cairo_recording_surface_replay_internal (cairo_surface_t *surface,
cairo_command_t *command = elements[i];
cairo_clip_t *clip = command->header.clip;
- if (type == CAIRO_RECORDING_REPLAY && region != CAIRO_RECORDING_REGION_ALL) {
+ if (type == CAIRO_RECORDING_REPLAY &&
+ region != CAIRO_RECORDING_REGION_ALL) {
if (command->header.region != region)
continue;
}
@@ -881,7 +894,6 @@ _cairo_recording_surface_replay_internal (cairo_surface_t *surface,
break;
case CAIRO_COMMAND_STROKE:
- {
status = _cairo_surface_wrapper_stroke (&wrapper,
command->header.op,
&command->stroke.source.base,
@@ -893,7 +905,7 @@ _cairo_recording_surface_replay_internal (cairo_surface_t *surface,
command->stroke.antialias,
clip);
break;
- }
+
case CAIRO_COMMAND_FILL:
{
cairo_command_t *stroke_command;
@@ -945,6 +957,7 @@ _cairo_recording_surface_replay_internal (cairo_surface_t *surface,
}
break;
}
+
case CAIRO_COMMAND_SHOW_TEXT_GLYPHS:
{
cairo_glyph_t *glyphs = command->show_text_glyphs.glyphs;
@@ -975,6 +988,7 @@ _cairo_recording_surface_replay_internal (cairo_surface_t *surface,
free (glyphs_copy);
break;
}
+
default:
ASSERT_NOT_REACHED;
}
@@ -1017,8 +1031,20 @@ cairo_status_t
_cairo_recording_surface_replay (cairo_surface_t *surface,
cairo_surface_t *target)
{
- return _cairo_recording_surface_replay_internal (surface, NULL,
- target,
+ return _cairo_recording_surface_replay_internal (surface, NULL, NULL,
+ target, NULL,
+ CAIRO_RECORDING_REPLAY,
+ CAIRO_RECORDING_REGION_ALL);
+}
+
+cairo_status_t
+_cairo_recording_surface_replay_with_clip (cairo_surface_t *surface,
+ const cairo_matrix_t *surface_transform,
+ cairo_surface_t *target,
+ const cairo_clip_t *target_clip)
+{
+ return _cairo_recording_surface_replay_internal (surface, NULL, surface_transform,
+ target, target_clip,
CAIRO_RECORDING_REPLAY,
CAIRO_RECORDING_REGION_ALL);
}
@@ -1033,8 +1059,8 @@ cairo_status_t
_cairo_recording_surface_replay_and_create_regions (cairo_surface_t *surface,
cairo_surface_t *target)
{
- return _cairo_recording_surface_replay_internal (surface, NULL,
- target,
+ return _cairo_recording_surface_replay_internal (surface, NULL, NULL,
+ target, NULL,
CAIRO_RECORDING_CREATE_REGIONS,
CAIRO_RECORDING_REGION_ALL);
}
@@ -1045,8 +1071,8 @@ _cairo_recording_surface_replay_region (cairo_surface_t *surface,
cairo_surface_t *target,
cairo_recording_region_type_t region)
{
- return _cairo_recording_surface_replay_internal (surface, surface_extents,
- target,
+ return _cairo_recording_surface_replay_internal (surface, surface_extents, NULL,
+ target, NULL,
CAIRO_RECORDING_REPLAY,
region);
}
diff --git a/src/cairo-surface-wrapper-private.h b/src/cairo-surface-wrapper-private.h
index b3d3a55ae..97ac8097a 100644
--- a/src/cairo-surface-wrapper-private.h
+++ b/src/cairo-surface-wrapper-private.h
@@ -46,8 +46,13 @@ CAIRO_BEGIN_DECLS
struct _cairo_surface_wrapper {
cairo_surface_t *target;
+ cairo_matrix_t transform;
+
cairo_bool_t has_extents;
cairo_rectangle_int_t extents;
+ const cairo_clip_t *clip;
+
+ cairo_bool_t needs_transform;
};
cairo_private void
@@ -59,6 +64,14 @@ _cairo_surface_wrapper_set_extents (cairo_surface_wrapper_t *wrapper,
const cairo_rectangle_int_t *extents);
cairo_private void
+_cairo_surface_wrapper_set_inverse_transform (cairo_surface_wrapper_t *wrapper,
+ const cairo_matrix_t *transform);
+
+cairo_private void
+_cairo_surface_wrapper_set_clip (cairo_surface_wrapper_t *wrapper,
+ const cairo_clip_t *clip);
+
+cairo_private void
_cairo_surface_wrapper_fini (cairo_surface_wrapper_t *wrapper);
cairo_private cairo_status_t
diff --git a/src/cairo-surface-wrapper.c b/src/cairo-surface-wrapper.c
index 9e746f9c6..8dc40f842 100644
--- a/src/cairo-surface-wrapper.c
+++ b/src/cairo-surface-wrapper.c
@@ -54,18 +54,6 @@ _copy_transformed_pattern (cairo_pattern_t *pattern,
_cairo_pattern_transform (pattern, ctm_inverse);
}
-static inline cairo_bool_t
-_cairo_surface_wrapper_needs_device_transform (cairo_surface_wrapper_t *wrapper)
-{
- return ! _cairo_matrix_is_identity (&wrapper->target->device_transform);
-}
-
-static cairo_bool_t
-_cairo_surface_wrapper_needs_extents_transform (cairo_surface_wrapper_t *wrapper)
-{
- return wrapper->has_extents && (wrapper->extents.x | wrapper->extents.y);
-}
-
cairo_status_t
_cairo_surface_wrapper_acquire_source_image (cairo_surface_wrapper_t *wrapper,
cairo_image_surface_t **image_out,
@@ -86,6 +74,24 @@ _cairo_surface_wrapper_release_source_image (cairo_surface_wrapper_t *wrapper,
_cairo_surface_release_source_image (wrapper->target, image, image_extra);
}
+static void
+_cairo_surface_wrapper_get_transform (cairo_surface_wrapper_t *wrapper,
+ cairo_matrix_t *m)
+{
+ cairo_matrix_init_identity (m);
+
+ if (wrapper->has_extents && (wrapper->extents.x || wrapper->extents.y))
+ cairo_matrix_translate (m, -wrapper->extents.x, -wrapper->extents.y);
+
+ if (! _cairo_matrix_is_identity (&wrapper->transform))
+ cairo_matrix_multiply (m, &wrapper->transform, m);
+
+
+ if (! _cairo_matrix_is_identity (&wrapper->target->device_transform))
+ cairo_matrix_multiply (m, &wrapper->target->device_transform, m);
+}
+
+
cairo_status_t
_cairo_surface_wrapper_paint (cairo_surface_wrapper_t *wrapper,
cairo_operator_t op,
@@ -108,21 +114,15 @@ _cairo_surface_wrapper_paint (cairo_surface_wrapper_t *wrapper,
goto FINISH;
}
- if (_cairo_surface_wrapper_needs_device_transform (wrapper) ||
- _cairo_surface_wrapper_needs_extents_transform (wrapper))
- {
+ if (wrapper->needs_transform) {
cairo_matrix_t m;
- cairo_matrix_init_identity (&m);
-
- if (_cairo_surface_wrapper_needs_extents_transform (wrapper))
- cairo_matrix_translate (&m, -wrapper->extents.x, -wrapper->extents.y);
-
- if (_cairo_surface_wrapper_needs_device_transform (wrapper))
- cairo_matrix_multiply (&m, &wrapper->target->device_transform, &m);
+ _cairo_surface_wrapper_get_transform (wrapper, &m);
/* XXX */
- dev_clip = _cairo_clip_copy_with_translation (clip, wrapper->extents.x, wrapper->extents.y);
+ dev_clip = _cairo_clip_copy_with_translation (dev_clip,
+ wrapper->extents.x,
+ wrapper->extents.y);
status = cairo_matrix_invert (&m);
assert (status == CAIRO_STATUS_SUCCESS);
@@ -131,6 +131,9 @@ _cairo_surface_wrapper_paint (cairo_surface_wrapper_t *wrapper,
source = &source_copy.base;
}
+ if (wrapper->clip)
+ dev_clip = _cairo_clip_copy_intersect_clip (dev_clip, wrapper->clip);
+
status = _cairo_surface_paint (wrapper->target, op, source, dev_clip);
FINISH:
@@ -164,21 +167,14 @@ _cairo_surface_wrapper_mask (cairo_surface_wrapper_t *wrapper,
goto FINISH;
}
- if (_cairo_surface_wrapper_needs_device_transform (wrapper) ||
- _cairo_surface_wrapper_needs_extents_transform (wrapper))
- {
+ if (wrapper->needs_transform) {
cairo_matrix_t m;
- cairo_matrix_init_identity (&m);
-
- if (_cairo_surface_wrapper_needs_extents_transform (wrapper))
- cairo_matrix_translate (&m, -wrapper->extents.x, -wrapper->extents.y);
+ _cairo_surface_wrapper_get_transform (wrapper, &m);
- if (_cairo_surface_wrapper_needs_device_transform (wrapper))
- cairo_matrix_multiply (&m, &wrapper->target->device_transform, &m);
-
- /* XXX */
- dev_clip = _cairo_clip_copy_with_translation (clip, wrapper->extents.x, wrapper->extents.y);
+ dev_clip = _cairo_clip_copy_with_translation (dev_clip,
+ wrapper->extents.x,
+ wrapper->extents.y);
status = cairo_matrix_invert (&m);
assert (status == CAIRO_STATUS_SUCCESS);
@@ -190,6 +186,9 @@ _cairo_surface_wrapper_mask (cairo_surface_wrapper_t *wrapper,
mask = &mask_copy.base;
}
+ if (wrapper->clip)
+ dev_clip = _cairo_clip_copy_intersect_clip (dev_clip, wrapper->clip);
+
status = _cairo_surface_mask (wrapper->target, op, source, mask, dev_clip);
FINISH:
@@ -230,18 +229,10 @@ _cairo_surface_wrapper_stroke (cairo_surface_wrapper_t *wrapper,
goto FINISH;
}
- if (_cairo_surface_wrapper_needs_device_transform (wrapper) ||
- _cairo_surface_wrapper_needs_extents_transform (wrapper))
- {
+ if (wrapper->needs_transform) {
cairo_matrix_t m;
- cairo_matrix_init_identity (&m);
-
- if (_cairo_surface_wrapper_needs_extents_transform (wrapper))
- cairo_matrix_translate (&m, -wrapper->extents.x, -wrapper->extents.y);
-
- if (_cairo_surface_wrapper_needs_device_transform (wrapper))
- cairo_matrix_multiply (&m, &wrapper->target->device_transform, &m);
+ _cairo_surface_wrapper_get_transform (wrapper, &m);
status = _cairo_path_fixed_init_copy (&path_copy, dev_path);
if (unlikely (status))
@@ -251,7 +242,9 @@ _cairo_surface_wrapper_stroke (cairo_surface_wrapper_t *wrapper,
dev_path = &path_copy;
/* XXX */
- dev_clip = _cairo_clip_copy_with_translation (clip, wrapper->extents.x, wrapper->extents.y);
+ dev_clip = _cairo_clip_copy_with_translation (dev_clip,
+ wrapper->extents.x,
+ wrapper->extents.y);
cairo_matrix_multiply (&dev_ctm, &dev_ctm, &m);
@@ -264,6 +257,9 @@ _cairo_surface_wrapper_stroke (cairo_surface_wrapper_t *wrapper,
source = &source_copy.base;
}
+ if (wrapper->clip)
+ dev_clip = _cairo_clip_copy_intersect_clip (dev_clip, wrapper->clip);
+
status = _cairo_surface_stroke (wrapper->target, op, source,
dev_path, stroke_style,
&dev_ctm, &dev_ctm_inverse,
@@ -316,18 +312,10 @@ _cairo_surface_wrapper_fill_stroke (cairo_surface_wrapper_t *wrapper,
goto FINISH;
}
- if (_cairo_surface_wrapper_needs_device_transform (wrapper) ||
- _cairo_surface_wrapper_needs_extents_transform (wrapper))
- {
+ if (wrapper->needs_transform) {
cairo_matrix_t m;
- cairo_matrix_init_identity (&m);
-
- if (_cairo_surface_wrapper_needs_extents_transform (wrapper))
- cairo_matrix_translate (&m, -wrapper->extents.x, -wrapper->extents.y);
-
- if (_cairo_surface_wrapper_needs_device_transform (wrapper))
- cairo_matrix_multiply (&m, &wrapper->target->device_transform, &m);
+ _cairo_surface_wrapper_get_transform (wrapper, &m);
status = _cairo_path_fixed_init_copy (&path_copy, dev_path);
if (unlikely (status))
@@ -337,7 +325,9 @@ _cairo_surface_wrapper_fill_stroke (cairo_surface_wrapper_t *wrapper,
dev_path = &path_copy;
/* XXX */
- dev_clip = _cairo_clip_copy_with_translation (clip, wrapper->extents.x, wrapper->extents.y);
+ dev_clip = _cairo_clip_copy_with_translation (dev_clip,
+ wrapper->extents.x,
+ wrapper->extents.y);
cairo_matrix_multiply (&dev_ctm, &dev_ctm, &m);
@@ -353,6 +343,9 @@ _cairo_surface_wrapper_fill_stroke (cairo_surface_wrapper_t *wrapper,
fill_source = &fill_source_copy.base;
}
+ if (wrapper->clip)
+ dev_clip = _cairo_clip_copy_intersect_clip (dev_clip, wrapper->clip);
+
status = _cairo_surface_fill_stroke (wrapper->target,
fill_op, fill_source, fill_rule,
fill_tolerance, fill_antialias,
@@ -399,18 +392,10 @@ _cairo_surface_wrapper_fill (cairo_surface_wrapper_t *wrapper,
goto FINISH;
}
- if (_cairo_surface_wrapper_needs_device_transform (wrapper) ||
- _cairo_surface_wrapper_needs_extents_transform (wrapper))
- {
+ if (wrapper->needs_transform) {
cairo_matrix_t m;
- cairo_matrix_init_identity (&m);
-
- if (_cairo_surface_wrapper_needs_extents_transform (wrapper))
- cairo_matrix_translate (&m, -wrapper->extents.x, -wrapper->extents.y);
-
- if (_cairo_surface_wrapper_needs_device_transform (wrapper))
- cairo_matrix_multiply (&m, &wrapper->target->device_transform, &m);
+ _cairo_surface_wrapper_get_transform (wrapper, &m);
status = _cairo_path_fixed_init_copy (&path_copy, dev_path);
if (unlikely (status))
@@ -420,7 +405,9 @@ _cairo_surface_wrapper_fill (cairo_surface_wrapper_t *wrapper,
dev_path = &path_copy;
/* XXX */
- dev_clip = _cairo_clip_copy_with_translation (clip, wrapper->extents.x, wrapper->extents.y);
+ dev_clip = _cairo_clip_copy_with_translation (dev_clip,
+ wrapper->extents.x,
+ wrapper->extents.y);
status = cairo_matrix_invert (&m);
assert (status == CAIRO_STATUS_SUCCESS);
@@ -429,6 +416,9 @@ _cairo_surface_wrapper_fill (cairo_surface_wrapper_t *wrapper,
source = &source_copy.base;
}
+ if (wrapper->clip)
+ dev_clip = _cairo_clip_copy_intersect_clip (dev_clip, wrapper->clip);
+
status = _cairo_surface_fill (wrapper->target, op, source,
dev_path, fill_rule,
tolerance, antialias,
@@ -477,22 +467,16 @@ _cairo_surface_wrapper_show_text_glyphs (cairo_surface_wrapper_t *wrapper,
goto FINISH;
}
- if (_cairo_surface_wrapper_needs_device_transform (wrapper) ||
- _cairo_surface_wrapper_needs_extents_transform (wrapper))
- {
+ if (wrapper->needs_transform) {
cairo_matrix_t m;
int i;
- cairo_matrix_init_identity (&m);
-
- if (_cairo_surface_wrapper_needs_extents_transform (wrapper))
- cairo_matrix_translate (&m, -wrapper->extents.x, -wrapper->extents.y);
-
- if (_cairo_surface_wrapper_needs_device_transform (wrapper))
- cairo_matrix_multiply (&m, &wrapper->target->device_transform, &m);
+ _cairo_surface_wrapper_get_transform (wrapper, &m);
/* XXX */
- dev_clip = _cairo_clip_copy_with_translation (clip, wrapper->extents.x, wrapper->extents.y);
+ dev_clip = _cairo_clip_copy_with_translation (dev_clip,
+ wrapper->extents.x,
+ wrapper->extents.y);
dev_glyphs = _cairo_malloc_ab (num_glyphs, sizeof (cairo_glyph_t));
if (dev_glyphs == NULL) {
@@ -512,6 +496,9 @@ _cairo_surface_wrapper_show_text_glyphs (cairo_surface_wrapper_t *wrapper,
source = &source_copy.base;
}
+ if (wrapper->clip)
+ dev_clip = _cairo_clip_copy_intersect_clip (dev_clip, wrapper->clip);
+
status = _cairo_surface_show_text_glyphs (wrapper->target, op, source,
utf8, utf8_len,
dev_glyphs, num_glyphs,
@@ -555,6 +542,15 @@ _cairo_surface_wrapper_get_extents (cairo_surface_wrapper_t *wrapper,
}
}
+static cairo_bool_t
+_cairo_surface_wrapper_needs_device_transform (cairo_surface_wrapper_t *wrapper)
+{
+ return
+ (wrapper->has_extents && (wrapper->extents.x | wrapper->extents.y)) ||
+ ! _cairo_matrix_is_identity (&wrapper->transform) ||
+ ! _cairo_matrix_is_identity (&wrapper->target->device_transform);
+}
+
void
_cairo_surface_wrapper_set_extents (cairo_surface_wrapper_t *wrapper,
const cairo_rectangle_int_t *extents)
@@ -565,6 +561,38 @@ _cairo_surface_wrapper_set_extents (cairo_surface_wrapper_t *wrapper,
} else {
wrapper->has_extents = FALSE;
}
+
+ wrapper->needs_transform =
+ _cairo_surface_wrapper_needs_device_transform (wrapper);
+}
+
+void
+_cairo_surface_wrapper_set_inverse_transform (cairo_surface_wrapper_t *wrapper,
+ const cairo_matrix_t *transform)
+{
+ cairo_status_t status;
+
+ if (transform == NULL || _cairo_matrix_is_identity (transform)) {
+ cairo_matrix_init_identity (&wrapper->transform);
+
+ wrapper->needs_transform =
+ _cairo_surface_wrapper_needs_device_transform (wrapper);
+ } else {
+ wrapper->transform = *transform;
+ status = cairo_matrix_invert (&wrapper->transform);
+ /* should always be invertible unless given pathological input */
+ assert (status == CAIRO_STATUS_SUCCESS);
+
+ wrapper->needs_transform = TRUE;
+ }
+
+}
+
+void
+_cairo_surface_wrapper_set_clip (cairo_surface_wrapper_t *wrapper,
+ const cairo_clip_t *clip)
+{
+ wrapper->clip = clip;
}
void
@@ -590,8 +618,12 @@ void
_cairo_surface_wrapper_init (cairo_surface_wrapper_t *wrapper,
cairo_surface_t *target)
{
+ _cairo_surface_wrapper_set_inverse_transform (wrapper, NULL);
+
wrapper->target = cairo_surface_reference (target);
wrapper->has_extents = FALSE;
+ wrapper->needs_transform =
+ ! _cairo_matrix_is_identity (&wrapper->target->device_transform);
}
void