diff options
author | Chris Wilson <chris@chris-wilson.co.uk> | 2012-05-11 22:38:27 +0100 |
---|---|---|
committer | Chris Wilson <chris@chris-wilson.co.uk> | 2012-05-11 23:14:21 +0100 |
commit | 6cd1f5040fed1385c2990a68d6017a7ca6c37103 (patch) | |
tree | 8da5bd7afbcc123d41ddf841d268d02697662781 /src/cairo-clip-surface.c | |
parent | 4ea3ace6c810ba090464e48795fac5456f6cdc24 (diff) |
clip: Apply clip boxes to the clip surface
As we convert the unaligned clip boxes to a region, we need to process
the intersection of the boxes with the clip surface as a separate step.
Fixes tighten-box for the base compositor.
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Diffstat (limited to 'src/cairo-clip-surface.c')
-rw-r--r-- | src/cairo-clip-surface.c | 86 |
1 files changed, 77 insertions, 9 deletions
diff --git a/src/cairo-clip-surface.c b/src/cairo-clip-surface.c index 523cd424..fff97240 100644 --- a/src/cairo-clip-surface.c +++ b/src/cairo-clip-surface.c @@ -91,6 +91,33 @@ _cairo_clip_combine_with_surface (const cairo_clip_t *clip, return status; } +static cairo_status_t +_cairo_path_fixed_add_box (cairo_path_fixed_t *path, + const cairo_box_t *box, + cairo_fixed_t fx, + cairo_fixed_t fy) +{ + cairo_status_t status; + + status = _cairo_path_fixed_move_to (path, box->p1.x + fx, box->p1.y + fy); + if (unlikely (status)) + return status; + + status = _cairo_path_fixed_line_to (path, box->p2.x + fx, box->p1.y + fy); + if (unlikely (status)) + return status; + + status = _cairo_path_fixed_line_to (path, box->p2.x + fx, box->p2.y + fy); + if (unlikely (status)) + return status; + + status = _cairo_path_fixed_line_to (path, box->p1.x + fx, box->p2.y + fy); + if (unlikely (status)) + return status; + + return _cairo_path_fixed_close_path (path); +} + cairo_surface_t * _cairo_clip_get_surface (const cairo_clip_t *clip, cairo_surface_t *target, @@ -98,16 +125,51 @@ _cairo_clip_get_surface (const cairo_clip_t *clip, { cairo_surface_t *surface; cairo_status_t status; - cairo_clip_t *copy; + cairo_clip_t *copy, *region; cairo_clip_path_t *copy_path, *clip_path; - surface = _cairo_surface_create_similar_solid (target, - CAIRO_CONTENT_ALPHA, - clip->extents.width, - clip->extents.height, - CAIRO_COLOR_WHITE); - if (unlikely (surface->status)) - return surface; + if (clip->num_boxes) { + cairo_path_fixed_t path; + int i; + + surface = _cairo_surface_create_similar_solid (target, + CAIRO_CONTENT_ALPHA, + clip->extents.width, + clip->extents.height, + CAIRO_COLOR_TRANSPARENT); + if (unlikely (surface->status)) + return surface; + + _cairo_path_fixed_init (&path); + status = CAIRO_STATUS_SUCCESS; + for (i = 0; status == CAIRO_STATUS_SUCCESS && i < clip->num_boxes; i++) { + status = _cairo_path_fixed_add_box (&path, &clip->boxes[i], + -_cairo_fixed_from_int (clip->extents.x), + -_cairo_fixed_from_int (clip->extents.y)); + } + if (status == CAIRO_STATUS_SUCCESS) + status = _cairo_surface_fill (surface, + CAIRO_OPERATOR_ADD, + &_cairo_pattern_white.base, + &path, + CAIRO_FILL_RULE_WINDING, + 1., + CAIRO_ANTIALIAS_DEFAULT, + NULL); + _cairo_path_fixed_fini (&path); + if (unlikely (status)) { + cairo_surface_destroy (surface); + return _cairo_surface_create_in_error (status); + } + } else { + surface = _cairo_surface_create_similar_solid (target, + CAIRO_CONTENT_ALPHA, + clip->extents.width, + clip->extents.height, + CAIRO_COLOR_WHITE); + if (unlikely (surface->status)) + return surface; + } copy = _cairo_clip_copy_with_translation (clip, -clip->extents.x, @@ -115,6 +177,10 @@ _cairo_clip_get_surface (const cairo_clip_t *clip, copy_path = copy->path; copy->path = NULL; + region = copy; + if (! _cairo_clip_is_region (copy)) + region = _cairo_clip_copy_region (copy); + status = CAIRO_STATUS_SUCCESS; clip_path = copy_path; while (status == CAIRO_STATUS_SUCCESS && clip_path) { @@ -125,12 +191,14 @@ _cairo_clip_get_surface (const cairo_clip_t *clip, clip_path->fill_rule, clip_path->tolerance, clip_path->antialias, - copy); + region); clip_path = clip_path->prev; } copy->path = copy_path; _cairo_clip_destroy (copy); + if (region != copy) + _cairo_clip_destroy (region); if (unlikely (status)) { cairo_surface_destroy (surface); |