mirror of
https://gitlab.freedesktop.org/cairo/cairo.git
synced 2025-12-24 11:20:10 +01:00
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
This commit is contained in:
parent
0c40f66c04
commit
79b2a79f2d
10 changed files with 544 additions and 67 deletions
10
ChangeLog
10
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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
62
src/cairo.c
62
src/cairo.c
|
|
@ -1494,6 +1494,68 @@ cairo_paint (cairo_t *cr)
|
|||
CAIRO_CHECK_SANITY (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
|
||||
|
|
|
|||
10
src/cairo.h
10
src/cairo.h
|
|
@ -462,6 +462,16 @@ cairo_close_path (cairo_t *cr);
|
|||
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);
|
||||
|
||||
|
|
|
|||
|
|
@ -1051,6 +1051,10 @@ _cairo_gstate_backend_to_user (cairo_gstate_t *gstate, double *x, double *y);
|
|||
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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
BIN
test/mask-ref.png
Normal file
BIN
test/mask-ref.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 58 KiB |
241
test/mask.c
Normal file
241
test/mask.c
Normal file
|
|
@ -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);
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue