2 * Copyright 2010 Intel Corporation
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:
12 * The above copyright notice and this permission notice shall be
13 * included in all copies or substantial portions of the Software.
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
24 * Author: Chris Wilson <chris@chris-wilson.co.uk>
27 #include "cairo-test.h"
29 /* Test the sampling stratagems of the rasterisers by creating pixels
30 * containing minute holes and seeing how close to the expected
31 * coverage each rasteriser approaches.
36 #include "../src/cairo-fixed-type-private.h"
37 #define SAMPLE (1 << CAIRO_FIXED_FRAC_BITS)
39 static uint32_t state;
42 hars_petruska_f54_1_random (void)
44 #define rol(x,k) ((x << k) | (x >> (32-k)))
45 return state = (state ^ rol (state, 5) ^ rol (state, 24)) + 0x37798849;
52 return hars_petruska_f54_1_random() / (double) UINT32_MAX;
55 /* coverage is given in [0,sample] */
57 compute_occupancy (uint8_t *occupancy, int coverage, int sample)
61 if (coverage < sample/2) {
62 memset (occupancy, 0, sample);
66 for (i = c = 0; i < sample; i++) {
67 if ((sample - i) * uniform_random() < coverage - c) {
74 coverage = sample - coverage;
75 memset (occupancy, 0xff, sample);
79 for (i = c = 0; i < sample; i++) {
80 if ((sample - i) * uniform_random() < coverage - c) {
89 static cairo_test_status_t
90 reference (cairo_t *cr, int width, int height)
94 cairo_set_source_rgb (cr, 0.0, 0.0, 0.0);
97 for (i = 0; i < SIZE*SIZE; i++) {
98 cairo_set_source_rgba (cr, 1., 1., 1.,
99 i / (double) (SIZE * SIZE));
100 cairo_rectangle (cr, i % SIZE, i / SIZE, 1, 1);
104 return CAIRO_STATUS_SUCCESS;
107 static cairo_test_status_t
108 three_quarter_reference (cairo_t *cr, int width, int height)
112 cairo_set_source_rgb (cr, 0.0, 0.0, 0.0);
115 for (i = 0; i < SIZE*SIZE; i++) {
116 cairo_set_source_rgba (cr, 1., 1., 1.,
117 .75 * i / (double) (SIZE * SIZE));
118 cairo_rectangle (cr, i % SIZE, i / SIZE, 1, 1);
122 return CAIRO_STATUS_SUCCESS;
125 static cairo_test_status_t
126 half_reference (cairo_t *cr, int width, int height)
130 cairo_set_source_rgb (cr, 0.0, 0.0, 0.0);
133 for (i = 0; i < SIZE*SIZE; i++) {
134 cairo_set_source_rgba (cr, 1., 1., 1.,
135 .5 * i / (double) (SIZE * SIZE));
136 cairo_rectangle (cr, i % SIZE, i / SIZE, 1, 1);
140 return CAIRO_STATUS_SUCCESS;
143 static cairo_test_status_t
144 rectangles (cairo_t *cr, int width, int height)
150 occupancy = xmalloc (SAMPLE*SAMPLE);
152 cairo_set_source_rgb (cr, 0.0, 0.0, 0.0);
155 cairo_set_operator (cr, CAIRO_OPERATOR_ADD);
156 for (channel = 0; channel < 3; channel++) {
159 case 0: cairo_set_source_rgb (cr, 1.0, 0.0, 0.0); break;
160 case 1: cairo_set_source_rgb (cr, 0.0, 1.0, 0.0); break;
161 case 2: cairo_set_source_rgb (cr, 0.0, 0.0, 1.0); break;
164 for (i = 0; i < SIZE*SIZE; i++) {
167 compute_occupancy (occupancy, SAMPLE*SAMPLE * i / (SIZE * SIZE), SAMPLE*SAMPLE);
169 xs = i % SIZE * SAMPLE;
170 ys = i / SIZE * SAMPLE;
171 for (j = 0; j < SAMPLE*SAMPLE; j++) {
174 (j % SAMPLE + xs) / (double) SAMPLE,
175 (j / SAMPLE + ys) / (double) SAMPLE,
177 1 / (double) SAMPLE);
186 return CAIRO_TEST_SUCCESS;
189 static cairo_test_status_t
190 intersecting_quads (cairo_t *cr, int width, int height)
196 occupancy = xmalloc (SAMPLE*SAMPLE);
198 cairo_set_source_rgb (cr, 0.0, 0.0, 0.0);
201 cairo_set_operator (cr, CAIRO_OPERATOR_ADD);
202 for (channel = 0; channel < 3; channel++) {
205 case 0: cairo_set_source_rgb (cr, 1.0, 0.0, 0.0); break;
206 case 1: cairo_set_source_rgb (cr, 0.0, 1.0, 0.0); break;
207 case 2: cairo_set_source_rgb (cr, 0.0, 0.0, 1.0); break;
210 for (i = 0; i < SIZE*SIZE; i++) {
213 compute_occupancy (occupancy, SAMPLE*SAMPLE * i / (SIZE * SIZE), SAMPLE*SAMPLE);
215 xs = i % SIZE * SAMPLE;
216 ys = i / SIZE * SAMPLE;
217 for (j = 0; j < SAMPLE*SAMPLE; j++) {
220 (j % SAMPLE + xs) / (double) SAMPLE,
221 (j / SAMPLE + ys) / (double) SAMPLE);
222 cairo_rel_line_to (cr, 1 / (double) SAMPLE, 1 / (double) SAMPLE);
223 cairo_rel_line_to (cr, 0, -1 / (double) SAMPLE);
224 cairo_rel_line_to (cr, -1 / (double) SAMPLE, 1 / (double) SAMPLE);
225 cairo_close_path (cr);
234 return CAIRO_TEST_SUCCESS;
237 static cairo_test_status_t
238 half_triangles (cairo_t *cr, int width, int height)
244 occupancy = xmalloc (SAMPLE*SAMPLE);
246 cairo_set_source_rgb (cr, 0.0, 0.0, 0.0);
249 cairo_set_operator (cr, CAIRO_OPERATOR_ADD);
250 for (channel = 0; channel < 3; channel++) {
253 case 0: cairo_set_source_rgb (cr, 1.0, 0.0, 0.0); break;
254 case 1: cairo_set_source_rgb (cr, 0.0, 1.0, 0.0); break;
255 case 2: cairo_set_source_rgb (cr, 0.0, 0.0, 1.0); break;
258 for (i = 0; i < SIZE*SIZE; i++) {
261 compute_occupancy (occupancy, SAMPLE*SAMPLE * i / (SIZE * SIZE), SAMPLE*SAMPLE);
263 xs = i % SIZE * SAMPLE;
264 ys = i / SIZE * SAMPLE;
265 for (j = 0; j < SAMPLE*SAMPLE; j++) {
267 int x = j % SAMPLE + xs;
268 int y = j / SAMPLE + ys;
269 cairo_move_to (cr, x / (double) SAMPLE, y / (double) SAMPLE);
270 cairo_line_to (cr, (x+1) / (double) SAMPLE, (y+1) / (double) SAMPLE);
271 cairo_line_to (cr, (x+1) / (double) SAMPLE, y / (double) SAMPLE);
272 cairo_close_path (cr);
281 return CAIRO_TEST_SUCCESS;
284 static cairo_test_status_t
285 overlap_half_triangles (cairo_t *cr, int width, int height)
291 occupancy = xmalloc (SAMPLE*SAMPLE);
293 cairo_set_source_rgb (cr, 0.0, 0.0, 0.0);
296 cairo_set_operator (cr, CAIRO_OPERATOR_ADD);
297 for (channel = 0; channel < 3; channel++) {
300 case 0: cairo_set_source_rgb (cr, 1.0, 0.0, 0.0); break;
301 case 1: cairo_set_source_rgb (cr, 0.0, 1.0, 0.0); break;
302 case 2: cairo_set_source_rgb (cr, 0.0, 0.0, 1.0); break;
305 for (i = 0; i < SIZE*SIZE; i++) {
308 compute_occupancy (occupancy, SAMPLE/2*SAMPLE/2 * i / (SIZE * SIZE), SAMPLE/2*SAMPLE/2);
310 xs = i % SIZE * SAMPLE;
311 ys = i / SIZE * SAMPLE;
312 for (j = 0; j < SAMPLE/2*SAMPLE/2; j++) {
314 int x = 2 * (j % (SAMPLE/2)) + xs;
315 int y = 2 * (j / (SAMPLE/2)) + ys;
317 /* Add a 4-tile composed of two overlapping triangles.
326 * Coverage should be computable as 50% (due to counter-winding).
329 cairo_move_to (cr, (x) / (double) SAMPLE, (y) / (double) SAMPLE);
330 cairo_line_to (cr, (x) / (double) SAMPLE, (y+2) / (double) SAMPLE);
331 cairo_line_to (cr, (x+2) / (double) SAMPLE, (y) / (double) SAMPLE);
332 cairo_close_path (cr);
334 cairo_move_to (cr, (x) / (double) SAMPLE, (y) / (double) SAMPLE);
335 cairo_line_to (cr, (x+2) / (double) SAMPLE, (y) / (double) SAMPLE);
336 cairo_line_to (cr, (x+2) / (double) SAMPLE, (y+2) / (double) SAMPLE);
337 cairo_close_path (cr);
346 return CAIRO_TEST_SUCCESS;
349 static cairo_test_status_t
350 overlap_half_triangles_eo (cairo_t *cr, int width, int height)
356 occupancy = xmalloc (SAMPLE*SAMPLE);
358 cairo_set_source_rgb (cr, 0.0, 0.0, 0.0);
361 cairo_set_fill_rule (cr, CAIRO_FILL_RULE_EVEN_ODD);
363 cairo_set_operator (cr, CAIRO_OPERATOR_ADD);
364 for (channel = 0; channel < 3; channel++) {
367 case 0: cairo_set_source_rgb (cr, 1.0, 0.0, 0.0); break;
368 case 1: cairo_set_source_rgb (cr, 0.0, 1.0, 0.0); break;
369 case 2: cairo_set_source_rgb (cr, 0.0, 0.0, 1.0); break;
372 for (i = 0; i < SIZE*SIZE; i++) {
375 compute_occupancy (occupancy, SAMPLE/2*SAMPLE/2 * i / (SIZE * SIZE), SAMPLE/2*SAMPLE/2);
377 xs = i % SIZE * SAMPLE;
378 ys = i / SIZE * SAMPLE;
379 for (j = 0; j < SAMPLE/2*SAMPLE/2; j++) {
381 int x = 2 * (j % (SAMPLE/2)) + xs;
382 int y = 2 * (j / (SAMPLE/2)) + ys;
384 /* Add a 4-tile composed of two overlapping triangles.
393 * Coverage should be computable as 50%, due to even-odd fill rule.
396 cairo_move_to (cr, (x) / (double) SAMPLE, (y) / (double) SAMPLE);
397 cairo_line_to (cr, (x) / (double) SAMPLE, (y+2) / (double) SAMPLE);
398 cairo_line_to (cr, (x+2) / (double) SAMPLE, (y) / (double) SAMPLE);
399 cairo_close_path (cr);
401 cairo_move_to (cr, (x) / (double) SAMPLE, (y) / (double) SAMPLE);
402 cairo_line_to (cr, (x+2) / (double) SAMPLE, (y+2) / (double) SAMPLE);
403 cairo_line_to (cr, (x+2) / (double) SAMPLE, (y) / (double) SAMPLE);
404 cairo_close_path (cr);
413 return CAIRO_TEST_SUCCESS;
416 static cairo_test_status_t
417 overlap_three_quarter_triangles (cairo_t *cr, int width, int height)
423 occupancy = xmalloc (SAMPLE*SAMPLE);
425 cairo_set_source_rgb (cr, 0.0, 0.0, 0.0);
428 cairo_set_operator (cr, CAIRO_OPERATOR_ADD);
429 for (channel = 0; channel < 3; channel++) {
432 case 0: cairo_set_source_rgb (cr, 1.0, 0.0, 0.0); break;
433 case 1: cairo_set_source_rgb (cr, 0.0, 1.0, 0.0); break;
434 case 2: cairo_set_source_rgb (cr, 0.0, 0.0, 1.0); break;
437 for (i = 0; i < SIZE*SIZE; i++) {
440 compute_occupancy (occupancy, SAMPLE/2*SAMPLE/2 * i / (SIZE * SIZE), SAMPLE/2*SAMPLE/2);
442 xs = i % SIZE * SAMPLE;
443 ys = i / SIZE * SAMPLE;
444 for (j = 0; j < SAMPLE/2*SAMPLE/2; j++) {
446 int x = 2 * (j % (SAMPLE/2)) + xs;
447 int y = 2 * (j / (SAMPLE/2)) + ys;
449 /* Add a 4-tile composed of two overlapping triangles.
458 * Coverage should be computable as 75%.
461 cairo_move_to (cr, (x) / (double) SAMPLE, (y) / (double) SAMPLE);
462 cairo_line_to (cr, (x) / (double) SAMPLE, (y+2) / (double) SAMPLE);
463 cairo_line_to (cr, (x+2) / (double) SAMPLE, (y) / (double) SAMPLE);
464 cairo_close_path (cr);
466 cairo_move_to (cr, (x) / (double) SAMPLE, (y) / (double) SAMPLE);
467 cairo_line_to (cr, (x+2) / (double) SAMPLE, (y+2) / (double) SAMPLE);
468 cairo_line_to (cr, (x+2) / (double) SAMPLE, (y) / (double) SAMPLE);
469 cairo_close_path (cr);
478 return CAIRO_TEST_SUCCESS;
481 static cairo_test_status_t
482 triangles (cairo_t *cr, int width, int height)
488 occupancy = xmalloc (SAMPLE*SAMPLE);
490 cairo_set_source_rgb (cr, 0.0, 0.0, 0.0);
493 cairo_set_operator (cr, CAIRO_OPERATOR_ADD);
494 for (channel = 0; channel < 3; channel++) {
497 case 0: cairo_set_source_rgb (cr, 1.0, 0.0, 0.0); break;
498 case 1: cairo_set_source_rgb (cr, 0.0, 1.0, 0.0); break;
499 case 2: cairo_set_source_rgb (cr, 0.0, 0.0, 1.0); break;
502 for (i = 0; i < SIZE*SIZE; i++) {
505 compute_occupancy (occupancy, SAMPLE*SAMPLE * i / (SIZE * SIZE), SAMPLE*SAMPLE);
507 xs = i % SIZE * SAMPLE;
508 ys = i / SIZE * SAMPLE;
509 for (j = 0; j < SAMPLE*SAMPLE; j++) {
511 /* Add a tile composed of two non-overlapping triangles.
517 int x = j % SAMPLE + xs;
518 int y = j / SAMPLE + ys;
520 /* top-left triangle */
521 cairo_move_to (cr, (x) / (double) SAMPLE, (y) / (double) SAMPLE);
522 cairo_line_to (cr, (x+1) / (double) SAMPLE, (y) / (double) SAMPLE);
523 cairo_line_to (cr, (x) / (double) SAMPLE, (y+1) / (double) SAMPLE);
524 cairo_close_path (cr);
526 /* bottom-right triangle */
527 cairo_move_to (cr, (x) / (double) SAMPLE, (y+1) / (double) SAMPLE);
528 cairo_line_to (cr, (x+1) / (double) SAMPLE, (y+1) / (double) SAMPLE);
529 cairo_line_to (cr, (x+1) / (double) SAMPLE, (y) / (double) SAMPLE);
530 cairo_close_path (cr);
539 return CAIRO_TEST_SUCCESS;
542 static cairo_test_status_t
543 intersecting_triangles (cairo_t *cr, int width, int height)
549 occupancy = xmalloc (SAMPLE*SAMPLE);
551 cairo_set_source_rgb (cr, 0.0, 0.0, 0.0);
554 cairo_set_operator (cr, CAIRO_OPERATOR_ADD);
555 for (channel = 0; channel < 3; channel++) {
558 case 0: cairo_set_source_rgb (cr, 1.0, 0.0, 0.0); break;
559 case 1: cairo_set_source_rgb (cr, 0.0, 1.0, 0.0); break;
560 case 2: cairo_set_source_rgb (cr, 0.0, 0.0, 1.0); break;
563 for (i = 0; i < SIZE*SIZE; i++) {
566 compute_occupancy (occupancy, SAMPLE*SAMPLE * i / (SIZE * SIZE), SAMPLE*SAMPLE);
568 xs = i % SIZE * SAMPLE;
569 ys = i / SIZE * SAMPLE;
570 for (j = 0; j < SAMPLE*SAMPLE; j++) {
572 /* Add 2 overlapping tiles in a single cell, each composed
573 * of two non-overlapping triangles.
579 int x = j % SAMPLE + xs;
580 int y = j / SAMPLE + ys;
582 /* first pair of triangles, diagonal bottom-left to top-right */
583 cairo_move_to (cr, (x) / (double) SAMPLE, (y) / (double) SAMPLE);
584 cairo_line_to (cr, (x+1) / (double) SAMPLE, (y) / (double) SAMPLE);
585 cairo_line_to (cr, (x) / (double) SAMPLE, (y+1) / (double) SAMPLE);
586 cairo_close_path (cr);
587 cairo_move_to (cr, (x) / (double) SAMPLE, (y+1) / (double) SAMPLE);
588 cairo_line_to (cr, (x+1) / (double) SAMPLE, (y+1) / (double) SAMPLE);
589 cairo_line_to (cr, (x+1) / (double) SAMPLE, (y) / (double) SAMPLE);
590 cairo_close_path (cr);
592 /* second pair of triangles, diagonal top-left to bottom-right */
593 cairo_move_to (cr, (x) / (double) SAMPLE, (y) / (double) SAMPLE);
594 cairo_line_to (cr, (x+1) / (double) SAMPLE, (y+1) / (double) SAMPLE);
595 cairo_line_to (cr, (x+1) / (double) SAMPLE, (y) / (double) SAMPLE);
596 cairo_close_path (cr);
597 cairo_move_to (cr, (x) / (double) SAMPLE, (y) / (double) SAMPLE);
598 cairo_line_to (cr, (x+1) / (double) SAMPLE, (y+1) / (double) SAMPLE);
599 cairo_line_to (cr, (x) / (double) SAMPLE, (y+1) / (double) SAMPLE);
600 cairo_close_path (cr);
609 return CAIRO_TEST_SUCCESS;
612 CAIRO_TEST (partial_coverage_rectangles,
613 "Check the fidelity of the rasterisation.",
614 "coverage raster", /* keywords */
615 "target=raster slow", /* requirements */
619 CAIRO_TEST (partial_coverage_intersecting_quads,
620 "Check the fidelity of the rasterisation.",
621 "coverage raster", /* keywords */
622 "target=raster slow", /* requirements */
624 NULL, intersecting_quads)
626 CAIRO_TEST (partial_coverage_intersecting_triangles,
627 "Check the fidelity of the rasterisation.",
628 "coverage raster", /* keywords */
629 "target=raster slow", /* requirements */
631 NULL, intersecting_triangles)
632 CAIRO_TEST (partial_coverage_triangles,
633 "Check the fidelity of the rasterisation.",
634 "coverage raster", /* keywords */
635 "target=raster slow", /* requirements */
638 CAIRO_TEST (partial_coverage_overlap_three_quarter_triangles,
639 "Check the fidelity of the rasterisation.",
640 "coverage raster", /* keywords */
641 "target=raster slow", /* requirements */
643 NULL, overlap_three_quarter_triangles)
644 CAIRO_TEST (partial_coverage_overlap_half_triangles_eo,
645 "Check the fidelity of the rasterisation.",
646 "coverage raster", /* keywords */
647 "target=raster slow", /* requirements */
649 NULL, overlap_half_triangles_eo)
650 CAIRO_TEST (partial_coverage_overlap_half_triangles,
651 "Check the fidelity of the rasterisation.",
652 "coverage raster", /* keywords */
653 "target=raster slow", /* requirements */
655 NULL, overlap_half_triangles)
656 CAIRO_TEST (partial_coverage_half_triangles,
657 "Check the fidelity of the rasterisation.",
658 "coverage raster", /* keywords */
659 "target=raster slow", /* requirements */
661 NULL, half_triangles)
663 CAIRO_TEST (partial_coverage_reference,
664 "Check the fidelity of this test.",
665 "coverage raster", /* keywords */
666 "target=raster", /* requirements */
669 CAIRO_TEST (partial_coverage_three_quarter_reference,
670 "Check the fidelity of this test.",
671 "coverage raster", /* keywords */
672 "target=raster", /* requirements */
674 NULL, three_quarter_reference)
675 CAIRO_TEST (partial_coverage_half_reference,
676 "Check the fidelity of this test.",
677 "coverage raster", /* keywords */
678 "target=raster", /* requirements */
680 NULL, half_reference)