cairo_status_t _cairo_surface_clipper_set_clip (cairo_surface_clipper_t *clipper, cairo_clip_t *clip) { cairo_status_t status; cairo_bool_t clear; /* 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) return CAIRO_STATUS_SUCCESS; if (clip != NULL && clip->path == clipper->clip.path) return CAIRO_STATUS_SUCCESS; if (clip != NULL && clipper->clip.path != NULL && _cairo_path_fixed_equal (&clip->path->path, &clipper->clip.path->path)) { return CAIRO_STATUS_SUCCESS; } /* all clipped out state should never propagate this far */ assert (clip == NULL || clip->path != NULL); /* 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; _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; clipper->is_clipped = TRUE; status = clipper->intersect_clip_path (clipper, &path->path, path->fill_rule, path->tolerance, path->antialias); } return status; }
static cairo_status_t _cairo_clip_intersect_path (cairo_clip_t *clip, const cairo_path_fixed_t *path, cairo_fill_rule_t fill_rule, double tolerance, cairo_antialias_t antialias) { cairo_clip_path_t *clip_path; cairo_status_t status; cairo_rectangle_int_t extents; cairo_box_t box; cairo_bool_t is_box = FALSE; if (clip->path != NULL) { 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; } } _cairo_path_fixed_approximate_clip_extents (path, &extents); if (extents.width == 0 || extents.height == 0) { _cairo_clip_set_all_clipped (clip); return CAIRO_STATUS_SUCCESS; } is_box = _cairo_path_fixed_is_box (path, &box); if (clip->path != NULL) { if (! _cairo_rectangle_intersect (&extents, &clip->path->extents)) { _cairo_clip_set_all_clipped (clip); return CAIRO_STATUS_SUCCESS; } /* does this clip wholly subsume the others? */ if (is_box && box.p1.x <= _cairo_fixed_from_int (clip->path->extents.x) && box.p2.x >= _cairo_fixed_from_int (clip->path->extents.x + clip->path->extents.width) && box.p1.y <= _cairo_fixed_from_int (clip->path->extents.y) && box.p2.y >= _cairo_fixed_from_int (clip->path->extents.y + clip->path->extents.height)) { return CAIRO_STATUS_SUCCESS; } } clip_path = _cairo_clip_path_create (clip); if (unlikely (clip_path == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); status = _cairo_path_fixed_init_copy (&clip_path->path, path); if (unlikely (status)) { clip->path = clip->path->prev; _cairo_clip_path_destroy (clip_path); return status; } clip_path->extents = extents; clip_path->fill_rule = fill_rule; clip_path->tolerance = tolerance; clip_path->antialias = antialias; if (is_box) clip_path->flags |= CAIRO_CLIP_PATH_IS_BOX; return CAIRO_STATUS_SUCCESS; }