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
    case CAIRO_STATUS_JBIG2_GLOBAL_MISSING:
110
    case CAIRO_STATUS_PNG_ERROR:
111
    case CAIRO_STATUS_FREETYPE_ERROR:
112
    case CAIRO_STATUS_WIN32_GDI_ERROR:
113
    case CAIRO_STATUS_TAG_ERROR:
114
    case CAIRO_STATUS_DWRITE_ERROR:
115
    case CAIRO_STATUS_SVG_FONT_ERROR:
116
    default:
117
	_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
118
	return (cairo_region_t *) &_cairo_region_nil;
119
    }
120
}
121

            
122
/**
123
 * _cairo_region_set_error:
124
 * @region: a region
125
 * @status: a status value indicating an error
126
 *
127
 * Atomically sets region->status to @status and calls _cairo_error;
128
 * Does nothing if status is %CAIRO_STATUS_SUCCESS or any of the internal
129
 * status values.
130
 *
131
 * All assignments of an error status to region->status should happen
132
 * through _cairo_region_set_error(). Note that due to the nature of
133
 * the atomic operation, it is not safe to call this function on the
134
 * nil objects.
135
 *
136
 * The purpose of this function is to allow the user to set a
137
 * breakpoint in _cairo_error() to generate a stack trace for when the
138
 * user causes cairo to detect an error.
139
 *
140
 * Return value: the error status.
141
 **/
142
static cairo_status_t
143
_cairo_region_set_error (cairo_region_t *region,
144
			 cairo_status_t status)
145
{
146
    if (status == CAIRO_STATUS_SUCCESS)
147
        return CAIRO_STATUS_SUCCESS;
148

            
149
    /* Don't overwrite an existing error. This preserves the first
150
     * error, which is the most significant. */
151
    _cairo_status_set_error (&region->status, status);
152

            
153
    return _cairo_error (status);
154
}
155

            
156
void
157
2516
_cairo_region_init (cairo_region_t *region)
158
{
159
    VG (VALGRIND_MAKE_MEM_UNDEFINED (region, sizeof (cairo_region_t)));
160

            
161
2516
    region->status = CAIRO_STATUS_SUCCESS;
162
2516
    CAIRO_REFERENCE_COUNT_INIT (&region->ref_count, 0);
163
2516
    pixman_region32_init (&region->rgn);
164
2516
}
165

            
166
void
167
_cairo_region_init_rectangle (cairo_region_t *region,
168
			      const cairo_rectangle_int_t *rectangle)
169
{
170
    VG (VALGRIND_MAKE_MEM_UNDEFINED (region, sizeof (cairo_region_t)));
171

            
172
    region->status = CAIRO_STATUS_SUCCESS;
173
    CAIRO_REFERENCE_COUNT_INIT (&region->ref_count, 0);
174
    pixman_region32_init_rect (&region->rgn,
175
			       rectangle->x, rectangle->y,
176
			       rectangle->width, rectangle->height);
177
}
178

            
179
void
180
69788
_cairo_region_fini (cairo_region_t *region)
181
{
182
139576
    assert (! CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&region->ref_count));
183
69788
    pixman_region32_fini (&region->rgn);
184
    VG (VALGRIND_MAKE_MEM_UNDEFINED (region, sizeof (cairo_region_t)));
185
69788
}
186

            
187
/**
188
 * cairo_region_create:
189
 *
190
 * Allocates a new empty region object.
191
 *
192
 * Return value: A newly allocated #cairo_region_t. Free with
193
 *   cairo_region_destroy(). This function always returns a
194
 *   valid pointer; if memory cannot be allocated, then a special
195
 *   error object is returned where all operations on the object do nothing.
196
 *   You can check for this with cairo_region_status().
197
 *
198
 * Since: 1.10
199
 **/
