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 (®ion->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 (®ion->ref_count, 0);
154 pixman_region32_init (®ion->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 (®ion->ref_count, 0);
165 pixman_region32_init_rect (®ion->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 (®ion->ref_count));
174 pixman_region32_fini (®ion->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 (®ion->ref_count, 1);
202
203 pixman_region32_init (®ion->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 (®ion->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 (®ion->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 (®ion->ref_count, 1);
293
294 pixman_region32_init_rect (®ion->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 (©->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 (®ion->ref_count))
355 return NULL;
356
357 assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (®ion->ref_count));
358
359 _cairo_reference_count_inc (®ion->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 (®ion->ref_count))
378 return;
379
380 assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (®ion->ref_count));
381
382 if (! _cairo_reference_count_dec_and_test (®ion->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 ®ion->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 ®ion->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 ®ion->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 (®ion,
543 rectangle->x, rectangle->y,
544 rectangle->width, rectangle->height);
545
546 if (! pixman_region32_subtract (&dst->rgn, &dst->rgn, ®ion))
547 status = _cairo_region_set_error (dst, CAIRO_STATUS_NO_MEMORY);
548
549 pixman_region32_fini (®ion);
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 (®ion,
605 rectangle->x, rectangle->y,
606 rectangle->width, rectangle->height);
607
608 if (! pixman_region32_intersect (&dst->rgn, &dst->rgn, ®ion))
609 status = _cairo_region_set_error (dst, CAIRO_STATUS_NO_MEMORY);
610
611 pixman_region32_fini (®ion);
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 (®ion,
667 rectangle->x, rectangle->y,
668 rectangle->width, rectangle->height);
669
670 if (! pixman_region32_union (&dst->rgn, &dst->rgn, ®ion))
671 status = _cairo_region_set_error (dst, CAIRO_STATUS_NO_MEMORY);
672
673 pixman_region32_fini (®ion);
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 (®ion,
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, ®ion, &dst->rgn) ||
748 ! pixman_region32_subtract (&dst->rgn, &dst->rgn, ®ion) ||
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 (®ion);
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 ®ion->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 (®ion->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 ®ion->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 ®ion->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