diff options
author | Sebastian Dröge <sebastian.droege@collabora.co.uk> | 2009-10-16 08:21:27 +0200 |
---|---|---|
committer | Sebastian Dröge <sebastian.droege@collabora.co.uk> | 2009-10-16 08:21:27 +0200 |
commit | 0b05d5812d0ceaeb5a9db5a50be0d3f7f16b277a (patch) | |
tree | c564d4accd135ebbd3c3e66a37c1f223996aed12 /src/cairo-surface.c | |
parent | 0e79096a3831c10cf9735a7f518bfb65d0632923 (diff) |
Import upstream version 1.9.4
Diffstat (limited to 'src/cairo-surface.c')
-rw-r--r-- | src/cairo-surface.c | 1207 |
1 files changed, 547 insertions, 660 deletions
diff --git a/src/cairo-surface.c b/src/cairo-surface.c index fdb25fa..ab84bbf 100644 --- a/src/cairo-surface.c +++ b/src/cairo-surface.c @@ -41,6 +41,8 @@ #include "cairo-surface-fallback-private.h" #include "cairo-clip-private.h" #include "cairo-meta-surface-private.h" +#include "cairo-region-private.h" +#include "cairo-tee-surface-private.h" #define DEFINE_NIL_SURFACE(status, name) \ const cairo_surface_t name = { \ @@ -59,9 +61,6 @@ const cairo_surface_t name = { \ 0.0, /* y_resolution */ \ 0.0, /* x_fallback_resolution */ \ 0.0, /* y_fallback_resolution */ \ - NULL, /* clip */ \ - 0, /* next_clip_serial */ \ - 0, /* current_clip_serial */ \ NULL, /* snapshot_of */ \ NULL, /* snapshot_detach */ \ { 0, /* size */ \ @@ -77,7 +76,11 @@ const cairo_surface_t name = { \ } /* font_options */ \ } +/* XXX error object! */ + static DEFINE_NIL_SURFACE(CAIRO_STATUS_NO_MEMORY, _cairo_surface_nil); +static DEFINE_NIL_SURFACE(CAIRO_STATUS_SURFACE_TYPE_MISMATCH, _cairo_surface_nil_surface_type_mismatch); +static DEFINE_NIL_SURFACE(CAIRO_STATUS_INVALID_STATUS, _cairo_surface_nil_invalid_status); static DEFINE_NIL_SURFACE(CAIRO_STATUS_INVALID_CONTENT, _cairo_surface_nil_invalid_content); static DEFINE_NIL_SURFACE(CAIRO_STATUS_INVALID_FORMAT, _cairo_surface_nil_invalid_format); static DEFINE_NIL_SURFACE(CAIRO_STATUS_INVALID_VISUAL, _cairo_surface_nil_invalid_visual); @@ -88,7 +91,7 @@ static DEFINE_NIL_SURFACE(CAIRO_STATUS_WRITE_ERROR, _cairo_surface_nil_write_err static DEFINE_NIL_SURFACE(CAIRO_STATUS_INVALID_STRIDE, _cairo_surface_nil_invalid_stride); static DEFINE_NIL_SURFACE(CAIRO_STATUS_INVALID_SIZE, _cairo_surface_nil_invalid_size); -static cairo_status_t +static void _cairo_surface_copy_pattern_for_destination (const cairo_pattern_t **pattern, cairo_surface_t *destination, cairo_pattern_t *pattern_copy); @@ -190,14 +193,14 @@ slim_hidden_def (cairo_surface_status); static unsigned int _cairo_surface_allocate_unique_id (void) { - static unsigned int unique_id; + static cairo_atomic_int_t unique_id; #if CAIRO_NO_MUTEX if (++unique_id == 0) unique_id = 1; return unique_id; #else - unsigned int old, id; + cairo_atomic_int_t old, id; do { old = _cairo_atomic_uint_get (&unique_id); @@ -233,6 +236,8 @@ _cairo_surface_detach_snapshots (cairo_surface_t *surface) if (snapshots[i]->snapshot_detach != NULL) snapshots[i]->snapshot_detach (snapshots[i]); + + cairo_surface_destroy (snapshots[i]); } surface->snapshots.num_elements = 0; @@ -244,6 +249,8 @@ _cairo_surface_attach_snapshot (cairo_surface_t *surface, cairo_surface_t *snapshot, cairo_surface_func_t detach_func) { + cairo_status_t status; + assert (surface != snapshot); if (snapshot->snapshot_of != NULL) @@ -252,20 +259,29 @@ _cairo_surface_attach_snapshot (cairo_surface_t *surface, snapshot->snapshot_of = surface; snapshot->snapshot_detach = detach_func; - return _cairo_array_append (&surface->snapshots, &snapshot); + status = _cairo_array_append (&surface->snapshots, &snapshot); + if (unlikely (status)) + return status; + + cairo_surface_reference (snapshot); + return CAIRO_STATUS_SUCCESS; } cairo_surface_t * _cairo_surface_has_snapshot (cairo_surface_t *surface, - const cairo_surface_backend_t *backend) + const cairo_surface_backend_t *backend, + cairo_content_t content) { cairo_surface_t **snapshots; unsigned int i; snapshots = _cairo_array_index (&surface->snapshots, 0); for (i = 0; i < surface->snapshots.num_elements; i++) { - if (snapshots[i]->backend == backend) + if (snapshots[i]->backend == backend && + snapshots[i]->content == content) + { return snapshots[i]; + } } return NULL; @@ -297,6 +313,8 @@ _cairo_surface_detach_snapshot (cairo_surface_t *snapshot) if (snapshot->snapshot_detach != NULL) snapshot->snapshot_detach (snapshot); + + cairo_surface_destroy (snapshot); } static cairo_bool_t @@ -345,53 +363,48 @@ _cairo_surface_init (cairo_surface_t *surface, surface->x_fallback_resolution = CAIRO_SURFACE_FALLBACK_RESOLUTION_DEFAULT; surface->y_fallback_resolution = CAIRO_SURFACE_FALLBACK_RESOLUTION_DEFAULT; - surface->clip = NULL; - surface->next_clip_serial = 0; - surface->current_clip_serial = 0; - _cairo_array_init (&surface->snapshots, sizeof (cairo_surface_t *)); surface->snapshot_of = NULL; surface->has_font_options = FALSE; } +static void +_cairo_surface_copy_similar_properties (cairo_surface_t *surface, + cairo_surface_t *other) +{ + if (other->has_font_options || other->backend != surface->backend) { + cairo_font_options_t options; + + cairo_surface_get_font_options (other, &options); + _cairo_surface_set_font_options (surface, &options); + } + + cairo_surface_set_fallback_resolution (surface, + other->x_fallback_resolution, + other->y_fallback_resolution); +} + cairo_surface_t * _cairo_surface_create_similar_scratch (cairo_surface_t *other, cairo_content_t content, int width, int height) { - cairo_surface_t *surface = NULL; + cairo_surface_t *surface; - if (other->status) + if (unlikely (other->status)) return _cairo_surface_create_in_error (other->status); - if (other->backend->create_similar) { - surface = other->backend->create_similar (other, content, width, height); - if (surface != NULL && surface->status) - return surface; - } - - if (surface == NULL) { - surface = - cairo_image_surface_create (_cairo_format_from_content (content), - width, height); - } + if (other->backend->create_similar == NULL) + return NULL; - /* If any error occurred, then return the nil surface we received. */ - if (unlikely (surface->status)) + surface = other->backend->create_similar (other, + content, width, height); + if (surface == NULL || surface->status) return surface; - if (other->has_font_options || other->backend != surface->backend) { - cairo_font_options_t options; - - cairo_surface_get_font_options (other, &options); - _cairo_surface_set_font_options (surface, &options); - } - - cairo_surface_set_fallback_resolution (surface, - other->x_fallback_resolution, - other->y_fallback_resolution); + _cairo_surface_copy_similar_properties (surface, other); return surface; } @@ -427,46 +440,46 @@ cairo_surface_create_similar (cairo_surface_t *other, int width, int height) { - if (other->status) + if (unlikely (other->status)) return _cairo_surface_create_in_error (other->status); - if (! CAIRO_CONTENT_VALID (content)) + if (unlikely (! CAIRO_CONTENT_VALID (content))) return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_CONTENT)); - return _cairo_surface_create_similar_solid (other, content, - width, height, - CAIRO_COLOR_TRANSPARENT); + return _cairo_surface_create_similar_solid (other, + content, width, height, + CAIRO_COLOR_TRANSPARENT, + TRUE); } -slim_hidden_def (cairo_surface_create_similar); cairo_surface_t * _cairo_surface_create_similar_solid (cairo_surface_t *other, cairo_content_t content, int width, int height, - const cairo_color_t *color) + const cairo_color_t *color, + cairo_bool_t allow_fallback) { cairo_status_t status; cairo_surface_t *surface; - cairo_solid_pattern_t solid_pattern; + cairo_solid_pattern_t pattern; surface = _cairo_surface_create_similar_scratch (other, content, width, height); - if (surface->status) + if (surface == NULL && allow_fallback) + surface = _cairo_image_surface_create_with_content (content, + width, height); + if (surface == NULL || surface->status) return surface; - _cairo_pattern_init_solid (&solid_pattern, color, content); - + _cairo_pattern_init_solid (&pattern, color, content); status = _cairo_surface_paint (surface, color == CAIRO_COLOR_TRANSPARENT ? CAIRO_OPERATOR_CLEAR : CAIRO_OPERATOR_SOURCE, - &solid_pattern.base, NULL); - - _cairo_pattern_fini (&solid_pattern.base); - + &pattern.base, NULL); if (unlikely (status)) { cairo_surface_destroy (surface); - return _cairo_surface_create_in_error (status); + surface = _cairo_surface_create_in_error (status); } return surface; @@ -488,7 +501,8 @@ _cairo_surface_create_solid_pattern_surface (cairo_surface_t *other, return _cairo_surface_create_similar_solid (other, solid_pattern->content, 1, 1, - &solid_pattern->color); + &solid_pattern->color, + FALSE); } cairo_int_status_t @@ -516,17 +530,6 @@ _cairo_surface_repaint_solid_pattern_surface (cairo_surface_t *other, NULL); } -cairo_clip_mode_t -_cairo_surface_get_clip_mode (cairo_surface_t *surface) -{ - if (surface->backend->intersect_clip_path != NULL) - return CAIRO_CLIP_MODE_PATH; - else if (surface->backend->set_clip_region != NULL) - return CAIRO_CLIP_MODE_REGION; - else - return CAIRO_CLIP_MODE_MASK; -} - /** * cairo_surface_reference: * @surface: a #cairo_surface_t @@ -575,6 +578,8 @@ cairo_surface_destroy (cairo_surface_t *surface) if (! _cairo_reference_count_dec_and_test (&surface->ref_count)) return; + assert (surface->snapshot_of == NULL); + if (! surface->finished) cairo_surface_finish (surface); @@ -587,36 +592,6 @@ cairo_surface_destroy (cairo_surface_t *surface) slim_hidden_def(cairo_surface_destroy); /** - * _cairo_surface_reset: - * @surface: a #cairo_surface_t - * - * Resets the surface back to defaults such that it may be reused in lieu - * of creating a new surface. - **/ -cairo_status_t -_cairo_surface_reset (cairo_surface_t *surface) -{ - if (surface == NULL || - CAIRO_REFERENCE_COUNT_IS_INVALID (&surface->ref_count)) - return CAIRO_STATUS_SUCCESS; - - assert (CAIRO_REFERENCE_COUNT_GET_VALUE (&surface->ref_count) == 1); - - _cairo_user_data_array_fini (&surface->user_data); - _cairo_user_data_array_fini (&surface->mime_data); - - if (surface->backend->reset != NULL) { - cairo_status_t status = surface->backend->reset (surface); - if (unlikely (status)) - return _cairo_surface_set_error (surface, status); - } - - _cairo_surface_init (surface, surface->backend, surface->content); - - return CAIRO_STATUS_SUCCESS; -} - -/** * cairo_surface_get_reference_count: * @surface: a #cairo_surface_t * @@ -1060,14 +1035,7 @@ cairo_surface_mark_dirty_rectangle (cairo_surface_t *surface, * call mark_dirty()). */ assert (! _cairo_surface_has_snapshots (surface)); - /* Always reset the clip here, to avoid having external calls to - * clip manipulation functions of the underlying device clip result - * in a desync between the cairo clip and the backend clip, due to - * the clip caching. - */ - surface->current_clip_serial = -1; - - if (surface->backend->mark_dirty_rectangle) { + if (surface->backend->mark_dirty_rectangle != NULL) { /* XXX: FRAGILE: We're ignoring the scaling component of * device_transform here. I don't know what the right thing to * do would actually be if there were some scaling here, but @@ -1251,6 +1219,14 @@ cairo_surface_set_fallback_resolution (cairo_surface_t *surface, return; } + if (x_pixels_per_inch <= 0 || y_pixels_per_inch <= 0) { + /* XXX Could delay raising the error until we fallback, but throwing + * the error here means that we can catch the real culprit. + */ + status = _cairo_surface_set_error (surface, CAIRO_STATUS_INVALID_MATRIX); + return; + } + _cairo_surface_begin_modification (surface); surface->x_fallback_resolution = x_pixels_per_inch; @@ -1434,6 +1410,82 @@ _cairo_surface_release_dest_image (cairo_surface_t *surface, image, image_rect, image_extra); } +static cairo_status_t +_cairo_meta_surface_clone_similar (cairo_surface_t *surface, + cairo_surface_t *src, + cairo_content_t content, + int src_x, + int src_y, + int width, + int height, + int *clone_offset_x, + int *clone_offset_y, + cairo_surface_t **clone_out) +{ + cairo_meta_surface_t *meta = (cairo_meta_surface_t *) src; + cairo_surface_t *similar; + cairo_status_t status; + + similar = _cairo_surface_has_snapshot (src, + surface->backend, + src->content & content); + if (similar != NULL) { + *clone_out = cairo_surface_reference (similar); + *clone_offset_x = 0; + *clone_offset_y = 0; + return CAIRO_STATUS_SUCCESS; + } + + if (meta->unbounded || + width*height*8 < meta->extents.width*meta->extents.height) + { + /* XXX use _solid to perform an initial CLEAR? */ + similar = _cairo_surface_create_similar_scratch (surface, + src->content & content, + width, height); + if (similar == NULL) + return CAIRO_INT_STATUS_UNSUPPORTED; + if (unlikely (similar->status)) + return similar->status; + + cairo_surface_set_device_offset (similar, -src_x, -src_y); + + status = _cairo_meta_surface_replay (src, similar); + if (unlikely (status)) { + cairo_surface_destroy (similar); + return status; + } + } else { + similar = _cairo_surface_create_similar_scratch (surface, + src->content & content, + meta->extents.width, + meta->extents.height); + if (similar == NULL) + return CAIRO_INT_STATUS_UNSUPPORTED; + if (unlikely (similar->status)) + return similar->status; + + status = _cairo_meta_surface_replay (src, similar); + if (unlikely (status)) { + cairo_surface_destroy (similar); + return status; + } + + status = _cairo_surface_attach_snapshot (src, similar, NULL); + if (unlikely (status)) { + cairo_surface_destroy (similar); + return status; + } + + src_x = src_y = 0; + } + + *clone_out = similar; + *clone_offset_x = src_x; + *clone_offset_y = src_y; + return CAIRO_STATUS_SUCCESS; +} + /** * _cairo_surface_clone_similar: * @surface: a #cairo_surface_t @@ -1477,7 +1529,17 @@ _cairo_surface_clone_similar (cairo_surface_t *surface, if (unlikely (surface->finished)) return _cairo_error (CAIRO_STATUS_SURFACE_FINISHED); - if (surface->backend->clone_similar) { + if (src->type == CAIRO_SURFACE_TYPE_TEE) { + cairo_surface_t *match; + + match = _cairo_tee_surface_find_match (src, + surface->backend, + content); + if (match != NULL) + src = match; + } + + if (surface->backend->clone_similar != NULL) { status = surface->backend->clone_similar (surface, src, content, src_x, src_y, @@ -1485,34 +1547,19 @@ _cairo_surface_clone_similar (cairo_surface_t *surface, clone_offset_x, clone_offset_y, clone_out); - if (status == CAIRO_INT_STATUS_UNSUPPORTED) { if (_cairo_surface_is_image (src)) return CAIRO_INT_STATUS_UNSUPPORTED; /* First check to see if we can replay to a similar surface */ if (_cairo_surface_is_meta (src)) { - cairo_surface_t *similar; - - similar = cairo_surface_create_similar (surface, - src->content & content, - width, height); - status = similar->status; - if (unlikely (status)) - return status; - - cairo_surface_set_device_offset (similar, -src_x, -src_y); - - status = _cairo_meta_surface_replay (src, similar); - if (unlikely (status)) { - cairo_surface_destroy (similar); - return status; - } - - *clone_out = similar; - *clone_offset_x = src_x; - *clone_offset_y = src_y; - return CAIRO_STATUS_SUCCESS; + return _cairo_meta_surface_clone_similar (surface, src, + content, + src_x, src_y, + width, height, + clone_offset_x, + clone_offset_y, + clone_out); } /* If we failed, try again with an image surface */ @@ -1544,7 +1591,6 @@ _cairo_surface_clone_similar (cairo_surface_t *surface, clone_out); } - /* We should never get UNSUPPORTED here, so if we have an error, bail. */ if (unlikely (status)) return status; @@ -1590,31 +1636,37 @@ _cairo_surface_snapshot (cairo_surface_t *surface) if (surface->snapshot_of != NULL) return cairo_surface_reference (surface); - snapshot = _cairo_surface_has_snapshot (surface, surface->backend); + snapshot = _cairo_surface_has_snapshot (surface, + surface->backend, + surface->content); if (snapshot != NULL) return cairo_surface_reference (snapshot); if (surface->backend->snapshot != NULL) { snapshot = surface->backend->snapshot (surface); - if (unlikely (snapshot->status)) - return snapshot; - - /* Is this surface just a proxy - e.g. paginated surfaces? */ - if (snapshot->backend != surface->backend) { - cairo_surface_t *previous; - - previous = _cairo_surface_has_snapshot (surface, - snapshot->backend); - if (previous != NULL) { - cairo_surface_destroy (snapshot); - return cairo_surface_reference (previous); + if (snapshot != NULL) { + if (unlikely (snapshot->status)) + return snapshot; + + /* Is this surface just a proxy - e.g. paginated surfaces? */ + if (snapshot->backend != surface->backend) { + cairo_surface_t *previous; + + previous = _cairo_surface_has_snapshot (surface, + snapshot->backend, + snapshot->content); + if (previous != NULL) { + cairo_surface_destroy (snapshot); + return cairo_surface_reference (previous); + } } } } if (snapshot == NULL) { snapshot = _cairo_surface_has_snapshot (surface, - &_cairo_image_surface_backend); + &_cairo_image_surface_backend, + surface->content); if (snapshot != NULL) return cairo_surface_reference (snapshot); @@ -1682,11 +1734,12 @@ _cairo_surface_composite (cairo_operator_t op, int dst_x, int dst_y, unsigned int width, - unsigned int height) + unsigned int height, + cairo_region_t *clip_region) { cairo_int_status_t status; - if (dst->status) + if (unlikely (dst->status)) return dst->status; assert (_cairo_surface_is_writable (dst)); @@ -1704,7 +1757,8 @@ _cairo_surface_composite (cairo_operator_t op, src_x, src_y, mask_x, mask_y, dst_x, dst_y, - width, height); + width, height, + clip_region); if (status != CAIRO_INT_STATUS_UNSUPPORTED) return _cairo_surface_set_error (dst, status); } @@ -1715,7 +1769,8 @@ _cairo_surface_composite (cairo_operator_t op, src_x, src_y, mask_x, mask_y, dst_x, dst_y, - width, height)); + width, height, + clip_region)); } /** @@ -1791,6 +1846,13 @@ _cairo_surface_fill_region (cairo_surface_t *surface, if (num_rects == 0) return CAIRO_STATUS_SUCCESS; + /* catch a common reduction of _cairo_clip_combine_with_surface() */ + if (op == CAIRO_OPERATOR_IN && + _cairo_color_equal (color, CAIRO_COLOR_WHITE)) + { + return CAIRO_STATUS_SUCCESS; + } + if (num_rects > ARRAY_LENGTH (stack_rects)) { rects = _cairo_malloc_ab (num_rects, sizeof (cairo_rectangle_int_t)); @@ -1803,8 +1865,8 @@ _cairo_surface_fill_region (cairo_surface_t *surface, for (i = 0; i < num_rects; i++) cairo_region_get_rectangle (region, i, &rects[i]); - status = _cairo_surface_fill_rectangles (surface, op, - color, rects, num_rects); + status = _cairo_surface_fill_rectangles (surface, + op, color, rects, num_rects); if (rects != stack_rects) free (rects); @@ -1846,14 +1908,16 @@ _cairo_surface_fill_rectangles (cairo_surface_t *surface, return CAIRO_STATUS_SUCCESS; if (surface->backend->fill_rectangles) { - status = surface->backend->fill_rectangles (surface, op, color, + status = surface->backend->fill_rectangles (surface, + op, color, rects, num_rects); if (status != CAIRO_INT_STATUS_UNSUPPORTED) return _cairo_surface_set_error (surface, status); } return _cairo_surface_set_error (surface, - _cairo_surface_fallback_fill_rectangles (surface, op, color, + _cairo_surface_fallback_fill_rectangles (surface, + op, color, rects, num_rects)); } @@ -1861,34 +1925,32 @@ cairo_status_t _cairo_surface_paint (cairo_surface_t *surface, cairo_operator_t op, const cairo_pattern_t *source, - cairo_rectangle_int_t *extents) + cairo_clip_t *clip) { cairo_status_t status; cairo_pattern_union_t dev_source; - if (surface->status) + if (unlikely (surface->status)) return surface->status; + if (clip && clip->all_clipped) + return CAIRO_STATUS_SUCCESS; + _cairo_surface_begin_modification (surface); - status = _cairo_surface_copy_pattern_for_destination (&source, - surface, - &dev_source.base); - if (unlikely (status)) - return _cairo_surface_set_error (surface, status); + _cairo_surface_copy_pattern_for_destination (&source, + surface, + &dev_source.base); - if (surface->backend->paint) { - status = surface->backend->paint (surface, op, source, extents); + if (surface->backend->paint != NULL) { + status = surface->backend->paint (surface, op, source, clip); if (status != CAIRO_INT_STATUS_UNSUPPORTED) goto FINISH; } - status = _cairo_surface_fallback_paint (surface, op, source); + status = _cairo_surface_fallback_paint (surface, op, source, clip); FINISH: - if (source == &dev_source.base) - _cairo_pattern_fini (&dev_source.base); - return _cairo_surface_set_error (surface, status); } @@ -1897,45 +1959,34 @@ _cairo_surface_mask (cairo_surface_t *surface, cairo_operator_t op, const cairo_pattern_t *source, const cairo_pattern_t *mask, - cairo_rectangle_int_t *extents) + cairo_clip_t *clip) { cairo_status_t status; cairo_pattern_union_t dev_source; cairo_pattern_union_t dev_mask; - if (surface->status) + if (unlikely (surface->status)) return surface->status; - _cairo_surface_begin_modification (surface); + if (clip && clip->all_clipped) + return CAIRO_STATUS_SUCCESS; - status = _cairo_surface_copy_pattern_for_destination (&source, - surface, - &dev_source.base); - if (unlikely (status)) - goto FINISH; + _cairo_surface_begin_modification (surface); - status = _cairo_surface_copy_pattern_for_destination (&mask, - surface, - &dev_mask.base); - if (unlikely (status)) - goto CLEANUP_SOURCE; + _cairo_surface_copy_pattern_for_destination (&source, surface, + &dev_source.base); + _cairo_surface_copy_pattern_for_destination (&mask, surface, + &dev_mask.base); - if (surface->backend->mask) { - status = surface->backend->mask (surface, op, source, mask, extents); + if (surface->backend->mask != NULL) { + status = surface->backend->mask (surface, op, source, mask, clip); if (status != CAIRO_INT_STATUS_UNSUPPORTED) - goto CLEANUP_MASK; + goto FINISH; } - status = _cairo_surface_fallback_mask (surface, op, source, mask); + status = _cairo_surface_fallback_mask (surface, op, source, mask, clip); - CLEANUP_MASK: - if (mask == &dev_mask.base) - _cairo_pattern_fini (&dev_mask.base); - CLEANUP_SOURCE: - if (source == &dev_source.base) - _cairo_pattern_fini (&dev_source.base); FINISH: - return _cairo_surface_set_error (surface, status); } @@ -1954,13 +2005,16 @@ _cairo_surface_fill_stroke (cairo_surface_t *surface, cairo_matrix_t *stroke_ctm_inverse, double stroke_tolerance, cairo_antialias_t stroke_antialias, - cairo_rectangle_int_t *extents) + cairo_clip_t *clip) { cairo_status_t status; - if (surface->status) + if (unlikely (surface->status)) return surface->status; + if (clip && clip->all_clipped) + return CAIRO_STATUS_SUCCESS; + _cairo_surface_begin_modification (surface); if (surface->backend->fill_stroke) { @@ -1969,21 +2023,10 @@ _cairo_surface_fill_stroke (cairo_surface_t *surface, cairo_matrix_t dev_ctm = *stroke_ctm; cairo_matrix_t dev_ctm_inverse = *stroke_ctm_inverse; - status = _cairo_surface_copy_pattern_for_destination (&stroke_source, - surface, - &dev_stroke_source.base); - if (unlikely (status)) - return _cairo_surface_set_error (surface, status); - - status = _cairo_surface_copy_pattern_for_destination (&fill_source, - surface, - &dev_fill_source.base); - if (unlikely (status)) { - if (stroke_source == &dev_stroke_source.base) - _cairo_pattern_fini (&dev_stroke_source.base); - - return _cairo_surface_set_error (surface, status); - } + _cairo_surface_copy_pattern_for_destination (&stroke_source, surface, + &dev_stroke_source.base); + _cairo_surface_copy_pattern_for_destination (&fill_source, surface, + &dev_fill_source.base); status = surface->backend->fill_stroke (surface, fill_op, fill_source, fill_rule, @@ -1993,26 +2036,22 @@ _cairo_surface_fill_stroke (cairo_surface_t *surface, stroke_style, &dev_ctm, &dev_ctm_inverse, stroke_tolerance, stroke_antialias, - extents); - - if (stroke_source == &dev_stroke_source.base) - _cairo_pattern_fini (&dev_stroke_source.base); - - if (fill_source == &dev_fill_source.base) - _cairo_pattern_fini (&dev_fill_source.base); + clip); if (status != CAIRO_INT_STATUS_UNSUPPORTED) return _cairo_surface_set_error (surface, status); } status = _cairo_surface_fill (surface, fill_op, fill_source, path, - fill_rule, fill_tolerance, fill_antialias, NULL); + fill_rule, fill_tolerance, fill_antialias, + clip); if (unlikely (status)) return _cairo_surface_set_error (surface, status); status = _cairo_surface_stroke (surface, stroke_op, stroke_source, path, stroke_style, stroke_ctm, stroke_ctm_inverse, - stroke_tolerance, stroke_antialias, NULL); + stroke_tolerance, stroke_antialias, + clip); if (unlikely (status)) return _cairo_surface_set_error (surface, status); @@ -2029,31 +2068,28 @@ _cairo_surface_stroke (cairo_surface_t *surface, cairo_matrix_t *ctm_inverse, double tolerance, cairo_antialias_t antialias, - cairo_rectangle_int_t *extents) + cairo_clip_t *clip) { cairo_status_t status; cairo_pattern_union_t dev_source; - cairo_path_fixed_t *dev_path = path; - cairo_path_fixed_t real_dev_path; - cairo_matrix_t dev_ctm = *ctm; - cairo_matrix_t dev_ctm_inverse = *ctm_inverse; - if (surface->status) + if (unlikely (surface->status)) return surface->status; + if (clip && clip->all_clipped) + return CAIRO_STATUS_SUCCESS; + _cairo_surface_begin_modification (surface); - status = _cairo_surface_copy_pattern_for_destination (&source, - surface, - &dev_source.base); - if (unlikely (status)) - return _cairo_surface_set_error (surface, status); + _cairo_surface_copy_pattern_for_destination (&source, surface, + &dev_source.base); - if (surface->backend->stroke) { + if (surface->backend->stroke != NULL) { status = surface->backend->stroke (surface, op, source, path, stroke_style, - &dev_ctm, &dev_ctm_inverse, - tolerance, antialias, extents); + ctm, ctm_inverse, + tolerance, antialias, + clip); if (status != CAIRO_INT_STATUS_UNSUPPORTED) goto FINISH; @@ -2061,16 +2097,11 @@ _cairo_surface_stroke (cairo_surface_t *surface, status = _cairo_surface_fallback_stroke (surface, op, source, path, stroke_style, - &dev_ctm, &dev_ctm_inverse, - tolerance, antialias); + ctm, ctm_inverse, + tolerance, antialias, + clip); FINISH: - if (dev_path == &real_dev_path) - _cairo_path_fixed_fini (&real_dev_path); - - if (source == &dev_source.base) - _cairo_pattern_fini (&dev_source.base); - return _cairo_surface_set_error (surface, status); } @@ -2082,26 +2113,26 @@ _cairo_surface_fill (cairo_surface_t *surface, cairo_fill_rule_t fill_rule, double tolerance, cairo_antialias_t antialias, - cairo_rectangle_int_t *extents) + cairo_clip_t *clip) { cairo_status_t status; cairo_pattern_union_t dev_source; - if (surface->status) + if (unlikely (surface->status)) return surface->status; - _cairo_surface_begin_modification (surface); + if (clip && clip->all_clipped) + return CAIRO_STATUS_SUCCESS; - status = _cairo_surface_copy_pattern_for_destination (&source, - surface, - &dev_source.base); - if (unlikely (status)) - return _cairo_surface_set_error (surface, status); + _cairo_surface_begin_modification (surface); - if (surface->backend->fill) { + _cairo_surface_copy_pattern_for_destination (&source, surface, + &dev_source.base); + if (surface->backend->fill != NULL) { status = surface->backend->fill (surface, op, source, path, fill_rule, - tolerance, antialias, extents); + tolerance, antialias, + clip); if (status != CAIRO_INT_STATUS_UNSUPPORTED) goto FINISH; @@ -2109,12 +2140,10 @@ _cairo_surface_fill (cairo_surface_t *surface, status = _cairo_surface_fallback_fill (surface, op, source, path, fill_rule, - tolerance, antialias); + tolerance, antialias, + clip); FINISH: - if (source == &dev_source.base) - _cairo_pattern_fini (&dev_source.base); - return _cairo_surface_set_error (surface, status); } @@ -2130,7 +2159,8 @@ _cairo_surface_composite_trapezoids (cairo_operator_t op, unsigned int width, unsigned int height, cairo_trapezoid_t *traps, - int num_traps) + int num_traps, + cairo_region_t *clip_region) { cairo_int_status_t status; @@ -2151,7 +2181,8 @@ _cairo_surface_composite_trapezoids (cairo_operator_t op, src_x, src_y, dst_x, dst_y, width, height, - traps, num_traps); + traps, num_traps, + clip_region); if (status != CAIRO_INT_STATUS_UNSUPPORTED) return _cairo_surface_set_error (dst, status); } @@ -2162,59 +2193,54 @@ _cairo_surface_composite_trapezoids (cairo_operator_t op, src_x, src_y, dst_x, dst_y, width, height, - traps, num_traps)); + traps, num_traps, + clip_region)); } cairo_span_renderer_t * -_cairo_surface_create_span_renderer (cairo_operator_t op, - const cairo_pattern_t *pattern, +_cairo_surface_create_span_renderer (cairo_operator_t op, + const cairo_pattern_t *pattern, cairo_surface_t *dst, - cairo_antialias_t antialias, - const cairo_composite_rectangles_t *rects) + cairo_antialias_t antialias, + const cairo_composite_rectangles_t *rects, + cairo_region_t *clip_region) { assert (dst->snapshot_of == NULL); - if (dst->status) + if (unlikely (dst->status)) return _cairo_span_renderer_create_in_error (dst->status); - if (dst->finished) + if (unlikely (dst->finished)) return _cairo_span_renderer_create_in_error (CAIRO_STATUS_SURFACE_FINISHED); if (dst->backend->create_span_renderer) { return dst->backend->create_span_renderer (op, pattern, dst, antialias, - rects); + rects, + clip_region); } ASSERT_NOT_REACHED; return _cairo_span_renderer_create_in_error (CAIRO_INT_STATUS_UNSUPPORTED); } cairo_bool_t -_cairo_surface_check_span_renderer (cairo_operator_t op, - const cairo_pattern_t *pattern, - cairo_surface_t *dst, - cairo_antialias_t antialias, - const cairo_composite_rectangles_t *rects) +_cairo_surface_check_span_renderer (cairo_operator_t op, + const cairo_pattern_t *pattern, + cairo_surface_t *dst, + cairo_antialias_t antialias) { - cairo_int_status_t status; - assert (dst->snapshot_of == NULL); + assert (dst->status == CAIRO_STATUS_SUCCESS); + assert (! dst->finished); - if (dst->status) + /* XXX: Currently we have no mono span renderer */ + if (antialias == CAIRO_ANTIALIAS_NONE) return FALSE; - if (dst->finished) { - status = _cairo_surface_set_error (dst, CAIRO_STATUS_SURFACE_FINISHED); - return FALSE; - } + if (dst->backend->check_span_renderer != NULL) + return dst->backend->check_span_renderer (op, pattern, dst, antialias); - if (dst->backend->check_span_renderer) { - return dst->backend->check_span_renderer (op, - pattern, dst, - antialias, - rects); - } return FALSE; } @@ -2277,7 +2303,7 @@ cairo_surface_show_page (cairo_surface_t *surface) if (surface->status) return; - assert (surface->snapshot_of == NULL); + _cairo_surface_begin_modification (surface); if (surface->finished) { status_ignored = _cairo_surface_set_error (surface, @@ -2295,301 +2321,6 @@ cairo_surface_show_page (cairo_surface_t *surface) slim_hidden_def (cairo_surface_show_page); /** - * _cairo_surface_get_current_clip_serial: - * @surface: the #cairo_surface_t to return the serial number for - * - * This space left intentionally blank. - * - * Returns: the serial number associated with the current - * clip in the surface. All gstate functions must - * verify that the correct clip is set in the surface before - * invoking any surface drawing function. - */ -unsigned int -_cairo_surface_get_current_clip_serial (cairo_surface_t *surface) -{ - return surface->current_clip_serial; -} - -/** - * _cairo_surface_allocate_clip_serial: - * @surface: the #cairo_surface_t to allocate a serial number from - * - * Each surface has a separate set of clipping serial numbers, and - * this function allocates one from the specified surface. As zero is - * reserved for the special no-clipping case, this function will not - * return that except for an in-error surface, (ie. surface->status != - * %CAIRO_STATUS_SUCCESS). - */ -unsigned int -_cairo_surface_allocate_clip_serial (cairo_surface_t *surface) -{ - unsigned int serial; - - if (surface->status) - return 0; - - if ((serial = ++(surface->next_clip_serial)) == 0) - serial = ++(surface->next_clip_serial); - return serial; -} - -/** - * _cairo_surface_reset_clip: - * @surface: the #cairo_surface_t to reset the clip on - * - * This function sets the clipping for the surface to - * None, which is to say that drawing is entirely - * unclipped. It also sets the clip serial number - * to zero. - */ -cairo_status_t -_cairo_surface_reset_clip (cairo_surface_t *surface) -{ - cairo_status_t status; - - if (surface->status) - return surface->status; - - if (surface->finished) - return _cairo_surface_set_error (surface,CAIRO_STATUS_SURFACE_FINISHED); - - surface->current_clip_serial = 0; - - if (surface->backend->intersect_clip_path) { - status = surface->backend->intersect_clip_path (surface, - NULL, - CAIRO_FILL_RULE_WINDING, - 0, - CAIRO_ANTIALIAS_DEFAULT); - if (unlikely (status)) - return _cairo_surface_set_error (surface, status); - } - - if (surface->backend->set_clip_region != NULL) { - status = surface->backend->set_clip_region (surface, NULL); - if (unlikely (status)) - return _cairo_surface_set_error (surface, status); - } - - return CAIRO_STATUS_SUCCESS; -} - -/** - * _cairo_surface_set_clip_region: - * @surface: the #cairo_surface_t to reset the clip on - * @region: the #cairo_region_t to use for clipping - * @serial: the clip serial number associated with the region - * - * This function sets the clipping for the surface to - * the specified region and sets the surface clipping - * serial number to the associated serial number. - */ -cairo_status_t -_cairo_surface_set_clip_region (cairo_surface_t *surface, - cairo_region_t *region, - unsigned int serial) -{ - cairo_status_t status; - - if (surface->status) - return surface->status; - - if (surface->finished) - return _cairo_surface_set_error (surface,CAIRO_STATUS_SURFACE_FINISHED); - - assert (surface->backend->set_clip_region != NULL); - - status = surface->backend->set_clip_region (surface, region); - if (unlikely (status)) - return _cairo_surface_set_error (surface, status); - - surface->current_clip_serial = serial; - - return CAIRO_STATUS_SUCCESS; -} - -cairo_int_status_t -_cairo_surface_intersect_clip_path (cairo_surface_t *surface, - cairo_path_fixed_t *path, - cairo_fill_rule_t fill_rule, - double tolerance, - cairo_antialias_t antialias) -{ - cairo_path_fixed_t *dev_path = path; - cairo_status_t status; - - if (surface->status) - return surface->status; - - if (surface->finished) - return _cairo_surface_set_error (surface,CAIRO_STATUS_SURFACE_FINISHED); - - assert (surface->backend->intersect_clip_path != NULL); - - status = surface->backend->intersect_clip_path (surface, - dev_path, - fill_rule, - tolerance, - antialias); - - return _cairo_surface_set_error (surface, status); -} - -static cairo_status_t -_cairo_surface_set_clip_path_recursive (cairo_surface_t *surface, - cairo_clip_path_t *clip_path) -{ - cairo_status_t status; - - if (surface->status) - return surface->status; - - if (clip_path == NULL) - return CAIRO_STATUS_SUCCESS; - - status = _cairo_surface_set_clip_path_recursive (surface, clip_path->prev); - if (unlikely (status)) - return status; - - return _cairo_surface_intersect_clip_path (surface, - &clip_path->path, - clip_path->fill_rule, - clip_path->tolerance, - clip_path->antialias); -} - -/** - * _cairo_surface_set_clip_path: - * @surface: the #cairo_surface_t to set the clip on - * @clip_path: the clip path to set - * @serial: the clip serial number associated with the clip path - * - * Sets the given clipping path for the surface and assigns the - * clipping serial to the surface. - **/ -static cairo_status_t -_cairo_surface_set_clip_path (cairo_surface_t *surface, - cairo_clip_path_t *clip_path, - unsigned int serial) -{ - cairo_status_t status; - - if (surface->status) - return surface->status; - - if (surface->finished) - return _cairo_surface_set_error (surface,CAIRO_STATUS_SURFACE_FINISHED); - - assert (surface->backend->intersect_clip_path != NULL); - - status = surface->backend->intersect_clip_path (surface, - NULL, - CAIRO_FILL_RULE_WINDING, - 0, - CAIRO_ANTIALIAS_DEFAULT); - if (unlikely (status)) - return _cairo_surface_set_error (surface, status); - - status = _cairo_surface_set_clip_path_recursive (surface, clip_path); - if (unlikely (status)) - return _cairo_surface_set_error (surface, status); - - surface->current_clip_serial = serial; - - return CAIRO_STATUS_SUCCESS; -} - - -/** - * _cairo_surface_set_empty_clip_path: - * @surface: the #cairo_surface_t to set the clip on - * @serial: the clip serial number associated with the clip path - * - * Create an empty clip path, one that represents the entire surface clipped - * out, and assigns the given clipping serial to the surface. - **/ -static cairo_status_t -_cairo_surface_set_empty_clip_path (cairo_surface_t *surface, - unsigned int serial) -{ - cairo_path_fixed_t path; - cairo_status_t status; - - if (surface->status) - return surface->status; - - _cairo_path_fixed_init (&path); - - status = surface->backend->intersect_clip_path (surface, - &path, - CAIRO_FILL_RULE_WINDING, - 0, - CAIRO_ANTIALIAS_DEFAULT); - - if (status == CAIRO_STATUS_SUCCESS) - surface->current_clip_serial = serial; - - _cairo_path_fixed_fini (&path); - - return _cairo_surface_set_error (surface, status); -} - -cairo_clip_t * -_cairo_surface_get_clip (cairo_surface_t *surface) -{ - return surface->clip; -} - -cairo_status_t -_cairo_surface_set_clip (cairo_surface_t *surface, cairo_clip_t *clip) -{ - unsigned int serial = 0; - - if (surface->status) - return surface->status; - - if (surface->finished) - return _cairo_surface_set_error (surface,CAIRO_STATUS_SURFACE_FINISHED); - - if (clip) { - serial = clip->serial; - if (serial == 0) - clip = NULL; - } - - surface->clip = clip; - - if (serial == _cairo_surface_get_current_clip_serial (surface)) - return CAIRO_STATUS_SUCCESS; - - if (clip) { - if (clip->all_clipped) { - if (surface->backend->intersect_clip_path != NULL) - return _cairo_surface_set_empty_clip_path (surface, - clip->serial); - - if (surface->backend->set_clip_region != NULL) - return _cairo_surface_set_clip_region (surface, - clip->region, - clip->serial); - } else { - if (clip->path) - return _cairo_surface_set_clip_path (surface, - clip->path, - clip->serial); - - if (clip->region) - return _cairo_surface_set_clip_region (surface, - clip->region, - clip->serial); - } - } - - return _cairo_surface_reset_clip (surface); -} - -/** * _cairo_surface_get_extents: * @surface: the #cairo_surface_t to fetch extents for * @@ -2613,31 +2344,22 @@ _cairo_surface_set_clip (cairo_surface_t *surface, cairo_clip_t *clip) * This behavior would have to be changed is we ever exported a public * variant of this function. */ -cairo_int_status_t +cairo_bool_t _cairo_surface_get_extents (cairo_surface_t *surface, cairo_rectangle_int_t *extents) { - cairo_int_status_t status = CAIRO_INT_STATUS_UNSUPPORTED; + cairo_bool_t bounded = FALSE; - if (surface->status) - return surface->status; + if (unlikely (surface->status || surface->finished)) + return TRUE; - if (surface->finished) - return _cairo_surface_set_error (surface,CAIRO_STATUS_SURFACE_FINISHED); - - if (surface->backend->get_extents) { - status = _cairo_surface_set_error (surface, - surface->backend->get_extents (surface, extents)); - } + if (surface->backend->get_extents != NULL) + bounded = surface->backend->get_extents (surface, extents); - if (status == CAIRO_INT_STATUS_UNSUPPORTED) { - extents->x = CAIRO_RECT_INT_MIN; - extents->y = CAIRO_RECT_INT_MIN; - extents->width = CAIRO_RECT_INT_MAX - CAIRO_RECT_INT_MIN; - extents->height = CAIRO_RECT_INT_MAX - CAIRO_RECT_INT_MIN; - } + if (! bounded) + _cairo_unbounded_rectangle_init (extents); - return status; + return bounded; } /** @@ -2709,25 +2431,25 @@ _cairo_surface_show_text_glyphs (cairo_surface_t *surface, int num_clusters, cairo_text_cluster_flags_t cluster_flags, cairo_scaled_font_t *scaled_font, - cairo_rectangle_int_t *extents) + cairo_clip_t *clip) { cairo_status_t status; cairo_scaled_font_t *dev_scaled_font = scaled_font; cairo_pattern_union_t dev_source; - if (surface->status) + if (unlikely (surface->status)) return surface->status; if (num_glyphs == 0 && utf8_len == 0) return CAIRO_STATUS_SUCCESS; + if (clip && clip->all_clipped) + return CAIRO_STATUS_SUCCESS; + _cairo_surface_begin_modification (surface); - status = _cairo_surface_copy_pattern_for_destination (&source, - surface, - &dev_source.base); - if (unlikely (status)) - return _cairo_surface_set_error (surface, status); + _cairo_surface_copy_pattern_for_destination (&source, surface, + &dev_source.base); if (_cairo_surface_has_device_transform (surface) && ! _cairo_matrix_is_integer_translation (&surface->device_transform, NULL, NULL)) @@ -2745,12 +2467,8 @@ _cairo_surface_show_text_glyphs (cairo_surface_t *surface, &font_options); } status = cairo_scaled_font_status (dev_scaled_font); - if (unlikely (status)) { - if (source == &dev_source.base) - _cairo_pattern_fini (&dev_source.base); - + if (unlikely (status)) return _cairo_surface_set_error (surface, status); - } status = CAIRO_INT_STATUS_UNSUPPORTED; @@ -2759,21 +2477,25 @@ _cairo_surface_show_text_glyphs (cairo_surface_t *surface, if (clusters) { /* A real show_text_glyphs call. Try show_text_glyphs backend * method first */ - if (surface->backend->show_text_glyphs) { + if (surface->backend->show_text_glyphs != NULL) { status = surface->backend->show_text_glyphs (surface, op, source, utf8, utf8_len, glyphs, num_glyphs, clusters, num_clusters, cluster_flags, - dev_scaled_font, extents); + dev_scaled_font, + clip); } - if (status == CAIRO_INT_STATUS_UNSUPPORTED && surface->backend->show_glyphs) { + if (status == CAIRO_INT_STATUS_UNSUPPORTED && + surface->backend->show_glyphs) + { int remaining_glyphs = num_glyphs; status = surface->backend->show_glyphs (surface, op, source, glyphs, num_glyphs, dev_scaled_font, - &remaining_glyphs, extents); + clip, + &remaining_glyphs); glyphs += num_glyphs - remaining_glyphs; num_glyphs = remaining_glyphs; if (status == CAIRO_INT_STATUS_UNSUPPORTED && remaining_glyphs == 0) @@ -2781,18 +2503,19 @@ _cairo_surface_show_text_glyphs (cairo_surface_t *surface, } } else { /* A mere show_glyphs call. Try show_glyphs backend method first */ - if (surface->backend->show_glyphs) { + if (surface->backend->show_glyphs != NULL) { int remaining_glyphs = num_glyphs; status = surface->backend->show_glyphs (surface, op, source, glyphs, num_glyphs, dev_scaled_font, - &remaining_glyphs, extents); + clip, + &remaining_glyphs); glyphs += num_glyphs - remaining_glyphs; num_glyphs = remaining_glyphs; if (status == CAIRO_INT_STATUS_UNSUPPORTED && remaining_glyphs == 0) status = CAIRO_STATUS_SUCCESS; - } else if (surface->backend->show_text_glyphs) { + } else if (surface->backend->show_text_glyphs != NULL) { /* Intentionally only try show_text_glyphs method for show_glyphs * calls if backend does not have show_glyphs. If backend has * both methods implemented, we don't fallback from show_glyphs to @@ -2806,22 +2529,22 @@ _cairo_surface_show_text_glyphs (cairo_surface_t *surface, utf8, utf8_len, glyphs, num_glyphs, clusters, num_clusters, cluster_flags, - dev_scaled_font, extents); + dev_scaled_font, + clip); } } - if (status == CAIRO_INT_STATUS_UNSUPPORTED) + if (status == CAIRO_INT_STATUS_UNSUPPORTED) { status = _cairo_surface_fallback_show_glyphs (surface, op, source, glyphs, num_glyphs, - dev_scaled_font); + dev_scaled_font, + clip); + } if (dev_scaled_font != scaled_font) cairo_scaled_font_destroy (dev_scaled_font); - if (source == &dev_source.base) - _cairo_pattern_fini (&dev_source.base); - return _cairo_surface_set_error (surface, status); } @@ -2842,7 +2565,8 @@ _cairo_surface_old_show_glyphs (cairo_scaled_font_t *scaled_font, unsigned int width, unsigned int height, cairo_glyph_t *glyphs, - int num_glyphs) + int num_glyphs, + cairo_region_t *clip_region) { cairo_status_t status; @@ -2857,7 +2581,8 @@ _cairo_surface_old_show_glyphs (cairo_scaled_font_t *scaled_font, source_x, source_y, dest_x, dest_y, width, height, - glyphs, num_glyphs); + glyphs, num_glyphs, + clip_region); } else status = CAIRO_INT_STATUS_UNSUPPORTED; @@ -2871,10 +2596,11 @@ _cairo_surface_composite_fixup_unbounded_internal (cairo_surface_t *dst, int dst_x, int dst_y, unsigned int width, - unsigned int height) + unsigned int height, + cairo_region_t *clip_region) { cairo_rectangle_int_t dst_rectangle; - cairo_region_t *clear_region; + cairo_region_t clear_region; cairo_status_t status; /* The area that was drawn is the area in the destination rectangle but @@ -2885,33 +2611,36 @@ _cairo_surface_composite_fixup_unbounded_internal (cairo_surface_t *dst, dst_rectangle.width = width; dst_rectangle.height = height; - clear_region = cairo_region_create_rectangle (&dst_rectangle); - status = clear_region->status; - if (unlikely (status)) - goto CLEANUP_REGIONS; + _cairo_region_init_rectangle (&clear_region, &dst_rectangle); + + if (clip_region != NULL) { + status = cairo_region_intersect (&clear_region, clip_region); + if (unlikely (status)) + goto CLEANUP_REGIONS; + } - if (src_rectangle) { + if (src_rectangle != NULL) { if (! _cairo_rectangle_intersect (&dst_rectangle, src_rectangle)) goto EMPTY; } - if (mask_rectangle) { + if (mask_rectangle != NULL) { if (! _cairo_rectangle_intersect (&dst_rectangle, mask_rectangle)) goto EMPTY; } /* Now compute the area that is in dst but not drawn */ - status = cairo_region_subtract_rectangle (clear_region, &dst_rectangle); - if (unlikely (status)) + status = cairo_region_subtract_rectangle (&clear_region, &dst_rectangle); + if (unlikely (status) || cairo_region_is_empty (&clear_region)) goto CLEANUP_REGIONS; EMPTY: - status = _cairo_surface_fill_region (dst, CAIRO_OPERATOR_SOURCE, + status = _cairo_surface_fill_region (dst, CAIRO_OPERATOR_CLEAR, CAIRO_COLOR_TRANSPARENT, - clear_region); + &clear_region); CLEANUP_REGIONS: - cairo_region_destroy (clear_region); + _cairo_region_fini (&clear_region); return _cairo_surface_set_error (dst, status); } @@ -2955,13 +2684,14 @@ _cairo_surface_composite_fixup_unbounded (cairo_surface_t *dst, int dst_x, int dst_y, unsigned int width, - unsigned int height) + unsigned int height, + cairo_region_t *clip_region) { cairo_rectangle_int_t src_tmp, mask_tmp; cairo_rectangle_int_t *src_rectangle = NULL; cairo_rectangle_int_t *mask_rectangle = NULL; - if (dst->status) + if (unlikely (dst->status)) return dst->status; assert (_cairo_surface_is_writable (dst)); @@ -2993,7 +2723,8 @@ _cairo_surface_composite_fixup_unbounded (cairo_surface_t *dst, } return _cairo_surface_composite_fixup_unbounded_internal (dst, src_rectangle, mask_rectangle, - dst_x, dst_y, width, height); + dst_x, dst_y, width, height, + clip_region); } /** @@ -3033,11 +2764,11 @@ _cairo_surface_composite_shape_fixup_unbounded (cairo_surface_t *dst, int dst_x, int dst_y, unsigned int width, - unsigned int height) + unsigned int height, + cairo_region_t *clip_region) { - cairo_rectangle_int_t src_tmp, mask_tmp; - cairo_rectangle_int_t *src_rectangle = NULL; - cairo_rectangle_int_t *mask_rectangle = NULL; + cairo_rectangle_int_t src_tmp, *src= NULL; + cairo_rectangle_int_t mask; if (dst->status) return dst->status; @@ -3052,21 +2783,20 @@ _cairo_surface_composite_shape_fixup_unbounded (cairo_surface_t *dst, { src_tmp.x = (dst_x - (src_x + src_attr->x_offset)); src_tmp.y = (dst_y - (src_y + src_attr->y_offset)); - src_tmp.width = src_width; + src_tmp.width = src_width; src_tmp.height = src_height; - src_rectangle = &src_tmp; + src = &src_tmp; } - mask_tmp.x = dst_x - mask_x; - mask_tmp.y = dst_y - mask_y; - mask_tmp.width = mask_width; - mask_tmp.height = mask_height; - - mask_rectangle = &mask_tmp; + mask.x = dst_x - mask_x; + mask.y = dst_y - mask_y; + mask.width = mask_width; + mask.height = mask_height; - return _cairo_surface_composite_fixup_unbounded_internal (dst, src_rectangle, mask_rectangle, - dst_x, dst_y, width, height); + return _cairo_surface_composite_fixup_unbounded_internal (dst, src, &mask, + dst_x, dst_y, width, height, + clip_region); } /** @@ -3078,26 +2808,19 @@ _cairo_surface_composite_shape_fixup_unbounded (cairo_surface_t *dst, * Copies the given pattern, taking into account device scale and offsets * of the destination surface. */ -static cairo_status_t +static void _cairo_surface_copy_pattern_for_destination (const cairo_pattern_t **pattern, cairo_surface_t *destination, cairo_pattern_t *pattern_copy) { - cairo_status_t status; - if (! _cairo_surface_has_device_transform (destination)) - return CAIRO_STATUS_SUCCESS; - - status = _cairo_pattern_init_copy (pattern_copy, *pattern); - if (unlikely (status)) - return status; + return; + _cairo_pattern_init_static_copy (pattern_copy, *pattern); _cairo_pattern_transform (pattern_copy, &destination->device_transform_inverse); - *pattern = pattern_copy; - return CAIRO_STATUS_SUCCESS; } /** @@ -3122,12 +2845,178 @@ _cairo_surface_set_resolution (cairo_surface_t *surface, surface->y_resolution = y_res; } +/* Generic methods for determining operation extents. */ + +static void +_rectangle_intersect_clip (cairo_rectangle_int_t *extents, cairo_clip_t *clip) +{ + const cairo_rectangle_int_t *clip_extents; + cairo_bool_t is_empty; + + clip_extents = NULL; + if (clip != NULL) + clip_extents = _cairo_clip_get_extents (clip); + + if (clip_extents != NULL) + is_empty = _cairo_rectangle_intersect (extents, clip_extents); +} + +static void +_cairo_surface_operation_extents (cairo_surface_t *surface, + cairo_operator_t op, + const cairo_pattern_t *source, + cairo_clip_t *clip, + cairo_rectangle_int_t *extents) +{ + cairo_bool_t is_empty; + + is_empty = _cairo_surface_get_extents (surface, extents); + + if (_cairo_operator_bounded_by_source (op)) { + cairo_rectangle_int_t source_extents; + + _cairo_pattern_get_extents (source, &source_extents); + is_empty = _cairo_rectangle_intersect (extents, &source_extents); + } + + _rectangle_intersect_clip (extents, clip); +} + +cairo_status_t +_cairo_surface_paint_extents (cairo_surface_t *surface, + cairo_operator_t op, + const cairo_pattern_t *source, + cairo_clip_t *clip, + cairo_rectangle_int_t *extents) +{ + _cairo_surface_operation_extents (surface, op, source, clip, extents); + return CAIRO_STATUS_SUCCESS; +} + +cairo_status_t +_cairo_surface_mask_extents (cairo_surface_t *surface, + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_pattern_t *mask, + cairo_clip_t *clip, + cairo_rectangle_int_t *extents) +{ + cairo_bool_t is_empty; + + _cairo_surface_operation_extents (surface, op, source, clip, extents); + + if (_cairo_operator_bounded_by_mask (op)) { + cairo_rectangle_int_t mask_extents; + + _cairo_pattern_get_extents (mask, &mask_extents); + is_empty = _cairo_rectangle_intersect (extents, &mask_extents); + } + + return CAIRO_STATUS_SUCCESS; +} + +cairo_status_t +_cairo_surface_stroke_extents (cairo_surface_t *surface, + cairo_operator_t op, + const cairo_pattern_t *source, + cairo_path_fixed_t *path, + cairo_stroke_style_t *style, + const cairo_matrix_t *ctm, + const cairo_matrix_t *ctm_inverse, + double tolerance, + cairo_antialias_t antialias, + cairo_clip_t *clip, + cairo_rectangle_int_t *extents) +{ + cairo_status_t status; + cairo_bool_t is_empty; + + _cairo_surface_operation_extents (surface, op, source, clip, extents); + + if (_cairo_operator_bounded_by_mask (op)) { + cairo_rectangle_int_t mask_extents; + + status = _cairo_path_fixed_stroke_extents (path, style, + ctm, ctm_inverse, + tolerance, + &mask_extents); + if (unlikely (status)) + return status; + + is_empty = _cairo_rectangle_intersect (extents, &mask_extents); + } + + return CAIRO_STATUS_SUCCESS; +} + +cairo_status_t +_cairo_surface_fill_extents (cairo_surface_t *surface, + cairo_operator_t op, + const cairo_pattern_t *source, + cairo_path_fixed_t *path, + cairo_fill_rule_t fill_rule, + double tolerance, + cairo_antialias_t antialias, + cairo_clip_t *clip, + cairo_rectangle_int_t *extents) +{ + cairo_bool_t is_empty; + + _cairo_surface_operation_extents (surface, op, source, clip, extents); + + if (_cairo_operator_bounded_by_mask (op)) { + cairo_rectangle_int_t mask_extents; + + _cairo_path_fixed_fill_extents (path, fill_rule, tolerance, + &mask_extents); + is_empty = _cairo_rectangle_intersect (extents, &mask_extents); + } + + return CAIRO_STATUS_SUCCESS; +} + +cairo_status_t +_cairo_surface_glyphs_extents (cairo_surface_t *surface, + cairo_operator_t op, + const cairo_pattern_t *source, + cairo_glyph_t *glyphs, + int num_glyphs, + cairo_scaled_font_t *scaled_font, + cairo_clip_t *clip, + cairo_rectangle_int_t *extents) +{ + cairo_status_t status; + cairo_bool_t is_empty; + + _cairo_surface_operation_extents (surface, op, source, clip, extents); + + if (_cairo_operator_bounded_by_mask (op)) { + cairo_rectangle_int_t glyph_extents; + + status = _cairo_scaled_font_glyph_device_extents (scaled_font, + glyphs, + num_glyphs, + &glyph_extents, + NULL); + if (unlikely (status)) + return status; + + is_empty = _cairo_rectangle_intersect (extents, &glyph_extents); + } + + return CAIRO_STATUS_SUCCESS; +} + cairo_surface_t * _cairo_surface_create_in_error (cairo_status_t status) { switch (status) { case CAIRO_STATUS_NO_MEMORY: return (cairo_surface_t *) &_cairo_surface_nil; + case CAIRO_STATUS_SURFACE_TYPE_MISMATCH: + return (cairo_surface_t *) &_cairo_surface_nil_surface_type_mismatch; + case CAIRO_STATUS_INVALID_STATUS: + return (cairo_surface_t *) &_cairo_surface_nil_invalid_status; case CAIRO_STATUS_INVALID_CONTENT: return (cairo_surface_t *) &_cairo_surface_nil_invalid_content; case CAIRO_STATUS_INVALID_FORMAT: @@ -3154,12 +3043,10 @@ _cairo_surface_create_in_error (cairo_status_t status) case CAIRO_STATUS_INVALID_POP_GROUP: case CAIRO_STATUS_NO_CURRENT_POINT: case CAIRO_STATUS_INVALID_MATRIX: - case CAIRO_STATUS_INVALID_STATUS: case CAIRO_STATUS_NULL_POINTER: case CAIRO_STATUS_INVALID_STRING: case CAIRO_STATUS_INVALID_PATH_DATA: case CAIRO_STATUS_SURFACE_FINISHED: - case CAIRO_STATUS_SURFACE_TYPE_MISMATCH: case CAIRO_STATUS_PATTERN_TYPE_MISMATCH: case CAIRO_STATUS_INVALID_DASH: case CAIRO_STATUS_INVALID_DSC_COMMENT: |