1
/*
2
 * Copyright © 2011 Uli Schlachter
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: Uli Schlachter <psychon@znc.in>
25
 */
26

            
27
#include "cairo-test.h"
28

            
29
180
static void path_none (cairo_t *cr, int size)
30
{
31
180
}
32

            
33
360
static void path_box (cairo_t *cr, int size)
34
{
35
360
    cairo_rectangle (cr, 0, 0, size, size);
36
360
}
37

            
38
360
static void path_box_unaligned (cairo_t *cr, int size)
39
{
40
360
    cairo_rectangle (cr, 0.5, 0.5, size - 1, size - 1);
41
360
}
42

            
43
360
static void path_triangle (cairo_t *cr, int size)
44
{
45
360
    cairo_move_to (cr, 0, 0);
46
360
    cairo_line_to (cr, size/2, size);
47
360
    cairo_line_to (cr, size, 0);
48
360
    cairo_close_path (cr);
49
360
}
50

            
51
360
static void path_circle (cairo_t *cr, int size)
52
{
53
360
    cairo_arc (cr, size / 2.0, size / 2.0, size / 2.0, 0, 2 * M_PI);
54
360
}
55

            
56
static void (* const path_funcs[])(cairo_t *cr, int size) = {
57
    path_none,
58
    path_box,
59
    path_box_unaligned,
60
    path_triangle,
61
    path_circle
62
};
63

            
64
#define SIZE 20
65
#define PAD 2
66
#define TYPES 6
67
/* All-clipped is boring, thus we skip path_none for clipping */
68
#define CLIP_OFFSET 1
69
#define IMAGE_WIDTH ((ARRAY_LENGTH (path_funcs) - CLIP_OFFSET) * TYPES * (SIZE + PAD) - PAD)
70
#define IMAGE_HEIGHT (ARRAY_LENGTH (path_funcs) * (SIZE + PAD) - PAD)
71

            
72
static void
73
360
draw_idx (cairo_t *cr, int i, int j, int type)
74
{
75
    cairo_bool_t little_path;
76
    cairo_bool_t empty_clip;
77
    cairo_bool_t little_clip;
78

            
79
    /* The lowest bit controls the path, the rest the clip */
80
360
    little_path = type & 1;
81

            
82
    /* We don't want the combination "empty_clip = TRUE, little_clip = FALSE"
83
     * (== all clipped).
84
     */
85
360
    switch (type >> 1)
86
    {
87
120
    case 0:
88
120
	empty_clip = FALSE;
89
120
	little_clip = FALSE;
90
120
	break;
91
120
    case 1:
92
120
	empty_clip = FALSE;
93
120
	little_clip = TRUE;
94
120
	break;
95
120
    case 2:
96
120
	empty_clip = TRUE;
97
120
	little_clip = TRUE;
98
120
	break;
99
    default:
100
	return;
101
    }
102

            
103
360
    cairo_save (cr);
104

            
105
    /* Thanks to the fill rule, drawing something twice removes it again */
106
360
    cairo_set_fill_rule (cr, CAIRO_FILL_RULE_EVEN_ODD);
107

            
108
360
    path_funcs[i] (cr, SIZE);
109
360
    if (empty_clip)
110
120
	path_funcs[i] (cr, SIZE);
111
360
    if (little_clip)
112
    {
113
240
	cairo_save (cr);
114
240
	cairo_translate (cr, SIZE / 4, SIZE / 4);
115
240
	path_funcs[i] (cr, SIZE / 2);
116
240
	cairo_restore (cr);
117
    }
118
360
    cairo_clip (cr);
119

            
120
360
    path_funcs[j] (cr, SIZE);
121
360
    path_funcs[j] (cr, SIZE);
122
360
    if (little_path)
123
    {
124
	/* Draw the object again in the center of itself */
125
180
	cairo_save (cr);
126
180
	cairo_translate (cr, SIZE / 4, SIZE / 4);
127
180
	path_funcs[j] (cr, SIZE / 2);
128
180
	cairo_restore (cr);
129
    }
130
360
    cairo_fill (cr);
131
360
    cairo_restore (cr);
132
}
133

            
134
static cairo_test_status_t
135
3
draw (cairo_t *cr, int width, int height)
136
{
137
    size_t i, j, k;
138

            
139
3
    cairo_set_source_rgb (cr, 0, 1, 0);
140
3
    cairo_paint (cr);
141

            
142
    /* Set an unbounded operator so that we can see how accurate the bounded
143
     * extents were.
144
     */
145
3
    cairo_set_operator (cr, CAIRO_OPERATOR_IN);
146
3
    cairo_set_source_rgb (cr, 1, 1, 1);
147

            
148
18
    for (j = 0; j < ARRAY_LENGTH (path_funcs); j++) {
149
15
	cairo_save (cr);
150
75
	for (i = CLIP_OFFSET; i < ARRAY_LENGTH (path_funcs); i++) {
151
420
	    for (k = 0; k < TYPES; k++) {
152
360
		cairo_save (cr);
153
360
		cairo_rectangle (cr, 0, 0, SIZE, SIZE);
154
360
		cairo_clip (cr);
155
360
		draw_idx (cr, i, j, k);
156
360
		cairo_restore (cr);
157
360
		cairo_translate (cr, SIZE + PAD, 0);
158
	    }
159
	}
160
15
	cairo_restore (cr);
161
15
	cairo_translate (cr, 0, SIZE + PAD);
162
    }
163

            
164
3
    return CAIRO_TEST_SUCCESS;
165
}
166

            
167
1
CAIRO_TEST (tighten_bounds,
168
	    "Tests that we tighten the bounds after tessellation.",
169
	    "fill", /* keywords */
170
	    NULL, /* requirements */
171
	    IMAGE_WIDTH, IMAGE_HEIGHT,
172
	    NULL, draw)