diff options
Diffstat (limited to 'src/cairo-gstate.c')
-rw-r--r-- | src/cairo-gstate.c | 233 |
1 files changed, 144 insertions, 89 deletions
diff --git a/src/cairo-gstate.c b/src/cairo-gstate.c index 8f206ad9a..2257db0f7 100644 --- a/src/cairo-gstate.c +++ b/src/cairo-gstate.c @@ -100,7 +100,7 @@ _cairo_gstate_init (cairo_gstate_t *gstate, _cairo_font_options_init_default (&gstate->font_options); - _cairo_clip_init (&gstate->clip, target); + _cairo_clip_init (&gstate->clip); gstate->target = cairo_surface_reference (target); gstate->parent_target = NULL; @@ -164,14 +164,7 @@ _cairo_gstate_init_copy (cairo_gstate_t *gstate, cairo_gstate_t *other) _cairo_font_options_init_copy (&gstate->font_options , &other->font_options); - status = _cairo_clip_init_copy (&gstate->clip, &other->clip); - if (unlikely (status)) { - _cairo_stroke_style_fini (&gstate->stroke_style); - cairo_font_face_destroy (gstate->font_face); - cairo_scaled_font_destroy (gstate->scaled_font); - cairo_scaled_font_destroy (gstate->previous_scaled_font); - return status; - } + _cairo_clip_init_copy (&gstate->clip, &other->clip); gstate->target = cairo_surface_reference (other->target); /* parent_target is always set to NULL; it's only ever set by redirect_target */ @@ -299,7 +292,7 @@ _cairo_gstate_restore (cairo_gstate_t **gstate, cairo_gstate_t **freelist) cairo_status_t _cairo_gstate_redirect_target (cairo_gstate_t *gstate, cairo_surface_t *child) { - cairo_status_t status; + cairo_matrix_t matrix; /* If this gstate is already redirected, this is an error; we need a * new gstate to be able to redirect */ @@ -315,18 +308,15 @@ _cairo_gstate_redirect_target (cairo_gstate_t *gstate, cairo_surface_t *child) * since its ref is now owned by gstate->parent_target */ gstate->target = cairo_surface_reference (child); - _cairo_clip_reset (&gstate->clip); - status = _cairo_clip_init_deep_copy (&gstate->clip, &gstate->next->clip, child); - if (unlikely (status)) - return status; - /* The clip is in surface backend coordinates for the previous target; * translate it into the child's backend coordinates. */ - _cairo_clip_translate (&gstate->clip, - _cairo_fixed_from_double (child->device_transform.x0 - gstate->parent_target->device_transform.x0), - _cairo_fixed_from_double (child->device_transform.y0 - gstate->parent_target->device_transform.y0)); - - return CAIRO_STATUS_SUCCESS; + cairo_matrix_init_translate (&matrix, + child->device_transform.x0 - gstate->parent_target->device_transform.x0, + child->device_transform.y0 - gstate->parent_target->device_transform.y0); + _cairo_clip_reset (&gstate->clip); + return _cairo_clip_init_copy_transformed (&gstate->clip, + &gstate->next->clip, + &matrix); } /** @@ -870,43 +860,63 @@ _cairo_gstate_copy_transformed_mask (cairo_gstate_t *gstate, &gstate->ctm_inverse); } +#define _gstate_get_clip(g) ((g)->clip.path ? &(g)->clip : NULL) + +static cairo_bool_t +_clipped (const cairo_gstate_t *gstate) +{ + cairo_rectangle_int_t extents; + + 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, + &gstate->clip.path->extents)) + { + return TRUE; + } + } + + return FALSE; +} + cairo_status_t _cairo_gstate_paint (cairo_gstate_t *gstate) { - cairo_status_t status; cairo_pattern_union_t pattern; - if (gstate->source->status) + if (unlikely (gstate->source->status)) return gstate->source->status; - status = _cairo_surface_set_clip (gstate->target, &gstate->clip); - if (unlikely (status)) - return status; + if (_clipped (gstate)) + return CAIRO_STATUS_SUCCESS; _cairo_gstate_copy_transformed_source (gstate, &pattern.base); return _cairo_surface_paint (gstate->target, gstate->op, &pattern.base, - NULL); + _gstate_get_clip (gstate)); } cairo_status_t _cairo_gstate_mask (cairo_gstate_t *gstate, cairo_pattern_t *mask) { - cairo_status_t status; cairo_pattern_union_t source_pattern, mask_pattern; - if (mask->status) + if (unlikely (mask->status)) return mask->status; - if (gstate->source->status) + if (unlikely (gstate->source->status)) return gstate->source->status; - status = _cairo_surface_set_clip (gstate->target, &gstate->clip); - if (unlikely (status)) - return status; + if (_clipped (gstate)) + return CAIRO_STATUS_SUCCESS; _cairo_gstate_copy_transformed_source (gstate, &source_pattern.base); _cairo_gstate_copy_transformed_mask (gstate, &mask_pattern.base, mask); @@ -915,24 +925,22 @@ _cairo_gstate_mask (cairo_gstate_t *gstate, gstate->op, &source_pattern.base, &mask_pattern.base, - NULL); + _gstate_get_clip (gstate)); } cairo_status_t _cairo_gstate_stroke (cairo_gstate_t *gstate, cairo_path_fixed_t *path) { - cairo_status_t status; cairo_pattern_union_t source_pattern; - if (gstate->source->status) + if (unlikely (gstate->source->status)) return gstate->source->status; if (gstate->stroke_style.line_width <= 0.0) return CAIRO_STATUS_SUCCESS; - status = _cairo_surface_set_clip (gstate->target, &gstate->clip); - if (unlikely (status)) - return status; + if (_clipped (gstate)) + return CAIRO_STATUS_SUCCESS; _cairo_gstate_copy_transformed_source (gstate, &source_pattern.base); @@ -945,7 +953,7 @@ _cairo_gstate_stroke (cairo_gstate_t *gstate, cairo_path_fixed_t *path) &gstate->ctm_inverse, gstate->tolerance, gstate->antialias, - NULL); + _gstate_get_clip (gstate)); } cairo_status_t @@ -1009,15 +1017,26 @@ BAIL: cairo_status_t _cairo_gstate_fill (cairo_gstate_t *gstate, cairo_path_fixed_t *path) { - cairo_status_t status; cairo_pattern_union_t pattern; - if (gstate->source->status) + if (unlikely (gstate->source->status)) return gstate->source->status; - status = _cairo_surface_set_clip (gstate->target, &gstate->clip); - if (unlikely (status)) - return status; + if (_clipped (gstate)) + return CAIRO_STATUS_SUCCESS; + + if (_cairo_path_fixed_fill_is_empty (path)) { + if (_cairo_operator_bounded_by_mask (gstate->op)) + return CAIRO_STATUS_SUCCESS; + + _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)); + } _cairo_gstate_copy_transformed_source (gstate, &pattern.base); @@ -1028,23 +1047,56 @@ _cairo_gstate_fill (cairo_gstate_t *gstate, cairo_path_fixed_t *path) gstate->fill_rule, gstate->tolerance, gstate->antialias, - NULL); + _gstate_get_clip (gstate)); } -void +cairo_bool_t _cairo_gstate_in_fill (cairo_gstate_t *gstate, cairo_path_fixed_t *path, double x, - double y, - cairo_bool_t *inside_ret) + double y) +{ + _cairo_gstate_user_to_backend (gstate, &x, &y); + + return _cairo_path_fixed_in_fill (path, + gstate->fill_rule, + gstate->tolerance, + x, y); +} + +cairo_bool_t +_cairo_gstate_in_clip (cairo_gstate_t *gstate, + double x, + double y) { + cairo_clip_path_t *clip_path; + + if (gstate->clip.all_clipped) + return FALSE; + + clip_path = gstate->clip.path; + if (clip_path == NULL) + return TRUE; + _cairo_gstate_user_to_backend (gstate, &x, &y); - _cairo_path_fixed_in_fill (path, - gstate->fill_rule, - gstate->tolerance, - x, y, - inside_ret); + if (x < clip_path->extents.x || + x >= clip_path->extents.x + clip_path->extents.width || + y < clip_path->extents.y || + y >= clip_path->extents.y + clip_path->extents.height) + { + return FALSE; + } + + do { + if (! _cairo_path_fixed_in_fill (&clip_path->path, + clip_path->fill_rule, + clip_path->tolerance, + x, y)) + return FALSE; + } while ((clip_path = clip_path->prev) != NULL); + + return TRUE; } cairo_status_t @@ -1179,26 +1231,31 @@ cairo_status_t _cairo_gstate_clip (cairo_gstate_t *gstate, cairo_path_fixed_t *path) { return _cairo_clip_clip (&gstate->clip, - path, gstate->fill_rule, gstate->tolerance, - gstate->antialias, gstate->target); + path, gstate->fill_rule, + gstate->tolerance, gstate->antialias); } -static cairo_status_t +static cairo_bool_t _cairo_gstate_int_clip_extents (cairo_gstate_t *gstate, cairo_rectangle_int_t *extents) { - cairo_status_t status; + const cairo_rectangle_int_t *clip_extents; + cairo_bool_t is_bounded; - status = _cairo_surface_get_extents (gstate->target, extents); - if (unlikely (status)) - return status; + is_bounded = _cairo_surface_get_extents (gstate->target, extents); - status = _cairo_clip_intersect_to_rectangle (&gstate->clip, extents); + clip_extents = _cairo_clip_get_extents (&gstate->clip); + if (clip_extents != NULL) { + cairo_bool_t is_empty; - return status; + is_empty = _cairo_rectangle_intersect (extents, clip_extents); + is_bounded = TRUE; + } + + return is_bounded; } -cairo_status_t +cairo_bool_t _cairo_gstate_clip_extents (cairo_gstate_t *gstate, double *x1, double *y1, @@ -1207,11 +1264,9 @@ _cairo_gstate_clip_extents (cairo_gstate_t *gstate, { cairo_rectangle_int_t extents; double px1, py1, px2, py2; - cairo_status_t status; - status = _cairo_gstate_int_clip_extents (gstate, &extents); - if (unlikely (status)) - return status; + if (! _cairo_gstate_int_clip_extents (gstate, &extents)) + return FALSE; px1 = extents.x; py1 = extents.y; @@ -1231,7 +1286,7 @@ _cairo_gstate_clip_extents (cairo_gstate_t *gstate, if (y2) *y2 = py2; - return CAIRO_STATUS_SUCCESS; + return TRUE; } cairo_rectangle_list_t* @@ -1576,12 +1631,11 @@ _cairo_gstate_show_text_glyphs (cairo_gstate_t *gstate, cairo_text_cluster_t *transformed_clusters; cairo_status_t status; - if (gstate->source->status) + if (unlikely (gstate->source->status)) return gstate->source->status; - status = _cairo_surface_set_clip (gstate->target, &gstate->clip); - if (unlikely (status)) - return status; + if (_clipped (gstate)) + return CAIRO_STATUS_SUCCESS; status = _cairo_gstate_ensure_scaled_font (gstate); if (unlikely (status)) @@ -1635,7 +1689,8 @@ _cairo_gstate_show_text_glyphs (cairo_gstate_t *gstate, * * Needless to say, do this only if show_text_glyphs is not available. */ if (cairo_surface_has_show_text_glyphs (gstate->target) || - _cairo_scaled_font_get_max_scale (gstate->scaled_font) <= 10240) { + _cairo_scaled_font_get_max_scale (gstate->scaled_font) <= 10240) + { status = _cairo_surface_show_text_glyphs (gstate->target, gstate->op, &source_pattern.base, @@ -1643,8 +1698,11 @@ _cairo_gstate_show_text_glyphs (cairo_gstate_t *gstate, transformed_glyphs, num_glyphs, transformed_clusters, num_clusters, cluster_flags, - gstate->scaled_font, NULL); - } else { + gstate->scaled_font, + _gstate_get_clip (gstate)); + } + else + { cairo_path_fixed_t path; _cairo_path_fixed_init (&path); @@ -1653,14 +1711,16 @@ _cairo_gstate_show_text_glyphs (cairo_gstate_t *gstate, transformed_glyphs, num_glyphs, &path); - if (status == CAIRO_STATUS_SUCCESS) - status = _cairo_surface_fill (gstate->target, - gstate->op, - &source_pattern.base, - &path, - CAIRO_FILL_RULE_WINDING, - gstate->tolerance, - gstate->scaled_font->options.antialias, NULL); + if (status == CAIRO_STATUS_SUCCESS) { + status = _cairo_surface_fill (gstate->target, + gstate->op, + &source_pattern.base, + &path, + CAIRO_FILL_RULE_WINDING, + gstate->tolerance, + gstate->scaled_font->options.antialias, + _gstate_get_clip (gstate)); + } _cairo_path_fixed_fini (&path); } @@ -1765,17 +1825,12 @@ _cairo_gstate_transform_glyphs_to_backend (cairo_gstate_t *gstate, cairo_matrix_t *device_transform = &gstate->target->device_transform; cairo_bool_t drop = FALSE; double x1 = 0, x2 = 0, y1 = 0, y2 = 0; - cairo_status_t status; if (num_transformed_glyphs != NULL) { cairo_rectangle_int_t surface_extents; drop = TRUE; - status = _cairo_gstate_int_clip_extents (gstate, &surface_extents); - if (_cairo_status_is_error (status)) - return status; - - if (status == CAIRO_INT_STATUS_UNSUPPORTED) { + if (! _cairo_gstate_int_clip_extents (gstate, &surface_extents)) { drop = FALSE; /* unbounded surface */ } else { double scale10 = 10 * _cairo_scaled_font_get_max_scale (gstate->scaled_font); |