200
cairo_region_t *
201
cairo_region_create (void)
202
{
203
    cairo_region_t *region;
204

            
205
    region = _cairo_calloc (sizeof (cairo_region_t));
206
    if (region == NULL)
207
	return (cairo_region_t *) &_cairo_region_nil;
208

            
209
    region->status = CAIRO_STATUS_SUCCESS;
210
    CAIRO_REFERENCE_COUNT_INIT (&region->ref_count, 1);
211

            
212
    pixman_region32_init (&region->rgn);
213

            
214
    return region;
215
}
216

            
217
/**
218
 * cairo_region_create_rectangles:
219
 * @rects: an array of @count rectangles
220
 * @count: number of rectangles
221
 *
222
 * Allocates a new region object containing the union of all given @rects.
223
 *
224
 * Return value: A newly allocated #cairo_region_t. Free with
225
 *   cairo_region_destroy(). This function always returns a
226
 *   valid pointer; if memory cannot be allocated, then a special
227
 *   error object is returned where all operations on the object do nothing.
228
 *   You can check for this with cairo_region_status().
229
 *
230
 * Since: 1.10
231
 **/
232
cairo_region_t *
233
67269
cairo_region_create_rectangles (const cairo_rectangle_int_t *rects,
234
				int count)
235
{
236
    pixman_box32_t stack_pboxes[CAIRO_STACK_ARRAY_LENGTH (pixman_box32_t)];
237
67269
    pixman_box32_t *pboxes = stack_pboxes;
238
    cairo_region_t *region;
239
    int i;
240

            
241
67269
    region = _cairo_calloc (sizeof (cairo_region_t));
242
67269
    if (unlikely (region == NULL))
243
	return _cairo_region_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
244

            
245
67269
    CAIRO_REFERENCE_COUNT_INIT (&region->ref_count, 1);
246
67269
    region->status = CAIRO_STATUS_SUCCESS;
247

            
248
67269
    if (count == 1) {
249
67184
	pixman_region32_init_rect (&region->rgn,
250
67184
				   rects->x, rects->y,
251
67184
				   rects->width, rects->height);
252

            
253
67184
	return region;
254
    }
255

            
256
85
    if (count > ARRAY_LENGTH (stack_pboxes)) {
257
	pboxes = _cairo_malloc_ab (count, sizeof (pixman_box32_t));
258
	if (unlikely (pboxes == NULL)) {
259
	    free (region);
260
	    return _cairo_region_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
261
	}
262
    }
263

            
264
405
    for (i = 0; i < count; i++) {
265
320
	pboxes[i].x1 = rects[i].x;
266
320
	pboxes[i].y1 = rects[i].y;
267
320
	pboxes[i].x2 = rects[i].x + rects[i].width;
268
320
	pboxes[i].y2 = rects[i].y + rects[i].height;
269
    }
270

            
271
85
    i = pixman_region32_init_rects (&region->rgn, pboxes, count);
272

            
273
85
    if (pboxes != stack_pboxes)
274
	free (pboxes);
275

            
276
85
    if (unlikely (i == 0)) {
277
	free (region);
278
	return _cairo_region_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
279
    }
280

            
281
85
    return region;
282
}
283

            
284
cairo_region_t *
285
3
_cairo_region_create_from_boxes (const cairo_box_t *boxes, int count)
286
{
287
    cairo_region_t *region;
288

            
289
3
    region = _cairo_calloc (sizeof (cairo_region_t));
290
3
    if (unlikely (region == NULL))
291
	return _cairo_region_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
292

            
293
3
    CAIRO_REFERENCE_COUNT_INIT (&region->ref_count, 1);
294
3
    region->status = CAIRO_STATUS_SUCCESS;
295

            
296
3
    if (! pixman_region32_init_rects (&region->rgn,
297
				      (pixman_box32_t *)boxes, count)) {
298
	free (region);
299
	return _cairo_region_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
300
    }
301

            
302
3
    return region;
303
}
304

            
305
cairo_box_t *
306
_cairo_region_get_boxes (const cairo_region_t *region, int *nbox)
307
{
308
    if (region->status) {
309
	nbox = 0;
310
	return NULL;
311
    }
312

            
313
    return (cairo_box_t *) pixman_region32_rectangles (CONST_CAST &region->rgn, nbox);
314
}
315

            
316
/**
317
 * cairo_region_create_rectangle:
318
 * @rectangle: a #cairo_rectangle_int_t
319
 *
320
 * Allocates a new region object containing @rectangle.
321
 *
322
 * Return value: A newly allocated #cairo_region_t. Free with
323
 *   cairo_region_destroy(). This function always returns a
324
 *   valid pointer; if memory cannot be allocated, then a special
325
 *   error object is returned where all operations on the object do nothing.
326
 *   You can check for this with cairo_region_status().
327
 *
328
 * Since: 1.10
329
 **/
