1 /* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
2 /* cairo - a vector graphics library with display and print output
3  *
4  * Copyright © 2002 University of Southern California
5  * Copyright © 2005 Red Hat, Inc.
6  * Copyright © 2009 Chris Wilson
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it either under the terms of the GNU Lesser General Public
10  * License version 2.1 as published by the Free Software Foundation
11  * (the "LGPL") or, at your option, under the terms of the Mozilla
12  * Public License Version 1.1 (the "MPL"). If you do not alter this
13  * notice, a recipient may use your version of this file under either
14  * the MPL or the LGPL.
15  *
16  * You should have received a copy of the LGPL along with this library
17  * in the file COPYING-LGPL-2.1; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
19  * You should have received a copy of the MPL along with this library
20  * in the file COPYING-MPL-1.1
21  *
22  * The contents of this file are subject to the Mozilla Public License
23  * Version 1.1 (the "License"); you may not use this file except in
24  * compliance with the License. You may obtain a copy of the License at
25  * http://www.mozilla.org/MPL/
26  *
27  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
28  * OF ANY KIND, either express or implied. See the LGPL or the MPL for
29  * the specific language governing rights and limitations.
30  *
31  * The Original Code is the cairo graphics library.
32  *
33  * The Initial Developer of the Original Code is University of Southern
34  * California.
35  *
36  * Contributor(s):
37  *	Carl D. Worth <cworth@cworth.org>
38  *	Kristian Høgsberg <krh@redhat.com>
39  *	Chris Wilson <chris@chris-wilson.co.uk>
40  */
41 
42 #include "cairoint.h"
43 #include "cairo-clip-private.h"
44 #include "cairo-error-private.h"
45 #include "cairo-freed-pool-private.h"
46 #include "cairo-gstate-private.h"
47 #include "cairo-path-fixed-private.h"
48 #include "cairo-composite-rectangles-private.h"
49 #include "cairo-region-private.h"
50 
51 #if HAS_FREED_POOL
52 static freed_pool_t clip_path_pool;
53 #endif
54 
55 static cairo_clip_path_t *
_cairo_clip_path_create(cairo_clip_t * clip)56 _cairo_clip_path_create (cairo_clip_t *clip)
57 {
58     cairo_clip_path_t *clip_path;
59 
60     clip_path = _freed_pool_get (&clip_path_pool);
61     if (unlikely (clip_path == NULL)) {
62 	clip_path = malloc (sizeof (cairo_clip_path_t));
63 	if (unlikely (clip_path == NULL))
64 	    return NULL;
65     }
66 
67     CAIRO_REFERENCE_COUNT_INIT (&clip_path->ref_count, 1);
68 
69     clip_path->flags = 0;
70     clip_path->region = NULL;
71     clip_path->surface = NULL;
72 
73     clip_path->prev = clip->path;
74     clip->path = clip_path;
75 
76     return clip_path;
77 }
78 
79 static cairo_clip_path_t *
_cairo_clip_path_reference(cairo_clip_path_t * clip_path)80 _cairo_clip_path_reference (cairo_clip_path_t *clip_path)
81 {
82     assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&clip_path->ref_count));
83 
84     _cairo_reference_count_inc (&clip_path->ref_count);
85 
86     return clip_path;
87 }
88 
89 static void
_cairo_clip_path_destroy(cairo_clip_path_t * clip_path)90 _cairo_clip_path_destroy (cairo_clip_path_t *clip_path)
91 {
92     assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&clip_path->ref_count));
93 
94     if (! _cairo_reference_count_dec_and_test (&clip_path->ref_count))
95 	return;
96 
97     _cairo_path_fixed_fini (&clip_path->path);
98     if (clip_path->region != NULL)
99 	cairo_region_destroy (clip_path->region);
100     if (clip_path->surface != NULL)
101 	cairo_surface_destroy (clip_path->surface);
102 
103     if (clip_path->prev != NULL)
104 	_cairo_clip_path_destroy (clip_path->prev);
105 
106     _freed_pool_put (&clip_path_pool, clip_path);
107 }
108 
109 void
_cairo_clip_init(cairo_clip_t * clip)110 _cairo_clip_init (cairo_clip_t *clip)
111 {
112     clip->all_clipped = FALSE;
113     clip->path = NULL;
114 }
115 
116 static void
_cairo_clip_set_all_clipped(cairo_clip_t * clip)117 _cairo_clip_set_all_clipped (cairo_clip_t *clip)
118 {
119     clip->all_clipped = TRUE;
120     if (clip->path != NULL) {
121 	_cairo_clip_path_destroy (clip->path);
122 	clip->path = NULL;
123     }
124 }
125 
126 static cairo_status_t
_cairo_clip_intersect_rectangle(cairo_clip_t * clip,const cairo_rectangle_int_t * rect)127 _cairo_clip_intersect_rectangle (cairo_clip_t *clip,
128 				 const cairo_rectangle_int_t *rect)
129 {
130     cairo_clip_path_t *clip_path;
131     cairo_status_t status;
132 
133     if (clip->path != NULL) {
134 	if (rect->x <= clip->path->extents.x &&
135 	    rect->y <= clip->path->extents.y &&
136 	    rect->x + rect->width >= clip->path->extents.x + clip->path->extents.width &&
137 	    rect->y + rect->height >= clip->path->extents.y + clip->path->extents.height)
138 	{
139 	    return CAIRO_STATUS_SUCCESS;
140 	}
141     }
142 
143     clip_path = _cairo_clip_path_create (clip);
144     if (unlikely (clip_path == NULL))
145 	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
146 
147     _cairo_path_fixed_init (&clip_path->path);
148 
149     status = _cairo_path_fixed_move_to (&clip_path->path,
150 					_cairo_fixed_from_int (rect->x),
151 					_cairo_fixed_from_int (rect->y));
152     assert (status == CAIRO_STATUS_SUCCESS);
153     status = _cairo_path_fixed_rel_line_to (&clip_path->path,
154 					    _cairo_fixed_from_int (rect->width),
155 					    _cairo_fixed_from_int (0));
156     assert (status == CAIRO_STATUS_SUCCESS);
157     status = _cairo_path_fixed_rel_line_to (&clip_path->path,
158 					    _cairo_fixed_from_int (0),
159 					    _cairo_fixed_from_int (rect->height));
160     assert (status == CAIRO_STATUS_SUCCESS);
161     status = _cairo_path_fixed_rel_line_to (&clip_path->path,
162 					    _cairo_fixed_from_int (-rect->width),
163 					    _cairo_fixed_from_int (0));
164     assert (status == CAIRO_STATUS_SUCCESS);
165     status = _cairo_path_fixed_close_path (&clip_path->path);
166     assert (status == CAIRO_STATUS_SUCCESS);
167 
168     clip_path->fill_rule = CAIRO_FILL_RULE_WINDING;
169     clip_path->tolerance = 1;
170     clip_path->antialias = CAIRO_ANTIALIAS_DEFAULT;
171     clip_path->flags |= CAIRO_CLIP_PATH_IS_BOX;
172 
173     clip_path->extents = *rect;
174     if (clip_path->prev != NULL) {
175 	if (! _cairo_rectangle_intersect (&clip_path->extents,
176 					  &clip_path->prev->extents))
177 	{
178 	    _cairo_clip_set_all_clipped (clip);
179 	}
180     }
181 
182     /* could preallocate the region if it proves worthwhile */
183 
184     return CAIRO_STATUS_SUCCESS;
185 }
186 
187 cairo_clip_t *
_cairo_clip_init_copy(cairo_clip_t * clip,cairo_clip_t * other)188 _cairo_clip_init_copy (cairo_clip_t *clip, cairo_clip_t *other)
189 {
190     if (other != NULL) {
191 	clip->all_clipped = other->all_clipped;
192 	if (other->path == NULL) {
193 	    clip->path = NULL;
194 	    if (! clip->all_clipped)
195 		clip = NULL;
196 	} else {
197 	    clip->path = _cairo_clip_path_reference (other->path);
198 	}
199     } else {
200 	_cairo_clip_init (clip);
201 	clip = NULL;
202     }
203 
204     return clip;
205 }
206 
207 void
_cairo_clip_reset(cairo_clip_t * clip)208 _cairo_clip_reset (cairo_clip_t *clip)
209 {
210     clip->all_clipped = FALSE;
211     if (clip->path != NULL) {
212 	_cairo_clip_path_destroy (clip->path);
213 	clip->path = NULL;
214     }
215 }
216 
217 static cairo_status_t
_cairo_clip_intersect_path(cairo_clip_t * clip,const cairo_path_fixed_t * path,cairo_fill_rule_t fill_rule,double tolerance,cairo_antialias_t antialias)218 _cairo_clip_intersect_path (cairo_clip_t       *clip,
219 			    const cairo_path_fixed_t *path,
220 			    cairo_fill_rule_t   fill_rule,
221 			    double              tolerance,
222 			    cairo_antialias_t   antialias)
223 {
224     cairo_clip_path_t *clip_path;
225     cairo_status_t status;
226     cairo_rectangle_int_t extents;
227     cairo_box_t box;
228     cairo_bool_t is_box = FALSE;
229 
230     if (clip->path != NULL) {
231 	if (clip->path->fill_rule == fill_rule &&
232 	    (path->is_rectilinear || tolerance == clip->path->tolerance) &&
233 	    antialias == clip->path->antialias &&
234 	    _cairo_path_fixed_equal (&clip->path->path, path))
235 	{
236 	    return CAIRO_STATUS_SUCCESS;
237 	}
238     }
239 
240     _cairo_path_fixed_approximate_clip_extents (path, &extents);
241     if (extents.width == 0 || extents.height == 0) {
242 	_cairo_clip_set_all_clipped (clip);
243 	return CAIRO_STATUS_SUCCESS;
244     }
245 
246     is_box = _cairo_path_fixed_is_box (path, &box);
247     if (clip->path != NULL) {
248 	if (! _cairo_rectangle_intersect (&extents, &clip->path->extents)) {
249 	    _cairo_clip_set_all_clipped (clip);
250 	    return CAIRO_STATUS_SUCCESS;
251 	}
252 
253 	/* does this clip wholly subsume the others? */
254 	if (is_box &&
255 	    box.p1.x <= _cairo_fixed_from_int (clip->path->extents.x) &&
256 	    box.p2.x >= _cairo_fixed_from_int (clip->path->extents.x + clip->path->extents.width) &&
257 	    box.p1.y <= _cairo_fixed_from_int (clip->path->extents.y) &&
258 	    box.p2.y >= _cairo_fixed_from_int (clip->path->extents.y + clip->path->extents.height))
259 	{
260 	    return CAIRO_STATUS_SUCCESS;
261 	}
262     }
263 
264     clip_path = _cairo_clip_path_create (clip);
265     if (unlikely (clip_path == NULL))
266 	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
267 
268     status = _cairo_path_fixed_init_copy (&clip_path->path, path);
269     if (unlikely (status)) {
270 	clip->path = clip->path->prev;
271 	_cairo_clip_path_destroy (clip_path);
272 	return status;
273     }
274 
275     clip_path->extents = extents;
276     clip_path->fill_rule = fill_rule;
277     clip_path->tolerance = tolerance;
278     clip_path->antialias = antialias;
279     if (is_box)
280 	clip_path->flags |= CAIRO_CLIP_PATH_IS_BOX;
281 
282     return CAIRO_STATUS_SUCCESS;
283 }
284 
285 cairo_bool_t
_cairo_clip_equal(const cairo_clip_t * clip_a,const cairo_clip_t * clip_b)286 _cairo_clip_equal (const cairo_clip_t *clip_a,
287 		   const cairo_clip_t *clip_b)
288 {
289     const cairo_clip_path_t *clip_path_a, *clip_path_b;
290 
291     clip_path_a = clip_a->path;
292     clip_path_b = clip_b->path;
293 
294     while (clip_path_a && clip_path_b) {
295 	if (clip_path_a == clip_path_b)
296 	    return TRUE;
297 
298 	if (clip_path_a->fill_rule != clip_path_b->fill_rule)
299 	    return FALSE;
300 
301 	if (clip_path_a->tolerance != clip_path_b->tolerance)
302 	    return FALSE;
303 
304 	if (clip_path_a->antialias != clip_path_b->antialias)
305 	    return FALSE;
306 
307 	if (! _cairo_path_fixed_equal (&clip_path_a->path, &clip_path_b->path))
308 	    return FALSE;
309 
310 	clip_path_a = clip_path_a->prev;
311 	clip_path_b = clip_path_b->prev;
312     }
313 
314     return clip_path_a == clip_path_b; /* ie both NULL */
315 }
316 
317 cairo_status_t
_cairo_clip_clip(cairo_clip_t * clip,const cairo_path_fixed_t * path,cairo_fill_rule_t fill_rule,double tolerance,cairo_antialias_t antialias)318 _cairo_clip_clip (cairo_clip_t       *clip,
319 		  const cairo_path_fixed_t *path,
320 		  cairo_fill_rule_t   fill_rule,
321 		  double              tolerance,
322 		  cairo_antialias_t   antialias)
323 {
324     if (clip->all_clipped)
325 	return CAIRO_STATUS_SUCCESS;
326 
327     /* catch the empty clip path */
328     if (_cairo_path_fixed_fill_is_empty (path)) {
329 	_cairo_clip_set_all_clipped (clip);
330 	return CAIRO_STATUS_SUCCESS;
331     }
332 
333     return _cairo_clip_intersect_path (clip,
334 				       path, fill_rule, tolerance,
335 				       antialias);
336 }
337 
338 cairo_status_t
_cairo_clip_rectangle(cairo_clip_t * clip,const cairo_rectangle_int_t * rectangle)339 _cairo_clip_rectangle (cairo_clip_t       *clip,
340 		       const cairo_rectangle_int_t *rectangle)
341 {
342     if (clip->all_clipped)
343 	return CAIRO_STATUS_SUCCESS;
344 
345     if (rectangle->width == 0 || rectangle->height == 0) {
346 	_cairo_clip_set_all_clipped (clip);
347 	return CAIRO_STATUS_SUCCESS;
348     }
349 
350     /* if a smaller clip has already been set, ignore the new path */
351     if (clip->path != NULL) {
352 	if (rectangle->x <= clip->path->extents.x &&
353 	    rectangle->y <= clip->path->extents.y &&
354 	    rectangle->x + rectangle->width  >= clip->path->extents.x + clip->path->extents.width &&
355 	    rectangle->y + rectangle->height >= clip->path->extents.y + clip->path->extents.height)
356 	{
357 	    return CAIRO_STATUS_SUCCESS;
358 	}
359     }
360 
361     return _cairo_clip_intersect_rectangle (clip, rectangle);
362 }
363 
364 static cairo_status_t
_cairo_clip_path_reapply_clip_path_transform(cairo_clip_t * clip,cairo_clip_path_t * other_path,const cairo_matrix_t * matrix)365 _cairo_clip_path_reapply_clip_path_transform (cairo_clip_t      *clip,
366 					      cairo_clip_path_t *other_path,
367 					      const cairo_matrix_t *matrix)
368 {
369     cairo_status_t status;
370     cairo_clip_path_t *clip_path;
371     cairo_bool_t is_empty;
372 
373     if (other_path->prev != NULL) {
374         status = _cairo_clip_path_reapply_clip_path_transform (clip,
375 							       other_path->prev,
376 							       matrix);
377 	if (unlikely (status))
378 	    return status;
379     }
380 
381     clip_path = _cairo_clip_path_create (clip);
382     if (unlikely (clip_path == NULL))
383 	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
384 
385     status = _cairo_path_fixed_init_copy (&clip_path->path,
386 					  &other_path->path);
387     if (unlikely (status)) {
388 	clip->path = clip->path->prev;
389 	_cairo_clip_path_destroy (clip_path);
390 	return status;
391     }
392 
393     _cairo_path_fixed_transform (&clip_path->path, matrix);
394     _cairo_path_fixed_approximate_clip_extents (&clip_path->path,
395 						&clip_path->extents);
396     if (clip_path->prev != NULL) {
397 	is_empty = _cairo_rectangle_intersect (&clip_path->extents,
398 					       &clip_path->prev->extents);
399     }
400 
401     clip_path->fill_rule = other_path->fill_rule;
402     clip_path->tolerance = other_path->tolerance;
403     clip_path->antialias = other_path->antialias;
404 
405     return CAIRO_STATUS_SUCCESS;
406 }
407 
408 static cairo_status_t
_cairo_clip_path_reapply_clip_path_translate(cairo_clip_t * clip,cairo_clip_path_t * other_path,int tx,int ty)409 _cairo_clip_path_reapply_clip_path_translate (cairo_clip_t      *clip,
410 					      cairo_clip_path_t *other_path,
411 					      int tx, int ty)
412 {
413     cairo_status_t status;
414     cairo_clip_path_t *clip_path;
415 
416     if (other_path->prev != NULL) {
417         status = _cairo_clip_path_reapply_clip_path_translate (clip,
418 							       other_path->prev,
419 							       tx, ty);
420 	if (unlikely (status))
421 	    return status;
422     }
423 
424     clip_path = _cairo_clip_path_create (clip);
425     if (unlikely (clip_path == NULL))
426 	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
427 
428     status = _cairo_path_fixed_init_copy (&clip_path->path,
429 					  &other_path->path);
430     if (unlikely (status)) {
431 	clip->path = clip->path->prev;
432 	_cairo_clip_path_destroy (clip_path);
433 	return status;
434     }
435 
436     _cairo_path_fixed_translate (&clip_path->path,
437 				 _cairo_fixed_from_int (tx),
438 				 _cairo_fixed_from_int (ty));
439 
440     clip_path->fill_rule = other_path->fill_rule;
441     clip_path->tolerance = other_path->tolerance;
442     clip_path->antialias = other_path->antialias;
443 
444     clip_path->flags = other_path->flags;
445     if (other_path->region != NULL) {
446 	clip_path->region = cairo_region_copy (other_path->region);
447 	status = clip_path->region->status;
448 	if (unlikely (status)) {
449 	    clip->path = clip->path->prev;
450 	    _cairo_clip_path_destroy (clip_path);
451 	    return status;
452 	}
453 
454 	cairo_region_translate (clip_path->region, tx, ty);
455     }
456     clip_path->surface = cairo_surface_reference (other_path->surface);
457 
458     clip_path->extents = other_path->extents;
459     clip_path->extents.x += tx;
460     clip_path->extents.y += ty;
461 
462     return CAIRO_STATUS_SUCCESS;
463 }
464 
465 cairo_status_t
_cairo_clip_init_copy_transformed(cairo_clip_t * clip,cairo_clip_t * other,const cairo_matrix_t * matrix)466 _cairo_clip_init_copy_transformed (cairo_clip_t    *clip,
467 				   cairo_clip_t    *other,
468 				   const cairo_matrix_t *matrix)
469 {
470     cairo_status_t status = CAIRO_STATUS_SUCCESS;
471     int tx, ty;
472 
473     if (other == NULL) {
474 	_cairo_clip_init (clip);
475 	return CAIRO_STATUS_SUCCESS;
476     }
477 
478     if (other->all_clipped) {
479 	_cairo_clip_init (clip);
480 	clip->all_clipped = TRUE;
481 	return CAIRO_STATUS_SUCCESS;
482     }
483 
484     if (_cairo_matrix_is_identity (matrix)) {
485 	_cairo_clip_init_copy (clip, other);
486 	return CAIRO_STATUS_SUCCESS;
487     }
488 
489     if (other->path != NULL) {
490 	_cairo_clip_init (clip);
491 
492 	/* if we only need to translate, so we can reuse the caches... */
493 	/* XXX we still loose the benefit of constructs when the copy is
494 	 * deleted though. Indirect clip_paths?
495 	 */
496 	if (_cairo_matrix_is_integer_translation (matrix, &tx, &ty)) {
497 	    status = _cairo_clip_path_reapply_clip_path_translate (clip,
498 								   other->path,
499 								   tx, ty);
500 	} else {
501 	    status = _cairo_clip_path_reapply_clip_path_transform (clip,
502 								   other->path,
503 								   matrix);
504 	    if (clip->path->extents.width == 0 &&
505 		clip->path->extents.height == 0)
506 	    {
507 		_cairo_clip_set_all_clipped (clip);
508 	    }
509 	}
510     }
511 
512     return status;
513 }
514 
515 static cairo_status_t
_cairo_clip_apply_clip_path(cairo_clip_t * clip,const cairo_clip_path_t * path)516 _cairo_clip_apply_clip_path (cairo_clip_t *clip,
517 			     const cairo_clip_path_t *path)
518 {
519     cairo_status_t status;
520 
521     if (path->prev != NULL)
522 	status = _cairo_clip_apply_clip_path (clip, path->prev);
523 
524     return _cairo_clip_intersect_path (clip,
525 				       &path->path,
526 				       path->fill_rule,
527 				       path->tolerance,
528 				       path->antialias);
529 }
530 
531 cairo_status_t
_cairo_clip_apply_clip(cairo_clip_t * clip,const cairo_clip_t * other)532 _cairo_clip_apply_clip (cairo_clip_t *clip,
533 			const cairo_clip_t *other)
534 {
535     cairo_status_t status;
536 
537     if (clip->all_clipped)
538 	return CAIRO_STATUS_SUCCESS;
539 
540     if (other->all_clipped) {
541 	_cairo_clip_set_all_clipped (clip);
542 	return CAIRO_STATUS_SUCCESS;
543     }
544 
545     status = CAIRO_STATUS_SUCCESS;
546     if (other->path != NULL)
547 	status = _cairo_clip_apply_clip_path (clip, other->path);
548 
549     return status;
550 }
551 
552 static inline cairo_bool_t
_clip_paths_are_rectilinear(cairo_clip_path_t * clip_path)553 _clip_paths_are_rectilinear (cairo_clip_path_t *clip_path)
554 {
555     while (clip_path != NULL) {
556 	if (! clip_path->path.is_rectilinear)
557 	    return FALSE;
558 
559 	clip_path = clip_path->prev;
560     }
561 
562     return TRUE;
563 }
564 
565 static cairo_int_status_t
_cairo_clip_path_to_region_geometric(cairo_clip_path_t * clip_path)566 _cairo_clip_path_to_region_geometric (cairo_clip_path_t *clip_path)
567 {
568     cairo_traps_t traps;
569     cairo_box_t stack_boxes[CAIRO_STACK_ARRAY_LENGTH (cairo_box_t)];
570     cairo_box_t *boxes = stack_boxes;
571     cairo_status_t status;
572     int n;
573 
574     /* If we have nothing to intersect with this path, then it cannot
575      * magically be reduced into a region.
576      */
577     if (clip_path->prev == NULL)
578 	goto UNSUPPORTED;
579 
580     /* Start simple... Intersect some boxes with an arbitrary path. */
581     if (! clip_path->path.is_rectilinear)
582 	goto UNSUPPORTED;
583     if (clip_path->prev->prev != NULL)
584 	goto UNSUPPORTED;
585 
586     _cairo_traps_init (&traps);
587     _cairo_box_from_rectangle (&boxes[0], &clip_path->extents);
588     _cairo_traps_limit (&traps, boxes, 1);
589 
590     status = _cairo_path_fixed_fill_rectilinear_to_traps (&clip_path->path,
591 							  clip_path->fill_rule,
592 							  &traps);
593     if (unlikely (_cairo_status_is_error (status)))
594 	return status;
595     if (status == CAIRO_INT_STATUS_UNSUPPORTED)
596 	goto UNSUPPORTED;
597 
598     if (unlikely (traps.num_traps == 0)) {
599 	clip_path->region = cairo_region_create ();
600 	clip_path->flags |= CAIRO_CLIP_PATH_HAS_REGION;
601 	return CAIRO_STATUS_SUCCESS;
602     }
603 
604     if (traps.num_traps > ARRAY_LENGTH (stack_boxes)) {
605 	boxes = _cairo_malloc_ab (traps.num_traps, sizeof (cairo_box_t));
606 	if (unlikely (boxes == NULL))
607 	    return _cairo_error (CAIRO_STATUS_NO_MEMORY);
608     }
609 
610     for (n = 0; n < traps.num_traps; n++) {
611 	boxes[n].p1.x = traps.traps[n].left.p1.x;
612 	boxes[n].p1.y = traps.traps[n].top;
613 	boxes[n].p2.x = traps.traps[n].right.p1.x;
614 	boxes[n].p2.y = traps.traps[n].bottom;
615     }
616 
617     _cairo_traps_clear (&traps);
618     _cairo_traps_limit (&traps, boxes, n);
619     status = _cairo_path_fixed_fill_to_traps (&clip_path->prev->path,
620 					      clip_path->prev->fill_rule,
621 					      clip_path->prev->tolerance,
622 					      &traps);
623     if (boxes != stack_boxes)
624 	free (boxes);
625 
626     if (unlikely (status))
627 	return status;
628 
629     status = _cairo_traps_extract_region (&traps, &clip_path->region);
630     _cairo_traps_fini (&traps);
631 
632     if (status == CAIRO_INT_STATUS_UNSUPPORTED)
633 	goto UNSUPPORTED;
634     if (unlikely (status))
635 	return status;
636 
637     clip_path->flags |= CAIRO_CLIP_PATH_HAS_REGION;
638     return CAIRO_STATUS_SUCCESS;
639 
640 UNSUPPORTED:
641     clip_path->flags |= CAIRO_CLIP_PATH_REGION_IS_UNSUPPORTED;
642     return CAIRO_INT_STATUS_UNSUPPORTED;
643 }
644 
645 static cairo_int_status_t
_cairo_clip_path_to_region(cairo_clip_path_t * clip_path)646 _cairo_clip_path_to_region (cairo_clip_path_t *clip_path)
647 {
648     cairo_int_status_t status;
649     cairo_region_t *prev = NULL;
650 
651     if (clip_path->flags &
652 	(CAIRO_CLIP_PATH_HAS_REGION |
653 	 CAIRO_CLIP_PATH_REGION_IS_UNSUPPORTED))
654     {
655 	return clip_path->flags & CAIRO_CLIP_PATH_REGION_IS_UNSUPPORTED ?
656 	    CAIRO_INT_STATUS_UNSUPPORTED :
657 	    CAIRO_STATUS_SUCCESS;
658     }
659 
660     if (! clip_path->path.maybe_fill_region)
661 	return _cairo_clip_path_to_region_geometric (clip_path);
662 
663     /* first retrieve the region for our antecedents */
664     if (clip_path->prev != NULL) {
665 	status = _cairo_clip_path_to_region (clip_path->prev);
666 	if (status) {
667 	    if (status == CAIRO_INT_STATUS_UNSUPPORTED)
668 		return _cairo_clip_path_to_region_geometric (clip_path);
669 
670 	    return status;
671 	}
672 
673 	prev = clip_path->prev->region;
674     }
675 
676     /* now extract the region for ourselves */
677     clip_path->region =
678 	_cairo_path_fixed_fill_rectilinear_to_region (&clip_path->path,
679 						      clip_path->fill_rule,
680 						      &clip_path->extents);
681     assert (clip_path->region != NULL);
682 
683     status = clip_path->region->status;
684     if (unlikely (status))
685 	return status;
686 
687     if (prev != NULL) {
688 	status = cairo_region_intersect (clip_path->region, prev);
689 	if (unlikely (status))
690 	    return status;
691     }
692 
693     clip_path->flags |= CAIRO_CLIP_PATH_HAS_REGION;
694     return CAIRO_STATUS_SUCCESS;
695 }
696 
697 static inline int
pot(int v)698 pot (int v)
699 {
700     v--;
701     v |= v >> 1;
702     v |= v >> 2;
703     v |= v >> 4;
704     v |= v >> 8;
705     v |= v >> 16;
706     v++;
707     return v;
708 }
709 
710 /* XXX there is likely a faster method! ;-) */
711 static cairo_status_t
_region_clip_to_boxes(const cairo_region_t * region,cairo_box_t ** boxes,int * num_boxes,int * size_boxes)712 _region_clip_to_boxes (const cairo_region_t *region,
713 		       cairo_box_t **boxes,
714 		       int *num_boxes,
715 		       int *size_boxes)
716 {
717     cairo_traps_t traps;
718     cairo_status_t status;
719     int n, num_rects;
720 
721     _cairo_traps_init (&traps);
722     _cairo_traps_limit (&traps, *boxes, *num_boxes);
723     traps.is_rectilinear = TRUE;
724     traps.is_rectangular = TRUE;
725 
726     num_rects = cairo_region_num_rectangles (region);
727     for (n = 0; n < num_rects; n++) {
728 	cairo_rectangle_int_t rect;
729 	cairo_point_t p1, p2;
730 
731 	cairo_region_get_rectangle (region, n, &rect);
732 
733 	p1.x = _cairo_fixed_from_int (rect.x);
734 	p1.y = _cairo_fixed_from_int (rect.y);
735 	p2.x = _cairo_fixed_from_int (rect.x + rect.width);
736 	p2.y = _cairo_fixed_from_int (rect.y + rect.height);
737 
738 	status = _cairo_traps_tessellate_rectangle (&traps, &p1, &p2);
739 	if (unlikely (status))
740 	    goto CLEANUP;
741     }
742 
743     status = _cairo_bentley_ottmann_tessellate_rectangular_traps (&traps, CAIRO_FILL_RULE_WINDING);
744     if (unlikely (status))
745 	goto CLEANUP;
746 
747     n = *size_boxes;
748     if (n < 0)
749 	n = -n;
750 
751     if (traps.num_traps > n) {
752 	cairo_box_t *new_boxes;
753 
754 	new_boxes = _cairo_malloc_ab (traps.num_traps, sizeof (cairo_box_t));
755 	if (unlikely (new_boxes == NULL)) {
756 	    status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
757 	    goto CLEANUP;
758 	}
759 
760 	if (*size_boxes > 0)
761 	    free (*boxes);
762 
763 	*boxes = new_boxes;
764 	*size_boxes = traps.num_traps;
765     }
766 
767     for (n = 0; n < traps.num_traps; n++) {
768 	(*boxes)[n].p1.x = traps.traps[n].left.p1.x;
769 	(*boxes)[n].p1.y = traps.traps[n].top;
770 	(*boxes)[n].p2.x = traps.traps[n].right.p1.x;
771 	(*boxes)[n].p2.y = traps.traps[n].bottom;
772     }
773     *num_boxes = n;
774 
775   CLEANUP:
776     _cairo_traps_fini (&traps);
777 
778     return status;
779 }
780 
781 static cairo_status_t
_rectilinear_clip_to_boxes(const cairo_path_fixed_t * path,cairo_fill_rule_t fill_rule,cairo_box_t ** boxes,int * num_boxes,int * size_boxes)782 _rectilinear_clip_to_boxes (const cairo_path_fixed_t *path,
783 			    cairo_fill_rule_t fill_rule,
784 			    cairo_box_t **boxes,
785 			    int *num_boxes,
786 			    int *size_boxes)
787 {
788     cairo_polygon_t polygon;
789     cairo_traps_t traps;
790     cairo_status_t status;
791 
792     _cairo_traps_init (&traps);
793     _cairo_traps_limit (&traps, *boxes, *num_boxes);
794 
795     _cairo_polygon_init (&polygon);
796     _cairo_polygon_limit (&polygon, *boxes, *num_boxes);
797 
798     status = _cairo_path_fixed_fill_rectilinear_to_traps (path,
799 							  fill_rule,
800 							  &traps);
801     if (unlikely (_cairo_status_is_error (status)))
802 	goto CLEANUP;
803     if (status == CAIRO_STATUS_SUCCESS)
804 	goto BOXES;
805 
806     /* tolerance will be ignored as the path is rectilinear */
807     status = _cairo_path_fixed_fill_to_polygon (path, 0., &polygon);
808     if (unlikely (status))
809 	goto CLEANUP;
810 
811     if (polygon.num_edges == 0) {
812 	*num_boxes = 0;
813     } else {
814 	status = _cairo_bentley_ottmann_tessellate_rectilinear_polygon (&traps,
815 									&polygon,
816 									fill_rule);
817 	if (likely (status == CAIRO_STATUS_SUCCESS)) {
818 	    int i;
819 
820           BOXES:
821 	    i = *size_boxes;
822 	    if (i < 0)
823 		i = -i;
824 
825 	    if (traps.num_traps > i) {
826 		cairo_box_t *new_boxes;
827 		int new_size;
828 
829 		new_size = pot (traps.num_traps);
830 		new_boxes = _cairo_malloc_ab (new_size, sizeof (cairo_box_t));
831 		if (unlikely (new_boxes == NULL)) {
832 		    status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
833 		    goto CLEANUP;
834 		}
835 
836 		if (*size_boxes > 0)
837 		    free (*boxes);
838 
839 		*boxes = new_boxes;
840 		*size_boxes = new_size;
841 	    }
842 
843 	    for (i = 0; i < traps.num_traps; i++) {
844 		(*boxes)[i].p1.x = traps.traps[i].left.p1.x;
845 		(*boxes)[i].p1.y = traps.traps[i].top;
846 		(*boxes)[i].p2.x = traps.traps[i].right.p1.x;
847 		(*boxes)[i].p2.y = traps.traps[i].bottom;
848 	    }
849 	    *num_boxes = i;
850 	}
851     }
852 
853   CLEANUP:
854     _cairo_polygon_fini (&polygon);
855     _cairo_traps_fini (&traps);
856 
857     return status;
858 }
859 
860 static cairo_int_status_t
_cairo_clip_path_to_boxes(cairo_clip_path_t * clip_path,cairo_box_t ** boxes,int * count)861 _cairo_clip_path_to_boxes (cairo_clip_path_t *clip_path,
862 			   cairo_box_t **boxes,
863 			   int *count)
864 {
865     int size = -*count;
866     int num_boxes = 0;
867     cairo_status_t status;
868 
869     if (clip_path->region != NULL) {
870 	int num_rects, n;
871 
872 	num_rects = cairo_region_num_rectangles (clip_path->region);
873 	if (num_rects > -size) {
874 	    cairo_box_t *new_boxes;
875 
876 	    new_boxes = _cairo_malloc_ab (num_rects, sizeof (cairo_box_t));
877 	    if (unlikely (new_boxes == NULL))
878 		return _cairo_error (CAIRO_STATUS_NO_MEMORY);
879 
880 	    *boxes = new_boxes;
881 	}
882 
883 	for (n = 0; n < num_rects; n++) {
884 	    cairo_rectangle_int_t rect;
885 
886 	    cairo_region_get_rectangle (clip_path->region, n, &rect);
887 	    (*boxes)[n].p1.x = _cairo_fixed_from_int (rect.x);
888 	    (*boxes)[n].p1.y = _cairo_fixed_from_int (rect.y);
889 	    (*boxes)[n].p2.x = _cairo_fixed_from_int (rect.x + rect.width);
890 	    (*boxes)[n].p2.y = _cairo_fixed_from_int (rect.y + rect.height);
891 	}
892 
893 	*count = num_rects;
894 	return CAIRO_STATUS_SUCCESS;
895     }
896 
897     /* keep it simple at first */
898     if (! _clip_paths_are_rectilinear (clip_path))
899 	return CAIRO_INT_STATUS_UNSUPPORTED;
900 
901     assert (-size >= 1);
902     if (_cairo_path_fixed_is_box (&clip_path->path, *boxes)) {
903 	num_boxes = 1;
904     } else {
905 	status = _rectilinear_clip_to_boxes (&clip_path->path,
906 					     clip_path->fill_rule,
907 					     boxes, &num_boxes, &size);
908 	if (unlikely (status))
909 	    return status;
910     }
911 
912     while (num_boxes > 0 && (clip_path = clip_path->prev) != NULL) {
913 	cairo_box_t box;
914 
915 	if (clip_path->region != NULL) {
916 	    status = _region_clip_to_boxes (clip_path->region,
917 					    boxes, &num_boxes, &size);
918 	    if (unlikely (status))
919 		return status;
920 
921 	    break;
922 	} else if (_cairo_path_fixed_is_box (&clip_path->path, &box)) {
923 	    int i, j;
924 
925 	    for (i = j = 0; i < num_boxes; i++) {
926 		if (j != i)
927 		    (*boxes)[j] = (*boxes)[i];
928 
929 		if (box.p1.x > (*boxes)[j].p1.x)
930 		    (*boxes)[j].p1.x = box.p1.x;
931 		if (box.p2.x < (*boxes)[j].p2.x)
932 		    (*boxes)[j].p2.x = box.p2.x;
933 
934 		if (box.p1.y > (*boxes)[j].p1.y)
935 		    (*boxes)[j].p1.y = box.p1.y;
936 		if (box.p2.y < (*boxes)[j].p2.y)
937 		    (*boxes)[j].p2.y = box.p2.y;
938 
939 		j += (*boxes)[j].p2.x > (*boxes)[j].p1.x &&
940 		     (*boxes)[j].p2.y > (*boxes)[j].p1.y;
941 	    }
942 
943 	    num_boxes = j;
944 	} else {
945 	    status = _rectilinear_clip_to_boxes (&clip_path->path,
946 						 clip_path->fill_rule,
947 						 boxes, &num_boxes, &size);
948 	    if (unlikely (status))
949 		return status;
950 	}
951     }
952 
953     *count = num_boxes;
954     return CAIRO_STATUS_SUCCESS;
955 }
956 
957 static cairo_surface_t *
_cairo_clip_path_get_surface(cairo_clip_path_t * clip_path,cairo_surface_t * target,int * tx,int * ty)958 _cairo_clip_path_get_surface (cairo_clip_path_t *clip_path,
959 			      cairo_surface_t *target,
960 			      int *tx, int *ty)
961 {
962     const cairo_rectangle_int_t *clip_extents = &clip_path->extents;
963     cairo_bool_t need_translate;
964     cairo_surface_t *surface;
965     cairo_clip_path_t *prev;
966     cairo_status_t status;
967 
968     while (clip_path->prev != NULL &&
969 	   clip_path->flags & CAIRO_CLIP_PATH_IS_BOX &&
970 	   clip_path->path.maybe_fill_region)
971     {
972 	clip_path = clip_path->prev;
973     }
974 
975     clip_extents = &clip_path->extents;
976     if (clip_path->surface != NULL &&
977 	clip_path->surface->backend == target->backend)
978     {
979 	*tx = clip_extents->x;
980 	*ty = clip_extents->y;
981 	return clip_path->surface;
982     }
983 
984     surface = _cairo_surface_create_similar_scratch (target,
985 						     CAIRO_CONTENT_ALPHA,
986 						     clip_extents->width,
987 						     clip_extents->height);
988     if (surface == NULL) {
989 	surface = cairo_image_surface_create (CAIRO_FORMAT_A8,
990 					      clip_extents->width,
991 					      clip_extents->height);
992     }
993     if (unlikely (surface->status))
994 	return surface;
995 
996     need_translate = clip_extents->x | clip_extents->y;
997     if (clip_path->flags & CAIRO_CLIP_PATH_IS_BOX &&
998 	clip_path->path.maybe_fill_region)
999     {
1000 	status = _cairo_surface_paint (surface,
1001 				       CAIRO_OPERATOR_SOURCE,
1002 				       &_cairo_pattern_white.base,
1003 				       NULL);
1004 	if (unlikely (status))
1005 	    goto BAIL;
1006     }
1007     else
1008     {
1009 	status = _cairo_surface_paint (surface,
1010 				       CAIRO_OPERATOR_CLEAR,
1011 				       &_cairo_pattern_clear.base,
1012 				       NULL);
1013 	if (unlikely (status))
1014 	    goto BAIL;
1015 
1016 	if (need_translate) {
1017 	    _cairo_path_fixed_translate (&clip_path->path,
1018 					 _cairo_fixed_from_int (-clip_extents->x),
1019 					 _cairo_fixed_from_int (-clip_extents->y));
1020 	}
1021 	status = _cairo_surface_fill (surface,
1022 				      CAIRO_OPERATOR_ADD,
1023 				      &_cairo_pattern_white.base,
1024 				      &clip_path->path,
1025 				      clip_path->fill_rule,
1026 				      clip_path->tolerance,
1027 				      clip_path->antialias,
1028 				      NULL);
1029 	if (need_translate) {
1030 	    _cairo_path_fixed_translate (&clip_path->path,
1031 					 _cairo_fixed_from_int (clip_extents->x),
1032 					 _cairo_fixed_from_int (clip_extents->y));
1033 	}
1034 
1035 	if (unlikely (status))
1036 	    goto BAIL;
1037     }
1038 
1039     prev = clip_path->prev;
1040     while (prev != NULL) {
1041 	if (prev->flags & CAIRO_CLIP_PATH_IS_BOX &&
1042 	    prev->path.maybe_fill_region)
1043 	{
1044 	    /* a simple box only affects the extents */
1045 	}
1046 	else if (prev->path.is_rectilinear ||
1047 		prev->surface == NULL ||
1048 		prev->surface->backend != target->backend)
1049 	{
1050 	    if (need_translate) {
1051 		_cairo_path_fixed_translate (&prev->path,
1052 					     _cairo_fixed_from_int (-clip_extents->x),
1053 					     _cairo_fixed_from_int (-clip_extents->y));
1054 	    }
1055 	    status = _cairo_surface_fill (surface,
1056 					  CAIRO_OPERATOR_IN,
1057 					  &_cairo_pattern_white.base,
1058 					  &prev->path,
1059 					  prev->fill_rule,
1060 					  prev->tolerance,
1061 					  prev->antialias,
1062 					  NULL);
1063 	    if (need_translate) {
1064 		_cairo_path_fixed_translate (&prev->path,
1065 					     _cairo_fixed_from_int (clip_extents->x),
1066 					     _cairo_fixed_from_int (clip_extents->y));
1067 	    }
1068 
1069 	    if (unlikely (status))
1070 		goto BAIL;
1071 	}
1072 	else
1073 	{
1074 	    cairo_surface_pattern_t pattern;
1075 	    cairo_surface_t *prev_surface;
1076 	    int prev_tx, prev_ty;
1077 
1078 	    prev_surface = _cairo_clip_path_get_surface (prev, target, &prev_tx, &prev_ty);
1079 	    status = prev_surface->status;
1080 	    if (unlikely (status))
1081 		goto BAIL;
1082 
1083 	    _cairo_pattern_init_for_surface (&pattern, prev_surface);
1084 	    pattern.base.filter = CAIRO_FILTER_NEAREST;
1085 	    cairo_matrix_init_translate (&pattern.base.matrix,
1086 					 clip_extents->x - prev_tx,
1087 					 clip_extents->y - prev_ty);
1088 	    status = _cairo_surface_paint (surface,
1089 					   CAIRO_OPERATOR_IN,
1090 					   &pattern.base,
1091 					   NULL);
1092 	    _cairo_pattern_fini (&pattern.base);
1093 
1094 	    if (unlikely (status))
1095 		goto BAIL;
1096 
1097 	    break;
1098 	}
1099 
1100 	prev = prev->prev;
1101     }
1102 
1103     *tx = clip_extents->x;
1104     *ty = clip_extents->y;
1105     cairo_surface_destroy (clip_path->surface);
1106     return clip_path->surface = surface;
1107 
1108   BAIL:
1109     cairo_surface_destroy (surface);
1110     return _cairo_surface_create_in_error (status);
1111 }
1112 
1113 cairo_bool_t
_cairo_clip_contains_rectangle(cairo_clip_t * clip,const cairo_rectangle_int_t * rect)1114 _cairo_clip_contains_rectangle (cairo_clip_t *clip,
1115 				const cairo_rectangle_int_t *rect)
1116 {
1117     cairo_clip_path_t *clip_path;
1118 
1119     if (clip == NULL)
1120 	return FALSE;
1121 
1122     clip_path = clip->path;
1123     if (clip_path->extents.x > rect->x ||
1124 	clip_path->extents.y > rect->y ||
1125 	clip_path->extents.x + clip_path->extents.width  < rect->x + rect->width ||
1126 	clip_path->extents.y + clip_path->extents.height < rect->y + rect->height)
1127     {
1128 	return FALSE;
1129     }
1130 
1131     do {
1132 	cairo_box_t box;
1133 
1134 	if ((clip_path->flags & CAIRO_CLIP_PATH_IS_BOX) == 0)
1135 	    return FALSE;
1136 
1137 	if (! _cairo_path_fixed_is_box (&clip_path->path, &box))
1138 	    return FALSE;
1139 
1140 	if (box.p1.x > _cairo_fixed_from_int (rect->x) ||
1141 	    box.p1.y > _cairo_fixed_from_int (rect->y) ||
1142 	    box.p2.x < _cairo_fixed_from_int (rect->x + rect->width) ||
1143 	    box.p2.y < _cairo_fixed_from_int (rect->y + rect->height))
1144 	{
1145 	    return FALSE;
1146 	}
1147     } while ((clip_path = clip_path->prev) != NULL);
1148 
1149     return TRUE;
1150 }
1151 
1152 cairo_bool_t
_cairo_clip_contains_extents(cairo_clip_t * clip,const cairo_composite_rectangles_t * extents)1153 _cairo_clip_contains_extents (cairo_clip_t *clip,
1154 			      const cairo_composite_rectangles_t *extents)
1155 {
1156     const cairo_rectangle_int_t *rect;
1157 
1158     if (clip == NULL)
1159 	return FALSE;
1160 
1161     rect = extents->is_bounded ? &extents->bounded : &extents->unbounded;
1162     return _cairo_clip_contains_rectangle (clip, rect);
1163 }
1164 
1165 void
_cairo_debug_print_clip(FILE * stream,cairo_clip_t * clip)1166 _cairo_debug_print_clip (FILE *stream, cairo_clip_t *clip)
1167 {
1168     cairo_clip_path_t *clip_path;
1169 
1170     if (clip == NULL) {
1171 	fprintf (stream, "no clip\n");
1172 	return;
1173     }
1174 
1175     if (clip->all_clipped) {
1176 	fprintf (stream, "clip: all-clipped\n");
1177 	return;
1178     }
1179 
1180     if (clip->path == NULL) {
1181 	fprintf (stream, "clip: empty\n");
1182 	return;
1183     }
1184 
1185     fprintf (stream, "clip:\n");
1186 
1187     clip_path = clip->path;
1188     do {
1189 	fprintf (stream, "path: has region? %s, has surface? %s, aa=%d, tolerance=%f, rule=%d: ",
1190 		 clip_path->region == NULL ? "no" : "yes",
1191 		 clip_path->surface == NULL ? "no" : "yes",
1192 		 clip_path->antialias,
1193 		 clip_path->tolerance,
1194 		 clip_path->fill_rule);
1195 	_cairo_debug_print_path (stream, &clip_path->path);
1196 	fprintf (stream, "\n");
1197     } while ((clip_path = clip_path->prev) != NULL);
1198 }
1199 
1200 cairo_surface_t *
_cairo_clip_get_surface(cairo_clip_t * clip,cairo_surface_t * target,int * tx,int * ty)1201 _cairo_clip_get_surface (cairo_clip_t *clip, cairo_surface_t *target, int *tx, int *ty)
1202 {
1203     /* XXX is_clear -> all_clipped */
1204     assert (clip->path != NULL);
1205     return _cairo_clip_path_get_surface (clip->path, target, tx, ty);
1206 }
1207 
1208 cairo_status_t
_cairo_clip_combine_with_surface(cairo_clip_t * clip,cairo_surface_t * dst,int dst_x,int dst_y)1209 _cairo_clip_combine_with_surface (cairo_clip_t *clip,
1210 				  cairo_surface_t *dst,
1211 				  int dst_x, int dst_y)
1212 {
1213     cairo_clip_path_t *clip_path = clip->path;
1214     cairo_bool_t need_translate;
1215     cairo_status_t status;
1216 
1217     assert (clip_path != NULL);
1218 
1219     need_translate = dst_x | dst_y;
1220     do {
1221 	if (clip_path->surface != NULL &&
1222 	    clip_path->surface->backend == dst->backend)
1223 	{
1224 	    cairo_surface_pattern_t pattern;
1225 
1226 	    _cairo_pattern_init_for_surface (&pattern, clip_path->surface);
1227 	    cairo_matrix_init_translate (&pattern.base.matrix,
1228 					 dst_x - clip_path->extents.x,
1229 					 dst_y - clip_path->extents.y);
1230 	    pattern.base.filter = CAIRO_FILTER_NEAREST;
1231 	    status = _cairo_surface_paint (dst,
1232 					   CAIRO_OPERATOR_IN,
1233 					   &pattern.base,
1234 					   NULL);
1235 
1236 	    _cairo_pattern_fini (&pattern.base);
1237 
1238 	    return status;
1239 	}
1240 
1241 	if (clip_path->flags & CAIRO_CLIP_PATH_IS_BOX &&
1242 	    clip_path->path.maybe_fill_region)
1243 	{
1244 	    continue;
1245 	}
1246 
1247 	if (need_translate) {
1248 	    _cairo_path_fixed_translate (&clip_path->path,
1249 					 _cairo_fixed_from_int (-dst_x),
1250 					 _cairo_fixed_from_int (-dst_y));
1251 	}
1252 	status = _cairo_surface_fill (dst,
1253 				      CAIRO_OPERATOR_IN,
1254 				      &_cairo_pattern_white.base,
1255 				      &clip_path->path,
1256 				      clip_path->fill_rule,
1257 				      clip_path->tolerance,
1258 				      clip_path->antialias,
1259 				      NULL);
1260 	if (need_translate) {
1261 	    _cairo_path_fixed_translate (&clip_path->path,
1262 					 _cairo_fixed_from_int (dst_x),
1263 					 _cairo_fixed_from_int (dst_y));
1264 	}
1265 
1266 	if (unlikely (status))
1267 	    return status;
1268     } while ((clip_path = clip_path->prev) != NULL);
1269 
1270     return CAIRO_STATUS_SUCCESS;
1271 }
1272 
1273 static const cairo_rectangle_int_t _cairo_empty_rectangle_int = { 0, 0, 0, 0 };
1274 
1275 const cairo_rectangle_int_t *
_cairo_clip_get_extents(const cairo_clip_t * clip)1276 _cairo_clip_get_extents (const cairo_clip_t *clip)
1277 {
1278     if (clip->all_clipped)
1279 	return &_cairo_empty_rectangle_int;
1280 
1281     if (clip->path == NULL)
1282 	return NULL;
1283 
1284     return &clip->path->extents;
1285 }
1286 
1287 void
_cairo_clip_drop_cache(cairo_clip_t * clip)1288 _cairo_clip_drop_cache (cairo_clip_t  *clip)
1289 {
1290     cairo_clip_path_t *clip_path;
1291 
1292     if (clip->path == NULL)
1293 	return;
1294 
1295     clip_path = clip->path;
1296     do {
1297 	if (clip_path->region != NULL) {
1298 	    cairo_region_destroy (clip_path->region);
1299 	    clip_path->region = NULL;
1300 	}
1301 
1302 	if (clip_path->surface != NULL) {
1303 	    cairo_surface_destroy (clip_path->surface);
1304 	    clip_path->surface = NULL;
1305 	}
1306 
1307 	clip_path->flags &= ~CAIRO_CLIP_PATH_HAS_REGION;
1308     } while ((clip_path = clip_path->prev) != NULL);
1309 }
1310 
1311 const cairo_rectangle_list_t _cairo_rectangles_nil =
1312   { CAIRO_STATUS_NO_MEMORY, NULL, 0 };
1313 static const cairo_rectangle_list_t _cairo_rectangles_not_representable =
1314   { CAIRO_STATUS_CLIP_NOT_REPRESENTABLE, NULL, 0 };
1315 
1316 static cairo_bool_t
_cairo_clip_int_rect_to_user(cairo_gstate_t * gstate,cairo_rectangle_int_t * clip_rect,cairo_rectangle_t * user_rect)1317 _cairo_clip_int_rect_to_user (cairo_gstate_t *gstate,
1318 			      cairo_rectangle_int_t *clip_rect,
1319 			      cairo_rectangle_t *user_rect)
1320 {
1321     cairo_bool_t is_tight;
1322 
1323     double x1 = clip_rect->x;
1324     double y1 = clip_rect->y;
1325     double x2 = clip_rect->x + (int) clip_rect->width;
1326     double y2 = clip_rect->y + (int) clip_rect->height;
1327 
1328     _cairo_gstate_backend_to_user_rectangle (gstate,
1329 					     &x1, &y1, &x2, &y2,
1330 					     &is_tight);
1331 
1332     user_rect->x = x1;
1333     user_rect->y = y1;
1334     user_rect->width  = x2 - x1;
1335     user_rect->height = y2 - y1;
1336 
1337     return is_tight;
1338 }
1339 
1340 cairo_int_status_t
_cairo_clip_get_region(cairo_clip_t * clip,cairo_region_t ** region)1341 _cairo_clip_get_region (cairo_clip_t *clip,
1342 			cairo_region_t **region)
1343 {
1344     cairo_int_status_t status;
1345 
1346     if (clip->all_clipped)
1347 	goto CLIPPED;
1348 
1349     assert (clip->path != NULL);
1350 
1351     status = _cairo_clip_path_to_region (clip->path);
1352     if (status)
1353 	return status;
1354 
1355     if (cairo_region_is_empty (clip->path->region)) {
1356 	_cairo_clip_set_all_clipped (clip);
1357 	goto CLIPPED;
1358     }
1359 
1360     if (region)
1361 	*region = clip->path->region;
1362     return CAIRO_STATUS_SUCCESS;
1363 
1364   CLIPPED:
1365     if (region)
1366 	*region = NULL;
1367     return CAIRO_INT_STATUS_NOTHING_TO_DO;
1368 }
1369 
1370 cairo_int_status_t
_cairo_clip_get_boxes(cairo_clip_t * clip,cairo_box_t ** boxes,int * count)1371 _cairo_clip_get_boxes (cairo_clip_t *clip,
1372 		       cairo_box_t **boxes,
1373 		       int *count)
1374 {
1375     cairo_int_status_t status;
1376 
1377     if (clip->all_clipped)
1378 	return CAIRO_INT_STATUS_NOTHING_TO_DO;
1379 
1380     assert (clip->path != NULL);
1381 
1382     status = _cairo_clip_path_to_boxes (clip->path, boxes, count);
1383     if (status)
1384 	return status;
1385 
1386     if (*count == 0) {
1387 	_cairo_clip_set_all_clipped (clip);
1388 	return CAIRO_INT_STATUS_NOTHING_TO_DO;
1389     }
1390 
1391     return CAIRO_STATUS_SUCCESS;
1392 }
1393 
1394 static cairo_bool_t
box_is_aligned(const cairo_box_t * box)1395 box_is_aligned (const cairo_box_t *box)
1396 {
1397     return
1398 	_cairo_fixed_is_integer (box->p1.x) &&
1399 	_cairo_fixed_is_integer (box->p1.y) &&
1400 	_cairo_fixed_is_integer (box->p2.x) &&
1401 	_cairo_fixed_is_integer (box->p2.y);
1402 }
1403 
1404 static void
intersect_with_boxes(cairo_composite_rectangles_t * extents,cairo_box_t * boxes,int num_boxes)1405 intersect_with_boxes (cairo_composite_rectangles_t *extents,
1406 		      cairo_box_t *boxes,
1407 		      int num_boxes)
1408 {
1409     cairo_rectangle_int_t rect;
1410     cairo_box_t box;
1411     cairo_bool_t is_empty;
1412 
1413     box.p1.x = box.p1.y = INT_MIN;
1414     box.p2.x = box.p2.y = INT_MAX;
1415     while (num_boxes--) {
1416 	if (boxes->p1.x < box.p1.x)
1417 	    box.p1.x = boxes->p1.x;
1418 	if (boxes->p1.y < box.p1.y)
1419 	    box.p1.y = boxes->p1.y;
1420 
1421 	if (boxes->p2.x > box.p2.x)
1422 	    box.p2.x = boxes->p2.x;
1423 	if (boxes->p2.y > box.p2.y)
1424 	    box.p2.y = boxes->p2.y;
1425     }
1426 
1427     _cairo_box_round_to_rectangle (&box, &rect);
1428     is_empty = _cairo_rectangle_intersect (&extents->bounded, &rect);
1429     is_empty = _cairo_rectangle_intersect (&extents->unbounded, &rect);
1430 }
1431 
1432 cairo_status_t
_cairo_clip_to_boxes(cairo_clip_t ** clip,cairo_composite_rectangles_t * extents,cairo_box_t ** boxes,int * num_boxes)1433 _cairo_clip_to_boxes (cairo_clip_t **clip,
1434 		      cairo_composite_rectangles_t *extents,
1435 		      cairo_box_t **boxes,
1436 		      int *num_boxes)
1437 {
1438     cairo_status_t status;
1439     const cairo_rectangle_int_t *rect;
1440 
1441     rect = extents->is_bounded ? &extents->bounded : &extents->unbounded;
1442 
1443     if (*clip == NULL)
1444 	goto EXTENTS;
1445 
1446     status = _cairo_clip_rectangle (*clip, rect);
1447     if (unlikely (status))
1448 	return status;
1449 
1450     status = _cairo_clip_get_boxes (*clip, boxes, num_boxes);
1451     switch ((int) status) {
1452     case CAIRO_STATUS_SUCCESS:
1453 	intersect_with_boxes (extents, *boxes, *num_boxes);
1454 	if (rect->width == 0 || rect->height == 0 ||
1455 	    extents->is_bounded ||
1456 	    (*num_boxes == 1 && box_is_aligned (*boxes)))
1457 	{
1458 	    *clip = NULL;
1459 	}
1460 	goto DONE;
1461 
1462     case CAIRO_INT_STATUS_UNSUPPORTED:
1463 	goto EXTENTS;
1464 
1465     default:
1466 	return status;
1467     }
1468 
1469   EXTENTS:
1470     status = CAIRO_STATUS_SUCCESS;
1471     _cairo_box_from_rectangle (&(*boxes)[0], rect);
1472     *num_boxes = 1;
1473   DONE:
1474     return status;
1475 }
1476 
1477 
1478 static cairo_rectangle_list_t *
_cairo_rectangle_list_create_in_error(cairo_status_t status)1479 _cairo_rectangle_list_create_in_error (cairo_status_t status)
1480 {
1481     cairo_rectangle_list_t *list;
1482 
1483     if (status == CAIRO_STATUS_NO_MEMORY)
1484 	return (cairo_rectangle_list_t*) &_cairo_rectangles_nil;
1485     if (status == CAIRO_STATUS_CLIP_NOT_REPRESENTABLE)
1486 	return (cairo_rectangle_list_t*) &_cairo_rectangles_not_representable;
1487 
1488     list = malloc (sizeof (*list));
1489     if (unlikely (list == NULL)) {
1490 	_cairo_error_throw (status);
1491 	return (cairo_rectangle_list_t*) &_cairo_rectangles_nil;
1492     }
1493 
1494     list->status = status;
1495     list->rectangles = NULL;
1496     list->num_rectangles = 0;
1497 
1498     return list;
1499 }
1500 
1501 cairo_rectangle_list_t *
_cairo_clip_copy_rectangle_list(cairo_clip_t * clip,cairo_gstate_t * gstate)1502 _cairo_clip_copy_rectangle_list (cairo_clip_t *clip, cairo_gstate_t *gstate)
1503 {
1504 #define ERROR_LIST(S) _cairo_rectangle_list_create_in_error (_cairo_error (S))
1505 
1506     cairo_rectangle_list_t *list;
1507     cairo_rectangle_t *rectangles = NULL;
1508     cairo_region_t *region = NULL;
1509     cairo_int_status_t status;
1510     int n_rects = 0;
1511     int i;
1512 
1513     if (clip->all_clipped)
1514 	goto DONE;
1515 
1516     if (!clip->path)
1517 	return ERROR_LIST (CAIRO_STATUS_CLIP_NOT_REPRESENTABLE);
1518 
1519     status = _cairo_clip_get_region (clip, &region);
1520     if (status == CAIRO_INT_STATUS_NOTHING_TO_DO) {
1521 	goto DONE;
1522     } else if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
1523 	return ERROR_LIST (CAIRO_STATUS_CLIP_NOT_REPRESENTABLE);
1524     } else if (unlikely (status)) {
1525 	return ERROR_LIST (status);
1526     }
1527 
1528     n_rects = cairo_region_num_rectangles (region);
1529     if (n_rects) {
1530 	rectangles = _cairo_malloc_ab (n_rects, sizeof (cairo_rectangle_t));
1531 	if (unlikely (rectangles == NULL)) {
1532 	    return ERROR_LIST (CAIRO_STATUS_NO_MEMORY);
1533 	}
1534 
1535 	for (i = 0; i < n_rects; ++i) {
1536 	    cairo_rectangle_int_t clip_rect;
1537 
1538 	    cairo_region_get_rectangle (region, i, &clip_rect);
1539 
1540 	    if (! _cairo_clip_int_rect_to_user (gstate,
1541 						&clip_rect,
1542 						&rectangles[i]))
1543 	    {
1544 		free (rectangles);
1545 		return ERROR_LIST (CAIRO_STATUS_CLIP_NOT_REPRESENTABLE);
1546 	    }
1547 	}
1548     }
1549 
1550  DONE:
1551     list = malloc (sizeof (cairo_rectangle_list_t));
1552     if (unlikely (list == NULL)) {
1553         free (rectangles);
1554 	return ERROR_LIST (CAIRO_STATUS_NO_MEMORY);
1555     }
1556 
1557     list->status = CAIRO_STATUS_SUCCESS;
1558     list->rectangles = rectangles;
1559     list->num_rectangles = n_rects;
1560     return list;
1561 
1562 #undef ERROR_LIST
1563 }
1564 
1565 /**
1566  * cairo_rectangle_list_destroy:
1567  * @rectangle_list: a rectangle list, as obtained from cairo_copy_clip_rectangles()
1568  *
1569  * Unconditionally frees @rectangle_list and all associated
1570  * references. After this call, the @rectangle_list pointer must not
1571  * be dereferenced.
1572  *
1573  * Since: 1.4
1574  **/
1575 void
cairo_rectangle_list_destroy(cairo_rectangle_list_t * rectangle_list)1576 cairo_rectangle_list_destroy (cairo_rectangle_list_t *rectangle_list)
1577 {
1578     if (rectangle_list == NULL || rectangle_list == &_cairo_rectangles_nil ||
1579         rectangle_list == &_cairo_rectangles_not_representable)
1580         return;
1581 
1582     free (rectangle_list->rectangles);
1583     free (rectangle_list);
1584 }
1585 
1586 void
_cairo_clip_reset_static_data(void)1587 _cairo_clip_reset_static_data (void)
1588 {
1589     _freed_pool_reset (&clip_path_pool);
1590 }
1591