diff options
author | Owen Taylor <otaylor@redhat.com> | 2005-08-18 15:50:36 +0000 |
---|---|---|
committer | Owen Taylor <otaylor@redhat.com> | 2005-08-18 15:50:36 +0000 |
commit | 31341327bfa171845ec3e921151cee6f861c2da8 (patch) | |
tree | c349d426de2ab63e0d403008bd7d85ce8f5d1548 | |
parent | ff9654e677a916da7a3fcc97ac0547f128e71436 (diff) |
Implement new equations for CLEAR and SOURCE CLEAR: (mask IN clip) ? 0 : dest SOURCE: (mask IN clip) ? src : dest That behave more like what people expect.
CLEAR and SOURCE are now bounded.
Assert that SOURCE and CLEAR aren't passed to these functions.
Assert that SOURCE and CLEAR aren't passed to these functions when there is a mask.
Do fixups for SOURCE and CLEAR as well as unbounded operators, since in the absence of a mask, we need SOURCE to work correctly (don't care about CLEAR)
_cairo_ft_font_show_glyphs) Consistently use CLEAR/TRANSPARENT (source doesn't matter) rather than SOURCE/TRANSPARENT when clearing rectangles.
src/cairo-xlib-surface.c src/cairo-surface.c: Use IN rather than SOURCE as an example of an unbounded operator in docs.
Remove CLEAR/SOURCE columns since they are no longer unbounded.
test/operator-clear.c test/operator-source Makefile.am: Add targetted tests of CLEAR/SOURCE.
-rw-r--r-- | ChangeLog | 38 | ||||
-rw-r--r-- | src/cairo-font.c | 5 | ||||
-rw-r--r-- | src/cairo-ft-font.c | 4 | ||||
-rw-r--r-- | src/cairo-gstate.c | 219 | ||||
-rw-r--r-- | src/cairo-image-surface.c | 4 | ||||
-rw-r--r-- | src/cairo-surface.c | 14 | ||||
-rw-r--r-- | src/cairo-xlib-surface.c | 6 | ||||
-rw-r--r-- | test/.cvsignore | 2 | ||||
-rw-r--r-- | test/Makefile.am | 6 | ||||
-rw-r--r-- | test/clip-operator-ref.png | bin | 38336 -> 37330 bytes | |||
-rw-r--r-- | test/operator-clear-ref.png | bin | 0 -> 4992 bytes | |||
-rw-r--r-- | test/operator-clear.c | 214 | ||||
-rw-r--r-- | test/operator-source-ref.png | bin | 0 -> 19957 bytes | |||
-rw-r--r-- | test/operator-source.c | 253 | ||||
-rw-r--r-- | test/unbounded-operator-ref.png | bin | 14178 -> 11937 bytes | |||
-rw-r--r-- | test/unbounded-operator.c | 4 |
16 files changed, 706 insertions, 63 deletions
@@ -1,3 +1,41 @@ +2005-08-17 Owen Taylor <otaylor@redhat.com> + + * src/cairo-gstate.c: Implement new equations for CLEAR and SOURCE + CLEAR: (mask IN clip) ? 0 : dest + SOURCE: (mask IN clip) ? src : dest + That behave more like what people expect. + + * src/cairo-gstate.c (_cairo_operator_bounded): CLEAR and SOURCE are + now bounded. + + * src/cairo-font.c (_cairo_ft_scaled_font_show_glyphs) + * src/cairo-surface.c (_cairo_surface_composite_trapezoids): + Assert that SOURCE and CLEAR aren't passed to these functions. + + * src/cairo-surface.c (_cairo_surface_composite): + Assert that SOURCE and CLEAR aren't passed to these functions + when there is a mask. + + * src/cairo-xlib-surface.c (_cairo_xlib_surface_composite) + * src/cairo-image-surface.c (_cairo_image_surface_composite): + Do fixups for SOURCE and CLEAR as well as unbounded operators, + since in the absence of a mask, we need SOURCE to work + correctly (don't care about CLEAR) + + * src/cairo-ft-font.c (_transform_glyph_bitmap, _cairo_ft_font_show_glyphs) + Consistently use CLEAR/TRANSPARENT (source doesn't matter) + rather than SOURCE/TRANSPARENT when clearing rectangles. + + * src/cairo-xlib-surface.c src/cairo-surface.c: Use + IN rather than SOURCE as an example of an unbounded operator in + docs. + + * test/unbounded-operator.c: Remove CLEAR/SOURCE columns since + they are no longer unbounded. + + * test/operator-clear.c test/operator-source Makefile.am: Add + targetted tests of CLEAR/SOURCE. + 2005-08-18 Carl Worth <cworth@cworth.org> * src/cairo-quartz-surface.c diff --git a/src/cairo-font.c b/src/cairo-font.c index 913eb95de..c3bc3c1fd 100644 --- a/src/cairo-font.c +++ b/src/cairo-font.c @@ -890,6 +890,11 @@ _cairo_scaled_font_show_glyphs (cairo_scaled_font_t *scaled_font, { cairo_status_t status; + /* These operators aren't interpreted the same way by the backends; + * they are implemented in terms of other operators in cairo-gstate.c + */ + assert (operator != CAIRO_OPERATOR_SOURCE && operator != CAIRO_OPERATOR_CLEAR); + if (scaled_font->status) return scaled_font->status; diff --git a/src/cairo-ft-font.c b/src/cairo-ft-font.c index 15180c987..5605f8a05 100644 --- a/src/cairo-ft-font.c +++ b/src/cairo-ft-font.c @@ -1133,7 +1133,7 @@ _transform_glyph_bitmap (cairo_image_glyph_cache_entry_t *val) /* Initialize it to empty */ - _cairo_surface_fill_rectangle (image, CAIRO_OPERATOR_SOURCE, + _cairo_surface_fill_rectangle (image, CAIRO_OPERATOR_CLEAR, CAIRO_COLOR_TRANSPARENT, 0, 0, width, height); @@ -1960,7 +1960,7 @@ _cairo_ft_scaled_font_show_glyphs (void *abstract_font, if (!mask) goto CLEANUP_ENTRIES; - status = _cairo_surface_fill_rectangle (mask, CAIRO_OPERATOR_SOURCE, + status = _cairo_surface_fill_rectangle (mask, CAIRO_OPERATOR_CLEAR, CAIRO_COLOR_TRANSPARENT, 0, 0, width, height); if (status) diff --git a/src/cairo-gstate.c b/src/cairo-gstate.c index 83b48d133..79962c3a3 100644 --- a/src/cairo-gstate.c +++ b/src/cairo-gstate.c @@ -258,8 +258,8 @@ _cairo_gstate_begin_group (cairo_gstate_t *gstate) _cairo_surface_set_drawableWH (gstate->target, pix, width, height); status = _cairo_surface_fill_rectangle (gstate->target, - CAIRO_OPERATOR_SOURCE, - &CAIRO_COLOR_TRANSPARENT, + CAIRO_OPERATOR_CLEAR, + CAIRO_COLOR_TRANSPARENT, 0, 0, _cairo_surface_get_width (gstate->target), _cairo_surface_get_height (gstate->target)); @@ -723,6 +723,8 @@ cairo_bool_t _cairo_operator_bounded (cairo_operator_t operator) { switch (operator) { + case CAIRO_OPERATOR_CLEAR: + case CAIRO_OPERATOR_SOURCE: case CAIRO_OPERATOR_OVER: case CAIRO_OPERATOR_ATOP: case CAIRO_OPERATOR_DEST: @@ -732,8 +734,6 @@ _cairo_operator_bounded (cairo_operator_t operator) case CAIRO_OPERATOR_ADD: case CAIRO_OPERATOR_SATURATE: return TRUE; - case CAIRO_OPERATOR_CLEAR: - case CAIRO_OPERATOR_SOURCE: case CAIRO_OPERATOR_OUT: case CAIRO_OPERATOR_IN: case CAIRO_OPERATOR_DEST_IN: @@ -753,6 +753,47 @@ typedef cairo_status_t (*cairo_draw_func_t) (void *closure, int dst_y, const cairo_rectangle_t *extents); +static cairo_status_t +_create_composite_mask_pattern (cairo_surface_pattern_t *mask_pattern, + cairo_clip_t *clip, + cairo_draw_func_t draw_func, + void *draw_closure, + cairo_surface_t *dst, + const cairo_rectangle_t *extents) +{ + cairo_surface_t *mask; + cairo_status_t status; + + mask = cairo_surface_create_similar (dst, + CAIRO_CONTENT_ALPHA, + extents->width, + extents->height); + if (mask->status) + return CAIRO_STATUS_NO_MEMORY; + + status = (*draw_func) (draw_closure, CAIRO_OPERATOR_ADD, + NULL, mask, + extents->x, extents->y, + extents); + if (status) + goto CLEANUP_SURFACE; + + if (clip->surface) + status = _cairo_clip_combine_to_surface (clip, CAIRO_OPERATOR_IN, + mask, + extents->x, extents->y, + extents); + if (status) + goto CLEANUP_SURFACE; + + _cairo_pattern_init_for_surface (mask_pattern, mask); + + CLEANUP_SURFACE: + cairo_surface_destroy (mask); + + return status; +} + /* Handles compositing with a clip surface when the operator allows * us to combine the clip with the mask */ @@ -765,50 +806,30 @@ _cairo_gstate_clip_and_composite_with_mask (cairo_clip_t *clip, cairo_surface_t *dst, const cairo_rectangle_t *extents) { - cairo_surface_t *intermediate; - cairo_surface_pattern_t intermediate_pattern; + cairo_surface_pattern_t mask_pattern; cairo_status_t status; - intermediate = cairo_surface_create_similar (clip->surface, - CAIRO_CONTENT_ALPHA, - extents->width, - extents->height); - if (intermediate->status) - return CAIRO_STATUS_NO_MEMORY; - - status = (*draw_func) (draw_closure, CAIRO_OPERATOR_SOURCE, - NULL, intermediate, - extents->x, extents->y, - extents); + status = _create_composite_mask_pattern (&mask_pattern, + clip, + draw_func, draw_closure, + dst, extents); if (status) - goto CLEANUP_SURFACE; - - status = _cairo_clip_combine_to_surface (clip, CAIRO_OPERATOR_IN, - intermediate, - extents->x, extents->y, - extents); - if (status) - goto CLEANUP_SURFACE; - - _cairo_pattern_init_for_surface (&intermediate_pattern, intermediate); - + return status; + status = _cairo_surface_composite (operator, - src, &intermediate_pattern.base, dst, + src, &mask_pattern.base, dst, extents->x, extents->y, 0, 0, extents->x, extents->y, extents->width, extents->height); - _cairo_pattern_fini (&intermediate_pattern.base); - - CLEANUP_SURFACE: - cairo_surface_destroy (intermediate); + _cairo_pattern_fini (&mask_pattern.base); return status; } -/* Handles compositing with a clip surface when the operator allows - * us to combine the clip with the mask +/* Handles compositing with a clip surface when we have to do the operation + * in two pieces and combine them together. */ static cairo_status_t _cairo_gstate_clip_and_composite_combine (cairo_clip_t *clip, @@ -827,6 +848,7 @@ _cairo_gstate_clip_and_composite_combine (cairo_clip_t *clip, /* We'd be better off here creating a surface identical in format * to dst, but we have no way of getting that information. * A CAIRO_CONTENT_CLONE or something might be useful. + * cairo_surface_create_similar() also unnecessarily clears the surface. */ intermediate = cairo_surface_create_similar (dst, CAIRO_CONTENT_COLOR_ALPHA, @@ -895,6 +917,55 @@ _cairo_gstate_clip_and_composite_combine (cairo_clip_t *clip, return status; } +/* Handles compositing for CAIRO_OPERATOR_SOURCE, which is special; it's + * defined as (src IN mask IN clip) ADD (dst OUT (mask IN clip)) + */ +static cairo_status_t +_cairo_gstate_clip_and_composite_source (cairo_clip_t *clip, + cairo_pattern_t *src, + cairo_draw_func_t draw_func, + void *draw_closure, + cairo_surface_t *dst, + const cairo_rectangle_t *extents) +{ + cairo_surface_pattern_t mask_pattern; + cairo_status_t status; + + /* Create a surface that is mask IN clip + */ + status = _create_composite_mask_pattern (&mask_pattern, + clip, + draw_func, draw_closure, + dst, extents); + if (status) + return status; + + /* Compute dest' = dest OUT (mask IN clip) + */ + status = _cairo_surface_composite (CAIRO_OPERATOR_DEST_OUT, + &mask_pattern.base, NULL, dst, + 0, 0, + 0, 0, + extents->x, extents->y, + extents->width, extents->height); + + if (status) + goto CLEANUP_MASK_PATTERN; + + /* Now compute (src IN (mask IN clip)) ADD dest' + */ + status = _cairo_surface_composite (CAIRO_OPERATOR_ADD, + src, &mask_pattern.base, dst, + extents->x, extents->y, + 0, 0, + extents->x, extents->y, + extents->width, extents->height); + + CLEANUP_MASK_PATTERN: + _cairo_pattern_fini (&mask_pattern.base); + return status; +} + static int _cairo_rectangle_empty (const cairo_rectangle_t *rect) { @@ -931,30 +1002,49 @@ _cairo_gstate_clip_and_composite (cairo_clip_t *clip, cairo_surface_t *dst, const cairo_rectangle_t *extents) { + cairo_pattern_union_t solid_pattern; + cairo_status_t status; + if (_cairo_rectangle_empty (extents)) /* Nothing to do */ return CAIRO_STATUS_SUCCESS; - if (clip->surface) + if (operator == CAIRO_OPERATOR_CLEAR) { + _cairo_pattern_init_solid (&solid_pattern.solid, CAIRO_COLOR_WHITE); + src = &solid_pattern.base; + operator = CAIRO_OPERATOR_DEST_OUT; + } + + if (clip->surface || operator == CAIRO_OPERATOR_SOURCE) { - if (_cairo_operator_bounded (operator)) - return _cairo_gstate_clip_and_composite_with_mask (clip, operator, + if (operator == CAIRO_OPERATOR_SOURCE) + status = _cairo_gstate_clip_and_composite_source (clip, + src, + draw_func, draw_closure, + dst, extents); + else if (_cairo_operator_bounded (operator)) + status = _cairo_gstate_clip_and_composite_with_mask (clip, operator, + src, + draw_func, draw_closure, + dst, extents); + else + status = _cairo_gstate_clip_and_composite_combine (clip, operator, src, draw_func, draw_closure, dst, extents); - else - return _cairo_gstate_clip_and_composite_combine (clip, operator, - src, - draw_func, draw_closure, - dst, extents); } else { - return (*draw_func) (draw_closure, operator, - src, dst, - 0, 0, - extents); + status = (*draw_func) (draw_closure, operator, + src, dst, + 0, 0, + extents); } + + if (src == &solid_pattern.base) + _cairo_pattern_fini (&solid_pattern.base); + + return status; } @@ -1158,10 +1248,17 @@ _composite_trap_region (cairo_clip_t *clip, cairo_rectangle_t *extents) { cairo_status_t status; + cairo_pattern_union_t solid_pattern; cairo_pattern_union_t mask; int num_rects = pixman_region_num_rects (trap_region); unsigned int clip_serial; + if (clip->surface && operator == CAIRO_OPERATOR_CLEAR) { + _cairo_pattern_init_solid (&solid_pattern.solid, CAIRO_COLOR_WHITE); + src = &solid_pattern.base; + operator = CAIRO_OPERATOR_DEST_OUT; + } + if (num_rects == 0) return CAIRO_STATUS_SUCCESS; @@ -1193,6 +1290,9 @@ _composite_trap_region (cairo_clip_t *clip, if (clip->surface) _cairo_pattern_fini (&mask.base); + if (src == &solid_pattern.base) + _cairo_pattern_fini (&solid_pattern.base); + return status; } @@ -1308,21 +1408,28 @@ _cairo_surface_clip_and_composite_trapezoids (cairo_pattern_t *src, if (trap_region) { - if (src->type == CAIRO_PATTERN_SOLID && !clip->surface) + if ((src->type == CAIRO_PATTERN_SOLID || operator == CAIRO_OPERATOR_CLEAR) && + !clip->surface) { + const cairo_color_t *color; + + if (operator == CAIRO_OPERATOR_CLEAR) + color = CAIRO_COLOR_TRANSPARENT; + else + color = &((cairo_solid_pattern_t *)src)->color; + /* Solid rectangles special case */ - status = _cairo_surface_fill_region (dst, operator, - &((cairo_solid_pattern_t *)src)->color, - trap_region); + status = _cairo_surface_fill_region (dst, operator, color, trap_region); if (!status && clear_region) - status = _cairo_surface_fill_region (dst, operator, + status = _cairo_surface_fill_region (dst, CAIRO_OPERATOR_CLEAR, CAIRO_COLOR_TRANSPARENT, clear_region); goto out; } - if (_cairo_operator_bounded (operator) || !clip->surface) + if ((_cairo_operator_bounded (operator) && operator != CAIRO_OPERATOR_SOURCE) || + !clip->surface) { /* For a simple rectangle, we can just use composite(), for more * rectangles, we have to set a clip region. The cost of rasterizing @@ -1330,8 +1437,10 @@ _cairo_surface_clip_and_composite_trapezoids (cairo_pattern_t *src, * worthwhile even if a region is needed. * * If we have a clip surface, we set it as the mask; this only works - * for bounded operators; for unbounded operators, clip and mask - * cannot be interchanged. + * for bounded operators other than SOURCE; for unbounded operators, + * clip and mask cannot be interchanged. For SOURCE, the operator + * as implemented by the backends is different in it's handling + * of the mask then what we want. * * CAIRO_INT_STATUS_UNSUPPORTED will be returned if the region has * more than rectangle and the destination doesn't support clip diff --git a/src/cairo-image-surface.c b/src/cairo-image-surface.c index 1de9402e5..3b59a8b37 100644 --- a/src/cairo-image-surface.c +++ b/src/cairo-image-surface.c @@ -616,7 +616,9 @@ _cairo_image_surface_composite (cairo_operator_t operator, width, height); } - if (!_cairo_operator_bounded (operator)) + if (!_cairo_operator_bounded (operator) || + operator == CAIRO_OPERATOR_SOURCE || + operator == CAIRO_OPERATOR_CLEAR) status = _cairo_surface_composite_fixup_unbounded (&dst->base, &src_attr, src->width, src->height, mask ? &mask_attr : NULL, diff --git a/src/cairo-surface.c b/src/cairo-surface.c index 6ba25a7d2..4621e812d 100644 --- a/src/cairo-surface.c +++ b/src/cairo-surface.c @@ -817,6 +817,13 @@ _cairo_surface_composite (cairo_operator_t operator, { cairo_int_status_t status; + if (mask) { + /* These operators aren't interpreted the same way by the backends; + * they are implemented in terms of other operators in cairo-gstate.c + */ + assert (operator != CAIRO_OPERATOR_SOURCE && operator != CAIRO_OPERATOR_CLEAR); + } + if (dst->status) return dst->status; @@ -1013,7 +1020,7 @@ _fallback_fill_rectangles (cairo_surface_t *surface, * * Applies an operator to a set of rectangles using a solid color * as the source. Note that even if the operator is an unbounded operator - * such as %CAIRO_OPERATOR_CLEAR, only the given set of rectangles + * such as %CAIRO_OPERATOR_IN, only the given set of rectangles * is affected. This differs from _cairo_surface_composite_trapezoids() * where the entire destination rectangle is cleared. * @@ -1152,6 +1159,11 @@ _cairo_surface_composite_trapezoids (cairo_operator_t operator, { cairo_int_status_t status; + /* These operators aren't interpreted the same way by the backends; + * they are implemented in terms of other operators in cairo-gstate.c + */ + assert (operator != CAIRO_OPERATOR_SOURCE && operator != CAIRO_OPERATOR_CLEAR); + if (dst->status) return dst->status; diff --git a/src/cairo-xlib-surface.c b/src/cairo-xlib-surface.c index e778857eb..eafa02a43 100644 --- a/src/cairo-xlib-surface.c +++ b/src/cairo-xlib-surface.c @@ -1140,7 +1140,9 @@ _cairo_xlib_surface_composite (cairo_operator_t operator, width, height); } - if (!_cairo_operator_bounded (operator)) + if (!_cairo_operator_bounded (operator) || + operator == CAIRO_OPERATOR_SOURCE || + operator == CAIRO_OPERATOR_CLEAR) status = _cairo_surface_composite_fixup_unbounded (&dst->base, &src_attr, src->width, src->height, mask ? &mask_attr : NULL, @@ -2517,7 +2519,7 @@ _cairo_xlib_surface_show_glyphs8 (cairo_scaled_font_t *scaled_font, /* Handles clearing the regions that are outside of the temporary * mask created by XRenderCompositeText[N] but should be affected - * by an unbounded operator like CAIRO_OPERATOR_SOURCE. + * by an unbounded operator like CAIRO_OPERATOR_IN */ static cairo_status_t _show_glyphs_fixup_unbounded (cairo_xlib_surface_t *self, diff --git a/test/.cvsignore b/test/.cvsignore index e015ea046..d7bea4c93 100644 --- a/test/.cvsignore +++ b/test/.cvsignore @@ -26,6 +26,8 @@ mask mask-ctm mask-surface-ctm move-to-show-surface +operator-clear +operator-source paint paint-with-alpha path-data diff --git a/test/Makefile.am b/test/Makefile.am index a730ee343..dc3c902c3 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -21,6 +21,8 @@ mask \ mask-ctm \ mask-surface-ctm \ move-to-show-surface \ +operator-clear \ +operator-source \ paint \ paint-with-alpha \ path-data \ @@ -87,6 +89,8 @@ mask-ref.png \ mask-ctm-ref.png \ mask-surface-ctm-ref.png \ move-to-show-surface-ref.png \ +operator-clear-ref.png \ +operator-source-ref.png \ paint-ref.png \ paint-with-alpha-ref.png \ path-data-ref.png \ @@ -188,6 +192,8 @@ mask_LDADD = $(LDADDS) mask_ctm_LDADD = $(LDADDS) mask_surface_ctm_LDADD = $(LDADDS) move_to_show_surface_LDADD = $(LDADDS) +operator_clear_LDADD = $(LDADDS) +operator_source_LDADD = $(LDADDS) paint_LDADD = $(LDADDS) paint_with_alpha_LDADD = $(LDADDS) path_data_LDADD = $(LDADDS) diff --git a/test/clip-operator-ref.png b/test/clip-operator-ref.png Binary files differindex 8a0e18121..1cd0e5be1 100644 --- a/test/clip-operator-ref.png +++ b/test/clip-operator-ref.png diff --git a/test/operator-clear-ref.png b/test/operator-clear-ref.png Binary files differnew file mode 100644 index 000000000..538024a26 --- /dev/null +++ b/test/operator-clear-ref.png diff --git a/test/operator-clear.c b/test/operator-clear.c new file mode 100644 index 000000000..ca6d235ac --- /dev/null +++ b/test/operator-clear.c @@ -0,0 +1,214 @@ +/* + * 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: Kristian Høgsberg <krh@redhat.com> + * Owen Taylor <otaylor@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, 1.0, 0, 0.0); +} + +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_rgba (pattern, 0.2, 1, 0, 0, 1); + cairo_pattern_add_color_stop_rgba (pattern, 0.8, 1, 0, 0, 0.0); + cairo_set_source (cr, pattern); + cairo_pattern_destroy (pattern); +} + +static void +draw_mask (cairo_t *cr, int x, int y) +{ + cairo_surface_t *mask_surface; + cairo_t *cr2; + + double width = (int)(0.9 * WIDTH); + double height = (int)(0.9 * HEIGHT); + x += 0.05 * WIDTH; + y += 0.05 * HEIGHT; + + mask_surface = cairo_surface_create_similar (cairo_get_target (cr), + CAIRO_CONTENT_ALPHA, + width, height); + cr2 = cairo_create (mask_surface); + + cairo_set_source_rgb (cr2, 1, 1, 1); /* white */ + + cairo_arc (cr2, 0.5 * width, 0.5 * height, 0.45 * height, 0, 2 * M_PI); + cairo_fill (cr2); + + cairo_destroy (cr2); + + cairo_mask_surface (cr, mask_surface, x, y); + + cairo_surface_destroy (mask_surface); +} + +static void +draw_glyphs (cairo_t *cr, int x, int y) +{ + cairo_text_extents_t extents; + + cairo_set_font_size (cr, 0.8 * HEIGHT); + + cairo_text_extents (cr, "FG", &extents); + cairo_move_to (cr, + x + (WIDTH - extents.width) / 2 - extents.x_bearing, + y + (HEIGHT - extents.height) / 2 - extents.y_bearing); + cairo_show_text (cr, "FG"); +} + +static void +draw_polygon (cairo_t *cr, int x, int y) +{ + double width = (int)(0.9 * WIDTH); + double height = (int)(0.9 * HEIGHT); + x += 0.05 * WIDTH; + y += 0.05 * HEIGHT; + + 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 +draw_rects (cairo_t *cr, int x, int y) +{ + double block_width = (int)(0.33 * WIDTH + 0.5); + double block_height = (int)(0.33 * HEIGHT + 0.5); + int i, j; + + for (i = 0; i < 3; i++) + for (j = 0; j < 3; j++) + if ((i + j) % 2 == 0) + cairo_rectangle (cr, + x + block_width * i, y + block_height * j, + block_width, block_height); + + cairo_fill (cr); +} + +static void (*pattern_funcs[])(cairo_t *cr, int x, int y) = { + set_solid_pattern, + set_gradient_pattern, +}; + +static void (*draw_funcs[])(cairo_t *cr, int x, int y) = { + draw_mask, + draw_glyphs, + draw_polygon, + draw_rects +}; + +#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) * (HEIGHT + PAD) + PAD) + +static cairo_test_t test = { + "operator-clear", + "Test of CAIRO_OPERATOR_CLEAR", + IMAGE_WIDTH, IMAGE_HEIGHT +}; + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + int i, j, x, y; + cairo_font_options_t *font_options; + cairo_pattern_t *pattern; + + cairo_select_font_face (cr, "Bitstream Vera Sans", + CAIRO_FONT_SLANT_NORMAL, + CAIRO_FONT_WEIGHT_NORMAL); + + font_options = cairo_font_options_create (); + + cairo_font_options_set_hint_style (font_options, CAIRO_HINT_STYLE_NONE); + cairo_font_options_set_antialias (font_options, CAIRO_ANTIALIAS_GRAY); + + cairo_set_font_options (cr, font_options); + cairo_font_options_destroy (font_options); + + for (j = 0; j < ARRAY_SIZE (draw_funcs); j++) { + for (i = 0; i < ARRAY_SIZE (pattern_funcs); i++) { + x = i * (WIDTH + PAD) + PAD; + y = j * (HEIGHT + PAD) + PAD; + + cairo_save (cr); + + pattern = cairo_pattern_create_linear (x + WIDTH, y, + x, y + HEIGHT); + cairo_pattern_add_color_stop_rgba (pattern, 0.2, + 0.0, 0.0, 1.0, 1.0); /* Solid blue */ + cairo_pattern_add_color_stop_rgba (pattern, 0.8, + 0.0, 0.0, 1.0, 0.0); /* Transparent blue */ + cairo_set_source (cr, pattern); + cairo_pattern_destroy (pattern); + + cairo_rectangle (cr, x, y, WIDTH, HEIGHT); + cairo_fill_preserve (cr); + cairo_clip (cr); + + cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR); + pattern_funcs[i] (cr, x, y); + draw_funcs[j] (cr, x, y); + if (cairo_status (cr)) + cairo_test_log ("%d %d HERE!\n", i, j); + + cairo_restore (cr); + } + } + + if (cairo_status (cr) != CAIRO_STATUS_SUCCESS) + cairo_test_log ("%d %d .HERE!\n", i, j); + + return CAIRO_TEST_SUCCESS; +} + +int +main (void) +{ + return cairo_test (&test, draw); +} diff --git a/test/operator-source-ref.png b/test/operator-source-ref.png Binary files differnew file mode 100644 index 000000000..77b6abab8 --- /dev/null +++ b/test/operator-source-ref.png diff --git a/test/operator-source.c b/test/operator-source.c new file mode 100644 index 000000000..26b41f6ad --- /dev/null +++ b/test/operator-source.c @@ -0,0 +1,253 @@ +/* + * 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: Kristian Høgsberg <krh@redhat.com> + * Owen Taylor <otaylor@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, 1.0, 0, 0.0); +} + +static void +set_translucent_pattern (cairo_t *cr, int x, int y) +{ + cairo_set_source_rgba (cr, 1, 0, 0, 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_rgba (pattern, 0.2, 1, 0, 0, 1); + cairo_pattern_add_color_stop_rgba (pattern, 0.8, 1, 0, 0, 0.0); + cairo_set_source (cr, pattern); + cairo_pattern_destroy (pattern); +} + +static void +set_surface_pattern (cairo_t *cr, int x, int y) +{ + cairo_surface_t *source_surface; + cairo_t *cr2; + + double width = (int)(0.6 * WIDTH); + double height = (int)(0.6 * HEIGHT); + x += 0.2 * WIDTH; + y += 0.2 * HEIGHT; + + source_surface = cairo_surface_create_similar (cairo_get_target (cr), + CAIRO_CONTENT_COLOR_ALPHA, + width, height); + cr2 = cairo_create (source_surface); + + cairo_set_source_rgb (cr2, 1, 0, 0); /* red */ + cairo_paint (cr2); + + cairo_set_source_rgb (cr2, 1, 1, 1); /* white */ + + cairo_arc (cr2, 0.5 * width, 0.5 * height, 0.5 * height, 0, 2 * M_PI); + cairo_fill (cr2); + + cairo_destroy (cr2); + + cairo_set_source_surface (cr, source_surface, x, y); + + cairo_surface_destroy (source_surface); +} + +static void +draw_mask (cairo_t *cr, int x, int y) +{ + cairo_surface_t *mask_surface; + cairo_t *cr2; + + double width = (int)(0.9 * WIDTH); + double height = (int)(0.9 * HEIGHT); + x += 0.05 * WIDTH; + y += 0.05 * HEIGHT; + + mask_surface = cairo_surface_create_similar (cairo_get_target (cr), + CAIRO_CONTENT_ALPHA, + width, height); + cr2 = cairo_create (mask_surface); + + cairo_set_source_rgb (cr2, 1, 1, 1); /* white */ + + cairo_arc (cr2, 0.5 * width, 0.5 * height, 0.45 * height, 0, 2 * M_PI); + cairo_fill (cr2); + + cairo_destroy (cr2); + + cairo_mask_surface (cr, mask_surface, x, y); + + cairo_surface_destroy (mask_surface); +} + +static void +draw_glyphs (cairo_t *cr, int x, int y) +{ + cairo_text_extents_t extents; + + cairo_set_font_size (cr, 0.8 * HEIGHT); + + cairo_text_extents (cr, "FG", &extents); + cairo_move_to (cr, + x + (WIDTH - extents.width) / 2 - extents.x_bearing, + y + (HEIGHT - extents.height) / 2 - extents.y_bearing); + cairo_show_text (cr, "FG"); +} + +static void +draw_polygon (cairo_t *cr, int x, int y) +{ + double width = (int)(0.9 * WIDTH); + double height = (int)(0.9 * HEIGHT); + x += 0.05 * WIDTH; + y += 0.05 * HEIGHT; + + 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 +draw_rects (cairo_t *cr, int x, int y) +{ + double block_width = (int)(0.33 * WIDTH + 0.5); + double block_height = (int)(0.33 * HEIGHT + 0.5); + int i, j; + + for (i = 0; i < 3; i++) + for (j = 0; j < 3; j++) + if ((i + j) % 2 == 0) + cairo_rectangle (cr, + x + block_width * i, y + block_height * j, + block_width, block_height); + + cairo_fill (cr); +} + +static void (*pattern_funcs[])(cairo_t *cr, int x, int y) = { + set_solid_pattern, + set_translucent_pattern, + set_gradient_pattern, + set_surface_pattern, +}; + +static void (*draw_funcs[])(cairo_t *cr, int x, int y) = { + draw_mask, + draw_glyphs, + draw_polygon, + draw_rects +}; + +#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) * (HEIGHT + PAD) + PAD) + +static cairo_test_t test = { + "operator-source", + "Test of CAIRO_OPERATOR_SOURCE", + IMAGE_WIDTH, IMAGE_HEIGHT +}; + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + int i, j, x, y; + cairo_font_options_t *font_options; + cairo_pattern_t *pattern; + + cairo_select_font_face (cr, "Bitstream Vera Sans", + CAIRO_FONT_SLANT_NORMAL, + CAIRO_FONT_WEIGHT_NORMAL); + + font_options = cairo_font_options_create (); + + cairo_font_options_set_hint_style (font_options, CAIRO_HINT_STYLE_NONE); + cairo_font_options_set_antialias (font_options, CAIRO_ANTIALIAS_GRAY); + + cairo_set_font_options (cr, font_options); + cairo_font_options_destroy (font_options); + + for (j = 0; j < ARRAY_SIZE (draw_funcs); j++) { + for (i = 0; i < ARRAY_SIZE (pattern_funcs); i++) { + x = i * (WIDTH + PAD) + PAD; + y = j * (HEIGHT + PAD) + PAD; + + cairo_save (cr); + + pattern = cairo_pattern_create_linear (x + WIDTH, y, + x, y + HEIGHT); + cairo_pattern_add_color_stop_rgba (pattern, 0.2, + 0.0, 0.0, 1.0, 1.0); /* Solid blue */ + cairo_pattern_add_color_stop_rgba (pattern, 0.8, + 0.0, 0.0, 1.0, 0.0); /* Transparent blue */ + cairo_set_source (cr, pattern); + cairo_pattern_destroy (pattern); + + cairo_rectangle (cr, x, y, WIDTH, HEIGHT); + cairo_fill_preserve (cr); + cairo_clip (cr); + + cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); + pattern_funcs[i] (cr, x, y); + draw_funcs[j] (cr, x, y); + if (cairo_status (cr)) + cairo_test_log ("%d %d HERE!\n", i, j); + + cairo_restore (cr); + } + } + + if (cairo_status (cr) != CAIRO_STATUS_SUCCESS) + cairo_test_log ("%d %d .HERE!\n", i, j); + + return CAIRO_TEST_SUCCESS; +} + +int +main (void) +{ + return cairo_test (&test, draw); +} diff --git a/test/unbounded-operator-ref.png b/test/unbounded-operator-ref.png Binary files differindex 7e3b3a07c..b197c00ce 100644 --- a/test/unbounded-operator-ref.png +++ b/test/unbounded-operator-ref.png diff --git a/test/unbounded-operator.c b/test/unbounded-operator.c index 45535b976..a053ca3f7 100644 --- a/test/unbounded-operator.c +++ b/test/unbounded-operator.c @@ -124,8 +124,8 @@ static void (*draw_funcs[])(cairo_t *cr, int x, int y) = { }; static cairo_operator_t operators[] = { - CAIRO_OPERATOR_CLEAR, CAIRO_OPERATOR_SOURCE, CAIRO_OPERATOR_IN, - CAIRO_OPERATOR_OUT, CAIRO_OPERATOR_DEST_IN, CAIRO_OPERATOR_DEST_ATOP + CAIRO_OPERATOR_IN, CAIRO_OPERATOR_OUT, + CAIRO_OPERATOR_DEST_IN, CAIRO_OPERATOR_DEST_ATOP }; #define ARRAY_SIZE(a) (sizeof (a) / sizeof ((a)[0])) |