330
cairo_region_t *
331
cairo_region_create_rectangle (const cairo_rectangle_int_t *rectangle)
332
{
333
    cairo_region_t *region;
334

            
335
    region = _cairo_calloc (sizeof (cairo_region_t));
336
    if (unlikely (region == NULL))
337
	return (cairo_region_t *) &_cairo_region_nil;
338

            
339
    region->status = CAIRO_STATUS_SUCCESS;
340
    CAIRO_REFERENCE_COUNT_INIT (&region->ref_count, 1);
341

            
342
    pixman_region32_init_rect (&region->rgn,
343
			       rectangle->x, rectangle->y,
344
			       rectangle->width, rectangle->height);
345

            
346
    return region;
347
}
348

            
349
/**
350
 * cairo_region_copy:
351
 * @original: a #cairo_region_t
352
 *
353
 * Allocates a new region object copying the area from @original.
354
 *
355
 * Return value: A newly allocated #cairo_region_t. Free with
356
 *   cairo_region_destroy(). This function always returns a
357
 *   valid pointer; if memory cannot be allocated, then a special
358
 *   error object is returned where all operations on the object do nothing.
359
 *   You can check for this with cairo_region_status().
360
 *
361
 * Since: 1.10
362
 **/
363
cairo_region_t *
364
cairo_region_copy (const cairo_region_t *original)
365
{
366
    cairo_region_t *copy;
367

            
368
    if (original != NULL && original->status)
369
	return (cairo_region_t *) &_cairo_region_nil;
370

            
371
    copy = cairo_region_create ();
372
    if (unlikely (copy->status))
373
	return copy;
374

            
375
    if (original != NULL &&
376
	! pixman_region32_copy (&copy->rgn, CONST_CAST &original->rgn))
377
    {
378
	cairo_region_destroy (copy);
379
	return (cairo_region_t *) &_cairo_region_nil;
380
    }
381

            
382
    return copy;
383
}
384

            
385
/**
386
 * cairo_region_reference:
387
 * @region: a #cairo_region_t
388
 *
389
 * Increases the reference count on @region by one. This prevents
390
 * @region from being destroyed until a matching call to
391
 * cairo_region_destroy() is made.
392
 *
393
 * Return value: the referenced #cairo_region_t.
394
 *
395
 * Since: 1.10
396
 **/
397
cairo_region_t *
398
384033
cairo_region_reference (cairo_region_t *region)
399
{
400
384060
    if (region == NULL || CAIRO_REFERENCE_COUNT_IS_INVALID (&region->ref_count))
401
384006
	return NULL;
402

            
403
54
    assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&region->ref_count));
404

            
405
27
    _cairo_reference_count_inc (&region->ref_count);
406
27
    return region;
407
}
408

            
409
/**
410
 * cairo_region_destroy:
411
 * @region: a #cairo_region_t
412
 *
413
 * Destroys a #cairo_region_t object created with
414
 * cairo_region_create(), cairo_region_copy(), or
415
 * or cairo_region_create_rectangle().
416
 *
417
 * Since: 1.10
418
 **/
419
void
420
2331504
cairo_region_destroy (cairo_region_t *region)
421
{
422
2398803
    if (region == NULL || CAIRO_REFERENCE_COUNT_IS_INVALID (&region->ref_count))
423
2264205
	return;
424

            
425
134598
    assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&region->ref_count));
426

            
427
67299
    if (! _cairo_reference_count_dec_and_test (&region->ref_count))
428
27
	return;
429

            
430
67272
    _cairo_region_fini (region);
431
67272
    free (region);
432
}
433

            
434
/**
435
 * cairo_region_num_rectangles:
436
 * @region: a #cairo_region_t
437
 *
438
 * Returns the number of rectangles contained in @region.
439
 *
440
 * Return value: The number of rectangles contained in @region.
441
 *
442
 * Since: 1.10
443
 **/
444
int
445
16
cairo_region_num_rectangles (const cairo_region_t *region)
446
{
447
16
    if (region->status)
448
	return 0;
449

            
450
16
    return pixman_region32_n_rects (CONST_CAST &region->rgn);
451
}
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
37
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
37
    if (region->status) {
471
	rectangle->x = rectangle->y = 0;
472
	rectangle->width = rectangle->height = 0;
473
	return;
474
    }
475

            
476
37
    pbox = pixman_region32_rectangles (CONST_CAST &region->rgn, NULL) + nth;
477

            
478
37
    rectangle->x = pbox->x1;
479
37
    rectangle->y = pbox->y1;
480
37
    rectangle->width = pbox->x2 - pbox->x1;
481
37
    rectangle->height = pbox->y2 - pbox->y1;
482
}
483

            
484
/**
485
 * cairo_region_get_extents:
486
 * @region: a #cairo_region_t
487
 * @extents: rectangle into which to store the extents
488
 *
489
 * Gets the bounding rectangle of @region as a #cairo_rectangle_int_t
490
 *
491
 * Since: 1.10
492
 **/
493
void
494
cairo_region_get_extents (const cairo_region_t *region,
495
			  cairo_rectangle_int_t *extents)
496
{
497
    pixman_box32_t *pextents;
498

            
499
    if (region->status) {
500
	extents->x = extents->y = 0;
501
	extents->width = extents->height = 0;
502
	return;
503
    }
504

            
505
    pextents = pixman_region32_extents (CONST_CAST &region->rgn);
506

            
507
    extents->x = pextents->x1;
508
    extents->y = pextents->y1;
509
    extents->width = pextents->x2 - pextents->x1;
510
    extents->height = pextents->y2 - pextents->y1;
511
}
512

            
513
/**
514
 * cairo_region_status:
515
 * @region: a #cairo_region_t
516
 *
517
 * Checks whether an error has previous occurred for this
518
 * region object.
519
 *
520
 * Return value: %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY
521
 *
522
 * Since: 1.10
523
 **/
524
cairo_status_t
525
cairo_region_status (const cairo_region_t *region)
526
{
527
    return region->status;
528
}
529

            
530
/**
531
 * cairo_region_subtract:
532
 * @dst: a #cairo_region_t
533
 * @other: another #cairo_region_t
534
 *
535
 * Subtracts @other from @dst and places the result in @dst
536
 *
537
 * Return value: %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY
538
 *
539
 * Since: 1.10
540
 **/
541
cairo_status_t
542
cairo_region_subtract (cairo_region_t *dst, const cairo_region_t *other)
543
{
544
    if (dst->status)
545
	return dst->status;
546

            
547
    if (other->status)
548
	return _cairo_region_set_error (dst, other->status);
549

            
550
    if (! pixman_region32_subtract (&dst->rgn,
551
				    &dst->rgn,
552
				    CONST_CAST &other->rgn))
553
    {
554
	return _cairo_region_set_error (dst, CAIRO_STATUS_NO_MEMORY);
555
    }
556

            
557
    return CAIRO_STATUS_SUCCESS;
558
}
559

            
560
/**
561
 * cairo_region_subtract_rectangle:
562
 * @dst: a #cairo_region_t
563
 * @rectangle: a #cairo_rectangle_int_t
564
 *
565
 * Subtracts @rectangle from @dst and places the result in @dst
566
 *
567
 * Return value: %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY
568
 *
569
 * Since: 1.10
570
 **/
571
cairo_status_t
572
cairo_region_subtract_rectangle (cairo_region_t *dst,
573
				 const cairo_rectangle_int_t *rectangle)
