Coverage Report

Created: 2025-11-16 09:57

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/work/workdir/UnpackedTarball/cairo/src/cairo-region.c
Line
Count
Source
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
25.7k
#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
0
{
65
0
    switch (status) {
66
0
    case CAIRO_STATUS_NO_MEMORY:
67
0
  return (cairo_region_t *) &_cairo_region_nil;
68
69
0
    case CAIRO_STATUS_SUCCESS:
70
0
    case CAIRO_STATUS_LAST_STATUS:
71
0
  ASSERT_NOT_REACHED;
72
  /* fall-through */
73
0
    case CAIRO_STATUS_SURFACE_TYPE_MISMATCH:
74
0
    case CAIRO_STATUS_INVALID_STATUS:
75
0
    case CAIRO_STATUS_INVALID_CONTENT:
76
0
    case CAIRO_STATUS_INVALID_FORMAT:
77
0
    case CAIRO_STATUS_INVALID_VISUAL:
78
0
    case CAIRO_STATUS_READ_ERROR:
79
0
    case CAIRO_STATUS_WRITE_ERROR:
80
0
    case CAIRO_STATUS_FILE_NOT_FOUND:
81
0
    case CAIRO_STATUS_TEMP_FILE_ERROR:
82
0
    case CAIRO_STATUS_INVALID_STRIDE:
83
0
    case CAIRO_STATUS_INVALID_SIZE:
84
0
    case CAIRO_STATUS_DEVICE_TYPE_MISMATCH:
85
0
    case CAIRO_STATUS_DEVICE_ERROR:
86
0
    case CAIRO_STATUS_INVALID_RESTORE:
87
0
    case CAIRO_STATUS_INVALID_POP_GROUP:
88
0
    case CAIRO_STATUS_NO_CURRENT_POINT:
89
0
    case CAIRO_STATUS_INVALID_MATRIX:
90
0
    case CAIRO_STATUS_NULL_POINTER:
91
0
    case CAIRO_STATUS_INVALID_STRING:
92
0
    case CAIRO_STATUS_INVALID_PATH_DATA:
93
0
    case CAIRO_STATUS_SURFACE_FINISHED:
94
0
    case CAIRO_STATUS_PATTERN_TYPE_MISMATCH:
95
0
    case CAIRO_STATUS_INVALID_DASH:
96
0
    case CAIRO_STATUS_INVALID_DSC_COMMENT:
97
0
    case CAIRO_STATUS_INVALID_INDEX:
98
0
    case CAIRO_STATUS_CLIP_NOT_REPRESENTABLE:
99
0
    case CAIRO_STATUS_FONT_TYPE_MISMATCH:
100
0
    case CAIRO_STATUS_USER_FONT_IMMUTABLE:
101
0
    case CAIRO_STATUS_USER_FONT_ERROR:
102
0
    case CAIRO_STATUS_NEGATIVE_COUNT:
103
0
    case CAIRO_STATUS_INVALID_CLUSTERS:
104
0
    case CAIRO_STATUS_INVALID_SLANT:
105
0
    case CAIRO_STATUS_INVALID_WEIGHT:
106
0
    case CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED:
107
0
    case CAIRO_STATUS_INVALID_MESH_CONSTRUCTION:
108
0
    case CAIRO_STATUS_DEVICE_FINISHED:
109
0
    case CAIRO_STATUS_JBIG2_GLOBAL_MISSING:
110
0
    case CAIRO_STATUS_PNG_ERROR:
111
0
    case CAIRO_STATUS_FREETYPE_ERROR:
112
0
    case CAIRO_STATUS_WIN32_GDI_ERROR:
113
0
    case CAIRO_STATUS_TAG_ERROR:
114
0
    case CAIRO_STATUS_DWRITE_ERROR:
115
0
    case CAIRO_STATUS_SVG_FONT_ERROR:
116
0
    default:
117
0
  _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
118
0
  return (cairo_region_t *) &_cairo_region_nil;
119
0
    }
120
0
}
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
0
{
146
0
    if (status == CAIRO_STATUS_SUCCESS)
147
0
        return CAIRO_STATUS_SUCCESS;
148
149
    /* Don't overwrite an existing error. This preserves the first
150
     * error, which is the most significant. */
151
0
    _cairo_status_set_error (&region->status, status);
152
153
0
    return _cairo_error (status);
154
0
}
155
156
void
157
_cairo_region_init (cairo_region_t *region)
158
4
{
159
4
    VG (VALGRIND_MAKE_MEM_UNDEFINED (region, sizeof (cairo_region_t)));
160
161
4
    region->status = CAIRO_STATUS_SUCCESS;
162
4
    CAIRO_REFERENCE_COUNT_INIT (&region->ref_count, 0);
163
4
    pixman_region32_init (&region->rgn);
164
4
}
165
166
void
167
_cairo_region_init_rectangle (cairo_region_t *region,
168
            const cairo_rectangle_int_t *rectangle)
