diff options
Diffstat (limited to 'pixman/test/composite.c')
-rw-r--r-- | pixman/test/composite.c | 901 |
1 files changed, 901 insertions, 0 deletions
diff --git a/pixman/test/composite.c b/pixman/test/composite.c new file mode 100644 index 000000000..0624cd37d --- /dev/null +++ b/pixman/test/composite.c @@ -0,0 +1,901 @@ +/* + * Copyright © 2005 Eric Anholt + * Copyright © 2009 Chris Wilson + * + * 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 Eric Anholt not be used in + * advertising or publicity pertaining to distribution of the software without + * specific, written prior permission. Eric Anholt makes no + * representations about the suitability of this software for any purpose. It + * is provided "as is" without express or implied warranty. + * + * ERIC ANHOLT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL ERIC ANHOLT 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. + */ + +#include <pixman.h> +#include <stdio.h> +#include <stdlib.h> /* abort() */ +#include <math.h> +#include <config.h> + +#define FALSE 0 +#define TRUE !FALSE + +#define ARRAY_LENGTH(A) ((int) (sizeof (A) / sizeof ((A) [0]))) +#define min(a,b) ((a) <= (b) ? (a) : (b)) +#define max(a,b) ((a) >= (b) ? (a) : (b)) + +typedef struct color_t color_t; +typedef struct format_t format_t; +typedef struct image_t image_t; +typedef struct operator_t operator_t; + +struct color_t +{ + double r, g, b, a; +}; + +struct format_t +{ + pixman_format_code_t format; + const char *name; +}; + +static color_t colors[] = +{ + /* these are premultiplied in main() */ + { 1.0, 1.0, 1.0, 1.0 }, + { 1.0, 0.0, 0.0, 1.0 }, + { 0.0, 1.0, 0.0, 1.0 }, + { 0.0, 0.0, 1.0, 1.0 }, + { 0.0, 0.0, 0.0, 1.0 }, + { 0.5, 0.0, 0.0, 0.5 }, +}; + +static uint16_t +_color_double_to_short (double d) +{ + uint32_t i; + + i = (uint32_t) (d * 65536); + i -= (i >> 16); + + return i; +} + +static void +compute_pixman_color (const color_t *color, + pixman_color_t *out) +{ + out->red = _color_double_to_short (color->r); + out->green = _color_double_to_short (color->g); + out->blue = _color_double_to_short (color->b); + out->alpha = _color_double_to_short (color->a); +} + +static const format_t formats[] = +{ +#define P(x) { PIXMAN_##x, #x } + P(a8), + + /* 32bpp formats */ + P(a8r8g8b8), + P(x8r8g8b8), + P(a8b8g8r8), + P(x8b8g8r8), + P(b8g8r8a8), + P(b8g8r8x8), + + /* XXX: and here the errors begin! */ +#if 0 + P(x2r10g10b10), + P(a2r10g10b10), + P(x2b10g10r10), + P(a2b10g10r10), + + /* 24bpp formats */ + P(r8g8b8), + P(b8g8r8), + + /* 16bpp formats */ + P(r5g6b5), + P(b5g6r5), + + P(a1r5g5b5), + P(x1r5g5b5), + P(a1b5g5r5), + P(x1b5g5r5), + P(a4r4g4b4), + P(x4r4g4b4), + P(a4b4g4r4), + P(x4b4g4r4), + + /* 8bpp formats */ + P(a8), + P(r3g3b2), + P(b2g3r3), + P(a2r2g2b2), + P(a2b2g2r2), + + P(x4a4), + + /* 4bpp formats */ + P(a4), + P(r1g2b1), + P(b1g2r1), + P(a1r1g1b1), + P(a1b1g1r1), + + /* 1bpp formats */ + P(a1) +#endif +#undef P +}; + +struct image_t +{ + pixman_image_t *image; + const format_t *format; + const color_t *color; + pixman_repeat_t repeat; + int size; +}; + +struct operator_t +{ + pixman_op_t op; + const char *name; +}; + +static const operator_t operators[] = +{ +#define P(x) { PIXMAN_OP_##x, #x } + P(CLEAR), + P(SRC), + P(DST), + P(OVER), + P(OVER_REVERSE), + P(IN), + P(IN_REVERSE), + P(OUT), + P(OUT_REVERSE), + P(ATOP), + P(ATOP_REVERSE), + P(XOR), + P(ADD), + P(SATURATE), + + P(DISJOINT_CLEAR), + P(DISJOINT_SRC), + P(DISJOINT_DST), + P(DISJOINT_OVER), + P(DISJOINT_OVER_REVERSE), + P(DISJOINT_IN), + P(DISJOINT_IN_REVERSE), + P(DISJOINT_OUT), + P(DISJOINT_OUT_REVERSE), + P(DISJOINT_ATOP), + P(DISJOINT_ATOP_REVERSE), + P(DISJOINT_XOR), + + P(CONJOINT_CLEAR), + P(CONJOINT_SRC), + P(CONJOINT_DST), + P(CONJOINT_OVER), + P(CONJOINT_OVER_REVERSE), + P(CONJOINT_IN), + P(CONJOINT_IN_REVERSE), + P(CONJOINT_OUT), + P(CONJOINT_OUT_REVERSE), + P(CONJOINT_ATOP), + P(CONJOINT_ATOP_REVERSE), + P(CONJOINT_XOR), +#undef P +}; + +static double +calc_op (pixman_op_t op, double src, double dst, double srca, double dsta) +{ +#define mult_chan(src, dst, Fa, Fb) min ((src) * (Fa) + (dst) * (Fb), 1.0) + + double Fa, Fb; + + switch (op) + { + case PIXMAN_OP_CLEAR: + case PIXMAN_OP_DISJOINT_CLEAR: + case PIXMAN_OP_CONJOINT_CLEAR: + return mult_chan (src, dst, 0.0, 0.0); + + case PIXMAN_OP_SRC: + case PIXMAN_OP_DISJOINT_SRC: + case PIXMAN_OP_CONJOINT_SRC: + return mult_chan (src, dst, 1.0, 0.0); + + case PIXMAN_OP_DST: + case PIXMAN_OP_DISJOINT_DST: + case PIXMAN_OP_CONJOINT_DST: + return mult_chan (src, dst, 0.0, 1.0); + + case PIXMAN_OP_OVER: + return mult_chan (src, dst, 1.0, 1.0 - srca); + + case PIXMAN_OP_OVER_REVERSE: + return mult_chan (src, dst, 1.0 - dsta, 1.0); + + case PIXMAN_OP_IN: + return mult_chan (src, dst, dsta, 0.0); + + case PIXMAN_OP_IN_REVERSE: + return mult_chan (src, dst, 0.0, srca); + + case PIXMAN_OP_OUT: + return mult_chan (src, dst, 1.0 - dsta, 0.0); + + case PIXMAN_OP_OUT_REVERSE: + return mult_chan (src, dst, 0.0, 1.0 - srca); + + case PIXMAN_OP_ATOP: + return mult_chan (src, dst, dsta, 1.0 - srca); + + case PIXMAN_OP_ATOP_REVERSE: + return mult_chan (src, dst, 1.0 - dsta, srca); + + case PIXMAN_OP_XOR: + return mult_chan (src, dst, 1.0 - dsta, 1.0 - srca); + + case PIXMAN_OP_ADD: + return mult_chan (src, dst, 1.0, 1.0); + + case PIXMAN_OP_SATURATE: + case PIXMAN_OP_DISJOINT_OVER_REVERSE: + if (srca == 0.0) + Fa = 1.0; + else + Fa = min (1.0, (1.0 - dsta) / srca); + return mult_chan (src, dst, Fa, 1.0); + + case PIXMAN_OP_DISJOINT_OVER: + if (dsta == 0.0) + Fb = 1.0; + else + Fb = min (1.0, (1.0 - srca) / dsta); + return mult_chan (src, dst, 1.0, Fb); + + case PIXMAN_OP_DISJOINT_IN: + if (srca == 0.0) + Fa = 0.0; + else + Fa = max (0.0, 1.0 - (1.0 - dsta) / srca); + return mult_chan (src, dst, Fa, 0.0); + + case PIXMAN_OP_DISJOINT_IN_REVERSE: + if (dsta == 0.0) + Fb = 0.0; + else + Fb = max (0.0, 1.0 - (1.0 - srca) / dsta); + return mult_chan (src, dst, 0.0, Fb); + + case PIXMAN_OP_DISJOINT_OUT: + if (srca == 0.0) + Fa = 1.0; + else + Fa = min (1.0, (1.0 - dsta) / srca); + return mult_chan (src, dst, Fa, 0.0); + + case PIXMAN_OP_DISJOINT_OUT_REVERSE: + if (dsta == 0.0) + Fb = 1.0; + else + Fb = min (1.0, (1.0 - srca) / dsta); + return mult_chan (src, dst, 0.0, Fb); + + case PIXMAN_OP_DISJOINT_ATOP: + if (srca == 0.0) + Fa = 0.0; + else + Fa = max (0.0, 1.0 - (1.0 - dsta) / srca); + if (dsta == 0.0) + Fb = 1.0; + else + Fb = min (1.0, (1.0 - srca) / dsta); + return mult_chan (src, dst, Fa, Fb); + + case PIXMAN_OP_DISJOINT_ATOP_REVERSE: + if (srca == 0.0) + Fa = 1.0; + else + Fa = min (1.0, (1.0 - dsta) / srca); + if (dsta == 0.0) + Fb = 0.0; + else + Fb = max (0.0, 1.0 - (1.0 - srca) / dsta); + return mult_chan (src, dst, Fa, Fb); + + case PIXMAN_OP_DISJOINT_XOR: + if (srca == 0.0) + Fa = 1.0; + else + Fa = min (1.0, (1.0 - dsta) / srca); + if (dsta == 0.0) + Fb = 1.0; + else + Fb = min (1.0, (1.0 - srca) / dsta); + return mult_chan (src, dst, Fa, Fb); + + case PIXMAN_OP_CONJOINT_OVER: + if (dsta == 0.0) + Fb = 0.0; + else + Fb = max (0.0, 1.0 - srca / dsta); + return mult_chan (src, dst, 1.0, Fb); + + case PIXMAN_OP_CONJOINT_OVER_REVERSE: + if (srca == 0.0) + Fa = 0.0; + else + Fa = max (0.0, 1.0 - dsta / srca); + return mult_chan (src, dst, Fa, 1.0); + + case PIXMAN_OP_CONJOINT_IN: + if (srca == 0.0) + Fa = 1.0; + else + Fa = min (1.0, dsta / srca); + return mult_chan (src, dst, Fa, 0.0); + + case PIXMAN_OP_CONJOINT_IN_REVERSE: + if (dsta == 0.0) + Fb = 1.0; + else + Fb = min (1.0, srca / dsta); + return mult_chan (src, dst, 0.0, Fb); + + case PIXMAN_OP_CONJOINT_OUT: + if (srca == 0.0) + Fa = 0.0; + else + Fa = max (0.0, 1.0 - dsta / srca); + return mult_chan (src, dst, Fa, 0.0); + + case PIXMAN_OP_CONJOINT_OUT_REVERSE: + if (dsta == 0.0) + Fb = 0.0; + else + Fb = max (0.0, 1.0 - srca / dsta); + return mult_chan (src, dst, 0.0, Fb); + + case PIXMAN_OP_CONJOINT_ATOP: + if (srca == 0.0) + Fa = 1.0; + else + Fa = min (1.0, dsta / srca); + if (dsta == 0.0) + Fb = 0.0; + else + Fb = max (0.0, 1.0 - srca / dsta); + return mult_chan (src, dst, Fa, Fb); + + case PIXMAN_OP_CONJOINT_ATOP_REVERSE: + if (srca == 0.0) + Fa = 0.0; + else + Fa = max (0.0, 1.0 - dsta / srca); + if (dsta == 0.0) + Fb = 1.0; + else + Fb = min (1.0, srca / dsta); + return mult_chan (src, dst, Fa, Fb); + + case PIXMAN_OP_CONJOINT_XOR: + if (srca == 0.0) + Fa = 0.0; + else + Fa = max (0.0, 1.0 - dsta / srca); + if (dsta == 0.0) + Fb = 0.0; + else + Fb = max (0.0, 1.0 - srca / dsta); + return mult_chan (src, dst, Fa, Fb); + + case PIXMAN_OP_MULTIPLY: + case PIXMAN_OP_SCREEN: + case PIXMAN_OP_OVERLAY: + case PIXMAN_OP_DARKEN: + case PIXMAN_OP_LIGHTEN: + case PIXMAN_OP_COLOR_DODGE: + case PIXMAN_OP_COLOR_BURN: + case PIXMAN_OP_HARD_LIGHT: + case PIXMAN_OP_SOFT_LIGHT: + case PIXMAN_OP_DIFFERENCE: + case PIXMAN_OP_EXCLUSION: + case PIXMAN_OP_HSL_HUE: + case PIXMAN_OP_HSL_SATURATION: + case PIXMAN_OP_HSL_COLOR: + case PIXMAN_OP_HSL_LUMINOSITY: + default: + abort(); + } +#undef mult_chan +} + +static void +do_composite (pixman_op_t op, + const color_t *src, + const color_t *mask, + const color_t *dst, + color_t *result, + pixman_bool_t component_alpha) +{ + color_t srcval, srcalpha; + + if (mask == NULL) + { + srcval = *src; + + srcalpha.r = src->a; + srcalpha.g = src->a; + srcalpha.b = src->a; + srcalpha.a = src->a; + } + else if (component_alpha) + { + srcval.r = src->r * mask->r; + srcval.g = src->g * mask->g; + srcval.b = src->b * mask->b; + srcval.a = src->a * mask->a; + + srcalpha.r = src->a * mask->r; + srcalpha.g = src->a * mask->g; + srcalpha.b = src->a * mask->b; + srcalpha.a = src->a * mask->a; + } + else + { + srcval.r = src->r * mask->a; + srcval.g = src->g * mask->a; + srcval.b = src->b * mask->a; + srcval.a = src->a * mask->a; + + srcalpha.r = src->a * mask->a; + srcalpha.g = src->a * mask->a; + srcalpha.b = src->a * mask->a; + srcalpha.a = src->a * mask->a; + } + + result->r = calc_op (op, srcval.r, dst->r, srcalpha.r, dst->a); + result->g = calc_op (op, srcval.g, dst->g, srcalpha.g, dst->a); + result->b = calc_op (op, srcval.b, dst->b, srcalpha.b, dst->a); + result->a = calc_op (op, srcval.a, dst->a, srcalpha.a, dst->a); +} + +static void +color_correct (pixman_format_code_t format, + color_t *color) +{ +#define round_pix(pix, mask) \ + ((int)((pix) * (mask) + .5) / (double) (mask)) + + if (PIXMAN_FORMAT_R (format) == 0) + { + color->r = 0.0; + color->g = 0.0; + color->b = 0.0; + } + else + { + color->r = round_pix (color->r, PIXMAN_FORMAT_R (format)); + color->g = round_pix (color->g, PIXMAN_FORMAT_G (format)); + color->b = round_pix (color->b, PIXMAN_FORMAT_B (format)); + } + + if (PIXMAN_FORMAT_A (format) == 0) + color->a = 1.0; + else + color->a = round_pix (color->a, PIXMAN_FORMAT_A (format)); + +#undef round_pix +} + +static void +get_pixel (pixman_image_t *image, + pixman_format_code_t format, + color_t *color) +{ +#define MASK(N) ((1UL << (N))-1) + + unsigned long rs, gs, bs, as; + int a, r, g, b; + unsigned long val; + + val = *(unsigned long *) pixman_image_get_data (image); +#ifdef WORDS_BIGENDIAN + val >>= 8 * sizeof(val) - PIXMAN_FORMAT_BPP (format); +#endif + + /* Number of bits in each channel */ + a = PIXMAN_FORMAT_A (format); + r = PIXMAN_FORMAT_R (format); + g = PIXMAN_FORMAT_G (format); + b = PIXMAN_FORMAT_B (format); + + switch (PIXMAN_FORMAT_TYPE (format)) + { + case PIXMAN_TYPE_ARGB: + bs = 0; + gs = b + bs; + rs = g + gs; + as = r + rs; + break; + + case PIXMAN_TYPE_ABGR: + rs = 0; + gs = r + rs; + bs = g + gs; + as = b + bs; + break; + + case PIXMAN_TYPE_BGRA: + as = 0; + rs = PIXMAN_FORMAT_BPP (format) - (b + g + r); + gs = r + rs; + bs = g + gs; + break; + + case PIXMAN_TYPE_A: + as = 0; + rs = 0; + gs = 0; + bs = 0; + break; + + case PIXMAN_TYPE_OTHER: + case PIXMAN_TYPE_COLOR: + case PIXMAN_TYPE_GRAY: + case PIXMAN_TYPE_YUY2: + case PIXMAN_TYPE_YV12: + default: + abort (); + as = 0; + rs = 0; + gs = 0; + bs = 0; + break; + } + + if (MASK (a) != 0) + color->a = ((val >> as) & MASK (a)) / (double) MASK (a); + else + color->a = 1.0; + + if (MASK (r) != 0) + { + color->r = ((val >> rs) & MASK (r)) / (double) MASK (r); + color->g = ((val >> gs) & MASK (g)) / (double) MASK (g); + color->b = ((val >> bs) & MASK (b)) / (double) MASK (b); + } + else + { + color->r = 0.0; + color->g = 0.0; + color->b = 0.0; + } + +#undef MASK +} + +static double +eval_diff (color_t *expected, color_t *test) +{ + double rscale, gscale, bscale, ascale; + double rdiff, gdiff, bdiff, adiff; + + /* XXX: Need to be provided mask shifts so we can produce useful error + * values. + */ + rscale = 1.0 * (1 << 5); + gscale = 1.0 * (1 << 6); + bscale = 1.0 * (1 << 5); + ascale = 1.0 * 32; + + rdiff = fabs (test->r - expected->r) * rscale; + bdiff = fabs (test->g - expected->g) * gscale; + gdiff = fabs (test->b - expected->b) * bscale; + adiff = fabs (test->a - expected->a) * ascale; + + return max (max (max (rdiff, gdiff), bdiff), adiff); +} + +static char * +describe_image (image_t *info, char *buf, int buflen) +{ + if (info->size) + { + snprintf (buf, buflen, "%s %dx%d%s", + info->format->name, + info->size, info->size, + info->repeat ? "R" :""); + } + else + { + snprintf (buf, buflen, "solid"); + } + + return buf; +} + +/* Test a composite of a given operation, source, mask, and destination + * picture. + * Fills the window, and samples from the 0,0 pixel corner. + */ +static pixman_bool_t +composite_test (image_t *dst, + const operator_t *op, + image_t *src, + image_t *mask, + pixman_bool_t component_alpha) +{ + pixman_color_t fill; + pixman_rectangle16_t rect; + color_t expected, result, tdst, tsrc, tmsk; + double diff; + pixman_bool_t success = TRUE; + + compute_pixman_color (dst->color, &fill); + rect.x = rect.y = 0; + rect.width = rect.height = dst->size; + pixman_image_fill_rectangles (PIXMAN_OP_SRC, dst->image, + &fill, 1, &rect); + + if (mask != NULL) + { + pixman_image_set_component_alpha (mask->image, component_alpha); + pixman_image_composite (op->op, src->image, mask->image, dst->image, + 0, 0, + 0, 0, + 0, 0, + dst->size, dst->size); + + tmsk = *mask->color; + if (mask->size) + { + color_correct (mask->format->format, &tmsk); + + if (component_alpha && + PIXMAN_FORMAT_R (mask->format->format) == 0) + { + /* Ax component-alpha masks expand alpha into + * all color channels. + */ + tmsk.r = tmsk.g = tmsk.b = tmsk.a; + } + } + } + else + { + pixman_image_composite (op->op, src->image, NULL, dst->image, + 0, 0, + 0, 0, + 0, 0, + dst->size, dst->size); + } + get_pixel (dst->image, dst->format->format, &result); + + tdst = *dst->color; + color_correct (dst->format->format, &tdst); + tsrc = *src->color; + if (src->size) + color_correct (src->format->format, &tsrc); + do_composite (op->op, &tsrc, mask ? &tmsk : NULL, &tdst, + &expected, component_alpha); + color_correct (dst->format->format, &expected); + + diff = eval_diff (&expected, &result); + if (diff > 3.0) + { + char buf[40]; + + snprintf (buf, sizeof (buf), + "%s %scomposite", + op->name, + component_alpha ? "CA " : ""); + + printf ("%s test error of %.4f --\n" + " R G B A\n" + "got: %.2f %.2f %.2f %.2f [%08lx]\n" + "expected: %.2f %.2f %.2f %.2f\n", + buf, diff, + result.r, result.g, result.b, result.a, + *(unsigned long *) pixman_image_get_data (dst->image), + expected.r, expected.g, expected.b, expected.a); + + if (mask != NULL) + { + printf ("src color: %.2f %.2f %.2f %.2f\n" + "msk color: %.2f %.2f %.2f %.2f\n" + "dst color: %.2f %.2f %.2f %.2f\n", + src->color->r, src->color->g, + src->color->b, src->color->a, + mask->color->r, mask->color->g, + mask->color->b, mask->color->a, + dst->color->r, dst->color->g, + dst->color->b, dst->color->a); + printf ("src: %s, ", describe_image (src, buf, sizeof (buf))); + printf ("mask: %s, ", describe_image (mask, buf, sizeof (buf))); + printf ("dst: %s\n\n", describe_image (dst, buf, sizeof (buf))); + } + else + { + printf ("src color: %.2f %.2f %.2f %.2f\n" + "dst color: %.2f %.2f %.2f %.2f\n", + src->color->r, src->color->g, + src->color->b, src->color->a, + dst->color->r, dst->color->g, + dst->color->b, dst->color->a); + printf ("src: %s, ", describe_image (src, buf, sizeof (buf))); + printf ("dst: %s\n\n", describe_image (dst, buf, sizeof (buf))); + } + + success = FALSE; + } + + return success; +} + +#define REPEAT 0x01000000 +#define FLAGS 0xff000000 + +static void +image_init (image_t *info, + int color, + int format, + int size) +{ + pixman_color_t fill; + + info->color = &colors[color]; + compute_pixman_color (info->color, &fill); + + info->format = &formats[format]; + info->size = size & ~FLAGS; + info->repeat = PIXMAN_REPEAT_NONE; + + if (info->size) + { + pixman_rectangle16_t rect; + + info->image = pixman_image_create_bits (info->format->format, + info->size, info->size, + NULL, 0); + + rect.x = rect.y = 0; + rect.width = rect.height = info->size; + pixman_image_fill_rectangles (PIXMAN_OP_SRC, info->image, &fill, + 1, &rect); + + if (size & REPEAT) + { + pixman_image_set_repeat (info->image, PIXMAN_REPEAT_NORMAL); + info->repeat = PIXMAN_REPEAT_NORMAL; + } + } + else + { + info->image = pixman_image_create_solid_fill (&fill); + } +} + +static void +image_fini (image_t *info) +{ + pixman_image_unref (info->image); +} + +int +main (void) +{ + pixman_bool_t ok, group_ok = TRUE, ca; + int i, d, m, s; + int tests_passed = 0, tests_total = 0; + int sizes[] = { 1, 1 | REPEAT, 10 }; + int num_tests; + + for (i = 0; i < ARRAY_LENGTH (colors); i++) + { + colors[i].r *= colors[i].a; + colors[i].g *= colors[i].a; + colors[i].b *= colors[i].a; + } + + num_tests = ARRAY_LENGTH (colors) * ARRAY_LENGTH (formats); + + for (d = 0; d < num_tests; d++) + { + image_t dst; + + image_init ( + &dst, d / ARRAY_LENGTH (formats), d % ARRAY_LENGTH (formats), 1); + + + for (s = -ARRAY_LENGTH (colors); + s < ARRAY_LENGTH (sizes) * num_tests; + s++) + { + image_t src; + + if (s < 0) + { + image_init (&src, -s - 1, 0, 0); + } + else + { + image_init (&src, + s / ARRAY_LENGTH (sizes) / ARRAY_LENGTH (formats), + s / ARRAY_LENGTH (sizes) % ARRAY_LENGTH (formats), + sizes[s % ARRAY_LENGTH (sizes)]); + } + + for (m = -ARRAY_LENGTH (colors); + m < ARRAY_LENGTH (sizes) * num_tests; + m++) + { + image_t mask; + + if (m < 0) + { + image_init (&mask, -m - 1, 0, 0); + } + else + { + image_init ( + &mask, + m / ARRAY_LENGTH (sizes) / ARRAY_LENGTH (formats), + m / ARRAY_LENGTH (sizes) % ARRAY_LENGTH (formats), + sizes[m % ARRAY_LENGTH (sizes)]); + } + + for (ca = -1; ca <= 1; ca++) + { + for (i = 0; i < ARRAY_LENGTH (operators); i++) + { + const operator_t *op = &operators[i]; + + switch (ca) + { + case -1: + ok = composite_test (&dst, op, &src, NULL, FALSE); + break; + case 0: + ok = composite_test (&dst, op, &src, &mask, FALSE); + break; + case 1: + ok = composite_test (&dst, op, &src, &mask, + mask.size? TRUE : FALSE); + break; + default: + break; + } + group_ok = group_ok && ok; + tests_passed += ok; + tests_total++; + } + } + + image_fini (&mask); + } + image_fini (&src); + } + image_fini (&dst); + } + + return group_ok == FALSE; +} |