summaryrefslogtreecommitdiff
path: root/src/cairo-gstate.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/cairo-gstate.c')
-rw-r--r--src/cairo-gstate.c1451
1 files changed, 598 insertions, 853 deletions
diff --git a/src/cairo-gstate.c b/src/cairo-gstate.c
index ed3359b..a657f15 100644
--- a/src/cairo-gstate.c
+++ b/src/cairo-gstate.c
@@ -39,6 +39,7 @@
#include "cairoint.h"
+#include "cairo-clip-private.h"
#include "cairo-gstate-private.h"
static cairo_status_t
@@ -53,28 +54,16 @@ _cairo_gstate_fini (cairo_gstate_t *gstate);
static cairo_status_t
_cairo_gstate_clip_and_composite_trapezoids (cairo_gstate_t *gstate,
- cairo_pattern_t *src,
- cairo_operator_t operator,
- cairo_surface_t *dst,
- cairo_traps_t *traps);
-
-static cairo_status_t
-_cairo_gstate_ensure_font (cairo_gstate_t *gstate);
+ cairo_traps_t *traps);
static cairo_status_t
_cairo_gstate_ensure_font_face (cairo_gstate_t *gstate);
-static void
-_cairo_gstate_unset_font (cairo_gstate_t *gstate);
-
-static void
-_cairo_rectangle_intersect (cairo_rectangle_t *dest, cairo_rectangle_t *src);
-
-static void
-_cairo_clip_path_reference (cairo_clip_path_t *clip_path);
+static cairo_status_t
+_cairo_gstate_ensure_scaled_font (cairo_gstate_t *gstate);
static void
-_cairo_clip_path_destroy (cairo_clip_path_t *clip_path);
+_cairo_gstate_unset_scaled_font (cairo_gstate_t *gstate);
cairo_gstate_t *
_cairo_gstate_create (cairo_surface_t *target)
@@ -103,6 +92,7 @@ _cairo_gstate_init (cairo_gstate_t *gstate,
gstate->operator = CAIRO_GSTATE_OPERATOR_DEFAULT;
gstate->tolerance = CAIRO_GSTATE_TOLERANCE_DEFAULT;
+ gstate->antialias = CAIRO_ANTIALIAS_DEFAULT;
gstate->line_width = CAIRO_GSTATE_LINE_WIDTH_DEFAULT;
gstate->line_cap = CAIRO_GSTATE_LINE_CAP_DEFAULT;
@@ -124,18 +114,14 @@ _cairo_gstate_init (cairo_gstate_t *gstate,
_cairo_font_options_init_default (&gstate->font_options);
- gstate->clip.mode = _cairo_surface_get_clip_mode (target);
- gstate->clip.region = NULL;
- gstate->clip.surface = NULL;
- gstate->clip.serial = 0;
- gstate->clip.path = NULL;
+ _cairo_clip_init (&gstate->clip, target);
_cairo_gstate_identity_matrix (gstate);
+ cairo_matrix_init_identity (&gstate->source_ctm_inverse);
_cairo_pen_init_empty (&gstate->pen_regular);
- gstate->target = target;
- cairo_surface_reference (gstate->target);
+ gstate->target = cairo_surface_reference (target);
gstate->source = _cairo_pattern_create_solid (CAIRO_COLOR_BLACK);
if (gstate->source->status)
@@ -165,10 +151,7 @@ _cairo_gstate_init_copy (cairo_gstate_t *gstate, cairo_gstate_t *other)
memcpy (gstate->dash, other->dash, other->num_dashes * sizeof (double));
}
- if (other->clip.region) {
- gstate->clip.region = pixman_region_create ();
- pixman_region_copy (gstate->clip.region, other->clip.region);
- }
+ _cairo_clip_init_copy (&gstate->clip, &other->clip);
if (gstate->font_face)
cairo_font_face_reference (gstate->font_face);
@@ -177,8 +160,6 @@ _cairo_gstate_init_copy (cairo_gstate_t *gstate, cairo_gstate_t *other)
cairo_scaled_font_reference (gstate->scaled_font);
cairo_surface_reference (gstate->target);
- cairo_surface_reference (gstate->clip.surface);
- _cairo_clip_path_reference (gstate->clip.path);
cairo_pattern_reference (gstate->source);
@@ -212,18 +193,7 @@ _cairo_gstate_fini (cairo_gstate_t *gstate)
gstate->target = NULL;
}
- if (gstate->clip.surface)
- cairo_surface_destroy (gstate->clip.surface);
- gstate->clip.surface = NULL;
-
- if (gstate->clip.path)
- _cairo_clip_path_destroy (gstate->clip.path);
- gstate->clip.path = NULL;
-
- if (gstate->clip.region)
- pixman_region_destroy (gstate->clip.region);
- gstate->clip.region = NULL;
- gstate->clip.serial = 0;
+ _cairo_clip_fini (&gstate->clip);
cairo_pattern_destroy (gstate->source);
@@ -343,61 +313,6 @@ _cairo_gstate_end_group (cairo_gstate_t *gstate)
}
*/
-static cairo_status_t
-_cairo_gstate_set_clip (cairo_gstate_t *gstate)
-{
- cairo_surface_t *surface = gstate->target;
-
- if (!surface)
- return CAIRO_STATUS_NULL_POINTER;
- if (gstate->clip.serial == _cairo_surface_get_current_clip_serial (surface))
- return CAIRO_STATUS_SUCCESS;
-
- if (gstate->clip.path)
- return _cairo_surface_set_clip_path (surface,
- gstate->clip.path,
- gstate->clip.serial);
-
- if (gstate->clip.region)
- return _cairo_surface_set_clip_region (surface,
- gstate->clip.region,
- gstate->clip.serial);
-
- return _cairo_surface_reset_clip (surface);
-}
-
-static cairo_status_t
-_cairo_gstate_get_clip_extents (cairo_gstate_t *gstate,
- cairo_rectangle_t *rectangle)
-{
- cairo_status_t status;
-
- status = _cairo_surface_get_extents (gstate->target, rectangle);
- if (status)
- return status;
- /* check path extents here */
-
- if (gstate->clip.region) {
- pixman_box16_t *clip_box;
- cairo_rectangle_t clip_rect;
-
- /* get region extents as a box */
- clip_box = pixman_region_extents (gstate->clip.region);
- /* convert to a rectangle */
- clip_rect.x = clip_box->x1;
- clip_rect.width = clip_box->x2 - clip_box->x1;
- clip_rect.y = clip_box->y1;
- clip_rect.height = clip_box->y2 - clip_box->y1;
- /* intersect with surface extents */
- _cairo_rectangle_intersect (rectangle, &clip_rect);
- }
-
- if (gstate->clip.surface)
- _cairo_rectangle_intersect (rectangle, &gstate->clip.surface_rect);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
cairo_surface_t *
_cairo_gstate_get_target (cairo_gstate_t *gstate)
{
@@ -414,6 +329,7 @@ _cairo_gstate_set_source (cairo_gstate_t *gstate,
cairo_pattern_reference (source);
cairo_pattern_destroy (gstate->source);
gstate->source = source;
+ gstate->source_ctm_inverse = gstate->ctm_inverse;
return CAIRO_STATUS_SUCCESS;
}
@@ -559,7 +475,7 @@ _cairo_gstate_translate (cairo_gstate_t *gstate, double tx, double ty)
{
cairo_matrix_t tmp;
- _cairo_gstate_unset_font (gstate);
+ _cairo_gstate_unset_scaled_font (gstate);
cairo_matrix_init_translate (&tmp, tx, ty);
cairo_matrix_multiply (&gstate->ctm, &tmp, &gstate->ctm);
@@ -578,7 +494,7 @@ _cairo_gstate_scale (cairo_gstate_t *gstate, double sx, double sy)
if (sx == 0 || sy == 0)
return CAIRO_STATUS_INVALID_MATRIX;
- _cairo_gstate_unset_font (gstate);
+ _cairo_gstate_unset_scaled_font (gstate);
cairo_matrix_init_scale (&tmp, sx, sy);
cairo_matrix_multiply (&gstate->ctm, &tmp, &gstate->ctm);
@@ -594,7 +510,7 @@ _cairo_gstate_rotate (cairo_gstate_t *gstate, double angle)
{
cairo_matrix_t tmp;
- _cairo_gstate_unset_font (gstate);
+ _cairo_gstate_unset_scaled_font (gstate);
cairo_matrix_init_rotate (&tmp, angle);
cairo_matrix_multiply (&gstate->ctm, &tmp, &gstate->ctm);
@@ -611,7 +527,7 @@ _cairo_gstate_transform (cairo_gstate_t *gstate,
{
cairo_matrix_t tmp;
- _cairo_gstate_unset_font (gstate);
+ _cairo_gstate_unset_scaled_font (gstate);
tmp = *matrix;
cairo_matrix_multiply (&gstate->ctm, &tmp, &gstate->ctm);
@@ -628,7 +544,7 @@ _cairo_gstate_set_matrix (cairo_gstate_t *gstate,
{
cairo_status_t status;
- _cairo_gstate_unset_font (gstate);
+ _cairo_gstate_unset_scaled_font (gstate);
gstate->ctm = *matrix;
@@ -643,7 +559,7 @@ _cairo_gstate_set_matrix (cairo_gstate_t *gstate,
cairo_status_t
_cairo_gstate_identity_matrix (cairo_gstate_t *gstate)
{
- _cairo_gstate_unset_font (gstate);
+ _cairo_gstate_unset_scaled_font (gstate);
cairo_matrix_init_identity (&gstate->ctm);
cairo_matrix_init_identity (&gstate->ctm_inverse);
@@ -717,11 +633,15 @@ _cairo_gstate_stroke_to_path (cairo_gstate_t *gstate)
*/
static void
-_cairo_gstate_pattern_transform (cairo_gstate_t *gstate,
- cairo_pattern_t *pattern)
+_cairo_gstate_copy_transformed_pattern (cairo_gstate_t *gstate,
+ cairo_pattern_t *pattern,
+ cairo_pattern_t *original,
+ cairo_matrix_t *ctm_inverse)
{
- cairo_matrix_t tmp_matrix = gstate->ctm_inverse;
-
+ cairo_matrix_t tmp_matrix = *ctm_inverse;
+
+ _cairo_pattern_init_copy (pattern, original);
+
if (gstate->target)
cairo_matrix_translate (&tmp_matrix,
- gstate->target->device_x_offset,
@@ -730,6 +650,25 @@ _cairo_gstate_pattern_transform (cairo_gstate_t *gstate,
_cairo_pattern_transform (pattern, &tmp_matrix);
}
+static void
+_cairo_gstate_copy_transformed_source (cairo_gstate_t *gstate,
+ cairo_pattern_t *pattern)
+{
+ _cairo_gstate_copy_transformed_pattern (gstate, pattern,
+ gstate->source,
+ &gstate->source_ctm_inverse);
+}
+
+static void
+_cairo_gstate_copy_transformed_mask (cairo_gstate_t *gstate,
+ cairo_pattern_t *pattern,
+ cairo_pattern_t *mask)
+{
+ _cairo_gstate_copy_transformed_pattern (gstate, pattern,
+ mask,
+ &gstate->ctm_inverse);
+}
+
cairo_status_t
_cairo_gstate_paint (cairo_gstate_t *gstate)
{
@@ -741,11 +680,14 @@ _cairo_gstate_paint (cairo_gstate_t *gstate)
if (gstate->source->status)
return gstate->source->status;
- status = _cairo_gstate_set_clip (gstate);
+ status = _cairo_surface_set_clip (gstate->target, &gstate->clip);
if (status)
return status;
- status = _cairo_gstate_get_clip_extents (gstate, &rectangle);
+ status = _cairo_surface_get_extents (gstate->target, &rectangle);
+ if (status)
+ return status;
+ status = _cairo_clip_intersect_to_rectangle (&gstate->clip, &rectangle);
if (status)
return status;
@@ -757,119 +699,310 @@ _cairo_gstate_paint (cairo_gstate_t *gstate)
if (status)
return status;
- _cairo_gstate_clip_and_composite_trapezoids (gstate,
- gstate->source,
- gstate->operator,
- gstate->target,
- &traps);
+ _cairo_gstate_clip_and_composite_trapezoids (gstate, &traps);
_cairo_traps_fini (&traps);
return CAIRO_STATUS_SUCCESS;
}
-/* Combines @gstate->clip_surface using the IN operator with
- * the given intermediate surface, which corresponds to the
- * rectangle of the destination space given by @extents.
+/**
+ * _cairo_operator_bounded:
+ * @operator: a #cairo_operator_t
+ *
+ * A bounded operator is one where a source or mask pixel
+ * of zero results in no effect on the destination image.
+ *
+ * Unbounded operators often require special handling; if you, for
+ * example, draw trapezoids with an unbounded operator, the effect
+ * extends past the bounding box of the trapezoids.
+ *
+ * Return value: %TRUE if the operator is bounded
+ **/
+cairo_bool_t
+_cairo_operator_bounded (cairo_operator_t operator)
+{
+ switch (operator) {
+ case CAIRO_OPERATOR_OVER:
+ case CAIRO_OPERATOR_ATOP:
+ case CAIRO_OPERATOR_DEST:
+ case CAIRO_OPERATOR_DEST_OVER:
+ case CAIRO_OPERATOR_DEST_OUT:
+ case CAIRO_OPERATOR_XOR:
+ case CAIRO_OPERATOR_ADD:
+ case CAIRO_OPERATOR_SATURATE:
+ return TRUE;
+ case CAIRO_OPERATOR_CLEAR:
+ case CAIRO_OPERATOR_SOURCE:
+ case CAIRO_OPERATOR_OUT:
+ case CAIRO_OPERATOR_IN:
+ case CAIRO_OPERATOR_DEST_IN:
+ case CAIRO_OPERATOR_DEST_ATOP:
+ return FALSE;
+ }
+
+ ASSERT_NOT_REACHED;
+ return FALSE;
+}
+
+typedef cairo_status_t (*cairo_draw_func_t) (void *closure,
+ cairo_operator_t operator,
+ cairo_pattern_t *src,
+ cairo_surface_t *dst,
+ int dst_x,
+ int dst_y,
+ const cairo_rectangle_t *extents);
+
+/* Handles compositing with a clip surface when the operator allows
+ * us to combine the clip with the mask
*/
static cairo_status_t
-_cairo_gstate_combine_clip_surface (cairo_gstate_t *gstate,
- cairo_surface_t *intermediate,
- cairo_rectangle_t *extents)
+_cairo_gstate_clip_and_composite_with_mask (cairo_clip_t *clip,
+ cairo_operator_t operator,
+ cairo_pattern_t *src,
+ cairo_draw_func_t draw_func,
+ void *draw_closure,
+ cairo_surface_t *dst,
+ const cairo_rectangle_t *extents)
{
- cairo_pattern_union_t pattern;
+ cairo_surface_t *intermediate;
+ cairo_surface_pattern_t intermediate_pattern;
cairo_status_t status;
- _cairo_pattern_init_for_surface (&pattern.surface,
- gstate->clip.surface);
+ intermediate = cairo_surface_create_similar (clip->surface,
+ CAIRO_CONTENT_ALPHA,
+ extents->width,
+ extents->height);
+ if (intermediate->status)
+ return CAIRO_STATUS_NO_MEMORY;
+
+ status = (*draw_func) (draw_closure, CAIRO_OPERATOR_SOURCE,
+ NULL, intermediate,
+ extents->x, extents->y,
+ extents);
+ if (status)
+ goto CLEANUP_SURFACE;
- status = _cairo_surface_composite (CAIRO_OPERATOR_IN,
- &pattern.base,
- NULL,
- intermediate,
- extents->x - gstate->clip.surface_rect.x,
- extents->y - gstate->clip.surface_rect.y,
- 0, 0,
- 0, 0,
- extents->width, extents->height);
+ status = _cairo_clip_combine_to_surface (clip, CAIRO_OPERATOR_IN,
+ intermediate,
+ extents->x, extents->y,
+ extents);
+ if (status)
+ goto CLEANUP_SURFACE;
- _cairo_pattern_fini (&pattern.base);
+ _cairo_pattern_init_for_surface (&intermediate_pattern, intermediate);
+
+ status = _cairo_surface_composite (operator,
+ src, &intermediate_pattern.base, dst,
+ extents->x, extents->y,
+ 0, 0,
+ extents->x, extents->y,
+ extents->width, extents->height);
+
+ _cairo_pattern_fini (&intermediate_pattern.base);
+
+ CLEANUP_SURFACE:
+ cairo_surface_destroy (intermediate);
return status;
}
-/* Creates a region from a cairo_rectangle_t */
+/* Handles compositing with a clip surface when the operator allows
+ * us to combine the clip with the mask
+ */
static cairo_status_t
-_region_new_from_rect (cairo_rectangle_t *rect,
- pixman_region16_t **region)
-{
- *region = pixman_region_create ();
- if (pixman_region_union_rect (*region, *region,
- rect->x, rect->y,
- rect->width, rect->height) != PIXMAN_REGION_STATUS_SUCCESS) {
- pixman_region_destroy (*region);
+_cairo_gstate_clip_and_composite_combine (cairo_clip_t *clip,
+ cairo_operator_t operator,
+ cairo_pattern_t *src,
+ cairo_draw_func_t draw_func,
+ void *draw_closure,
+ cairo_surface_t *dst,
+ const cairo_rectangle_t *extents)
+{
+ cairo_surface_t *intermediate;
+ cairo_surface_pattern_t dst_pattern;
+ cairo_surface_pattern_t intermediate_pattern;
+ cairo_status_t status;
+
+ /* We'd be better off here creating a surface identical in format
+ * to dst, but we have no way of getting that information.
+ * A CAIRO_CONTENT_CLONE or something might be useful.
+ */
+ intermediate = cairo_surface_create_similar (dst,
+ CAIRO_CONTENT_COLOR_ALPHA,
+ extents->width,
+ extents->height);
+ if (intermediate->status)
return CAIRO_STATUS_NO_MEMORY;
- }
- return CAIRO_STATUS_SUCCESS;
-}
+ /* Initialize the intermediate surface from the destination surface
+ */
+ _cairo_pattern_init_for_surface (&dst_pattern, dst);
-/* Gets the bounding box of a region as a cairo_rectangle_t */
-static void
-_region_rect_extents (pixman_region16_t *region,
- cairo_rectangle_t *rect)
-{
- pixman_box16_t *region_extents = pixman_region_extents (region);
+ status = _cairo_surface_composite (CAIRO_OPERATOR_SOURCE,
+ &dst_pattern.base, NULL, intermediate,
+ extents->x, extents->y,
+ 0, 0,
+ 0, 0,
+ extents->width, extents->height);
- rect->x = region_extents->x1;
- rect->y = region_extents->y1;
- rect->width = region_extents->x2 - region_extents->x1;
- rect->height = region_extents->y2 - region_extents->y1;
-}
+ _cairo_pattern_fini (&dst_pattern.base);
-/* Intersects @region with the clipping bounds (both region
- * and surface) of @gstate
- */
-static cairo_status_t
-_cairo_gstate_intersect_clip (cairo_gstate_t *gstate,
- pixman_region16_t *region)
-{
- if (gstate->clip.region)
- pixman_region_intersect (region, gstate->clip.region, region);
+ if (status)
+ goto CLEANUP_SURFACE;
+
+ status = (*draw_func) (draw_closure, operator,
+ src, intermediate,
+ extents->x, extents->y,
+ extents);
+ if (status)
+ goto CLEANUP_SURFACE;
+
+ /* Combine that with the clip
+ */
+ status = _cairo_clip_combine_to_surface (clip, CAIRO_OPERATOR_DEST_IN,
+ intermediate,
+ extents->x, extents->y,
+ extents);
+ if (status)
+ goto CLEANUP_SURFACE;
+
+ /* Punch the clip out of the destination
+ */
+ status = _cairo_clip_combine_to_surface (clip, CAIRO_OPERATOR_DEST_OUT,
+ dst,
+ 0, 0,
+ extents);
+ if (status)
+ goto CLEANUP_SURFACE;
- if (gstate->clip.surface) {
- pixman_region16_t *clip_rect;
- cairo_status_t status;
+ /* Now add the two results together
+ */
+ _cairo_pattern_init_for_surface (&intermediate_pattern, intermediate);
- status = _region_new_from_rect (&gstate->clip.surface_rect, &clip_rect);
- if (status)
- return status;
-
- if (pixman_region_intersect (region,
- clip_rect,
- region) != PIXMAN_REGION_STATUS_SUCCESS)
- status = CAIRO_STATUS_NO_MEMORY;
+ status = _cairo_surface_composite (CAIRO_OPERATOR_ADD,
+ &intermediate_pattern.base, NULL, dst,
+ 0, 0,
+ 0, 0,
+ extents->x, extents->y,
+ extents->width, extents->height);
- pixman_region_destroy (clip_rect);
+ _cairo_pattern_fini (&intermediate_pattern.base);
+
+ CLEANUP_SURFACE:
+ cairo_surface_destroy (intermediate);
- if (status)
- return status;
- }
+ return status;
+}
- return CAIRO_STATUS_SUCCESS;
+static int
+_cairo_rectangle_empty (const cairo_rectangle_t *rect)
+{
+ return rect->width == 0 || rect->height == 0;
}
+/**
+ * _cairo_gstate_clip_and_composite:
+ * @gstate: a #cairo_gstate_t
+ * @operator: the operator to draw with
+ * @src: source pattern
+ * @draw_func: function that can be called to draw with the mask onto a surface.
+ * @draw_closure: data to pass to @draw_func.
+ * @dst: destination surface
+ * @extents: rectangle holding a bounding box for the operation; this
+ * rectangle will be used as the size for the temporary
+ * surface.
+ *
+ * When there is a surface clip, we typically need to create an intermediate
+ * surface. This function handles the logic of creating a temporary surface
+ * drawing to it, then compositing the result onto the target surface.
+ *
+ * @draw_func is to called to draw the mask; it will be called no more
+ * than once.
+ *
+ * Return value: %CAIRO_STATUS_SUCCESS if the drawing succeeded.
+ **/
+static cairo_status_t
+_cairo_gstate_clip_and_composite (cairo_clip_t *clip,
+ cairo_operator_t operator,
+ cairo_pattern_t *src,
+ cairo_draw_func_t draw_func,
+ void *draw_closure,
+ cairo_surface_t *dst,
+ const cairo_rectangle_t *extents)
+{
+ if (_cairo_rectangle_empty (extents))
+ /* Nothing to do */
+ return CAIRO_STATUS_SUCCESS;
+
+ if (clip->surface)
+ {
+ if (_cairo_operator_bounded (operator))
+ return _cairo_gstate_clip_and_composite_with_mask (clip, operator,
+ src,
+ draw_func, draw_closure,
+ dst, extents);
+ else
+ return _cairo_gstate_clip_and_composite_combine (clip, operator,
+ src,
+ draw_func, draw_closure,
+ dst, extents);
+ }
+ else
+ {
+ return (*draw_func) (draw_closure, operator,
+ src, dst,
+ 0, 0,
+ extents);
+ }
+}
+
+
static cairo_status_t
_get_mask_extents (cairo_gstate_t *gstate,
cairo_pattern_t *mask,
cairo_rectangle_t *extents)
{
+ cairo_status_t status;
+
/*
* XXX should take mask extents into account, but
- * that involves checking the transform... For now,
+ * that involves checking the transform and
+ * _cairo_operator_bounded (operator)... For now,
* be lazy and just use the destination extents
*/
- return _cairo_gstate_get_clip_extents (gstate, extents);
+ status = _cairo_surface_get_extents (gstate->target, extents);
+ if (status)
+ return status;
+
+ return _cairo_clip_intersect_to_rectangle (&gstate->clip, extents);
+}
+
+static cairo_status_t
+_cairo_gstate_mask_draw_func (void *closure,
+ cairo_operator_t operator,
+ cairo_pattern_t *src,
+ cairo_surface_t *dst,
+ int dst_x,
+ int dst_y,
+ const cairo_rectangle_t *extents)
+{
+ cairo_pattern_t *mask = closure;
+
+ if (src)
+ return _cairo_surface_composite (operator,
+ src, mask, dst,
+ extents->x, extents->y,
+ extents->x, extents->y,
+ extents->x - dst_x, extents->y - dst_y,
+ extents->width, extents->height);
+ else
+ return _cairo_surface_composite (operator,
+ mask, NULL, dst,
+ extents->x, extents->y,
+ 0, 0, /* unused */
+ extents->x - dst_x, extents->y - dst_y,
+ extents->width, extents->height);
}
cairo_status_t
@@ -877,11 +1010,8 @@ _cairo_gstate_mask (cairo_gstate_t *gstate,
cairo_pattern_t *mask)
{
cairo_rectangle_t extents;
- cairo_pattern_union_t pattern;
- cairo_surface_pattern_t intermediate_pattern;
- cairo_pattern_t *effective_mask;
+ cairo_pattern_union_t source_pattern, mask_pattern;
cairo_status_t status;
- int mask_x, mask_y;
if (mask->status)
return mask->status;
@@ -889,69 +1019,23 @@ _cairo_gstate_mask (cairo_gstate_t *gstate,
if (gstate->source->status)
return gstate->source->status;
- status = _cairo_gstate_set_clip (gstate);
+ status = _cairo_surface_set_clip (gstate->target, &gstate->clip);
if (status)
return status;
- _get_mask_extents (gstate, mask, &extents);
+ _cairo_gstate_copy_transformed_source (gstate, &source_pattern.base);
+ _cairo_gstate_copy_transformed_mask (gstate, &mask_pattern.base, mask);
- if (gstate->clip.surface) {
- /* When there is clip surface, we'll need to create a
- * temporary surface that combines the clip and mask
- */
- cairo_surface_t *intermediate;
-
- intermediate = cairo_surface_create_similar (gstate->clip.surface,
- CAIRO_CONTENT_ALPHA,
- extents.width,
- extents.height);
- if (intermediate->status)
- return CAIRO_STATUS_NO_MEMORY;
-
- status = _cairo_surface_composite (CAIRO_OPERATOR_SOURCE,
- mask, NULL, intermediate,
- extents.x, extents.y,
- 0, 0,
- 0, 0,
- extents.width, extents.height);
- if (status) {
- cairo_surface_destroy (intermediate);
- return status;
- }
-
- status = _cairo_gstate_combine_clip_surface (gstate, intermediate, &extents);
- if (status) {
- cairo_surface_destroy (intermediate);
- return status;
- }
-
- _cairo_pattern_init_for_surface (&intermediate_pattern, intermediate);
- cairo_surface_destroy (intermediate);
-
- effective_mask = &intermediate_pattern.base;
- mask_x = extents.x;
- mask_y = extents.y;
-
- } else {
- effective_mask = mask;
- mask_x = mask_y = 0;
- }
-
- _cairo_pattern_init_copy (&pattern.base, gstate->source);
- _cairo_gstate_pattern_transform (gstate, &pattern.base);
-
- status = _cairo_surface_composite (gstate->operator,
- &pattern.base,
- effective_mask,
- gstate->target,
- extents.x, extents.y,
- extents.x - mask_x, extents.y - mask_y,
- extents.x, extents.y,
- extents.width, extents.height);
+ _get_mask_extents (gstate, &mask_pattern.base, &extents);
+
+ status = _cairo_gstate_clip_and_composite (&gstate->clip, gstate->operator,
+ &source_pattern.base,
+ _cairo_gstate_mask_draw_func, &mask_pattern.base,
+ gstate->target,
+ &extents);
- if (gstate->clip.surface)
- _cairo_pattern_fini (&intermediate_pattern.base);
- _cairo_pattern_fini (&pattern.base);
+ _cairo_pattern_fini (&source_pattern.base);
+ _cairo_pattern_fini (&mask_pattern.base);
return status;
}
@@ -968,7 +1052,7 @@ _cairo_gstate_stroke (cairo_gstate_t *gstate, cairo_path_fixed_t *path)
if (gstate->line_width <= 0.0)
return CAIRO_STATUS_SUCCESS;
- status = _cairo_gstate_set_clip (gstate);
+ status = _cairo_surface_set_clip (gstate->target, &gstate->clip);
if (status)
return status;
@@ -982,11 +1066,7 @@ _cairo_gstate_stroke (cairo_gstate_t *gstate, cairo_path_fixed_t *path)
return status;
}
- _cairo_gstate_clip_and_composite_trapezoids (gstate,
- gstate->source,
- gstate->operator,
- gstate->target,
- &traps);
+ _cairo_gstate_clip_and_composite_trapezoids (gstate, &traps);
_cairo_traps_fini (&traps);
@@ -1035,7 +1115,7 @@ BAIL:
* _cairo_rectangle_fixed_round.
*/
-static void
+void
_cairo_box_round_to_rectangle (cairo_box_t *box, cairo_rectangle_t *rectangle)
{
rectangle->x = _cairo_fixed_integer_floor (box->p1.x);
@@ -1044,7 +1124,7 @@ _cairo_box_round_to_rectangle (cairo_box_t *box, cairo_rectangle_t *rectangle)
rectangle->height = _cairo_fixed_integer_ceil (box->p2.y) - rectangle->y;
}
-static void
+void
_cairo_rectangle_intersect (cairo_rectangle_t *dest, cairo_rectangle_t *src)
{
int x1, y1, x2, y2;
@@ -1067,80 +1147,10 @@ _cairo_rectangle_intersect (cairo_rectangle_t *dest, cairo_rectangle_t *src)
}
}
-static int
-_cairo_rectangle_empty (cairo_rectangle_t *rect)
-{
- return rect->width == 0 || rect->height == 0;
-}
-
-/* Given a region representing a set of trapezoids that will be
- * drawn, clip the region according to the gstate and compute
- * the overall extents.
- */
-static cairo_status_t
-_clip_and_compute_extents_region (cairo_gstate_t *gstate,
- pixman_region16_t *trap_region,
- cairo_rectangle_t *extents)
-{
- cairo_status_t status;
-
- status = _cairo_gstate_intersect_clip (gstate, trap_region);
- if (status)
- return status;
-
- _region_rect_extents (trap_region, extents);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-/* Given a a set of trapezoids to draw, find a bounding box (non-exact)
- * of the trapezoids clipped by the gstate
- */
-static cairo_status_t
-_clip_and_compute_extents_arbitrary (cairo_gstate_t *gstate,
- cairo_traps_t *traps,
- cairo_rectangle_t *extents)
-{
- cairo_box_t trap_extents;
-
- _cairo_traps_extents (traps, &trap_extents);
- _cairo_box_round_to_rectangle (&trap_extents, extents);
-
- if (gstate->clip.region) {
- pixman_region16_t *intersection;
- cairo_status_t status;
-
- status = _region_new_from_rect (extents, &intersection);
- if (status)
- return status;
-
- if (pixman_region_intersect (intersection,
- gstate->clip.region,
- intersection) == PIXMAN_REGION_STATUS_SUCCESS)
- {
- _region_rect_extents (intersection, extents);
- }
- else
- {
- status = CAIRO_STATUS_NO_MEMORY;
- }
-
- pixman_region_destroy (intersection);
-
- if (status)
- return status;
- }
-
- if (gstate->clip.surface)
- _cairo_rectangle_intersect (extents, &gstate->clip.surface_rect);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
/* Composites a region representing a set of trapezoids.
*/
static cairo_status_t
-_composite_trap_region (cairo_gstate_t *gstate,
+_composite_trap_region (cairo_clip_t *clip,
cairo_pattern_t *src,
cairo_operator_t operator,
cairo_surface_t *dst,
@@ -1148,7 +1158,6 @@ _composite_trap_region (cairo_gstate_t *gstate,
cairo_rectangle_t *extents)
{
cairo_status_t status;
- cairo_pattern_union_t pattern;
cairo_pattern_union_t mask;
int num_rects = pixman_region_num_rects (trap_region);
unsigned int clip_serial;
@@ -1157,146 +1166,42 @@ _composite_trap_region (cairo_gstate_t *gstate,
return CAIRO_STATUS_SUCCESS;
if (num_rects > 1) {
-
- if (gstate->clip.mode != CAIRO_CLIP_MODE_REGION)
+ if (clip->mode != CAIRO_CLIP_MODE_REGION)
return CAIRO_INT_STATUS_UNSUPPORTED;
- clip_serial = _cairo_surface_allocate_clip_serial (gstate->target);
- status = _cairo_surface_set_clip_region (gstate->target,
+ clip_serial = _cairo_surface_allocate_clip_serial (dst);
+ status = _cairo_surface_set_clip_region (dst,
trap_region,
clip_serial);
if (status)
return status;
}
- _cairo_pattern_init_copy (&pattern.base, src);
- _cairo_gstate_pattern_transform (gstate, &pattern.base);
-
- if (gstate->clip.surface)
- _cairo_pattern_init_for_surface (&mask.surface, gstate->clip.surface);
+ if (clip->surface)
+ _cairo_pattern_init_for_surface (&mask.surface, clip->surface);
- status = _cairo_surface_composite (gstate->operator,
- &pattern.base,
- gstate->clip.surface ? &mask.base : NULL,
+ status = _cairo_surface_composite (operator,
+ src,
+ clip->surface ? &mask.base : NULL,
dst,
extents->x, extents->y,
- extents->x - (gstate->clip.surface ? gstate->clip.surface_rect.x : 0),
- extents->y - (gstate->clip.surface ? gstate->clip.surface_rect.y : 0),
+ extents->x - (clip->surface ? clip->surface_rect.x : 0),
+ extents->y - (clip->surface ? clip->surface_rect.y : 0),
extents->x, extents->y,
extents->width, extents->height);
- _cairo_pattern_fini (&pattern.base);
- if (gstate->clip.surface)
+ if (clip->surface)
_cairo_pattern_fini (&mask.base);
return status;
}
-static void
-translate_traps (cairo_traps_t *traps, int x, int y)
-{
- cairo_fixed_t xoff, yoff;
- cairo_trapezoid_t *t;
- int i;
-
- /* Ugh. The cairo_composite/(Render) interface doesn't allow
- an offset for the trapezoids. Need to manually shift all
- the coordinates to align with the offset origin of the
- intermediate surface. */
-
- xoff = _cairo_fixed_from_int (x);
- yoff = _cairo_fixed_from_int (y);
-
- for (i = 0, t = traps->traps; i < traps->num_traps; i++, t++) {
- t->top += yoff;
- t->bottom += yoff;
- t->left.p1.x += xoff;
- t->left.p1.y += yoff;
- t->left.p2.x += xoff;
- t->left.p2.y += yoff;
- t->right.p1.x += xoff;
- t->right.p1.y += yoff;
- t->right.p2.x += xoff;
- t->right.p2.y += yoff;
- }
-}
-
-/* Composites a set of trapezoids in the case where we need to create
- * an intermediate surface to handle gstate->clip.surface
- *
- * Warning: This call modifies the coordinates of traps
- */
-static cairo_status_t
-_composite_traps_intermediate_surface (cairo_gstate_t *gstate,
- cairo_pattern_t *src,
- cairo_operator_t operator,
- cairo_surface_t *dst,
- cairo_traps_t *traps,
- cairo_rectangle_t *extents)
-{
- cairo_pattern_union_t pattern;
- cairo_surface_t *intermediate;
- cairo_surface_pattern_t intermediate_pattern;
- cairo_status_t status;
-
- translate_traps (traps, -extents->x, -extents->y);
-
- intermediate = _cairo_surface_create_similar_solid (gstate->clip.surface,
- CAIRO_CONTENT_ALPHA,
- extents->width,
- extents->height,
- CAIRO_COLOR_TRANSPARENT);
- if (intermediate->status)
- return CAIRO_STATUS_NO_MEMORY;
-
- _cairo_pattern_init_solid (&pattern.solid, CAIRO_COLOR_WHITE);
-
- status = _cairo_surface_composite_trapezoids (CAIRO_OPERATOR_ADD,
- &pattern.base,
- intermediate,
- extents->x, extents->y,
- 0, 0,
- extents->width,
- extents->height,
- traps->traps,
- traps->num_traps);
- _cairo_pattern_fini (&pattern.base);
-
- if (status)
- goto out;
-
- status = _cairo_gstate_combine_clip_surface (gstate, intermediate, extents);
- if (status)
- goto out;
-
- _cairo_pattern_init_for_surface (&intermediate_pattern, intermediate);
- _cairo_pattern_init_copy (&pattern.base, src);
- _cairo_gstate_pattern_transform (gstate, &pattern.base);
-
- status = _cairo_surface_composite (operator,
- &pattern.base,
- &intermediate_pattern.base,
- dst,
- extents->x, extents->y,
- 0, 0,
- extents->x, extents->y,
- extents->width, extents->height);
-
- _cairo_pattern_fini (&pattern.base);
- _cairo_pattern_fini (&intermediate_pattern.base);
-
- out:
- cairo_surface_destroy (intermediate);
-
- return status;
-}
-
/* Composites a region representing a set of trapezoids in the
* case of a solid source (so we can use
* _cairo_surface_fill_rectangles).
*/
static cairo_status_t
-_composite_trap_region_solid (cairo_gstate_t *gstate,
+_composite_trap_region_solid (cairo_clip_t *clip,
cairo_solid_pattern_t *src,
cairo_operator_t operator,
cairo_surface_t *dst,
@@ -1330,48 +1235,69 @@ _composite_trap_region_solid (cairo_gstate_t *gstate,
return status;
}
-/* Composites a set of trapezoids in the general case where
- gstate->clip.surface == NULL
- */
+typedef struct {
+ cairo_traps_t *traps;
+ cairo_antialias_t antialias;
+} cairo_composite_traps_info_t;
+
static cairo_status_t
-_composite_traps (cairo_gstate_t *gstate,
- cairo_pattern_t *src,
- cairo_operator_t operator,
- cairo_surface_t *dst,
- cairo_traps_t *traps,
- cairo_rectangle_t *extents)
-{
+_composite_traps_draw_func (void *closure,
+ cairo_operator_t operator,
+ cairo_pattern_t *src,
+ cairo_surface_t *dst,
+ int dst_x,
+ int dst_y,
+ const cairo_rectangle_t *extents)
+{
+ cairo_composite_traps_info_t *info = closure;
cairo_pattern_union_t pattern;
cairo_status_t status;
-
- _cairo_pattern_init_copy (&pattern.base, src);
- _cairo_gstate_pattern_transform (gstate, &pattern.base);
- status = _cairo_surface_composite_trapezoids (gstate->operator,
- &pattern.base, dst,
- extents->x, extents->y,
- extents->x, extents->y,
- extents->width,
- extents->height,
- traps->traps,
- traps->num_traps);
+ if (dst_x != 0 || dst_y != 0)
+ _cairo_traps_translate (info->traps, - dst_x, - dst_y);
+ _cairo_pattern_init_solid (&pattern.solid, CAIRO_COLOR_WHITE);
+ if (!src)
+ src = &pattern.base;
+
+ status = _cairo_surface_composite_trapezoids (operator,
+ src, dst, info->antialias,
+ extents->x, extents->y,
+ extents->x - dst_x, extents->y - dst_y,
+ extents->width, extents->height,
+ info->traps->traps,
+ info->traps->num_traps);
_cairo_pattern_fini (&pattern.base);
return status;
}
+/* Gets the bounding box of a region as a cairo_rectangle_t */
+static void
+_region_rect_extents (pixman_region16_t *region,
+ cairo_rectangle_t *rect)
+{
+ pixman_box16_t *region_extents = pixman_region_extents (region);
+
+ rect->x = region_extents->x1;
+ rect->y = region_extents->y1;
+ rect->width = region_extents->x2 - region_extents->x1;
+ rect->height = region_extents->y2 - region_extents->y1;
+}
+
/* Warning: This call modifies the coordinates of traps */
-static cairo_status_t
-_cairo_gstate_clip_and_composite_trapezoids (cairo_gstate_t *gstate,
- cairo_pattern_t *src,
- cairo_operator_t operator,
- cairo_surface_t *dst,
- cairo_traps_t *traps)
+cairo_status_t
+_cairo_surface_clip_and_composite_trapezoids (cairo_pattern_t *src,
+ cairo_operator_t operator,
+ cairo_surface_t *dst,
+ cairo_traps_t *traps,
+ cairo_clip_t *clip,
+ cairo_antialias_t antialias)
{
cairo_status_t status;
pixman_region16_t *trap_region;
cairo_rectangle_t extents;
+ cairo_composite_traps_info_t traps_info;
if (traps->num_traps == 0)
return CAIRO_STATUS_SUCCESS;
@@ -1380,60 +1306,65 @@ _cairo_gstate_clip_and_composite_trapezoids (cairo_gstate_t *gstate,
if (status)
return status;
- if (trap_region)
- status = _clip_and_compute_extents_region (gstate, trap_region, &extents);
+ if (_cairo_operator_bounded (operator))
+ {
+ if (trap_region) {
+ status = _cairo_clip_intersect_to_region (clip, trap_region);
+ _region_rect_extents (trap_region, &extents);
+ } else {
+ cairo_box_t trap_extents;
+ _cairo_traps_extents (traps, &trap_extents);
+ _cairo_box_round_to_rectangle (&trap_extents, &extents);
+ status = _cairo_clip_intersect_to_rectangle (clip, &extents);
+ }
+ }
else
- status = _clip_and_compute_extents_arbitrary (gstate, traps, &extents);
+ {
+ status = _cairo_surface_get_extents (dst, &extents);
+ if (status)
+ return status;
+ status = _cairo_clip_intersect_to_rectangle (clip, &extents);
+ if (status)
+ return status;
+ }
if (status)
goto out;
- if (_cairo_rectangle_empty (&extents))
- /* Nothing to do */
- goto out;
-
- if (gstate->clip.surface) {
- if (trap_region) {
- /* If we are compositing a set of rectangles, we can set them as the
- * clip region for the destination surface and use the clip surface
- * as the mask. A clip region might not be supported, in which case
- * we fall through to the next method
- */
- status = _composite_trap_region (gstate, src, operator, dst,
- trap_region, &extents);
- if (status != CAIRO_INT_STATUS_UNSUPPORTED)
- goto out;
- }
-
- /* Handle a clip surface by creating an intermediate surface. */
- status = _composite_traps_intermediate_surface (gstate, src, operator,
- dst, traps, &extents);
- } else {
- /* No clip surface */
- if (trap_region && src->type == CAIRO_PATTERN_SOLID) {
- /* Solid rectangles are handled specially */
- status = _composite_trap_region_solid (gstate, (cairo_solid_pattern_t *)src,
+ if (trap_region && _cairo_operator_bounded (operator))
+ {
+ if (src->type == CAIRO_PATTERN_SOLID && !clip->surface)
+ {
+ /* Solid rectangles special case */
+ status = _composite_trap_region_solid (clip, (cairo_solid_pattern_t *)src,
operator, dst, trap_region);
- } else {
- if (trap_region) {
- /* For a simple rectangle, we can just use composite(), for more
- * rectangles, we have to set a clip region. The cost of rasterizing
- * trapezoids is pretty high for most backends currently, so it's
- * worthwhile even if a region is needed.
- */
- status = _composite_trap_region (gstate, src, operator, dst,
- trap_region, &extents);
- if (status != CAIRO_INT_STATUS_UNSUPPORTED)
- goto out;
-
- /* If a clip regions aren't supported, fall through */
- }
-
- status = _composite_traps (gstate, src, operator,
- dst, traps, &extents);
+ goto out;
}
+
+ /* For a simple rectangle, we can just use composite(), for more
+ * rectangles, we have to set a clip region. The cost of rasterizing
+ * trapezoids is pretty high for most backends currently, so it's
+ * worthwhile even if a region is needed.
+ *
+ * If we have a clip surface, we set it as the mask.
+ *
+ * CAIRO_INT_STATUS_UNSUPPORTED will be returned if the region has
+ * more than rectangle and the destination doesn't support clip
+ * regions. In that case, we fall through.
+ */
+ status = _composite_trap_region (clip, src, operator, dst,
+ trap_region, &extents);
+ if (status != CAIRO_INT_STATUS_UNSUPPORTED)
+ goto out;
}
+ traps_info.traps = traps;
+ traps_info.antialias = antialias;
+
+ status = _cairo_gstate_clip_and_composite (clip, operator, src,
+ _composite_traps_draw_func, &traps_info,
+ dst, &extents);
+
out:
if (trap_region)
pixman_region_destroy (trap_region);
@@ -1441,6 +1372,28 @@ _cairo_gstate_clip_and_composite_trapezoids (cairo_gstate_t *gstate,
return status;
}
+/* Warning: This call modifies the coordinates of traps */
+static cairo_status_t
+_cairo_gstate_clip_and_composite_trapezoids (cairo_gstate_t *gstate,
+ cairo_traps_t *traps)
+{
+ cairo_pattern_union_t pattern;
+ cairo_status_t status;
+
+ _cairo_gstate_copy_transformed_source (gstate, &pattern.base);
+
+ status = _cairo_surface_clip_and_composite_trapezoids (&pattern.base,
+ gstate->operator,
+ gstate->target,
+ traps,
+ &gstate->clip,
+ gstate->antialias);
+
+ _cairo_pattern_fini (&pattern.base);
+
+ return status;
+}
+
cairo_status_t
_cairo_gstate_fill (cairo_gstate_t *gstate, cairo_path_fixed_t *path)
{
@@ -1450,7 +1403,7 @@ _cairo_gstate_fill (cairo_gstate_t *gstate, cairo_path_fixed_t *path)
if (gstate->source->status)
return gstate->source->status;
- status = _cairo_gstate_set_clip (gstate);
+ status = _cairo_surface_set_clip (gstate->target, &gstate->clip);
if (status)
return status;
@@ -1466,17 +1419,16 @@ _cairo_gstate_fill (cairo_gstate_t *gstate, cairo_path_fixed_t *path)
_cairo_traps_init (&traps);
- status = _cairo_path_fixed_fill_to_traps (path, gstate, &traps);
+ status = _cairo_path_fixed_fill_to_traps (path,
+ gstate->fill_rule,
+ gstate->tolerance,
+ &traps);
if (status) {
_cairo_traps_fini (&traps);
return status;
}
- _cairo_gstate_clip_and_composite_trapezoids (gstate,
- gstate->source,
- gstate->operator,
- gstate->target,
- &traps);
+ _cairo_gstate_clip_and_composite_trapezoids (gstate, &traps);
_cairo_traps_fini (&traps);
@@ -1497,7 +1449,10 @@ _cairo_gstate_in_fill (cairo_gstate_t *gstate,
_cairo_traps_init (&traps);
- status = _cairo_path_fixed_fill_to_traps (path, gstate, &traps);
+ status = _cairo_path_fixed_fill_to_traps (path,
+ gstate->fill_rule,
+ gstate->tolerance,
+ &traps);
if (status)
goto BAIL;
@@ -1567,7 +1522,10 @@ _cairo_gstate_fill_extents (cairo_gstate_t *gstate,
_cairo_traps_init (&traps);
- status = _cairo_path_fixed_fill_to_traps (path, gstate, &traps);
+ status = _cairo_path_fixed_fill_to_traps (path,
+ gstate->fill_rule,
+ gstate->tolerance,
+ &traps);
if (status)
goto BAIL;
@@ -1590,226 +1548,19 @@ BAIL:
cairo_status_t
_cairo_gstate_reset_clip (cairo_gstate_t *gstate)
{
- /* destroy any existing clip-region artifacts */
- if (gstate->clip.surface)
- cairo_surface_destroy (gstate->clip.surface);
- gstate->clip.surface = NULL;
-
- if (gstate->clip.region)
- pixman_region_destroy (gstate->clip.region);
- gstate->clip.region = NULL;
-
- if (gstate->clip.path)
- _cairo_clip_path_destroy (gstate->clip.path);
- gstate->clip.path = NULL;
-
- gstate->clip.serial = 0;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
-_cairo_gstate_intersect_clip_path (cairo_gstate_t *gstate,
- cairo_path_fixed_t *path)
-{
- cairo_clip_path_t *clip_path;
- cairo_status_t status;
-
- if (gstate->clip.mode != CAIRO_CLIP_MODE_PATH)
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- clip_path = malloc (sizeof (cairo_clip_path_t));
- if (clip_path == NULL)
- return CAIRO_STATUS_NO_MEMORY;
-
- status = _cairo_path_fixed_init_copy (&clip_path->path, path);
- if (status)
- return status;
-
- clip_path->ref_count = 1;
- clip_path->fill_rule = gstate->fill_rule;
- clip_path->tolerance = gstate->tolerance;
- clip_path->prev = gstate->clip.path;
- gstate->clip.path = clip_path;
- gstate->clip.serial = _cairo_surface_allocate_clip_serial (gstate->target);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static void
-_cairo_clip_path_reference (cairo_clip_path_t *clip_path)
-{
- if (clip_path == NULL)
- return;
-
- clip_path->ref_count++;
-}
-
-static void
-_cairo_clip_path_destroy (cairo_clip_path_t *clip_path)
-{
- if (clip_path == NULL)
- return;
-
- clip_path->ref_count--;
- if (clip_path->ref_count)
- return;
-
- _cairo_path_fixed_fini (&clip_path->path);
- _cairo_clip_path_destroy (clip_path->prev);
- free (clip_path);
-}
-
-static cairo_status_t
-_cairo_gstate_intersect_clip_region (cairo_gstate_t *gstate,
- cairo_traps_t *traps)
-{
- pixman_region16_t *region;
- cairo_status_t status;
-
- if (gstate->clip.mode != CAIRO_CLIP_MODE_REGION)
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- status = _cairo_traps_extract_region (traps, &region);
- if (status)
- return status;
-
- if (region == NULL)
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- status = CAIRO_STATUS_SUCCESS;
- if (gstate->clip.region == NULL) {
- gstate->clip.region = region;
- } else {
- pixman_region16_t *intersection = pixman_region_create();
-
- if (pixman_region_intersect (intersection,
- gstate->clip.region, region)
- == PIXMAN_REGION_STATUS_SUCCESS) {
- pixman_region_destroy (gstate->clip.region);
- gstate->clip.region = intersection;
- } else {
- status = CAIRO_STATUS_NO_MEMORY;
- }
- pixman_region_destroy (region);
- }
- gstate->clip.serial = _cairo_surface_allocate_clip_serial (gstate->target);
- return status;
-}
-
-static cairo_status_t
-_cairo_gstate_intersect_clip_mask (cairo_gstate_t *gstate,
- cairo_traps_t *traps)
-{
- cairo_pattern_union_t pattern;
- cairo_box_t extents;
- cairo_rectangle_t surface_rect;
- cairo_surface_t *surface;
- cairo_status_t status;
-
- /* Represent the clip as a mask surface. We create a new surface
- * the size of the intersection of the old mask surface and the
- * extents of the new clip path. */
-
- _cairo_traps_extents (traps, &extents);
- _cairo_box_round_to_rectangle (&extents, &surface_rect);
-
- if (gstate->clip.surface != NULL)
- _cairo_rectangle_intersect (&surface_rect, &gstate->clip.surface_rect);
-
- surface = _cairo_surface_create_similar_solid (gstate->target,
- CAIRO_CONTENT_ALPHA,
- surface_rect.width,
- surface_rect.height,
- CAIRO_COLOR_WHITE);
- if (surface->status)
- return CAIRO_STATUS_NO_MEMORY;
-
- /* Render the new clipping path into the new mask surface. */
-
- translate_traps (traps, -surface_rect.x, -surface_rect.y);
- _cairo_pattern_init_solid (&pattern.solid, CAIRO_COLOR_WHITE);
-
- status = _cairo_surface_composite_trapezoids (CAIRO_OPERATOR_IN,
- &pattern.base,
- surface,
- 0, 0,
- 0, 0,
- surface_rect.width,
- surface_rect.height,
- traps->traps,
- traps->num_traps);
-
- _cairo_pattern_fini (&pattern.base);
-
- if (status) {
- cairo_surface_destroy (surface);
- return status;
- }
-
- /* If there was a clip surface already, combine it with the new
- * mask surface using the IN operator, so we get the intersection
- * of the old and new clipping paths. */
-
- if (gstate->clip.surface != NULL) {
- _cairo_pattern_init_for_surface (&pattern.surface, gstate->clip.surface);
-
- status = _cairo_surface_composite (CAIRO_OPERATOR_IN,
- &pattern.base,
- NULL,
- surface,
- surface_rect.x - gstate->clip.surface_rect.x,
- surface_rect.y - gstate->clip.surface_rect.y,
- 0, 0,
- 0, 0,
- surface_rect.width,
- surface_rect.height);
-
- _cairo_pattern_fini (&pattern.base);
-
- if (status) {
- cairo_surface_destroy (surface);
- return status;
- }
-
- cairo_surface_destroy (gstate->clip.surface);
- }
-
- gstate->clip.surface = surface;
- gstate->clip.surface_rect = surface_rect;
-
- return status;
+ return _cairo_clip_reset (&gstate->clip);
}
cairo_status_t
_cairo_gstate_clip (cairo_gstate_t *gstate, cairo_path_fixed_t *path)
{
- cairo_status_t status;
- cairo_traps_t traps;
-
- status = _cairo_gstate_intersect_clip_path (gstate, path);
- if (status != CAIRO_INT_STATUS_UNSUPPORTED)
- return status;
-
- _cairo_traps_init (&traps);
- status = _cairo_path_fixed_fill_to_traps (path, gstate, &traps);
- if (status)
- goto bail;
-
- status = _cairo_gstate_intersect_clip_region (gstate, &traps);
- if (status != CAIRO_INT_STATUS_UNSUPPORTED)
- goto bail;
-
- status = _cairo_gstate_intersect_clip_mask (gstate, &traps);
-
- bail:
- _cairo_traps_fini (&traps);
-
- return status;
+ return _cairo_clip_clip (&gstate->clip,
+ path, gstate->fill_rule, gstate->tolerance,
+ gstate->antialias, gstate->target);
}
static void
-_cairo_gstate_unset_font (cairo_gstate_t *gstate)
+_cairo_gstate_unset_scaled_font (cairo_gstate_t *gstate)
{
if (gstate->scaled_font) {
cairo_scaled_font_destroy (gstate->scaled_font);
@@ -1825,7 +1576,7 @@ _cairo_gstate_select_font_face (cairo_gstate_t *gstate,
{
cairo_font_face_t *font_face;
- font_face = _cairo_simple_font_face_create (family, slant, weight);
+ font_face = _cairo_toy_font_face_create (family, slant, weight);
if (font_face->status)
return font_face->status;
@@ -1839,7 +1590,7 @@ cairo_status_t
_cairo_gstate_set_font_size (cairo_gstate_t *gstate,
double size)
{
- _cairo_gstate_unset_font (gstate);
+ _cairo_gstate_unset_scaled_font (gstate);
cairo_matrix_init_scale (&gstate->font_matrix, size, size);
@@ -1850,7 +1601,7 @@ cairo_status_t
_cairo_gstate_set_font_matrix (cairo_gstate_t *gstate,
const cairo_matrix_t *matrix)
{
- _cairo_gstate_unset_font (gstate);
+ _cairo_gstate_unset_scaled_font (gstate);
gstate->font_matrix = *matrix;
@@ -1868,7 +1619,7 @@ cairo_status_t
_cairo_gstate_set_font_options (cairo_gstate_t *gstate,
const cairo_font_options_t *options)
{
- _cairo_gstate_unset_font (gstate);
+ _cairo_gstate_unset_scaled_font (gstate);
gstate->font_options = *options;
@@ -1979,9 +1730,9 @@ _cairo_gstate_ensure_font_face (cairo_gstate_t *gstate)
if (!gstate->font_face) {
cairo_font_face_t *font_face;
- font_face = _cairo_simple_font_face_create (CAIRO_FONT_FAMILY_DEFAULT,
- CAIRO_FONT_SLANT_DEFAULT,
- CAIRO_FONT_WEIGHT_DEFAULT);
+ font_face = _cairo_toy_font_face_create (CAIRO_FONT_FAMILY_DEFAULT,
+ CAIRO_FONT_SLANT_DEFAULT,
+ CAIRO_FONT_WEIGHT_DEFAULT);
if (font_face->status)
return font_face->status;
else
@@ -1992,7 +1743,7 @@ _cairo_gstate_ensure_font_face (cairo_gstate_t *gstate)
}
static cairo_status_t
-_cairo_gstate_ensure_font (cairo_gstate_t *gstate)
+_cairo_gstate_ensure_scaled_font (cairo_gstate_t *gstate)
{
cairo_status_t status;
cairo_font_options_t options;
@@ -2022,7 +1773,7 @@ cairo_status_t
_cairo_gstate_get_font_extents (cairo_gstate_t *gstate,
cairo_font_extents_t *extents)
{
- cairo_status_t status = _cairo_gstate_ensure_font (gstate);
+ cairo_status_t status = _cairo_gstate_ensure_scaled_font (gstate);
if (status)
return status;
@@ -2042,7 +1793,7 @@ _cairo_gstate_text_to_glyphs (cairo_gstate_t *gstate,
cairo_status_t status;
int i;
- status = _cairo_gstate_ensure_font (gstate);
+ status = _cairo_gstate_ensure_scaled_font (gstate);
if (status)
return status;
@@ -2071,18 +1822,15 @@ cairo_status_t
_cairo_gstate_set_font_face (cairo_gstate_t *gstate,
cairo_font_face_t *font_face)
{
- if (font_face->status)
+ if (font_face && font_face->status)
return font_face->status;
if (font_face != gstate->font_face) {
- if (gstate->font_face)
- cairo_font_face_destroy (gstate->font_face);
- gstate->font_face = font_face;
- if (gstate->font_face)
- cairo_font_face_reference (gstate->font_face);
+ cairo_font_face_destroy (gstate->font_face);
+ gstate->font_face = cairo_font_face_reference (font_face);
}
- _cairo_gstate_unset_font (gstate);
+ _cairo_gstate_unset_scaled_font (gstate);
return CAIRO_STATUS_SUCCESS;
}
@@ -2095,7 +1843,7 @@ _cairo_gstate_glyph_extents (cairo_gstate_t *gstate,
{
cairo_status_t status;
- status = _cairo_gstate_ensure_font (gstate);
+ status = _cairo_gstate_ensure_scaled_font (gstate);
if (status)
return status;
@@ -2106,6 +1854,58 @@ _cairo_gstate_glyph_extents (cairo_gstate_t *gstate,
return CAIRO_STATUS_SUCCESS;
}
+typedef struct {
+ cairo_scaled_font_t *font;
+ cairo_glyph_t *glyphs;
+ int num_glyphs;
+} cairo_show_glyphs_info_t;
+
+static cairo_status_t
+_cairo_gstate_show_glyphs_draw_func (void *closure,
+ cairo_operator_t operator,
+ cairo_pattern_t *src,
+ cairo_surface_t *dst,
+ int dst_x,
+ int dst_y,
+ const cairo_rectangle_t *extents)
+{
+ cairo_show_glyphs_info_t *glyph_info = closure;
+ cairo_pattern_union_t pattern;
+ cairo_status_t status;
+
+ /* Modifying the glyph array is fine because we know that this function
+ * will be called only once, and we've already made a copy of the
+ * glyphs in the wrapper.
+ */
+ if (dst_x != 0 || dst_y != 0) {
+ int i;
+
+ for (i = 0; i < glyph_info->num_glyphs; ++i)
+ {
+ glyph_info->glyphs[i].x -= dst_x;
+ glyph_info->glyphs[i].y -= dst_y;
+ }
+ }
+
+ _cairo_pattern_init_solid (&pattern.solid, CAIRO_COLOR_WHITE);
+ if (!src)
+ src = &pattern.base;
+
+ status = _cairo_scaled_font_show_glyphs (glyph_info->font,
+ operator,
+ src, dst,
+ extents->x, extents->y,
+ extents->x - dst_x, extents->y - dst_y,
+ extents->width, extents->height,
+ glyph_info->glyphs,
+ glyph_info->num_glyphs);
+
+ if (src == &pattern.base)
+ _cairo_pattern_fini (&pattern.base);
+
+ return status;
+}
+
cairo_status_t
_cairo_gstate_show_glyphs (cairo_gstate_t *gstate,
cairo_glyph_t *glyphs,
@@ -2117,15 +1917,16 @@ _cairo_gstate_show_glyphs (cairo_gstate_t *gstate,
cairo_pattern_union_t pattern;
cairo_box_t bbox;
cairo_rectangle_t extents;
+ cairo_show_glyphs_info_t glyph_info;
if (gstate->source->status)
return gstate->source->status;
- status = _cairo_gstate_set_clip (gstate);
+ status = _cairo_surface_set_clip (gstate->target, &gstate->clip);
if (status)
return status;
- status = _cairo_gstate_ensure_font (gstate);
+ status = _cairo_gstate_ensure_scaled_font (gstate);
if (status)
return status;
@@ -2140,113 +1941,41 @@ _cairo_gstate_show_glyphs (cairo_gstate_t *gstate,
&transformed_glyphs[i].x,
&transformed_glyphs[i].y);
}
-
- status = _cairo_scaled_font_glyph_bbox (gstate->scaled_font,
- transformed_glyphs, num_glyphs,
- &bbox);
- _cairo_box_round_to_rectangle (&bbox, &extents);
- if (status)
- goto CLEANUP_GLYPHS;
-
- if (gstate->clip.surface)
+ if (_cairo_operator_bounded (gstate->operator))
{
- cairo_surface_t *intermediate;
- cairo_surface_pattern_t intermediate_pattern;
-
- _cairo_rectangle_intersect (&extents, &gstate->clip.surface_rect);
-
- /* Shortcut if empty */
- if (_cairo_rectangle_empty (&extents)) {
- status = CAIRO_STATUS_SUCCESS;
- goto BAIL1;
- }
-
- intermediate = _cairo_surface_create_similar_solid (gstate->clip.surface,
- CAIRO_CONTENT_ALPHA,
- extents.width,
- extents.height,
- CAIRO_COLOR_TRANSPARENT);
- if (intermediate->status) {
- status = CAIRO_STATUS_NO_MEMORY;
- goto BAIL1;
- }
-
- /* move the glyphs again, from dev space to intermediate space */
- for (i = 0; i < num_glyphs; ++i)
- {
- transformed_glyphs[i].x -= extents.x;
- transformed_glyphs[i].y -= extents.y;
- }
-
- _cairo_pattern_init_solid (&pattern.solid, CAIRO_COLOR_WHITE);
-
- status = _cairo_scaled_font_show_glyphs (gstate->scaled_font,
- CAIRO_OPERATOR_ADD,
- &pattern.base, intermediate,
- extents.x, extents.y,
- 0, 0,
- extents.width, extents.height,
- transformed_glyphs, num_glyphs);
-
- _cairo_pattern_fini (&pattern.base);
-
+ status = _cairo_scaled_font_glyph_bbox (gstate->scaled_font,
+ transformed_glyphs, num_glyphs,
+ &bbox);
if (status)
- goto BAIL2;
-
- _cairo_pattern_init_for_surface (&pattern.surface,
- gstate->clip.surface);
-
- status = _cairo_surface_composite (CAIRO_OPERATOR_IN,
- &pattern.base,
- NULL,
- intermediate,
- extents.x - gstate->clip.surface_rect.x,
- extents.y - gstate->clip.surface_rect.y,
- 0, 0,
- 0, 0,
- extents.width, extents.height);
-
- _cairo_pattern_fini (&pattern.base);
-
- if (status)
- goto BAIL2;
-
- _cairo_pattern_init_for_surface (&intermediate_pattern, intermediate);
- _cairo_pattern_init_copy (&pattern.base, gstate->source);
- _cairo_gstate_pattern_transform (gstate, &pattern.base);
-
- status = _cairo_surface_composite (gstate->operator,
- &pattern.base,
- &intermediate_pattern.base,
- gstate->target,
- extents.x, extents.y,
- 0, 0,
- extents.x, extents.y,
- extents.width, extents.height);
- _cairo_pattern_fini (&pattern.base);
- _cairo_pattern_fini (&intermediate_pattern.base);
-
- BAIL2:
- cairo_surface_destroy (intermediate);
- BAIL1:
- ;
+ goto CLEANUP_GLYPHS;
+
+ _cairo_box_round_to_rectangle (&bbox, &extents);
}
else
{
- _cairo_pattern_init_copy (&pattern.base, gstate->source);
- _cairo_gstate_pattern_transform (gstate, &pattern.base);
+ status = _cairo_surface_get_extents (gstate->target, &extents);
+ if (status)
+ goto CLEANUP_GLYPHS;
+ }
+
+ status = _cairo_clip_intersect_to_rectangle (&gstate->clip, &extents);
+ if (status)
+ goto CLEANUP_GLYPHS;
+
+ _cairo_gstate_copy_transformed_source (gstate, &pattern.base);
- status = _cairo_scaled_font_show_glyphs (gstate->scaled_font,
- gstate->operator, &pattern.base,
- gstate->target,
- extents.x, extents.y,
- extents.x, extents.y,
- extents.width, extents.height,
- transformed_glyphs, num_glyphs);
+ glyph_info.font = gstate->scaled_font;
+ glyph_info.glyphs = transformed_glyphs;
+ glyph_info.num_glyphs = num_glyphs;
+
+ status = _cairo_gstate_clip_and_composite (&gstate->clip, gstate->operator,
+ &pattern.base,
+ _cairo_gstate_show_glyphs_draw_func, &glyph_info,
+ gstate->target,
+ &extents);
- _cairo_pattern_fini (&pattern.base);
- }
+ _cairo_pattern_fini (&pattern.base);
CLEANUP_GLYPHS:
free (transformed_glyphs);
@@ -2264,7 +1993,7 @@ _cairo_gstate_glyph_path (cairo_gstate_t *gstate,
int i;
cairo_glyph_t *transformed_glyphs = NULL;
- status = _cairo_gstate_ensure_font (gstate);
+ status = _cairo_gstate_ensure_scaled_font (gstate);
if (status)
return status;
@@ -2287,3 +2016,19 @@ _cairo_gstate_glyph_path (cairo_gstate_t *gstate,
free (transformed_glyphs);
return status;
}
+
+cairo_private cairo_status_t
+_cairo_gstate_set_antialias (cairo_gstate_t *gstate,
+ cairo_antialias_t antialias)
+{
+ gstate->antialias = antialias;
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+cairo_private cairo_antialias_t
+_cairo_gstate_get_antialias (cairo_gstate_t *gstate)
+{
+ return gstate->antialias;
+}
+