169
0
{
170
0
    VG (VALGRIND_MAKE_MEM_UNDEFINED (region, sizeof (cairo_region_t)));
171
172
0
    region->status = CAIRO_STATUS_SUCCESS;
173
0
    CAIRO_REFERENCE_COUNT_INIT (&region->ref_count, 0);
174
0
    pixman_region32_init_rect (&region->rgn,
175
0
             rectangle->x, rectangle->y,
176
0
             rectangle->width, rectangle->height);
177
0
}
178
179
void
180
_cairo_region_fini (cairo_region_t *region)
181
25.7k
{
182
25.7k
    assert (! CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&region->ref_count));
183
25.7k
    pixman_region32_fini (&region->rgn);
184
25.7k
    VG (VALGRIND_MAKE_MEM_UNDEFINED (region, sizeof (cairo_region_t)));
185
25.7k
}
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
0
{
203
0
    cairo_region_t *region;
204
205
0
    region = _cairo_calloc (sizeof (cairo_region_t));
206
0
    if (region == NULL)
207
0
  return (cairo_region_t *) &_cairo_region_nil;
208
209
0
    region->status = CAIRO_STATUS_SUCCESS;
210
0
    CAIRO_REFERENCE_COUNT_INIT (&region->ref_count, 1);
211
212
0
    pixman_region32_init (&region->rgn);
213
214
0
    return region;
215
0
}
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
cairo_region_create_rectangles (const cairo_rectangle_int_t *rects,
234
        int count)
