diff options
-rw-r--r-- | ChangeLog | 18 | ||||
-rw-r--r-- | doc/public/cairo-docs.xml | 3 | ||||
-rw-r--r-- | src/cairo-gstate.c | 586 | ||||
-rw-r--r-- | src/cairo-traps.c | 55 | ||||
-rw-r--r-- | src/cairoint.h | 4 | ||||
-rw-r--r-- | test/Makefile.am | 5 | ||||
-rw-r--r-- | test/trap-clip-ref.png | bin | 0 -> 71701 bytes | |||
-rw-r--r-- | test/trap-clip.c | 213 |
8 files changed, 688 insertions, 196 deletions
@@ -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. diff --git a/doc/public/cairo-docs.xml b/doc/public/cairo-docs.xml index a472521d0..172d0d9b4 100644 --- a/doc/public/cairo-docs.xml +++ b/doc/public/cairo-docs.xml @@ -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> diff --git a/src/cairo-gstate.c b/src/cairo-gstate.c index d73e66f75..a9d72bb77 100644 --- a/src/cairo-gstate.c +++ b/src/cairo-gstate.c @@ -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); - - 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; - } - - translate_traps (traps, -extents.x, -extents.y); + status = _cairo_traps_extract_region (traps, &trap_region); + if (!CAIRO_OK (status)) + return status; - _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; - } + if (trap_region) + status = _clip_and_compute_extents_region (gstate, trap_region, &extents); + else + status = _clip_and_compute_extents_arbitrary (gstate, traps, &extents); - _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 (!CAIRO_OK (status)) + goto out; - 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 (_cairo_rectangle_empty (&extents)) + /* Nothing to do */ + goto out; - if (status) - return status; + if (gstate->clip.surface) { + if (trap_region) { + /* If we are compositing a set of rectangles, we can set them as the + * clip region for the destination surface and use the clip surface + * as the mask. A clip region might not be supported, in which case + * we fall through to the next method + */ + status = _composite_trap_region (gstate, src, operator, dst, + trap_region, &extents); + if (status != CAIRO_INT_STATUS_UNSUPPORTED) + goto out; + } + /* Handle a clip surface by creating an intermediate surface. */ + status = _composite_traps_intermediate_surface (gstate, src, operator, + 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); diff --git a/src/cairo-traps.c b/src/cairo-traps.c index 79c7e16b6..f08929221 100644 --- a/src/cairo-traps.c +++ b/src/cairo-traps.c @@ -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; +} + diff --git a/src/cairoint.h b/src/cairoint.h index 673071d5a..501f49ea3 100644 --- a/src/cairoint.h +++ b/src/cairoint.h @@ -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); diff --git a/test/Makefile.am b/test/Makefile.am index 3e5a86b0e..422327964 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -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 diff --git a/test/trap-clip-ref.png b/test/trap-clip-ref.png Binary files differnew file mode 100644 index 000000000..9b5b317aa --- /dev/null +++ b/test/trap-clip-ref.png diff --git a/test/trap-clip.c b/test/trap-clip.c new file mode 100644 index 000000000..4bc6f195a --- /dev/null +++ b/test/trap-clip.c @@ -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); +} |