Tizen 2.0 Release
[framework/graphics/cairo.git] / src / cairo-region.c
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 *
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     case CAIRO_STATUS_INVALID_MESH_CONSTRUCTION:
108     case CAIRO_STATUS_DEVICE_FINISHED:
109     default:
110         _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
111         return (cairo_region_t *) &_cairo_region_nil;
112     }
113 }
114
115 /**
116  * _cairo_region_set_error:
117  * @region: a region
118  * @status: a status value indicating an error
119  *
120  * Atomically sets region->status to @status and calls _cairo_error;
121  * Does nothing if status is %CAIRO_STATUS_SUCCESS or any of the internal
122  * status values.
123  *
124  * All assignments of an error status to region->status should happen
125  * through _cairo_region_set_error(). Note that due to the nature of
126  * the atomic operation, it is not safe to call this function on the
127  * nil objects.
128  *
129  * The purpose of this function is to allow the user to set a
130  * breakpoint in _cairo_error() to generate a stack trace for when the
131  * user causes cairo to detect an error.
132  *
133  * Return value: the error status.
134  **/
135 static cairo_status_t
136 _cairo_region_set_error (cairo_region_t *region,
137                          cairo_status_t status)
138 {
139     if (status == CAIRO_STATUS_SUCCESS)
140         return CAIRO_STATUS_SUCCESS;
141
142     /* Don't overwrite an existing error. This preserves the first
143      * error, which is the most significant. */
144     _cairo_status_set_error (&region->status, status);
145
146     return _cairo_error (status);
147 }
148
149 void
150 _cairo_region_init (cairo_region_t *region)
151 {
152     VG (VALGRIND_MAKE_MEM_UNDEFINED (region, sizeof (cairo_region_t)));
153
154     region->status = CAIRO_STATUS_SUCCESS;
155     CAIRO_REFERENCE_COUNT_INIT (&region->ref_count, 0);
156     pixman_region32_init (&region->rgn);
157 }
158
159 void
160 _cairo_region_init_rectangle (cairo_region_t *region,
161                               const cairo_rectangle_int_t *rectangle)
162 {
163     VG (VALGRIND_MAKE_MEM_UNDEFINED (region, sizeof (cairo_region_t)));
164
165     region->status = CAIRO_STATUS_SUCCESS;
166     CAIRO_REFERENCE_COUNT_INIT (&region->ref_count, 0);
167     pixman_region32_init_rect (&region->rgn,
168                                rectangle->x, rectangle->y,
169                                rectangle->width, rectangle->height);
170 }
171
172 void
173 _cairo_region_fini (cairo_region_t *region)
174 {
175     assert (! CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&region->ref_count));
176     pixman_region32_fini (&region->rgn);
177     VG (VALGRIND_MAKE_MEM_NOACCESS (region, sizeof (cairo_region_t)));
178 }
179
180 /**
181  * cairo_region_create:
182  *
183  * Allocates a new empty region object.
184  *
185  * Return value: A newly allocated #cairo_region_t. Free with
186  *   cairo_region_destroy(). This function always returns a
187  *   valid pointer; if memory cannot be allocated, then a special
188  *   error object is returned where all operations on the object do nothing.
189  *   You can check for this with cairo_region_status().
190  *
191  * Since: 1.10
192  **/
193 cairo_region_t *
194 cairo_region_create (void)
195 {
196     cairo_region_t *region;
197
198     region = _cairo_malloc (sizeof (cairo_region_t));
199     if (region == NULL)
200         return (cairo_region_t *) &_cairo_region_nil;
201
202     region->status = CAIRO_STATUS_SUCCESS;
203     CAIRO_REFERENCE_COUNT_INIT (&region->ref_count, 1);
204
205     pixman_region32_init (&region->rgn);
206
207     return region;
208 }
209 slim_hidden_def (cairo_region_create);
210
211 /**
212  * cairo_region_create_rectangles:
213  * @rects: an array of @count rectangles
214  * @count: number of rectangles
215  *
216  * Allocates a new region object containing the union of all given @rects.
217  *
218  * Return value: A newly allocated #cairo_region_t. Free with
219  *   cairo_region_destroy(). This function always returns a
220  *   valid pointer; if memory cannot be allocated, then a special
221  *   error object is returned where all operations on the object do nothing.
222  *   You can check for this with cairo_region_status().
223  *
224  * Since: 1.10
225  **/
226 cairo_region_t *
227 cairo_region_create_rectangles (const cairo_rectangle_int_t *rects,
228                                 int count)
229 {
230     pixman_box32_t stack_pboxes[CAIRO_STACK_ARRAY_LENGTH (pixman_box32_t)];
231     pixman_box32_t *pboxes = stack_pboxes;
232     cairo_region_t *region;
233     int i;
234
235     region = _cairo_malloc (sizeof (cairo_region_t));
236     if (unlikely (region == NULL))
237         return _cairo_region_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
238
239     CAIRO_REFERENCE_COUNT_INIT (&region->ref_count, 1);
240     region->status = CAIRO_STATUS_SUCCESS;
241
242     if (count == 1) {
243         pixman_region32_init_rect (&region->rgn,
244                                    rects->x, rects->y,
245                                    rects->width, rects->height);
246
247         return region;
248     }
249
250     if (count > ARRAY_LENGTH (stack_pboxes)) {
251         pboxes = _cairo_malloc_ab (count, sizeof (pixman_box32_t));
252         if (unlikely (pboxes == NULL)) {
253             free (region);
254             return _cairo_region_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
255         }
256     }
257
258     for (i = 0; i < count; i++) {
259         pboxes[i].x1 = rects[i].x;
260         pboxes[i].y1 = rects[i].y;
261         pboxes[i].x2 = rects[i].x + rects[i].width;
262         pboxes[i].y2 = rects[i].y + rects[i].height;
263     }
264
265     i = pixman_region32_init_rects (&region->rgn, pboxes, count);
266
267     if (pboxes != stack_pboxes)
268         free (pboxes);
269
270     if (unlikely (i == 0)) {
271         free (region);
272         return _cairo_region_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
273     }
274
275     return region;
276 }
277 slim_hidden_def (cairo_region_create_rectangles);
278
279 cairo_region_t *
280 _cairo_region_create_from_boxes (const cairo_box_t *boxes, int count)
281 {
282     cairo_region_t *region;
283
284     region = _cairo_malloc (sizeof (cairo_region_t));
285     if (unlikely (region == NULL))
286         return _cairo_region_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
287
288     CAIRO_REFERENCE_COUNT_INIT (&region->ref_count, 1);
289     region->status = CAIRO_STATUS_SUCCESS;
290
291     if (! pixman_region32_init_rects (&region->rgn,
292                                       (pixman_box32_t *)boxes, count)) {
293         free (region);
294         return _cairo_region_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
295     }
296
297     return region;
298 }
299
300 cairo_box_t *
301 _cairo_region_get_boxes (const cairo_region_t *region, int *nbox)
302 {
303     if (region->status) {
304         nbox = 0;
305         return NULL;
306     }
307
308     return (cairo_box_t *) pixman_region32_rectangles (CONST_CAST &region->rgn, nbox);
309 }
310
311 /**
312  * cairo_region_create_rectangle:
313  * @rectangle: a #cairo_rectangle_int_t
314  *
315  * Allocates a new region object containing @rectangle.
316  *
317  * Return value: A newly allocated #cairo_region_t. Free with
318  *   cairo_region_destroy(). This function always returns a
319  *   valid pointer; if memory cannot be allocated, then a special
320  *   error object is returned where all operations on the object do nothing.
321  *   You can check for this with cairo_region_status().
322  *
323  * Since: 1.10
324  **/
325 cairo_region_t *
326 cairo_region_create_rectangle (const cairo_rectangle_int_t *rectangle)
327 {
328     cairo_region_t *region;
329
330     region = _cairo_malloc (sizeof (cairo_region_t));
331     if (unlikely (region == NULL))
332         return (cairo_region_t *) &_cairo_region_nil;
333
334     region->status = CAIRO_STATUS_SUCCESS;
335     CAIRO_REFERENCE_COUNT_INIT (&region->ref_count, 1);
336
337     pixman_region32_init_rect (&region->rgn,
338                                rectangle->x, rectangle->y,
339                                rectangle->width, rectangle->height);
340
341     return region;
342 }
343 slim_hidden_def (cairo_region_create_rectangle);
344
345 /**
346  * cairo_region_copy:
347  * @original: a #cairo_region_t
348  *
349  * Allocates a new region object copying the area from @original.
350  *
351  * Return value: A newly allocated #cairo_region_t. Free with
352  *   cairo_region_destroy(). This function always returns a
353  *   valid pointer; if memory cannot be allocated, then a special
354  *   error object is returned where all operations on the object do nothing.
355  *   You can check for this with cairo_region_status().
356  *
357  * Since: 1.10
358  **/
359 cairo_region_t *
360 cairo_region_copy (const cairo_region_t *original)
361 {
362     cairo_region_t *copy;
363
364     if (original != NULL && original->status)
365         return (cairo_region_t *) &_cairo_region_nil;
366
367     copy = cairo_region_create ();
368     if (unlikely (copy->status))
369         return copy;
370
371     if (original != NULL &&
372         ! pixman_region32_copy (&copy->rgn, CONST_CAST &original->rgn))
373     {
374         cairo_region_destroy (copy);
375         return (cairo_region_t *) &_cairo_region_nil;
376     }
377
378     return copy;
379 }
380 slim_hidden_def (cairo_region_copy);
381
382 /**
383  * cairo_region_reference:
384  * @region: a #cairo_region_t
385  *
386  * Increases the reference count on @region by one. This prevents
387  * @region from being destroyed until a matching call to
388  * cairo_region_destroy() is made.
389  *
390  * Return value: the referenced #cairo_region_t.
391  *
392  * Since: 1.10
393  **/
394 cairo_region_t *
395 cairo_region_reference (cairo_region_t *region)
396 {
397     if (region == NULL || CAIRO_REFERENCE_COUNT_IS_INVALID (&region->ref_count))
398         return NULL;
399
400     assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&region->ref_count));
401
402     _cairo_reference_count_inc (&region->ref_count);
403     return region;
404 }
405 slim_hidden_def (cairo_region_reference);
406
407 /**
408  * cairo_region_destroy:
409  * @region: a #cairo_region_t
410  *
411  * Destroys a #cairo_region_t object created with
412  * cairo_region_create(), cairo_region_copy(), or
413  * or cairo_region_create_rectangle().
414  *
415  * Since: 1.10
416  **/
417 void
418 cairo_region_destroy (cairo_region_t *region)
419 {
420     if (region == NULL || CAIRO_REFERENCE_COUNT_IS_INVALID (&region->ref_count))
421         return;
422
423     assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&region->ref_count));
424
425     if (! _cairo_reference_count_dec_and_test (&region->ref_count))
426         return;
427
428     _cairo_region_fini (region);
429     free (region);
430 }
431 slim_hidden_def (cairo_region_destroy);
432
433 /**
434  * cairo_region_num_rectangles:
435  * @region: a #cairo_region_t
436  *
437  * Returns the number of rectangles contained in @region.
438  *
439  * Return value: The number of rectangles contained in @region.
440  *
441  * Since: 1.10
442  **/
443 int
444 cairo_region_num_rectangles (const cairo_region_t *region)
445 {
446     if (region->status)
447         return 0;
448
449     return pixman_region32_n_rects (CONST_CAST &region->rgn);
450 }
451 slim_hidden_def (cairo_region_num_rectangles);
452
453 /**
454  * cairo_region_get_rectangle:
455  * @region: a #cairo_region_t
456  * @nth: a number indicating which rectangle should be returned
457  * @rectangle: return location for a #cairo_rectangle_int_t
458  *
459  * Stores the @nth rectangle from the region in @rectangle.
460  *
461  * Since: 1.10
462  **/
463 void
464 cairo_region_get_rectangle (const cairo_region_t *region,
465                             int nth,
466                             cairo_rectangle_int_t *rectangle)
467 {
468     pixman_box32_t *pbox;
469
470     if (region->status) {
471         rectangle->x = rectangle->y = 0;
472         rectangle->width = rectangle->height = 0;
473         return;
474     }
475
476     pbox = pixman_region32_rectangles (CONST_CAST &region->rgn, NULL) + nth;
477
478     rectangle->x = pbox->x1;
479     rectangle->y = pbox->y1;
480     rectangle->width = pbox->x2 - pbox->x1;
481     rectangle->height = pbox->y2 - pbox->y1;
482 }
483 slim_hidden_def (cairo_region_get_rectangle);
484
485 /**
486  * cairo_region_get_extents:
487  * @region: a #cairo_region_t
488  * @extents: rectangle into which to store the extents
489  *
490  * Gets the bounding rectangle of @region as a #cairo_rectangle_int_t
491  *
492  * Since: 1.10
493  **/
494 void
495 cairo_region_get_extents (const cairo_region_t *region,
496                           cairo_rectangle_int_t *extents)
497 {
498     pixman_box32_t *pextents;
499
500     if (region->status) {
501         extents->x = extents->y = 0;
502         extents->width = extents->height = 0;
503         return;
504     }
505
506     pextents = pixman_region32_extents (CONST_CAST &region->rgn);
507
508     extents->x = pextents->x1;
509     extents->y = pextents->y1;
510     extents->width = pextents->x2 - pextents->x1;
511     extents->height = pextents->y2 - pextents->y1;
512 }
513 slim_hidden_def (cairo_region_get_extents);
514
515 /**
516  * cairo_region_status:
517  * @region: a #cairo_region_t
518  *
519  * Checks whether an error has previous occurred for this
520  * region object.
521  *
522  * Return value: %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY
523  *
524  * Since: 1.10
525  **/
526 cairo_status_t
527 cairo_region_status (const cairo_region_t *region)
528 {
529     return region->status;
530 }
531 slim_hidden_def (cairo_region_status);
532
533 /**
534  * cairo_region_subtract:
535  * @dst: a #cairo_region_t
536  * @other: another #cairo_region_t
537  *
538  * Subtracts @other from @dst and places the result in @dst
539  *
540  * Return value: %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY
541  *
542  * Since: 1.10
543  **/
544 cairo_status_t
545 cairo_region_subtract (cairo_region_t *dst, const cairo_region_t *other)
546 {
547     if (dst->status)
548         return dst->status;
549
550     if (other->status)
551         return _cairo_region_set_error (dst, other->status);
552
553     if (! pixman_region32_subtract (&dst->rgn,
554                                     &dst->rgn,
555                                     CONST_CAST &other->rgn))
556     {
557         return _cairo_region_set_error (dst, CAIRO_STATUS_NO_MEMORY);
558     }
559
560     return CAIRO_STATUS_SUCCESS;
561 }
562 slim_hidden_def (cairo_region_subtract);
563
564 /**
565  * cairo_region_subtract_rectangle:
566  * @dst: a #cairo_region_t
567  * @rectangle: a #cairo_rectangle_int_t
568  *
569  * Subtracts @rectangle from @dst and places the result in @dst
570  *
571  * Return value: %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY
572  *
573  * Since: 1.10
574  **/
575 cairo_status_t
576 cairo_region_subtract_rectangle (cairo_region_t *dst,
577                                  const cairo_rectangle_int_t *rectangle)
578 {
579     cairo_status_t status = CAIRO_STATUS_SUCCESS;
580     pixman_region32_t region;
581
582     if (dst->status)
583         return dst->status;
584
585     pixman_region32_init_rect (&region,
586                                rectangle->x, rectangle->y,
587                                rectangle->width, rectangle->height);
588
589     if (! pixman_region32_subtract (&dst->rgn, &dst->rgn, &region))
590         status = _cairo_region_set_error (dst, CAIRO_STATUS_NO_MEMORY);
591
592     pixman_region32_fini (&region);
593
594     return status;
595 }
596 slim_hidden_def (cairo_region_subtract_rectangle);
597
598 /**
599  * cairo_region_intersect:
600  * @dst: a #cairo_region_t
601  * @other: another #cairo_region_t
602  *
603  * Computes the intersection of @dst with @other and places the result in @dst
604  *
605  * Return value: %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY
606  *
607  * Since: 1.10
608  **/
609 cairo_status_t
610 cairo_region_intersect (cairo_region_t *dst, const cairo_region_t *other)
611 {
612     if (dst->status)
613         return dst->status;
614
615     if (other->status)
616         return _cairo_region_set_error (dst, other->status);
617
618     if (! pixman_region32_intersect (&dst->rgn, &dst->rgn, CONST_CAST &other->rgn))
619         return _cairo_region_set_error (dst, CAIRO_STATUS_NO_MEMORY);
620
621     return CAIRO_STATUS_SUCCESS;
622 }
623 slim_hidden_def (cairo_region_intersect);
624
625 /**
626  * cairo_region_intersect_rectangle:
627  * @dst: a #cairo_region_t
628  * @rectangle: a #cairo_rectangle_int_t
629  *
630  * Computes the intersection of @dst with @rectangle and places the
631  * result in @dst
632  *
633  * Return value: %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY
634  *
635  * Since: 1.10
636  **/
637 cairo_status_t
638 cairo_region_intersect_rectangle (cairo_region_t *dst,
639                                   const cairo_rectangle_int_t *rectangle)
640 {
641     cairo_status_t status = CAIRO_STATUS_SUCCESS;
642     pixman_region32_t region;
643
644     if (dst->status)
645         return dst->status;
646
647     pixman_region32_init_rect (&region,
648                                rectangle->x, rectangle->y,
649                                rectangle->width, rectangle->height);
650
651     if (! pixman_region32_intersect (&dst->rgn, &dst->rgn, &region))
652         status = _cairo_region_set_error (dst, CAIRO_STATUS_NO_MEMORY);
653
654     pixman_region32_fini (&region);
655
656     return status;
657 }
658 slim_hidden_def (cairo_region_intersect_rectangle);
659
660 /**
661  * cairo_region_union:
662  * @dst: a #cairo_region_t
663  * @other: another #cairo_region_t
664  *
665  * Computes the union of @dst with @other and places the result in @dst
666  *
667  * Return value: %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY
668  *
669  * Since: 1.10
670  **/
671 cairo_status_t
672 cairo_region_union (cairo_region_t *dst,
673                     const cairo_region_t *other)
674 {
675     if (dst->status)
676         return dst->status;
677
678     if (other->status)
679         return _cairo_region_set_error (dst, other->status);
680
681     if (! pixman_region32_union (&dst->rgn, &dst->rgn, CONST_CAST &other->rgn))
682         return _cairo_region_set_error (dst, CAIRO_STATUS_NO_MEMORY);
683
684     return CAIRO_STATUS_SUCCESS;
685 }
686 slim_hidden_def (cairo_region_union);
687
688 /**
689  * cairo_region_union_rectangle:
690  * @dst: a #cairo_region_t
691  * @rectangle: a #cairo_rectangle_int_t
692  *
693  * Computes the union of @dst with @rectangle and places the result in @dst.
694  *
695  * Return value: %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY
696  *
697  * Since: 1.10
698  **/
699 cairo_status_t
700 cairo_region_union_rectangle (cairo_region_t *dst,
701                               const cairo_rectangle_int_t *rectangle)
702 {
703     cairo_status_t status = CAIRO_STATUS_SUCCESS;
704     pixman_region32_t region;
705
706     if (dst->status)
707         return dst->status;
708
709     pixman_region32_init_rect (&region,
710                                rectangle->x, rectangle->y,
711                                rectangle->width, rectangle->height);
712
713     if (! pixman_region32_union (&dst->rgn, &dst->rgn, &region))
714         status = _cairo_region_set_error (dst, CAIRO_STATUS_NO_MEMORY);
715
716     pixman_region32_fini (&region);
717
718     return status;
719 }
720 slim_hidden_def (cairo_region_union_rectangle);
721
722 /**
723  * cairo_region_xor:
724  * @dst: a #cairo_region_t
725  * @other: another #cairo_region_t
726  *
727  * Computes the exclusive difference of @dst with @other and places the
728  * result in @dst. That is, @dst will be set to contain all areas that
729  * are either in @dst or in @other, but not in both.
730  *
731  * Return value: %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY
732  *
733  * Since: 1.10
734  **/
735 cairo_status_t
736 cairo_region_xor (cairo_region_t *dst, const cairo_region_t *other)
737 {
738     cairo_status_t status = CAIRO_STATUS_SUCCESS;
739     pixman_region32_t tmp;
740
741     if (dst->status)
742         return dst->status;
743
744     if (other->status)
745         return _cairo_region_set_error (dst, other->status);
746
747     pixman_region32_init (&tmp);
748
749     /* XXX: get an xor function into pixman */
750     if (! pixman_region32_subtract (&tmp, CONST_CAST &other->rgn, &dst->rgn) ||
751         ! pixman_region32_subtract (&dst->rgn, &dst->rgn, CONST_CAST &other->rgn) || 
752         ! pixman_region32_union (&dst->rgn, &dst->rgn, &tmp))
753         status = _cairo_region_set_error (dst, CAIRO_STATUS_NO_MEMORY);
754
755     pixman_region32_fini (&tmp);
756
757     return status;
758 }
759 slim_hidden_def (cairo_region_xor);
760
761 /**
762  * cairo_region_xor_rectangle:
763  * @dst: a #cairo_region_t
764  * @rectangle: a #cairo_rectangle_int_t
765  *
766  * Computes the exclusive difference of @dst with @rectangle and places the
767  * result in @dst. That is, @dst will be set to contain all areas that are 
768  * either in @dst or in @rectangle, but not in both.
769  *
770  * Return value: %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY
771  *
772  * Since: 1.10
773  **/
774 cairo_status_t
775 cairo_region_xor_rectangle (cairo_region_t *dst,
776                             const cairo_rectangle_int_t *rectangle)
777 {
778     cairo_status_t status = CAIRO_STATUS_SUCCESS;
779     pixman_region32_t region, tmp;
780
781     if (dst->status)
782         return dst->status;
783
784     pixman_region32_init_rect (&region,
785                                rectangle->x, rectangle->y,
786                                rectangle->width, rectangle->height);
787     pixman_region32_init (&tmp);
788
789     /* XXX: get an xor function into pixman */
790     if (! pixman_region32_subtract (&tmp, &region, &dst->rgn) ||
791         ! pixman_region32_subtract (&dst->rgn, &dst->rgn, &region) || 
792         ! pixman_region32_union (&dst->rgn, &dst->rgn, &tmp))
793         status = _cairo_region_set_error (dst, CAIRO_STATUS_NO_MEMORY);
794
795     pixman_region32_fini (&tmp);
796     pixman_region32_fini (&region);
797
798     return status;
799 }
800 slim_hidden_def (cairo_region_xor_rectangle);
801
802 /**
803  * cairo_region_is_empty:
804  * @region: a #cairo_region_t
805  *
806  * Checks whether @region is empty.
807  *
808  * Return value: %TRUE if @region is empty, %FALSE if it isn't.
809  *
810  * Since: 1.10
811  **/
812 cairo_bool_t
813 cairo_region_is_empty (const cairo_region_t *region)
814 {
815     if (region->status)
816         return TRUE;
817
818     return ! pixman_region32_not_empty (CONST_CAST &region->rgn);
819 }
820 slim_hidden_def (cairo_region_is_empty);
821
822 /**
823  * cairo_region_translate:
824  * @region: a #cairo_region_t
825  * @dx: Amount to translate in the x direction
826  * @dy: Amount to translate in the y direction
827  *
828  * Translates @region by (@dx, @dy).
829  *
830  * Since: 1.10
831  **/
832 void
833 cairo_region_translate (cairo_region_t *region,
834                         int dx, int dy)
835 {
836     if (region->status)
837         return;
838
839     pixman_region32_translate (&region->rgn, dx, dy);
840 }
841 slim_hidden_def (cairo_region_translate);
842
843 /**
844  * cairo_region_overlap_t:
845  * @CAIRO_REGION_OVERLAP_IN: The contents are entirely inside the region. (Since 1.10)
846  * @CAIRO_REGION_OVERLAP_OUT: The contents are entirely outside the region. (Since 1.10)
847  * @CAIRO_REGION_OVERLAP_PART: The contents are partially inside and
848  *     partially outside the region. (Since 1.10)
849  *
850  * Used as the return value for cairo_region_contains_rectangle().
851  *
852  * Since: 1.10
853  **/
854
855 /**
856  * cairo_region_contains_rectangle:
857  * @region: a #cairo_region_t
858  * @rectangle: a #cairo_rectangle_int_t
859  *
860  * Checks whether @rectangle is inside, outside or partially contained
861  * in @region
862  *
863  * Return value:
864  *   %CAIRO_REGION_OVERLAP_IN if @rectangle is entirely inside @region,
865  *   %CAIRO_REGION_OVERLAP_OUT if @rectangle is entirely outside @region, or
866  *   %CAIRO_REGION_OVERLAP_PART if @rectangle is partially inside and partially outside @region.
867  *
868  * Since: 1.10
869  **/
870 cairo_region_overlap_t
871 cairo_region_contains_rectangle (const cairo_region_t *region,
872                                  const cairo_rectangle_int_t *rectangle)
873 {
874     pixman_box32_t pbox;
875     pixman_region_overlap_t poverlap;
876
877     if (region->status)
878         return CAIRO_REGION_OVERLAP_OUT;
879
880     pbox.x1 = rectangle->x;
881     pbox.y1 = rectangle->y;
882     pbox.x2 = rectangle->x + rectangle->width;
883     pbox.y2 = rectangle->y + rectangle->height;
884
885     poverlap = pixman_region32_contains_rectangle (CONST_CAST &region->rgn,
886                                                    &pbox);
887     switch (poverlap) {
888     default:
889     case PIXMAN_REGION_OUT:  return CAIRO_REGION_OVERLAP_OUT;
890     case PIXMAN_REGION_IN:   return CAIRO_REGION_OVERLAP_IN;
891     case PIXMAN_REGION_PART: return CAIRO_REGION_OVERLAP_PART;
892     }
893 }
894 slim_hidden_def (cairo_region_contains_rectangle);
895
896 /**
897  * cairo_region_contains_point:
898  * @region: a #cairo_region_t
899  * @x: the x coordinate of a point
900  * @y: the y coordinate of a point
901  *
902  * Checks whether (@x, @y) is contained in @region.
903  *
904  * Return value: %TRUE if (@x, @y) is contained in @region, %FALSE if it is not.
905  *
906  * Since: 1.10
907  **/
908 cairo_bool_t
909 cairo_region_contains_point (const cairo_region_t *region,
910                              int x, int y)
911 {
912     pixman_box32_t box;
913
914     if (region->status)
915         return FALSE;
916
917     return pixman_region32_contains_point (CONST_CAST &region->rgn, x, y, &box);
918 }
919 slim_hidden_def (cairo_region_contains_point);
920
921 /**
922  * cairo_region_equal:
923  * @a: a #cairo_region_t or %NULL
924  * @b: a #cairo_region_t or %NULL
925  *
926  * Compares whether region_a is equivalent to region_b. %NULL as an argument
927  * is equal to itself, but not to any non-%NULL region.
928  *
929  * Return value: %TRUE if both regions contained the same coverage,
930  * %FALSE if it is not or any region is in an error status.
931  *
932  * Since: 1.10
933  **/
934 cairo_bool_t
935 cairo_region_equal (const cairo_region_t *a,
936                     const cairo_region_t *b)
937 {
938     /* error objects are never equal */
939     if ((a != NULL && a->status) || (b != NULL && b->status))
940         return FALSE;
941
942     if (a == b)
943         return TRUE;
944
945     if (a == NULL || b == NULL)
946         return FALSE;
947
948     return pixman_region32_equal (CONST_CAST &a->rgn, CONST_CAST &b->rgn);
949 }
950 slim_hidden_def (cairo_region_equal);