Coverage Report

Created: 2025-07-07 10:01

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