mirror of
https://gitlab.freedesktop.org/cairo/cairo.git
synced 2026-05-06 08:08:04 +02:00
[cairo-clip] Avoid work when all clipped out.
When the clip mask is empty we perform actions like composite 0x0 surfaces, which results in a lot of unnecessary work and allocations. Avoid doing work when we know everything is clip out and take the liberty of freeing any memory associated with the clop state.
This commit is contained in:
parent
c70c2cf6d6
commit
5c08226a0f
2 changed files with 79 additions and 9 deletions
|
|
@ -53,6 +53,8 @@ struct _cairo_clip_path {
|
|||
struct _cairo_clip {
|
||||
cairo_clip_mode_t mode;
|
||||
|
||||
cairo_bool_t all_clipped;
|
||||
|
||||
/*
|
||||
* Mask-based clipping for cases where the backend
|
||||
* clipping isn't sufficiently able.
|
||||
|
|
|
|||
|
|
@ -54,6 +54,8 @@ _cairo_clip_init (cairo_clip_t *clip, cairo_surface_t *target)
|
|||
else
|
||||
clip->mode = CAIRO_CLIP_MODE_MASK;
|
||||
|
||||
clip->all_clipped = FALSE;
|
||||
|
||||
clip->surface = NULL;
|
||||
clip->surface_rect.x = 0;
|
||||
clip->surface_rect.y = 0;
|
||||
|
|
@ -73,6 +75,8 @@ _cairo_clip_init_copy (cairo_clip_t *clip, cairo_clip_t *other)
|
|||
{
|
||||
clip->mode = other->mode;
|
||||
|
||||
clip->all_clipped = other->all_clipped;
|
||||
|
||||
clip->surface = cairo_surface_reference (other->surface);
|
||||
clip->surface_rect = other->surface_rect;
|
||||
|
||||
|
|
@ -81,12 +85,12 @@ _cairo_clip_init_copy (cairo_clip_t *clip, cairo_clip_t *other)
|
|||
_cairo_region_init (&clip->region);
|
||||
|
||||
if (other->has_region) {
|
||||
if (_cairo_region_copy (&clip->region, &other->region) !=
|
||||
CAIRO_STATUS_SUCCESS)
|
||||
{
|
||||
cairo_status_t status;
|
||||
status = _cairo_region_copy (&clip->region, &other->region);
|
||||
if (status) {
|
||||
_cairo_region_fini (&clip->region);
|
||||
cairo_surface_destroy (clip->surface);
|
||||
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
|
||||
return status;
|
||||
}
|
||||
clip->has_region = TRUE;
|
||||
} else {
|
||||
|
|
@ -94,13 +98,15 @@ _cairo_clip_init_copy (cairo_clip_t *clip, cairo_clip_t *other)
|
|||
}
|
||||
|
||||
clip->path = _cairo_clip_path_reference (other->path);
|
||||
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
void
|
||||
_cairo_clip_reset (cairo_clip_t *clip)
|
||||
{
|
||||
clip->all_clipped = FALSE;
|
||||
|
||||
/* destroy any existing clip-region artifacts */
|
||||
cairo_surface_destroy (clip->surface);
|
||||
clip->surface = NULL;
|
||||
|
|
@ -121,9 +127,19 @@ _cairo_clip_reset (cairo_clip_t *clip)
|
|||
clip->path = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
_cairo_clip_set_all_clipped (cairo_clip_t *clip, cairo_surface_t *target)
|
||||
{
|
||||
_cairo_clip_reset (clip);
|
||||
|
||||
clip->all_clipped = TRUE;
|
||||
clip->serial = _cairo_surface_allocate_clip_serial (target);
|
||||
}
|
||||
|
||||
|
||||
static cairo_status_t
|
||||
_cairo_clip_path_intersect_to_rectangle (cairo_clip_path_t *clip_path,
|
||||
cairo_rectangle_int_t *rectangle)
|
||||
cairo_rectangle_int_t *rectangle)
|
||||
{
|
||||
while (clip_path) {
|
||||
cairo_status_t status;
|
||||
|
|
@ -161,9 +177,14 @@ _cairo_clip_intersect_to_rectangle (cairo_clip_t *clip,
|
|||
if (!clip)
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
|
||||
if (clip->all_clipped) {
|
||||
*rectangle = clip->surface_rect;
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
if (clip->path) {
|
||||
cairo_status_t status;
|
||||
|
||||
|
||||
status = _cairo_clip_path_intersect_to_rectangle (clip->path,
|
||||
rectangle);
|
||||
if (status)
|
||||
|
|
@ -203,6 +224,18 @@ _cairo_clip_intersect_to_region (cairo_clip_t *clip,
|
|||
if (!clip)
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
|
||||
if (clip->all_clipped) {
|
||||
cairo_region_t clip_rect;
|
||||
|
||||
_cairo_region_init_rect (&clip_rect, &clip->surface_rect);
|
||||
|
||||
status = _cairo_region_intersect (region, &clip_rect, region);
|
||||
|
||||
_cairo_region_fini (&clip_rect);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
if (clip->path) {
|
||||
/* Intersect clip path into region. */
|
||||
}
|
||||
|
|
@ -244,6 +277,9 @@ _cairo_clip_combine_to_surface (cairo_clip_t *clip,
|
|||
cairo_pattern_union_t pattern;
|
||||
cairo_status_t status;
|
||||
|
||||
if (clip->all_clipped)
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
|
||||
_cairo_pattern_init_for_surface (&pattern.surface, clip->surface);
|
||||
|
||||
status = _cairo_surface_composite (op,
|
||||
|
|
@ -324,6 +360,7 @@ _cairo_clip_path_destroy (cairo_clip_path_t *clip_path)
|
|||
free (clip_path);
|
||||
}
|
||||
|
||||
|
||||
static cairo_int_status_t
|
||||
_cairo_clip_intersect_region (cairo_clip_t *clip,
|
||||
cairo_traps_t *traps,
|
||||
|
|
@ -332,6 +369,9 @@ _cairo_clip_intersect_region (cairo_clip_t *clip,
|
|||
cairo_region_t region;
|
||||
cairo_int_status_t status;
|
||||
|
||||
if (clip->all_clipped)
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
|
||||
if (clip->mode != CAIRO_CLIP_MODE_REGION)
|
||||
return CAIRO_INT_STATUS_UNSUPPORTED;
|
||||
|
||||
|
|
@ -363,6 +403,9 @@ _cairo_clip_intersect_region (cairo_clip_t *clip,
|
|||
clip->serial = _cairo_surface_allocate_clip_serial (target);
|
||||
_cairo_region_fini (®ion);
|
||||
|
||||
if (! _cairo_region_not_empty (&clip->region))
|
||||
_cairo_clip_set_all_clipped (clip, target);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
|
@ -378,6 +421,9 @@ _cairo_clip_intersect_mask (cairo_clip_t *clip,
|
|||
cairo_surface_t *surface;
|
||||
cairo_status_t status;
|
||||
|
||||
if (clip->all_clipped)
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
|
||||
/* Represent the clip as a mask surface. We create a new surface
|
||||
* the size of the intersection of the old mask surface and the
|
||||
* extents of the new clip path. */
|
||||
|
|
@ -395,6 +441,14 @@ _cairo_clip_intersect_mask (cairo_clip_t *clip,
|
|||
if (!status)
|
||||
_cairo_rectangle_intersect (&surface_rect, &target_rect);
|
||||
|
||||
if (surface_rect.width == 0 || surface_rect.height == 0) {
|
||||
surface = NULL;
|
||||
status = CAIRO_STATUS_SUCCESS;
|
||||
if (clip->surface != NULL)
|
||||
cairo_surface_destroy (clip->surface);
|
||||
goto DONE;
|
||||
}
|
||||
|
||||
_cairo_pattern_init_solid (&pattern.solid, CAIRO_COLOR_WHITE,
|
||||
CAIRO_CONTENT_COLOR);
|
||||
surface = _cairo_surface_create_similar_solid (target,
|
||||
|
|
@ -458,10 +512,14 @@ _cairo_clip_intersect_mask (cairo_clip_t *clip,
|
|||
cairo_surface_destroy (clip->surface);
|
||||
}
|
||||
|
||||
DONE:
|
||||
clip->surface = surface;
|
||||
clip->surface_rect = surface_rect;
|
||||
clip->serial = _cairo_surface_allocate_clip_serial (target);
|
||||
|
||||
if (surface_rect.width == 0 || surface_rect.height == 0)
|
||||
_cairo_clip_set_all_clipped (clip, target);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
|
@ -476,6 +534,9 @@ _cairo_clip_clip (cairo_clip_t *clip,
|
|||
cairo_status_t status;
|
||||
cairo_traps_t traps;
|
||||
|
||||
if (clip->all_clipped)
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
|
||||
status = _cairo_clip_intersect_path (clip,
|
||||
path, fill_rule, tolerance,
|
||||
antialias);
|
||||
|
|
@ -510,6 +571,9 @@ _cairo_clip_translate (cairo_clip_t *clip,
|
|||
cairo_fixed_t tx,
|
||||
cairo_fixed_t ty)
|
||||
{
|
||||
if (clip->all_clipped)
|
||||
return;
|
||||
|
||||
if (clip->has_region) {
|
||||
_cairo_region_translate (&clip->region,
|
||||
_cairo_fixed_integer_part (tx),
|
||||
|
|
@ -639,7 +703,10 @@ _cairo_clip_copy_rectangle_list (cairo_clip_t *clip, cairo_gstate_t *gstate)
|
|||
{
|
||||
cairo_rectangle_list_t *list;
|
||||
cairo_rectangle_t *rectangles = NULL;
|
||||
int n_boxes;
|
||||
int n_boxes = 0;
|
||||
|
||||
if (clip->all_clipped)
|
||||
goto DONE;
|
||||
|
||||
if (clip->path || clip->surface)
|
||||
return (cairo_rectangle_list_t*) &_cairo_rectangles_not_representable;
|
||||
|
|
@ -692,13 +759,14 @@ _cairo_clip_copy_rectangle_list (cairo_clip_t *clip, cairo_gstate_t *gstate)
|
|||
}
|
||||
}
|
||||
|
||||
DONE:
|
||||
list = malloc (sizeof (cairo_rectangle_list_t));
|
||||
if (list == NULL) {
|
||||
free (rectangles);
|
||||
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
|
||||
return (cairo_rectangle_list_t*) &_cairo_rectangles_nil;
|
||||
}
|
||||
|
||||
|
||||
list->status = CAIRO_STATUS_SUCCESS;
|
||||
list->rectangles = rectangles;
|
||||
list->num_rectangles = n_boxes;
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue