src/cairoint.h src/cairo-traps.c: Add _cairo_traps_extract_region for converting trapezoids into a pixman region.

Represent all rectangular pixel-aligned regions as regions, not just single rectangles.
Split into manageable pieces, optimize rectangular pixel- aligned regions by using _cairo_surface_fill_rectangles() or _cairo_surface_set_clip_region() as appropriate.
tests/trap-clip.c tests/trap-clip-ref.png tests/Makefile.am: Add a test for trapezoids clipping.
Add an index.
This commit is contained in:
Owen Taylor 2005-04-13 11:23:43 +00:00
parent 3bec073a7c
commit a16a634f97
8 changed files with 689 additions and 197 deletions

View file

@ -1,3 +1,21 @@
2005-04-13 Owen Taylor <otaylor@redhat.com>
* src/cairoint.h src/cairo-traps.c: Add _cairo_traps_extract_region
for converting trapezoids into a pixman region.
* src/cairo-gstate.c (cairo_clip): Represent all rectangular
pixel-aligned regions as regions, not just single rectangles.
* src/cairo-gstate.c (_cairo_gstate_clip_and_composite_trapezoid):
Split into manageable pieces, optimize rectangular pixel-
aligned regions by using _cairo_surface_fill_rectangles()
or _cairo_surface_set_clip_region() as appropriate.
* tests/trap-clip.c tests/trap-clip-ref.png tests/Makefile.am:
Add a test for trapezoids clipping.
* doc/public/cairo-docs.xml: Add an index.
2005-04-12 Carl Worth <cworth@cworth.org>
* test/translate-show-surface.c: Note that bug is now fixed.

View file

@ -24,6 +24,9 @@
<xi:include href="xml/cairo-xcb.xml"/>
<xi:include href="xml/cairo-xlib.xml"/>
</part>
<index>
<title>Index</title>
</index>
</book>

View file