235
25.7k
{
236
25.7k
    pixman_box32_t stack_pboxes[CAIRO_STACK_ARRAY_LENGTH (pixman_box32_t)];
237
25.7k
    pixman_box32_t *pboxes = stack_pboxes;
238
25.7k
    cairo_region_t *region;
239
25.7k
    int i;
240
241
25.7k
    region = _cairo_calloc (sizeof (cairo_region_t));
242
25.7k
    if (unlikely (region == NULL))
243
0
  return _cairo_region_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
244
245
25.7k
    CAIRO_REFERENCE_COUNT_INIT (&region->ref_count, 1);
246
25.7k
    region->status = CAIRO_STATUS_SUCCESS;
247
248
25.7k
    if (count == 1) {
249
25.7k
  pixman_region32_init_rect (&region->rgn,
250
25.7k
           rects->x, rects->y,
251
25.7k
           rects->width, rects->height);
252
253
25.7k
  return region;
254
25.7k
    }
255
256
0
    if (count > ARRAY_LENGTH (stack_pboxes)) {
257
0
  pboxes = _cairo_malloc_ab (count, sizeof (pixman_box32_t));
258
0
  if (unlikely (pboxes == NULL)) {
259
0
      free (region);
260
0
      return _cairo_region_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
261
0
  }
262
0
    }
263
264
0
    for (i = 0; i < count; i++) {
265
0
  pboxes[i].x1 = rects[i].x;
266
0
  pboxes[i].y1 = rects[i].y;
267
0
  pboxes[i].x2 = rects[i].x + rects[i].width;
268
0
  pboxes[i].y2 = rects[i].y + rects[i].height;
269
0
    }
270
271
0
    i = pixman_region32_init_rects (&region->rgn, pboxes, count);
272
273
0
    if (pboxes != stack_pboxes)
274
0
  free (pboxes);
275
276
0
    if (unlikely (i == 0)) {
277
0
  free (region);
278
0
  return _cairo_region_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
279
0
    }
280
281
0
    return region;
282
0
}
283
284
cairo_region_t *
285
_cairo_region_create_from_boxes (const cairo_box_t *boxes, int count)
286
0
{
287
0
    cairo_region_t *region;
288
289
0
    region = _cairo_calloc (sizeof (cairo_region_t));
290
0
    if (unlikely (region == NULL))
291
0
  return _cairo_region_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
292
293
0
    CAIRO_REFERENCE_COUNT_INIT (&region->ref_count, 1);
294
0
    region->status = CAIRO_STATUS_SUCCESS;
295
296
0
    if (! pixman_region32_init_rects (&region->rgn,
297
0
              (pixman_box32_t *)boxes, count)) {
298
0
  free (region);
299
0
  return _cairo_region_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
300
0
    }
301
302
0
    return region;
303
0
}
304
305
cairo_box_t *
306
_cairo_region_get_boxes (const cairo_region_t *region, int *nbox)
307
0
{
308
0
    if (region->status) {
309
0
  nbox = 0;
310
0
  return NULL;
311
0
    }
312
313
0
    return (cairo_box_t *) pixman_region32_rectangles (CONST_CAST &region->rgn, nbox);
314
0
}
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
0
{
333
0
    cairo_region_t *region;
334
335
0
    region = _cairo_calloc (sizeof (cairo_region_t));
336
0
    if (unlikely (region == NULL))
337
0
  return (cairo_region_t *) &_cairo_region_nil;
338
339
0
    region->status = CAIRO_STATUS_SUCCESS;
340
0
    CAIRO_REFERENCE_COUNT_INIT (&region->ref_count, 1);
341
342
0
    pixman_region32_init_rect (&region->rgn,
343
0
             rectangle->x, rectangle->y,
344
0
             rectangle->width, rectangle->height);
345
346
0
    return region;
347
0
}
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
0
{
366
0
    cairo_region_t *copy;
367
368
0
    if (original != NULL && original->status)
369
0
  return (cairo_region_t *) &_cairo_region_nil;
370
371
0
    copy = cairo_region_create ();
372
0
    if (unlikely (copy->status))
373
0
  return copy;
374
375
0
    if (original != NULL &&
376
0
  ! pixman_region32_copy (&copy->rgn, CONST_CAST &original->rgn))
377
0
    {
378
0
  cairo_region_destroy (copy);
379
0
  return (cairo_region_t *) &_cairo_region_nil;
380
0
    }
381
382
0
    return copy;
383
0
}
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
cairo_region_reference (cairo_region_t *region)
399
17.3k
{
400
17.3k
    if (region == NULL || CAIRO_REFERENCE_COUNT_IS_INVALID (&region->ref_count))
401
17.3k
  return NULL;
402
403
17.3k
    assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&region->ref_count));
404
405
0
    _cairo_reference_count_inc (&region->ref_count);
406
0
    return region;
407
0
}
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
cairo_region_destroy (cairo_region_t *region)
421
4.64M
{
422
4.64M
    if (region == NULL || CAIRO_REFERENCE_COUNT_IS_INVALID (&region->ref_count))
423
4.62M
  return;
424
425
4.64M
    assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&region->ref_count));
426
427
25.7k
    if (! _cairo_reference_count_dec_and_test (&region->ref_count))
428
0
  return;
429
430
25.7k
    _cairo_region_fini (region);
431
25.7k
    free (region);
