mirror of
https://gitlab.freedesktop.org/cairo/cairo.git
synced 2026-01-03 22:10:17 +01:00
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:
parent
3bec073a7c
commit
a16a634f97
8 changed files with 689 additions and 197 deletions
18
ChangeLog
18
ChangeLog
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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, ®ion);
|
||||
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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
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
213
test/trap-clip.c
Normal 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);
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue