Line data Source code
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 0 : _cairo_region_create_in_error (cairo_status_t status)
64 : {
65 0 : switch (status) {
66 : case CAIRO_STATUS_NO_MEMORY:
67 0 : return (cairo_region_t *) &_cairo_region_nil;
68 :
69 : case CAIRO_STATUS_SUCCESS:
70 : case CAIRO_STATUS_LAST_STATUS:
71 0 : 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 0 : _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
109 0 : 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
134 0 : _cairo_region_set_error (cairo_region_t *region,
135 : cairo_status_t status)
136 : {
137 0 : if (! _cairo_status_is_error (status))
138 0 : return status;
139 :
140 : /* Don't overwrite an existing error. This preserves the first
141 : * error, which is the most significant. */
142 0 : _cairo_status_set_error (®ion->status, status);
143 :
144 0 : return _cairo_error (status);
145 : }
146 :
147 : void
148 0 : _cairo_region_init (cairo_region_t *region)
149 : {
150 : VG (VALGRIND_MAKE_MEM_UNDEFINED (region, sizeof (cairo_region_t)));
151 :
152 0 : region->status = CAIRO_STATUS_SUCCESS;
153 0 : CAIRO_REFERENCE_COUNT_INIT (®ion->ref_count, 0);
154 0 : pixman_region32_init (®ion->rgn);
155 0 : }
156 :
157 : void
158 0 : _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 0 : region->status = CAIRO_STATUS_SUCCESS;
164 0 : CAIRO_REFERENCE_COUNT_INIT (®ion->ref_count, 0);
165 0 : pixman_region32_init_rect (®ion->rgn,
166 : rectangle->x, rectangle->y,
167 0 : rectangle->width, rectangle->height);
168 0 : }
169 :
170 : void
171 0 : _cairo_region_fini (cairo_region_t *region)
172 : {
173 0 : assert (! CAIRO_REFERENCE_COUNT_HAS_REFERENCE (®ion->ref_count));
174 0 : pixman_region32_fini (®ion->rgn);
175 : VG (VALGRIND_MAKE_MEM_NOACCESS (region, sizeof (cairo_region_t)));
176 0 : }
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 *
192 0 : cairo_region_create (void)
193 : {
194 : cairo_region_t *region;
195 :
196 0 : region = _cairo_malloc (sizeof (cairo_region_t));
197 0 : if (region == NULL)
198 0 : return (cairo_region_t *) &_cairo_region_nil;
199 :
200 0 : region->status = CAIRO_STATUS_SUCCESS;
201 0 : CAIRO_REFERENCE_COUNT_INIT (®ion->ref_count, 1);
202 :
203 0 : pixman_region32_init (®ion->rgn);
204 :
205 0 : 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 *
225 0 : 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 0 : pixman_box32_t *pboxes = stack_pboxes;
230 : cairo_region_t *region;
231 : int i;
232 :
233 0 : region = _cairo_malloc (sizeof (cairo_region_t));
234 0 : if (unlikely (region == NULL))
235 0 : return _cairo_region_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
236 :
237 0 : if (count > ARRAY_LENGTH (stack_pboxes)) {
238 0 : pboxes = _cairo_malloc_ab (count, sizeof (pixman_box32_t));
239 0 : if (unlikely (pboxes == NULL)) {
240 0 : free (region);
241 0 : return _cairo_region_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
242 : }
243 : }
244 :
245 0 : for (i = 0; i < count; i++) {
246 0 : pboxes[i].x1 = rects[i].x;
247 0 : pboxes[i].y1 = rects[i].y;
248 0 : pboxes[i].x2 = rects[i].x + rects[i].width;
249 0 : pboxes[i].y2 = rects[i].y + rects[i].height;
250 : }
251 :
252 0 : i = pixman_region32_init_rects (®ion->rgn, pboxes, count);
253 :
254 0 : if (pboxes != stack_pboxes)
255 0 : free (pboxes);
256 :
257 0 : if (unlikely (i == 0)) {
258 0 : free (region);
259 0 : return _cairo_region_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
260 : }
261 :
262 0 : CAIRO_REFERENCE_COUNT_INIT (®ion->ref_count, 1);
263 0 : region->status = CAIRO_STATUS_SUCCESS;
264 0 : 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 *
283 0 : cairo_region_create_rectangle (const cairo_rectangle_int_t *rectangle)
284 : {
285 : cairo_region_t *region;
286 :
287 0 : region = _cairo_malloc (sizeof (cairo_region_t));
288 0 : if (unlikely (region == NULL))
289 0 : return (cairo_region_t *) &_cairo_region_nil;
290 :
291 0 : region->status = CAIRO_STATUS_SUCCESS;
292 0 : CAIRO_REFERENCE_COUNT_INIT (®ion->ref_count, 1);
293 :
294 0 : pixman_region32_init_rect (®ion->rgn,
295 : rectangle->x, rectangle->y,
296 0 : rectangle->width, rectangle->height);
297 :
298 0 : 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 *
317 0 : cairo_region_copy (const cairo_region_t *original)
318 : {
319 : cairo_region_t *copy;
320 :
321 0 : if (original != NULL && original->status)
322 0 : return (cairo_region_t *) &_cairo_region_nil;
323 :
324 0 : copy = cairo_region_create ();
325 0 : if (unlikely (copy->status))
326 0 : return copy;
327 :
328 0 : if (original != NULL &&
329 0 : ! pixman_region32_copy (©->rgn, CONST_CAST &original->rgn))
330 : {
331 0 : cairo_region_destroy (copy);
332 0 : return (cairo_region_t *) &_cairo_region_nil;
333 : }
334 :
335 0 : 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 *
352 0 : cairo_region_reference (cairo_region_t *region)
353 : {
354 0 : if (region == NULL || CAIRO_REFERENCE_COUNT_IS_INVALID (®ion->ref_count))
355 0 : return NULL;
356 :
357 0 : assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (®ion->ref_count));
358 :
359 0 : _cairo_reference_count_inc (®ion->ref_count);
360 0 : 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
375 0 : cairo_region_destroy (cairo_region_t *region)
376 : {
377 0 : if (region == NULL || CAIRO_REFERENCE_COUNT_IS_INVALID (®ion->ref_count))
378 0 : return;
379 :
380 0 : assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (®ion->ref_count));
381 :
382 0 : if (! _cairo_reference_count_dec_and_test (®ion->ref_count))
383 0 : return;
384 :
385 0 : _cairo_region_fini (region);
386 0 : 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
401 0 : cairo_region_num_rectangles (const cairo_region_t *region)
402 : {
403 0 : if (region->status)
404 0 : return 0;
405 :
406 0 : 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
421 0 : 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 0 : if (region->status) {
428 0 : rectangle->x = rectangle->y = 0;
429 0 : rectangle->width = rectangle->height = 0;
430 0 : return;
431 : }
432 :
433 0 : pbox = pixman_region32_rectangles (CONST_CAST ®ion->rgn, NULL) + nth;
434 :
435 0 : rectangle->x = pbox->x1;
436 0 : rectangle->y = pbox->y1;
437 0 : rectangle->width = pbox->x2 - pbox->x1;
438 0 : 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
452 0 : cairo_region_get_extents (const cairo_region_t *region,
453 : cairo_rectangle_int_t *extents)
454 : {
455 : pixman_box32_t *pextents;
456 :
457 0 : if (region->status) {
458 0 : extents->x = extents->y = 0;
459 0 : extents->width = extents->height = 0;
460 0 : return;
461 : }
462 :
463 0 : pextents = pixman_region32_extents (CONST_CAST ®ion->rgn);
464 :
465 0 : extents->x = pextents->x1;
466 0 : extents->y = pextents->y1;
467 0 : extents->width = pextents->x2 - pextents->x1;
468 0 : 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
484 0 : cairo_region_status (const cairo_region_t *region)
485 : {
486 0 : 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
502 0 : cairo_region_subtract (cairo_region_t *dst, const cairo_region_t *other)
503 : {
504 0 : if (dst->status)
505 0 : return dst->status;
506 :
507 0 : if (other->status)
508 0 : return _cairo_region_set_error (dst, other->status);
509 :
510 0 : if (! pixman_region32_subtract (&dst->rgn,
511 : &dst->rgn,
512 0 : CONST_CAST &other->rgn))
513 : {
514 0 : return _cairo_region_set_error (dst, CAIRO_STATUS_NO_MEMORY);
515 : }
516 :
517 0 : 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
533 0 : cairo_region_subtract_rectangle (cairo_region_t *dst,
534 : const cairo_rectangle_int_t *rectangle)
535 : {
536 0 : cairo_status_t status = CAIRO_STATUS_SUCCESS;
537 : pixman_region32_t region;
538 :
539 0 : if (dst->status)
540 0 : return dst->status;
541 :
542 0 : pixman_region32_init_rect (®ion,
543 : rectangle->x, rectangle->y,
544 0 : rectangle->width, rectangle->height);
545 :
546 0 : if (! pixman_region32_subtract (&dst->rgn, &dst->rgn, ®ion))
547 0 : status = _cairo_region_set_error (dst, CAIRO_STATUS_NO_MEMORY);
548 :
549 0 : pixman_region32_fini (®ion);
550 :
551 0 : 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
567 0 : cairo_region_intersect (cairo_region_t *dst, const cairo_region_t *other)
568 : {
569 0 : if (dst->status)
570 0 : return dst->status;
571 :
572 0 : if (other->status)
573 0 : return _cairo_region_set_error (dst, other->status);
574 :
575 0 : if (! pixman_region32_intersect (&dst->rgn, &dst->rgn, CONST_CAST &other->rgn))
576 0 : return _cairo_region_set_error (dst, CAIRO_STATUS_NO_MEMORY);
577 :
578 0 : 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
595 0 : cairo_region_intersect_rectangle (cairo_region_t *dst,
596 : const cairo_rectangle_int_t *rectangle)
597 : {
598 0 : cairo_status_t status = CAIRO_STATUS_SUCCESS;
599 : pixman_region32_t region;
600 :
601 0 : if (dst->status)
602 0 : return dst->status;
603 :
604 0 : pixman_region32_init_rect (®ion,
605 : rectangle->x, rectangle->y,
606 0 : rectangle->width, rectangle->height);
607 :
608 0 : if (! pixman_region32_intersect (&dst->rgn, &dst->rgn, ®ion))
609 0 : status = _cairo_region_set_error (dst, CAIRO_STATUS_NO_MEMORY);
610 :
611 0 : pixman_region32_fini (®ion);
612 :
613 0 : 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
629 0 : cairo_region_union (cairo_region_t *dst,
630 : const cairo_region_t *other)
631 : {
632 0 : if (dst->status)
633 0 : return dst->status;
634 :
635 0 : if (other->status)
636 0 : return _cairo_region_set_error (dst, other->status);
637 :
638 0 : if (! pixman_region32_union (&dst->rgn, &dst->rgn, CONST_CAST &other->rgn))
639 0 : return _cairo_region_set_error (dst, CAIRO_STATUS_NO_MEMORY);
640 :
641 0 : 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
657 0 : cairo_region_union_rectangle (cairo_region_t *dst,
658 : const cairo_rectangle_int_t *rectangle)
659 : {
660 0 : cairo_status_t status = CAIRO_STATUS_SUCCESS;
661 : pixman_region32_t region;
662 :
663 0 : if (dst->status)
664 0 : return dst->status;
665 :
666 0 : pixman_region32_init_rect (®ion,
667 : rectangle->x, rectangle->y,
668 0 : rectangle->width, rectangle->height);
669 :
670 0 : if (! pixman_region32_union (&dst->rgn, &dst->rgn, ®ion))
671 0 : status = _cairo_region_set_error (dst, CAIRO_STATUS_NO_MEMORY);
672 :
673 0 : pixman_region32_fini (®ion);
674 :
675 0 : 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
693 0 : cairo_region_xor (cairo_region_t *dst, const cairo_region_t *other)
694 : {
695 0 : cairo_status_t status = CAIRO_STATUS_SUCCESS;
696 : pixman_region32_t tmp;
697 :
698 0 : if (dst->status)
699 0 : return dst->status;
700 :
701 0 : if (other->status)
702 0 : return _cairo_region_set_error (dst, other->status);
703 :
704 0 : pixman_region32_init (&tmp);
705 :
706 : /* XXX: get an xor function into pixman */
707 0 : if (! pixman_region32_subtract (&tmp, CONST_CAST &other->rgn, &dst->rgn) ||
708 0 : ! pixman_region32_subtract (&dst->rgn, &dst->rgn, CONST_CAST &other->rgn) ||
709 0 : ! pixman_region32_union (&dst->rgn, &dst->rgn, &tmp))
710 0 : status = _cairo_region_set_error (dst, CAIRO_STATUS_NO_MEMORY);
711 :
712 0 : pixman_region32_fini (&tmp);
713 :
714 0 : 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
732 0 : cairo_region_xor_rectangle (cairo_region_t *dst,
733 : const cairo_rectangle_int_t *rectangle)
734 : {
735 0 : cairo_status_t status = CAIRO_STATUS_SUCCESS;
736 : pixman_region32_t region, tmp;
737 :
738 0 : if (dst->status)
739 0 : return dst->status;
740 :
741 0 : pixman_region32_init_rect (®ion,
742 : rectangle->x, rectangle->y,
743 0 : rectangle->width, rectangle->height);
744 0 : pixman_region32_init (&tmp);
745 :
746 : /* XXX: get an xor function into pixman */
747 0 : if (! pixman_region32_subtract (&tmp, ®ion, &dst->rgn) ||
748 0 : ! pixman_region32_subtract (&dst->rgn, &dst->rgn, ®ion) ||
749 0 : ! pixman_region32_union (&dst->rgn, &dst->rgn, &tmp))
750 0 : status = _cairo_region_set_error (dst, CAIRO_STATUS_NO_MEMORY);
751 :
752 0 : pixman_region32_fini (&tmp);
753 0 : pixman_region32_fini (®ion);
754 :
755 0 : 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
770 0 : cairo_region_is_empty (const cairo_region_t *region)
771 : {
772 0 : if (region->status)
773 0 : return TRUE;
774 :
775 0 : 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
790 0 : cairo_region_translate (cairo_region_t *region,
791 : int dx, int dy)
792 : {
793 0 : if (region->status)
794 0 : return;
795 :
796 0 : 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
826 0 : 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 0 : if (region->status)
833 0 : return CAIRO_REGION_OVERLAP_OUT;
834 :
835 0 : pbox.x1 = rectangle->x;
836 0 : pbox.y1 = rectangle->y;
837 0 : pbox.x2 = rectangle->x + rectangle->width;
838 0 : pbox.y2 = rectangle->y + rectangle->height;
839 :
840 0 : poverlap = pixman_region32_contains_rectangle (CONST_CAST ®ion->rgn,
841 : &pbox);
842 0 : switch (poverlap) {
843 : default:
844 0 : case PIXMAN_REGION_OUT: return CAIRO_REGION_OVERLAP_OUT;
845 0 : case PIXMAN_REGION_IN: return CAIRO_REGION_OVERLAP_IN;
846 0 : 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
864 0 : cairo_region_contains_point (const cairo_region_t *region,
865 : int x, int y)
866 : {
867 : pixman_box32_t box;
868 :
869 0 : if (region->status)
870 0 : return FALSE;
871 :
872 0 : 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
890 0 : cairo_region_equal (const cairo_region_t *a,
891 : const cairo_region_t *b)
892 : {
893 : /* error objects are never equal */
894 0 : if ((a != NULL && a->status) || (b != NULL && b->status))
895 0 : return FALSE;
896 :
897 0 : if (a == b)
898 0 : return TRUE;
899 :
900 0 : if (a == NULL || b == NULL)
901 0 : return FALSE;
902 :
903 0 : return pixman_region32_equal (CONST_CAST &a->rgn, CONST_CAST &b->rgn);
904 : }
905 : slim_hidden_def (cairo_region_equal);
|