Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
1892 serge 1
/* cairo - a vector graphics library with display and print output
2
 *
3
 * Copyright © 2002 University of Southern California
4
 *
5
 * This library is free software; you can redistribute it and/or
6
 * modify it either under the terms of the GNU Lesser General Public
7
 * License version 2.1 as published by the Free Software Foundation
8
 * (the "LGPL") or, at your option, under the terms of the Mozilla
9
 * Public License Version 1.1 (the "MPL"). If you do not alter this
10
 * notice, a recipient may use your version of this file under either
11
 * the MPL or the LGPL.
12
 *
13
 * You should have received a copy of the LGPL along with this library
14
 * in the file COPYING-LGPL-2.1; if not, write to the Free Software
15
 * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
16
 * You should have received a copy of the MPL along with this library
17
 * in the file COPYING-MPL-1.1
18
 *
19
 * The contents of this file are subject to the Mozilla Public License
20
 * Version 1.1 (the "License"); you may not use this file except in
21
 * compliance with the License. You may obtain a copy of the License at
22
 * http://www.mozilla.org/MPL/
23
 *
24
 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
25
 * OF ANY KIND, either express or implied. See the LGPL or the MPL for
26
 * the specific language governing rights and limitations.
27
 *
28
 * The Original Code is the cairo graphics library.
29
 *
30
 * The Initial Developer of the Original Code is University of Southern
31
 * California.
32
 *
33
 * Contributor(s):
34
 *	Carl D. Worth 
35
 */
36
 
37
#include "cairoint.h"
38
#include "cairo-boxes-private.h"
39
#include "cairo-error-private.h"
40
#include "cairo-path-fixed-private.h"
41
#include "cairo-region-private.h"
42
 
43
typedef struct cairo_filler {
44
    double tolerance;
45
    cairo_polygon_t *polygon;
46
} cairo_filler_t;
47
 
48
static void
49
_cairo_filler_init (cairo_filler_t *filler,
50
		    double tolerance,
51
		    cairo_polygon_t *polygon)
52
{
53
    filler->tolerance = tolerance;
54
    filler->polygon = polygon;
55
}
56
 
57
static void
58
_cairo_filler_fini (cairo_filler_t *filler)
59
{
60
}
61
 
62
static cairo_status_t
63
_cairo_filler_move_to (void *closure,
64
		       const cairo_point_t *point)
65
{
66
    cairo_filler_t *filler = closure;
67
    cairo_polygon_t *polygon = filler->polygon;
68
 
69
    return _cairo_polygon_close (polygon) ||
70
           _cairo_polygon_move_to (polygon, point);
71
}
72
 
73
static cairo_status_t
74
_cairo_filler_line_to (void *closure,
75
		       const cairo_point_t *point)
76
{
77
    cairo_filler_t *filler = closure;
78
    return _cairo_polygon_line_to (filler->polygon, point);
79
}
80
 
81
static cairo_status_t
82
_cairo_filler_curve_to (void *closure,
83
			const cairo_point_t *b,
84
			const cairo_point_t *c,
85
			const cairo_point_t *d)
86
{
87
    cairo_filler_t *filler = closure;
88
    cairo_spline_t spline;
89
 
90
    if (! _cairo_spline_init (&spline,
91
			      _cairo_filler_line_to, filler,
92
			      &filler->polygon->current_point, b, c, d))
93
    {
94
	return _cairo_filler_line_to (closure, d);
95
    }
96
 
97
    return _cairo_spline_decompose (&spline, filler->tolerance);
98
}
99
 
100
static cairo_status_t
101
_cairo_filler_close_path (void *closure)
102
{
103
    cairo_filler_t *filler = closure;
104
    return _cairo_polygon_close (filler->polygon);
105
}
106
 
107
cairo_status_t
108
_cairo_path_fixed_fill_to_polygon (const cairo_path_fixed_t *path,
109
				   double tolerance,
110
				   cairo_polygon_t *polygon)
111
{
112
    cairo_filler_t filler;
113
    cairo_status_t status;
114
 
115
    _cairo_filler_init (&filler, tolerance, polygon);
116
 
117
    status = _cairo_path_fixed_interpret (path,
118
					  CAIRO_DIRECTION_FORWARD,
119
					  _cairo_filler_move_to,
120
					  _cairo_filler_line_to,
121
					  _cairo_filler_curve_to,
122
					  _cairo_filler_close_path,
123
					  &filler);
124
    if (unlikely (status))
125
	return status;
126
 
127
    status = _cairo_polygon_close (polygon);
128
    _cairo_filler_fini (&filler);
129
 
130
    return status;
131
}
132
 
133
cairo_status_t
134
_cairo_path_fixed_fill_to_traps (const cairo_path_fixed_t *path,
135
				 cairo_fill_rule_t fill_rule,
136
				 double tolerance,
137
				 cairo_traps_t *traps)
138
{
139
    cairo_polygon_t polygon;
140
    cairo_status_t status;
141
 
142
    if (path->is_empty_fill)
143
	return CAIRO_STATUS_SUCCESS;
144
 
145
    _cairo_polygon_init (&polygon);
146
    if (traps->num_limits)
147
	_cairo_polygon_limit (&polygon, traps->limits, traps->num_limits);
148
 
149
    status = _cairo_path_fixed_fill_to_polygon (path,
150
						tolerance,
151
						&polygon);
152
    if (unlikely (status || polygon.num_edges == 0))
153
	goto CLEANUP;
154
 
155
    if (path->is_rectilinear) {
156
	status = _cairo_bentley_ottmann_tessellate_rectilinear_polygon (traps,
157
									&polygon,
158
									fill_rule);
159
    } else {
160
	status = _cairo_bentley_ottmann_tessellate_polygon (traps,
161
							    &polygon,
162
							    fill_rule);
163
    }
164
 
165
  CLEANUP:
166
    _cairo_polygon_fini (&polygon);
167
    return status;
168
}
169
 
170
static cairo_region_t *
171
_cairo_path_fixed_fill_rectilinear_tessellate_to_region (const cairo_path_fixed_t	*path,
172
							 cairo_fill_rule_t	 fill_rule,
173
							 const cairo_rectangle_int_t *extents)
174
{
175
    cairo_box_t box;
176
    cairo_polygon_t polygon;
177
    cairo_traps_t traps;
178
    cairo_status_t status;
179
    cairo_region_t *region;
180
 
181
    /* first try to bypass fill-to-polygon */
182
    _cairo_traps_init (&traps);
183
    status = _cairo_path_fixed_fill_rectilinear_to_traps (path,
184
							  fill_rule,
185
							  &traps);
186
    if (_cairo_status_is_error (status))
187
	goto CLEANUP_TRAPS;
188
 
189
    if (status == CAIRO_STATUS_SUCCESS) {
190
	status = _cairo_traps_extract_region (&traps, ®ion);
191
	goto CLEANUP_TRAPS;
192
    }
193
 
194
    /* path is not rectangular, try extracting clipped rectilinear edges */
195
    _cairo_polygon_init (&polygon);
196
    if (extents != NULL) {
197
	_cairo_box_from_rectangle (&box, extents);
198
	_cairo_polygon_limit (&polygon, &box, 1);
199
    }
200
 
201
    /* tolerance will be ignored as the path is rectilinear */
202
    status = _cairo_path_fixed_fill_to_polygon (path, 0., &polygon);
203
    if (unlikely (status))
204
	goto CLEANUP_POLYGON;
205
 
206
    if (polygon.num_edges == 0) {
207
	region = cairo_region_create ();
208
    } else {
209
	status =
210
	    _cairo_bentley_ottmann_tessellate_rectilinear_polygon (&traps,
211
								   &polygon,
212
								   fill_rule);
213
	if (likely (status == CAIRO_STATUS_SUCCESS))
214
	    status = _cairo_traps_extract_region (&traps, ®ion);
215
    }
216
 
217
  CLEANUP_POLYGON:
218
    _cairo_polygon_fini (&polygon);
219
 
220
  CLEANUP_TRAPS:
221
    _cairo_traps_fini (&traps);
222
 
223
    if (unlikely (status))
224
	region = _cairo_region_create_in_error (status);
225
 
226
    return region;
227
}
228
 
229
/* This special-case filler supports only a path that describes a
230
 * device-axis aligned rectangle. It exists to avoid the overhead of
231
 * the general tessellator when drawing very common rectangles.
232
 *
233
 * If the path described anything but a device-axis aligned rectangle,
234
 * this function will abort.
235
 */
236
cairo_region_t *
237
_cairo_path_fixed_fill_rectilinear_to_region (const cairo_path_fixed_t	*path,
238
					      cairo_fill_rule_t	 fill_rule,
239
					      const cairo_rectangle_int_t *extents)
240
{
241
    cairo_rectangle_int_t rectangle_stack[CAIRO_STACK_ARRAY_LENGTH (cairo_rectangle_int_t)];
242
    cairo_box_t box;
243
    cairo_region_t *region = NULL;
244
 
245
    assert (path->maybe_fill_region);
246
    assert (! path->is_empty_fill);
247
 
248
    if (_cairo_path_fixed_is_box (path, &box)) {
249
	rectangle_stack[0].x = _cairo_fixed_integer_part (box.p1.x);
250
	rectangle_stack[0].y = _cairo_fixed_integer_part (box.p1.y);
251
	rectangle_stack[0].width = _cairo_fixed_integer_part (box.p2.x) -
252
	                            rectangle_stack[0].x;
253
	rectangle_stack[0].height = _cairo_fixed_integer_part (box.p2.y) -
254
	                            rectangle_stack[0].y;
255
	if (! _cairo_rectangle_intersect (&rectangle_stack[0], extents))
256
	    region = cairo_region_create ();
257
	else
258
	    region = cairo_region_create_rectangle (&rectangle_stack[0]);
259
    } else if (fill_rule == CAIRO_FILL_RULE_WINDING) {
260
	cairo_rectangle_int_t *rects = rectangle_stack;
261
	cairo_path_fixed_iter_t iter;
262
	int last_cw = -1;
263
	int size = ARRAY_LENGTH (rectangle_stack);
264
	int count = 0;
265
 
266
	/* Support a series of rectangles as can be expected to describe a
267
	 * GdkRegion clip region during exposes.
268
	 */
269
	_cairo_path_fixed_iter_init (&iter, path);
270
	while (_cairo_path_fixed_iter_is_fill_box (&iter, &box)) {
271
	    int cw = 0;
272
 
273
	    if (box.p1.x > box.p2.x) {
274
		cairo_fixed_t t;
275
 
276
		t = box.p1.x;
277
		box.p1.x = box.p2.x;
278
		box.p2.x = t;
279
 
280
		cw = ! cw;
281
	    }
282
 
283
	    if (box.p1.y > box.p2.y) {
284
		cairo_fixed_t t;
285
 
286
		t = box.p1.y;
287
		box.p1.y = box.p2.y;
288
		box.p2.y = t;
289
 
290
		cw = ! cw;
291
	    }
292
 
293
	    if (last_cw < 0)
294
		last_cw = cw;
295
	    else if (last_cw != cw)
296
		goto TESSELLATE;
297
 
298
	    if (count == size) {
299
		cairo_rectangle_int_t *new_rects;
300
 
301
		size *= 4;
302
		if (rects == rectangle_stack) {
303
		    new_rects = _cairo_malloc_ab (size,
304
						  sizeof (cairo_rectangle_int_t));
305
		    if (unlikely (new_rects == NULL)) {
306
			/* XXX _cairo_region_nil */
307
			break;
308
		    }
309
		    memcpy (new_rects, rects, sizeof (rectangle_stack));
310
		} else {
311
		    new_rects = _cairo_realloc_ab (rects, size,
312
						   sizeof (cairo_rectangle_int_t));
313
		    if (unlikely (new_rects == NULL)) {
314
			/* XXX _cairo_region_nil */
315
			break;
316
		    }
317
		}
318
		rects = new_rects;
319
	    }
320
 
321
	    rects[count].x = _cairo_fixed_integer_part (box.p1.x);
322
	    rects[count].y = _cairo_fixed_integer_part (box.p1.y);
323
	    rects[count].width = _cairo_fixed_integer_part (box.p2.x) - rects[count].x;
324
	    rects[count].height = _cairo_fixed_integer_part (box.p2.y) - rects[count].y;
325
	    if (_cairo_rectangle_intersect (&rects[count], extents))
326
		count++;
327
	}
328
 
329
	if (_cairo_path_fixed_iter_at_end (&iter))
330
	    region = cairo_region_create_rectangles (rects, count);
331
 
332
TESSELLATE:
333
	if (rects != rectangle_stack)
334
	    free (rects);
335
    }
336
 
337
    if (region == NULL) {
338
	/* Hmm, complex polygon */
339
	region = _cairo_path_fixed_fill_rectilinear_tessellate_to_region (path,
340
									  fill_rule,
341
									  extents);
342
 
343
 
344
    }
345
 
346
    return region;
347
}
348
 
349
cairo_int_status_t
350
_cairo_path_fixed_fill_rectilinear_to_traps (const cairo_path_fixed_t *path,
351
					     cairo_fill_rule_t fill_rule,
352
					     cairo_traps_t *traps)