@ -1438,6 +1438,165 @@ _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.
*/
static cairo_status_t
_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;
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;
}
_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 (!CAIRO_OK (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 (!CAIRO_OK (status))
return status;
}
if (gstate->clip.surface)
_cairo_rectangle_intersect (extents, &gstate->clip.rect);
return CAIRO_STATUS_SUCCESS;
}
/* Composites a region representing a set of trapezoids.
*/
static cairo_status_t
_composite_trap_region (cairo_gstate_t *gstate,
cairo_pattern_t *src,
cairo_operator_t operator,
cairo_surface_t *dst,
pixman_region16_t *trap_region,
cairo_rectangle_t *extents)
{
cairo_status_t status, tmp_status;
cairo_pattern_union_t pattern;
cairo_pattern_union_t mask;
int num_rects = pixman_region_num_rects (trap_region);
if (num_rects == 0)
return CAIRO_STATUS_SUCCESS;
if (num_rects > 1) {
status = _cairo_surface_set_clip_region (dst, trap_region);
if (!CAIRO_OK (status))
return status;
}
_cairo_gstate_pattern_init_copy (gstate, &pattern, src);
if (gstate->clip.surface)
_cairo_pattern_init_for_surface (&mask.surface, gstate->clip.surface);
status = _cairo_surface_composite (gstate->operator,
&pattern.base,
gstate->clip.surface ? &mask.base : NULL,
dst,
extents->x, extents->y,
extents->x - (gstate->clip.surface ? gstate->clip.rect.x : 0),
extents->y - (gstate->clip.surface ? gstate->clip.rect.y : 0),
extents->x, extents->y,
extents->width, extents->height);
if (gstate->clip.surface)
_cairo_pattern_fini (&pattern.base);
_cairo_pattern_fini (&mask.base);
if (num_rects > 1) {
tmp_status = _cairo_surface_set_clip_region (dst, gstate->clip.region);
if (!CAIRO_OK (tmp_status))
status = tmp_status;
}
return status;
}
static void
translate_traps (cairo_traps_t *traps, int x, int y)
{
@ -1467,6 +1626,164 @@ translate_traps (cairo_traps_t *traps, int x, int y)
}
}
/* Composites a set of trapezoids in the case where we need to create
* an intermediate surface to handle gstate->clip.surface
*
* Warning: This call modifies the coordinates of traps
*/
static cairo_status_t
_composite_traps_intermediate_surface (cairo_gstate_t *gstate,
cairo_pattern_t *src,
cairo_operator_t operator,
cairo_surface_t *dst,
cairo_traps_t *traps,
cairo_rectangle_t *extents)
{
cairo_surface_t *intermediate;
cairo_pattern_union_t pattern;
cairo_surface_pattern_t intermediate_pattern;
cairo_color_t empty_color;
cairo_status_t status;
translate_traps (traps, -extents->x, -extents->y);
_cairo_color_init (&empty_color);
_cairo_color_set_alpha (&empty_color, 0.);
intermediate = _cairo_surface_create_similar_solid (gstate->clip.surface,
CAIRO_FORMAT_A8,
extents->width,
extents->height,
&empty_color);
if (intermediate == NULL)
return CAIRO_STATUS_NO_MEMORY;
_cairo_pattern_init_solid (&pattern.solid, 1.0, 1.0, 1.0);
status = _cairo_surface_composite_trapezoids (CAIRO_OPERATOR_ADD,
&pattern.base,
intermediate,
extents->x, extents->y,
0, 0,
extents->width,
extents->height,
traps->traps,
traps->num_traps);
_cairo_pattern_fini (&pattern.base);
if (!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);
if (!CAIRO_OK (status))
goto out;
_cairo_pattern_init_for_surface (&intermediate_pattern, intermediate);
_cairo_gstate_pattern_init_copy (gstate, &pattern, src);
status = _cairo_surface_composite (operator,
&pattern.base,
&intermediate_pattern.base,
dst,
extents->x, extents->y,
0, 0,
extents->x, extents->y,
extents->width, extents->height);
_cairo_pattern_fini (&pattern.base);
_cairo_pattern_fini (&intermediate_pattern.base);
out:
cairo_surface_destroy (intermediate);
return status;
}
/* Composites a region representing a set of trapezoids in the
* case of a solid source (so we can use
* _cairo_surface_fill_rectangles).
*/
static cairo_status_t
_composite_trap_region_solid (cairo_gstate_t *gstate,
cairo_solid_pattern_t *src,
cairo_operator_t operator,
cairo_surface_t *dst,
pixman_region16_t *region)
{
cairo_color_t color;
int num_rects = pixman_region_num_rects (region);
pixman_box16_t *boxes = pixman_region_rects (region);
cairo_rectangle_t *rects;
cairo_status_t status;
int i;
if (!num_rects)
return CAIRO_STATUS_SUCCESS;
rects = malloc (sizeof (pixman_rectangle_t) * num_rects);
if (!rects)
return CAIRO_STATUS_NO_MEMORY;
for (i = 0; i < num_rects; i++) {
rects[i].x = boxes[i].x1;
rects[i].y = boxes[i].y1;
rects[i].width = boxes[i].x2 - boxes[i].x1;
rects[i].height = boxes[i].y2 - boxes[i].y1;
}
_cairo_color_init (&color);
_cairo_color_set_rgb (&color, src->red, src->green, src->blue);
_cairo_color_set_alpha (&color, gstate->alpha);
status = _cairo_surface_fill_rectangles (dst, operator,
&color, rects, num_rects);
free (rects);
return status;
}
/* Composites a set of trapezoids in the general case where
gstate->clip.surface == NULL
*/
static cairo_status_t
_composite_traps (cairo_gstate_t *gstate,
cairo_pattern_t *src,
cairo_operator_t operator,
cairo_surface_t *dst,
cairo_traps_t *traps,
cairo_rectangle_t *extents)
{
cairo_pattern_union_t pattern;
cairo_status_t status;
_cairo_gstate_pattern_init_copy (gstate, &pattern, src);
status = _cairo_surface_composite_trapezoids (gstate->operator,
&pattern.base, dst,
extents->x, extents->y,
extents->x, extents->y,
extents->width,
extents->height,
traps->traps,
traps->num_traps);
_cairo_pattern_fini (&pattern.base);
return status;
}
/* Warning: This call modifies the coordinates of traps */
static cairo_status_t
@ -1477,154 +1794,71 @@ _cairo_gstate_clip_and_composite_trapezoids (cairo_gstate_t *gstate,
cairo_traps_t *traps)
{
cairo_status_t status;
cairo_pattern_union_t pattern;
pixman_region16_t *trap_region;
cairo_rectangle_t extents;
cairo_box_t trap_extents;
if (traps->num_traps == 0)
return CAIRO_STATUS_SUCCESS;
if (gstate->surface == NULL)
return CAIRO_STATUS_NO_TARGET_SURFACE;
_cairo_traps_extents (traps, &trap_extents);
_cairo_box_round_to_rectangle (&trap_extents, &extents);
status = _cairo_traps_extract_region (traps, &trap_region);
if (!CAIRO_OK (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 (!CAIRO_OK (status))
goto out;
if (_cairo_rectangle_empty (&extents))
/* Nothing to do */
goto out;
if (gstate->clip.surface) {
cairo_surface_t *intermediate;
cairo_surface_pattern_t intermediate_pattern;
cairo_color_t empty_color;
_cairo_rectangle_intersect (&extents, &gstate->clip.rect);
if (_cairo_rectangle_empty (&extents)) {
status = CAIRO_STATUS_SUCCESS;
goto BAIL1;
if (trap_region) {
/* If we are compositing a set of rectangles, we can set them as the
* clip region for the destination surface and use the clip surface
* as the mask. A clip region might not be supported, in which case
* we fall through to the next method
*/
status = _composite_trap_region (gstate, src, operator, dst,
trap_region, &extents);
if (status != CAIRO_INT_STATUS_UNSUPPORTED)
goto out;
}
translate_traps (traps, -extents.x, -extents.y);
_cairo_color_init (&empty_color);
_cairo_color_set_alpha (&empty_color, 0.);
intermediate = _cairo_surface_create_similar_solid (gstate->clip.surface,
CAIRO_FORMAT_A8,
extents.width,
extents.height,
&empty_color);
if (intermediate == NULL) {
status = CAIRO_STATUS_NO_MEMORY;
goto BAIL1;
}
_cairo_pattern_init_solid (&pattern.solid, 1.0, 1.0, 1.0);
status = _cairo_surface_composite_trapezoids (CAIRO_OPERATOR_ADD,
&pattern.base,
intermediate,
extents.x, extents.y,
0, 0,
extents.width,
extents.height,
traps->traps,
traps->num_traps);
_cairo_pattern_fini (&pattern.base);
if (status)
goto BAIL2;
_cairo_pattern_init_for_surface (&pattern.surface,
gstate->clip.surface);
status = _cairo_surface_composite (CAIRO_OPERATOR_IN,
&pattern.base,
NULL,
intermediate,
extents.x - gstate->clip.rect.x,
extents.y - gstate->clip.rect.y,
0, 0,
0, 0,
extents.width, extents.height);
_cairo_pattern_fini (&pattern.base);
if (status)
goto BAIL2;
_cairo_pattern_init_for_surface (&intermediate_pattern, intermediate);
_cairo_gstate_pattern_init_copy (gstate, &pattern, src);
status = _cairo_surface_composite (operator,
&pattern.base,
&intermediate_pattern.base,
dst,
extents.x, extents.y,
0, 0,
extents.x, extents.y,
extents.width, extents.height);
_cairo_pattern_fini (&pattern.base);
_cairo_pattern_fini (&intermediate_pattern.base);
BAIL2:
cairo_surface_destroy (intermediate);
BAIL1:
if (status)
return status;
/* Handle a clip surface by creating an intermediate surface. */
status = _composite_traps_intermediate_surface (gstate, src, operator,
dst, traps, &extents);
} else {
if (gstate->clip.region) {
pixman_box16_t box;
pixman_box16_t *intersection_extents;
pixman_region16_t *rect, *intersection;
box.x1 = _cairo_fixed_integer_floor (trap_extents.p1.x);
box.y1 = _cairo_fixed_integer_floor (trap_extents.p1.y);
box.x2 = _cairo_fixed_integer_ceil (trap_extents.p2.x);
box.y2 = _cairo_fixed_integer_ceil (trap_extents.p2.y);
rect = pixman_region_create_simple (&box);
if (rect == NULL)
goto bail1;
intersection = pixman_region_create();
if (intersection == NULL)
goto bail2;
if (pixman_region_intersect (intersection, gstate->clip.region,
rect) != PIXMAN_REGION_STATUS_SUCCESS)
goto bail3;
intersection_extents = pixman_region_extents (intersection);
extents.x = intersection_extents->x1;
extents.y = intersection_extents->y1;
extents.width = intersection_extents->x2 - intersection_extents->x1;
extents.height = intersection_extents->y2 - intersection_extents->y1;
bail3:
pixman_region_destroy (intersection);
bail2:
pixman_region_destroy (rect);
bail1:
;
/* 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,
operator, dst, trap_region);
} else if (trap_region && pixman_region_num_rects (trap_region) <= 1) {
/* For a simple rectangle, we can just use composite(), for more
* rectangles, we'd have to set a clip region. That might still
* be a win, but it's less obvious. (Depends on the backend)
*/
status = _composite_trap_region (gstate, src, operator, dst,
trap_region, &extents);
} else {
status = _composite_traps (gstate, src, operator,
dst, traps, &extents);
}
_cairo_gstate_pattern_init_copy (gstate, &pattern, src);
status = _cairo_surface_composite_trapezoids (gstate->operator,
&pattern.base, dst,
extents.x, extents.y,
extents.x, extents.y,
extents.width,
extents.height,
traps->traps,
traps->num_traps);
_cairo_pattern_fini (&pattern.base);
if (status)
return status;
}
out:
if (trap_region)
pixman_region_destroy (trap_region);
return CAIRO_STATUS_SUCCESS;
return status;
}
cairo_status_t
@ -1781,40 +2015,6 @@ _cairo_gstate_reset_clip (cairo_gstate_t *gstate)
return CAIRO_STATUS_SUCCESS;
}
static int
extract_transformed_rectangle(cairo_matrix_t *mat,
cairo_traps_t *tr,
pixman_box16_t *box)
{
double a, b, c, d, tx, ty;
cairo_matrix_get_affine (mat, &a, &b, &c, &d, &tx, &ty);
if (!(b == 0. && c == 0.))
return 0;
if (tr->num_traps == 1
&& tr->traps[0].left.p1.x == tr->traps[0].left.p2.x
&& tr->traps[0].right.p1.x == tr->traps[0].right.p2.x
&& tr->traps[0].left.p1.y == tr->traps[0].right.p1.y
&& tr->traps[0].left.p2.y == tr->traps[0].right.p2.y
&& _cairo_fixed_is_integer(tr->traps[0].left.p1.x)
&& _cairo_fixed_is_integer(tr->traps[0].left.p1.y)
&& _cairo_fixed_is_integer(tr->traps[0].left.p2.x)
&& _cairo_fixed_is_integer(tr->traps[0].left.p2.y)
&& _cairo_fixed_is_integer(tr->traps[0].right.p1.x)
&& _cairo_fixed_is_integer(tr->traps[0].right.p1.y)
&& _cairo_fixed_is_integer(tr->traps[0].right.p2.x)
&& _cairo_fixed_is_integer(tr->traps[0].right.p2.y)) {
box->x1 = (short) _cairo_fixed_integer_part(tr->traps[0].left.p1.x);
box->x2 = (short) _cairo_fixed_integer_part(tr->traps[0].right.p1.x);
box->y1 = (short) _cairo_fixed_integer_part(tr->traps[0].left.p1.y);
box->y2 = (short) _cairo_fixed_integer_part(tr->traps[0].left.p2.y);
return 1;
}
return 0;
}
/* Reset surface clip region to the one in the gstate */
cairo_status_t
_cairo_gstate_restore_external_state (cairo_gstate_t *gstate)
@ -1842,51 +2042,47 @@ _cairo_gstate_clip (cairo_gstate_t *gstate)
cairo_traps_t traps;
cairo_color_t white_color;
cairo_box_t extents;
pixman_box16_t box;
pixman_region16_t *region;
/* Fill the clip region as traps. */
_cairo_traps_init (&traps);
status = _cairo_path_fixed_fill_to_traps (&gstate->path, gstate, &traps);
if (status) {
if (!CAIRO_OK (status)) {
_cairo_traps_fini (&traps);
return status;
}
/* Check to see if we can represent these traps as a PixRegion. */
if (extract_transformed_rectangle (&gstate->ctm, &traps, &box)) {
pixman_region16_t *rect = NULL;
pixman_region16_t *intersection = NULL;
status = _cairo_traps_extract_region (&traps, &region);
if (!CAIRO_OK (status)) {
_cairo_traps_fini (&traps);
return status;
}
if (region) {
status = CAIRO_STATUS_SUCCESS;
rect = pixman_region_create_simple (&box);
if (rect == NULL) {
status = CAIRO_STATUS_NO_MEMORY;
if (gstate->clip.region == NULL) {
gstate->clip.region = region;
} else {
if (gstate->clip.region == NULL) {
gstate->clip.region = rect;
} else {
intersection = pixman_region_create();
if (pixman_region_intersect (intersection,
gstate->clip.region, rect)
== PIXMAN_REGION_STATUS_SUCCESS) {
pixman_region_destroy (gstate->clip.region);
gstate->clip.region = intersection;
} else {
status = CAIRO_STATUS_NO_MEMORY;
}
pixman_region_destroy (rect);
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;
}
if (!status)
status = _cairo_surface_set_clip_region (gstate->surface,
gstate->clip.region);
pixman_region_destroy (region);
}
if (CAIRO_OK (status))
status = _cairo_surface_set_clip_region (gstate->surface,
gstate->clip.region);
if (status != CAIRO_INT_STATUS_UNSUPPORTED) {
_cairo_traps_fini (&traps);

View file

@ -738,3 +738,58 @@ _cairo_traps_extents (cairo_traps_t *traps, cairo_box_t *extents)
{
*extents = traps->extents;
}
/**
* _cairo_traps_extract_region:
* @traps: a #cairo_traps_t
* @region: on return, %NULL is stored here if the trapezoids aren't
* exactly representable as a pixman region, otherwise a
* a pointer to such a region, newly allocated.
* (free with pixman region destroy)
*
* Determines if a set of trapezoids are exactly representable as a
* pixman region, and if so creates such a region.
*
* Return value: %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY
**/
cairo_status_t
_cairo_traps_extract_region (cairo_traps_t *traps,
pixman_region16_t **region)
{
int i;
for (i = 0; i < traps->num_traps; i++)
if (!(traps->traps[i].left.p1.x == traps->traps[i].left.p2.x
&& traps->traps[i].right.p1.x == traps->traps[i].right.p2.x
&& traps->traps[i].left.p1.y == traps->traps[i].right.p1.y
&& traps->traps[i].left.p2.y == traps->traps[i].right.p2.y
&& _cairo_fixed_is_integer(traps->traps[i].left.p1.x)
&& _cairo_fixed_is_integer(traps->traps[i].left.p1.y)
&& _cairo_fixed_is_integer(traps->traps[i].left.p2.x)
&& _cairo_fixed_is_integer(traps->traps[i].left.p2.y)
&& _cairo_fixed_is_integer(traps->traps[i].right.p1.x)
&& _cairo_fixed_is_integer(traps->traps[i].right.p1.y)
&& _cairo_fixed_is_integer(traps->traps[i].right.p2.x)
&& _cairo_fixed_is_integer(traps->traps[i].right.p2.y))) {
*region = NULL;
return CAIRO_STATUS_SUCCESS;
}
*region = pixman_region_create ();
for (i = 0; i < traps->num_traps; i++) {
int x = _cairo_fixed_integer_part(traps->traps[i].left.p1.x);
int y = _cairo_fixed_integer_part(traps->traps[i].left.p1.y);
int width = _cairo_fixed_integer_part(traps->traps[i].right.p1.x) - x;
int height = _cairo_fixed_integer_part(traps->traps[i].left.p2.y) - y;
if (pixman_region_union_rect (*region, *region,
x, y, width, height) != PIXMAN_REGION_STATUS_SUCCESS) {
pixman_region_destroy (*region);
return CAIRO_STATUS_NO_MEMORY;
}
}
return CAIRO_STATUS_SUCCESS;
}

View file

@ -1625,6 +1625,10 @@ _cairo_traps_contain (cairo_traps_t *traps, double x, double y);
cairo_private void
_cairo_traps_extents (cairo_traps_t *traps, cairo_box_t *extents);
cairo_private cairo_status_t
_cairo_traps_extract_region (cairo_traps_t *tr,
pixman_region16_t **region);
/* cairo_slope.c */
cairo_private void
_cairo_slope_init (cairo_slope_t *slope, cairo_point_t *a, cairo_point_t *b);

View file

@ -15,6 +15,7 @@ text-cache-crash \
text-rotate \
transforms \
translate-show-surface \
trap-clip \
user-data
# And all new tests go here too. I really don't like having to repeat
@ -33,7 +34,8 @@ path-data-ref.png \
pixman-rotate-ref.png \
romedalen.png \
transforms-ref.png \
translate-show-surface-ref.png
translate-show-surface-ref.png \
trap-clip-ref.png
# Once we can draw the text-rotate.c test case correctly, we should
# create and add text-rotate-ref.png to the list of reference PNGs.
@ -92,6 +94,7 @@ text_cache_crash_LDADD = $(LDADDS)
text_rotate_LDADD = $(LDADDS)
transforms_LDADD = $(LDADDS)
translate_show_surface_LDADD = $(LDADDS)
trap_clip_LDADD = $(LDADDS)
user_data_LDADD = $(LDADDS)
noinst_PROGRAMS = imagediff

BIN
test/trap-clip-ref.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

213
test/trap-clip.c Normal file
View file

@ -0,0 +1,213 @@
/*
* 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.
*
* Author: 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_rgb_color (cr, 0, 0, 0.6);
cairo_set_alpha (cr, 1.0);
}
static void
set_translucent_pattern (cairo_t *cr, int x, int y)
{
cairo_set_rgb_color (cr, 0, 0, 0.6);
cairo_set_alpha (cr, 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);
cairo_set_alpha (cr, 1);
}
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);
cairo_set_alpha (cr, 1);
}
static void
draw_rect (cairo_t *cr, int x, int y)
{
cairo_new_path (cr);
cairo_rectangle (cr, x, y, WIDTH, HEIGHT);
cairo_fill (cr);
}
static void
draw_rects (cairo_t *cr, int x, int y)
{
int width = WIDTH / 3;
int height = HEIGHT / 2;
cairo_new_path (cr);
cairo_rectangle (cr, x, y, width, height);
cairo_rectangle (cr, x + width, y + height, width, height);
cairo_rectangle (cr, x + 2 * width, y, width, height);
cairo_fill (cr);
}
static void
draw_polygon (cairo_t *cr, int x, int y)
{
cairo_new_path (cr);
cairo_move_to (cr, x, y);
cairo_line_to (cr, x, y + HEIGHT);
cairo_line_to (cr, x + WIDTH / 2, y + 3 * HEIGHT / 4);
cairo_line_to (cr, x + WIDTH, y + HEIGHT);
cairo_line_to (cr, x + WIDTH, y);
cairo_line_to (cr, x + WIDTH / 2, y + HEIGHT / 4);
cairo_close_path (cr);
cairo_fill (cr);
}
static void
clip_none (cairo_t *cr, int x, int y)
{
}
static void
clip_rect (cairo_t *cr, int x, int y)
{
cairo_set_alpha (cr, 1.0);
cairo_new_path (cr);
cairo_rectangle (cr, x + (int)WIDTH / 6, y + (int)HEIGHT / 6,
4 * ((int)WIDTH / 6), 4 * ((int)WIDTH / 6));
cairo_clip (cr);
cairo_new_path (cr);
}
static void
clip_rects (cairo_t *cr, int x, int y)
{
int height = HEIGHT / 3;
cairo_set_alpha (cr, 1.0);
cairo_new_path (cr);
cairo_rectangle (cr, x, y, WIDTH, height);
cairo_rectangle (cr, x, y + 2 * height, WIDTH, height);
cairo_clip (cr);
cairo_new_path (cr);
}
static void
clip_circle (cairo_t *cr, int x, int y)
{
cairo_set_alpha (cr, 1.0);
cairo_new_path (cr);
cairo_arc (cr, x + WIDTH / 2, y + HEIGHT / 2,
WIDTH / 3, 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 (*draw_funcs[])(cairo_t *cr, int x, int y) = {
draw_rect,
draw_rects,
draw_polygon,
};
static void (*clip_funcs[])(cairo_t *cr, int x, int y) = {
clip_none,
clip_rect,
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 (draw_funcs) * ARRAY_SIZE (clip_funcs) * (HEIGHT + PAD) + PAD)
static cairo_test_t test = {
"trap-clip",
"Trapezoid clipping",
IMAGE_WIDTH, IMAGE_HEIGHT
};
static cairo_test_status_t
draw (cairo_t *cr, int width, int height)
{
int i, j, k, x, y;
for (k = 0; k < ARRAY_SIZE (clip_funcs); k++) {
for (j = 0; j < ARRAY_SIZE (draw_funcs); j++) {
for (i = 0; i < ARRAY_SIZE (pattern_funcs); i++) {
x = i * (WIDTH + PAD) + PAD;
y = (ARRAY_SIZE (draw_funcs) * k + j) * (HEIGHT + PAD) + PAD;
cairo_save (cr);
cairo_move_to (cr, x, y);
clip_funcs[k] (cr, x, y);
pattern_funcs[i] (cr, x, y);
draw_funcs[j] (cr, x, y);
if (cairo_status (cr))
fprintf (stderr, "%d %d HERE!\n", i, j);
cairo_restore (cr);
}
}
}
if (cairo_status (cr) != CAIRO_STATUS_SUCCESS)
fprintf (stderr, "%d %d .HERE!\n", i, j);
return CAIRO_TEST_SUCCESS;
}
int
main (void)
{
return cairo_test (&test, draw);
}