summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris Wilson <chris@chris-wilson.co.uk>2009-08-24 07:06:32 +0100
committerChris Wilson <chris@chris-wilson.co.uk>2009-08-29 08:08:32 +0100
commit85094c4eee4e50ec724bf1bb54ecff6f7c1014bf (patch)
tree43dda4b766dbc427e5e9d88d0bacde7fb161f0e2
parentff0ca6d02a2e8901e9cfca31326c3fdc16e77e2f (diff)
[clip] Eliminate redundant clips
First perform a simple geometric clip to catch the majority of cases where an unaligned clip has been set outside the operation extents that can be discarded without having to use an image surface. This causes a dramatic increase of over 13x for the poppler-bug-12266 trace and little impact elsewhere for more sensible clippers.
-rw-r--r--src/cairo-clip-private.h8
-rw-r--r--src/cairo-clip.c187
-rw-r--r--src/cairo-gstate.c106
-rw-r--r--src/cairo-path-fill.c3
-rw-r--r--src/cairo-surface-fallback.c111
5 files changed, 309 insertions, 106 deletions
diff --git a/src/cairo-clip-private.h b/src/cairo-clip-private.h
index 8a3e867ab..d045d12e3 100644
--- a/src/cairo-clip-private.h
+++ b/src/cairo-clip-private.h
@@ -79,7 +79,7 @@ cairo_private cairo_status_t
_cairo_clip_init_rectangle (cairo_clip_t *clip,
const cairo_rectangle_int_t *rect);
-cairo_private void
+cairo_private_no_warn cairo_clip_t *
_cairo_clip_init_copy (cairo_clip_t *clip, cairo_clip_t *other);
cairo_private cairo_status_t
@@ -90,6 +90,12 @@ _cairo_clip_init_copy_transformed (cairo_clip_t *clip,
cairo_private void
_cairo_clip_reset (cairo_clip_t *clip);
+#define _cairo_clip_fini(clip) _cairo_clip_reset (clip)
+
+cairo_private cairo_status_t
+_cairo_clip_rectangle (cairo_clip_t *clip,
+ const cairo_rectangle_int_t *rectangle);
+
cairo_private cairo_status_t
_cairo_clip_clip (cairo_clip_t *clip,
const cairo_path_fixed_t *path,
diff --git a/src/cairo-clip.c b/src/cairo-clip.c
index 7aa4d5e5a..320051183 100644
--- a/src/cairo-clip.c
+++ b/src/cairo-clip.c
@@ -205,21 +205,25 @@ _cairo_clip_set_all_clipped (cairo_clip_t *clip)
}
}
-/* XXX consider accepting a matrix, no users yet. */
-cairo_status_t
-_cairo_clip_init_rectangle (cairo_clip_t *clip,
- const cairo_rectangle_int_t *rect)
+static cairo_status_t
+_cairo_clip_intersect_rectangle (cairo_clip_t *clip,
+ const cairo_rectangle_int_t *rect)
{
cairo_clip_path_t *clip_path;
cairo_status_t status;
- _cairo_clip_init (clip);
- if (rect == NULL)
- return CAIRO_STATUS_SUCCESS;
+ if (clip->path != NULL) {
+ cairo_box_t box;
- if (rect->width == 0 || rect->height == 0) {
- _cairo_clip_set_all_clipped (clip);
- return CAIRO_STATUS_SUCCESS;
+ if (_cairo_path_fixed_is_box (&clip->path->path, &box)) {
+ if (box.p1.x >= _cairo_fixed_from_int (rect->x) &&
+ box.p1.y >= _cairo_fixed_from_int (rect->y) &&
+ box.p2.x <= _cairo_fixed_from_int (rect->x + rect->width) &&
+ box.p2.y <= _cairo_fixed_from_int (rect->y + rect->height))
+ {
+ return CAIRO_STATUS_SUCCESS;
+ }
+ }
}
clip_path = _cairo_clip_path_create (clip);
@@ -257,16 +261,40 @@ _cairo_clip_init_rectangle (cairo_clip_t *clip,
return CAIRO_STATUS_SUCCESS;
}
-void
+/* XXX consider accepting a matrix, no users yet. */
+cairo_status_t
+_cairo_clip_init_rectangle (cairo_clip_t *clip,
+ const cairo_rectangle_int_t *rect)
+{
+ _cairo_clip_init (clip);
+
+ if (rect == NULL)
+ return CAIRO_STATUS_SUCCESS;
+
+ if (rect->width == 0 || rect->height == 0) {
+ _cairo_clip_set_all_clipped (clip);
+ return CAIRO_STATUS_SUCCESS;
+ }
+
+ return _cairo_clip_intersect_rectangle (clip, rect);
+}
+
+cairo_clip_t *
_cairo_clip_init_copy (cairo_clip_t *clip, cairo_clip_t *other)
{
if (other != NULL) {
- clip->all_clipped = other->all_clipped;
- clip->path = _cairo_clip_path_reference (other->path);
+ if (other->path == NULL) {
+ _cairo_clip_init (clip);
+ clip = NULL;
+ } else {
+ clip->all_clipped = other->all_clipped;
+ clip->path = _cairo_clip_path_reference (other->path);
+ }
} else {
- clip->all_clipped = FALSE;
- clip->path = NULL;
+ _cairo_clip_init (clip);
}
+
+ return clip;
}
void
@@ -291,15 +319,13 @@ _cairo_clip_intersect_path (cairo_clip_t *clip,
cairo_rectangle_int_t extents;
if (clip->path != NULL) {
- if (_cairo_path_fixed_equal (&clip->path->path, path)) {
- if (clip->path->fill_rule == fill_rule) {
- if (path->is_rectilinear ||
- (tolerance == clip->path->tolerance &&
- antialias == clip->path->antialias))
- {
- return CAIRO_STATUS_SUCCESS;
- }
- }
+ if (clip->path->fill_rule == fill_rule &&
+ (path->is_rectilinear ||
+ (tolerance == clip->path->tolerance &&
+ antialias == clip->path->antialias)) &&
+ _cairo_path_fixed_equal (&clip->path->path, path))
+ {
+ return CAIRO_STATUS_SUCCESS;
}
}
@@ -369,6 +395,32 @@ _cairo_clip_clip (cairo_clip_t *clip,
antialias);
}
+cairo_status_t
+_cairo_clip_rectangle (cairo_clip_t *clip,
+ const cairo_rectangle_int_t *rectangle)
+{
+ if (clip->all_clipped)
+ return CAIRO_STATUS_SUCCESS;
+
+ if (rectangle->width == 0 || rectangle->height == 0) {
+ _cairo_clip_set_all_clipped (clip);
+ return CAIRO_STATUS_SUCCESS;
+ }
+
+ /* if a smaller clip has already been set, ignore the new path */
+ if (clip->path != NULL) {
+ if (rectangle->x <= clip->path->extents.x &&
+ rectangle->y <= clip->path->extents.x &&
+ rectangle->x + rectangle->width >= clip->path->extents.x + clip->path->extents.width &&
+ rectangle->y + rectangle->height >= clip->path->extents.y + clip->path->extents.height)
+ {
+ return CAIRO_STATUS_SUCCESS;
+ }
+ }
+
+ return _cairo_clip_intersect_rectangle (clip, rectangle);
+}
+
static cairo_status_t
_cairo_clip_path_reapply_clip_path_transform (cairo_clip_t *clip,
cairo_clip_path_t *other_path,
@@ -548,6 +600,65 @@ _cairo_clip_apply_clip (cairo_clip_t *clip,
return status;
}
+#if 0
+static inline cairo_bool_t
+_clip_paths_are_rectilinear (cairo_clip_path_t *clip_path)
+{
+ while (clip_path != NULL) {
+ if (! clip_path->path.is_rectilinear)
+ return FALSE;
+
+ clip_path = clip_path->prev;
+ }
+
+ return TRUE;
+}
+#endif
+
+static cairo_int_status_t
+_cairo_clip_path_to_region_geometric (cairo_clip_path_t *clip_path)
+{
+ cairo_traps_t traps;
+ cairo_box_t box;
+ cairo_status_t status;
+
+ /* If we have nothing to intersect with this path, then it cannot
+ * magically be reduced into a region.
+ */
+ if (clip_path->prev == NULL)
+ goto UNSUPPORTED;
+
+ /* start simple... */
+ if (! clip_path->path.maybe_fill_region)
+ goto UNSUPPORTED;
+
+ _cairo_traps_init (&traps);
+ _cairo_box_from_rectangle (&box, &clip_path->extents);
+ _cairo_traps_limit (&traps, &box);
+
+ status = _cairo_path_fixed_fill_to_traps (&clip_path->prev->path,
+ clip_path->prev->fill_rule,
+ clip_path->prev->tolerance,
+ &traps);
+ if (unlikely (status))
+ return status;
+
+ status = _cairo_traps_extract_region (&traps, &clip_path->region);
+ _cairo_traps_fini (&traps);
+
+ if (status == CAIRO_INT_STATUS_UNSUPPORTED)
+ goto UNSUPPORTED;
+ if (unlikely (status))
+ return status;
+
+ clip_path->flags |= CAIRO_CLIP_PATH_HAS_REGION;
+ return CAIRO_STATUS_SUCCESS;
+
+UNSUPPORTED:
+ clip_path->flags |= CAIRO_CLIP_PATH_REGION_IS_UNSUPPORTED;
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+}
+
static cairo_int_status_t
_cairo_clip_path_to_region (cairo_clip_path_t *clip_path)
{
@@ -563,16 +674,16 @@ _cairo_clip_path_to_region (cairo_clip_path_t *clip_path)
CAIRO_STATUS_SUCCESS;
}
- if (! clip_path->path.maybe_fill_region) {
- clip_path->flags |= CAIRO_CLIP_PATH_REGION_IS_UNSUPPORTED;
- return CAIRO_INT_STATUS_UNSUPPORTED;
- }
+ if (! clip_path->path.maybe_fill_region)
+ return _cairo_clip_path_to_region_geometric (clip_path);
/* first retrieve the region for our antecedents */
if (clip_path->prev != NULL) {
status = _cairo_clip_path_to_region (clip_path->prev);
if (status) {
- clip_path->flags |= CAIRO_CLIP_PATH_REGION_IS_UNSUPPORTED;
+ if (status == CAIRO_INT_STATUS_UNSUPPORTED)
+ return _cairo_clip_path_to_region_geometric (clip_path);
+
return status;
}
@@ -581,7 +692,6 @@ _cairo_clip_path_to_region (cairo_clip_path_t *clip_path)
/* now extract the region for ourselves */
- /* XXX just use the cheap search for now */
clip_path->region =
_cairo_path_fixed_fill_rectilinear_to_region (&clip_path->path,
clip_path->fill_rule,
@@ -647,7 +757,7 @@ _cairo_clip_get_surface (cairo_clip_t *clip, cairo_surface_t *target)
CAIRO_CONTENT_COLOR);
status = _cairo_clip_get_region (clip, &clip_region);
- if (_cairo_status_is_error (status))
+ if (unlikely (_cairo_status_is_error (status)))
goto BAIL;
need_translate = clip_extents->x || clip_extents->y;
@@ -693,18 +803,18 @@ _cairo_clip_get_surface (cairo_clip_t *clip, cairo_surface_t *target)
}
while ((clip_path = clip_path->prev) != NULL) {
- status = _cairo_clip_get_region (clip, &clip_region);
- if (_cairo_status_is_error (status))
+ status = _cairo_clip_path_to_region (clip_path);
+ if (unlikely (_cairo_status_is_error (status)))
goto BAIL;
if (status == CAIRO_STATUS_SUCCESS) {
- 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_IN,
CAIRO_COLOR_WHITE,
- clip_region);
- cairo_region_translate (clip_region,
+ clip_path->region);
+ cairo_region_translate (clip_path->region,
clip_extents->x, clip_extents->y);
if (unlikely (status))
goto BAIL;
@@ -844,6 +954,11 @@ _cairo_clip_get_region (cairo_clip_t *clip,
if (status)
return status;
+ if (cairo_region_is_empty (clip->path->region)) {
+ _cairo_clip_set_all_clipped (clip);
+ return CAIRO_INT_STATUS_NOTHING_TO_DO;
+ }
+
*region = clip->path->region;
return CAIRO_STATUS_SUCCESS;
}
diff --git a/src/cairo-gstate.c b/src/cairo-gstate.c
index 344c34cdc..e17df67a2 100644
--- a/src/cairo-gstate.c
+++ b/src/cairo-gstate.c
@@ -860,7 +860,10 @@ _cairo_gstate_copy_transformed_mask (cairo_gstate_t *gstate,
&gstate->ctm_inverse);
}
-#define _gstate_get_clip(g) ((g)->clip.path ? &(g)->clip : NULL)
+/* We need to take a copy of the clip so that the lower layers may modify it
+ * by, perhaps, intersecting it with the operation extents and other paths.
+ */
+#define _gstate_get_clip(G, C) _cairo_clip_init_copy ((C), &(G)->clip)
static cairo_bool_t
_clipped (const cairo_gstate_t *gstate)
@@ -870,11 +873,12 @@ _clipped (const cairo_gstate_t *gstate)
if (gstate->clip.all_clipped)
return TRUE;
- if (gstate->clip.path == NULL)
- return FALSE;
-
if (_cairo_surface_get_extents (gstate->target, &extents)) {
- if (! _cairo_rectangle_intersect (&extents,
+ if (extents.width == 0 || extents.height == 0)
+ return TRUE;
+
+ if (gstate->clip.path != NULL &&
+ ! _cairo_rectangle_intersect (&extents,
&gstate->clip.path->extents))
{
return TRUE;
@@ -888,6 +892,8 @@ cairo_status_t
_cairo_gstate_paint (cairo_gstate_t *gstate)
{
cairo_pattern_union_t pattern;
+ cairo_clip_t clip;
+ cairo_status_t status;
if (unlikely (gstate->source->status))
return gstate->source->status;
@@ -897,10 +903,13 @@ _cairo_gstate_paint (cairo_gstate_t *gstate)
_cairo_gstate_copy_transformed_source (gstate, &pattern.base);
- return _cairo_surface_paint (gstate->target,
- gstate->op,
- &pattern.base,
- _gstate_get_clip (gstate));
+ status = _cairo_surface_paint (gstate->target,
+ gstate->op,
+ &pattern.base,
+ _gstate_get_clip (gstate, &clip));
+ _cairo_clip_fini (&clip);
+
+ return status;
}
cairo_status_t
@@ -908,6 +917,8 @@ _cairo_gstate_mask (cairo_gstate_t *gstate,
cairo_pattern_t *mask)
{
cairo_pattern_union_t source_pattern, mask_pattern;
+ cairo_clip_t clip;
+ cairo_status_t status;
if (unlikely (mask->status))
return mask->status;
@@ -921,17 +932,22 @@ _cairo_gstate_mask (cairo_gstate_t *gstate,
_cairo_gstate_copy_transformed_source (gstate, &source_pattern.base);
_cairo_gstate_copy_transformed_mask (gstate, &mask_pattern.base, mask);
- return _cairo_surface_mask (gstate->target,
- gstate->op,
- &source_pattern.base,
- &mask_pattern.base,
- _gstate_get_clip (gstate));
+ status = _cairo_surface_mask (gstate->target,
+ gstate->op,
+ &source_pattern.base,
+ &mask_pattern.base,
+ _gstate_get_clip (gstate, &clip));
+ _cairo_clip_fini (&clip);
+
+ return status;
}
cairo_status_t
_cairo_gstate_stroke (cairo_gstate_t *gstate, cairo_path_fixed_t *path)
{
cairo_pattern_union_t source_pattern;
+ cairo_clip_t clip;
+ cairo_status_t status;
if (unlikely (gstate->source->status))
return gstate->source->status;
@@ -944,16 +960,19 @@ _cairo_gstate_stroke (cairo_gstate_t *gstate, cairo_path_fixed_t *path)
_cairo_gstate_copy_transformed_source (gstate, &source_pattern.base);
- return _cairo_surface_stroke (gstate->target,
- gstate->op,
- &source_pattern.base,
- path,
- &gstate->stroke_style,
- &gstate->ctm,
- &gstate->ctm_inverse,
- gstate->tolerance,
- gstate->antialias,
- _gstate_get_clip (gstate));
+ status = _cairo_surface_stroke (gstate->target,
+ gstate->op,
+ &source_pattern.base,
+ path,
+ &gstate->stroke_style,
+ &gstate->ctm,
+ &gstate->ctm_inverse,
+ gstate->tolerance,
+ gstate->antialias,
+ _gstate_get_clip (gstate, &clip));
+ _cairo_clip_fini (&clip);
+
+ return status;
}
cairo_status_t
@@ -1018,6 +1037,8 @@ cairo_status_t
_cairo_gstate_fill (cairo_gstate_t *gstate, cairo_path_fixed_t *path)
{
cairo_pattern_union_t pattern;
+ cairo_clip_t clip;
+ cairo_status_t status;
if (unlikely (gstate->source->status))
return gstate->source->status;
@@ -1032,22 +1053,26 @@ _cairo_gstate_fill (cairo_gstate_t *gstate, cairo_path_fixed_t *path)
_cairo_pattern_init_solid (&pattern.solid,
CAIRO_COLOR_TRANSPARENT,
CAIRO_CONTENT_COLOR_ALPHA);
- return _cairo_surface_paint (gstate->target,
- CAIRO_OPERATOR_CLEAR,
- &pattern.base,
- _gstate_get_clip (gstate));
+ status = _cairo_surface_paint (gstate->target,
+ CAIRO_OPERATOR_CLEAR,
+ &pattern.base,
+ _gstate_get_clip (gstate, &clip));
+ } else {
+ _cairo_gstate_copy_transformed_source (gstate, &pattern.base);
+
+ status = _cairo_surface_fill (gstate->target,
+ gstate->op,
+ &pattern.base,
+ path,
+ gstate->fill_rule,
+ gstate->tolerance,
+ gstate->antialias,
+ _gstate_get_clip (gstate, &clip));
}
- _cairo_gstate_copy_transformed_source (gstate, &pattern.base);
+ _cairo_clip_fini (&clip);
- return _cairo_surface_fill (gstate->target,
- gstate->op,
- &pattern.base,
- path,
- gstate->fill_rule,
- gstate->tolerance,
- gstate->antialias,
- _gstate_get_clip (gstate));
+ return status;
}
cairo_bool_t
@@ -1642,6 +1667,7 @@ _cairo_gstate_show_text_glyphs (cairo_gstate_t *gstate,
cairo_text_cluster_t stack_transformed_clusters[CAIRO_STACK_ARRAY_LENGTH (cairo_text_cluster_t)];
cairo_text_cluster_t *transformed_clusters;
cairo_status_t status;
+ cairo_clip_t clip;
if (unlikely (gstate->source->status))
return gstate->source->status;
@@ -1711,7 +1737,7 @@ _cairo_gstate_show_text_glyphs (cairo_gstate_t *gstate,
transformed_clusters, num_clusters,
cluster_flags,
gstate->scaled_font,
- _gstate_get_clip (gstate));
+ _gstate_get_clip (gstate, &clip));
}
else
{
@@ -1731,12 +1757,14 @@ _cairo_gstate_show_text_glyphs (cairo_gstate_t *gstate,
CAIRO_FILL_RULE_WINDING,
gstate->tolerance,
gstate->scaled_font->options.antialias,
- _gstate_get_clip (gstate));
+ _gstate_get_clip (gstate, &clip));
}
_cairo_path_fixed_fini (&path);
}
+ _cairo_clip_fini (&clip);
+
CLEANUP_GLYPHS:
if (transformed_glyphs != stack_transformed_glyphs)
cairo_glyph_free (transformed_glyphs);
diff --git a/src/cairo-path-fill.c b/src/cairo-path-fill.c
index b74bf0aa4..50cd2183a 100644
--- a/src/cairo-path-fill.c
+++ b/src/cairo-path-fill.c
@@ -157,6 +157,9 @@ _cairo_path_fixed_fill_to_traps (const cairo_path_fixed_t *path,
cairo_status_t status;
_cairo_polygon_init (&polygon);
+ if (traps->has_limits)
+ _cairo_polygon_limit (&polygon, &traps->limits);
+
status = _cairo_path_fixed_fill_to_polygon (path,
tolerance,
&polygon);
diff --git a/src/cairo-surface-fallback.c b/src/cairo-surface-fallback.c
index bba26a7af..cca63846a 100644
--- a/src/cairo-surface-fallback.c
+++ b/src/cairo-surface-fallback.c
@@ -133,6 +133,9 @@ _create_composite_mask_pattern (cairo_surface_pattern_t *mask_pattern,
status = _cairo_clip_get_region (clip, &clip_region);
assert (! _cairo_status_is_error (status));
+ /* The all-clipped state should never propagate this far. */
+ assert (status != CAIRO_INT_STATUS_NOTHING_TO_DO);
+
clip_surface = status == CAIRO_INT_STATUS_UNSUPPORTED;
if (clip_region && cairo_region_num_rectangles (clip_region) == 1)
@@ -349,23 +352,26 @@ _clip_and_composite_source (cairo_clip_t *clip,
cairo_region_t *clip_region = NULL;
cairo_status_t status;
- /* Create a surface that is mask IN clip */
- status = _create_composite_mask_pattern (&mask_pattern,
- clip,
- draw_func, draw_closure,
- dst, extents);
- if (unlikely (status))
- return status;
-
if (clip != NULL) {
status = _cairo_clip_get_region (clip, &clip_region);
assert (! _cairo_status_is_error (status));
+ if (unlikely (status == CAIRO_INT_STATUS_NOTHING_TO_DO))
+ return CAIRO_STATUS_SUCCESS;
/* a solitary clip rectangle is already accommodated by extents */
if (clip_region && cairo_region_num_rectangles (clip_region) == 1)
clip_region = NULL;
}
+
+ /* Create a surface that is mask IN clip */
+ status = _create_composite_mask_pattern (&mask_pattern,
+ clip,
+ draw_func, draw_closure,
+ dst, extents);
+ if (unlikely (status))
+ return status;
+
/* Compute dest' = dest OUT (mask IN clip) */
status = _cairo_surface_composite (CAIRO_OPERATOR_DEST_OUT,
&mask_pattern.base, NULL, dst,
@@ -454,6 +460,8 @@ _clip_and_composite (cairo_clip_t *clip,
if (clip != NULL) {
status = _cairo_clip_get_region (clip, &clip_region);
assert (! _cairo_status_is_error (status));
+ if (unlikely (status == CAIRO_INT_STATUS_NOTHING_TO_DO))
+ return CAIRO_STATUS_SUCCESS;
clip_surface = status == CAIRO_INT_STATUS_UNSUPPORTED;
}
@@ -670,9 +678,9 @@ _clip_and_composite_trapezoids (const cairo_pattern_t *src,
status = _cairo_clip_get_region (clip, &clip_region);
if (unlikely (_cairo_status_is_error (status)))
return status;
+ if (unlikely (status == CAIRO_INT_STATUS_NOTHING_TO_DO))
+ return CAIRO_STATUS_SUCCESS;
- /* The all-clipped state should not have been propagated this far. */
- assert (status != CAIRO_INT_STATUS_NOTHING_TO_DO);
clip_surface = status == CAIRO_INT_STATUS_UNSUPPORTED;
}
@@ -785,18 +793,21 @@ _composite_spans_draw_func (void *closure,
clip_region);
}
-static cairo_bool_t
+static cairo_status_t
_rectangle_intersect_clip (cairo_rectangle_int_t *extents, cairo_clip_t *clip)
{
if (clip != NULL) {
- const cairo_rectangle_int_t *clip_extents;
+ if (! _cairo_rectangle_intersect (extents,
+ _cairo_clip_get_extents (clip)))
+ {
+ return CAIRO_INT_STATUS_NOTHING_TO_DO;
+ }
- clip_extents = _cairo_clip_get_extents (clip);
- if (clip_extents != NULL)
- return _cairo_rectangle_intersect (extents, clip_extents);
- }
+ return _cairo_clip_rectangle (clip, extents);
+ } else if (_cairo_rectangle_empty (extents))
+ return CAIRO_INT_STATUS_NOTHING_TO_DO;
- return ! _cairo_rectangle_empty (extents);
+ return CAIRO_STATUS_SUCCESS;
}
cairo_status_t
@@ -824,17 +835,21 @@ _cairo_surface_fallback_paint (cairo_surface_t *surface,
return CAIRO_STATUS_SUCCESS;
}
- if (! _rectangle_intersect_clip (&extents, clip))
- return CAIRO_STATUS_SUCCESS;
+ status = _rectangle_intersect_clip (&extents, clip);
+ if (status) {
+ if (status == CAIRO_INT_STATUS_NOTHING_TO_DO)
+ status = CAIRO_STATUS_SUCCESS;
+ return status;
+ }
/* avoid the palaver of constructing traps for a simple region */
if (clip != NULL) {
status = _cairo_clip_get_region (clip, &clip_region);
if (unlikely (_cairo_status_is_error (status)))
return status;
+ if (unlikely (status == CAIRO_INT_STATUS_NOTHING_TO_DO))
+ return CAIRO_STATUS_SUCCESS;
- /* The all-clipped state should not have been propagated this far. */
- assert (status != CAIRO_INT_STATUS_NOTHING_TO_DO);
clip_surface = status == CAIRO_INT_STATUS_UNSUPPORTED;
}
@@ -929,6 +944,7 @@ _cairo_surface_fallback_mask (cairo_surface_t *surface,
{
cairo_rectangle_int_t extents;
cairo_bool_t is_bounded;
+ cairo_status_t status;
is_bounded = _cairo_surface_get_extents (surface, &extents);
assert (is_bounded || clip);
@@ -949,8 +965,12 @@ _cairo_surface_fallback_mask (cairo_surface_t *surface,
return CAIRO_STATUS_SUCCESS;
}
- if (! _rectangle_intersect_clip (&extents, clip))
- return CAIRO_STATUS_SUCCESS;
+ status = _rectangle_intersect_clip (&extents, clip);
+ if (status) {
+ if (status == CAIRO_INT_STATUS_NOTHING_TO_DO)
+ status = CAIRO_STATUS_SUCCESS;
+ return status;
+ }
return _clip_and_composite (clip, op, source,
_cairo_surface_mask_draw_func,
@@ -988,8 +1008,22 @@ _cairo_surface_fallback_stroke (cairo_surface_t *surface,
return CAIRO_STATUS_SUCCESS;
}
- if (! _rectangle_intersect_clip (&extents, clip))
- return CAIRO_STATUS_SUCCESS;
+ if (_cairo_operator_bounded_by_mask (op)) {
+ cairo_rectangle_int_t path_extents;
+
+ _cairo_path_fixed_approximate_stroke_extents (path,
+ stroke_style, ctm,
+ &path_extents);
+ if (! _cairo_rectangle_intersect (&extents, &path_extents))
+ return CAIRO_STATUS_SUCCESS;
+ }
+
+ status = _rectangle_intersect_clip (&extents, clip);
+ if (status) {
+ if (status == CAIRO_INT_STATUS_NOTHING_TO_DO)
+ status = CAIRO_STATUS_SUCCESS;
+ return status;
+ }
_cairo_box_from_rectangle (&box, &extents);
@@ -1092,8 +1126,20 @@ _cairo_surface_fallback_fill (cairo_surface_t *surface,
return CAIRO_STATUS_SUCCESS;
}
- if (! _rectangle_intersect_clip (&extents, clip))
- return CAIRO_STATUS_SUCCESS;
+ if (_cairo_operator_bounded_by_mask (op)) {
+ cairo_rectangle_int_t path_extents;
+
+ _cairo_path_fixed_approximate_fill_extents (path, &path_extents);
+ if (! _cairo_rectangle_intersect (&extents, &path_extents))
+ return CAIRO_STATUS_SUCCESS;
+ }
+
+ status = _rectangle_intersect_clip (&extents, clip);
+ if (status) {
+ if (status == CAIRO_INT_STATUS_NOTHING_TO_DO)
+ status = CAIRO_STATUS_SUCCESS;
+ return status;
+ }
/* avoid the palaver of constructing traps for a simple region */
if (path->maybe_fill_region) {
@@ -1104,8 +1150,9 @@ _cairo_surface_fallback_fill (cairo_surface_t *surface,
status = _cairo_clip_get_region (clip, &clip_region);
if (unlikely (_cairo_status_is_error (status)))
return status;
+ if (unlikely (status == CAIRO_INT_STATUS_NOTHING_TO_DO))
+ return CAIRO_STATUS_SUCCESS;
- assert (status != CAIRO_INT_STATUS_NOTHING_TO_DO);
clip_surface = status == CAIRO_INT_STATUS_UNSUPPORTED;
}
@@ -1310,8 +1357,12 @@ _cairo_surface_fallback_show_glyphs (cairo_surface_t *surface,
return CAIRO_STATUS_SUCCESS;
}
- if (! _rectangle_intersect_clip (&extents, clip))
- return CAIRO_STATUS_SUCCESS;
+ status = _rectangle_intersect_clip (&extents, clip);
+ if (status) {
+ if (status == CAIRO_INT_STATUS_NOTHING_TO_DO)
+ status = CAIRO_STATUS_SUCCESS;
+ return status;
+ }
glyph_info.font = scaled_font;
glyph_info.glyphs = glyphs;