• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
12 static 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 
64 static 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 
74 static int
get_size(void)75 get_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 
103 static void
destroy(pixman_image_t * image,void * data)104 destroy (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 
124 static uint32_t
real_reader(const void * src,int size)125 real_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 
141 static void
real_writer(void * src,uint32_t value,int size)142 real_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 
164 static uint32_t
fake_reader(const void * src,int size)165 fake_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 
174 static void
fake_writer(void * src,uint32_t value,int size)175 fake_writer (void *src, uint32_t value, int size)
176 {
177     assert (size == 1 || size == 2 || size == 4);
178 }
179 
180 static int32_t
log_rand(void)181 log_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 
190 static int32_t
rand_x(pixman_image_t * image)191 rand_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 
199 static int32_t
rand_y(pixman_image_t * image)200 rand_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 
208 typedef enum
209 {
210     DONT_CARE,
211     PREFER_ALPHA,
212     REQUIRE_ALPHA
213 } alpha_preference_t;
214 
215 static pixman_format_code_t
random_format(alpha_preference_t alpha)216 random_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 
237 static pixman_image_t *
create_random_bits_image(alpha_preference_t alpha_preference)238 create_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 
390 static pixman_repeat_t repeats[] =
391 {
392     PIXMAN_REPEAT_NONE,
393     PIXMAN_REPEAT_NORMAL,
394     PIXMAN_REPEAT_REFLECT,
395     PIXMAN_REPEAT_PAD
396 };
397 
398 static uint32_t
absolute(int32_t i)399 absolute (int32_t i)
400 {
401     return i < 0? -i : i;
402 }
403 
404 static void
set_general_properties(pixman_image_t * image,pixman_bool_t allow_alpha_map)405 set_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 
581 static pixman_color_t
random_color(void)582 random_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 
596 static pixman_image_t *
create_random_solid_image(void)597 create_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 
605 static pixman_gradient_stop_t *
create_random_stops(int * n_stops)606 create_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 
634 static pixman_point_fixed_t
create_random_point(void)635 create_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 
645 static pixman_image_t *
create_random_linear_image(void)646 create_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 
667 static pixman_image_t *
create_random_radial_image(void)668 create_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 
694 static pixman_image_t *
create_random_conical_image(void)695 create_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 
718 static pixman_image_t *
create_random_image(void)719 create_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 
753 static void
random_line(pixman_line_fixed_t * line,int width,int height)754 random_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 
762 static pixman_trapezoid_t *
create_random_trapezoids(int * n_traps,int height,int width)763 create_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 
786 static 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 
846 static void
run_test(uint32_t seed,pixman_bool_t verbose,uint32_t mod)847 run_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 
938 out:
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 
947 static pixman_bool_t
get_int(char * s,uint32_t * i)948 get_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 
964 int
main(int argc,char ** argv)965 main (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