574
{
575
    cairo_status_t status = CAIRO_STATUS_SUCCESS;
576
    pixman_region32_t region;
577

            
578
    if (dst->status)
579
	return dst->status;
580

            
581
    pixman_region32_init_rect (&region,
582
			       rectangle->x, rectangle->y,
583
			       rectangle->width, rectangle->height);
584

            
585
    if (! pixman_region32_subtract (&dst->rgn, &dst->rgn, &region))
586
	status = _cairo_region_set_error (dst, CAIRO_STATUS_NO_MEMORY);
587

            
588
    pixman_region32_fini (&region);
589

            
590
    return status;
591
}
592

            
593
/**
594
 * cairo_region_intersect:
595
 * @dst: a #cairo_region_t
596
 * @other: another #cairo_region_t
597
 *
598
 * Computes the intersection of @dst with @other and places the result in @dst
599
 *
600
 * Return value: %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY
601
 *
602
 * Since: 1.10
603
 **/
604
cairo_status_t
605
cairo_region_intersect (cairo_region_t *dst, const cairo_region_t *other)
606
{
607
    if (dst->status)
608
	return dst->status;
609

            
610
    if (other->status)
611
	return _cairo_region_set_error (dst, other->status);
612

            
613
    if (! pixman_region32_intersect (&dst->rgn, &dst->rgn, CONST_CAST &other->rgn))
614
	return _cairo_region_set_error (dst, CAIRO_STATUS_NO_MEMORY);
615

            
616
    return CAIRO_STATUS_SUCCESS;
617
}
618

            
619
/**
620
 * cairo_region_intersect_rectangle:
621
 * @dst: a #cairo_region_t
622
 * @rectangle: a #cairo_rectangle_int_t
623
 *
624
 * Computes the intersection of @dst with @rectangle and places the
625
 * result in @dst
626
 *
627
 * Return value: %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY
628
 *
629
 * Since: 1.10
630
 **/
631
cairo_status_t
632
cairo_region_intersect_rectangle (cairo_region_t *dst,
633
				  const cairo_rectangle_int_t *rectangle)
634
{
635
    cairo_status_t status = CAIRO_STATUS_SUCCESS;
636
    pixman_region32_t region;
637

            
638
    if (dst->status)
639
	return dst->status;
640

            
641
    pixman_region32_init_rect (&region,
642
			       rectangle->x, rectangle->y,
643
			       rectangle->width, rectangle->height);
644

            
645
    if (! pixman_region32_intersect (&dst->rgn, &dst->rgn, &region))
646
	status = _cairo_region_set_error (dst, CAIRO_STATUS_NO_MEMORY);
647

            
648
    pixman_region32_fini (&region);
649

            
650
    return status;
651
}
652

            
653
/**
654
 * cairo_region_union:
655
 * @dst: a #cairo_region_t
656
 * @other: another #cairo_region_t
657
 *
658
 * Computes the union of @dst with @other and places the result in @dst
659
 *
660
 * Return value: %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY
661
 *
662
 * Since: 1.10
663
 **/
664
cairo_status_t
665
167
cairo_region_union (cairo_region_t *dst,
666
		    const cairo_region_t *other)
667
{
668
167
    if (dst->status)
669
	return dst->status;
670

            
671
167
    if (other->status)
672
	return _cairo_region_set_error (dst, other->status);
673

            
674
167
    if (! pixman_region32_union (&dst->rgn, &dst->rgn, CONST_CAST &other->rgn))
675
	return _cairo_region_set_error (dst, CAIRO_STATUS_NO_MEMORY);
676

            
677
167
    return CAIRO_STATUS_SUCCESS;
678
}
679

            
680
/**
681
 * cairo_region_union_rectangle:
682
 * @dst: a #cairo_region_t
683
 * @rectangle: a #cairo_rectangle_int_t
684
 *
685
 * Computes the union of @dst with @rectangle and places the result in @dst.
686
 *
687
 * Return value: %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY
688
 *
689
 * Since: 1.10
690
 **/
691
cairo_status_t
692
1604
cairo_region_union_rectangle (cairo_region_t *dst,
693
			      const cairo_rectangle_int_t *rectangle)
