diff --git a/ChangeLog b/ChangeLog index 66f680239..2f48d7f82 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,41 @@ +2005-08-17 Owen Taylor + + * 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 * 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 index 8a0e18121..1cd0e5be1 100644 Binary files a/test/clip-operator-ref.png and b/test/clip-operator-ref.png differ diff --git a/test/operator-clear-ref.png b/test/operator-clear-ref.png new file mode 100644 index 000000000..538024a26 Binary files /dev/null and b/test/operator-clear-ref.png differ 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 + * Owen Taylor + */ + +#include +#include "cairo-test.h" +#include + +#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 new file mode 100644 index 000000000..77b6abab8 Binary files /dev/null and b/test/operator-source-ref.png differ 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 + * Owen Taylor + */ + +#include +#include "cairo-test.h" +#include + +#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 index 7e3b3a07c..b197c00ce 100644 Binary files a/test/unbounded-operator-ref.png and b/test/unbounded-operator-ref.png differ 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]))