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