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.
This commit is contained in:
Owen Taylor 2005-08-18 15:50:36 +00:00
parent ff9654e677
commit 31341327bf
16 changed files with 706 additions and 63 deletions

View file

@ -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

View file

@ -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;

View file

@ -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)

View file

@ -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

View file

@ -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,

View file

@ -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;

View file

@ -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,

View file

@ -26,6 +26,8 @@ mask
mask-ctm
mask-surface-ctm
move-to-show-surface
operator-clear
operator-source
paint
paint-with-alpha
path-data

View file

@ -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)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB

After

Width:  |  Height:  |  Size: 36 KiB

BIN
test/operator-clear-ref.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

214
test/operator-clear.c Normal file
View file

@ -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);
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

253
test/operator-source.c Normal file
View file

@ -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);
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 12 KiB

View file

@ -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]))