diff --git a/src/cairo-image-surface.c b/src/cairo-image-surface.c index 6bbf80cf1..d8d57c638 100644 --- a/src/cairo-image-surface.c +++ b/src/cairo-image-surface.c @@ -936,6 +936,37 @@ _pixman_operator (cairo_operator_t op) return PIXMAN_OP_ADD; case CAIRO_OPERATOR_SATURATE: return PIXMAN_OP_SATURATE; + + case CAIRO_OPERATOR_MULTIPLY: + return PIXMAN_OP_MULTIPLY; + case CAIRO_OPERATOR_SCREEN: + return PIXMAN_OP_SCREEN; + case CAIRO_OPERATOR_OVERLAY: + return PIXMAN_OP_OVERLAY; + case CAIRO_OPERATOR_DARKEN: + return PIXMAN_OP_DARKEN; + case CAIRO_OPERATOR_LIGHTEN: + return PIXMAN_OP_LIGHTEN; + case CAIRO_OPERATOR_COLOR_DODGE: + return PIXMAN_OP_COLOR_DODGE; + case CAIRO_OPERATOR_COLOR_BURN: + return PIXMAN_OP_COLOR_BURN; + case CAIRO_OPERATOR_HARD_LIGHT: + return PIXMAN_OP_HARD_LIGHT; + case CAIRO_OPERATOR_SOFT_LIGHT: + return PIXMAN_OP_SOFT_LIGHT; + case CAIRO_OPERATOR_DIFFERENCE: + return PIXMAN_OP_DIFFERENCE; + case CAIRO_OPERATOR_EXCLUSION: + return PIXMAN_OP_EXCLUSION; + case CAIRO_OPERATOR_HSL_HUE: + return PIXMAN_OP_HSL_HUE; + case CAIRO_OPERATOR_HSL_SATURATION: + return PIXMAN_OP_HSL_SATURATION; + case CAIRO_OPERATOR_HSL_COLOR: + return PIXMAN_OP_HSL_COLOR; + case CAIRO_OPERATOR_HSL_LUMINOSITY: + return PIXMAN_OP_HSL_LUMINOSITY; default: return PIXMAN_OP_OVER; } diff --git a/src/cairo-misc.c b/src/cairo-misc.c index 8d9557e96..56c7d0b5e 100644 --- a/src/cairo-misc.c +++ b/src/cairo-misc.c @@ -334,6 +334,21 @@ _cairo_operator_bounded_by_mask (cairo_operator_t op) case CAIRO_OPERATOR_XOR: case CAIRO_OPERATOR_ADD: case CAIRO_OPERATOR_SATURATE: + case CAIRO_OPERATOR_MULTIPLY: + case CAIRO_OPERATOR_SCREEN: + case CAIRO_OPERATOR_OVERLAY: + case CAIRO_OPERATOR_DARKEN: + case CAIRO_OPERATOR_LIGHTEN: + case CAIRO_OPERATOR_COLOR_DODGE: + case CAIRO_OPERATOR_COLOR_BURN: + case CAIRO_OPERATOR_HARD_LIGHT: + case CAIRO_OPERATOR_SOFT_LIGHT: + case CAIRO_OPERATOR_DIFFERENCE: + case CAIRO_OPERATOR_EXCLUSION: + case CAIRO_OPERATOR_HSL_HUE: + case CAIRO_OPERATOR_HSL_SATURATION: + case CAIRO_OPERATOR_HSL_COLOR: + case CAIRO_OPERATOR_HSL_LUMINOSITY: return TRUE; case CAIRO_OPERATOR_OUT: case CAIRO_OPERATOR_IN: @@ -372,6 +387,21 @@ _cairo_operator_bounded_by_source (cairo_operator_t op) case CAIRO_OPERATOR_XOR: case CAIRO_OPERATOR_ADD: case CAIRO_OPERATOR_SATURATE: + case CAIRO_OPERATOR_MULTIPLY: + case CAIRO_OPERATOR_SCREEN: + case CAIRO_OPERATOR_OVERLAY: + case CAIRO_OPERATOR_DARKEN: + case CAIRO_OPERATOR_LIGHTEN: + case CAIRO_OPERATOR_COLOR_DODGE: + case CAIRO_OPERATOR_COLOR_BURN: + case CAIRO_OPERATOR_HARD_LIGHT: + case CAIRO_OPERATOR_SOFT_LIGHT: + case CAIRO_OPERATOR_DIFFERENCE: + case CAIRO_OPERATOR_EXCLUSION: + case CAIRO_OPERATOR_HSL_HUE: + case CAIRO_OPERATOR_HSL_SATURATION: + case CAIRO_OPERATOR_HSL_COLOR: + case CAIRO_OPERATOR_HSL_LUMINOSITY: return TRUE; case CAIRO_OPERATOR_CLEAR: case CAIRO_OPERATOR_SOURCE: diff --git a/src/cairo.h b/src/cairo.h index 8f7e53388..c2f209caa 100644 --- a/src/cairo.h +++ b/src/cairo.h @@ -422,6 +422,41 @@ cairo_pop_group_to_source (cairo_t *cr); * @CAIRO_OPERATOR_ADD: source and destination layers are accumulated * @CAIRO_OPERATOR_SATURATE: like over, but assuming source and dest are * disjoint geometries + * @CAIRO_OPERATOR_MULTIPLY: source and destination layers are multiplied. + * This causes the result to be at least as dark as the darker inputs. + * @CAIRO_OPERATOR_SCREEN: source and destination are complemented and + * multiplied. This causes the result to be at least as light as the lighter + * inputs. + * @CAIRO_OPERATOR_OVERLAY: multiplies or screens, depending on the + * lightness of the destination color. + * @CAIRO_OPERATOR_DARKEN: replaces the destination with the source if it + * is darker, otherwise keeps the source. + * @CAIRO_OPERATOR_LIGHTEN: replaces the destination with the source if it + * is lighter, otherwise keeps the source. + * @CAIRO_OPERATOR_COLOR_DODGE: brightens the destination color to reflect + * the source color. + * @CAIRO_OPERATOR_COLOR_BURN: darkens the destination color to reflect + * the source color. + * @CAIRO_OPERATOR_HARD_LIGHT: Multiplies or screens, dependant on source + * color. + * @CAIRO_OPERATOR_SOFT_LIGHT: Darkens or lightens, dependant on source + * color. + * @CAIRO_OPERATOR_DIFFERENCE: Takes the difference of the source and + * destination color. + * @CAIRO_OPERATOR_EXCLUSION: Produces an effect similar to difference, but + * with lower contrast. + * @CAIRO_OPERATOR_HSL_HUE: Creates a color with the hue of the source + * and the saturation and luminosity of the target. + * @CAIRO_OPERATOR_HSL_SATURATION: Creates a color with the saturation + * of the source and the hue and luminosity of the target. Painting with + * this mode onto a gray area prduces no change. + * @CAIRO_OPERATOR_HSL_COLOR: Creates a color with the hue and saturation + * of the source and the luminosity of the target. This preserves the gray + * levels of the target and is useful for coloring monochrome images or + * tinting color images. + * @CAIRO_OPERATOR_HSL_LUMINOSITY: Creates a color with the luminosity of + * the source and the hue and saturation of the target. This produces an + * inverse effect to @CAIRO_OPERATOR_HSL_COLOR. * * #cairo_operator_t is used to set the compositing operator for all cairo * drawing operations. @@ -458,7 +493,23 @@ typedef enum _cairo_operator { CAIRO_OPERATOR_XOR, CAIRO_OPERATOR_ADD, - CAIRO_OPERATOR_SATURATE + CAIRO_OPERATOR_SATURATE, + + CAIRO_OPERATOR_MULTIPLY, + CAIRO_OPERATOR_SCREEN, + CAIRO_OPERATOR_OVERLAY, + CAIRO_OPERATOR_DARKEN, + CAIRO_OPERATOR_LIGHTEN, + CAIRO_OPERATOR_COLOR_DODGE, + CAIRO_OPERATOR_COLOR_BURN, + CAIRO_OPERATOR_HARD_LIGHT, + CAIRO_OPERATOR_SOFT_LIGHT, + CAIRO_OPERATOR_DIFFERENCE, + CAIRO_OPERATOR_EXCLUSION, + CAIRO_OPERATOR_HSL_HUE, + CAIRO_OPERATOR_HSL_SATURATION, + CAIRO_OPERATOR_HSL_COLOR, + CAIRO_OPERATOR_HSL_LUMINOSITY } cairo_operator_t; cairo_public void diff --git a/test/Makefile.am b/test/Makefile.am index 81add8c88..68b9325b6 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -308,6 +308,10 @@ REFERENCE_IMAGES = \ device-offset.ref.png \ device-offset.rgb24.ref.png \ device-offset-scale.ref.png \ + extended-blend.argb32.ref.png \ + extended-blend.rgb24.ref.png \ + extended-blend-alpha.argb32.ref.png \ + extended-blend-alpha.rgb24.ref.png \ extend-pad-border.ref.png \ extend-pad.ref.png \ extend-pad.ps.ref.png \ diff --git a/test/Makefile.sources b/test/Makefile.sources index e37b3e811..740982093 100644 --- a/test/Makefile.sources +++ b/test/Makefile.sources @@ -55,6 +55,8 @@ test_sources = \ extend-reflect-similar.c \ extend-repeat.c \ extend-repeat-similar.c \ + extended-blend.c \ + extended-blend-alpha.c \ fill-alpha.c \ fill-alpha-pattern.c \ fill-and-stroke.c \ diff --git a/test/extended-blend-alpha.argb32.ref.png b/test/extended-blend-alpha.argb32.ref.png new file mode 100644 index 000000000..3ecd61870 Binary files /dev/null and b/test/extended-blend-alpha.argb32.ref.png differ diff --git a/test/extended-blend-alpha.c b/test/extended-blend-alpha.c new file mode 100644 index 000000000..e0316f35f --- /dev/null +++ b/test/extended-blend-alpha.c @@ -0,0 +1,115 @@ +/* + * Copyright © 2005 Red Hat, Inc. + * Copyright © 2007 Emmanuel Pacaud + * Copyright © 2008 Benjamin Otte + * + * 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: Owen Taylor + * Kristian Høgsberg + * Emmanuel Pacaud + */ + +#include +#include "cairo-test.h" +#include + +#define STEPS 16 +#define START_OPERATOR CAIRO_OPERATOR_MULTIPLY +#define STOP_OPERATOR CAIRO_OPERATOR_HSL_LUMINOSITY + +static void +create_patterns (cairo_t *bg, cairo_t *fg) +{ + int x; + + for (x = 0; x < STEPS; x++) { + /* draw a yellow background fading in using discrete steps */ + cairo_set_source_rgba (bg, 1, 1, 0, (double) x / (STEPS - 1)); + cairo_rectangle (bg, x, 0, 1, STEPS); + cairo_fill (bg); + + /* draw an orthogonal teal pattern fading in using discrete steps */ + cairo_set_source_rgba (fg, 0, 1, 1, (double) x / (STEPS - 1)); + cairo_rectangle (fg, 0, x, STEPS, 1); + cairo_fill (fg); + } +} + +/* expects a STEP*STEP pixel rectangle */ +static void +do_blend (cairo_t *cr, cairo_operator_t op, cairo_surface_t *bg, cairo_surface_t *fg) +{ + /* not using CAIRO_OPERATOR_SOURCE here, it triggers a librsvg bug */ + cairo_set_operator (cr, CAIRO_OPERATOR_OVER); + cairo_set_source_surface (cr, bg, 0, 0); + cairo_paint (cr); + + cairo_set_operator (cr, op); + cairo_set_source_surface (cr, fg, 0, 0); + cairo_paint (cr); +} + +#define SIZE 5 +#define COUNT 4 +#define FULL_WIDTH ((STEPS + 1) * COUNT - 1) +#define FULL_HEIGHT ((COUNT + STOP_OPERATOR - START_OPERATOR) / COUNT) * (STEPS + 1) + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + size_t i = 0; + cairo_operator_t op; + cairo_t *bgcr, *fgcr; + cairo_surface_t *bg, *fg; + + bg = cairo_surface_create_similar (cairo_get_target (cr), + CAIRO_CONTENT_COLOR_ALPHA, SIZE * STEPS, SIZE * STEPS); + fg = cairo_surface_create_similar (cairo_get_target (cr), + CAIRO_CONTENT_COLOR_ALPHA, SIZE * STEPS, SIZE * STEPS); + bgcr = cairo_create (bg); + fgcr = cairo_create (fg); + cairo_scale (bgcr, SIZE, SIZE); + cairo_scale (fgcr, SIZE, SIZE); + create_patterns (bgcr, fgcr); + cairo_destroy (bgcr); + cairo_destroy (fgcr); + + for (op = START_OPERATOR; op <= STOP_OPERATOR; op++, i++) { + cairo_save (cr); + cairo_translate (cr, + SIZE * (STEPS + 1) * (i % COUNT), + SIZE * (STEPS + 1) * (i / COUNT)); + do_blend (cr, op, bg, fg); + cairo_restore (cr); + } + + cairo_surface_destroy (fg); + cairo_surface_destroy (bg); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (extended_blend_alpha, + "Tests extended blend modes with alpha", + "operator", /* keywords */ + NULL, /* requirements */ + FULL_WIDTH * SIZE, FULL_HEIGHT * SIZE, + NULL, draw) diff --git a/test/extended-blend-alpha.rgb24.ref.png b/test/extended-blend-alpha.rgb24.ref.png new file mode 100644 index 000000000..f62dda959 Binary files /dev/null and b/test/extended-blend-alpha.rgb24.ref.png differ diff --git a/test/extended-blend.argb32.ref.png b/test/extended-blend.argb32.ref.png new file mode 100644 index 000000000..083fe8737 Binary files /dev/null and b/test/extended-blend.argb32.ref.png differ diff --git a/test/extended-blend.c b/test/extended-blend.c new file mode 100644 index 000000000..cd2b06b99 --- /dev/null +++ b/test/extended-blend.c @@ -0,0 +1,117 @@ +/* + * Copyright © 2005 Red Hat, Inc. + * Copyright © 2007 Emmanuel Pacaud + * Copyright © 2008 Benjamin Otte + * + * 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: Owen Taylor + * Kristian Høgsberg + * Emmanuel Pacaud + */ + +#include +#include "cairo-test.h" +#include + +#define STEPS 16 +#define START_OPERATOR CAIRO_OPERATOR_MULTIPLY +#define STOP_OPERATOR CAIRO_OPERATOR_HSL_LUMINOSITY + +static void +create_patterns (cairo_t *bg, cairo_t *fg) +{ + int x; + + for (x = 0; x < STEPS; x++) { + double i = (double) x / (STEPS - 1); + /* draw a yellow background fading in using discrete steps */ + cairo_set_source_rgba (bg, i, i, 0, 1); + cairo_rectangle (bg, x, 0, 1, STEPS); + cairo_fill (bg); + + /* draw an orthogonal teal pattern fading in using discrete steps */ + cairo_set_source_rgba (fg, 0, i, i, 1); + cairo_rectangle (fg, 0, x, STEPS, 1); + cairo_fill (fg); + } +} + +/* expects a STEP*STEP pixel rectangle */ +static void +do_blend (cairo_t *cr, cairo_operator_t op, cairo_surface_t *bg, cairo_surface_t *fg) +{ + /* not using CAIRO_OPERATOR_SOURCE here, it triggers a librsvg bug */ + cairo_set_operator (cr, CAIRO_OPERATOR_OVER); + cairo_set_source_surface (cr, bg, 0, 0); + cairo_paint (cr); + + cairo_set_operator (cr, op); + cairo_set_source_surface (cr, fg, 0, 0); + cairo_paint (cr); +} + +#define SIZE 5 +#define COUNT 4 +#define FULL_WIDTH ((STEPS + 1) * COUNT - 1) +#define FULL_HEIGHT ((COUNT + STOP_OPERATOR - START_OPERATOR) / COUNT) * (STEPS + 1) + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + size_t i = 0; + cairo_operator_t op; + cairo_t *bgcr, *fgcr; + cairo_surface_t *bg, *fg; + + bg = cairo_surface_create_similar (cairo_get_target (cr), + CAIRO_CONTENT_COLOR_ALPHA, SIZE * STEPS, SIZE * STEPS); + fg = cairo_surface_create_similar (cairo_get_target (cr), + CAIRO_CONTENT_COLOR_ALPHA, SIZE * STEPS, SIZE * STEPS); + bgcr = cairo_create (bg); + fgcr = cairo_create (fg); + cairo_scale (bgcr, SIZE, SIZE); + cairo_scale (fgcr, SIZE, SIZE); + create_patterns (bgcr, fgcr); + cairo_destroy (bgcr); + cairo_destroy (fgcr); + + for (op = START_OPERATOR; op <= STOP_OPERATOR; op++, i++) { + cairo_save (cr); + cairo_translate (cr, + SIZE * (STEPS + 1) * (i % COUNT), + SIZE * (STEPS + 1) * (i / COUNT)); + do_blend (cr, op, bg, fg); + cairo_restore (cr); + } + + cairo_surface_destroy (fg); + cairo_surface_destroy (bg); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (extended_blend, + "Tests extended blend modes without alpha", + "operator", /* keywords */ + NULL, /* requirements */ + FULL_WIDTH * SIZE, FULL_HEIGHT * SIZE, + NULL, draw) + diff --git a/test/extended-blend.rgb24.ref.png b/test/extended-blend.rgb24.ref.png new file mode 100644 index 000000000..53c1b226c Binary files /dev/null and b/test/extended-blend.rgb24.ref.png differ