1
/*
2
 * Copyright 2014 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
#include "../src/cairo-fixed-type-private.h"
36

            
37
#if GENERATE_REFERENCE
38
#include <assert.h>
39
struct coverage {
40
	int width, height;
41
	struct {
42
		int uncovered_area;
43
		int covered_height;
44
	} cells[0];
45
};
46

            
47
static int pfloor (int v)
48
{
49
    return v >> CAIRO_FIXED_FRAC_BITS;
50
}
51

            
52
static int pfrac (int v)
53
{
54
    return v & ((1 << CAIRO_FIXED_FRAC_BITS) - 1);
55
}
56

            
57
static void add_edge (struct coverage *coverage,
58
		      int x1, int y1, int x2, int y2,
59
		      int sign)
60
{
61
    int dx, dy;
62
    int dxdy_quo, dxdy_rem;
63
    int xq, xr;
64
    int y, t;
65

            
66
    if (y2 < y1) {
67
	t = y1;
68
	y1 = y2;
69
	y2 = t;
70

            
71
	t = x1;
72
	x1 = x2;
73
	x2 = t;
74

            
75
	sign = -sign;
76
    }
77

            
78
    dx = x2 - x1;
79
    dy = y2 - y1;
80
    if (dy == 0)
81
	return;
82

            
83
    dy *= 2;
84

            
85
    dxdy_quo = 2*dx / dy;
86
    dxdy_rem = 2*dx % dy;
87

            
88
    xq = x1 + dxdy_quo / 2;
89
    xr = dxdy_rem / 2;
90
    if (xr < 0) {
91
	xq--;
92
	xr += dy;
93
    }
94

            
95
    for (y = MAX(0, y1); y < MIN(y2, 256*coverage->height); y++) {
96
	int x = xq + (xr >= dy/2);
97

            
98
	if (x < 256*coverage->width) {
99
		int i = pfloor (y) * coverage->width;
100
		if (x > 0) {
101
			i += pfloor (x);
102
			coverage->cells[i].uncovered_area += sign * pfrac(x);
103
		}
104
		coverage->cells[i].covered_height += sign;
105
	}
106

            
107
	xq += dxdy_quo;
108
	xr += dxdy_rem;
109
	if (xr < 0) {
110
	    xq--;
111
	    xr += dy;
112
	} else if (xr >= dy) {
113
	    xq++;
114
	    xr -= dy;
115
	}
116
    }
117
}
118

            
119
static struct coverage *
120
coverage_create (int width, int height)
121
{
122
    int size;
123
    struct coverage *c;
124

            
125
    size = sizeof (struct coverage);
126
    size += width * height * sizeof (int) * 2;
127

            
128
    c = malloc (size);
129
    if (c == NULL)
130
	return c;
131

            
132
    memset(c, 0, size);
133
    c->width = width;
134
    c->height = height;
135

            
136
    return c;
137
}
138

            
139
static cairo_surface_t *
140
coverage_to_alpha (struct coverage *c)
141
{
142
    cairo_surface_t *image;
143
    uint8_t *data;
144
    int x, y, stride;
145

            
146
    image = cairo_image_surface_create (CAIRO_FORMAT_A8, c->width, c->height);
147

            
148
    data = cairo_image_surface_get_data (image);
149
    stride = cairo_image_surface_get_stride (image);
150

            
151
    cairo_surface_flush (image);
152
    for (y = 0; y < c->height; y++) {
153
	uint8_t *row = data + y *stride;
154
	int cover = 0;
155
	for (x = 0; x < c->width; x++) {
156
	    int v = y*c->width + x;
157

            
158
	    cover += c->cells[v].covered_height * 256;
159
	    v = cover - c->cells[v].uncovered_area;
160

            
161
	    v /= 256;
162
	    if (v < 0)
163
		v = -v;
164
	    row[x] = v - (v >> 8);
165
	}
166
    }
167
    cairo_surface_mark_dirty (image);
168

            
169
    free (c);
170
    return image;
171
}
172
#endif
173

            
174
static cairo_test_status_t
175
3
edge (cairo_t *cr, int width, int height)
176
{
177
3
    cairo_set_source_rgb (cr, 0.0, 0.0, 0.0);
178
3
    cairo_paint (cr);
179

            
180
3
    cairo_set_operator (cr, CAIRO_OPERATOR_ADD);
181

            
182
#if GENERATE_REFERENCE
183
    {
184
	struct coverage *c;
185
	cairo_surface_t *mask;
186

            
187
	cairo_set_source_rgb (cr, 1, 0, 0);
188

            
189
	c = coverage_create (width, height);
190
	add_edge (c, 128*256, 129*256, 129*256,   1*256, 1);
191
	add_edge (c, 128*256, 129*256, 128*256, 131*256, -1);
192
	add_edge (c, 128*256, 131*256, 129*256, 259*256, -1);
193
	add_edge (c, 130*256, 129*256, 129*256,   1*256, -1);
194
	add_edge (c, 130*256, 129*256, 130*256, 131*256, 1);
195
	add_edge (c, 130*256, 131*256, 129*256, 259*256, 1);
196
	mask = coverage_to_alpha (c);
197
	cairo_mask_surface (cr, mask, 0, 0);
198
	cairo_surface_destroy (mask);
199

            
200
	c = coverage_create (width, height);
201
	add_edge (c, 128*256/2, 129*256/2, 129*256/2,   1*256/2, 1);
202
	add_edge (c, 128*256/2, 129*256/2, 128*256/2, 131*256/2, -1);
203
	add_edge (c, 128*256/2, 131*256/2, 129*256/2, 259*256/2, -1);
204
	add_edge (c, 130*256/2, 129*256/2, 129*256/2,   1*256/2, -1);
205
	add_edge (c, 130*256/2, 129*256/2, 130*256/2, 131*256/2, 1);
206
	add_edge (c, 130*256/2, 131*256/2, 129*256/2, 259*256/2, 1);
207
	mask = coverage_to_alpha (c);
208
	cairo_mask_surface (cr, mask, 0, 0);
209
	cairo_surface_destroy (mask);
210

            
211
	c = coverage_create (width, height);
212
	add_edge (c, (192-2)*256, 129*256, 192*256,   1*256, 1);
213
	add_edge (c, (192-2)*256, 129*256, (192-2)*256, 131*256, -1);
214
	add_edge (c, (192-2)*256, 131*256, 192*256, 259*256, -1);
215
	add_edge (c, (192+2)*256, 129*256, 192*256,   1*256, -1);
216
	add_edge (c, (192+2)*256, 129*256, (192+2)*256, 131*256, 1);
217
	add_edge (c, (192+2)*256, 131*256, 192*256, 259*256, 1);
218
	mask = coverage_to_alpha (c);
219
	cairo_mask_surface (cr, mask, 0, 0);
220
	cairo_surface_destroy (mask);
221

            
222
	c = coverage_create (width, height);
223
	add_edge (c, (256-4)*256, 129*256, 256*256,   1*256, 1);
224
	add_edge (c, (256-4)*256, 129*256, (256-4)*256, 131*256, -1);
225
	add_edge (c, (256-4)*256, 131*256, 256*256, 259*256, -1);
226
	add_edge (c, (256+4)*256, 129*256, 256*256,   1*256, -1);
227
	add_edge (c, (256+4)*256, 129*256, (256+4)*256, 131*256, 1);
228
	add_edge (c, (256+4)*256, 131*256, 256*256, 259*256, 1);
229
	mask = coverage_to_alpha (c);
230
	cairo_mask_surface (cr, mask, 0, 0);
231
	cairo_surface_destroy (mask);
232

            
233
	cairo_set_source_rgb (cr, 0, 1, 0);
234

            
235
	c = coverage_create (width, height);
236
	add_edge (c,   1*256, 129*256, 129*256, 128*256, 1);
237
	add_edge (c, 131*256, 128*256, 259*256, 129*256, 1);
238
	add_edge (c,   1*256, 129*256, 129*256, 130*256, -1);
239
	add_edge (c, 131*256, 130*256, 259*256, 129*256, -1);
240
	mask = coverage_to_alpha (c);
241
	cairo_mask_surface (cr, mask, 0, 0);
242
	cairo_surface_destroy (mask);
243

            
244
	c = coverage_create (width, height);
245
	add_edge (c,   1*256/2, 129*256/2, 129*256/2, 128*256/2, 1);
246
	add_edge (c, 131*256/2, 128*256/2, 259*256/2, 129*256/2, 1);
247
	add_edge (c,   1*256/2, 129*256/2, 129*256/2, 130*256/2, -1);
248
	add_edge (c, 131*256/2, 130*256/2, 259*256/2, 129*256/2, -1);
249
	mask = coverage_to_alpha (c);
250
	cairo_mask_surface (cr, mask, 0, 0);
251
	cairo_surface_destroy (mask);
252

            
253
	c = coverage_create (width, height);
254
	add_edge (c,   1*256, (192-0)*256, 129*256, (192-2)*256, 1);
255
	add_edge (c, 131*256, (192-2)*256, 259*256, (192-0)*256, 1);
256
	add_edge (c,   1*256, (192+0)*256, 129*256, (192+2)*256, -1);
257
	add_edge (c, 131*256, (192+2)*256, 259*256, (192+0)*256, -1);
258
	mask = coverage_to_alpha (c);
259
	cairo_mask_surface (cr, mask, 0, 0);
260
	cairo_surface_destroy (mask);
261

            
262
	c = coverage_create (width, height);
263
	add_edge (c,   1*256, (256-0)*256, 129*256, (256-4)*256, 1);
264
	add_edge (c, 131*256, (256-4)*256, 259*256, (256-0)*256, 1);
265
	add_edge (c,   1*256, (256+0)*256, 129*256, (256+4)*256, -1);
266
	add_edge (c, 131*256, (256+4)*256, 259*256, (256+0)*256, -1);
267
	mask = coverage_to_alpha (c);
268
	cairo_mask_surface (cr, mask, 0, 0);
269
	cairo_surface_destroy (mask);
270
    }
271
#else
272
3
    cairo_set_source_rgb (cr, 1, 0, 0);
273
3
    cairo_move_to (cr, 129,   1);
274
3
    cairo_line_to (cr, 128, 129);
275
3
    cairo_line_to (cr, 128, 131);
276
3
    cairo_line_to (cr, 129, 259);
277
3
    cairo_line_to (cr, 130, 131);
278
3
    cairo_line_to (cr, 130, 129);
279
3
    cairo_fill (cr);
280

            
281
3
    cairo_move_to (cr, 129/2.,   1/2.);
282
3
    cairo_line_to (cr, 128/2., 129/2.);
283
3
    cairo_line_to (cr, 128/2., 131/2.);
284
3
    cairo_line_to (cr, 129/2., 259/2.);
285
3
    cairo_line_to (cr, 130/2., 131/2.);
286
3
    cairo_line_to (cr, 130/2., 129/2.);
287
3
    cairo_fill (cr);
288

            
289
3
    cairo_move_to (cr, 192,   1);
290
3
    cairo_line_to (cr, 192-2, 129);
291
3
    cairo_line_to (cr, 192-2, 131);
292
3
    cairo_line_to (cr, 192, 259);
293
3
    cairo_line_to (cr, 192+2, 131);
294
3
    cairo_line_to (cr, 192+2, 129);
295
3
    cairo_fill (cr);
296

            
297
3
    cairo_move_to (cr, 256,   1);
298
3
    cairo_line_to (cr, 256-4, 129);
299
3
    cairo_line_to (cr, 256-4, 131);
300
3
    cairo_line_to (cr, 256, 259);
301
3
    cairo_line_to (cr, 256+4, 131);
302
3
    cairo_line_to (cr, 256+4, 129);
303
3
    cairo_fill (cr);
304

            
305
3
    cairo_set_source_rgb (cr, 0, 1, 0);
306
3
    cairo_move_to (cr,   1, 129);
307
3
    cairo_line_to (cr, 129, 128);
308
3
    cairo_line_to (cr, 131, 128);
309
3
    cairo_line_to (cr, 259, 129);
310
3
    cairo_line_to (cr, 131, 130);
311
3
    cairo_line_to (cr, 129, 130);
312
3
    cairo_fill (cr);
313

            
314
3
    cairo_move_to (cr,   1/2., 129/2.);
315
3
    cairo_line_to (cr, 129/2., 128/2.);
316
3
    cairo_line_to (cr, 131/2., 128/2.);
317
3
    cairo_line_to (cr, 259/2., 129/2.);
318
3
    cairo_line_to (cr, 131/2., 130/2.);
319
3
    cairo_line_to (cr, 129/2., 130/2.);
320
3
    cairo_fill (cr);
321

            
322
3
    cairo_move_to (cr,   1, 192);
323
3
    cairo_line_to (cr, 129, 192-2);
324
3
    cairo_line_to (cr, 131, 192-2);
325
3
    cairo_line_to (cr, 259, 192);
326
3
    cairo_line_to (cr, 131, 192+2);
327
3
    cairo_line_to (cr, 129, 192+2);
328
3
    cairo_fill (cr);
329

            
330
3
    cairo_move_to (cr,   1, 256);
331
3
    cairo_line_to (cr, 129, 256-4);
332
3
    cairo_line_to (cr, 131, 256-4);
333
3
    cairo_line_to (cr, 259, 256);
334
3
    cairo_line_to (cr, 131, 256+4);
335
3
    cairo_line_to (cr, 129, 256+4);
336
3
    cairo_fill (cr);
337
#endif
338

            
339
3
    return CAIRO_TEST_SUCCESS;
340
}
341

            
342
1
CAIRO_TEST (simple_edge,
343
	    "Check the fidelity of the rasterisation.",
344
	    NULL, /* keywords */
345
	    "target=raster", /* requirements */
346
	    260, 260,
347
	    NULL, edge)