Upload Tizen2.0 source
[framework/graphics/cairo.git] / test / coverage.c
1 /*
2  * Copyright 2010 Intel Corporation
3  *
4  * Permission is hereby granted, free of charge, to any person
5  * obtaining a copy of this software and associated documentation
6  * files (the "Software"), to deal in the Software without
7  * restriction, including without limitation the rights to use, copy,
8  * modify, merge, publish, distribute, sublicense, and/or sell copies
9  * of the Software, and to permit persons to whom the Software is
10  * furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be
13  * included in all copies or substantial portions of the Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
19  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
20  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22  * SOFTWARE.
23  *
24  * Author: Chris Wilson <chris@chris-wilson.co.uk>
25  */
26
27 #include "cairo-test.h"
28
29 /* Test the fidelity of the rasterisation, because Cairo is my favourite
30  * driver test suite.
31  */
32
33 #define GENERATE_REFERENCE 0
34
35 #define WIDTH 256
36 #define HEIGHT 40
37
38 #include "../src/cairo-fixed-type-private.h"
39 #define PRECISION (1 << CAIRO_FIXED_FRAC_BITS)
40
41 /* XXX beware multithreading! */
42 static uint32_t state;
43
44 static uint32_t
45 hars_petruska_f54_1_random (void)
46 {
47 #define rol(x,k) ((x << k) | (x >> (32-k)))
48     return state = (state ^ rol (state, 5) ^ rol (state, 24)) + 0x37798849;
49 #undef rol
50 }
51
52 static double
53 random_offset (int range, int precise)
54 {
55     double x = hars_petruska_f54_1_random() / (double) UINT32_MAX * range / WIDTH;
56     if (precise)
57         x = floor (x * PRECISION) / PRECISION;
58     return x;
59 }
60
61 static cairo_test_status_t
62 rectangles (cairo_t *cr, int width, int height)
63 {
64     int x, y, channel;
65
66     state = 0x12345678;
67
68     cairo_set_source_rgb (cr, 0.0, 0.0, 0.0);
69     cairo_paint (cr);
70
71 #if GENERATE_REFERENCE
72     for (x = 0; x < WIDTH; x++) {
73         cairo_set_source_rgba (cr, 1, 1, 1, x * x * 1.0 / (WIDTH * WIDTH));
74         cairo_rectangle (cr, x, 0, 1, HEIGHT);
75         cairo_fill (cr);
76     }
77 #else
78     cairo_set_operator (cr, CAIRO_OPERATOR_ADD);
79     for (channel = 0; channel < 3; channel++) {
80         switch (channel) {
81         default:
82         case 0: cairo_set_source_rgb (cr, 1.0, 0.0, 0.0); break;
83         case 1: cairo_set_source_rgb (cr, 0.0, 1.0, 0.0); break;
84         case 2: cairo_set_source_rgb (cr, 0.0, 0.0, 1.0); break;
85         }
86
87         for (x = 0; x < WIDTH; x++) {
88             for (y = 0; y < HEIGHT; y++) {
89                 double dx = random_offset (WIDTH - x, TRUE);
90                 double dy = random_offset (WIDTH - x, TRUE);
91                 cairo_rectangle (cr, x + dx, y + dy, x / (double) WIDTH, x / (double) WIDTH);
92             }
93         }
94         cairo_fill (cr);
95     }
96 #endif
97
98     return CAIRO_TEST_SUCCESS;
99 }
100
101 static cairo_test_status_t
102 intersecting_quads (cairo_t *cr, int width, int height)
103 {
104     int x, y, channel;
105
106     state = 0x12345678;
107
108     cairo_set_source_rgb (cr, 0.0, 0.0, 0.0);
109     cairo_paint (cr);
110
111 #if GENERATE_REFERENCE
112     for (x = 0; x < WIDTH; x++) {
113         cairo_set_source_rgba (cr, 1, 1, 1, x * x * 0.5 / (WIDTH * WIDTH));
114         cairo_rectangle (cr, x, 0, 1, HEIGHT);
115         cairo_fill (cr);
116     }
117 #else
118     cairo_set_operator (cr, CAIRO_OPERATOR_ADD);
119     for (channel = 0; channel < 3; channel++) {
120         switch (channel) {
121         default:
122         case 0: cairo_set_source_rgb (cr, 1.0, 0.0, 0.0); break;
123         case 1: cairo_set_source_rgb (cr, 0.0, 1.0, 0.0); break;
124         case 2: cairo_set_source_rgb (cr, 0.0, 0.0, 1.0); break;
125         }
126
127         for (x = 0; x < WIDTH; x++) {
128             double step = x / (double) WIDTH;
129             for (y = 0; y < HEIGHT; y++) {
130                 double dx = random_offset (WIDTH - x, TRUE);
131                 double dy = random_offset (WIDTH - x, TRUE);
132                 cairo_move_to (cr, x + dx, y + dy);
133                 cairo_rel_line_to (cr, step, step);
134                 cairo_rel_line_to (cr, 0, -step);
135                 cairo_rel_line_to (cr, -step, step);
136                 cairo_close_path (cr);
137             }
138         }
139         cairo_fill (cr);
140     }
141 #endif
142
143     return CAIRO_TEST_SUCCESS;
144 }
145
146 static cairo_test_status_t
147 intersecting_triangles (cairo_t *cr, int width, int height)
148 {
149     int x, y, channel;
150
151     state = 0x12345678;
152
153     cairo_set_source_rgb (cr, 0.0, 0.0, 0.0);
154     cairo_paint (cr);
155
156 #if GENERATE_REFERENCE
157     for (x = 0; x < WIDTH; x++) {
158         cairo_set_source_rgba (cr, 1, 1, 1, x * 0.75 / WIDTH);
159         cairo_rectangle (cr, x, 0, 1, HEIGHT);
160         cairo_fill (cr);
161     }
162 #else
163     cairo_set_operator (cr, CAIRO_OPERATOR_ADD);
164     for (channel = 0; channel < 3; channel++) {
165         switch (channel) {
166         default:
167         case 0: cairo_set_source_rgb (cr, 1.0, 0.0, 0.0); break;
168         case 1: cairo_set_source_rgb (cr, 0.0, 1.0, 0.0); break;
169         case 2: cairo_set_source_rgb (cr, 0.0, 0.0, 1.0); break;
170         }
171
172         for (x = 0; x < WIDTH; x++) {
173             double step = x / (double) WIDTH;
174             for (y = 0; y < HEIGHT; y++) {
175                 double dx = random_offset (WIDTH - x, TRUE);
176                 double dy = random_offset (WIDTH - x, TRUE);
177
178                 /* left */
179                 cairo_move_to (cr, x + dx, y + dy);
180                 cairo_rel_line_to (cr, 0, step);
181                 cairo_rel_line_to (cr, step, 0);
182                 cairo_close_path (cr);
183
184                 /* right, mirrored */
185                 cairo_move_to (cr, x + dx + step, y + dy + step);
186                 cairo_rel_line_to (cr, 0, -step);
187                 cairo_rel_line_to (cr, -step, step);
188                 cairo_close_path (cr);
189             }
190         }
191         cairo_fill (cr);
192     }
193 #endif
194
195     return CAIRO_TEST_SUCCESS;
196 }
197
198 static cairo_test_status_t
199 triangles (cairo_t *cr, int width, int height)
200 {
201     int x, y, channel;
202
203     state = 0x12345678;
204
205     cairo_set_source_rgb (cr, 0.0, 0.0, 0.0);
206     cairo_paint (cr);
207
208 #if GENERATE_REFERENCE
209     for (x = 0; x < WIDTH; x++) {
210         cairo_set_source_rgba (cr, 1, 1, 1, x * x * 0.5 / (WIDTH * WIDTH));
211         cairo_rectangle (cr, x, 0, 1, HEIGHT);
212         cairo_fill (cr);
213     }
214 #else
215     cairo_set_operator (cr, CAIRO_OPERATOR_ADD);
216     for (channel = 0; channel < 3; channel++) {
217         switch (channel) {
218         default:
219         case 0: cairo_set_source_rgb (cr, 1.0, 0.0, 0.0); break;
220         case 1: cairo_set_source_rgb (cr, 0.0, 1.0, 0.0); break;
221         case 2: cairo_set_source_rgb (cr, 0.0, 0.0, 1.0); break;
222         }
223
224         for (x = 0; x < WIDTH; x++) {
225             for (y = 0; y < HEIGHT; y++) {
226                 double dx = random_offset (WIDTH - x, TRUE);
227                 double dy = random_offset (WIDTH - x, TRUE);
228                 cairo_move_to (cr, x + dx, y + dy);
229                 cairo_rel_line_to (cr, x / (double) WIDTH, 0);
230                 cairo_rel_line_to (cr, 0, x / (double) WIDTH);
231                 cairo_close_path (cr);
232             }
233         }
234         cairo_fill (cr);
235     }
236 #endif
237
238     return CAIRO_TEST_SUCCESS;
239 }
240
241 static cairo_test_status_t
242 column_triangles (cairo_t *cr, int width, int height)
243 {
244     int x, y, i, channel;
245
246     state = 0x12345678;
247
248     cairo_set_source_rgb (cr, 0.0, 0.0, 0.0);
249     cairo_paint (cr);
250
251 #if GENERATE_REFERENCE
252     for (x = 0; x < WIDTH; x++) {
253         cairo_set_source_rgba (cr, 1, 1, 1, x * 0.5 / WIDTH);
254         cairo_rectangle (cr, x, 0, 1, HEIGHT);
255         cairo_fill (cr);
256     }
257 #else
258     cairo_set_operator (cr, CAIRO_OPERATOR_ADD);
259     for (channel = 0; channel < 3; channel++) {
260         switch (channel) {
261         default:
262         case 0: cairo_set_source_rgb (cr, 1.0, 0.0, 0.0); break;
263         case 1: cairo_set_source_rgb (cr, 0.0, 1.0, 0.0); break;
264         case 2: cairo_set_source_rgb (cr, 0.0, 0.0, 1.0); break;
265         }
266
267         for (x = 0; x < WIDTH; x++) {
268             double step = x / (double) (2 * WIDTH);
269             for (y = 0; y < HEIGHT; y++) {
270                 for (i = 0; i < PRECISION; i++) {
271                     double dy = random_offset (WIDTH - x, FALSE);
272
273                     /*
274                      * We want to test some sharing of edges to further
275                      * stress the rasterisers, so instead of using one
276                      * tall triangle, it is split into two, with vertical
277                      * edges on either side that may co-align with their
278                      * neighbours:
279                      *
280                      *  s ---  .      ---
281                      *  t  |   |\      |
282                      *  e  |   | \     |
283                      *  p ---  ....    |  2 * step = x / WIDTH
284                      *          \ |    |
285                      *           \|    |
286                      *            .   ---
287                      *        |---|
288                      *     1 / PRECISION
289                      *
290                      * Each column contains two triangles of width one quantum and
291                      * total height of (x / WIDTH), thus the total area covered by all
292                      * columns in each pixel is .5 * (x / WIDTH).
293                      */
294
295                     cairo_move_to (cr, x + i / (double) PRECISION, y + dy);
296                     cairo_rel_line_to (cr, 0, step);
297                     cairo_rel_line_to (cr, 1 / (double) PRECISION, step);
298                     cairo_rel_line_to (cr, 0, -step);
299                     cairo_close_path (cr);
300                 }
301                 cairo_fill (cr); /* do these per-pixel due to the extra volume of edges */
302             }
303         }
304     }
305 #endif
306
307     return CAIRO_TEST_SUCCESS;
308 }
309
310 static cairo_test_status_t
311 row_triangles (cairo_t *cr, int width, int height)
312 {
313     int x, y, i, channel;
314
315     state = 0x12345678;
316
317     cairo_set_source_rgb (cr, 0.0, 0.0, 0.0);
318     cairo_paint (cr);
319
320 #if GENERATE_REFERENCE
321     for (x = 0; x < WIDTH; x++) {
322         cairo_set_source_rgba (cr, 1, 1, 1, x * 0.5 / WIDTH);
323         cairo_rectangle (cr, x, 0, 1, HEIGHT);
324         cairo_fill (cr);
325     }
326 #else
327     cairo_set_operator (cr, CAIRO_OPERATOR_ADD);
328     for (channel = 0; channel < 3; channel++) {
329         switch (channel) {
330         default:
331         case 0: cairo_set_source_rgb (cr, 1.0, 0.0, 0.0); break;
332         case 1: cairo_set_source_rgb (cr, 0.0, 1.0, 0.0); break;
333         case 2: cairo_set_source_rgb (cr, 0.0, 0.0, 1.0); break;
334         }
335
336         for (x = 0; x < WIDTH; x++) {
337             double step = x / (double) (2 * WIDTH);
338             for (y = 0; y < HEIGHT; y++) {
339                 for (i = 0; i < PRECISION; i++) {
340                     double dx = random_offset (WIDTH - x, FALSE);
341
342                     /* See column_triangles() for a transposed description
343                      * of this geometry.
344                      */
345
346                     cairo_move_to (cr, x + dx, y + i / (double) PRECISION);
347                     cairo_rel_line_to (cr,  step, 0);
348                     cairo_rel_line_to (cr,  step, 1 / (double) PRECISION);
349                     cairo_rel_line_to (cr, -step, 0);
350                     cairo_close_path (cr);
351                 }
352                 cairo_fill (cr); /* do these per-pixel due to the extra volume of edges */
353             }
354         }
355     }
356 #endif
357
358     return CAIRO_TEST_SUCCESS;
359 }
360
361 CAIRO_TEST (coverage_rectangles,
362             "Check the fidelity of the rasterisation.",
363             NULL, /* keywords */
364             "target=raster slow", /* requirements */
365             WIDTH, HEIGHT,
366             NULL, rectangles)
367
368 CAIRO_TEST (coverage_intersecting_quads,
369             "Check the fidelity of the rasterisation.",
370             NULL, /* keywords */
371             "target=raster slow", /* requirements */
372             WIDTH, HEIGHT,
373             NULL, intersecting_quads)
374
375 CAIRO_TEST (coverage_intersecting_triangles,
376             "Check the fidelity of the rasterisation.",
377             NULL, /* keywords */
378             "target=raster slow", /* requirements */
379             WIDTH, HEIGHT,
380             NULL, intersecting_triangles)
381 CAIRO_TEST (coverage_row_triangles,
382             "Check the fidelity of the rasterisation.",
383             NULL, /* keywords */
384             "target=raster slow", /* requirements */
385             WIDTH, HEIGHT,
386             NULL, row_triangles)
387 CAIRO_TEST (coverage_column_triangles,
388             "Check the fidelity of the rasterisation.",
389             NULL, /* keywords */
390             "target=raster slow", /* requirements */
391             WIDTH, HEIGHT,
392             NULL, column_triangles)
393 CAIRO_TEST (coverage_triangles,
394             "Check the fidelity of the rasterisation.",
395             NULL, /* keywords */
396             "target=raster slow", /* requirements */
397             WIDTH, HEIGHT,
398             NULL, triangles)