432
25.7k
}
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
cairo_region_num_rectangles (const cairo_region_t *region)
446
0
{
447
0
    if (region->status)
448
0
  return 0;
449
450
0
    return pixman_region32_n_rects (CONST_CAST &region->rgn);
451
0
}
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
0
{
468
0
    pixman_box32_t *pbox;
469
470
0
    if (region->status) {
471
0
  rectangle->x = rectangle->y = 0;
472
0
  rectangle->width = rectangle->height = 0;
473
0
  return;
474
0
    }
475
476
0
    pbox = pixman_region32_rectangles (CONST_CAST &region->rgn, NULL) + nth;
477
478
0
    rectangle->x = pbox->x1;
479
0
    rectangle->y = pbox->y1;
480
0
    rectangle->width = pbox->x2 - pbox->x1;
481
0
    rectangle->height = pbox->y2 - pbox->y1;
482
0
}
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
0
{
497
0
    pixman_box32_t *pextents;
498
499
0
    if (region->status) {
500
0
  extents->x = extents->y = 0;
501
0
  extents->width = extents->height = 0;
502
0
  return;
503
0
    }
504
505
0
    pextents = pixman_region32_extents (CONST_CAST &region->rgn);
506
507
0
    extents->x = pextents->x1;
508
0
    extents->y = pextents->y1;
509
0
    extents->width = pextents->x2 - pextents->x1;
510
0
    extents->height = pextents->y2 - pextents->y1;
511
0
}
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
0
{
527
0
    return region->status;
528
0
}
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
0
{
544
0
    if (dst->status)
545
0
  return dst->status;
546
547
0
    if (other->status)
548
0
  return _cairo_region_set_error (dst, other->status);
549
550
0
    if (! pixman_region32_subtract (&dst->rgn,
551
0
            &dst->rgn,
552
0
            CONST_CAST &other->rgn))
553
0
    {
554
0
  return _cairo_region_set_error (dst, CAIRO_STATUS_NO_MEMORY);
555
0
    }
556
557
0
    return CAIRO_STATUS_SUCCESS;
558
0
}
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
0
{
575
0
    cairo_status_t status = CAIRO_STATUS_SUCCESS;
576
0
    pixman_region32_t region;
577
578
0
    if (dst->status)
579
0
  return dst->status;
580
581
0
    pixman_region32_init_rect (&region,
582
0
             rectangle->x, rectangle->y,
583
0
             rectangle->width, rectangle->height);
584
585
0
    if (! pixman_region32_subtract (&dst->rgn, &dst->rgn, &region))
586
0
  status = _cairo_region_set_error (dst, CAIRO_STATUS_NO_MEMORY);
587
588
0
    pixman_region32_fini (&region);
589
590
0
    return status;
591
0
}
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
0
{
607
0
    if (dst->status)
608
0
  return dst->status;
609
610
0
    if (other->status)
611
0
  return _cairo_region_set_error (dst, other->status);
612
613
0
    if (! pixman_region32_intersect (&dst->rgn, &dst->rgn, CONST_CAST &other->rgn))
614
0
  return _cairo_region_set_error (dst, CAIRO_STATUS_NO_MEMORY);
615
616
0
    return CAIRO_STATUS_SUCCESS;
617
0
}
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
0
{
635
0
    cairo_status_t status = CAIRO_STATUS_SUCCESS;
636
0
    pixman_region32_t region;
637
638
0
    if (dst->status)
639
0
  return dst->status;
640
641
0
    pixman_region32_init_rect (&region,
642
0
             rectangle->x, rectangle->y,
643
0
             rectangle->width, rectangle->height);
644
645
0
    if (! pixman_region32_intersect (&dst->rgn, &dst->rgn, &region))
646
0
  status = _cairo_region_set_error (dst, CAIRO_STATUS_NO_MEMORY);
647
648
0
    pixman_region32_fini (&region);
649
650
0
    return status;
651
0
}
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
cairo_region_union (cairo_region_t *dst,
666
        const cairo_region_t *other)
667
0
{
668
0
    if (dst->status)
669
0
  return dst->status;
670
671
0
    if (other->status)
672
0
  return _cairo_region_set_error (dst, other->status);
673
674
0
    if (! pixman_region32_union (&dst->rgn, &dst->rgn, CONST_CAST &other->rgn))
675
0
  return _cairo_region_set_error (dst, CAIRO_STATUS_NO_MEMORY);
676
677
0
    return CAIRO_STATUS_SUCCESS;
678
0
}
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
cairo_region_union_rectangle (cairo_region_t *dst,
693
            const cairo_rectangle_int_t *rectangle)
