beta-0.89.2
[luatex.git] / source / libs / cairo / cairo-src / src / cairo-region.c
blobccfb2200e14f6007db9cf07b363f58288aebe736
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
4 * Copyright © 2005 Red Hat, Inc.
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.
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
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/
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.
29 * The Original Code is the cairo graphics library.
31 * The Initial Developer of the Original Code is Red Hat, Inc.
33 * Contributor(s):
34 * Owen Taylor <otaylor@redhat.com>
35 * Vladimir Vukicevic <vladimir@pobox.com>
36 * Søren Sandmann <sandmann@daimi.au.dk>
39 #include "cairoint.h"
41 #include "cairo-error-private.h"
42 #include "cairo-region-private.h"
44 /* XXX need to update pixman headers to be const as appropriate */
45 #define CONST_CAST (pixman_region32_t *)
47 /**
48 * SECTION:cairo-region
49 * @Title: Regions
50 * @Short_Description: Representing a pixel-aligned area
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 **/
57 static const cairo_region_t _cairo_region_nil = {
58 CAIRO_REFERENCE_COUNT_INVALID, /* ref_count */
59 CAIRO_STATUS_NO_MEMORY, /* status */
62 cairo_region_t *
63 _cairo_region_create_in_error (cairo_status_t status)
65 switch (status) {
66 case CAIRO_STATUS_NO_MEMORY:
67 return (cairo_region_t *) &_cairo_region_nil;
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 case CAIRO_STATUS_INVALID_MESH_CONSTRUCTION:
108 case CAIRO_STATUS_DEVICE_FINISHED:
109 case CAIRO_STATUS_JBIG2_GLOBAL_MISSING:
110 default:
111 _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
112 return (cairo_region_t *) &_cairo_region_nil;
117 * _cairo_region_set_error:
118 * @region: a region
119 * @status: a status value indicating an error
121 * Atomically sets region->status to @status and calls _cairo_error;
122 * Does nothing if status is %CAIRO_STATUS_SUCCESS or any of the internal
123 * status values.
125 * All assignments of an error status to region->status should happen
126 * through _cairo_region_set_error(). Note that due to the nature of
127 * the atomic operation, it is not safe to call this function on the
128 * nil objects.
130 * The purpose of this function is to allow the user to set a
131 * breakpoint in _cairo_error() to generate a stack trace for when the
132 * user causes cairo to detect an error.
134 * Return value: the error status.
136 static cairo_status_t
137 _cairo_region_set_error (cairo_region_t *region,
138 cairo_status_t status)
140 if (status == CAIRO_STATUS_SUCCESS)
141 return CAIRO_STATUS_SUCCESS;
143 /* Don't overwrite an existing error. This preserves the first
144 * error, which is the most significant. */
145 _cairo_status_set_error (&region->status, status);
147 return _cairo_error (status);
150 void
151 _cairo_region_init (cairo_region_t *region)
153 VG (VALGRIND_MAKE_MEM_UNDEFINED (region, sizeof (cairo_region_t)));
155 region->status = CAIRO_STATUS_SUCCESS;
156 CAIRO_REFERENCE_COUNT_INIT (&region->ref_count, 0);
157 pixman_region32_init (&region->rgn);
160 void
161 _cairo_region_init_rectangle (cairo_region_t *region,
162 const cairo_rectangle_int_t *rectangle)
164 VG (VALGRIND_MAKE_MEM_UNDEFINED (region, sizeof (cairo_region_t)));
166 region->status = CAIRO_STATUS_SUCCESS;
167 CAIRO_REFERENCE_COUNT_INIT (&region->ref_count, 0);
168 pixman_region32_init_rect (&region->rgn,
169 rectangle->x, rectangle->y,
170 rectangle->width, rectangle->height);
173 void
174 _cairo_region_fini (cairo_region_t *region)
176 assert (! CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&region->ref_count));
177 pixman_region32_fini (&region->rgn);
178 VG (VALGRIND_MAKE_MEM_NOACCESS (region, sizeof (cairo_region_t)));
182 * cairo_region_create:
184 * Allocates a new empty region object.
186 * Return value: A newly allocated #cairo_region_t. Free with
187 * cairo_region_destroy(). This function always returns a
188 * valid pointer; if memory cannot be allocated, then a special
189 * error object is returned where all operations on the object do nothing.
190 * You can check for this with cairo_region_status().
192 * Since: 1.10
194 cairo_region_t *
195 cairo_region_create (void)
197 cairo_region_t *region;
199 region = _cairo_malloc (sizeof (cairo_region_t));
200 if (region == NULL)
201 return (cairo_region_t *) &_cairo_region_nil;
203 region->status = CAIRO_STATUS_SUCCESS;
204 CAIRO_REFERENCE_COUNT_INIT (&region->ref_count, 1);
206 pixman_region32_init (&region->rgn);
208 return region;
210 slim_hidden_def (cairo_region_create);
213 * cairo_region_create_rectangles:
214 * @rects: an array of @count rectangles
215 * @count: number of rectangles
217 * Allocates a new region object containing the union of all given @rects.
219 * Return value: A newly allocated #cairo_region_t. Free with
220 * cairo_region_destroy(). This function always returns a
221 * valid pointer; if memory cannot be allocated, then a special
222 * error object is returned where all operations on the object do nothing.
223 * You can check for this with cairo_region_status().
225 * Since: 1.10
227 cairo_region_t *
228 cairo_region_create_rectangles (const cairo_rectangle_int_t *rects,
229 int count)
231 pixman_box32_t stack_pboxes[CAIRO_STACK_ARRAY_LENGTH (pixman_box32_t)];
232 pixman_box32_t *pboxes = stack_pboxes;
233 cairo_region_t *region;
234 int i;
236 region = _cairo_malloc (sizeof (cairo_region_t));
237 if (unlikely (region == NULL))
238 return _cairo_region_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
240 CAIRO_REFERENCE_COUNT_INIT (&region->ref_count, 1);
241 region->status = CAIRO_STATUS_SUCCESS;
243 if (count == 1) {
244 pixman_region32_init_rect (&region->rgn,
245 rects->x, rects->y,
246 rects->width, rects->height);
248 return region;
251 if (count > ARRAY_LENGTH (stack_pboxes)) {
252 pboxes = _cairo_malloc_ab (count, sizeof (pixman_box32_t));
253 if (unlikely (pboxes == NULL)) {
254 free (region);
255 return _cairo_region_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
259 for (i = 0; i < count; i++) {
260 pboxes[i].x1 = rects[i].x;
261 pboxes[i].y1 = rects[i].y;
262 pboxes[i].x2 = rects[i].x + rects[i].width;
263 pboxes[i].y2 = rects[i].y + rects[i].height;
266 i = pixman_region32_init_rects (&region->rgn, pboxes, count);
268 if (pboxes != stack_pboxes)
269 free (pboxes);
271 if (unlikely (i == 0)) {
272 free (region);
273 return _cairo_region_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
276 return region;
278 slim_hidden_def (cairo_region_create_rectangles);
280 cairo_region_t *
281 _cairo_region_create_from_boxes (const cairo_box_t *boxes, int count)
283 cairo_region_t *region;
285 region = _cairo_malloc (sizeof (cairo_region_t));
286 if (unlikely (region == NULL))
287 return _cairo_region_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
289 CAIRO_REFERENCE_COUNT_INIT (&region->ref_count, 1);
290 region->status = CAIRO_STATUS_SUCCESS;
292 if (! pixman_region32_init_rects (&region->rgn,
293 (pixman_box32_t *)boxes, count)) {
294 free (region);
295 return _cairo_region_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
298 return region;
301 cairo_box_t *
302 _cairo_region_get_boxes (const cairo_region_t *region, int *nbox)
304 if (region->status) {
305 nbox = 0;
306 return NULL;
309 return (cairo_box_t *) pixman_region32_rectangles (CONST_CAST &region->rgn, nbox);
313 * cairo_region_create_rectangle:
314 * @rectangle: a #cairo_rectangle_int_t
316 * Allocates a new region object containing @rectangle.
318 * Return value: A newly allocated #cairo_region_t. Free with
319 * cairo_region_destroy(). This function always returns a
320 * valid pointer; if memory cannot be allocated, then a special
321 * error object is returned where all operations on the object do nothing.
322 * You can check for this with cairo_region_status().
324 * Since: 1.10
326 cairo_region_t *
327 cairo_region_create_rectangle (const cairo_rectangle_int_t *rectangle)
329 cairo_region_t *region;
331 region = _cairo_malloc (sizeof (cairo_region_t));
332 if (unlikely (region == NULL))
333 return (cairo_region_t *) &_cairo_region_nil;
335 region->status = CAIRO_STATUS_SUCCESS;
336 CAIRO_REFERENCE_COUNT_INIT (&region->ref_count, 1);
338 pixman_region32_init_rect (&region->rgn,
339 rectangle->x, rectangle->y,
340 rectangle->width, rectangle->height);
342 return region;
344 slim_hidden_def (cairo_region_create_rectangle);
347 * cairo_region_copy:
348 * @original: a #cairo_region_t
350 * Allocates a new region object copying the area from @original.
352 * Return value: A newly allocated #cairo_region_t. Free with
353 * cairo_region_destroy(). This function always returns a
354 * valid pointer; if memory cannot be allocated, then a special
355 * error object is returned where all operations on the object do nothing.
356 * You can check for this with cairo_region_status().
358 * Since: 1.10
360 cairo_region_t *
361 cairo_region_copy (const cairo_region_t *original)
363 cairo_region_t *copy;
365 if (original != NULL && original->status)
366 return (cairo_region_t *) &_cairo_region_nil;
368 copy = cairo_region_create ();
369 if (unlikely (copy->status))
370 return copy;
372 if (original != NULL &&
373 ! pixman_region32_copy (&copy->rgn, CONST_CAST &original->rgn))
375 cairo_region_destroy (copy);
376 return (cairo_region_t *) &_cairo_region_nil;
379 return copy;
381 slim_hidden_def (cairo_region_copy);
384 * cairo_region_reference:
385 * @region: a #cairo_region_t
387 * Increases the reference count on @region by one. This prevents
388 * @region from being destroyed until a matching call to
389 * cairo_region_destroy() is made.
391 * Return value: the referenced #cairo_region_t.
393 * Since: 1.10
395 cairo_region_t *
396 cairo_region_reference (cairo_region_t *region)
398 if (region == NULL || CAIRO_REFERENCE_COUNT_IS_INVALID (&region->ref_count))
399 return NULL;
401 assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&region->ref_count));
403 _cairo_reference_count_inc (&region->ref_count);
404 return region;
406 slim_hidden_def (cairo_region_reference);
409 * cairo_region_destroy:
410 * @region: a #cairo_region_t
412 * Destroys a #cairo_region_t object created with
413 * cairo_region_create(), cairo_region_copy(), or
414 * or cairo_region_create_rectangle().
416 * Since: 1.10
418 void
419 cairo_region_destroy (cairo_region_t *region)
421 if (region == NULL || CAIRO_REFERENCE_COUNT_IS_INVALID (&region->ref_count))
422 return;
424 assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&region->ref_count));
426 if (! _cairo_reference_count_dec_and_test (&region->ref_count))
427 return;
429 _cairo_region_fini (region);
430 free (region);
432 slim_hidden_def (cairo_region_destroy);
435 * cairo_region_num_rectangles:
436 * @region: a #cairo_region_t
438 * Returns the number of rectangles contained in @region.
440 * Return value: The number of rectangles contained in @region.
442 * Since: 1.10
445 cairo_region_num_rectangles (const cairo_region_t *region)
447 if (region->status)
448 return 0;
450 return pixman_region32_n_rects (CONST_CAST &region->rgn);
452 slim_hidden_def (cairo_region_num_rectangles);
455 * cairo_region_get_rectangle:
456 * @region: a #cairo_region_t
457 * @nth: a number indicating which rectangle should be returned
458 * @rectangle: return location for a #cairo_rectangle_int_t
460 * Stores the @nth rectangle from the region in @rectangle.
462 * Since: 1.10
464 void
465 cairo_region_get_rectangle (const cairo_region_t *region,
466 int nth,
467 cairo_rectangle_int_t *rectangle)
469 pixman_box32_t *pbox;
471 if (region->status) {
472 rectangle->x = rectangle->y = 0;
473 rectangle->width = rectangle->height = 0;
474 return;
477 pbox = pixman_region32_rectangles (CONST_CAST &region->rgn, NULL) + nth;
479 rectangle->x = pbox->x1;
480 rectangle->y = pbox->y1;
481 rectangle->width = pbox->x2 - pbox->x1;
482 rectangle->height = pbox->y2 - pbox->y1;
484 slim_hidden_def (cairo_region_get_rectangle);
487 * cairo_region_get_extents:
488 * @region: a #cairo_region_t
489 * @extents: rectangle into which to store the extents
491 * Gets the bounding rectangle of @region as a #cairo_rectangle_int_t
493 * Since: 1.10
495 void
496 cairo_region_get_extents (const cairo_region_t *region,
497 cairo_rectangle_int_t *extents)
499 pixman_box32_t *pextents;
501 if (region->status) {
502 extents->x = extents->y = 0;
503 extents->width = extents->height = 0;
504 return;
507 pextents = pixman_region32_extents (CONST_CAST &region->rgn);
509 extents->x = pextents->x1;
510 extents->y = pextents->y1;
511 extents->width = pextents->x2 - pextents->x1;
512 extents->height = pextents->y2 - pextents->y1;
514 slim_hidden_def (cairo_region_get_extents);
517 * cairo_region_status:
518 * @region: a #cairo_region_t
520 * Checks whether an error has previous occurred for this
521 * region object.
523 * Return value: %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY
525 * Since: 1.10
527 cairo_status_t
528 cairo_region_status (const cairo_region_t *region)
530 return region->status;
532 slim_hidden_def (cairo_region_status);
535 * cairo_region_subtract:
536 * @dst: a #cairo_region_t
537 * @other: another #cairo_region_t
539 * Subtracts @other from @dst and places the result in @dst
541 * Return value: %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY
543 * Since: 1.10
545 cairo_status_t
546 cairo_region_subtract (cairo_region_t *dst, const cairo_region_t *other)
548 if (dst->status)
549 return dst->status;
551 if (other->status)
552 return _cairo_region_set_error (dst, other->status);
554 if (! pixman_region32_subtract (&dst->rgn,
555 &dst->rgn,
556 CONST_CAST &other->rgn))
558 return _cairo_region_set_error (dst, CAIRO_STATUS_NO_MEMORY);
561 return CAIRO_STATUS_SUCCESS;
563 slim_hidden_def (cairo_region_subtract);
566 * cairo_region_subtract_rectangle:
567 * @dst: a #cairo_region_t
568 * @rectangle: a #cairo_rectangle_int_t
570 * Subtracts @rectangle from @dst and places the result in @dst
572 * Return value: %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY
574 * Since: 1.10
576 cairo_status_t
577 cairo_region_subtract_rectangle (cairo_region_t *dst,
578 const cairo_rectangle_int_t *rectangle)
580 cairo_status_t status = CAIRO_STATUS_SUCCESS;
581 pixman_region32_t region;
583 if (dst->status)
584 return dst->status;
586 pixman_region32_init_rect (&region,
587 rectangle->x, rectangle->y,
588 rectangle->width, rectangle->height);
590 if (! pixman_region32_subtract (&dst->rgn, &dst->rgn, &region))
591 status = _cairo_region_set_error (dst, CAIRO_STATUS_NO_MEMORY);
593 pixman_region32_fini (&region);
595 return status;
597 slim_hidden_def (cairo_region_subtract_rectangle);
600 * cairo_region_intersect:
601 * @dst: a #cairo_region_t
602 * @other: another #cairo_region_t
604 * Computes the intersection of @dst with @other and places the result in @dst
606 * Return value: %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY
608 * Since: 1.10
610 cairo_status_t
611 cairo_region_intersect (cairo_region_t *dst, const cairo_region_t *other)
613 if (dst->status)
614 return dst->status;
616 if (other->status)
617 return _cairo_region_set_error (dst, other->status);
619 if (! pixman_region32_intersect (&dst->rgn, &dst->rgn, CONST_CAST &other->rgn))
620 return _cairo_region_set_error (dst, CAIRO_STATUS_NO_MEMORY);
622 return CAIRO_STATUS_SUCCESS;
624 slim_hidden_def (cairo_region_intersect);
627 * cairo_region_intersect_rectangle:
628 * @dst: a #cairo_region_t
629 * @rectangle: a #cairo_rectangle_int_t
631 * Computes the intersection of @dst with @rectangle and places the
632 * result in @dst
634 * Return value: %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY
636 * Since: 1.10
638 cairo_status_t
639 cairo_region_intersect_rectangle (cairo_region_t *dst,
640 const cairo_rectangle_int_t *rectangle)
642 cairo_status_t status = CAIRO_STATUS_SUCCESS;
643 pixman_region32_t region;
645 if (dst->status)
646 return dst->status;
648 pixman_region32_init_rect (&region,
649 rectangle->x, rectangle->y,
650 rectangle->width, rectangle->height);
652 if (! pixman_region32_intersect (&dst->rgn, &dst->rgn, &region))
653 status = _cairo_region_set_error (dst, CAIRO_STATUS_NO_MEMORY);
655 pixman_region32_fini (&region);
657 return status;
659 slim_hidden_def (cairo_region_intersect_rectangle);
662 * cairo_region_union:
663 * @dst: a #cairo_region_t
664 * @other: another #cairo_region_t
666 * Computes the union of @dst with @other and places the result in @dst
668 * Return value: %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY
670 * Since: 1.10
672 cairo_status_t
673 cairo_region_union (cairo_region_t *dst,
674 const cairo_region_t *other)
676 if (dst->status)
677 return dst->status;
679 if (other->status)
680 return _cairo_region_set_error (dst, other->status);
682 if (! pixman_region32_union (&dst->rgn, &dst->rgn, CONST_CAST &other->rgn))
683 return _cairo_region_set_error (dst, CAIRO_STATUS_NO_MEMORY);
685 return CAIRO_STATUS_SUCCESS;
687 slim_hidden_def (cairo_region_union);
690 * cairo_region_union_rectangle:
691 * @dst: a #cairo_region_t
692 * @rectangle: a #cairo_rectangle_int_t
694 * Computes the union of @dst with @rectangle and places the result in @dst.
696 * Return value: %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY
698 * Since: 1.10
700 cairo_status_t
701 cairo_region_union_rectangle (cairo_region_t *dst,
702 const cairo_rectangle_int_t *rectangle)
704 cairo_status_t status = CAIRO_STATUS_SUCCESS;
705 pixman_region32_t region;
707 if (dst->status)
708 return dst->status;
710 pixman_region32_init_rect (&region,
711 rectangle->x, rectangle->y,
712 rectangle->width, rectangle->height);
714 if (! pixman_region32_union (&dst->rgn, &dst->rgn, &region))
715 status = _cairo_region_set_error (dst, CAIRO_STATUS_NO_MEMORY);
717 pixman_region32_fini (&region);
719 return status;
721 slim_hidden_def (cairo_region_union_rectangle);
724 * cairo_region_xor:
725 * @dst: a #cairo_region_t
726 * @other: another #cairo_region_t
728 * Computes the exclusive difference of @dst with @other and places the
729 * result in @dst. That is, @dst will be set to contain all areas that
730 * are either in @dst or in @other, but not in both.
732 * Return value: %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY
734 * Since: 1.10
736 cairo_status_t
737 cairo_region_xor (cairo_region_t *dst, const cairo_region_t *other)
739 cairo_status_t status = CAIRO_STATUS_SUCCESS;
740 pixman_region32_t tmp;
742 if (dst->status)
743 return dst->status;
745 if (other->status)
746 return _cairo_region_set_error (dst, other->status);
748 pixman_region32_init (&tmp);
750 /* XXX: get an xor function into pixman */
751 if (! pixman_region32_subtract (&tmp, CONST_CAST &other->rgn, &dst->rgn) ||
752 ! pixman_region32_subtract (&dst->rgn, &dst->rgn, CONST_CAST &other->rgn) ||
753 ! pixman_region32_union (&dst->rgn, &dst->rgn, &tmp))
754 status = _cairo_region_set_error (dst, CAIRO_STATUS_NO_MEMORY);
756 pixman_region32_fini (&tmp);
758 return status;
760 slim_hidden_def (cairo_region_xor);
763 * cairo_region_xor_rectangle:
764 * @dst: a #cairo_region_t
765 * @rectangle: a #cairo_rectangle_int_t
767 * Computes the exclusive difference of @dst with @rectangle and places the
768 * result in @dst. That is, @dst will be set to contain all areas that are
769 * either in @dst or in @rectangle, but not in both.
771 * Return value: %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY
773 * Since: 1.10
775 cairo_status_t
776 cairo_region_xor_rectangle (cairo_region_t *dst,
777 const cairo_rectangle_int_t *rectangle)
779 cairo_status_t status = CAIRO_STATUS_SUCCESS;
780 pixman_region32_t region, tmp;
782 if (dst->status)
783 return dst->status;
785 pixman_region32_init_rect (&region,
786 rectangle->x, rectangle->y,
787 rectangle->width, rectangle->height);
788 pixman_region32_init (&tmp);
790 /* XXX: get an xor function into pixman */
791 if (! pixman_region32_subtract (&tmp, &region, &dst->rgn) ||
792 ! pixman_region32_subtract (&dst->rgn, &dst->rgn, &region) ||
793 ! pixman_region32_union (&dst->rgn, &dst->rgn, &tmp))
794 status = _cairo_region_set_error (dst, CAIRO_STATUS_NO_MEMORY);
796 pixman_region32_fini (&tmp);
797 pixman_region32_fini (&region);
799 return status;
801 slim_hidden_def (cairo_region_xor_rectangle);
804 * cairo_region_is_empty:
805 * @region: a #cairo_region_t
807 * Checks whether @region is empty.
809 * Return value: %TRUE if @region is empty, %FALSE if it isn't.
811 * Since: 1.10
813 cairo_bool_t
814 cairo_region_is_empty (const cairo_region_t *region)
816 if (region->status)
817 return TRUE;
819 return ! pixman_region32_not_empty (CONST_CAST &region->rgn);
821 slim_hidden_def (cairo_region_is_empty);
824 * cairo_region_translate:
825 * @region: a #cairo_region_t
826 * @dx: Amount to translate in the x direction
827 * @dy: Amount to translate in the y direction
829 * Translates @region by (@dx, @dy).
831 * Since: 1.10
833 void
834 cairo_region_translate (cairo_region_t *region,
835 int dx, int dy)
837 if (region->status)
838 return;
840 pixman_region32_translate (&region->rgn, dx, dy);
842 slim_hidden_def (cairo_region_translate);
845 * cairo_region_contains_rectangle:
846 * @region: a #cairo_region_t
847 * @rectangle: a #cairo_rectangle_int_t
849 * Checks whether @rectangle is inside, outside or partially contained
850 * in @region
852 * Return value:
853 * %CAIRO_REGION_OVERLAP_IN if @rectangle is entirely inside @region,
854 * %CAIRO_REGION_OVERLAP_OUT if @rectangle is entirely outside @region, or
855 * %CAIRO_REGION_OVERLAP_PART if @rectangle is partially inside and partially outside @region.
857 * Since: 1.10
859 cairo_region_overlap_t
860 cairo_region_contains_rectangle (const cairo_region_t *region,
861 const cairo_rectangle_int_t *rectangle)
863 pixman_box32_t pbox;
864 pixman_region_overlap_t poverlap;
866 if (region->status)
867 return CAIRO_REGION_OVERLAP_OUT;
869 pbox.x1 = rectangle->x;
870 pbox.y1 = rectangle->y;
871 pbox.x2 = rectangle->x + rectangle->width;
872 pbox.y2 = rectangle->y + rectangle->height;
874 poverlap = pixman_region32_contains_rectangle (CONST_CAST &region->rgn,
875 &pbox);
876 switch (poverlap) {
877 default:
878 case PIXMAN_REGION_OUT: return CAIRO_REGION_OVERLAP_OUT;
879 case PIXMAN_REGION_IN: return CAIRO_REGION_OVERLAP_IN;
880 case PIXMAN_REGION_PART: return CAIRO_REGION_OVERLAP_PART;
883 slim_hidden_def (cairo_region_contains_rectangle);
886 * cairo_region_contains_point:
887 * @region: a #cairo_region_t
888 * @x: the x coordinate of a point
889 * @y: the y coordinate of a point
891 * Checks whether (@x, @y) is contained in @region.
893 * Return value: %TRUE if (@x, @y) is contained in @region, %FALSE if it is not.
895 * Since: 1.10
897 cairo_bool_t
898 cairo_region_contains_point (const cairo_region_t *region,
899 int x, int y)
901 pixman_box32_t box;
903 if (region->status)
904 return FALSE;
906 return pixman_region32_contains_point (CONST_CAST &region->rgn, x, y, &box);
908 slim_hidden_def (cairo_region_contains_point);
911 * cairo_region_equal:
912 * @a: a #cairo_region_t or %NULL
913 * @b: a #cairo_region_t or %NULL
915 * Compares whether region_a is equivalent to region_b. %NULL as an argument
916 * is equal to itself, but not to any non-%NULL region.
918 * Return value: %TRUE if both regions contained the same coverage,
919 * %FALSE if it is not or any region is in an error status.
921 * Since: 1.10
923 cairo_bool_t
924 cairo_region_equal (const cairo_region_t *a,
925 const cairo_region_t *b)
927 /* error objects are never equal */
928 if ((a != NULL && a->status) || (b != NULL && b->status))
929 return FALSE;
931 if (a == b)
932 return TRUE;
934 if (a == NULL || b == NULL)
935 return FALSE;
937 return pixman_region32_equal (CONST_CAST &a->rgn, CONST_CAST &b->rgn);
939 slim_hidden_def (cairo_region_equal);