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 © 2005 Red Hat, Inc.
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it either under the terms of the GNU Lesser General Public
8  * License version 2.1 as published by the Free Software Foundation
9  * (the "LGPL") or, at your option, under the terms of the Mozilla
10  * Public License Version 1.1 (the "MPL"). If you do not alter this
11  * notice, a recipient may use your version of this file under either
12  * the MPL or the LGPL.
13  *
14  * You should have received a copy of the LGPL along with this library
15  * in the file COPYING-LGPL-2.1; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
17  * You should have received a copy of the MPL along with this library
18  * in the file COPYING-MPL-1.1
19  *
20  * The contents of this file are subject to the Mozilla Public License
21  * Version 1.1 (the "License"); you may not use this file except in
22  * compliance with the License. You may obtain a copy of the License at
23  * http://www.mozilla.org/MPL/
24  *
25  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
26  * OF ANY KIND, either express or implied. See the LGPL or the MPL for
27  * the specific language governing rights and limitations.
28  *
29  * The Original Code is the cairo graphics library.
30  *
31  * The Initial Developer of the Original Code is Red Hat, Inc.
32  *
33  * Contributor(s):
34  *	Owen Taylor <otaylor@redhat.com>
35  *      Vladimir Vukicevic <vladimir@pobox.com>
36  *      Søren Sandmann <sandmann@daimi.au.dk>
37  */
38 
39 #include "cairoint.h"
40 
41 #include "cairo-error-private.h"
42 #include "cairo-region-private.h"
43 
44 /* XXX need to update pixman headers to be const as appropriate */
45 #define CONST_CAST (pixman_region32_t *)
46 
47 /**
48  * SECTION:cairo-region
49  * @Title: Regions
50  * @Short_Description: Representing a pixel-aligned area
51  *
52  * Regions are a simple graphical data type representing an area of
53  * integer-aligned rectangles. They are often used on raster surfaces
54  * to track areas of interest, such as change or clip areas.
55  */
56 
57 static const cairo_region_t _cairo_region_nil = {
58     CAIRO_REFERENCE_COUNT_INVALID,	/* ref_count */
59     CAIRO_STATUS_NO_MEMORY,		/* status */
60 };
61 
62 cairo_region_t *
_cairo_region_create_in_error(cairo_status_t status)63 _cairo_region_create_in_error (cairo_status_t status)
64 {
65     switch (status) {
66     case CAIRO_STATUS_NO_MEMORY:
67 	return (cairo_region_t *) &_cairo_region_nil;
68 
69     case CAIRO_STATUS_SUCCESS:
70     case CAIRO_STATUS_LAST_STATUS:
71 	ASSERT_NOT_REACHED;
72 	/* fall-through */
73     case CAIRO_STATUS_SURFACE_TYPE_MISMATCH:
74     case CAIRO_STATUS_INVALID_STATUS:
75     case CAIRO_STATUS_INVALID_CONTENT:
76     case CAIRO_STATUS_INVALID_FORMAT:
77     case CAIRO_STATUS_INVALID_VISUAL:
78     case CAIRO_STATUS_READ_ERROR:
79     case CAIRO_STATUS_WRITE_ERROR:
80     case CAIRO_STATUS_FILE_NOT_FOUND:
81     case CAIRO_STATUS_TEMP_FILE_ERROR:
82     case CAIRO_STATUS_INVALID_STRIDE:
83     case CAIRO_STATUS_INVALID_SIZE:
84     case CAIRO_STATUS_DEVICE_TYPE_MISMATCH:
85     case CAIRO_STATUS_DEVICE_ERROR:
86     case CAIRO_STATUS_INVALID_RESTORE:
87     case CAIRO_STATUS_INVALID_POP_GROUP:
88     case CAIRO_STATUS_NO_CURRENT_POINT:
89     case CAIRO_STATUS_INVALID_MATRIX:
90     case CAIRO_STATUS_NULL_POINTER:
91     case CAIRO_STATUS_INVALID_STRING:
92     case CAIRO_STATUS_INVALID_PATH_DATA:
93     case CAIRO_STATUS_SURFACE_FINISHED:
94     case CAIRO_STATUS_PATTERN_TYPE_MISMATCH:
95     case CAIRO_STATUS_INVALID_DASH:
96     case CAIRO_STATUS_INVALID_DSC_COMMENT:
97     case CAIRO_STATUS_INVALID_INDEX:
98     case CAIRO_STATUS_CLIP_NOT_REPRESENTABLE:
99     case CAIRO_STATUS_FONT_TYPE_MISMATCH:
100     case CAIRO_STATUS_USER_FONT_IMMUTABLE:
101     case CAIRO_STATUS_USER_FONT_ERROR:
102     case CAIRO_STATUS_NEGATIVE_COUNT:
103     case CAIRO_STATUS_INVALID_CLUSTERS:
104     case CAIRO_STATUS_INVALID_SLANT:
105     case CAIRO_STATUS_INVALID_WEIGHT:
106     case CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED:
107     default:
108 	_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
109 	return (cairo_region_t *) &_cairo_region_nil;
110     }
111 }
112 
113 /**
114  * _cairo_region_set_error:
115  * @region: a region
116  * @status: a status value indicating an error
117  *
118  * Atomically sets region->status to @status and calls _cairo_error;
119  * Does nothing if status is %CAIRO_STATUS_SUCCESS or any of the internal
120  * status values.
121  *
122  * All assignments of an error status to region->status should happen
123  * through _cairo_region_set_error(). Note that due to the nature of
124  * the atomic operation, it is not safe to call this function on the
125  * nil objects.
126  *
127  * The purpose of this function is to allow the user to set a
128  * breakpoint in _cairo_error() to generate a stack trace for when the
129  * user causes cairo to detect an error.
130  *
131  * Return value: the error status.
132  **/
133 static cairo_status_t
_cairo_region_set_error(cairo_region_t * region,cairo_status_t status)134 _cairo_region_set_error (cairo_region_t *region,
135 			cairo_status_t status)
136 {
137     if (! _cairo_status_is_error (status))
138 	return status;
139 
140     /* Don't overwrite an existing error. This preserves the first
141      * error, which is the most significant. */
142     _cairo_status_set_error (&region->status, status);
143 
144     return _cairo_error (status);
145 }
146 
147 void
_cairo_region_init(cairo_region_t * region)148 _cairo_region_init (cairo_region_t *region)
149 {
150     VG (VALGRIND_MAKE_MEM_UNDEFINED (region, sizeof (cairo_region_t)));
151 
152     region->status = CAIRO_STATUS_SUCCESS;
153     CAIRO_REFERENCE_COUNT_INIT (&region->ref_count, 0);
154     pixman_region32_init (&region->rgn);
155 }
156 
157 void
_cairo_region_init_rectangle(cairo_region_t * region,const cairo_rectangle_int_t * rectangle)158 _cairo_region_init_rectangle (cairo_region_t *region,
159 			      const cairo_rectangle_int_t *rectangle)
160 {
161     VG (VALGRIND_MAKE_MEM_UNDEFINED (region, sizeof (cairo_region_t)));
162 
163     region->status = CAIRO_STATUS_SUCCESS;
164     CAIRO_REFERENCE_COUNT_INIT (&region->ref_count, 0);
165     pixman_region32_init_rect (&region->rgn,
166 			       rectangle->x, rectangle->y,
167 			       rectangle->width, rectangle->height);
168 }
169 
170 void
_cairo_region_fini(cairo_region_t * region)171 _cairo_region_fini (cairo_region_t *region)
172 {
173     assert (! CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&region->ref_count));
174     pixman_region32_fini (&region->rgn);
175     VG (VALGRIND_MAKE_MEM_NOACCESS (region, sizeof (cairo_region_t)));
176 }
177 
178 /**
179  * cairo_region_create:
180  *
181  * Allocates a new empty region object.
182  *
183  * Return value: A newly allocated #cairo_region_t. Free with
184  *   cairo_region_destroy(). This function always returns a
185  *   valid pointer; if memory cannot be allocated, then a special
186  *   error object is returned where all operations on the object do nothing.
187  *   You can check for this with cairo_region_status().
188  *
189  * Since: 1.10
190  **/
191 cairo_region_t *
cairo_region_create(void)192 cairo_region_create (void)
193 {
194     cairo_region_t *region;
195 
196     region = _cairo_malloc (sizeof (cairo_region_t));
197     if (region == NULL)
198 	return (cairo_region_t *) &_cairo_region_nil;
199 
200     region->status = CAIRO_STATUS_SUCCESS;
201     CAIRO_REFERENCE_COUNT_INIT (&region->ref_count, 1);
202 
203     pixman_region32_init (&region->rgn);
204 
205     return region;
206 }
207 slim_hidden_def (cairo_region_create);
208 
209 /**
210  * cairo_region_create_rectangles:
211  * @rects: an array of @count rectangles
212  * @count: number of rectangles
213  *
214  * Allocates a new region object containing the union of all given @rects.
215  *
216  * Return value: A newly allocated #cairo_region_t. Free with
217  *   cairo_region_destroy(). This function always returns a
218  *   valid pointer; if memory cannot be allocated, then a special
219  *   error object is returned where all operations on the object do nothing.
220  *   You can check for this with cairo_region_status().
221  *
222  * Since: 1.10
223  **/
224 cairo_region_t *
cairo_region_create_rectangles(const cairo_rectangle_int_t * rects,int count)225 cairo_region_create_rectangles (const cairo_rectangle_int_t *rects,
226 				int count)
227 {
228     pixman_box32_t stack_pboxes[CAIRO_STACK_ARRAY_LENGTH (pixman_box32_t)];
229     pixman_box32_t *pboxes = stack_pboxes;
230     cairo_region_t *region;
231     int i;
232 
233     region = _cairo_malloc (sizeof (cairo_region_t));
234     if (unlikely (region == NULL))
235 	return _cairo_region_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
236 
237     if (count > ARRAY_LENGTH (stack_pboxes)) {
238 	pboxes = _cairo_malloc_ab (count, sizeof (pixman_box32_t));
239 	if (unlikely (pboxes == NULL)) {
240 	    free (region);
241 	    return _cairo_region_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
242 	}
243     }
244 
245     for (i = 0; i < count; i++) {
246 	pboxes[i].x1 = rects[i].x;
247 	pboxes[i].y1 = rects[i].y;
248 	pboxes[i].x2 = rects[i].x + rects[i].width;
249 	pboxes[i].y2 = rects[i].y + rects[i].height;
250     }
251 
252     i = pixman_region32_init_rects (&region->rgn, pboxes, count);
253 
254     if (pboxes != stack_pboxes)
255 	free (pboxes);
256 
257     if (unlikely (i == 0)) {
258 	free (region);
259 	return _cairo_region_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
260     }
261 
262     CAIRO_REFERENCE_COUNT_INIT (&region->ref_count, 1);
263     region->status = CAIRO_STATUS_SUCCESS;
264     return region;
265 }
266 slim_hidden_def (cairo_region_create_rectangles);
267 
268 /**
269  * cairo_region_create_rectangle:
270  * @rectangle: a #cairo_rectangle_int_t
271  *
272  * Allocates a new region object containing @rectangle.
273  *
274  * Return value: A newly allocated #cairo_region_t. Free with
275  *   cairo_region_destroy(). This function always returns a
276  *   valid pointer; if memory cannot be allocated, then a special
277  *   error object is returned where all operations on the object do nothing.
278  *   You can check for this with cairo_region_status().
279  *
280  * Since: 1.10
281  **/
282 cairo_region_t *
cairo_region_create_rectangle(const cairo_rectangle_int_t * rectangle)283 cairo_region_create_rectangle (const cairo_rectangle_int_t *rectangle)
284 {
285     cairo_region_t *region;
286 
287     region = _cairo_malloc (sizeof (cairo_region_t));
288     if (unlikely (region == NULL))
289 	return (cairo_region_t *) &_cairo_region_nil;
290 
291     region->status = CAIRO_STATUS_SUCCESS;
292     CAIRO_REFERENCE_COUNT_INIT (&region->ref_count, 1);
293 
294     pixman_region32_init_rect (&region->rgn,
295 			       rectangle->x, rectangle->y,
296 			       rectangle->width, rectangle->height);
297 
298     return region;
299 }
300 slim_hidden_def (cairo_region_create_rectangle);
301 
302 /**
303  * cairo_region_copy:
304  * @original: a #cairo_region_t
305  *
306  * Allocates a new region object copying the area from @original.
307  *
308  * Return value: A newly allocated #cairo_region_t. Free with
309  *   cairo_region_destroy(). This function always returns a
310  *   valid pointer; if memory cannot be allocated, then a special
311  *   error object is returned where all operations on the object do nothing.
312  *   You can check for this with cairo_region_status().
313  *
314  * Since: 1.10
315  **/
316 cairo_region_t *
cairo_region_copy(const cairo_region_t * original)317 cairo_region_copy (const cairo_region_t *original)
318 {
319     cairo_region_t *copy;
320 
321     if (original != NULL && original->status)
322 	return (cairo_region_t *) &_cairo_region_nil;
323 
324     copy = cairo_region_create ();
325     if (unlikely (copy->status))
326 	return copy;
327 
328     if (original != NULL &&
329 	! pixman_region32_copy (&copy->rgn, CONST_CAST &original->rgn))
330     {
331 	cairo_region_destroy (copy);
332 	return (cairo_region_t *) &_cairo_region_nil;
333     }
334 
335     return copy;
336 }
337 slim_hidden_def (cairo_region_copy);
338 
339 /**
340  * cairo_region_reference:
341  * @region: a #cairo_region_t
342  *
343  * Increases the reference count on @region by one. This prevents
344  * @region from being destroyed until a matching call to
345  * cairo_region_destroy() is made.
346  *
347  * Return value: the referenced #cairo_region_t.
348  *
349  * Since: 1.10
350  **/
351 cairo_region_t *
cairo_region_reference(cairo_region_t * region)352 cairo_region_reference (cairo_region_t *region)
353 {
354     if (region == NULL || CAIRO_REFERENCE_COUNT_IS_INVALID (&region->ref_count))
355 	return NULL;
356 
357     assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&region->ref_count));
358 
359     _cairo_reference_count_inc (&region->ref_count);
360     return region;
361 }
362 slim_hidden_def (cairo_region_reference);
363 
364 /**
365  * cairo_region_destroy:
366  * @region: a #cairo_region_t
367  *
368  * Destroys a #cairo_region_t object created with
369  * cairo_region_create(), cairo_region_copy(), or
370  * or cairo_region_create_rectangle().
371  *
372  * Since: 1.10
373  **/
374 void
cairo_region_destroy(cairo_region_t * region)375 cairo_region_destroy (cairo_region_t *region)
376 {
377     if (region == NULL || CAIRO_REFERENCE_COUNT_IS_INVALID (&region->ref_count))
378 	return;
379 
380     assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&region->ref_count));
381 
382     if (! _cairo_reference_count_dec_and_test (&region->ref_count))
383 	return;
384 
385     _cairo_region_fini (region);
386     free (region);
387 }
388 slim_hidden_def (cairo_region_destroy);
389 
390 /**
391  * cairo_region_num_rectangles:
392  * @region: a #cairo_region_t
393  *
394  * Returns the number of rectangles contained in @region.
395  *
396  * Return value: The number of rectangles contained in @region.
397  *
398  * Since: 1.10
399  **/
400 int
cairo_region_num_rectangles(const cairo_region_t * region)401 cairo_region_num_rectangles (const cairo_region_t *region)
402 {
403     if (region->status)
404 	return 0;
405 
406     return pixman_region32_n_rects (CONST_CAST &region->rgn);
407 }
408 slim_hidden_def (cairo_region_num_rectangles);
409 
410 /**
411  * cairo_region_get_rectangle:
412  * @region: a #cairo_region_t
413  * @nth: a number indicating which rectangle should be returned
414  * @rectangle: return location for a #cairo_rectangle_int_t
415  *
416  * Stores the @nth rectangle from the region in @rectangle.
417  *
418  * Since: 1.10
419  **/
420 void
cairo_region_get_rectangle(const cairo_region_t * region,int nth,cairo_rectangle_int_t * rectangle)421 cairo_region_get_rectangle (const cairo_region_t *region,
422 			    int nth,
423 			    cairo_rectangle_int_t *rectangle)
424 {
425     pixman_box32_t *pbox;
426 
427     if (region->status) {
428 	rectangle->x = rectangle->y = 0;
429 	rectangle->width = rectangle->height = 0;
430 	return;
431     }
432 
433     pbox = pixman_region32_rectangles (CONST_CAST &region->rgn, NULL) + nth;
434 
435     rectangle->x = pbox->x1;
436     rectangle->y = pbox->y1;
437     rectangle->width = pbox->x2 - pbox->x1;
438     rectangle->height = pbox->y2 - pbox->y1;
439 }
440 slim_hidden_def (cairo_region_get_rectangle);
441 
442 /**
443  * cairo_region_get_extents:
444  * @region: a #cairo_region_t
445  * @extents: rectangle into which to store the extents
446  *
447  * Gets the bounding rectangle of @region as a #cairo_rectangle_int_t
448  *
449  * Since: 1.10
450  **/
451 void
cairo_region_get_extents(const cairo_region_t * region,cairo_rectangle_int_t * extents)452 cairo_region_get_extents (const cairo_region_t *region,
453 			  cairo_rectangle_int_t *extents)
454 {
455     pixman_box32_t *pextents;
456 
457     if (region->status) {
458 	extents->x = extents->y = 0;
459 	extents->width = extents->height = 0;
460 	return;
461     }
462 
463     pextents = pixman_region32_extents (CONST_CAST &region->rgn);
464 
465     extents->x = pextents->x1;
466     extents->y = pextents->y1;
467     extents->width = pextents->x2 - pextents->x1;
468     extents->height = pextents->y2 - pextents->y1;
469 }
470 slim_hidden_def (cairo_region_get_extents);
471 
472 /**
473  * cairo_region_status:
474  * @region: a #cairo_region_t
475  *
476  * Checks whether an error has previous occured for this
477  * region object.
478  *
479  * Return value: %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY
480  *
481  * Since: 1.10
482  **/
483 cairo_status_t
cairo_region_status(const cairo_region_t * region)484 cairo_region_status (const cairo_region_t *region)
485 {
486     return region->status;
487 }
488 slim_hidden_def (cairo_region_status);
489 
490 /**
491  * cairo_region_subtract:
492  * @dst: a #cairo_region_t
493  * @other: another #cairo_region_t
494  *
495  * Subtracts @other from @dst and places the result in @dst
496  *
497  * Return value: %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY
498  *
499  * Since: 1.10
500  **/
501 cairo_status_t
cairo_region_subtract(cairo_region_t * dst,const cairo_region_t * other)502 cairo_region_subtract (cairo_region_t *dst, const cairo_region_t *other)
503 {
504     if (dst->status)
505 	return dst->status;
506 
507     if (other->status)
508 	return _cairo_region_set_error (dst, other->status);
509 
510     if (! pixman_region32_subtract (&dst->rgn,
511 				    &dst->rgn,
512 				    CONST_CAST &other->rgn))
513     {
514 	return _cairo_region_set_error (dst, CAIRO_STATUS_NO_MEMORY);
515     }
516 
517     return CAIRO_STATUS_SUCCESS;
518 }
519 slim_hidden_def (cairo_region_subtract);
520 
521 /**
522  * cairo_region_subtract_rectangle:
523  * @dst: a #cairo_region_t
524  * @rectangle: a #cairo_rectangle_int_t
525  *
526  * Subtracts @rectangle from @dst and places the result in @dst
527  *
528  * Return value: %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY
529  *
530  * Since: 1.10
531  **/
532 cairo_status_t
cairo_region_subtract_rectangle(cairo_region_t * dst,const cairo_rectangle_int_t * rectangle)533 cairo_region_subtract_rectangle (cairo_region_t *dst,
534 				 const cairo_rectangle_int_t *rectangle)
535 {
536     cairo_status_t status = CAIRO_STATUS_SUCCESS;
537     pixman_region32_t region;
538 
539     if (dst->status)
540 	return dst->status;
541 
542     pixman_region32_init_rect (&region,
543 			       rectangle->x, rectangle->y,
544 			       rectangle->width, rectangle->height);
545 
546     if (! pixman_region32_subtract (&dst->rgn, &dst->rgn, &region))
547 	status = _cairo_region_set_error (dst, CAIRO_STATUS_NO_MEMORY);
548 
549     pixman_region32_fini (&region);
550 
551     return status;
552 }
553 slim_hidden_def (cairo_region_subtract_rectangle);
554 
555 /**
556  * cairo_region_intersect:
557  * @dst: a #cairo_region_t
558  * @other: another #cairo_region_t
559  *
560  * Computes the intersection of @dst with @other and places the result in @dst
561  *
562  * Return value: %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY
563  *
564  * Since: 1.10
565  **/
566 cairo_status_t
cairo_region_intersect(cairo_region_t * dst,const cairo_region_t * other)567 cairo_region_intersect (cairo_region_t *dst, const cairo_region_t *other)
568 {
569     if (dst->status)
570 	return dst->status;
571 
572     if (other->status)
573 	return _cairo_region_set_error (dst, other->status);
574 
575     if (! pixman_region32_intersect (&dst->rgn, &dst->rgn, CONST_CAST &other->rgn))
576 	return _cairo_region_set_error (dst, CAIRO_STATUS_NO_MEMORY);
577 
578     return CAIRO_STATUS_SUCCESS;
579 }
580 slim_hidden_def (cairo_region_intersect);
581 
582 /**
583  * cairo_region_intersect_rectangle:
584  * @dst: a #cairo_region_t
585  * @rectangle: a #cairo_rectangle_int_t
586  *
587  * Computes the intersection of @dst with @rectangle and places the
588  * result in @dst
589  *
590  * Return value: %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY
591  *
592  * Since: 1.10
593  **/
594 cairo_status_t
cairo_region_intersect_rectangle(cairo_region_t * dst,const cairo_rectangle_int_t * rectangle)595 cairo_region_intersect_rectangle (cairo_region_t *dst,
596 				  const cairo_rectangle_int_t *rectangle)
597 {
598     cairo_status_t status = CAIRO_STATUS_SUCCESS;
599     pixman_region32_t region;
600 
601     if (dst->status)
602 	return dst->status;
603 
604     pixman_region32_init_rect (&region,
605 			       rectangle->x, rectangle->y,
606 			       rectangle->width, rectangle->height);
607 
608     if (! pixman_region32_intersect (&dst->rgn, &dst->rgn, &region))
609 	status = _cairo_region_set_error (dst, CAIRO_STATUS_NO_MEMORY);
610 
611     pixman_region32_fini (&region);
612 
613     return status;
614 }
615 slim_hidden_def (cairo_region_intersect_rectangle);
616 
617 /**
618  * cairo_region_union:
619  * @dst: a #cairo_region_t
620  * @other: another #cairo_region_t
621  *
622  * Computes the union of @dst with @other and places the result in @dst
623  *
624  * Return value: %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY
625  *
626  * Since: 1.10
627  **/
628 cairo_status_t
cairo_region_union(cairo_region_t * dst,const cairo_region_t * other)629 cairo_region_union (cairo_region_t *dst,
630 		    const cairo_region_t *other)
631 {
632     if (dst->status)
633 	return dst->status;
634 
635     if (other->status)
636 	return _cairo_region_set_error (dst, other->status);
637 
638     if (! pixman_region32_union (&dst->rgn, &dst->rgn, CONST_CAST &other->rgn))
639 	return _cairo_region_set_error (dst, CAIRO_STATUS_NO_MEMORY);
640 
641     return CAIRO_STATUS_SUCCESS;
642 }
643 slim_hidden_def (cairo_region_union);
644 
645 /**
646  * cairo_region_union_rectangle:
647  * @dst: a #cairo_region_t
648  * @rectangle: a #cairo_rectangle_int_t
649  *
650  * Computes the union of @dst with @rectangle and places the result in @dst.
651  *
652  * Return value: %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY
653  *
654  * Since: 1.10
655  **/
656 cairo_status_t
cairo_region_union_rectangle(cairo_region_t * dst,const cairo_rectangle_int_t * rectangle)657 cairo_region_union_rectangle (cairo_region_t *dst,
658 			      const cairo_rectangle_int_t *rectangle)
659 {
660     cairo_status_t status = CAIRO_STATUS_SUCCESS;
661     pixman_region32_t region;
662 
663     if (dst->status)
664 	return dst->status;
665 
666     pixman_region32_init_rect (&region,
667 			       rectangle->x, rectangle->y,
668 			       rectangle->width, rectangle->height);
669 
670     if (! pixman_region32_union (&dst->rgn, &dst->rgn, &region))
671 	status = _cairo_region_set_error (dst, CAIRO_STATUS_NO_MEMORY);
672 
673     pixman_region32_fini (&region);
674 
675     return status;
676 }
677 slim_hidden_def (cairo_region_union_rectangle);
678 
679 /**
680  * cairo_region_xor:
681  * @dst: a #cairo_region_t
682  * @other: another #cairo_region_t
683  *
684  * Computes the exclusive difference of @dst with @other and places the
685  * result in @dst. That is, @dst will be set to contain all areas that
686  * are either in @dst or in @other, but not in both.
687  *
688  * Return value: %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY
689  *
690  * Since: 1.10
691  **/
692 cairo_status_t
cairo_region_xor(cairo_region_t * dst,const cairo_region_t * other)693 cairo_region_xor (cairo_region_t *dst, const cairo_region_t *other)
694 {
695     cairo_status_t status = CAIRO_STATUS_SUCCESS;
696     pixman_region32_t tmp;
697 
698     if (dst->status)
699 	return dst->status;
700 
701     if (other->status)
702 	return _cairo_region_set_error (dst, other->status);
703 
704     pixman_region32_init (&tmp);
705 
706     /* XXX: get an xor function into pixman */
707     if (! pixman_region32_subtract (&tmp, CONST_CAST &other->rgn, &dst->rgn) ||
708         ! pixman_region32_subtract (&dst->rgn, &dst->rgn, CONST_CAST &other->rgn) ||
709         ! pixman_region32_union (&dst->rgn, &dst->rgn, &tmp))
710 	status = _cairo_region_set_error (dst, CAIRO_STATUS_NO_MEMORY);
711 
712     pixman_region32_fini (&tmp);
713 
714     return status;
715 }
716 slim_hidden_def (cairo_region_xor);
717 
718 /**
719  * cairo_region_xor_rectangle:
720  * @dst: a #cairo_region_t
721  * @rectangle: a #cairo_rectangle_int_t
722  *
723  * Computes the exclusive difference of @dst with @rectangle and places the
724  * result in @dst. That is, @dst will be set to contain all areas that are
725  * either in @dst or in @rectangle, but not in both.
726  *
727  * Return value: %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY
728  *
729  * Since: 1.10
730  **/
731 cairo_status_t
cairo_region_xor_rectangle(cairo_region_t * dst,const cairo_rectangle_int_t * rectangle)732 cairo_region_xor_rectangle (cairo_region_t *dst,
733 			    const cairo_rectangle_int_t *rectangle)
734 {
735     cairo_status_t status = CAIRO_STATUS_SUCCESS;
736     pixman_region32_t region, tmp;
737 
738     if (dst->status)
739 	return dst->status;
740 
741     pixman_region32_init_rect (&region,
742 			       rectangle->x, rectangle->y,
743 			       rectangle->width, rectangle->height);
744     pixman_region32_init (&tmp);
745 
746     /* XXX: get an xor function into pixman */
747     if (! pixman_region32_subtract (&tmp, &region, &dst->rgn) ||
748         ! pixman_region32_subtract (&dst->rgn, &dst->rgn, &region) ||
749         ! pixman_region32_union (&dst->rgn, &dst->rgn, &tmp))
750 	status = _cairo_region_set_error (dst, CAIRO_STATUS_NO_MEMORY);
751 
752     pixman_region32_fini (&tmp);
753     pixman_region32_fini (&region);
754 
755     return status;
756 }
757 slim_hidden_def (cairo_region_xor_rectangle);
758 
759 /**
760  * cairo_region_is_empty:
761  * @region: a #cairo_region_t
762  *
763  * Checks whether @region is empty.
764  *
765  * Return value: %TRUE if @region is empty, %FALSE if it isn't.
766  *
767  * Since: 1.10
768  **/
769 cairo_bool_t
cairo_region_is_empty(const cairo_region_t * region)770 cairo_region_is_empty (const cairo_region_t *region)
771 {
772     if (region->status)
773 	return TRUE;
774 
775     return ! pixman_region32_not_empty (CONST_CAST &region->rgn);
776 }
777 slim_hidden_def (cairo_region_is_empty);
778 
779 /**
780  * cairo_region_translate:
781  * @region: a #cairo_region_t
782  * @dx: Amount to translate in the x direction
783  * @dy: Amount to translate in the y direction
784  *
785  * Translates @region by (@dx, @dy).
786  *
787  * Since: 1.10
788  **/
789 void
cairo_region_translate(cairo_region_t * region,int dx,int dy)790 cairo_region_translate (cairo_region_t *region,
791 			int dx, int dy)
792 {
793     if (region->status)
794 	return;
795 
796     pixman_region32_translate (&region->rgn, dx, dy);
797 }
798 slim_hidden_def (cairo_region_translate);
799 
800 /**
801  * cairo_region_overlap_t:
802  * @CAIRO_REGION_OVERLAP_IN: The contents are entirely inside the region
803  * @CAIRO_REGION_OVERLAP_OUT: The contents are entirely outside the region
804  * @CAIRO_REGION_OVERLAP_PART: The contents are partially inside and
805  *     partially outside the region.
806  *
807  * Used as the return value for cairo_region_contains_rectangle().
808  */
809 
810 /**
811  * cairo_region_contains_rectangle:
812  * @region: a #cairo_region_t
813  * @rectangle: a #cairo_rectangle_int_t
814  *
815  * Checks whether @rectangle is inside, outside or partially contained
816  * in @region
817  *
818  * Return value:
819  *   %CAIRO_REGION_OVERLAP_IN if @rectangle is entirely inside @region,
820  *   %CAIRO_REGION_OVERLAP_OUT if @rectangle is entirely outside @region, or
821  *   %CAIRO_REGION_OVERLAP_PART if @rectangle is partially inside and partially outside @region.
822  *
823  * Since: 1.10
824  **/
825 cairo_region_overlap_t
cairo_region_contains_rectangle(const cairo_region_t * region,const cairo_rectangle_int_t * rectangle)826 cairo_region_contains_rectangle (const cairo_region_t *region,
827 				 const cairo_rectangle_int_t *rectangle)
828 {
829     pixman_box32_t pbox;
830     pixman_region_overlap_t poverlap;
831 
832     if (region->status)
833 	return CAIRO_REGION_OVERLAP_OUT;
834 
835     pbox.x1 = rectangle->x;
836     pbox.y1 = rectangle->y;
837     pbox.x2 = rectangle->x + rectangle->width;
838     pbox.y2 = rectangle->y + rectangle->height;
839 
840     poverlap = pixman_region32_contains_rectangle (CONST_CAST &region->rgn,
841 						   &pbox);
842     switch (poverlap) {
843     default:
844     case PIXMAN_REGION_OUT:  return CAIRO_REGION_OVERLAP_OUT;
845     case PIXMAN_REGION_IN:   return CAIRO_REGION_OVERLAP_IN;
846     case PIXMAN_REGION_PART: return CAIRO_REGION_OVERLAP_PART;
847     }
848 }
849 slim_hidden_def (cairo_region_contains_rectangle);
850 
851 /**
852  * cairo_region_contains_point:
853  * @region: a #cairo_region_t
854  * @x: the x coordinate of a point
855  * @y: the y coordinate of a point
856  *
857  * Checks whether (@x, @y) is contained in @region.
858  *
859  * Return value: %TRUE if (@x, @y) is contained in @region, %FALSE if it is not.
860  *
861  * Since: 1.10
862  **/
863 cairo_bool_t
cairo_region_contains_point(const cairo_region_t * region,int x,int y)864 cairo_region_contains_point (const cairo_region_t *region,
865 			     int x, int y)
866 {
867     pixman_box32_t box;
868 
869     if (region->status)
870 	return FALSE;
871 
872     return pixman_region32_contains_point (CONST_CAST &region->rgn, x, y, &box);
873 }
874 slim_hidden_def (cairo_region_contains_point);
875 
876 /**
877  * cairo_region_equal:
878  * @a: a #cairo_region_t or %NULL
879  * @b: a #cairo_region_t or %NULL
880  *
881  * Compares whether region_a is equivalent to region_b. %NULL as an argument
882  * is equal to itself, but not to any non-%NULL region.
883  *
884  * Return value: %TRUE if both regions contained the same coverage,
885  * %FALSE if it is not or any region is in an error status.
886  *
887  * Since: 1.10
888  **/
889 cairo_bool_t
cairo_region_equal(const cairo_region_t * a,const cairo_region_t * b)890 cairo_region_equal (const cairo_region_t *a,
891 		    const cairo_region_t *b)
892 {
893     /* error objects are never equal */
894     if ((a != NULL && a->status) || (b != NULL && b->status))
895 	return FALSE;
896 
897     if (a == b)
898 	return TRUE;
899 
900     if (a == NULL || b == NULL)
901 	return FALSE;
902 
903     return pixman_region32_equal (CONST_CAST &a->rgn, CONST_CAST &b->rgn);
904 }
905 slim_hidden_def (cairo_region_equal);
906