1#include <stdio.h>
2#include <stdlib.h>
3#include "utils.h"
4#include <sys/types.h>
5
6#if 0
7#define fence_malloc malloc
8#define fence_free free
9#define make_random_bytes malloc
10#endif
11
12static const pixman_format_code_t image_formats[] =
13{
14    PIXMAN_a8r8g8b8,
15    PIXMAN_x8r8g8b8,
16    PIXMAN_r5g6b5,
17    PIXMAN_r3g3b2,
18    PIXMAN_a8,
19    PIXMAN_a8b8g8r8,
20    PIXMAN_x8b8g8r8,
21    PIXMAN_b8g8r8a8,
22    PIXMAN_b8g8r8x8,
23    PIXMAN_r8g8b8a8,
24    PIXMAN_r8g8b8x8,
25    PIXMAN_x14r6g6b6,
26    PIXMAN_r8g8b8,
27    PIXMAN_b8g8r8,
28    PIXMAN_a8r8g8b8_sRGB,
29    PIXMAN_r5g6b5,
30    PIXMAN_b5g6r5,
31    PIXMAN_x2r10g10b10,
32    PIXMAN_a2r10g10b10,
33    PIXMAN_x2b10g10r10,
34    PIXMAN_a2b10g10r10,
35    PIXMAN_a1r5g5b5,
36    PIXMAN_x1r5g5b5,
37    PIXMAN_a1b5g5r5,
38    PIXMAN_x1b5g5r5,
39    PIXMAN_a4r4g4b4,
40    PIXMAN_x4r4g4b4,
41    PIXMAN_a4b4g4r4,
42    PIXMAN_x4b4g4r4,
43    PIXMAN_a8,
44    PIXMAN_r3g3b2,
45    PIXMAN_b2g3r3,
46    PIXMAN_a2r2g2b2,
47    PIXMAN_a2b2g2r2,
48    PIXMAN_c8,
49    PIXMAN_g8,
50    PIXMAN_x4c4,
51    PIXMAN_x4g4,
52    PIXMAN_c4,
53    PIXMAN_g4,
54    PIXMAN_g1,
55    PIXMAN_x4a4,
56    PIXMAN_a4,
57    PIXMAN_r1g2b1,
58    PIXMAN_b1g2r1,
59    PIXMAN_a1r1g1b1,
60    PIXMAN_a1b1g1r1,
61    PIXMAN_a1
62};
63
64static pixman_filter_t filters[] =
65{
66    PIXMAN_FILTER_NEAREST,
67    PIXMAN_FILTER_BILINEAR,
68    PIXMAN_FILTER_FAST,
69    PIXMAN_FILTER_GOOD,
70    PIXMAN_FILTER_BEST,
71    PIXMAN_FILTER_CONVOLUTION
72};
73
74static int
75get_size (void)
76{
77    switch (prng_rand_n (28))
78    {
79    case 0:
80	return 1;
81
82    case 1:
83	return 2;
84
85    default:
86    case 2:
87	return prng_rand_n (100);
88
89    case 4:
90	return prng_rand_n (2000) + 1000;
91
92    case 5:
93	return 65535;
94
95    case 6:
96	return 65536;
97
98    case 7:
99	return prng_rand_n (64000) + 63000;
100    }
101}
102
103static void
104destroy (pixman_image_t *image, void *data)
105{
106    if (image->type == BITS && image->bits.free_me != image->bits.bits)
107    {
108	uint32_t *bits;
109
110	if (image->bits.bits != (void *)0x01)
111	{
112	    bits = image->bits.bits;
113
114	    if (image->bits.rowstride < 0)
115		bits -= (- image->bits.rowstride * (image->bits.height - 1));
116
117	    fence_free (bits);
118	}
119    }
120
121    free (data);
122}
123
124static uint32_t
125real_reader (const void *src, int size)
126{
127    switch (size)
128    {
129    case 1:
130	return *(uint8_t *)src;
131    case 2:
132	return *(uint16_t *)src;
133    case 4:
134	return *(uint32_t *)src;
135    default:
136	assert (0);
137	return 0; /* silence MSVC */
138    }
139}
140
141static void
142real_writer (void *src, uint32_t value, int size)
143{
144    switch (size)
145    {
146    case 1:
147	*(uint8_t *)src = value;
148	break;
149
150    case 2:
151	*(uint16_t *)src = value;
152	break;
153
154    case 4:
155	*(uint32_t *)src = value;
156	break;
157
158    default:
159	assert (0);
160	break;
161    }
162}
163
164static uint32_t
165fake_reader (const void *src, int size)
166{
167    uint32_t r = prng_rand ();
168
169    assert (size == 1 || size == 2 || size == 4);
170
171    return r >> (32 - (size * 8));
172}
173
174static void
175fake_writer (void *src, uint32_t value, int size)
176{
177    assert (size == 1 || size == 2 || size == 4);
178}
179
180static int32_t
181log_rand (void)
182{
183    uint32_t mask;
184
185    mask = (1 << prng_rand_n (10)) - 1;
186
187    return (prng_rand () & mask) - (mask >> 1);
188}
189
190static int32_t
191rand_x (pixman_image_t *image)
192{
193    if (image->type == BITS)
194	return prng_rand_n (image->bits.width);
195    else
196	return log_rand ();
197}
198
199static int32_t
200rand_y (pixman_image_t *image)
201{
202    if (image->type == BITS)
203	return prng_rand_n (image->bits.height);
204    else
205	return log_rand ();
206}
207
208typedef enum
209{
210    DONT_CARE,
211    PREFER_ALPHA,
212    REQUIRE_ALPHA
213} alpha_preference_t;
214
215static pixman_format_code_t
216random_format (alpha_preference_t alpha)
217{
218    pixman_format_code_t format;
219    int n = prng_rand_n (ARRAY_LENGTH (image_formats));
220
221    if (alpha >= PREFER_ALPHA &&
222	(alpha == REQUIRE_ALPHA || prng_rand_n (4) != 0))
223    {
224        do
225        {
226            format = image_formats[n++ % ARRAY_LENGTH (image_formats)];
227        } while (PIXMAN_FORMAT_TYPE (format) != PIXMAN_TYPE_A);
228    }
229    else
230    {
231        format = image_formats[n];
232    }
233
234    return format;
235}
236
237static pixman_image_t *
238create_random_bits_image (alpha_preference_t alpha_preference)
239{
240    pixman_format_code_t format;
241    pixman_indexed_t *indexed;
242    pixman_image_t *image;
243    int width, height, stride;
244    uint32_t *bits;
245    pixman_read_memory_func_t read_func = NULL;
246    pixman_write_memory_func_t write_func = NULL;
247    pixman_filter_t filter;
248    pixman_fixed_t *coefficients = NULL;
249    int n_coefficients = 0;
250
251    /* format */
252    format = random_format (alpha_preference);
253
254    indexed = NULL;
255    if (PIXMAN_FORMAT_TYPE (format) == PIXMAN_TYPE_COLOR)
256    {
257	indexed = malloc (sizeof (pixman_indexed_t));
258
259	initialize_palette (indexed, PIXMAN_FORMAT_BPP (format), TRUE);
260    }
261    else if (PIXMAN_FORMAT_TYPE (format) == PIXMAN_TYPE_GRAY)
262    {
263	indexed = malloc (sizeof (pixman_indexed_t));
264
265	initialize_palette (indexed, PIXMAN_FORMAT_BPP (format), FALSE);
266    }
267    else
268    {
269	indexed = NULL;
270    }
271
272    /* size */
273    width = get_size ();
274    height = get_size ();
275
276    while ((uint64_t)width * height > 200000)
277    {
278	if (prng_rand_n(2) == 0)
279	    height = 200000 / width;
280	else
281	    width = 200000 / height;
282    }
283
284    if (height == 0)
285	height = 1;
286    if (width == 0)
287	width = 1;
288
289    /* bits */
290    switch (prng_rand_n (7))
291    {
292    default:
293    case 0:
294	stride = width * PIXMAN_FORMAT_BPP (format) + prng_rand_n (17);
295	stride = (stride + 3) & (~3);
296	bits = (uint32_t *)make_random_bytes (height * stride);
297	break;
298
299    case 1:
300	stride = 0;
301	bits = NULL;
302	break;
303
304    case 2: /* Zero-filled */
305	stride = width * PIXMAN_FORMAT_BPP (format) + prng_rand_n (17);
306	stride = (stride + 3) & (~3);
307	bits = fence_malloc (height * stride);
308	if (!bits)
309	    return NULL;
310	memset (bits, 0, height * stride);
311	break;
312
313    case 3: /* Filled with 0xFF */
314	stride = width * PIXMAN_FORMAT_BPP (format) + prng_rand_n (17);
315	stride = (stride + 3) & (~3);
316	bits = fence_malloc (height * stride);
317	if (!bits)
318	    return NULL;
319	memset (bits, 0xff, height * stride);
320	break;
321
322    case 4: /* bits is a bad pointer, has read/write functions */
323	stride = 232;
324	bits = (void *)0x01;
325	read_func = fake_reader;
326	write_func = fake_writer;
327	break;
328
329    case 5: /* bits is a real pointer, has read/write functions */
330	stride = width * PIXMAN_FORMAT_BPP (format) + prng_rand_n (17);
331	stride = (stride + 3) & (~3);
332	bits = fence_malloc (height * stride);
333	if (!bits)
334	    return NULL;
335	memset (bits, 0xff, height * stride);
336	read_func = real_reader;
337	write_func = real_writer;
338	break;
339
340    case 6: /* bits is a real pointer, stride is negative */
341	stride = (width * PIXMAN_FORMAT_BPP (format) + prng_rand_n (17));
342	stride = (stride + 3) & (~3);
343	bits = (uint32_t *)make_random_bytes (height * stride);
344	if (!bits)
345	    return NULL;
346	bits += ((height - 1) * stride) / 4;
347	stride = - stride;
348	break;
349    }
350
351    /* Filter */
352    filter = filters[prng_rand_n (ARRAY_LENGTH (filters))];
353    if (filter == PIXMAN_FILTER_CONVOLUTION)
354    {
355	int width = prng_rand_n (3);
356	int height = prng_rand_n (4);
357
358	n_coefficients = width * height + 2;
359	coefficients = malloc (n_coefficients * sizeof (pixman_fixed_t));
360
361	if (coefficients)
362	{
363	    int i;
364
365	    for (i = 0; i < width * height; ++i)
366		coefficients[i + 2] = prng_rand();
367
368	    coefficients[0] = width << 16;
369	    coefficients[1] = height << 16;
370	}
371	else
372	{
373	    filter = PIXMAN_FILTER_BEST;
374	}
375    }
376
377    /* Finally create the image */
378    image = pixman_image_create_bits (format, width, height, bits, stride);
379    if (!image)
380	return NULL;
381
382    pixman_image_set_indexed (image, indexed);
383    pixman_image_set_destroy_function (image, destroy, indexed);
384    pixman_image_set_accessors (image, read_func, write_func);
385    pixman_image_set_filter (image, filter, coefficients, n_coefficients);
386
387    return image;
388}
389
390static pixman_repeat_t repeats[] =
391{
392    PIXMAN_REPEAT_NONE,
393    PIXMAN_REPEAT_NORMAL,
394    PIXMAN_REPEAT_REFLECT,
395    PIXMAN_REPEAT_PAD
396};
397
398static uint32_t
399absolute (int32_t i)
400{
401    return i < 0? -i : i;
402}
403
404static void
405set_general_properties (pixman_image_t *image, pixman_bool_t allow_alpha_map)
406{
407    pixman_repeat_t repeat;
408
409    /* Set properties that are generic to all images */
410
411    /* Repeat */
412    repeat = repeats[prng_rand_n (ARRAY_LENGTH (repeats))];
413    pixman_image_set_repeat (image, repeat);
414
415    /* Alpha map */
416    if (allow_alpha_map && prng_rand_n (4) == 0)
417    {
418	pixman_image_t *alpha_map;
419	int16_t x, y;
420
421	alpha_map = create_random_bits_image (DONT_CARE);
422
423	if (alpha_map)
424	{
425	    set_general_properties (alpha_map, FALSE);
426
427	    x = rand_x (image) - image->bits.width / 2;
428	    y = rand_y (image) - image->bits.height / 2;
429
430	    pixman_image_set_alpha_map (image, alpha_map, x, y);
431
432	    pixman_image_unref (alpha_map);
433	}
434    }
435
436    /* Component alpha */
437    pixman_image_set_component_alpha (image, prng_rand_n (3) == 0);
438
439    /* Clip region */
440    if (prng_rand_n (8) < 2)
441    {
442	pixman_region32_t region;
443	int i, n_rects;
444
445	pixman_region32_init (&region);
446
447	switch (prng_rand_n (12))
448	{
449	case 0:
450	    n_rects = 0;
451	    break;
452
453	case 1: case 2: case 3:
454	    n_rects = 1;
455	    break;
456
457	case 4: case 5:
458	    n_rects = 2;
459	    break;
460
461	case 6: case 7:
462	    n_rects = 3;
463	    break;
464
465	default:
466	    n_rects = prng_rand_n (100);
467	    break;
468	}
469
470	for (i = 0; i < n_rects; ++i)
471	{
472	    uint32_t width, height;
473	    int x, y;
474
475	    x = log_rand();
476	    y = log_rand();
477	    width = absolute (log_rand ()) + 1;
478	    height = absolute (log_rand ()) + 1;
479
480	    pixman_region32_union_rect (
481		&region, &region, x, y, width, height);
482	}
483
484	if (image->type == BITS && prng_rand_n (8) != 0)
485	{
486	    uint32_t width, height;
487	    int x, y;
488	    int i;
489
490	    /* Also add a couple of clip rectangles inside the image
491	     * so that compositing will actually take place.
492	     */
493	    for (i = 0; i < 5; ++i)
494	    {
495		x = prng_rand_n (2 * image->bits.width) - image->bits.width;
496		y = prng_rand_n (2 * image->bits.height) - image->bits.height;
497		width = prng_rand_n (image->bits.width) - x + 10;
498		height = prng_rand_n (image->bits.height) - y + 10;
499
500		if (width + x < x)
501		    width = INT32_MAX - x;
502		if (height + y < y)
503		    height = INT32_MAX - y;
504
505		pixman_region32_union_rect (
506		    &region, &region, x, y, width, height);
507	    }
508	}
509
510	pixman_image_set_clip_region32 (image, &region);
511
512	pixman_region32_fini (&region);
513    }
514
515    /* Whether source clipping is enabled */
516    pixman_image_set_source_clipping (image, !!prng_rand_n (2));
517
518    /* Client clip */
519    pixman_image_set_has_client_clip (image, !!prng_rand_n (2));
520
521    /* Transform */
522    if (prng_rand_n (5) < 2)
523    {
524	pixman_transform_t xform;
525	int i, j, k;
526	uint32_t tx, ty, sx, sy;
527	uint32_t c, s;
528
529	memset (&xform, 0, sizeof xform);
530	xform.matrix[0][0] = pixman_fixed_1;
531	xform.matrix[1][1] = pixman_fixed_1;
532	xform.matrix[2][2] = pixman_fixed_1;
533
534	for (k = 0; k < 3; ++k)
535	{
536	    switch (prng_rand_n (4))
537	    {
538	    case 0:
539		/* rotation */
540		c = prng_rand_n (2 * 65536) - 65536;
541		s = prng_rand_n (2 * 65536) - 65536;
542		pixman_transform_rotate (&xform, NULL, c, s);
543		break;
544
545	    case 1:
546		/* translation */
547		tx = prng_rand();
548		ty = prng_rand();
549		pixman_transform_translate (&xform, NULL, tx, ty);
550		break;
551
552	    case 2:
553		/* scale */
554		sx = prng_rand();
555		sy = prng_rand();
556		pixman_transform_scale (&xform, NULL, sx, sy);
557		break;
558
559	    case 3:
560		if (prng_rand_n (16) == 0)
561		{
562		    /* random */
563		    for (i = 0; i < 3; ++i)
564			for (j = 0; j < 3; ++j)
565			    xform.matrix[i][j] = prng_rand();
566		    break;
567		}
568		else if (prng_rand_n (16) == 0)
569		{
570		    /* zero */
571		    memset (&xform, 0, sizeof xform);
572		}
573		break;
574	    }
575	}
576
577	pixman_image_set_transform (image, &xform);
578    }
579}
580
581static pixman_color_t
582random_color (void)
583{
584    pixman_color_t color =
585    {
586	prng_rand() & 0xffff,
587	prng_rand() & 0xffff,
588	prng_rand() & 0xffff,
589	prng_rand() & 0xffff,
590    };
591
592    return color;
593}
594
595
596static pixman_image_t *
597create_random_solid_image (void)
598{
599    pixman_color_t color = random_color();
600    pixman_image_t *image = pixman_image_create_solid_fill (&color);
601
602    return image;
603}
604
605static pixman_gradient_stop_t *
606create_random_stops (int *n_stops)
607{
608    pixman_fixed_t step;
609    pixman_fixed_t s;
610    int i;
611    pixman_gradient_stop_t *stops;
612
613    *n_stops = prng_rand_n (50) + 1;
614
615    step = pixman_fixed_1 / *n_stops;
616
617    stops = malloc (*n_stops * sizeof (pixman_gradient_stop_t));
618
619    s = 0;
620    for (i = 0; i < (*n_stops) - 1; ++i)
621    {
622	stops[i].x = s;
623	stops[i].color = random_color();
624
625	s += step;
626    }
627
628    stops[*n_stops - 1].x = pixman_fixed_1;
629    stops[*n_stops - 1].color = random_color();
630
631    return stops;
632}
633
634static pixman_point_fixed_t
635create_random_point (void)
636{
637    pixman_point_fixed_t p;
638
639    p.x = log_rand ();
640    p.y = log_rand ();
641
642    return p;
643}
644
645static pixman_image_t *
646create_random_linear_image (void)
647{
648    int n_stops;
649    pixman_gradient_stop_t *stops;
650    pixman_point_fixed_t p1, p2;
651    pixman_image_t *result;
652
653    stops = create_random_stops (&n_stops);
654    if (!stops)
655	return NULL;
656
657    p1 = create_random_point ();
658    p2 = create_random_point ();
659
660    result = pixman_image_create_linear_gradient (&p1, &p2, stops, n_stops);
661
662    free (stops);
663
664    return result;
665}
666
667static pixman_image_t *
668create_random_radial_image (void)
669{
670    int n_stops;
671    pixman_gradient_stop_t *stops;
672    pixman_point_fixed_t inner_c, outer_c;
673    pixman_fixed_t inner_r, outer_r;
674    pixman_image_t *result;
675
676    inner_c = create_random_point();
677    outer_c = create_random_point();
678    inner_r = prng_rand();
679    outer_r = prng_rand();
680
681    stops = create_random_stops (&n_stops);
682
683    if (!stops)
684	return NULL;
685
686    result = pixman_image_create_radial_gradient (
687	&inner_c, &outer_c, inner_r, outer_r, stops, n_stops);
688
689    free (stops);
690
691    return result;
692}
693
694static pixman_image_t *
695create_random_conical_image (void)
696{
697    pixman_gradient_stop_t *stops;
698    int n_stops;
699    pixman_point_fixed_t c;
700    pixman_fixed_t angle;
701    pixman_image_t *result;
702
703    c = create_random_point();
704    angle = prng_rand();
705
706    stops = create_random_stops (&n_stops);
707
708    if (!stops)
709	return NULL;
710
711    result = pixman_image_create_conical_gradient (&c, angle, stops, n_stops);
712
713    free (stops);
714
715    return result;
716}
717
718static pixman_image_t *
719create_random_image (void)
720{
721    pixman_image_t *result;
722
723    switch (prng_rand_n (5))
724    {
725    default:
726    case 0:
727	result = create_random_bits_image (DONT_CARE);
728	break;
729
730    case 1:
731	result = create_random_solid_image ();
732	break;
733
734    case 2:
735	result = create_random_linear_image ();
736	break;
737
738    case 3:
739	result = create_random_radial_image ();
740	break;
741
742    case 4:
743	result = create_random_conical_image ();
744	break;
745    }
746
747    if (result)
748	set_general_properties (result, TRUE);
749
750    return result;
751}
752
753static void
754random_line (pixman_line_fixed_t *line, int width, int height)
755{
756    line->p1.x = prng_rand_n (width) << 16;
757    line->p1.y = prng_rand_n (height) << 16;
758    line->p2.x = prng_rand_n (width) << 16;
759    line->p2.y = prng_rand_n (height) << 16;
760}
761
762static pixman_trapezoid_t *
763create_random_trapezoids (int *n_traps, int height, int width)
764{
765    pixman_trapezoid_t *trapezoids;
766    int i;
767
768    *n_traps = prng_rand_n (16) + 1;
769
770    trapezoids = malloc (sizeof (pixman_trapezoid_t) * *n_traps);
771
772    for (i = 0; i < *n_traps; ++i)
773    {
774        pixman_trapezoid_t *t = &(trapezoids[i]);
775
776        t->top = prng_rand_n (height) << 16;
777        t->bottom = prng_rand_n (height) << 16;
778
779        random_line (&t->left, height, width);
780        random_line (&t->right, height, width);
781    }
782
783    return trapezoids;
784}
785
786static const pixman_op_t op_list[] =
787{
788    PIXMAN_OP_SRC,
789    PIXMAN_OP_OVER,
790    PIXMAN_OP_ADD,
791    PIXMAN_OP_CLEAR,
792    PIXMAN_OP_SRC,
793    PIXMAN_OP_DST,
794    PIXMAN_OP_OVER,
795    PIXMAN_OP_OVER_REVERSE,
796    PIXMAN_OP_IN,
797    PIXMAN_OP_IN_REVERSE,
798    PIXMAN_OP_OUT,
799    PIXMAN_OP_OUT_REVERSE,
800    PIXMAN_OP_ATOP,
801    PIXMAN_OP_ATOP_REVERSE,
802    PIXMAN_OP_XOR,
803    PIXMAN_OP_ADD,
804    PIXMAN_OP_SATURATE,
805    PIXMAN_OP_DISJOINT_CLEAR,
806    PIXMAN_OP_DISJOINT_SRC,
807    PIXMAN_OP_DISJOINT_DST,
808    PIXMAN_OP_DISJOINT_OVER,
809    PIXMAN_OP_DISJOINT_OVER_REVERSE,
810    PIXMAN_OP_DISJOINT_IN,
811    PIXMAN_OP_DISJOINT_IN_REVERSE,
812    PIXMAN_OP_DISJOINT_OUT,
813    PIXMAN_OP_DISJOINT_OUT_REVERSE,
814    PIXMAN_OP_DISJOINT_ATOP,
815    PIXMAN_OP_DISJOINT_ATOP_REVERSE,
816    PIXMAN_OP_DISJOINT_XOR,
817    PIXMAN_OP_CONJOINT_CLEAR,
818    PIXMAN_OP_CONJOINT_SRC,
819    PIXMAN_OP_CONJOINT_DST,
820    PIXMAN_OP_CONJOINT_OVER,
821    PIXMAN_OP_CONJOINT_OVER_REVERSE,
822    PIXMAN_OP_CONJOINT_IN,
823    PIXMAN_OP_CONJOINT_IN_REVERSE,
824    PIXMAN_OP_CONJOINT_OUT,
825    PIXMAN_OP_CONJOINT_OUT_REVERSE,
826    PIXMAN_OP_CONJOINT_ATOP,
827    PIXMAN_OP_CONJOINT_ATOP_REVERSE,
828    PIXMAN_OP_CONJOINT_XOR,
829    PIXMAN_OP_MULTIPLY,
830    PIXMAN_OP_SCREEN,
831    PIXMAN_OP_OVERLAY,
832    PIXMAN_OP_DARKEN,
833    PIXMAN_OP_LIGHTEN,
834    PIXMAN_OP_COLOR_DODGE,
835    PIXMAN_OP_COLOR_BURN,
836    PIXMAN_OP_HARD_LIGHT,
837    PIXMAN_OP_DIFFERENCE,
838    PIXMAN_OP_EXCLUSION,
839    PIXMAN_OP_SOFT_LIGHT,
840    PIXMAN_OP_HSL_HUE,
841    PIXMAN_OP_HSL_SATURATION,
842    PIXMAN_OP_HSL_COLOR,
843    PIXMAN_OP_HSL_LUMINOSITY,
844};
845
846static void
847run_test (uint32_t seed, pixman_bool_t verbose, uint32_t mod)
848{
849    pixman_image_t *source, *mask, *dest;
850    pixman_op_t op;
851
852    if (verbose)
853    {
854	if (mod == 0 || (seed % mod) == 0)
855	    printf ("Seed 0x%08x\n", seed);
856    }
857
858    source = mask = dest = NULL;
859
860    prng_srand (seed);
861
862    if (prng_rand_n (8) == 0)
863    {
864        int n_traps;
865        pixman_trapezoid_t *trapezoids;
866	int p = prng_rand_n (3);
867
868	if (p == 0)
869	    dest = create_random_bits_image (DONT_CARE);
870	else
871	    dest = create_random_bits_image (REQUIRE_ALPHA);
872
873	if (!dest)
874	    goto out;
875
876	set_general_properties (dest, TRUE);
877
878	if (!(trapezoids = create_random_trapezoids (
879		  &n_traps, dest->bits.width, dest->bits.height)))
880	{
881	    goto out;
882	}
883
884	switch (p)
885	{
886	case 0:
887	    source = create_random_image ();
888
889	    if (source)
890	    {
891		op = op_list [prng_rand_n (ARRAY_LENGTH (op_list))];
892
893		pixman_composite_trapezoids (
894		    op, source, dest,
895		    random_format (REQUIRE_ALPHA),
896		    rand_x (source), rand_y (source),
897		    rand_x (dest), rand_y (dest),
898		    n_traps, trapezoids);
899	    }
900	    break;
901
902	case 1:
903	    pixman_rasterize_trapezoid (
904		dest, &trapezoids[prng_rand_n (n_traps)],
905		rand_x (dest), rand_y (dest));
906	    break;
907
908	case 2:
909	    pixman_add_trapezoids (
910		dest, rand_x (dest), rand_y (dest), n_traps, trapezoids);
911	    break;
912        }
913
914	free (trapezoids);
915    }
916    else
917    {
918        dest = create_random_bits_image (DONT_CARE);
919        source = create_random_image ();
920        mask = create_random_image ();
921
922        if (source && mask && dest)
923        {
924            set_general_properties (dest, TRUE);
925
926            op = op_list [prng_rand_n (ARRAY_LENGTH (op_list))];
927
928            pixman_image_composite32 (op,
929                                      source, mask, dest,
930                                      rand_x (source), rand_y (source),
931                                      rand_x (mask), rand_y (mask),
932                                      0, 0,
933                                      dest->bits.width,
934                                      dest->bits.height);
935        }
936    }
937
938out:
939    if (source)
940	pixman_image_unref (source);
941    if (mask)
942	pixman_image_unref (mask);
943    if (dest)
944	pixman_image_unref (dest);
945}
946
947static pixman_bool_t
948get_int (char *s, uint32_t *i)
949{
950    char *end;
951    int p;
952
953    p = strtol (s, &end, 0);
954
955    if (end != s && *end == 0)
956    {
957	*i = p;
958	return TRUE;
959    }
960
961    return FALSE;
962}
963
964int
965main (int argc, char **argv)
966{
967    int verbose = FALSE;
968    uint32_t seed = 1;
969    uint32_t n_tests = 8000;
970    uint32_t mod = 0;
971    pixman_bool_t use_threads = TRUE;
972    int32_t i;
973
974    pixman_disable_out_of_bounds_workaround ();
975
976    enable_divbyzero_exceptions();
977
978    if (getenv ("VERBOSE") != NULL)
979	verbose = TRUE;
980
981    for (i = 1; i < argc; ++i)
982    {
983	if (strcmp (argv[i], "-v") == 0)
984	{
985	    verbose = TRUE;
986
987	    if (i + 1 < argc)
988	    {
989		get_int (argv[i + 1], &mod);
990		i++;
991	    }
992	}
993	else if (strcmp (argv[i], "-s") == 0 && i + 1 < argc)
994	{
995	    get_int (argv[i + 1], &seed);
996	    use_threads = FALSE;
997	    i++;
998	}
999	else if (strcmp (argv[i], "-n") == 0 && i + 1 < argc)
1000	{
1001	    get_int (argv[i + 1], &n_tests);
1002	    i++;
1003	}
1004	else
1005	{
1006	    if (strcmp (argv[i], "-h") != 0)
1007		printf ("Unknown option '%s'\n\n", argv[i]);
1008
1009	    printf ("Options:\n\n"
1010		    "-n <number>        Number of tests to run\n"
1011		    "-s <seed> 	        Seed of first test (ignored if PIXMAN_RANDOMIZE_TESTS is set)\n"
1012		    "-v                 Print out seeds\n"
1013		    "-v <n>             Print out every n'th seed\n\n");
1014
1015	    exit (-1);
1016	}
1017    }
1018
1019    if (getenv ("PIXMAN_RANDOMIZE_TESTS"))
1020    {
1021	seed = get_random_seed();
1022	printf ("First seed: 0x%08x\n", seed);
1023    }
1024
1025    if (use_threads)
1026    {
1027#ifdef USE_OPENMP
1028#   pragma omp parallel for default(none) shared(verbose, n_tests, mod, seed)
1029#endif
1030	for (i = 0; i < (int32_t)n_tests; ++i)
1031	    run_test (seed + i, verbose, mod);
1032    }
1033    else
1034    {
1035	for (i = 0; i < (int32_t)n_tests; ++i)
1036	    run_test (seed + i, verbose, mod);
1037    }
1038
1039    return 0;
1040}
1041