diff options
author | Chris Wilson <chris@chris-wilson.co.uk> | 2011-08-14 01:41:44 +0100 |
---|---|---|
committer | Chris Wilson <chris@chris-wilson.co.uk> | 2011-08-14 12:37:57 +0100 |
commit | b8f09f08c4ca3569581a3e39056adb0b5a6752ae (patch) | |
tree | 1b1bdc16ab3b1957c885b6f537d50f33b098bb52 /src/cairo-analysis-surface.c | |
parent | 8f99e926c8b1a8fa7f7e0d828a96bac6dc1fe39c (diff) | |
download | cairo-b8f09f08c4ca3569581a3e39056adb0b5a6752ae.tar.gz |
analysis: prevent recursion whilst analysing recording patterns
Thanks to subsurface recursion. There's a pattern here, but no clean
solution has yet presented itself.
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Diffstat (limited to 'src/cairo-analysis-surface.c')
-rw-r--r-- | src/cairo-analysis-surface.c | 73 |
1 files changed, 61 insertions, 12 deletions
diff --git a/src/cairo-analysis-surface.c b/src/cairo-analysis-surface.c index 10dbaf1bb..8fa833e6c 100644 --- a/src/cairo-analysis-surface.c +++ b/src/cairo-analysis-surface.c @@ -95,31 +95,81 @@ _cairo_analysis_surface_merge_status (cairo_int_status_t status_a, return CAIRO_INT_STATUS_SUCCESS; } +struct proxy { + cairo_surface_t base; + cairo_surface_t *target; +}; + +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, +}; + +static cairo_surface_t * +attach_proxy (cairo_surface_t *source, + cairo_surface_t *target) +{ + 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, target->content); + + proxy->target = target; + _cairo_surface_attach_snapshot (source, &proxy->base, NULL); + + return &proxy->base; +} + +static void +detach_proxy (cairo_surface_t *proxy) +{ + cairo_surface_finish (proxy); + cairo_surface_destroy (proxy); +} + static cairo_int_status_t _analyze_recording_surface_pattern (cairo_analysis_surface_t *surface, const cairo_pattern_t *pattern) { const cairo_surface_pattern_t *surface_pattern; - cairo_bool_t old_has_ctm; - cairo_matrix_t old_ctm, p2d; + cairo_analysis_surface_t *tmp; + cairo_surface_t *source, *proxy; + cairo_matrix_t p2d; cairo_status_t status; - cairo_surface_t *source; assert (pattern->type == CAIRO_PATTERN_TYPE_SURFACE); surface_pattern = (const cairo_surface_pattern_t *) pattern; assert (surface_pattern->surface->type == CAIRO_SURFACE_TYPE_RECORDING); + source = surface_pattern->surface; + + proxy = _cairo_surface_has_snapshot (source, &proxy_backend); + if (proxy != NULL) { + /* nothing untoward found so far */ + return CAIRO_STATUS_SUCCESS; + } - old_ctm = surface->ctm; - old_has_ctm = surface->has_ctm; + tmp = (cairo_analysis_surface_t *) + _cairo_analysis_surface_create (surface->target); + if (unlikely (tmp->base.status)) + return tmp->base.status; + proxy = attach_proxy (source, &tmp->base); p2d = pattern->matrix; status = cairo_matrix_invert (&p2d); assert (status == CAIRO_STATUS_SUCCESS); - cairo_matrix_multiply (&surface->ctm, &p2d, &surface->ctm); - surface->has_ctm = ! _cairo_matrix_is_identity (&surface->ctm); + cairo_matrix_multiply (&tmp->ctm, &p2d, &surface->ctm); + tmp->has_ctm = ! _cairo_matrix_is_identity (&tmp->ctm); - source = surface_pattern->surface; if (_cairo_surface_is_snapshot (source)) source = _cairo_surface_snapshot_get_target (source); if (source->backend->type == CAIRO_SURFACE_TYPE_SUBSURFACE) { @@ -127,10 +177,9 @@ _analyze_recording_surface_pattern (cairo_analysis_surface_t *surface, source = sub->target; } - status = _cairo_recording_surface_replay_and_create_regions (source, &surface->base); - - surface->ctm = old_ctm; - surface->has_ctm = old_has_ctm; + status = _cairo_recording_surface_replay_and_create_regions (source, &tmp->base); + detach_proxy (proxy); + cairo_surface_destroy (&tmp->base); return status; } |