summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOwen Taylor <otaylor@redhat.com>2005-05-02 11:01:18 +0000
committerOwen Taylor <otaylor@redhat.com>2005-05-02 11:01:18 +0000
commit79b2a79f2d9ba8dbef44d04656fa84d83836ac6c (patch)
tree4e905226d89f28bfe18bcef83c365e73ff5dcd8d
parent0c40f66c04bffa1847d37cf9c64e48db9e76f51f (diff)
src/cairo.[ch] src/cairo-gstate.c: Add cairo_mask() and cairo_mask_surface().
test/maks.c tests/Makefile.am tests/mask-ref.png: Add a comprehensive tests for cairo_mask(). Updated
-rw-r--r--ChangeLog10
-rw-r--r--doc/public/cairo-sections.txt2
-rw-r--r--doc/public/tmpl/cairo.sgml20
-rw-r--r--src/cairo-gstate.c259
-rw-r--r--src/cairo.c62
-rw-r--r--src/cairo.h10
-rw-r--r--src/cairoint.h4
-rw-r--r--test/Makefile.am3
-rw-r--r--test/mask-ref.pngbin0 -> 58954 bytes
-rw-r--r--test/mask.c241
10 files changed, 544 insertions, 67 deletions
diff --git a/ChangeLog b/ChangeLog
index 34459d56..86b945a5 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,13 @@
+2005-05-02 Owen Taylor <otaylor@redhat.com>
+
+ * src/cairo.[ch] src/cairo-gstate.c: Add cairo_mask()
+ and cairo_mask_surface().
+
+ * test/maks.c tests/Makefile.am tests/mask-ref.png: Add a
+ comprehensive tests for cairo_mask().
+
+ * docs/public/cairo-sections.txt: Updated
+
2005-05-02 Kristian Høgsberg <krh@redhat.com>
* src/cairo-gstate.c (_cairo_gstate_glyph_path): Also call
diff --git a/doc/public/cairo-sections.txt b/doc/public/cairo-sections.txt
index 9e329b9c..14a490b2 100644
--- a/doc/public/cairo-sections.txt
+++ b/doc/public/cairo-sections.txt
@@ -218,6 +218,8 @@ cairo_rel_curve_to
cairo_rectangle
cairo_close_path
cairo_paint
+cairo_mask
+cairo_mask_surface
cairo_stroke
cairo_stroke_preserve
cairo_fill
diff --git a/doc/public/tmpl/cairo.sgml b/doc/public/tmpl/cairo.sgml
index ceac45c0..342c1eda 100644
--- a/doc/public/tmpl/cairo.sgml
+++ b/doc/public/tmpl/cairo.sgml
@@ -523,6 +523,26 @@ Drawing contexts.
@cr:
+<!-- ##### FUNCTION cairo_mask ##### -->
+<para>
+
+</para>
+
+@cr:
+@pattern:
+
+
+<!-- ##### FUNCTION cairo_mask_surface ##### -->
+<para>
+
+</para>
+
+@cr:
+@surface:
+@surface_x:
+@surface_y:
+
+
<!-- ##### FUNCTION cairo_stroke ##### -->
<para>
diff --git a/src/cairo-gstate.c b/src/cairo-gstate.c
index 1cc01816..f4bfb5d8 100644
--- a/src/cairo-gstate.c
+++ b/src/cairo-gstate.c
@@ -745,6 +745,192 @@ _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.rect.x,
+ extents->y - gstate->clip.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.rect, &clip_rect);
+ if (!CAIRO_OK (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 (!CAIRO_OK (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_rectangle_t clip_rect;
+ pixman_region16_t *clip_region;
+ cairo_status_t status;
+
+ status = _cairo_surface_get_clip_extents (gstate->surface, &clip_rect);
+ if (!CAIRO_OK (status))
+ return status;
+
+ status = _region_new_from_rect (&clip_rect, &clip_region);
+ if (!CAIRO_OK (status))
+ return status;
+
+ status = _cairo_gstate_intersect_clip (gstate, clip_region);
+ if (!CAIRO_OK (status))
+ return status;
+
+ _region_rect_extents (clip_region, extents);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+cairo_status_t
+_cairo_gstate_mask (cairo_gstate_t *gstate,
+ cairo_pattern_t *mask)
+{
+ cairo_rectangle_t extents;
+ cairo_surface_pattern_t intermediate_pattern;
+ cairo_pattern_t *effective_mask;
+ cairo_status_t status;
+ int mask_x, mask_y;
+
+ _get_mask_extents (gstate, mask, &extents);
+
+ 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_FORMAT_A8,
+ extents.width,
+ extents.height);
+ if (intermediate == NULL)
+ return CAIRO_STATUS_NO_MEMORY;
+
+ status = _cairo_surface_composite (CAIRO_OPERATOR_SRC,
+ mask, NULL, intermediate,
+ extents.x, extents.y,
+ 0, 0,
+ 0, 0,
+ extents.width, extents.height);
+ if (!CAIRO_OK (status)) {
+ cairo_surface_destroy (intermediate);
+ return status;
+ }
+
+ status = _cairo_gstate_combine_clip_surface (gstate, intermediate, &extents);
+ if (!CAIRO_OK (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;
+ }
+
+ status = _cairo_surface_composite (gstate->operator,
+ gstate->source,
+ effective_mask,
+ gstate->surface,
+ extents.x, extents.y,
+ extents.x - mask_x, extents.y - mask_y,
+ extents.x, extents.y,
+ extents.width, extents.height);
+
+ if (gstate->clip.surface)
+ _cairo_pattern_fini (&intermediate_pattern.base);
+
+ return status;
+}
+
cairo_status_t
_cairo_gstate_stroke (cairo_gstate_t *gstate, cairo_path_fixed_t *path)
{
@@ -855,35 +1041,6 @@ _cairo_rectangle_empty (cairo_rectangle_t *rect)
return rect->width == 0 || rect->height == 0;
}
-/* 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;
-}
-
/* Given a region representing a set of trapezoids that will be
* drawn, clip the region according to the gstate and compute
* the overall extents.
@@ -893,30 +1050,11 @@ _clip_and_compute_extents_region (cairo_gstate_t *gstate,
pixman_region16_t *trap_region,
cairo_rectangle_t *extents)
{
- if (gstate->clip.region)
- pixman_region_intersect (trap_region,
- gstate->clip.region,
- trap_region);
-
- if (gstate->clip.surface) {
- pixman_region16_t *clip_rect;
- cairo_status_t status;
+ cairo_status_t status;
- status = _region_new_from_rect (&gstate->clip.rect,
- &clip_rect);
- if (!CAIRO_OK (status))
- return status;
-
- if (pixman_region_intersect (trap_region,
- clip_rect,
- trap_region) != PIXMAN_REGION_STATUS_SUCCESS)
- status = CAIRO_STATUS_NO_MEMORY;
-
- pixman_region_destroy (clip_rect);
-
- if (!CAIRO_OK (status))
- return status;
- }
+ status = _cairo_gstate_intersect_clip (gstate, trap_region);
+ if (!CAIRO_OK (status))
+ return status;
_region_rect_extents (trap_region, extents);
@@ -1058,8 +1196,8 @@ _composite_traps_intermediate_surface (cairo_gstate_t *gstate,
cairo_traps_t *traps,
cairo_rectangle_t *extents)
{
- cairo_surface_t *intermediate;
cairo_pattern_union_t pattern;
+ cairo_surface_t *intermediate;
cairo_surface_pattern_t intermediate_pattern;
cairo_status_t status;
@@ -1089,20 +1227,7 @@ _composite_traps_intermediate_surface (cairo_gstate_t *gstate,
if (!CAIRO_OK (status))
goto out;
- _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.rect.x,
- extents->y - gstate->clip.rect.y,
- 0, 0,
- 0, 0,
- extents->width, extents->height);
- _cairo_pattern_fini (&pattern.base);
-
+ status = _cairo_gstate_combine_clip_surface (gstate, intermediate, extents);
if (!CAIRO_OK (status))
goto out;
diff --git a/src/cairo.c b/src/cairo.c
index 316827f7..4f17fbea 100644
--- a/src/cairo.c
+++ b/src/cairo.c
@@ -1495,6 +1495,68 @@ cairo_paint (cairo_t *cr)
}
/**
+ * cairo_mask:
+ * @cr: a cairo context
+ * @pattern: a #cairo_pattern_t
+ *
+ * A drawing operator that paints the current source
+ * using the alpha channel of @pattern as a mask. (Opaque
+ * areas of @mask are painted with the source, transparent
+ * areas are not painted.)
+ */
+void
+cairo_mask (cairo_t *cr,
+ cairo_pattern_t *pattern)
+{
+ CAIRO_CHECK_SANITY (cr);
+ if (cr->status)
+ return;
+
+ cr->status = _cairo_gstate_mask (cr->gstate, pattern);
+
+ CAIRO_CHECK_SANITY (cr);
+}
+
+/**
+ * cairo_mask_surface:
+ * @cr: a cairo context
+ * @surface: a #cairo_surface_t
+ * @surface_x: X coordinate at which to place the origin of @surface
+ * @surface_y: Y coordinate at which to place the origin of @surface
+ *
+ * A drawing operator that paints the current source
+ * using the alpha channel of @surface as a mask. (Opaque
+ * areas of @surface are painted with the source, transparent
+ * areas are not painted.)
+ */
+void
+cairo_mask_surface (cairo_t *cr,
+ cairo_surface_t *surface,
+ double surface_x,
+ double surface_y)
+{
+ cairo_pattern_t *pattern;
+ cairo_matrix_t matrix;
+
+ CAIRO_CHECK_SANITY (cr);
+ if (cr->status)
+ return;
+
+ pattern = cairo_pattern_create_for_surface (surface);
+ if (!pattern) {
+ cr->status = CAIRO_STATUS_NO_MEMORY;
+ return;
+ }
+
+ cairo_matrix_init_translate (&matrix, - surface_x, - surface_y);
+ cairo_pattern_set_matrix (pattern, &matrix);
+
+ cairo_mask (cr, pattern);
+
+ cairo_pattern_destroy (pattern);
+}
+
+/**
* cairo_stroke:
* @cr: a cairo context
*
diff --git a/src/cairo.h b/src/cairo.h
index 58b58d82..c0a122fd 100644
--- a/src/cairo.h
+++ b/src/cairo.h
@@ -463,6 +463,16 @@ void
cairo_paint (cairo_t *cr);
void
+cairo_mask (cairo_t *cr,
+ cairo_pattern_t *pattern);
+
+void
+cairo_mask_surface (cairo_t *cr,
+ cairo_surface_t *surface,
+ double surface_x,
+ double surface_y);
+
+void
cairo_stroke (cairo_t *cr);
void
diff --git a/src/cairoint.h b/src/cairoint.h
index 44618cc7..1a6ff337 100644
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -1052,6 +1052,10 @@ cairo_private cairo_status_t
_cairo_gstate_paint (cairo_gstate_t *gstate);
cairo_private cairo_status_t
+_cairo_gstate_mask (cairo_gstate_t *gstate,
+ cairo_pattern_t *mask);
+
+cairo_private cairo_status_t
_cairo_gstate_stroke (cairo_gstate_t *gstate, cairo_path_fixed_t *path);
cairo_private cairo_status_t
diff --git a/test/Makefile.am b/test/Makefile.am
index f7f12382..ef625e66 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -10,6 +10,7 @@ gradient-alpha \
leaky-polygon \
line-width \
linear-gradient \
+mask \
move-to-show-surface \
paint \
path-data \
@@ -37,6 +38,7 @@ gradient-alpha-ref.png \
leaky-polygon-ref.png \
line-width-ref.png \
linear-gradient-ref.png \
+mask.png \
move-to-show-surface-ref.png \
coverage-ref.png \
clip-twice-ref.png \
@@ -105,6 +107,7 @@ gradient_alpha_LDADD = $(LDADDS)
leaky_polygon_LDADD = $(LDADDS)
line_width_LDADD = $(LDADDS)
linear_gradient_LDADD = $(LDADDS)
+mask_LDADD = $(LDADDS)
move_to_show_surface_LDADD = $(LDADDS)
paint_LDADD = $(LDADDS)
path_data_LDADD = $(LDADDS)
diff --git a/test/mask-ref.png b/test/mask-ref.png
new file mode 100644
index 00000000..518e3d42
--- /dev/null
+++ b/test/mask-ref.png
Binary files differ
diff --git a/test/mask.c b/test/mask.c
new file mode 100644
index 00000000..20547b02
--- /dev/null
+++ b/test/mask.c
@@ -0,0 +1,241 @@
+/*
+ * Copyright © 2005 Red Hat, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without
+ * fee, provided that the above copyright notice appear in all copies
+ * and that both that copyright notice and this permission notice
+ * appear in supporting documentation, and that the name of
+ * Red Hat, Inc. not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior
+ * permission. Red Hat, Inc. makes no representations about the
+ * suitability of this software for any purpose. It is provided "as
+ * is" without express or implied warranty.
+ *
+ * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL,
+ * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
+ * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Authors: Owen Taylor <otaylor@redhat.com>
+ * Kristian Høgsberg <krh@redhat.com>
+ */
+
+#include <math.h>
+#include "cairo-test.h"
+#include <stdio.h>
+
+#define WIDTH 64
+#define HEIGHT 64
+#define PAD 10
+
+const char png_filename[] = "romedalen.png";
+
+static void
+set_solid_pattern (cairo_t *cr, int x, int y)
+{
+ cairo_set_source_rgb (cr, 0, 0, 0.6);
+}
+
+static void
+set_translucent_pattern (cairo_t *cr, int x, int y)
+{
+ cairo_set_source_rgba (cr, 0, 0, 0.6, 0.5);
+}
+
+static void
+set_gradient_pattern (cairo_t *cr, int x, int y)
+{
+ cairo_pattern_t *pattern;
+
+ pattern =
+ cairo_pattern_create_linear (x, y, x + WIDTH, y + HEIGHT);
+ cairo_pattern_add_color_stop (pattern, 0, 1, 1, 1, 1);
+ cairo_pattern_add_color_stop (pattern, 1, 0, 0, 0.4, 1);
+ cairo_set_pattern (cr, pattern);
+}
+
+static void
+set_image_pattern (cairo_t *cr, int x, int y)
+{
+ cairo_pattern_t *pattern;
+
+ pattern = cairo_test_create_png_pattern (cr, png_filename);
+ cairo_set_pattern (cr, pattern);
+}
+
+static void
+mask_polygon (cairo_t *cr, int x, int y)
+{
+ cairo_surface_t *mask_surface;
+ cairo_t *cr2;
+
+ mask_surface = cairo_surface_create_similar (cairo_get_target_surface (cr),
+ CAIRO_FORMAT_A8,
+ WIDTH, HEIGHT);
+ cr2 = cairo_create ();
+ cairo_set_target_surface (cr2, mask_surface);
+
+ cairo_save (cr2);
+ cairo_set_source_rgba (cr2, 0, 0, 0, 0); /* transparent */
+ cairo_set_operator (cr2, CAIRO_OPERATOR_SRC);
+ cairo_paint (cr2);
+ cairo_restore (cr2);
+
+ cairo_set_source_rgb (cr2, 1, 1, 1); /* white */
+
+ cairo_new_path (cr2);
+ cairo_move_to (cr2, 0, 0);
+ cairo_line_to (cr2, 0, HEIGHT);
+ cairo_line_to (cr2, WIDTH / 2, 3 * HEIGHT / 4);
+ cairo_line_to (cr2, WIDTH, HEIGHT);
+ cairo_line_to (cr2, WIDTH, 0);
+ cairo_line_to (cr2, WIDTH / 2, HEIGHT / 4);
+ cairo_close_path (cr2);
+ cairo_fill (cr2);
+
+ cairo_destroy (cr2);
+
+ cairo_mask_surface (cr, mask_surface, x, y);
+
+ cairo_surface_destroy (mask_surface);
+}
+
+static void
+mask_gradient (cairo_t *cr, int x, int y)
+{
+ cairo_pattern_t *pattern;
+
+ pattern = cairo_pattern_create_linear (x, y,
+ x + WIDTH, y + HEIGHT);
+
+ cairo_pattern_add_color_stop_rgba (pattern,
+ 0,
+ 1, 1, 1, 1);
+ cairo_pattern_add_color_stop_rgba (pattern,
+ 1,
+ 1, 1, 1, 0);
+
+ cairo_mask (cr, pattern);
+
+ cairo_pattern_destroy (pattern);
+}
+
+static void
+clip_none (cairo_t *cr, int x, int y)
+{
+}
+
+static void
+clip_rects (cairo_t *cr, int x, int y)
+{
+ int height = HEIGHT / 3;
+
+ cairo_new_path (cr);
+ cairo_rectangle (cr, x, y, WIDTH, height);
+ cairo_rectangle (cr, x, y + 2 * height, WIDTH, height);
+ cairo_clip (cr);
+}
+
+static void
+clip_circle (cairo_t *cr, int x, int y)
+{
+ cairo_new_path (cr);
+ cairo_arc (cr, x + WIDTH / 2, y + HEIGHT / 2,
+ WIDTH / 2, 0, 2 * M_PI);
+ cairo_clip (cr);
+ cairo_new_path (cr);
+}
+
+static void (*pattern_funcs[])(cairo_t *cr, int x, int y) = {
+ set_solid_pattern,
+ set_translucent_pattern,
+ set_gradient_pattern,
+ set_image_pattern,
+};
+
+static void (*mask_funcs[])(cairo_t *cr, int x, int y) = {
+ mask_gradient,
+ mask_polygon,
+};
+
+static void (*clip_funcs[])(cairo_t *cr, int x, int y) = {
+ clip_none,
+ clip_rects,
+ clip_circle,
+};
+
+#define ARRAY_SIZE(a) (sizeof (a) / sizeof ((a)[0]))
+#define IMAGE_WIDTH (ARRAY_SIZE (pattern_funcs) * (WIDTH + PAD) + PAD)
+#define IMAGE_HEIGHT (ARRAY_SIZE (mask_funcs) * ARRAY_SIZE (clip_funcs) * (HEIGHT + PAD) + PAD)
+
+static cairo_test_t test = {
+ "mask",
+ "Tests of cairo_mask",
+ IMAGE_WIDTH, IMAGE_HEIGHT
+};
+
+static cairo_test_status_t
+draw (cairo_t *cr, int width, int height)
+{
+ cairo_surface_t *tmp_surface;
+ cairo_pattern_t *tmp_pattern;
+ int i, j, k;
+ cairo_t *cr2;
+
+ /* Some of our drawing is unbounded, so we draw each test to
+ * a temporary surface and copy over.
+ */
+ tmp_surface = cairo_surface_create_similar (cairo_get_target_surface (cr),
+ CAIRO_FORMAT_ARGB32,
+ IMAGE_WIDTH, IMAGE_HEIGHT);
+ cr2 = cairo_create ();
+ cairo_set_target_surface (cr2, tmp_surface);
+
+ tmp_pattern = cairo_pattern_create_for_surface (tmp_surface);
+ cairo_set_source (cr, tmp_pattern);
+
+ for (k = 0; k < ARRAY_SIZE (clip_funcs); k++) {
+ for (j = 0; j < ARRAY_SIZE (mask_funcs); j++) {
+ for (i = 0; i < ARRAY_SIZE (pattern_funcs); i++) {
+ int x = i * (WIDTH + PAD) + PAD;
+ int y = (ARRAY_SIZE (mask_funcs) * k + j) * (HEIGHT + PAD) + PAD;
+
+ /* Clear area we are going to be drawing onto */
+ cairo_save (cr2);
+ cairo_set_source_rgba (cr2, 0, 0, 0, 0); /* transparent */
+ cairo_set_operator (cr2, CAIRO_OPERATOR_SRC);
+ cairo_rectangle (cr2, x, y, WIDTH, HEIGHT);
+ cairo_fill (cr2);
+ cairo_restore (cr2);
+
+ /* draw */
+ cairo_save (cr2);
+
+ clip_funcs[k] (cr2, x, y);
+ pattern_funcs[i] (cr2, x, y);
+ mask_funcs[j] (cr2, x, y);
+
+ cairo_restore (cr2);
+
+ /* Copy back to the main pixmap */
+ cairo_rectangle (cr, x, y, WIDTH, HEIGHT);
+ cairo_fill (cr);
+ }
+ }
+ }
+
+ cairo_destroy (cr2);
+ cairo_surface_destroy (tmp_surface);
+
+ return CAIRO_TEST_SUCCESS;
+}
+
+int
+main (void)
+{
+ return cairo_test (&test, draw);
+}