mirror of
https://gitlab.freedesktop.org/cairo/cairo.git
synced 2026-05-08 06:48:03 +02:00
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>
This commit is contained in:
parent
8f99e926c8
commit
b8f09f08c4
1 changed files with 61 additions and 12 deletions
|
|
@ -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;
|
||||
|
||||
old_ctm = surface->ctm;
|
||||
old_has_ctm = surface->has_ctm;
|
||||
proxy = _cairo_surface_has_snapshot (source, &proxy_backend);
|
||||
if (proxy != NULL) {
|
||||
/* nothing untoward found so far */
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue