summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorKristian Høgsberg <krh@redhat.com>2005-08-04 22:45:59 +0000
committerKristian Høgsberg <krh@redhat.com>2005-08-04 22:45:59 +0000
commitebf985c87688f090c27c3906a6b441522b2f702a (patch)
tree4ed92acbdfb22a6c1204d77bb0761923ace5a4b6 /src
parent27573750eb9f2655d0b4cb5640a9f3f6c1316bc0 (diff)
New files. Move code for manipulating cairo_clip_t out into cairo_clip_* functions and put them in cairo-clip.c.
Rewrite to use new cairo_clip_t functions for manipulating the clip state, change the clip_and_composite_trapezoids call tree to use cairo_clip_t instead of cairo_gstate_t. Use new cairo_clip_t function to maintain clip state while replaying. Pass fill rule and tolerance directly, to break gstate dependency. New function. Set the clip for a surface as specified by the cairo_clip_t. Move translate_traps() from cairo-gstate.c to here and rename it. Reviewed by: otaylor
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am2
-rw-r--r--src/cairo-clip-private.h118
-rw-r--r--src/cairo-clip.c457
-rw-r--r--src/cairo-gstate-private.h41
-rw-r--r--src/cairo-gstate.c637
-rw-r--r--src/cairo-meta-surface.c132
-rw-r--r--src/cairo-path-fill.c20
-rw-r--r--src/cairo-surface.c23
-rw-r--r--src/cairo-traps.c29
-rw-r--r--src/cairoint.h35
10 files changed, 820 insertions, 674 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 4456bdc9..b518392e 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -92,6 +92,8 @@ libcairo_la_SOURCES = \
cairo-font-options.c \
cairo-gstate.c \
cairo-gstate-private.h \
+ cairo-clip.c \
+ cairo-clip-private.h \
cairo-hull.c \
cairo-image-surface.c \
cairo-matrix.c \
diff --git a/src/cairo-clip-private.h b/src/cairo-clip-private.h
new file mode 100644
index 00000000..f8846b5c
--- /dev/null
+++ b/src/cairo-clip-private.h
@@ -0,0 +1,118 @@
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2005 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it either under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * (the "LGPL") or, at your option, under the terms of the Mozilla
+ * Public License Version 1.1 (the "MPL"). If you do not alter this
+ * notice, a recipient may use your version of this file under either
+ * the MPL or the LGPL.
+ *
+ * You should have received a copy of the LGPL along with this library
+ * in the file COPYING-LGPL-2.1; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ *
+ * The Original Code is the cairo graphics library.
+ *
+ * The Initial Developer of the Original Code is Red Hat, Inc.
+ *
+ * Contributor(s):
+ * Kristian Høgsberg <krh@redhat.com>
+ */
+
+#ifndef CAIRO_CLIP_PRIVATE_H
+#define CAIRO_CLIP_PRIVATE_H
+
+#include "cairo-path-fixed-private.h"
+
+enum _cairo_clip_mode {
+ CAIRO_CLIP_MODE_PATH,
+ CAIRO_CLIP_MODE_REGION,
+ CAIRO_CLIP_MODE_MASK
+};
+
+struct _cairo_clip_path {
+ unsigned int ref_count;
+ cairo_path_fixed_t path;
+ cairo_fill_rule_t fill_rule;
+ double tolerance;
+ cairo_clip_path_t *prev;
+};
+
+struct _cairo_clip {
+ cairo_clip_mode_t mode;
+
+ /*
+ * Mask-based clipping for cases where the backend
+ * clipping isn't sufficiently able.
+ *
+ * The rectangle here represents the
+ * portion of the destination surface that this
+ * clip surface maps to, it does not
+ * represent the extents of the clip region or
+ * clip paths
+ */
+ cairo_surface_t *surface;
+ cairo_rectangle_t surface_rect;
+ /*
+ * Surface clip serial number to store
+ * in the surface when this clip is set
+ */
+ unsigned int serial;
+ /*
+ * A clip region that can be placed in the surface
+ */
+ pixman_region16_t *region;
+ /*
+ * If the surface supports path clipping, we store the list of
+ * clipping paths that has been set here as a linked list.
+ */
+ cairo_clip_path_t *path;
+};
+
+cairo_private void
+_cairo_clip_init (cairo_clip_t *clip, cairo_surface_t *target);
+
+cairo_private void
+_cairo_clip_fini (cairo_clip_t *clip);
+
+cairo_private void
+_cairo_clip_init_copy (cairo_clip_t *clip, cairo_clip_t *other);
+
+cairo_private cairo_status_t
+_cairo_clip_reset (cairo_clip_t *clip);
+
+cairo_private cairo_status_t
+_cairo_clip_clip (cairo_clip_t *clip,
+ cairo_path_fixed_t *path,
+ cairo_fill_rule_t fill_rule,
+ double tolerance,
+ cairo_surface_t *target);
+
+cairo_private cairo_status_t
+_cairo_clip_intersect_to_rectangle (cairo_clip_t *clip,
+ cairo_rectangle_t *rectangle);
+
+cairo_private cairo_status_t
+_cairo_clip_intersect_to_region (cairo_clip_t *clip,
+ pixman_region16_t *region);
+
+cairo_private cairo_status_t
+_cairo_clip_combine_to_surface (cairo_clip_t *clip,
+ cairo_surface_t *intermediate,
+ cairo_rectangle_t *extents);
+
+#endif /* CAIRO_CLIP_PRIVATE_H */
diff --git a/src/cairo-clip.c b/src/cairo-clip.c
new file mode 100644
index 00000000..c211e2b8
--- /dev/null
+++ b/src/cairo-clip.c
@@ -0,0 +1,457 @@
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2002 University of Southern California
+ * Copyright © 2005 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it either under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * (the "LGPL") or, at your option, under the terms of the Mozilla
+ * Public License Version 1.1 (the "MPL"). If you do not alter this
+ * notice, a recipient may use your version of this file under either
+ * the MPL or the LGPL.
+ *
+ * You should have received a copy of the LGPL along with this library
+ * in the file COPYING-LGPL-2.1; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ *
+ * The Original Code is the cairo graphics library.
+ *
+ * The Initial Developer of the Original Code is University of Southern
+ * California.
+ *
+ * Contributor(s):
+ * Carl D. Worth <cworth@cworth.org>
+ * Kristian Høgsberg <krh@redhat.com>
+ */
+
+#include "cairoint.h"
+#include "cairo-clip-private.h"
+
+static cairo_clip_path_t *
+_cairo_clip_path_reference (cairo_clip_path_t *clip_path);
+
+static void
+_cairo_clip_path_destroy (cairo_clip_path_t *clip_path);
+
+/* Creates a region from a cairo_rectangle_t */
+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);
+ return CAIRO_STATUS_NO_MEMORY;
+ }
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+/* 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;
+}
+
+void
+_cairo_clip_init (cairo_clip_t *clip, cairo_surface_t *target)
+{
+ clip->mode = _cairo_surface_get_clip_mode (target);
+ clip->region = NULL;
+ clip->surface = NULL;
+ clip->serial = 0;
+ clip->path = NULL;
+}
+
+void
+_cairo_clip_fini (cairo_clip_t *clip)
+{
+ if (clip->surface)
+ cairo_surface_destroy (clip->surface);
+ clip->surface = NULL;
+
+ if (clip->path)
+ _cairo_clip_path_destroy (clip->path);
+ clip->path = NULL;
+
+ if (clip->region)
+ pixman_region_destroy (clip->region);
+ clip->region = NULL;
+ clip->serial = 0;
+}
+
+void
+_cairo_clip_init_copy (cairo_clip_t *clip, cairo_clip_t *other)
+{
+ if (other->region) {
+ clip->region = pixman_region_create ();
+ pixman_region_copy (clip->region, other->region);
+ }
+
+ cairo_surface_reference (other->surface);
+ clip->surface = other->surface;
+ _cairo_clip_path_reference (other->path);
+ clip->path = other->path;
+}
+
+cairo_status_t
+_cairo_clip_reset (cairo_clip_t *clip)
+{
+ /* destroy any existing clip-region artifacts */
+ if (clip->surface)
+ cairo_surface_destroy (clip->surface);
+ clip->surface = NULL;
+
+ if (clip->region)
+ pixman_region_destroy (clip->region);
+ clip->region = NULL;
+
+ if (clip->path)
+ _cairo_clip_path_destroy (clip->path);
+ clip->path = NULL;
+
+ clip->serial = 0;
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+cairo_status_t
+_cairo_clip_intersect_to_rectangle (cairo_clip_t *clip,
+ cairo_rectangle_t *rectangle)
+{
+ if (clip->path) {
+ /* Intersect path extents here. */
+ }
+
+ if (clip->region) {
+ pixman_region16_t *intersection;
+ cairo_status_t status;
+ pixman_region_status_t pixman_status;
+
+ status = _region_new_from_rect (rectangle, &intersection);
+ if (status)
+ return status;
+
+ pixman_status = pixman_region_intersect (intersection,
+ clip->region,
+ intersection);
+ if (pixman_status == PIXMAN_REGION_STATUS_SUCCESS)
+ _region_rect_extents (intersection, rectangle);
+ else
+ status = CAIRO_STATUS_NO_MEMORY;
+
+ pixman_region_destroy (intersection);
+
+ if (status)
+ return status;
+ }
+
+ if (clip->surface)
+ _cairo_rectangle_intersect (rectangle, &clip->surface_rect);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+cairo_status_t
+_cairo_clip_intersect_to_region (cairo_clip_t *clip,
+ pixman_region16_t *region)
+{
+ if (clip->path) {
+ /* Intersect clip path into region. */
+ }
+
+ if (clip->region)
+ pixman_region_intersect (region, clip->region, region);
+
+ if (clip->surface) {
+ pixman_region16_t *clip_rect;
+ pixman_region_status_t pixman_status;
+ cairo_status_t status;
+
+ status = _region_new_from_rect (&clip->surface_rect, &clip_rect);
+ if (status)
+ return status;
+
+ pixman_status = pixman_region_intersect (region,
+ clip_rect,
+ region);
+ if (pixman_status != PIXMAN_REGION_STATUS_SUCCESS)
+ status = CAIRO_STATUS_NO_MEMORY;
+
+ pixman_region_destroy (clip_rect);
+
+ if (status)
+ return status;
+ }
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+/* Combines clip->surface using the IN operator with the given
+ * intermediate surface, which corresponds to the rectangle of the
+ * destination space given by @extents.
+ */
+cairo_status_t
+_cairo_clip_combine_to_surface (cairo_clip_t *clip,
+ cairo_surface_t *intermediate,
+ cairo_rectangle_t *extents)
+{
+ cairo_pattern_union_t pattern;
+ cairo_status_t status;
+
+ _cairo_pattern_init_for_surface (&pattern.surface, clip->surface);
+
+ status = _cairo_surface_composite (CAIRO_OPERATOR_IN,
+ &pattern.base,
+ NULL,
+ intermediate,
+ extents->x - clip->surface_rect.x,
+ extents->y - clip->surface_rect.y,
+ 0, 0,
+ 0, 0,
+ extents->width, extents->height);
+
+ _cairo_pattern_fini (&pattern.base);
+
+ return status;
+}
+
+static cairo_status_t
+_cairo_clip_intersect_path (cairo_clip_t *clip,
+ cairo_path_fixed_t *path,
+ cairo_fill_rule_t fill_rule,
+ double tolerance,
+ cairo_surface_t *target)
+{
+ cairo_clip_path_t *clip_path;
+ cairo_status_t status;
+
+ if (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 = fill_rule;
+ clip_path->tolerance = tolerance;
+ clip_path->prev = clip->path;
+ clip->path = clip_path;
+ clip->serial = _cairo_surface_allocate_clip_serial (target);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_clip_path_t *
+_cairo_clip_path_reference (cairo_clip_path_t *clip_path)
+{
+ if (clip_path == NULL)
+ return NULL;
+
+ clip_path->ref_count++;
+
+ return clip_path;
+}
+
+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_clip_intersect_region (cairo_clip_t *clip,
+ cairo_traps_t *traps,
+ cairo_surface_t *target)
+{
+ pixman_region16_t *region;
+ cairo_status_t status;
+
+ if (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 (clip->region == NULL) {
+ clip->region = region;
+ } else {
+ pixman_region16_t *intersection = pixman_region_create();
+
+ if (pixman_region_intersect (intersection,
+ clip->region, region)
+ == PIXMAN_REGION_STATUS_SUCCESS) {
+ pixman_region_destroy (clip->region);
+ clip->region = intersection;
+ } else {
+ status = CAIRO_STATUS_NO_MEMORY;
+ }
+ pixman_region_destroy (region);
+ }
+
+ clip->serial = _cairo_surface_allocate_clip_serial (target);
+
+ return status;
+}
+
+static cairo_status_t
+_cairo_clip_intersect_mask (cairo_clip_t *clip,
+ cairo_traps_t *traps,
+ cairo_surface_t *target)
+{
+ 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 (clip->surface != NULL)
+ _cairo_rectangle_intersect (&surface_rect, &clip->surface_rect);
+
+ surface = _cairo_surface_create_similar_solid (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. */
+
+ _cairo_traps_translate (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 (clip->surface != NULL) {
+ _cairo_pattern_init_for_surface (&pattern.surface, clip->surface);
+
+ status = _cairo_surface_composite (CAIRO_OPERATOR_IN,
+ &pattern.base,
+ NULL,
+ surface,
+ surface_rect.x - clip->surface_rect.x,
+ surface_rect.y - 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 (clip->surface);
+ }
+
+ clip->surface = surface;
+ clip->surface_rect = surface_rect;
+ clip->serial = _cairo_surface_allocate_clip_serial (target);
+
+ return status;
+}
+
+cairo_status_t
+_cairo_clip_clip (cairo_clip_t *clip,
+ cairo_path_fixed_t *path,
+ cairo_fill_rule_t fill_rule,
+ double tolerance,
+ cairo_surface_t *target)
+{
+ cairo_status_t status;
+ cairo_traps_t traps;
+
+ status = _cairo_clip_intersect_path (clip,
+ path, fill_rule, tolerance,
+ target);
+ if (status != CAIRO_INT_STATUS_UNSUPPORTED)
+ return status;
+
+ _cairo_traps_init (&traps);
+ status = _cairo_path_fixed_fill_to_traps (path,
+ fill_rule,
+ tolerance,
+ &traps);
+ if (status)
+ goto bail;
+
+ status = _cairo_clip_intersect_region (clip, &traps, target);
+ if (status != CAIRO_INT_STATUS_UNSUPPORTED)
+ goto bail;
+
+ status = _cairo_clip_intersect_mask (clip, &traps, target);
+
+ bail:
+ _cairo_traps_fini (&traps);
+
+ return status;
+}
diff --git a/src/cairo-gstate-private.h b/src/cairo-gstate-private.h
index 06352576..7e82883d 100644
--- a/src/cairo-gstate-private.h
+++ b/src/cairo-gstate-private.h
@@ -36,46 +36,7 @@
#ifndef CAIRO_GSTATE_PRIVATE_H
#define CAIRO_GSTATE_PRIVATE_H
-#include "cairo-path-fixed-private.h"
-
-struct _cairo_clip_path {
- unsigned int ref_count;
- cairo_path_fixed_t path;
- cairo_fill_rule_t fill_rule;
- double tolerance;
- cairo_clip_path_t *prev;
-};
-
-typedef struct _cairo_clip {
- cairo_clip_mode_t mode;
-
- /*
- * Mask-based clipping for cases where the backend
- * clipping isn't sufficiently able.
- *
- * The rectangle here represents the
- * portion of the destination surface that this
- * clip surface maps to, it does not
- * represent the extents of the clip region or
- * clip paths
- */
- cairo_surface_t *surface;
- cairo_rectangle_t surface_rect;
- /*
- * Surface clip serial number to store
- * in the surface when this clip is set
- */
- unsigned int serial;
- /*
- * A clip region that can be placed in the surface
- */
- pixman_region16_t *region;
- /*
- * If the surface supports path clipping, we store the list of
- * clipping paths that has been set here as a linked list.
- */
- cairo_clip_path_t *path;
-} cairo_clip_t;
+#include "cairo-clip-private.h"
struct _cairo_gstate {
cairo_operator_t operator;
diff --git a/src/cairo-gstate.c b/src/cairo-gstate.c
index 8db78505..f38d76ca 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
@@ -64,15 +65,6 @@ _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 cairo_clip_path_t *
-_cairo_clip_path_reference (cairo_clip_path_t *clip_path);
-
-static void
-_cairo_clip_path_destroy (cairo_clip_path_t *clip_path);
-
cairo_gstate_t *
_cairo_gstate_create (cairo_surface_t *target)
{
@@ -121,11 +113,7 @@ _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);
@@ -162,10 +150,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);
@@ -174,8 +159,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);
@@ -209,18 +192,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);
@@ -340,61 +312,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)
{
@@ -762,11 +679,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;
@@ -785,108 +705,23 @@ _cairo_gstate_paint (cairo_gstate_t *gstate)
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.
- */
-static cairo_status_t
-_cairo_gstate_combine_clip_surface (cairo_gstate_t *gstate,
- cairo_surface_t *intermediate,
- cairo_rectangle_t *extents)
-{
- cairo_pattern_union_t pattern;
- cairo_status_t status;
-
- _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);
-
- return status;
-}
-
-/* Creates a region from a cairo_rectangle_t */
-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);
- return CAIRO_STATUS_NO_MEMORY;
- }
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-/* 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;
-}
-
-/* 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 (gstate->clip.surface) {
- pixman_region16_t *clip_rect;
- cairo_status_t status;
-
- 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;
-
- pixman_region_destroy (clip_rect);
-
- if (status)
- return status;
- }
-
- return CAIRO_STATUS_SUCCESS;
-}
-
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,
* 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);
}
cairo_status_t
@@ -906,7 +741,7 @@ _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;
@@ -936,7 +771,7 @@ _cairo_gstate_mask (cairo_gstate_t *gstate,
return status;
}
- status = _cairo_gstate_combine_clip_surface (gstate, intermediate, &extents);
+ status = _cairo_clip_combine_to_surface (&gstate->clip, intermediate, &extents);
if (status) {
cairo_surface_destroy (intermediate);
return status;
@@ -986,7 +821,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;
@@ -1049,7 +884,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);
@@ -1058,7 +893,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;
@@ -1087,74 +922,10 @@ _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,
@@ -1170,73 +941,43 @@ _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;
}
- 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,
+ status = _cairo_surface_composite (operator,
src,
- gstate->clip.surface ? &mask.base : NULL,
+ 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);
- 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
+ * an intermediate surface to handle clip->surface
*
* Warning: This call modifies the coordinates of traps
*/
static cairo_status_t
-_composite_traps_intermediate_surface (cairo_gstate_t *gstate,
+_composite_traps_intermediate_surface (cairo_clip_t *clip,
cairo_pattern_t *src,
cairo_operator_t operator,
cairo_surface_t *dst,
@@ -1248,9 +989,9 @@ _composite_traps_intermediate_surface (cairo_gstate_t *gstate,
cairo_surface_pattern_t intermediate_pattern;
cairo_status_t status;
- translate_traps (traps, -extents->x, -extents->y);
+ _cairo_traps_translate (traps, -extents->x, -extents->y);
- intermediate = _cairo_surface_create_similar_solid (gstate->clip.surface,
+ intermediate = _cairo_surface_create_similar_solid (clip->surface,
CAIRO_CONTENT_ALPHA,
extents->width,
extents->height,
@@ -1274,7 +1015,7 @@ _composite_traps_intermediate_surface (cairo_gstate_t *gstate,
if (status)
goto out;
- status = _cairo_gstate_combine_clip_surface (gstate, intermediate, extents);
+ status = _cairo_clip_combine_to_surface (clip, intermediate, extents);
if (status)
goto out;
@@ -1302,7 +1043,7 @@ _composite_traps_intermediate_surface (cairo_gstate_t *gstate,
* _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,
@@ -1337,10 +1078,10 @@ _composite_trap_region_solid (cairo_gstate_t *gstate,
}
/* Composites a set of trapezoids in the general case where
- gstate->clip.surface == NULL
+ clip->surface == NULL
*/
static cairo_status_t
-_composite_traps (cairo_gstate_t *gstate,
+_composite_traps (cairo_clip_t *clip,
cairo_pattern_t *src,
cairo_operator_t operator,
cairo_surface_t *dst,
@@ -1349,7 +1090,7 @@ _composite_traps (cairo_gstate_t *gstate,
{
cairo_status_t status;
- status = _cairo_surface_composite_trapezoids (gstate->operator,
+ status = _cairo_surface_composite_trapezoids (operator,
src, dst,
extents->x, extents->y,
extents->x, extents->y,
@@ -1361,13 +1102,26 @@ _composite_traps (cairo_gstate_t *gstate,
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
-_clip_and_composite_trapezoids_transformed (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_status_t status;
pixman_region16_t *trap_region;
@@ -1380,10 +1134,15 @@ _clip_and_composite_trapezoids_transformed (cairo_gstate_t *gstate,
if (status)
return status;
- if (trap_region)
- status = _clip_and_compute_extents_region (gstate, trap_region, &extents);
- else
- status = _clip_and_compute_extents_arbitrary (gstate, traps, &extents);
+ 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);
+ }
if (status)
goto out;
@@ -1392,27 +1151,27 @@ _clip_and_composite_trapezoids_transformed (cairo_gstate_t *gstate,
/* Nothing to do */
goto out;
- if (gstate->clip.surface) {
+ if (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,
+ status = _composite_trap_region (clip, 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,
+ status = _composite_traps_intermediate_surface (clip, 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,
+ status = _composite_trap_region_solid (clip, (cairo_solid_pattern_t *)src,
operator, dst, trap_region);
} else {
if (trap_region) {
@@ -1421,7 +1180,7 @@ _clip_and_composite_trapezoids_transformed (cairo_gstate_t *gstate,
* 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,
+ status = _composite_trap_region (clip, src, operator, dst,
trap_region, &extents);
if (status != CAIRO_INT_STATUS_UNSUPPORTED)
goto out;
@@ -1429,7 +1188,7 @@ _clip_and_composite_trapezoids_transformed (cairo_gstate_t *gstate,
/* If a clip regions aren't supported, fall through */
}
- status = _composite_traps (gstate, src, operator,
+ status = _composite_traps (clip, src, operator,
dst, traps, &extents);
}
}
@@ -1451,11 +1210,11 @@ _cairo_gstate_clip_and_composite_trapezoids (cairo_gstate_t *gstate,
_cairo_gstate_copy_transformed_source (gstate, &pattern.base);
- status = _clip_and_composite_trapezoids_transformed (gstate,
- &pattern.base,
- gstate->operator,
- gstate->target,
- traps);
+ status = _cairo_surface_clip_and_composite_trapezoids (&pattern.base,
+ gstate->operator,
+ gstate->target,
+ traps,
+ &gstate->clip);
_cairo_pattern_fini (&pattern.base);
@@ -1471,7 +1230,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;
@@ -1487,7 +1246,10 @@ _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;
@@ -1514,7 +1276,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;
@@ -1584,7 +1349,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;
@@ -1607,224 +1375,15 @@ 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 cairo_clip_path_t *
-_cairo_clip_path_reference (cairo_clip_path_t *clip_path)
-{
- if (clip_path == NULL)
- return NULL;
-
- clip_path->ref_count++;
-
- return clip_path;
-}
-
-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->target);
}
static void
@@ -2140,7 +1699,7 @@ _cairo_gstate_show_glyphs (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;
diff --git a/src/cairo-meta-surface.c b/src/cairo-meta-surface.c
index c2be862e..3781fabc 100644
--- a/src/cairo-meta-surface.c
+++ b/src/cairo-meta-surface.c
@@ -35,15 +35,7 @@
#include "cairoint.h"
#include "cairo-meta-surface-private.h"
-
-/*
- * Notes:
- *
- * Can't use cairo_surface_* calls since we often don't want
- * fallbacks. For example, when determining the font subsets or the
- * fallback areas. Hmm... but maybe those passes could be integrated
- * into the delegation wrappers and the ps output pass, respectively.
- */
+#include "cairo-gstate-private.h"
static const cairo_surface_backend_t cairo_meta_surface_backend;
@@ -106,10 +98,6 @@ _cairo_meta_surface_finish (void *abstract_surface)
free (command);
break;
- case CAIRO_COMMAND_SET_CLIP_REGION:
- free (command);
- break;
-
case CAIRO_COMMAND_INTERSECT_CLIP_PATH:
if (command->intersect_clip_path.path_pointer)
_cairo_path_fixed_fini (&command->intersect_clip_path.path);
@@ -276,38 +264,6 @@ _cairo_meta_surface_composite_trapezoids (cairo_operator_t operator,
}
static cairo_int_status_t
-_cairo_meta_surface_set_clip_region (void *abstract_surface,
- pixman_region16_t *region)
-{
- cairo_meta_surface_t *meta = abstract_surface;
- cairo_command_set_clip_region_t *command;
-
- command = malloc (sizeof (cairo_command_set_clip_region_t));
- if (command == NULL)
- return CAIRO_STATUS_NO_MEMORY;
-
- command->type = CAIRO_COMMAND_SET_CLIP_REGION;
-
- if (region) {
- command->region = pixman_region_create ();
- pixman_region_copy (command->region, region);
- } else {
- command->region = NULL;
- }
-
- command->serial = meta->base.current_clip_serial;
-
- if (_cairo_array_append (&meta->commands, &command, 1) == NULL) {
- if (command->region)
- pixman_region_destroy (command->region);
- free (command);
- return CAIRO_STATUS_NO_MEMORY;
- }
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_int_status_t
_cairo_meta_surface_intersect_clip_path (void *dst,
cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule,
@@ -468,7 +424,7 @@ static const cairo_surface_backend_t cairo_meta_surface_backend = {
_cairo_meta_surface_composite_trapezoids,
NULL, /* copy_page */
NULL, /* show_page */
- _cairo_meta_surface_set_clip_region,
+ NULL, /* set_clip_region */
_cairo_meta_surface_intersect_clip_path,
_cairo_meta_surface_get_extents,
_cairo_meta_surface_show_glyphs,
@@ -483,16 +439,24 @@ _cairo_meta_surface_replay (cairo_surface_t *surface,
cairo_command_t *command, **elements;
int i, num_elements;
cairo_int_status_t status;
+ cairo_traps_t traps;
+ cairo_clip_t clip;
meta = (cairo_meta_surface_t *) surface;
status = CAIRO_STATUS_SUCCESS;
+ _cairo_clip_init (&clip, target);
+
num_elements = meta->commands.num_elements;
elements = (cairo_command_t **) meta->commands.elements;
for (i = 0; i < num_elements; i++) {
command = elements[i];
switch (command->type) {
case CAIRO_COMMAND_COMPOSITE:
+ status = _cairo_surface_set_clip (target, &clip);
+ if (status)
+ break;
+
status = _cairo_surface_composite
(command->composite.operator,
&command->composite.src_pattern.base,
@@ -509,6 +473,10 @@ _cairo_meta_surface_replay (cairo_surface_t *surface,
break;
case CAIRO_COMMAND_FILL_RECTANGLES:
+ status = _cairo_surface_set_clip (target, &clip);
+ if (status)
+ break;
+
status = _cairo_surface_fill_rectangles
(target,
command->fill_rectangles.operator,
@@ -518,6 +486,10 @@ _cairo_meta_surface_replay (cairo_surface_t *surface,
break;
case CAIRO_COMMAND_COMPOSITE_TRAPEZOIDS:
+ status = _cairo_surface_set_clip (target, &clip);
+ if (status)
+ break;
+
status = _cairo_surface_composite_trapezoids
(command->composite_trapezoids.operator,
&command->composite_trapezoids.pattern.base,
@@ -532,27 +504,24 @@ _cairo_meta_surface_replay (cairo_surface_t *surface,
command->composite_trapezoids.num_traps);
break;
- case CAIRO_COMMAND_SET_CLIP_REGION:
- status = _cairo_surface_set_clip_region
- (target,
- command->set_clip_region.region,
- command->set_clip_region.serial);
- break;
-
case CAIRO_COMMAND_INTERSECT_CLIP_PATH:
/* XXX Meta surface clipping is broken and requires some
* cairo-gstate.c rewriting. Work around it for now. */
- if (target->backend->intersect_clip_path == NULL)
- break;
-
- status = _cairo_surface_intersect_clip_path
- (target,
- command->intersect_clip_path.path_pointer,
- command->intersect_clip_path.fill_rule,
- command->intersect_clip_path.tolerance);
+ if (command->intersect_clip_path.path_pointer == NULL)
+ status = _cairo_clip_reset (&clip);
+ else
+ status = _cairo_clip_clip (&clip,
+ command->intersect_clip_path.path_pointer,
+ command->intersect_clip_path.fill_rule,
+ command->intersect_clip_path.tolerance,
+ target);
break;
case CAIRO_COMMAND_SHOW_GLYPHS:
+ status = _cairo_surface_set_clip (target, &clip);
+ if (status)
+ break;
+
status = _cairo_surface_show_glyphs
(command->show_glyphs.scaled_font,
command->show_glyphs.operator,
@@ -569,18 +538,37 @@ _cairo_meta_surface_replay (cairo_surface_t *surface,
break;
case CAIRO_COMMAND_FILL_PATH:
- /* XXX Meta surface fill_path is broken and requires some
- * cairo-gstate.c rewriting. Work around it for now. */
- if (target->backend->fill_path == NULL)
+ status = _cairo_surface_set_clip (target, &clip);
+ if (status)
break;
- status = _cairo_surface_fill_path
- (command->fill_path.operator,
- &command->fill_path.pattern.base,
- target,
- &command->fill_path.path,
- command->fill_path.fill_rule,
- command->fill_path.tolerance);
+ status = _cairo_surface_fill_path (command->fill_path.operator,
+ &command->fill_path.pattern.base,
+ target,
+ &command->fill_path.path,
+ command->fill_path.fill_rule,
+ command->fill_path.tolerance);
+ if (status != CAIRO_INT_STATUS_UNSUPPORTED)
+ break;
+
+ _cairo_traps_init (&traps);
+
+ status = _cairo_path_fixed_fill_to_traps (&command->fill_path.path,
+ command->fill_path.fill_rule,
+ command->fill_path.tolerance,
+ &traps);
+ if (status) {
+ _cairo_traps_fini (&traps);
+ break;
+ }
+
+ status = _cairo_surface_clip_and_composite_trapezoids (&command->fill_path.pattern.base,
+ command->fill_path.operator,
+ target,
+ &traps,
+ &clip);
+
+ _cairo_traps_fini (&traps);
break;
default:
@@ -591,5 +579,7 @@ _cairo_meta_surface_replay (cairo_surface_t *surface,
break;
}
+ _cairo_clip_fini (&clip);
+
return status;
}
diff --git a/src/cairo-path-fill.c b/src/cairo-path-fill.c
index c0015fc9..31b83ade 100644
--- a/src/cairo-path-fill.c
+++ b/src/cairo-path-fill.c
@@ -36,10 +36,8 @@
#include "cairoint.h"
-#include "cairo-gstate-private.h"
-
typedef struct cairo_filler {
- cairo_gstate_t *gstate;
+ double tolerance;
cairo_traps_t *traps;
cairo_point_t current_point;
@@ -48,7 +46,7 @@ typedef struct cairo_filler {
} cairo_filler_t;
static void
-_cairo_filler_init (cairo_filler_t *filler, cairo_gstate_t *gstate, cairo_traps_t *traps);
+_cairo_filler_init (cairo_filler_t *filler, double tolerance, cairo_traps_t *traps);
static void
_cairo_filler_fini (cairo_filler_t *filler);
@@ -69,9 +67,9 @@ static cairo_status_t
_cairo_filler_close_path (void *closure);
static void
-_cairo_filler_init (cairo_filler_t *filler, cairo_gstate_t *gstate, cairo_traps_t *traps)
+_cairo_filler_init (cairo_filler_t *filler, double tolerance, cairo_traps_t *traps)
{
- filler->gstate = gstate;
+ filler->tolerance = tolerance;
filler->traps = traps;
filler->current_point.x = 0;
@@ -132,7 +130,6 @@ _cairo_filler_curve_to (void *closure,
cairo_status_t status = CAIRO_STATUS_SUCCESS;
cairo_filler_t *filler = closure;
cairo_polygon_t *polygon = &filler->polygon;
- cairo_gstate_t *gstate = filler->gstate;
cairo_spline_t spline;
status = _cairo_spline_init (&spline, &filler->current_point, b, c, d);
@@ -140,7 +137,7 @@ _cairo_filler_curve_to (void *closure,
if (status == CAIRO_INT_STATUS_DEGENERATE)
return CAIRO_STATUS_SUCCESS;
- _cairo_spline_decompose (&spline, gstate->tolerance);
+ _cairo_spline_decompose (&spline, filler->tolerance);
if (status)
goto CLEANUP_SPLINE;
@@ -174,13 +171,14 @@ _cairo_filler_close_path (void *closure)
cairo_status_t
_cairo_path_fixed_fill_to_traps (cairo_path_fixed_t *path,
- cairo_gstate_t *gstate,
+ cairo_fill_rule_t fill_rule,
+ double tolerance,
cairo_traps_t *traps)
{
cairo_status_t status = CAIRO_STATUS_SUCCESS;
cairo_filler_t filler;
- _cairo_filler_init (&filler, gstate, traps);
+ _cairo_filler_init (&filler, tolerance, traps);
status = _cairo_path_fixed_interpret (path,
CAIRO_DIRECTION_FORWARD,
@@ -198,7 +196,7 @@ _cairo_path_fixed_fill_to_traps (cairo_path_fixed_t *path,
status = _cairo_traps_tessellate_polygon (filler.traps,
&filler.polygon,
- filler.gstate->fill_rule);
+ fill_rule);
if (status)
goto BAIL;
diff --git a/src/cairo-surface.c b/src/cairo-surface.c
index 4ff8c700..52804ebb 100644
--- a/src/cairo-surface.c
+++ b/src/cairo-surface.c
@@ -1283,7 +1283,7 @@ _cairo_surface_set_clip_path_recursive (cairo_surface_t *surface,
* Sets the clipping path to be the intersection of the current
* clipping path of the surface and the given path.
**/
-cairo_status_t
+static cairo_status_t
_cairo_surface_set_clip_path (cairo_surface_t *surface,
cairo_clip_path_t *clip_path,
unsigned int serial)
@@ -1314,6 +1314,27 @@ _cairo_surface_set_clip_path (cairo_surface_t *surface,
return CAIRO_STATUS_SUCCESS;
}
+cairo_status_t
+_cairo_surface_set_clip (cairo_surface_t *surface, cairo_clip_t *clip)
+{
+ if (!surface)
+ return CAIRO_STATUS_NULL_POINTER;
+ if (clip->serial == _cairo_surface_get_current_clip_serial (surface))
+ return CAIRO_STATUS_SUCCESS;
+
+ 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
diff --git a/src/cairo-traps.c b/src/cairo-traps.c
index a97d5848..18b944c1 100644
--- a/src/cairo-traps.c
+++ b/src/cairo-traps.c
@@ -229,6 +229,35 @@ _compare_point_fixed_by_y (const void *av, const void *bv)
return ret;
}
+void
+_cairo_traps_translate (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;
+ }
+}
+
cairo_status_t
_cairo_traps_tessellate_triangle (cairo_traps_t *traps, cairo_point_t t[3])
{
diff --git a/src/cairoint.h b/src/cairoint.h
index 78387fb0..74e58c96 100644
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -240,6 +240,9 @@ typedef enum cairo_direction {
} cairo_direction_t;
typedef struct _cairo_path_fixed cairo_path_fixed_t;
+typedef enum _cairo_clip_mode cairo_clip_mode_t;
+typedef struct _cairo_clip_path cairo_clip_path_t;
+typedef struct _cairo_clip cairo_clip_t;
typedef struct _cairo_edge {
cairo_line_t edge;
@@ -289,6 +292,13 @@ typedef struct _cairo_pen {
typedef struct _cairo_color cairo_color_t;
typedef struct _cairo_image_surface cairo_image_surface_t;
+cairo_private void
+_cairo_box_round_to_rectangle (cairo_box_t *box, cairo_rectangle_t *rectangle);
+
+cairo_private void
+_cairo_rectangle_intersect (cairo_rectangle_t *dest, cairo_rectangle_t *src);
+
+
/* cairo_array.c structures and functions */
typedef struct _cairo_array cairo_array_t;
@@ -813,12 +823,6 @@ typedef struct _cairo_format_masks {
unsigned long blue_mask;
} cairo_format_masks_t;
-typedef enum _cairo_clip_mode {
- CAIRO_CLIP_MODE_PATH,
- CAIRO_CLIP_MODE_REGION,
- CAIRO_CLIP_MODE_MASK
-} cairo_clip_mode_t;
-
struct _cairo_surface {
const cairo_surface_backend_t *backend;
@@ -1499,7 +1503,8 @@ _cairo_path_fixed_bounds (cairo_path_fixed_t *path,
/* cairo_path_fill.c */
cairo_private cairo_status_t
_cairo_path_fixed_fill_to_traps (cairo_path_fixed_t *path,
- cairo_gstate_t *gstate,
+ cairo_fill_rule_t fill_rule,
+ double tolerance,
cairo_traps_t *traps);
/* cairo_path_stroke.c */
@@ -1585,6 +1590,13 @@ _cairo_surface_composite_trapezoids (cairo_operator_t operator,
cairo_trapezoid_t *traps,
int ntraps);
+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_private cairo_status_t
_cairo_surface_copy_page (cairo_surface_t *surface);
@@ -1640,12 +1652,8 @@ _cairo_surface_intersect_clip_path (cairo_surface_t *surface,
cairo_fill_rule_t fill_rule,
double tolerance);
-typedef struct _cairo_clip_path cairo_clip_path_t;
-
cairo_private cairo_status_t
-_cairo_surface_set_clip_path (cairo_surface_t *surface,
- cairo_clip_path_t *clip_path,
- unsigned int serial);
+_cairo_surface_set_clip (cairo_surface_t *surface, cairo_clip_t *clip);
cairo_private cairo_status_t
_cairo_surface_get_extents (cairo_surface_t *surface,
@@ -1800,6 +1808,9 @@ _cairo_traps_init_box (cairo_traps_t *traps,
cairo_private void
_cairo_traps_fini (cairo_traps_t *traps);
+cairo_private void
+_cairo_traps_translate (cairo_traps_t *traps, int x, int y);
+
cairo_private cairo_status_t
_cairo_traps_tessellate_triangle (cairo_traps_t *traps, cairo_point_t t[3]);