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