composite.c revision 952204ab
1/*
2 * Copyright © 2005 Eric Anholt
3 * Copyright © 2009 Chris Wilson
4 *
5 * Permission to use, copy, modify, distribute, and sell this software and its
6 * documentation for any purpose is hereby granted without fee, provided that
7 * the above copyright notice appear in all copies and that both that
8 * copyright notice and this permission notice appear in supporting
9 * documentation, and that the name of Eric Anholt not be used in
10 * advertising or publicity pertaining to distribution of the software without
11 * specific, written prior permission.  Eric Anholt makes no
12 * representations about the suitability of this software for any purpose.  It
13 * is provided "as is" without express or implied warranty.
14 *
15 * ERIC ANHOLT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
16 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
17 * EVENT SHALL ERIC ANHOLT BE LIABLE FOR ANY SPECIAL, INDIRECT OR
18 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
19 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
20 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
21 * PERFORMANCE OF THIS SOFTWARE.
22 */
23
24#include <pixman.h>
25#include <stdio.h>
26#include <stdlib.h> /* abort() */
27#include <math.h>
28#include <config.h>
29
30#define FALSE 0
31#define TRUE !FALSE
32
33#define ARRAY_LENGTH(A) ((int) (sizeof (A) / sizeof ((A) [0])))
34#define min(a,b) ((a) <= (b) ? (a) : (b))
35#define max(a,b) ((a) >= (b) ? (a) : (b))
36
37typedef struct color_t color_t;
38typedef struct format_t format_t;
39typedef struct image_t image_t;
40typedef struct operator_t operator_t;
41
42struct color_t
43{
44    double r, g, b, a;
45};
46
47struct format_t
48{
49    pixman_format_code_t format;
50    const char *name;
51};
52
53static color_t colors[] =
54{
55    /* these are premultiplied in main() */
56    { 1.0, 1.0, 1.0, 1.0 },
57    { 1.0, 0.0, 0.0, 1.0 },
58    { 0.0, 1.0, 0.0, 1.0 },
59    { 0.0, 0.0, 1.0, 1.0 },
60    { 0.0, 0.0, 0.0, 1.0 },
61    { 0.5, 0.0, 0.0, 0.5 },
62};
63
64static uint16_t
65_color_double_to_short (double d)
66{
67    uint32_t i;
68
69    i = (uint32_t) (d * 65536);
70    i -= (i >> 16);
71
72    return i;
73}
74
75static void
76compute_pixman_color (const color_t *color,
77		      pixman_color_t *out)
78{
79    out->red   = _color_double_to_short (color->r);
80    out->green = _color_double_to_short (color->g);
81    out->blue  = _color_double_to_short (color->b);
82    out->alpha = _color_double_to_short (color->a);
83}
84
85static const format_t formats[] =
86{
87#define P(x) { PIXMAN_##x, #x }
88    P(a8),
89
90    /* 32bpp formats */
91    P(a8r8g8b8),
92    P(x8r8g8b8),
93    P(a8b8g8r8),
94    P(x8b8g8r8),
95    P(b8g8r8a8),
96    P(b8g8r8x8),
97
98    /* XXX: and here the errors begin! */
99#if 0
100    P(x2r10g10b10),
101    P(a2r10g10b10),
102    P(x2b10g10r10),
103    P(a2b10g10r10),
104
105    /* 24bpp formats */
106    P(r8g8b8),
107    P(b8g8r8),
108
109    /* 16bpp formats */
110    P(r5g6b5),
111    P(b5g6r5),
112
113    P(a1r5g5b5),
114    P(x1r5g5b5),
115    P(a1b5g5r5),
116    P(x1b5g5r5),
117    P(a4r4g4b4),
118    P(x4r4g4b4),
119    P(a4b4g4r4),
120    P(x4b4g4r4),
121
122    /* 8bpp formats */
123    P(a8),
124    P(r3g3b2),
125    P(b2g3r3),
126    P(a2r2g2b2),
127    P(a2b2g2r2),
128
129    P(x4a4),
130
131    /* 4bpp formats */
132    P(a4),
133    P(r1g2b1),
134    P(b1g2r1),
135    P(a1r1g1b1),
136    P(a1b1g1r1),
137
138    /* 1bpp formats */
139    P(a1)
140#endif
141#undef P
142};
143
144struct image_t
145{
146    pixman_image_t *image;
147    const format_t *format;
148    const color_t *color;
149    pixman_repeat_t repeat;
150    int size;
151};
152
153struct operator_t
154{
155    pixman_op_t op;
156    const char *name;
157};
158
159static const operator_t operators[] =
160{
161#define P(x) { PIXMAN_OP_##x, #x }
162    P(CLEAR),
163    P(SRC),
164    P(DST),
165    P(OVER),
166    P(OVER_REVERSE),
167    P(IN),
168    P(IN_REVERSE),
169    P(OUT),
170    P(OUT_REVERSE),
171    P(ATOP),
172    P(ATOP_REVERSE),
173    P(XOR),
174    P(ADD),
175    P(SATURATE),
176
177    P(DISJOINT_CLEAR),
178    P(DISJOINT_SRC),
179    P(DISJOINT_DST),
180    P(DISJOINT_OVER),
181    P(DISJOINT_OVER_REVERSE),
182    P(DISJOINT_IN),
183    P(DISJOINT_IN_REVERSE),
184    P(DISJOINT_OUT),
185    P(DISJOINT_OUT_REVERSE),
186    P(DISJOINT_ATOP),
187    P(DISJOINT_ATOP_REVERSE),
188    P(DISJOINT_XOR),
189
190    P(CONJOINT_CLEAR),
191    P(CONJOINT_SRC),
192    P(CONJOINT_DST),
193    P(CONJOINT_OVER),
194    P(CONJOINT_OVER_REVERSE),
195    P(CONJOINT_IN),
196    P(CONJOINT_IN_REVERSE),
197    P(CONJOINT_OUT),
198    P(CONJOINT_OUT_REVERSE),
199    P(CONJOINT_ATOP),
200    P(CONJOINT_ATOP_REVERSE),
201    P(CONJOINT_XOR),
202#undef P
203};
204
205static double
206calc_op (pixman_op_t op, double src, double dst, double srca, double dsta)
207{
208#define mult_chan(src, dst, Fa, Fb) min ((src) * (Fa) + (dst) * (Fb), 1.0)
209
210    double Fa, Fb;
211
212    switch (op)
213    {
214    case PIXMAN_OP_CLEAR:
215    case PIXMAN_OP_DISJOINT_CLEAR:
216    case PIXMAN_OP_CONJOINT_CLEAR:
217	return mult_chan (src, dst, 0.0, 0.0);
218
219    case PIXMAN_OP_SRC:
220    case PIXMAN_OP_DISJOINT_SRC:
221    case PIXMAN_OP_CONJOINT_SRC:
222	return mult_chan (src, dst, 1.0, 0.0);
223
224    case PIXMAN_OP_DST:
225    case PIXMAN_OP_DISJOINT_DST:
226    case PIXMAN_OP_CONJOINT_DST:
227	return mult_chan (src, dst, 0.0, 1.0);
228
229    case PIXMAN_OP_OVER:
230	return mult_chan (src, dst, 1.0, 1.0 - srca);
231
232    case PIXMAN_OP_OVER_REVERSE:
233	return mult_chan (src, dst, 1.0 - dsta, 1.0);
234
235    case PIXMAN_OP_IN:
236	return mult_chan (src, dst, dsta, 0.0);
237
238    case PIXMAN_OP_IN_REVERSE:
239	return mult_chan (src, dst, 0.0, srca);
240
241    case PIXMAN_OP_OUT:
242	return mult_chan (src, dst, 1.0 - dsta, 0.0);
243
244    case PIXMAN_OP_OUT_REVERSE:
245	return mult_chan (src, dst, 0.0, 1.0 - srca);
246
247    case PIXMAN_OP_ATOP:
248	return mult_chan (src, dst, dsta, 1.0 - srca);
249
250    case PIXMAN_OP_ATOP_REVERSE:
251	return mult_chan (src, dst, 1.0 - dsta,  srca);
252
253    case PIXMAN_OP_XOR:
254	return mult_chan (src, dst, 1.0 - dsta, 1.0 - srca);
255
256    case PIXMAN_OP_ADD:
257	return mult_chan (src, dst, 1.0, 1.0);
258
259    case PIXMAN_OP_SATURATE:
260    case PIXMAN_OP_DISJOINT_OVER_REVERSE:
261	if (srca == 0.0)
262	    Fa = 1.0;
263	else
264	    Fa = min (1.0, (1.0 - dsta) / srca);
265	return mult_chan (src, dst, Fa, 1.0);
266
267    case PIXMAN_OP_DISJOINT_OVER:
268	if (dsta == 0.0)
269	    Fb = 1.0;
270	else
271	    Fb = min (1.0, (1.0 - srca) / dsta);
272	return mult_chan (src, dst, 1.0, Fb);
273
274    case PIXMAN_OP_DISJOINT_IN:
275	if (srca == 0.0)
276	    Fa = 0.0;
277	else
278	    Fa = max (0.0, 1.0 - (1.0 - dsta) / srca);
279	return mult_chan (src, dst, Fa, 0.0);
280
281    case PIXMAN_OP_DISJOINT_IN_REVERSE:
282	if (dsta == 0.0)
283	    Fb = 0.0;
284	else
285	    Fb = max (0.0, 1.0 - (1.0 - srca) / dsta);
286	return mult_chan (src, dst, 0.0, Fb);
287
288    case PIXMAN_OP_DISJOINT_OUT:
289	if (srca == 0.0)
290	    Fa = 1.0;
291	else
292	    Fa = min (1.0, (1.0 - dsta) / srca);
293	return mult_chan (src, dst, Fa, 0.0);
294
295    case PIXMAN_OP_DISJOINT_OUT_REVERSE:
296	if (dsta == 0.0)
297	    Fb = 1.0;
298	else
299	    Fb = min (1.0, (1.0 - srca) / dsta);
300	return mult_chan (src, dst, 0.0, Fb);
301
302    case PIXMAN_OP_DISJOINT_ATOP:
303	if (srca == 0.0)
304	    Fa = 0.0;
305	else
306	    Fa = max (0.0, 1.0 - (1.0 - dsta) / srca);
307	if (dsta == 0.0)
308	    Fb = 1.0;
309	else
310	    Fb = min (1.0, (1.0 - srca) / dsta);
311	return mult_chan (src, dst, Fa, Fb);
312
313    case PIXMAN_OP_DISJOINT_ATOP_REVERSE:
314	if (srca == 0.0)
315	    Fa = 1.0;
316	else
317	    Fa = min (1.0, (1.0 - dsta) / srca);
318	if (dsta == 0.0)
319	    Fb = 0.0;
320	else
321	    Fb = max (0.0, 1.0 - (1.0 - srca) / dsta);
322	return mult_chan (src, dst, Fa, Fb);
323
324    case PIXMAN_OP_DISJOINT_XOR:
325	if (srca == 0.0)
326	    Fa = 1.0;
327	else
328	    Fa = min (1.0, (1.0 - dsta) / srca);
329	if (dsta == 0.0)
330	    Fb = 1.0;
331	else
332	    Fb = min (1.0, (1.0 - srca) / dsta);
333	return mult_chan (src, dst, Fa, Fb);
334
335    case PIXMAN_OP_CONJOINT_OVER:
336	if (dsta == 0.0)
337	    Fb = 0.0;
338	else
339	    Fb = max (0.0, 1.0 - srca / dsta);
340	return mult_chan (src, dst, 1.0, Fb);
341
342    case PIXMAN_OP_CONJOINT_OVER_REVERSE:
343	if (srca == 0.0)
344	    Fa = 0.0;
345	else
346	    Fa = max (0.0, 1.0 - dsta / srca);
347	return mult_chan (src, dst, Fa, 1.0);
348
349    case PIXMAN_OP_CONJOINT_IN:
350	if (srca == 0.0)
351	    Fa = 1.0;
352	else
353	    Fa = min (1.0, dsta / srca);
354	return mult_chan (src, dst, Fa, 0.0);
355
356    case PIXMAN_OP_CONJOINT_IN_REVERSE:
357	if (dsta == 0.0)
358	    Fb = 1.0;
359	else
360	    Fb = min (1.0, srca / dsta);
361	return mult_chan (src, dst, 0.0, Fb);
362
363    case PIXMAN_OP_CONJOINT_OUT:
364	if (srca == 0.0)
365	    Fa = 0.0;
366	else
367	    Fa = max (0.0, 1.0 - dsta / srca);
368	return mult_chan (src, dst, Fa, 0.0);
369
370    case PIXMAN_OP_CONJOINT_OUT_REVERSE:
371	if (dsta == 0.0)
372	    Fb = 0.0;
373	else
374	    Fb = max (0.0, 1.0 - srca / dsta);
375	return mult_chan (src, dst, 0.0, Fb);
376
377    case PIXMAN_OP_CONJOINT_ATOP:
378	if (srca == 0.0)
379	    Fa = 1.0;
380	else
381	    Fa = min (1.0, dsta / srca);
382	if (dsta == 0.0)
383	    Fb = 0.0;
384	else
385	    Fb = max (0.0, 1.0 - srca / dsta);
386	return mult_chan (src, dst, Fa, Fb);
387
388    case PIXMAN_OP_CONJOINT_ATOP_REVERSE:
389	if (srca == 0.0)
390	    Fa = 0.0;
391	else
392	    Fa = max (0.0, 1.0 - dsta / srca);
393	if (dsta == 0.0)
394	    Fb = 1.0;
395	else
396	    Fb = min (1.0, srca / dsta);
397	return mult_chan (src, dst, Fa, Fb);
398
399    case PIXMAN_OP_CONJOINT_XOR:
400	if (srca == 0.0)
401	    Fa = 0.0;
402	else
403	    Fa = max (0.0, 1.0 - dsta / srca);
404	if (dsta == 0.0)
405	    Fb = 0.0;
406	else
407	    Fb = max (0.0, 1.0 - srca / dsta);
408	return mult_chan (src, dst, Fa, Fb);
409
410    case PIXMAN_OP_MULTIPLY:
411    case PIXMAN_OP_SCREEN:
412    case PIXMAN_OP_OVERLAY:
413    case PIXMAN_OP_DARKEN:
414    case PIXMAN_OP_LIGHTEN:
415    case PIXMAN_OP_COLOR_DODGE:
416    case PIXMAN_OP_COLOR_BURN:
417    case PIXMAN_OP_HARD_LIGHT:
418    case PIXMAN_OP_SOFT_LIGHT:
419    case PIXMAN_OP_DIFFERENCE:
420    case PIXMAN_OP_EXCLUSION:
421    case PIXMAN_OP_HSL_HUE:
422    case PIXMAN_OP_HSL_SATURATION:
423    case PIXMAN_OP_HSL_COLOR:
424    case PIXMAN_OP_HSL_LUMINOSITY:
425    default:
426	abort();
427    }
428#undef mult_chan
429}
430
431static void
432do_composite (pixman_op_t op,
433	      const color_t *src,
434	      const color_t *mask,
435	      const color_t *dst,
436	      color_t *result,
437	      pixman_bool_t component_alpha)
438{
439    color_t srcval, srcalpha;
440
441    if (mask == NULL)
442    {
443	srcval = *src;
444
445	srcalpha.r = src->a;
446	srcalpha.g = src->a;
447	srcalpha.b = src->a;
448	srcalpha.a = src->a;
449    }
450    else if (component_alpha)
451    {
452	srcval.r = src->r * mask->r;
453	srcval.g = src->g * mask->g;
454	srcval.b = src->b * mask->b;
455	srcval.a = src->a * mask->a;
456
457	srcalpha.r = src->a * mask->r;
458	srcalpha.g = src->a * mask->g;
459	srcalpha.b = src->a * mask->b;
460	srcalpha.a = src->a * mask->a;
461    }
462    else
463    {
464	srcval.r = src->r * mask->a;
465	srcval.g = src->g * mask->a;
466	srcval.b = src->b * mask->a;
467	srcval.a = src->a * mask->a;
468
469	srcalpha.r = src->a * mask->a;
470	srcalpha.g = src->a * mask->a;
471	srcalpha.b = src->a * mask->a;
472	srcalpha.a = src->a * mask->a;
473    }
474
475    result->r = calc_op (op, srcval.r, dst->r, srcalpha.r, dst->a);
476    result->g = calc_op (op, srcval.g, dst->g, srcalpha.g, dst->a);
477    result->b = calc_op (op, srcval.b, dst->b, srcalpha.b, dst->a);
478    result->a = calc_op (op, srcval.a, dst->a, srcalpha.a, dst->a);
479}
480
481static void
482color_correct (pixman_format_code_t format,
483	       color_t *color)
484{
485#define round_pix(pix, mask) \
486    ((int)((pix) * (mask) + .5) / (double) (mask))
487
488    if (PIXMAN_FORMAT_R (format) == 0)
489    {
490	color->r = 0.0;
491	color->g = 0.0;
492	color->b = 0.0;
493    }
494    else
495    {
496	color->r = round_pix (color->r, PIXMAN_FORMAT_R (format));
497	color->g = round_pix (color->g, PIXMAN_FORMAT_G (format));
498	color->b = round_pix (color->b, PIXMAN_FORMAT_B (format));
499    }
500
501    if (PIXMAN_FORMAT_A (format) == 0)
502	color->a = 1.0;
503    else
504	color->a = round_pix (color->a, PIXMAN_FORMAT_A (format));
505
506#undef round_pix
507}
508
509static void
510get_pixel (pixman_image_t *image,
511	   pixman_format_code_t format,
512	   color_t *color)
513{
514#define MASK(N) ((1UL << (N))-1)
515
516    unsigned long rs, gs, bs, as;
517    int a, r, g, b;
518    unsigned long val;
519
520    val = *(unsigned long *) pixman_image_get_data (image);
521#ifdef WORDS_BIGENDIAN
522    val >>= 8 * sizeof(val) - PIXMAN_FORMAT_BPP (format);
523#endif
524
525    /* Number of bits in each channel */
526    a = PIXMAN_FORMAT_A (format);
527    r = PIXMAN_FORMAT_R (format);
528    g = PIXMAN_FORMAT_G (format);
529    b = PIXMAN_FORMAT_B (format);
530
531    switch (PIXMAN_FORMAT_TYPE (format))
532    {
533    case PIXMAN_TYPE_ARGB:
534        bs = 0;
535        gs = b + bs;
536        rs = g + gs;
537        as = r + rs;
538	break;
539
540    case PIXMAN_TYPE_ABGR:
541        rs = 0;
542        gs = r + rs;
543        bs = g + gs;
544        as = b + bs;
545	break;
546
547    case PIXMAN_TYPE_BGRA:
548        as = 0;
549	rs = PIXMAN_FORMAT_BPP (format) - (b + g + r);
550        gs = r + rs;
551        bs = g + gs;
552	break;
553
554    case PIXMAN_TYPE_A:
555        as = 0;
556        rs = 0;
557        gs = 0;
558        bs = 0;
559	break;
560
561    case PIXMAN_TYPE_OTHER:
562    case PIXMAN_TYPE_COLOR:
563    case PIXMAN_TYPE_GRAY:
564    case PIXMAN_TYPE_YUY2:
565    case PIXMAN_TYPE_YV12:
566    default:
567	abort ();
568        as = 0;
569        rs = 0;
570        gs = 0;
571        bs = 0;
572	break;
573    }
574
575    if (MASK (a) != 0)
576	color->a = ((val >> as) & MASK (a)) / (double) MASK (a);
577    else
578	color->a = 1.0;
579
580    if (MASK (r) != 0)
581    {
582	color->r = ((val >> rs) & MASK (r)) / (double) MASK (r);
583	color->g = ((val >> gs) & MASK (g)) / (double) MASK (g);
584	color->b = ((val >> bs) & MASK (b)) / (double) MASK (b);
585    }
586    else
587    {
588	color->r = 0.0;
589	color->g = 0.0;
590	color->b = 0.0;
591    }
592
593#undef MASK
594}
595
596static double
597eval_diff (color_t *expected, color_t *test)
598{
599    double rscale, gscale, bscale, ascale;
600    double rdiff, gdiff, bdiff, adiff;
601
602    /* XXX: Need to be provided mask shifts so we can produce useful error
603     * values.
604     */
605    rscale = 1.0 * (1 << 5);
606    gscale = 1.0 * (1 << 6);
607    bscale = 1.0 * (1 << 5);
608    ascale = 1.0 * 32;
609
610    rdiff = fabs (test->r - expected->r) * rscale;
611    bdiff = fabs (test->g - expected->g) * gscale;
612    gdiff = fabs (test->b - expected->b) * bscale;
613    adiff = fabs (test->a - expected->a) * ascale;
614
615    return max (max (max (rdiff, gdiff), bdiff), adiff);
616}
617
618static char *
619describe_image (image_t *info, char *buf, int buflen)
620{
621    if (info->size)
622    {
623	snprintf (buf, buflen, "%s %dx%d%s",
624		  info->format->name,
625		  info->size, info->size,
626		  info->repeat ? "R" :"");
627    }
628    else
629    {
630	snprintf (buf, buflen, "solid");
631    }
632
633    return buf;
634}
635
636/* Test a composite of a given operation, source, mask, and destination
637 * picture.
638 * Fills the window, and samples from the 0,0 pixel corner.
639 */
640static pixman_bool_t
641composite_test (image_t *dst,
642		const operator_t *op,
643		image_t *src,
644		image_t *mask,
645		pixman_bool_t component_alpha)
646{
647    pixman_color_t fill;
648    pixman_rectangle16_t rect;
649    color_t expected, result, tdst, tsrc, tmsk;
650    double diff;
651    pixman_bool_t success = TRUE;
652
653    compute_pixman_color (dst->color, &fill);
654    rect.x = rect.y = 0;
655    rect.width = rect.height = dst->size;
656    pixman_image_fill_rectangles (PIXMAN_OP_SRC, dst->image,
657				  &fill, 1, &rect);
658
659    if (mask != NULL)
660    {
661	pixman_image_set_component_alpha (mask->image, component_alpha);
662	pixman_image_composite (op->op, src->image, mask->image, dst->image,
663				0, 0,
664				0, 0,
665				0, 0,
666				dst->size, dst->size);
667
668	tmsk = *mask->color;
669	if (mask->size)
670	{
671	    color_correct (mask->format->format, &tmsk);
672
673	    if (component_alpha &&
674		PIXMAN_FORMAT_R (mask->format->format) == 0)
675	    {
676		/* Ax component-alpha masks expand alpha into
677		 * all color channels.
678		 */
679		tmsk.r = tmsk.g = tmsk.b = tmsk.a;
680	    }
681	}
682    }
683    else
684    {
685	pixman_image_composite (op->op, src->image, NULL, dst->image,
686				0, 0,
687				0, 0,
688				0, 0,
689				dst->size, dst->size);
690    }
691    get_pixel (dst->image, dst->format->format, &result);
692
693    tdst = *dst->color;
694    color_correct (dst->format->format, &tdst);
695    tsrc = *src->color;
696    if (src->size)
697	color_correct (src->format->format, &tsrc);
698    do_composite (op->op, &tsrc, mask ? &tmsk : NULL, &tdst,
699		  &expected, component_alpha);
700    color_correct (dst->format->format, &expected);
701
702    diff = eval_diff (&expected, &result);
703    if (diff > 3.0)
704    {
705	char buf[40];
706
707	snprintf (buf, sizeof (buf),
708		  "%s %scomposite",
709		  op->name,
710		  component_alpha ? "CA " : "");
711
712	printf ("%s test error of %.4f --\n"
713		"           R    G    B    A\n"
714		"got:       %.2f %.2f %.2f %.2f [%08lx]\n"
715		"expected:  %.2f %.2f %.2f %.2f\n",
716		buf, diff,
717		result.r, result.g, result.b, result.a,
718		*(unsigned long *) pixman_image_get_data (dst->image),
719		expected.r, expected.g, expected.b, expected.a);
720
721	if (mask != NULL)
722	{
723	    printf ("src color: %.2f %.2f %.2f %.2f\n"
724		    "msk color: %.2f %.2f %.2f %.2f\n"
725		    "dst color: %.2f %.2f %.2f %.2f\n",
726		    src->color->r, src->color->g,
727		    src->color->b, src->color->a,
728		    mask->color->r, mask->color->g,
729		    mask->color->b, mask->color->a,
730		    dst->color->r, dst->color->g,
731		    dst->color->b, dst->color->a);
732	    printf ("src: %s, ", describe_image (src, buf, sizeof (buf)));
733	    printf ("mask: %s, ", describe_image (mask, buf, sizeof (buf)));
734	    printf ("dst: %s\n\n", describe_image (dst, buf, sizeof (buf)));
735	}
736	else
737	{
738	    printf ("src color: %.2f %.2f %.2f %.2f\n"
739		    "dst color: %.2f %.2f %.2f %.2f\n",
740		    src->color->r, src->color->g,
741		    src->color->b, src->color->a,
742		    dst->color->r, dst->color->g,
743		    dst->color->b, dst->color->a);
744	    printf ("src: %s, ", describe_image (src, buf, sizeof (buf)));
745	    printf ("dst: %s\n\n", describe_image (dst, buf, sizeof (buf)));
746	}
747
748	success = FALSE;
749    }
750
751    return success;
752}
753
754#define REPEAT 0x01000000
755#define FLAGS  0xff000000
756
757static void
758image_init (image_t *info,
759	    int color,
760	    int format,
761	    int size)
762{
763    pixman_color_t fill;
764
765    info->color = &colors[color];
766    compute_pixman_color (info->color, &fill);
767
768    info->format = &formats[format];
769    info->size = size & ~FLAGS;
770    info->repeat = PIXMAN_REPEAT_NONE;
771
772    if (info->size)
773    {
774	pixman_rectangle16_t rect;
775
776	info->image = pixman_image_create_bits (info->format->format,
777						info->size, info->size,
778						NULL, 0);
779
780	rect.x = rect.y = 0;
781	rect.width = rect.height = info->size;
782	pixman_image_fill_rectangles (PIXMAN_OP_SRC, info->image, &fill,
783				      1, &rect);
784
785	if (size & REPEAT)
786	{
787	    pixman_image_set_repeat (info->image, PIXMAN_REPEAT_NORMAL);
788	    info->repeat = PIXMAN_REPEAT_NORMAL;
789	}
790    }
791    else
792    {
793	info->image = pixman_image_create_solid_fill (&fill);
794    }
795}
796
797static void
798image_fini (image_t *info)
799{
800    pixman_image_unref (info->image);
801}
802
803int
804main (void)
805{
806    pixman_bool_t ok, group_ok = TRUE, ca;
807    int i, d, m, s;
808    int tests_passed = 0, tests_total = 0;
809    int sizes[] = { 1, 1 | REPEAT, 10 };
810    int num_tests;
811
812    for (i = 0; i < ARRAY_LENGTH (colors); i++)
813    {
814	colors[i].r *= colors[i].a;
815	colors[i].g *= colors[i].a;
816	colors[i].b *= colors[i].a;
817    }
818
819    num_tests = ARRAY_LENGTH (colors) * ARRAY_LENGTH (formats);
820
821    for (d = 0; d < num_tests; d++)
822    {
823	image_t dst;
824
825	image_init (
826	    &dst, d / ARRAY_LENGTH (formats), d % ARRAY_LENGTH (formats), 1);
827
828
829	for (s = -ARRAY_LENGTH (colors);
830	     s < ARRAY_LENGTH (sizes) * num_tests;
831	     s++)
832	{
833	    image_t src;
834
835	    if (s < 0)
836	    {
837		image_init (&src, -s - 1, 0, 0);
838	    }
839	    else
840	    {
841		image_init (&src,
842			    s / ARRAY_LENGTH (sizes) / ARRAY_LENGTH (formats),
843			    s / ARRAY_LENGTH (sizes) % ARRAY_LENGTH (formats),
844			    sizes[s % ARRAY_LENGTH (sizes)]);
845	    }
846
847	    for (m = -ARRAY_LENGTH (colors);
848		 m < ARRAY_LENGTH (sizes) * num_tests;
849		 m++)
850	    {
851		image_t mask;
852
853		if (m < 0)
854		{
855		    image_init (&mask, -m - 1, 0, 0);
856		}
857		else
858		{
859		    image_init (
860			&mask,
861			m / ARRAY_LENGTH (sizes) / ARRAY_LENGTH (formats),
862			m / ARRAY_LENGTH (sizes) % ARRAY_LENGTH (formats),
863			sizes[m % ARRAY_LENGTH (sizes)]);
864		}
865
866		for (ca = -1; ca <= 1; ca++)
867		{
868		    for (i = 0; i < ARRAY_LENGTH (operators); i++)
869		    {
870			const operator_t *op = &operators[i];
871
872			switch (ca)
873			{
874			case -1:
875			    ok = composite_test (&dst, op, &src, NULL, FALSE);
876			    break;
877			case 0:
878			    ok = composite_test (&dst, op, &src, &mask, FALSE);
879			    break;
880			case 1:
881			    ok = composite_test (&dst, op, &src, &mask,
882						 mask.size? TRUE : FALSE);
883			    break;
884                        default:
885                            break;
886			}
887			group_ok = group_ok && ok;
888			tests_passed += ok;
889			tests_total++;
890		    }
891		}
892
893		image_fini (&mask);
894	    }
895	    image_fini (&src);
896	}
897	image_fini (&dst);
898    }
899
900    return group_ok == FALSE;
901}
902