1 /*
2  * Copyright © 2015 RISC OS Open Ltd
3  *
4  * Permission to use, copy, modify, distribute, and sell this software and its
5  * documentation for any purpose is hereby granted without fee, provided that
6  * the above copyright notice appear in all copies and that both that
7  * copyright notice and this permission notice appear in supporting
8  * documentation, and that the name of the copyright holders not be used in
9  * advertising or publicity pertaining to distribution of the software without
10  * specific, written prior permission.  The copyright holders make no
11  * representations about the suitability of this software for any purpose.  It
12  * is provided "as is" without express or implied warranty.
13  *
14  * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
15  * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
16  * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
17  * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
18  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
19  * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
20  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
21  * SOFTWARE.
22  *
23  * Author:  Ben Avison (bavison@riscosopen.org)
24  *
25  */
26 
27 #include "utils.h"
28 #include <stdlib.h>
29 #include <stdint.h>
30 #include <stdio.h>
31 
32 #define WIDTH 32
33 #define HEIGHT 32
34 
35 static const pixman_op_t op_list[] = {
36     PIXMAN_OP_SRC,
37     PIXMAN_OP_OVER,
38     PIXMAN_OP_ADD,
39     PIXMAN_OP_CLEAR,
40     PIXMAN_OP_SRC,
41     PIXMAN_OP_DST,
42     PIXMAN_OP_OVER,
43     PIXMAN_OP_OVER_REVERSE,
44     PIXMAN_OP_IN,
45     PIXMAN_OP_IN_REVERSE,
46     PIXMAN_OP_OUT,
47     PIXMAN_OP_OUT_REVERSE,
48     PIXMAN_OP_ATOP,
49     PIXMAN_OP_ATOP_REVERSE,
50     PIXMAN_OP_XOR,
51     PIXMAN_OP_ADD,
52     PIXMAN_OP_MULTIPLY,
53     PIXMAN_OP_SCREEN,
54     PIXMAN_OP_OVERLAY,
55     PIXMAN_OP_DARKEN,
56     PIXMAN_OP_LIGHTEN,
57     PIXMAN_OP_HARD_LIGHT,
58     PIXMAN_OP_DIFFERENCE,
59     PIXMAN_OP_EXCLUSION,
60 #if 0 /* these use floating point math and are not always bitexact on different platforms */
61     PIXMAN_OP_SATURATE,
62     PIXMAN_OP_DISJOINT_CLEAR,
63     PIXMAN_OP_DISJOINT_SRC,
64     PIXMAN_OP_DISJOINT_DST,
65     PIXMAN_OP_DISJOINT_OVER,
66     PIXMAN_OP_DISJOINT_OVER_REVERSE,
67     PIXMAN_OP_DISJOINT_IN,
68     PIXMAN_OP_DISJOINT_IN_REVERSE,
69     PIXMAN_OP_DISJOINT_OUT,
70     PIXMAN_OP_DISJOINT_OUT_REVERSE,
71     PIXMAN_OP_DISJOINT_ATOP,
72     PIXMAN_OP_DISJOINT_ATOP_REVERSE,
73     PIXMAN_OP_DISJOINT_XOR,
74     PIXMAN_OP_CONJOINT_CLEAR,
75     PIXMAN_OP_CONJOINT_SRC,
76     PIXMAN_OP_CONJOINT_DST,
77     PIXMAN_OP_CONJOINT_OVER,
78     PIXMAN_OP_CONJOINT_OVER_REVERSE,
79     PIXMAN_OP_CONJOINT_IN,
80     PIXMAN_OP_CONJOINT_IN_REVERSE,
81     PIXMAN_OP_CONJOINT_OUT,
82     PIXMAN_OP_CONJOINT_OUT_REVERSE,
83     PIXMAN_OP_CONJOINT_ATOP,
84     PIXMAN_OP_CONJOINT_ATOP_REVERSE,
85     PIXMAN_OP_CONJOINT_XOR,
86     PIXMAN_OP_COLOR_DODGE,
87     PIXMAN_OP_COLOR_BURN,
88     PIXMAN_OP_SOFT_LIGHT,
89     PIXMAN_OP_HSL_HUE,
90     PIXMAN_OP_HSL_SATURATION,
91     PIXMAN_OP_HSL_COLOR,
92     PIXMAN_OP_HSL_LUMINOSITY,
93 #endif
94 };
95 
96 /* The first eight format in the list are by far the most widely
97  * used formats, so we test those more than the others
98  */
99 #define N_MOST_LIKELY_FORMATS 8
100 
101 static const pixman_format_code_t img_fmt_list[] = {
102     PIXMAN_a8r8g8b8,
103     PIXMAN_a8b8g8r8,
104     PIXMAN_x8r8g8b8,
105     PIXMAN_x8b8g8r8,
106     PIXMAN_r5g6b5,
107     PIXMAN_b5g6r5,
108     PIXMAN_a8,
109     PIXMAN_a1,
110     PIXMAN_r3g3b2,
111     PIXMAN_b8g8r8a8,
112     PIXMAN_b8g8r8x8,
113     PIXMAN_r8g8b8a8,
114     PIXMAN_r8g8b8x8,
115     PIXMAN_x14r6g6b6,
116     PIXMAN_r8g8b8,
117     PIXMAN_b8g8r8,
118 #if 0 /* These are going to use floating point in the near future */
119     PIXMAN_x2r10g10b10,
120     PIXMAN_a2r10g10b10,
121     PIXMAN_x2b10g10r10,
122     PIXMAN_a2b10g10r10,
123 #endif
124     PIXMAN_a1r5g5b5,
125     PIXMAN_x1r5g5b5,
126     PIXMAN_a1b5g5r5,
127     PIXMAN_x1b5g5r5,
128     PIXMAN_a4r4g4b4,
129     PIXMAN_x4r4g4b4,
130     PIXMAN_a4b4g4r4,
131     PIXMAN_x4b4g4r4,
132     PIXMAN_r3g3b2,
133     PIXMAN_b2g3r3,
134     PIXMAN_a2r2g2b2,
135     PIXMAN_a2b2g2r2,
136     PIXMAN_c8,
137     PIXMAN_g8,
138     PIXMAN_x4c4,
139     PIXMAN_x4g4,
140     PIXMAN_c4,
141     PIXMAN_g4,
142     PIXMAN_g1,
143     PIXMAN_x4a4,
144     PIXMAN_a4,
145     PIXMAN_r1g2b1,
146     PIXMAN_b1g2r1,
147     PIXMAN_a1r1g1b1,
148     PIXMAN_a1b1g1r1,
149     PIXMAN_null
150 };
151 
152 static const pixman_format_code_t mask_fmt_list[] = {
153     PIXMAN_a8r8g8b8,
154     PIXMAN_a8,
155     PIXMAN_a4,
156     PIXMAN_a1,
157     PIXMAN_null
158 };
159 
160 static pixman_indexed_t rgb_palette[9];
161 static pixman_indexed_t y_palette[9];
162 
163 static pixman_format_code_t
random_format(const pixman_format_code_t * allowed_formats)164 random_format (const pixman_format_code_t *allowed_formats)
165 {
166     int n = 0;
167 
168     while (allowed_formats[n] != PIXMAN_null)
169         n++;
170 
171     if (n > N_MOST_LIKELY_FORMATS && prng_rand_n (4) != 0)
172         n = N_MOST_LIKELY_FORMATS;
173 
174     return allowed_formats[prng_rand_n (n)];
175 }
176 
177 static pixman_image_t *
create_multi_pixel_image(const pixman_format_code_t * allowed_formats,uint32_t * buffer,pixman_format_code_t * used_fmt)178 create_multi_pixel_image (const pixman_format_code_t *allowed_formats,
179                           uint32_t                   *buffer,
180                           pixman_format_code_t       *used_fmt)
181 {
182     pixman_format_code_t fmt;
183     pixman_image_t *img;
184     int stride;
185 
186     fmt = random_format (allowed_formats);
187     stride = (WIDTH * PIXMAN_FORMAT_BPP (fmt) + 31) / 32 * 4;
188     img = pixman_image_create_bits (fmt, WIDTH, HEIGHT, buffer, stride);
189 
190     if (PIXMAN_FORMAT_TYPE (fmt) == PIXMAN_TYPE_COLOR)
191         pixman_image_set_indexed (img, &(rgb_palette[PIXMAN_FORMAT_BPP (fmt)]));
192     else if (PIXMAN_FORMAT_TYPE (fmt) == PIXMAN_TYPE_GRAY)
193         pixman_image_set_indexed (img, &(y_palette[PIXMAN_FORMAT_BPP (fmt)]));
194 
195     prng_randmemset (buffer, WIDTH * HEIGHT * 4, 0);
196     image_endian_swap (img);
197 
198     if (used_fmt)
199         *used_fmt = fmt;
200 
201     return img;
202 }
203 
204 static pixman_image_t *
create_solid_image(const pixman_format_code_t * allowed_formats,uint32_t * buffer,pixman_format_code_t * used_fmt)205 create_solid_image (const pixman_format_code_t *allowed_formats,
206                     uint32_t                   *buffer,
207                     pixman_format_code_t       *used_fmt)
208 {
209     if (prng_rand_n (2))
210     {
211         /* Use a repeating 1x1 bitmap image for solid */
212         pixman_format_code_t fmt;
213         pixman_image_t      *img, *dummy_img;
214         uint32_t             bpp, dummy_buf;
215 
216         fmt = random_format (allowed_formats);
217         bpp = PIXMAN_FORMAT_BPP (fmt);
218         img = pixman_image_create_bits (fmt, 1, 1, buffer, 4);
219         pixman_image_set_repeat (img, PIXMAN_REPEAT_NORMAL);
220 
221         if (PIXMAN_FORMAT_TYPE (fmt) == PIXMAN_TYPE_COLOR)
222             pixman_image_set_indexed (img, &(rgb_palette[bpp]));
223         else if (PIXMAN_FORMAT_TYPE (fmt) == PIXMAN_TYPE_GRAY)
224             pixman_image_set_indexed (img, &(y_palette[bpp]));
225 
226         /* Force the flags to be calculated for image with initial
227          * bitmap contents of 0 or 2^bpp-1 by plotting from it into a
228          * separate throwaway image. It is simplest to write all 0s
229          * or all 1s to the first word irrespective of the colour
230          * depth even though we actually only care about the first
231          * pixel since the stride has to be a whole number of words.
232          */
233         *buffer = prng_rand_n (2) ? 0xFFFFFFFFu : 0;
234         dummy_img = pixman_image_create_bits (PIXMAN_a8r8g8b8, 1, 1,
235                                               &dummy_buf, 4);
236         pixman_image_composite (PIXMAN_OP_SRC, img, NULL, dummy_img,
237                                 0, 0, 0, 0, 0, 0, 1, 1);
238         pixman_image_unref (dummy_img);
239 
240         /* Now set the bitmap contents to a random value */
241         prng_randmemset (buffer, 4, 0);
242         image_endian_swap (img);
243 
244         if (used_fmt)
245             *used_fmt = fmt;
246 
247         return img;
248     }
249     else
250     {
251         /* Use a native solid image */
252         pixman_color_t color;
253         pixman_image_t *img;
254 
255         color.alpha = prng_rand_n (UINT16_MAX + 1);
256         color.red   = prng_rand_n (UINT16_MAX + 1);
257         color.green = prng_rand_n (UINT16_MAX + 1);
258         color.blue  = prng_rand_n (UINT16_MAX + 1);
259         img = pixman_image_create_solid_fill (&color);
260 
261         if (used_fmt)
262             *used_fmt = PIXMAN_solid;
263 
264         return img;
265     }
266 }
267 
268 static uint32_t
test_solid(int testnum,int verbose)269 test_solid (int testnum, int verbose)
270 {
271     pixman_op_t          op;
272     uint32_t             src_buf[WIDTH * HEIGHT];
273     uint32_t             dst_buf[WIDTH * HEIGHT];
274     uint32_t             mask_buf[WIDTH * HEIGHT];
275     pixman_image_t      *src_img;
276     pixman_image_t      *dst_img;
277     pixman_image_t      *mask_img = NULL;
278     pixman_format_code_t src_fmt, dst_fmt, mask_fmt = PIXMAN_null;
279     pixman_bool_t        ca = 0;
280     uint32_t             crc32;
281 
282     prng_srand (testnum);
283 
284     op = op_list[prng_rand_n (ARRAY_LENGTH (op_list))];
285 
286     dst_img = create_multi_pixel_image (img_fmt_list, dst_buf, &dst_fmt);
287     switch (prng_rand_n (3))
288     {
289     case 0: /* Solid source, no mask */
290         src_img = create_solid_image (img_fmt_list, src_buf, &src_fmt);
291         break;
292     case 1: /* Solid source, bitmap mask */
293         src_img = create_solid_image (img_fmt_list, src_buf, &src_fmt);
294         mask_img = create_multi_pixel_image (mask_fmt_list, mask_buf, &mask_fmt);
295         break;
296     case 2: /* Bitmap image, solid mask */
297         src_img = create_multi_pixel_image (img_fmt_list, src_buf, &src_fmt);
298         mask_img = create_solid_image (mask_fmt_list, mask_buf, &mask_fmt);
299         break;
300     default:
301         abort ();
302     }
303 
304     if (mask_img)
305     {
306         ca = prng_rand_n (2);
307         pixman_image_set_component_alpha (mask_img, ca);
308     }
309 
310     if (verbose)
311     {
312         printf ("op=%s\n", operator_name (op));
313         printf ("src_fmt=%s, dst_fmt=%s, mask_fmt=%s\n",
314                 format_name (src_fmt), format_name (dst_fmt),
315                 format_name (mask_fmt));
316         printf ("src_size=%u, mask_size=%u, component_alpha=%u\n",
317                 src_fmt == PIXMAN_solid ? 1 : src_img->bits.width,
318                 !mask_img || mask_fmt == PIXMAN_solid ? 1 : mask_img->bits.width,
319                 ca);
320     }
321 
322     pixman_image_composite (op, src_img, mask_img, dst_img,
323                             0, 0, 0, 0, 0, 0, WIDTH, HEIGHT);
324 
325     if (verbose)
326         print_image (dst_img);
327 
328     crc32 = compute_crc32_for_image (0, dst_img);
329 
330     pixman_image_unref (src_img);
331     pixman_image_unref (dst_img);
332     if (mask_img)
333         pixman_image_unref (mask_img);
334 
335     return crc32;
336 }
337 
338 int
main(int argc,const char * argv[])339 main (int argc, const char *argv[])
340 {
341     int i;
342 
343     prng_srand (0);
344 
345     for (i = 1; i <= 8; i++)
346     {
347         initialize_palette (&(rgb_palette[i]), i, TRUE);
348         initialize_palette (&(y_palette[i]), i, FALSE);
349     }
350 
351     return fuzzer_test_main ("solid", 500000,
352                              0xC30FD380,
353 			     test_solid, argc, argv);
354 }
355