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