diff options
author | Chris Wilson <chris@chris-wilson.co.uk> | 2009-08-24 08:04:12 +0100 |
---|---|---|
committer | Chris Wilson <chris@chris-wilson.co.uk> | 2009-08-29 08:08:36 +0100 |
commit | 60d73da9f2e148e982254c78773f0b925be184ff (patch) | |
tree | 3186488c2f3c4c7f7d28d4f3e4be170d85a6d961 /src/cairo-clip.c | |
parent | 50c7d637f3a97031c5f4e2bc8d41d17e5397db45 (diff) |
[clip] Cache intermediate clip masks.
As we now superimpose a per-operation clip, this defeats the current
top-level caching mechanism. Instead we need to cache the mask for
each path. This still seems quite wasteful, and an avenue would be to
avoid caching if the path is rectilinear and reduce the number of
required composite operations. (However, first find test case...)
Diffstat (limited to 'src/cairo-clip.c')
-rw-r--r-- | src/cairo-clip.c | 165 |
1 files changed, 101 insertions, 64 deletions
diff --git a/src/cairo-clip.c b/src/cairo-clip.c index 67079c4b..8d68e47e 100644 --- a/src/cairo-clip.c +++ b/src/cairo-clip.c @@ -964,19 +964,17 @@ _cairo_clip_path_to_boxes (cairo_clip_path_t *clip_path, return CAIRO_STATUS_SUCCESS; } -cairo_surface_t * -_cairo_clip_get_surface (cairo_clip_t *clip, cairo_surface_t *target) +static cairo_surface_t * +_cairo_clip_path_get_surface (cairo_clip_path_t *clip_path, + cairo_surface_t *target) { cairo_surface_t *surface; cairo_pattern_union_t pattern; cairo_status_t status; - cairo_clip_path_t *clip_path = clip->path; const cairo_rectangle_int_t *clip_extents = &clip_path->extents; - cairo_region_t *clip_region; + cairo_clip_path_t *prev; cairo_bool_t need_translate; - assert (clip_path != NULL); - if (clip_path->surface != NULL && clip_path->surface->backend == target->backend) { @@ -1008,22 +1006,22 @@ _cairo_clip_get_surface (cairo_clip_t *clip, cairo_surface_t *target) CAIRO_COLOR_WHITE, CAIRO_CONTENT_COLOR); - status = _cairo_clip_get_region (clip, &clip_region); + status = _cairo_clip_path_to_region (clip_path); if (unlikely (_cairo_status_is_error (status))) goto BAIL; need_translate = clip_extents->x || clip_extents->y; if (status == CAIRO_STATUS_SUCCESS) { if (need_translate) { - cairo_region_translate (clip_region, + cairo_region_translate (clip_path->region, -clip_extents->x, -clip_extents->y); } status = _cairo_surface_fill_region (surface, - CAIRO_OPERATOR_ADD, + CAIRO_OPERATOR_SOURCE, CAIRO_COLOR_WHITE, - clip_region); + clip_path->region); if (need_translate) { - cairo_region_translate (clip_region, + cairo_region_translate (clip_path->region, clip_extents->x, clip_extents->y); } if (unlikely (status)) @@ -1037,7 +1035,7 @@ _cairo_clip_get_surface (cairo_clip_t *clip, cairo_surface_t *target) _cairo_fixed_from_int (-clip_extents->y)); } status = _cairo_surface_fill (surface, - CAIRO_OPERATOR_ADD, + CAIRO_OPERATOR_OVER, &pattern.base, &clip_path->path, clip_path->fill_rule, @@ -1054,79 +1052,118 @@ _cairo_clip_get_surface (cairo_clip_t *clip, cairo_surface_t *target) goto BAIL; } - while ((clip_path = clip_path->prev) != NULL) { - status = _cairo_clip_path_to_region (clip_path); + prev = clip_path->prev; + NEXT_PATH: + if (prev != NULL) { + status = _cairo_clip_path_to_region (prev); if (unlikely (_cairo_status_is_error (status))) goto BAIL; if (status == CAIRO_STATUS_SUCCESS) { - cairo_region_translate (clip_path->region, - -clip_extents->x, -clip_extents->y); + if (need_translate) { + cairo_region_translate (prev->region, + -clip_extents->x, -clip_extents->y); + } status = _cairo_surface_fill_region (surface, CAIRO_OPERATOR_IN, CAIRO_COLOR_WHITE, - clip_path->region); - cairo_region_translate (clip_path->region, - clip_extents->x, clip_extents->y); + prev->region); + if (need_translate) { + cairo_region_translate (prev->region, + clip_extents->x, clip_extents->y); + } + if (unlikely (status)) + goto BAIL; + } else if (prev->path.is_rectilinear) { + if (need_translate) { + _cairo_path_fixed_translate (&prev->path, + _cairo_fixed_from_int (-clip_extents->x), + _cairo_fixed_from_int (-clip_extents->y)); + } + status = _cairo_surface_fill (surface, + CAIRO_OPERATOR_IN, + &pattern.base, + &prev->path, + clip_path->fill_rule, + clip_path->tolerance, + clip_path->antialias, + NULL); + if (need_translate) { + _cairo_path_fixed_translate (&prev->path, + _cairo_fixed_from_int (clip_extents->x), + _cairo_fixed_from_int (clip_extents->y)); + } + if (unlikely (status)) goto BAIL; - goto DONE; + prev = prev->prev; + goto NEXT_PATH; } else { - if (clip_path->surface != NULL && - clip_path->surface->backend == surface->backend) - { - _cairo_pattern_init_for_surface (&pattern.surface, - clip_path->surface); - cairo_matrix_init_translate (&pattern.base.matrix, - -clip_path->extents.x + clip_extents->x, - -clip_path->extents.y + clip_extents->y); - status = _cairo_surface_paint (surface, - CAIRO_OPERATOR_IN, - &pattern.base, - NULL); - - _cairo_pattern_fini (&pattern.base); - - if (unlikely (status)) - goto BAIL; - - goto DONE; - } else { - /* XXX build intermediate surfaces? */ - if (need_translate) { - _cairo_path_fixed_translate (&clip_path->path, - _cairo_fixed_from_int (-clip_extents->x), - _cairo_fixed_from_int (-clip_extents->y)); - } - status = _cairo_surface_fill (surface, - CAIRO_OPERATOR_IN, - &pattern.base, - &clip_path->path, - clip_path->fill_rule, - clip_path->tolerance, - clip_path->antialias, - NULL); - if (need_translate) { - _cairo_path_fixed_translate (&clip_path->path, - _cairo_fixed_from_int (clip_extents->x), - _cairo_fixed_from_int (clip_extents->y)); - } - } + _cairo_pattern_init_for_surface (&pattern.surface, + _cairo_clip_path_get_surface (prev, + target)); + cairo_matrix_init_translate (&pattern.base.matrix, + -prev->extents.x + clip_extents->x, + -prev->extents.y + clip_extents->y); + status = _cairo_surface_paint (surface, + CAIRO_OPERATOR_IN, + &pattern.base, + NULL); + _cairo_pattern_fini (&pattern.base); + if (unlikely (status)) goto BAIL; } } -DONE: - cairo_surface_destroy (clip->path->surface); - return clip->path->surface = cairo_surface_reference (surface); + DONE: + cairo_surface_destroy (clip_path->surface); + return clip_path->surface = cairo_surface_reference (surface); -BAIL: + BAIL: cairo_surface_destroy (surface); return _cairo_surface_create_in_error (status); } +void +_cairo_debug_print_clip (FILE *stream, cairo_clip_t *clip) +{ + cairo_clip_path_t *clip_path; + + if (clip == NULL) { + fprintf (stream, "no clip\n"); + return; + } + + if (clip->all_clipped) { + fprintf (stream, "clip: all-clipped\n"); + return; + } + + if (clip->path == NULL) { + fprintf (stream, "clip: empty\n"); + return; + } + + fprintf (stream, "clip:\n"); + + clip_path = clip->path; + do { + fprintf (stream, "path: has region? %s, has surface? %s: ", + clip_path->region == NULL ? "no" : "yes", + clip_path->surface == NULL ? "no" : "yes"); + _cairo_debug_print_path (stream, &clip_path->path); + } while ((clip_path = clip_path->prev) != NULL); +} + +cairo_surface_t * +_cairo_clip_get_surface (cairo_clip_t *clip, cairo_surface_t *target) +{ + assert (clip->path != NULL); + return _cairo_clip_path_get_surface (clip->path, target); +} + cairo_status_t _cairo_clip_combine_with_surface (cairo_clip_t *clip, cairo_surface_t *dst) { |