694
{
695
1604
    cairo_status_t status = CAIRO_STATUS_SUCCESS;
696
    pixman_region32_t region;
697

            
698
1604
    if (dst->status)
699
	return dst->status;
700

            
701
1604
    pixman_region32_init_rect (&region,
702
1604
			       rectangle->x, rectangle->y,
703
1604
			       rectangle->width, rectangle->height);
704

            
705
1604
    if (! pixman_region32_union (&dst->rgn, &dst->rgn, &region))
706
	status = _cairo_region_set_error (dst, CAIRO_STATUS_NO_MEMORY);
707

            
708
1604
    pixman_region32_fini (&region);
709

            
710
1604
    return status;
711
}
712

            
713
/**
714
 * cairo_region_xor:
715
 * @dst: a #cairo_region_t
716
 * @other: another #cairo_region_t
717
 *
718
 * Computes the exclusive difference of @dst with @other and places the
719
 * result in @dst. That is, @dst will be set to contain all areas that
720
 * are either in @dst or in @other, but not in both.
721
 *
722
 * Return value: %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY
723
 *
724
 * Since: 1.10
725
 **/
726
cairo_status_t
727
cairo_region_xor (cairo_region_t *dst, const cairo_region_t *other)
728
{
729
    cairo_status_t status = CAIRO_STATUS_SUCCESS;
730
    pixman_region32_t tmp;
731

            
732
    if (dst->status)
733
	return dst->status;
734

            
735
    if (other->status)
736
	return _cairo_region_set_error (dst, other->status);
737

            
738
    pixman_region32_init (&tmp);
739

            
740
    /* XXX: get an xor function into pixman */
741
    if (! pixman_region32_subtract (&tmp, CONST_CAST &other->rgn, &dst->rgn) ||
742
        ! pixman_region32_subtract (&dst->rgn, &dst->rgn, CONST_CAST &other->rgn) || 
743
        ! pixman_region32_union (&dst->rgn, &dst->rgn, &tmp))
744
	status = _cairo_region_set_error (dst, CAIRO_STATUS_NO_MEMORY);
745

            
746
    pixman_region32_fini (&tmp);
747

            
748
    return status;
749
}
750

            
751
/**
752
 * cairo_region_xor_rectangle:
753
 * @dst: a #cairo_region_t
754
 * @rectangle: a #cairo_rectangle_int_t
755
 *
756
 * Computes the exclusive difference of @dst with @rectangle and places the
757
 * result in @dst. That is, @dst will be set to contain all areas that are 
758
 * either in @dst or in @rectangle, but not in both.
759
 *
760
 * Return value: %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY
761
 *
762
 * Since: 1.10
763
 **/
764
cairo_status_t
765
cairo_region_xor_rectangle (cairo_region_t *dst,
766
			    const cairo_rectangle_int_t *rectangle)
767
{
768
    cairo_status_t status = CAIRO_STATUS_SUCCESS;
769
    pixman_region32_t region, tmp;
770

            
771
    if (dst->status)
772
	return dst->status;
773

            
774
    pixman_region32_init_rect (&region,
775
			       rectangle->x, rectangle->y,
776
			       rectangle->width, rectangle->height);
777
    pixman_region32_init (&tmp);
778

            
779
    /* XXX: get an xor function into pixman */
780
    if (! pixman_region32_subtract (&tmp, &region, &dst->rgn) ||
781
        ! pixman_region32_subtract (&dst->rgn, &dst->rgn, &region) || 
782
        ! pixman_region32_union (&dst->rgn, &dst->rgn, &tmp))
783
	status = _cairo_region_set_error (dst, CAIRO_STATUS_NO_MEMORY);
784

            
785
    pixman_region32_fini (&tmp);
786
    pixman_region32_fini (&region);
787

            
788
    return status;
789
}
790

            
791
/**
792
 * cairo_region_is_empty:
793
 * @region: a #cairo_region_t
794
 *
795
 * Checks whether @region is empty.
796
 *
797
 * Return value: %TRUE if @region is empty, %FALSE if it isn't.
798
 *
799
 * Since: 1.10
800
 **/
801
cairo_bool_t
802
cairo_region_is_empty (const cairo_region_t *region)
803
{
804
    if (region->status)
805
	return TRUE;
806

            
807
    return ! pixman_region32_not_empty (CONST_CAST &region->rgn);
808
}
809

            
810
/**
811
 * cairo_region_translate:
812
 * @region: a #cairo_region_t
813
 * @dx: Amount to translate in the x direction
814
 * @dy: Amount to translate in the y direction
815
 *
816
 * Translates @region by (@dx, @dy).
817
 *
818
 * Since: 1.10
819
 **/