694
0
{
695
0
    cairo_status_t status = CAIRO_STATUS_SUCCESS;
696
0
    pixman_region32_t region;
697
698
0
    if (dst->status)
699
0
  return dst->status;
700
701
0
    pixman_region32_init_rect (&region,
702
0
             rectangle->x, rectangle->y,
703
0
             rectangle->width, rectangle->height);
704
705
0
    if (! pixman_region32_union (&dst->rgn, &dst->rgn, &region))
706
0
  status = _cairo_region_set_error (dst, CAIRO_STATUS_NO_MEMORY);
707
708
0
    pixman_region32_fini (&region);
709
710
0
    return status;
711
0
}
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
0
{
729
0
    cairo_status_t status = CAIRO_STATUS_SUCCESS;
730
0
    pixman_region32_t tmp;
731
732
0
    if (dst->status)
733
0
  return dst->status;
734
735
0
    if (other->status)
736
0
  return _cairo_region_set_error (dst, other->status);
737
738
0
    pixman_region32_init (&tmp);
739
740
    /* XXX: get an xor function into pixman */
741
0
    if (! pixman_region32_subtract (&tmp, CONST_CAST &other->rgn, &dst->rgn) ||
742
0
        ! pixman_region32_subtract (&dst->rgn, &dst->rgn, CONST_CAST &other->rgn) || 
743
0
        ! pixman_region32_union (&dst->rgn, &dst->rgn, &tmp))
744
0
  status = _cairo_region_set_error (dst, CAIRO_STATUS_NO_MEMORY);
745
746
0
    pixman_region32_fini (&tmp);
747
748
0
    return status;
749
0
}
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
0
{
768
0
    cairo_status_t status = CAIRO_STATUS_SUCCESS;
769
0
    pixman_region32_t region, tmp;
770
771
0
    if (dst->status)
772
0
  return dst->status;
773
774
0
    pixman_region32_init_rect (&region,
775
0
             rectangle->x, rectangle->y,
776
0
             rectangle->width, rectangle->height);
777
0
    pixman_region32_init (&tmp);
778
779
    /* XXX: get an xor function into pixman */
780
0
    if (! pixman_region32_subtract (&tmp, &region, &dst->rgn) ||
781
0
        ! pixman_region32_subtract (&dst->rgn, &dst->rgn, &region) || 
782
0
        ! pixman_region32_union (&dst->rgn, &dst->rgn, &tmp))
783
0
  status = _cairo_region_set_error (dst, CAIRO_STATUS_NO_MEMORY);
784
785
0
    pixman_region32_fini (&tmp);
786
0
    pixman_region32_fini (&region);
787
788
0
    return status;
789
0
}
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
0
{
804
0
    if (region->status)
805
0
  return TRUE;
806
807
0
    return ! pixman_region32_not_empty (CONST_CAST &region->rgn);
808
0
}
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
0
{
824
0
    if (region->status)
825
0
  return;
826
827
0
    pixman_region32_translate (&region->rgn, dx, dy);
828
0
}
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
cairo_region_contains_rectangle (const cairo_region_t *region,
847
         const cairo_rectangle_int_t *rectangle)
848
25.7k
{
849
25.7k
    pixman_box32_t pbox;
850
25.7k
    pixman_region_overlap_t poverlap;
851
852
25.7k
    if (region->status)
853
0
  return CAIRO_REGION_OVERLAP_OUT;
854
855
25.7k
    pbox.x1 = rectangle->x;
856
25.7k
    pbox.y1 = rectangle->y;
857
25.7k
    pbox.x2 = rectangle->x + rectangle->width;
858
25.7k
    pbox.y2 = rectangle->y + rectangle->height;
859
860
25.7k
    poverlap = pixman_region32_contains_rectangle (CONST_CAST &region->rgn,
861
25.7k
               &pbox);
862
25.7k
    switch (poverlap) {
863
0
    default:
864
0
    case PIXMAN_REGION_OUT:  return CAIRO_REGION_OVERLAP_OUT;
865
25.7k
    case PIXMAN_REGION_IN:   return CAIRO_REGION_OVERLAP_IN;
866
0
    case PIXMAN_REGION_PART: return CAIRO_REGION_OVERLAP_PART;
867
25.7k
    }
868
25.7k
}
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
0
{
886
0
    pixman_box32_t box;
887
888
0
    if (region->status)
889
0
  return FALSE;
890
891
0
    return pixman_region32_contains_point (CONST_CAST &region->rgn, x, y, &box);
892
0
}
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
0
{
911
    /* error objects are never equal */
912
0
    if ((a != NULL && a->status) || (b != NULL && b->status))
913
0
  return FALSE;
914
915
0
    if (a == b)
916
0
  return TRUE;
917
918
0
    if (a == NULL || b == NULL)
919
0
  return FALSE;
920
921
0
    return pixman_region32_equal (CONST_CAST &a->rgn, CONST_CAST &b->rgn);
922
0
}