Don't use __thread on MinGW.
[profile/ivi/pixman.git] / test / composite.c
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
37 typedef struct color_t color_t;
38 typedef struct format_t format_t;
39 typedef struct image_t image_t;
40 typedef struct operator_t operator_t;
41
42 struct color_t
43 {
44     double r, g, b, a;
45 };
46
47 struct format_t
48 {
49     pixman_format_code_t format;
50     const char *name;
51 };
52
53 static 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
64 static 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
75 static void
76 compute_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
85 static 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
144 struct 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
153 struct operator_t
154 {
155     pixman_op_t op;
156     const char *name;
157 };
158
159 static 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
205 static double
206 calc_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
431 static void
432 do_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
481 static void
482 color_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
509 static void
510 get_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
596 static double
597 eval_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
618 static char *
619 describe_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  */
640 static pixman_bool_t
641 composite_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
757 static void
758 image_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
797 static void
798 image_fini (image_t *info)
799 {
800     pixman_image_unref (info->image);
801 }
802
803 int
804 main (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 }