820
void
821
cairo_region_translate (cairo_region_t *region,
822
			int dx, int dy)
823
{
824
    if (region->status)
825
	return;
826

            
827
    pixman_region32_translate (&region->rgn, dx, dy);
828
}
829

            
830
/**
831
 * cairo_region_contains_rectangle:
832
 * @region: a #cairo_region_t
833
 * @rectangle: a #cairo_rectangle_int_t
834
 *
835
 * Checks whether @rectangle is inside, outside or partially contained
836
 * in @region
837
 *
838
 * Return value:
839
 *   %CAIRO_REGION_OVERLAP_IN if @rectangle is entirely inside @region,
840
 *   %CAIRO_REGION_OVERLAP_OUT if @rectangle is entirely outside @region, or
841
 *   %CAIRO_REGION_OVERLAP_PART if @rectangle is partially inside and partially outside @region.
842
 *
843
 * Since: 1.10
844
 **/
845
cairo_region_overlap_t
846
68783
cairo_region_contains_rectangle (const cairo_region_t *region,
847
				 const cairo_rectangle_int_t *rectangle)
848
{
849
    pixman_box32_t pbox;
850
    pixman_region_overlap_t poverlap;
851

            
852
68783
    if (region->status)
853
	return CAIRO_REGION_OVERLAP_OUT;
854

            
855
68783
    pbox.x1 = rectangle->x;
856
68783
    pbox.y1 = rectangle->y;
857
68783
    pbox.x2 = rectangle->x + rectangle->width;
858
68783
    pbox.y2 = rectangle->y + rectangle->height;
859

            
860
68783
    poverlap = pixman_region32_contains_rectangle (CONST_CAST &region->rgn,
861
						   &pbox);
862
68783
    switch (poverlap) {
863
1599
    default:
864
1599
    case PIXMAN_REGION_OUT:  return CAIRO_REGION_OVERLAP_OUT;
865
32523
    case PIXMAN_REGION_IN:   return CAIRO_REGION_OVERLAP_IN;
866
34661
    case PIXMAN_REGION_PART: return CAIRO_REGION_OVERLAP_PART;
867
    }
868
}
869

            
870
/**
871
 * cairo_region_contains_point:
872
 * @region: a #cairo_region_t
873
 * @x: the x coordinate of a point
874
 * @y: the y coordinate of a point
875
 *
876
 * Checks whether (@x, @y) is contained in @region.
877
 *
878
 * Return value: %TRUE if (@x, @y) is contained in @region, %FALSE if it is not.
879
 *
880
 * Since: 1.10
881
 **/
882
cairo_bool_t
883
cairo_region_contains_point (const cairo_region_t *region,
884
			     int x, int y)
885
{
886
    pixman_box32_t box;
887

            
888
    if (region->status)
889
	return FALSE;
890

            
891
    return pixman_region32_contains_point (CONST_CAST &region->rgn, x, y, &box);
892
}
893

            
894
/**
895
 * cairo_region_equal:
896
 * @a: a #cairo_region_t or %NULL
897
 * @b: a #cairo_region_t or %NULL
898
 *
899
 * Compares whether region_a is equivalent to region_b. %NULL as an argument
900
 * is equal to itself, but not to any non-%NULL region.
901
 *
902
 * Return value: %TRUE if both regions contained the same coverage,
903
 * %FALSE if it is not or any region is in an error status.
904
 *
905
 * Since: 1.10
906
 **/
907
cairo_bool_t
908
cairo_region_equal (const cairo_region_t *a,
909
		    const cairo_region_t *b)
910
{
911
    /* error objects are never equal */
912
    if ((a != NULL && a->status) || (b != NULL && b->status))
913
	return FALSE;
914

            
915
    if (a == b)
916
	return TRUE;
917

            
918
    if (a == NULL || b == NULL)
919
	return FALSE;
920

            
921
    return pixman_region32_equal (CONST_CAST &a->rgn, CONST_CAST &b->rgn);
922
}