353
{
354
    cairo_box_t box;
355
    cairo_status_t status;
356
 
357
    traps->is_rectilinear = TRUE;
358
    traps->is_rectangular = TRUE;
359
 
360
    if (_cairo_path_fixed_is_box (path, &box)) {
361
	return _cairo_traps_tessellate_rectangle (traps, &box.p1, &box.p2);
362
    } else {
363
	cairo_path_fixed_iter_t iter;
364
 
365
	_cairo_path_fixed_iter_init (&iter, path);
366
	while (_cairo_path_fixed_iter_is_fill_box (&iter, &box)) {
367
	    if (box.p1.y > box.p2.y) {
368
		cairo_fixed_t t;
369
 
370
		t = box.p1.y;
371
		box.p1.y = box.p2.y;
372
		box.p2.y = t;
373
 
374
		t = box.p1.x;
375
		box.p1.x = box.p2.x;
376
		box.p2.x = t;
377
	    }
378
 
379
	    status = _cairo_traps_tessellate_rectangle (traps,
380
							&box.p1, &box.p2);
381
	    if (unlikely (status)) {
382
		_cairo_traps_clear (traps);
383
		return status;
384
	    }
385
	}
386
 
387
	if (_cairo_path_fixed_iter_at_end (&iter))
388
	    return _cairo_bentley_ottmann_tessellate_rectangular_traps (traps, fill_rule);
389
 
390
	_cairo_traps_clear (traps);
391
	return CAIRO_INT_STATUS_UNSUPPORTED;
392
    }
393
}
394
 
395
static cairo_status_t
396
_cairo_path_fixed_fill_rectilinear_tessellate_to_boxes (const cairo_path_fixed_t *path,
397
							cairo_fill_rule_t fill_rule,
398
							cairo_boxes_t *boxes)
399
{
400
    cairo_polygon_t polygon;
401
    cairo_status_t status;
402
 
403
    _cairo_polygon_init (&polygon);
404
    if (boxes->num_limits) {
405
	_cairo_polygon_limit (&polygon, boxes->limits, boxes->num_limits);
406
	boxes->num_limits = 0;
407
    }
408
 
409
    /* tolerance will be ignored as the path is rectilinear */
410
    status = _cairo_path_fixed_fill_to_polygon (path, 0., &polygon);
411
    if (likely (status == CAIRO_STATUS_SUCCESS)) {
412
	status =
413
	    _cairo_bentley_ottmann_tessellate_rectilinear_polygon_to_boxes (&polygon,
414
									    fill_rule,
415
									    boxes);
416
    }
417
 
418
    _cairo_polygon_fini (&polygon);
419
 
420
    return status;
421
}
422
 
423
cairo_status_t
424
_cairo_path_fixed_fill_rectilinear_to_boxes (const cairo_path_fixed_t *path,
425
					     cairo_fill_rule_t fill_rule,
426
					     cairo_boxes_t *boxes)
427
{
428
    cairo_path_fixed_iter_t iter;
429
    cairo_status_t status;
430
    cairo_box_t box;
431
 
432
    if (_cairo_path_fixed_is_box (path, &box))
433
	return _cairo_boxes_add (boxes, &box);
434
 
435
    _cairo_path_fixed_iter_init (&iter, path);
436
    while (_cairo_path_fixed_iter_is_fill_box (&iter, &box)) {
437
	if (box.p1.y == box.p2.y || box.p1.x == box.p2.x)
438
	    continue;
439
 
440
	if (box.p1.y > box.p2.y) {
441
	    cairo_fixed_t t;
442
 
443
	    t = box.p1.y;
444
	    box.p1.y = box.p2.y;
445
	    box.p2.y = t;
446
 
447
	    t = box.p1.x;
448
	    box.p1.x = box.p2.x;
449
	    box.p2.x = t;
450
	}
451
 
452
	status = _cairo_boxes_add (boxes, &box);
453
	if (unlikely (status))
454
	    return status;
455
    }
456
 
457
    if (_cairo_path_fixed_iter_at_end (&iter))
458
	return _cairo_bentley_ottmann_tessellate_boxes (boxes, fill_rule, boxes);
459
 
460
    /* path is not rectangular, try extracting clipped rectilinear edges */
461
    _cairo_boxes_clear (boxes);
462
    return _cairo_path_fixed_fill_rectilinear_tessellate_to_boxes (path,
463
								   fill_rule,
464
								   boxes);
465
}