35,20 → 35,83 |
|
#include "cairoint.h" |
|
#include "cairo-clip-inline.h" |
#include "cairo-surface-clipper-private.h" |
|
/* A collection of routines to facilitate vector surface clipping */ |
|
/* XXX Eliminate repeated paths and nested clips */ |
|
static cairo_status_t |
_cairo_path_fixed_add_box (cairo_path_fixed_t *path, |
const cairo_box_t *box) |
{ |
cairo_status_t status; |
|
status = _cairo_path_fixed_move_to (path, box->p1.x, box->p1.y); |
if (unlikely (status)) |
return status; |
|
status = _cairo_path_fixed_line_to (path, box->p2.x, box->p1.y); |
if (unlikely (status)) |
return status; |
|
status = _cairo_path_fixed_line_to (path, box->p2.x, box->p2.y); |
if (unlikely (status)) |
return status; |
|
status = _cairo_path_fixed_line_to (path, box->p1.x, box->p2.y); |
if (unlikely (status)) |
return status; |
|
return _cairo_path_fixed_close_path (path); |
} |
|
static cairo_status_t |
_cairo_surface_clipper_intersect_clip_boxes (cairo_surface_clipper_t *clipper, |
const cairo_clip_t *clip) |
{ |
cairo_path_fixed_t path; |
cairo_status_t status; |
int i; |
|
if (clip->num_boxes == 0) |
return CAIRO_STATUS_SUCCESS; |
|
/* Reconstruct the path for the clip boxes. |
* XXX maybe a new clipper callback? |
*/ |
|
_cairo_path_fixed_init (&path); |
for (i = 0; i < clip->num_boxes; i++) { |
status = _cairo_path_fixed_add_box (&path, &clip->boxes[i]); |
if (unlikely (status)) { |
_cairo_path_fixed_fini (&path); |
return status; |
} |
} |
|
status = clipper->intersect_clip_path (clipper, &path, |
CAIRO_FILL_RULE_WINDING, |
0., |
CAIRO_ANTIALIAS_DEFAULT); |
_cairo_path_fixed_fini (&path); |
|
return status; |
} |
|
static cairo_status_t |
_cairo_surface_clipper_intersect_clip_path_recursive (cairo_surface_clipper_t *clipper, |
cairo_clip_path_t *clip_path) |
cairo_clip_path_t *clip_path, |
cairo_clip_path_t *end) |
{ |
cairo_status_t status; |
|
if (clip_path->prev != NULL) { |
if (clip_path->prev != end) { |
status = |
_cairo_surface_clipper_intersect_clip_path_recursive (clipper, |
clip_path->prev); |
clip_path->prev, |
end); |
if (unlikely (status)) |
return status; |
} |
62,57 → 125,56 |
|
cairo_status_t |
_cairo_surface_clipper_set_clip (cairo_surface_clipper_t *clipper, |
cairo_clip_t *clip) |
const cairo_clip_t *clip) |
{ |
cairo_status_t status; |
cairo_bool_t clear; |
cairo_bool_t incremental = FALSE; |
|
/* XXX as we cache a reference to the path, and compare every time, |
* we may in future need to install a notification if the clip->path |
* is every modified (e.g. cairo_clip_translate). |
*/ |
|
if (clip == NULL && clipper->clip.path == NULL) |
if (_cairo_clip_equal (clip, clipper->clip)) |
return CAIRO_STATUS_SUCCESS; |
|
if (clip != NULL && clipper->clip.path != NULL && |
_cairo_clip_equal (clip, &clipper->clip)) |
/* all clipped out state should never propagate this far */ |
assert (!_cairo_clip_is_all_clipped (clip)); |
|
/* XXX Is this an incremental clip? */ |
if (clipper->clip && clip && |
clip->num_boxes == clipper->clip->num_boxes && |
memcmp (clip->boxes, clipper->clip->boxes, |
sizeof (cairo_box_t) * clip->num_boxes) == 0) |
{ |
return CAIRO_STATUS_SUCCESS; |
cairo_clip_path_t *clip_path = clip->path; |
while (clip_path != NULL && clip_path != clipper->clip->path) |
clip_path = clip_path->prev; |
|
if (clip_path) { |
incremental = TRUE; |
status = _cairo_surface_clipper_intersect_clip_path_recursive (clipper, |
clip->path, |
clipper->clip->path); |
} |
} |
|
/* all clipped out state should never propagate this far */ |
assert (clip == NULL || clip->path != NULL); |
_cairo_clip_destroy (clipper->clip); |
clipper->clip = _cairo_clip_copy (clip); |
|
/* Check whether this clip is a continuation of the previous. |
* If not, we have to remove the current clip and rebuild. |
*/ |
clear = clip == NULL || clip->path->prev != clipper->clip.path; |
if (incremental) |
return status; |
|
_cairo_clip_reset (&clipper->clip); |
_cairo_clip_init_copy (&clipper->clip, clip); |
|
if (clear) { |
clipper->is_clipped = FALSE; |
status = clipper->intersect_clip_path (clipper, NULL, 0, 0, 0); |
if (unlikely (status)) |
return status; |
|
if (clip != NULL && clip->path != NULL) { |
status = |
_cairo_surface_clipper_intersect_clip_path_recursive (clipper, |
clip->path); |
clipper->is_clipped = TRUE; |
} |
} else { |
cairo_clip_path_t *path = clip->path; |
if (clip == NULL) |
return CAIRO_STATUS_SUCCESS; |
|
clipper->is_clipped = TRUE; |
status = clipper->intersect_clip_path (clipper, |
&path->path, |
path->fill_rule, |
path->tolerance, |
path->antialias); |
status = _cairo_surface_clipper_intersect_clip_boxes (clipper, clip); |
if (unlikely (status)) |
return status; |
|
if (clip->path != NULL) { |
status = _cairo_surface_clipper_intersect_clip_path_recursive (clipper, |
clip->path, |
NULL); |
} |
|
return status; |
122,8 → 184,7 |
_cairo_surface_clipper_init (cairo_surface_clipper_t *clipper, |
cairo_surface_clipper_intersect_clip_path_func_t func) |
{ |
_cairo_clip_init (&clipper->clip); |
clipper->is_clipped = FALSE; |
clipper->clip = NULL; |
clipper->intersect_clip_path = func; |
} |
|
130,6 → 191,6 |
void |
_cairo_surface_clipper_reset (cairo_surface_clipper_t *clipper) |
{ |
_cairo_clip_reset (&clipper->clip); |
clipper->is_clipped = FALSE; |
_cairo_clip_destroy (clipper->clip); |
clipper->clip = NULL; |
} |