Coverage Report

Created: 2025-07-07 10:01

/work/workdir/UnpackedTarball/cairo/src/cairo-clip.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 © 2002 University of Southern California
5
 * Copyright © 2005 Red Hat, Inc.
6
 * Copyright © 2009 Chris Wilson
7
 *
8
 * This library is free software; you can redistribute it and/or
9
 * modify it either under the terms of the GNU Lesser General Public
10
 * License version 2.1 as published by the Free Software Foundation
11
 * (the "LGPL") or, at your option, under the terms of the Mozilla
12
 * Public License Version 1.1 (the "MPL"). If you do not alter this
13
 * notice, a recipient may use your version of this file under either
14
 * the MPL or the LGPL.
15
 *
16
 * You should have received a copy of the LGPL along with this library
17
 * in the file COPYING-LGPL-2.1; if not, write to the Free Software
18
 * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
19
 * You should have received a copy of the MPL along with this library
20
 * in the file COPYING-MPL-1.1
21
 *
22
 * The contents of this file are subject to the Mozilla Public License
23
 * Version 1.1 (the "License"); you may not use this file except in
24
 * compliance with the License. You may obtain a copy of the License at
25
 * http://www.mozilla.org/MPL/
26
 *
27
 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
28
 * OF ANY KIND, either express or implied. See the LGPL or the MPL for
29
 * the specific language governing rights and limitations.
30
 *
31
 * The Original Code is the cairo graphics library.
32
 *
33
 * The Initial Developer of the Original Code is University of Southern
34
 * California.
35
 *
36
 * Contributor(s):
37
 *  Carl D. Worth <cworth@cworth.org>
38
 *  Kristian Høgsberg <krh@redhat.com>
39
 *  Chris Wilson <chris@chris-wilson.co.uk>
40
 */
41
42
#include "cairoint.h"
43
#include "cairo-clip-inline.h"
44
#include "cairo-clip-private.h"
45
#include "cairo-error-private.h"
46
#include "cairo-freed-pool-private.h"
47
#include "cairo-gstate-private.h"
48
#include "cairo-path-fixed-private.h"
49
#include "cairo-pattern-private.h"
50
#include "cairo-composite-rectangles-private.h"
51
#include "cairo-region-private.h"
52
53
static freed_pool_t clip_path_pool;
54
static freed_pool_t clip_pool;
55
56
const cairo_clip_t __cairo_clip_all;
57
58
static cairo_clip_path_t *
59
_cairo_clip_path_create (cairo_clip_t *clip)
60
0
{
61
0
    cairo_clip_path_t *clip_path;
62
63
0
    clip_path = _freed_pool_get (&clip_path_pool);
64
0
    if (unlikely (clip_path == NULL)) {
65
0
  clip_path = _cairo_malloc (sizeof (cairo_clip_path_t));
66
0
  if (unlikely (clip_path == NULL))
67
0
      return NULL;
68
0
    }
69
70
0
    CAIRO_REFERENCE_COUNT_INIT (&clip_path->ref_count, 1);
71
72
0
    clip_path->prev = clip->path;
73
0
    clip->path = clip_path;
74
75
0
    return clip_path;
76
0
}
77
78
cairo_clip_path_t *
79
_cairo_clip_path_reference (cairo_clip_path_t *clip_path)
80
0
{
81
0
    assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&clip_path->ref_count));
82
83
0
    _cairo_reference_count_inc (&clip_path->ref_count);
84
85
0
    return clip_path;
86
0
}
87
88
void
89
_cairo_clip_path_destroy (cairo_clip_path_t *clip_path)
90
0
{
91
0
    assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&clip_path->ref_count));
92
93
0
    if (! _cairo_reference_count_dec_and_test (&clip_path->ref_count))
94
0
  return;
95
96
0
    _cairo_path_fixed_fini (&clip_path->path);
97
98
0
    if (clip_path->prev != NULL)
99
0
  _cairo_clip_path_destroy (clip_path->prev);
100
101
0
    _freed_pool_put (&clip_path_pool, clip_path);
102
0
}
103
104
cairo_clip_t *
105
_cairo_clip_create (void)
106
1.60M
{
107
1.60M
    cairo_clip_t *clip;
108
109
1.60M
    clip = _freed_pool_get (&clip_pool);
110
1.60M
    if (unlikely (clip == NULL)) {
111
11
  clip = _cairo_malloc (sizeof (cairo_clip_t));
112
11
  if (unlikely (clip == NULL))
113
0
      return NULL;
114
11
    }
115
116
1.60M
    clip->extents = _cairo_unbounded_rectangle;
117
118
1.60M
    clip->path = NULL;
119
1.60M
    clip->boxes = NULL;
120
1.60M
    clip->num_boxes = 0;
121
1.60M
    clip->region = NULL;
122
1.60M
    clip->is_region = FALSE;
123
124
1.60M
    return clip;
125
1.60M
}
126
127
void
128
_cairo_clip_destroy (cairo_clip_t *clip)
129
16.7M
{
130
16.7M
    if (clip == NULL || _cairo_clip_is_all_clipped (clip))
131
15.1M
  return;
132
133
1.60M
    if (clip->path != NULL)
134
0
  _cairo_clip_path_destroy (clip->path);
135
136
1.60M
    if (clip->boxes != &clip->embedded_box)
137
20.7k
  free (clip->boxes);
138
1.60M
    cairo_region_destroy (clip->region);
139
140
1.60M
    _freed_pool_put (&clip_pool, clip);
141
1.60M
}
142
143
cairo_clip_t *
144
_cairo_clip_copy (const cairo_clip_t *clip)
145
19.4k
{
146
19.4k
    cairo_clip_t *copy;
147
148
19.4k
    if (clip == NULL || _cairo_clip_is_all_clipped (clip))
149
1.07k
  return (cairo_clip_t *) clip;
150
151
18.3k
    copy = _cairo_clip_create ();
152
153
18.3k
    if (clip->path)
154
0
  copy->path = _cairo_clip_path_reference (clip->path);
155
156
18.3k
    if (clip->num_boxes) {
157
18.3k
  if (clip->num_boxes == 1) {
158
18.3k
      copy->boxes = &copy->embedded_box;
159
18.3k
  } else {
160
2
      copy->boxes = _cairo_malloc_ab (clip->num_boxes, sizeof (cairo_box_t));
161
2
      if (unlikely (copy->boxes == NULL))
162
0
    return _cairo_clip_set_all_clipped (copy);
163
2
  }
164
165
18.3k
  memcpy (copy->boxes, clip->boxes,
166
18.3k
    clip->num_boxes * sizeof (cairo_box_t));
167
18.3k
  copy->num_boxes = clip->num_boxes;
168
18.3k
    }
169
170
18.3k
    copy->extents = clip->extents;
171
18.3k
    copy->region = cairo_region_reference (clip->region);
172
18.3k
    copy->is_region = clip->is_region;
173
174
18.3k
    return copy;
175
18.3k
}
176
177
cairo_clip_t *
178
_cairo_clip_copy_path (const cairo_clip_t *clip)
179
40.5k
{
180
40.5k
    cairo_clip_t *copy;
181
182
40.5k
    if (clip == NULL || _cairo_clip_is_all_clipped (clip))
183
0
  return (cairo_clip_t *) clip;
184
185
40.5k
    assert (clip->num_boxes);
186
187
40.5k
    copy = _cairo_clip_create ();
188
40.5k
    copy->extents = clip->extents;
189
40.5k
    if (clip->path)
190
0
  copy->path = _cairo_clip_path_reference (clip->path);
191
192
40.5k
    return copy;
193
40.5k
}
194
195
cairo_clip_t *
196
_cairo_clip_copy_region (const cairo_clip_t *clip)
197
0
{
198
0
    cairo_clip_t *copy;
199
0
    int i;
200
201
0
    if (clip == NULL || _cairo_clip_is_all_clipped (clip))
202
0
  return (cairo_clip_t *) clip;
203
204
0
    assert (clip->num_boxes);
205
206
0
    copy = _cairo_clip_create ();
207
0
    copy->extents = clip->extents;
208
209
0
    if (clip->num_boxes == 1) {
210
0
  copy->boxes = &copy->embedded_box;
211
0
    } else {
212
0
  copy->boxes = _cairo_malloc_ab (clip->num_boxes, sizeof (cairo_box_t));
213
0
  if (unlikely (copy->boxes == NULL))
214
0
      return _cairo_clip_set_all_clipped (copy);
215
0
    }
216
217
0
    for (i = 0; i < clip->num_boxes; i++) {
218
0
  copy->boxes[i].p1.x = _cairo_fixed_floor (clip->boxes[i].p1.x);
219
0
  copy->boxes[i].p1.y = _cairo_fixed_floor (clip->boxes[i].p1.y);
220
0
  copy->boxes[i].p2.x = _cairo_fixed_ceil (clip->boxes[i].p2.x);
221
0
  copy->boxes[i].p2.y = _cairo_fixed_ceil (clip->boxes[i].p2.y);
222
0
    }
223
0
    copy->num_boxes = clip->num_boxes;
224
225
0
    copy->region = cairo_region_reference (clip->region);
226
0
    copy->is_region = TRUE;
227
228
0
    return copy;
229
0
}
230
231
cairo_clip_t *
232
_cairo_clip_intersect_path (cairo_clip_t       *clip,
233
          const cairo_path_fixed_t *path,
234
          cairo_fill_rule_t   fill_rule,
235
          double              tolerance,
236
          cairo_antialias_t   antialias)
237
267k
{
238
267k
    cairo_clip_path_t *clip_path;
239
267k
    cairo_status_t status;
240
267k
    cairo_rectangle_int_t extents;
241
267k
    cairo_box_t box;
242
243
267k
    if (_cairo_clip_is_all_clipped (clip))
244
0
  return clip;
245
246
    /* catch the empty clip path */
247
267k
    if (_cairo_path_fixed_fill_is_empty (path))
248
0
  return _cairo_clip_set_all_clipped (clip);
249
250
267k
    if (_cairo_path_fixed_is_box (path, &box)) {
251
266k
  if (antialias == CAIRO_ANTIALIAS_NONE) {
252
255k
      box.p1.x = _cairo_fixed_round_down (box.p1.x);
253
255k
      box.p1.y = _cairo_fixed_round_down (box.p1.y);
254
255k
      box.p2.x = _cairo_fixed_round_down (box.p2.x);
255
255k
      box.p2.y = _cairo_fixed_round_down (box.p2.y);
256
255k
  }
257
258
266k
  return _cairo_clip_intersect_box (clip, &box);
259
266k
    }
260
1.37k
    if (_cairo_path_fixed_fill_is_rectilinear (path))
261
1.37k
  return _cairo_clip_intersect_rectilinear_path (clip, path,
262
1.37k
                   fill_rule, antialias);
263
264
0
    _cairo_path_fixed_approximate_clip_extents (path, &extents);
265
0
    if (extents.width == 0 || extents.height == 0)
266
0
  return _cairo_clip_set_all_clipped (clip);
267
268
0
    clip = _cairo_clip_intersect_rectangle (clip, &extents);
269
0
    if (_cairo_clip_is_all_clipped (clip))
270
0
  return clip;
271
272
0
    clip_path = _cairo_clip_path_create (clip);
273
0
    if (unlikely (clip_path == NULL))
274
0
  return _cairo_clip_set_all_clipped (clip);
275
276
0
    status = _cairo_path_fixed_init_copy (&clip_path->path, path);
277
0
    if (unlikely (status))
278
0
  return _cairo_clip_set_all_clipped (clip);
279
280
0
    clip_path->fill_rule = fill_rule;
281
0
    clip_path->tolerance = tolerance;
282
0
    clip_path->antialias = antialias;
283
284
0
    if (clip->region) {
285
0
  cairo_region_destroy (clip->region);
286
0
  clip->region = NULL;
287
0
    }
288
289
0
    clip->is_region = FALSE;
290
0
    return clip;
291
0
}
292
293
static cairo_clip_t *
294
_cairo_clip_intersect_clip_path (cairo_clip_t *clip,
295
         const cairo_clip_path_t *clip_path)
296
0
{
297
0
    if (clip_path->prev)
298
0
  clip = _cairo_clip_intersect_clip_path (clip, clip_path->prev);
299
300
0
    return _cairo_clip_intersect_path (clip,
301
0
               &clip_path->path,
302
0
               clip_path->fill_rule,
303
0
               clip_path->tolerance,
304
0
               clip_path->antialias);
305
0
}
306
307
cairo_clip_t *
308
_cairo_clip_intersect_clip (cairo_clip_t *clip,
309
          const cairo_clip_t *other)
310
0
{
311
0
    if (_cairo_clip_is_all_clipped (clip))
312
0
  return clip;
313
314
0
    if (other == NULL)
315
0
  return clip;
316
317
0
    if (clip == NULL)
318
0
  return _cairo_clip_copy (other);
319
320
0
    if (_cairo_clip_is_all_clipped (other))
321
0
  return _cairo_clip_set_all_clipped (clip);
322
323
0
    if (! _cairo_rectangle_intersect (&clip->extents, &other->extents))
324
0
  return _cairo_clip_set_all_clipped (clip);
325
326
0
    if (other->num_boxes) {
327
0
  cairo_boxes_t boxes;
328
329
0
  _cairo_boxes_init_for_array (&boxes, other->boxes, other->num_boxes);
330
0
  clip = _cairo_clip_intersect_boxes (clip, &boxes);
331
0
    }
332
333
0
    if (! _cairo_clip_is_all_clipped (clip)) {
334
0
  if (other->path) {
335
0
      if (clip->path == NULL)
336
0
    clip->path = _cairo_clip_path_reference (other->path);
337
0
      else
338
0
    clip = _cairo_clip_intersect_clip_path (clip, other->path);
339
0
  }
340
0
    }
341
342
0
    if (clip->region) {
343
0
  cairo_region_destroy (clip->region);
344
0
  clip->region = NULL;
345
0
    }
346
0
    clip->is_region = FALSE;
347
348
0
    return clip;
349
0
}
350
351
cairo_bool_t
352
_cairo_clip_equal (const cairo_clip_t *clip_a,
353
       const cairo_clip_t *clip_b)
354
0
{
355
0
    const cairo_clip_path_t *cp_a, *cp_b;
356
357
    /* are both all-clipped or no-clip? */
358
0
    if (clip_a == clip_b)
359
0
  return TRUE;
360
361
    /* or just one of them? */
362
0
    if (clip_a == NULL || clip_b == NULL ||
363
0
  _cairo_clip_is_all_clipped (clip_a) ||
364
0
  _cairo_clip_is_all_clipped (clip_b))
365
0
    {
366
0
  return FALSE;
367
0
    }
368
369
    /* We have a pair of normal clips, check their contents */
370
371
0
    if (clip_a->num_boxes != clip_b->num_boxes)
372
0
  return FALSE;
373
374
0
    if (memcmp (clip_a->boxes, clip_b->boxes,
375
0
    sizeof (cairo_box_t) * clip_a->num_boxes))
376
0
  return FALSE;
377
378
0
    cp_a = clip_a->path;
379
0
    cp_b = clip_b->path;
380
0
    while (cp_a && cp_b) {
381
0
  if (cp_a == cp_b)
382
0
      return TRUE;
383
384
  /* XXX compare reduced polygons? */
385
386
0
  if (cp_a->antialias != cp_b->antialias)
387
0
      return FALSE;
388
389
0
  if (cp_a->tolerance != cp_b->tolerance)
390
0
      return FALSE;
391
392
0
  if (cp_a->fill_rule != cp_b->fill_rule)
393
0
      return FALSE;
394
395
0
  if (! _cairo_path_fixed_equal (&cp_a->path,
396
0
               &cp_b->path))
397
0
      return FALSE;
398
399
0
  cp_a = cp_a->prev;
400
0
  cp_b = cp_b->prev;
401
0
    }
402
403
0
    return cp_a == NULL && cp_b == NULL;
404
0
}
405
406
static cairo_clip_t *
407
_cairo_clip_path_copy_with_translation (cairo_clip_t      *clip,
408
          cairo_clip_path_t *other_path,
409
          int fx, int fy)
410
0
{
411
0
    cairo_status_t status;
412
0
    cairo_clip_path_t *clip_path;
413
414
0
    if (other_path->prev != NULL)
415
0
  clip = _cairo_clip_path_copy_with_translation (clip, other_path->prev,
416
0
                   fx, fy);
417
0
    if (_cairo_clip_is_all_clipped (clip))
418
0
  return clip;
419
420
0
    clip_path = _cairo_clip_path_create (clip);
421
0
    if (unlikely (clip_path == NULL))
422
0
  return _cairo_clip_set_all_clipped (clip);
423
424
0
    status = _cairo_path_fixed_init_copy (&clip_path->path,
425
0
            &other_path->path);
426
0
    if (unlikely (status))
427
0
  return _cairo_clip_set_all_clipped (clip);
428
429
0
    _cairo_path_fixed_translate (&clip_path->path, fx, fy);
430
431
0
    clip_path->fill_rule = other_path->fill_rule;
432
0
    clip_path->tolerance = other_path->tolerance;
433
0
    clip_path->antialias = other_path->antialias;
434
435
0
    return clip;
436
0
}
437
438
cairo_clip_t *
439
_cairo_clip_translate (cairo_clip_t *clip, int tx, int ty)
440
0
{
441
0
    int fx, fy, i;
442
0
    cairo_clip_path_t *clip_path;
443
444
0
    if (clip == NULL || _cairo_clip_is_all_clipped (clip))
445
0
  return clip;
446
447
0
    if (tx == 0 && ty == 0)
448
0
  return clip;
449
450
0
    fx = _cairo_fixed_from_int (tx);
451
0
    fy = _cairo_fixed_from_int (ty);
452
453
0
    for (i = 0; i < clip->num_boxes; i++) {
454
0
  clip->boxes[i].p1.x += fx;
455
0
  clip->boxes[i].p2.x += fx;
456
0
  clip->boxes[i].p1.y += fy;
457
0
  clip->boxes[i].p2.y += fy;
458
0
    }
459
460
0
    clip->extents.x += tx;
461
0
    clip->extents.y += ty;
462
463
0
    if (clip->path == NULL)
464
0
  return clip;
465
466
0
    clip_path = clip->path;
467
0
    clip->path = NULL;
468
0
    clip = _cairo_clip_path_copy_with_translation (clip, clip_path, fx, fy);
469
0
    _cairo_clip_path_destroy (clip_path);
470
471
0
    return clip;
472
0
}
473
474
static cairo_status_t
475
_cairo_path_fixed_add_box (cairo_path_fixed_t *path,
476
         const cairo_box_t *box)
477
0
{
478
0
    cairo_status_t status;
479
480
0
    status = _cairo_path_fixed_move_to (path, box->p1.x, box->p1.y);
481
0
    if (unlikely (status))
482
0
  return status;
483
484
0
    status = _cairo_path_fixed_line_to (path, box->p2.x, box->p1.y);
485
0
    if (unlikely (status))
486
0
  return status;
487
488
0
    status = _cairo_path_fixed_line_to (path, box->p2.x, box->p2.y);
489
0
    if (unlikely (status))
490
0
  return status;
491
492
0
    status = _cairo_path_fixed_line_to (path, box->p1.x, box->p2.y);
493
0
    if (unlikely (status))
494
0
  return status;
495
496
0
    return _cairo_path_fixed_close_path (path);
497
0
}
498
499
static cairo_status_t
500
_cairo_path_fixed_init_from_boxes (cairo_path_fixed_t *path,
501
           const cairo_boxes_t *boxes)
502
0
{
503
0
    cairo_status_t status;
504
0
    const struct _cairo_boxes_chunk *chunk;
505
0
    int i;
506
507
0
    _cairo_path_fixed_init (path);
508
0
    if (boxes->num_boxes == 0)
509
0
  return CAIRO_STATUS_SUCCESS;
510
511
0
    for (chunk = &boxes->chunks; chunk; chunk = chunk->next) {
512
0
  for (i = 0; i < chunk->count; i++) {
513
0
      status = _cairo_path_fixed_add_box (path, &chunk->base[i]);
514
0
      if (unlikely (status)) {
515
0
    _cairo_path_fixed_fini (path);
516
0
    return status;
517
0
      }
518
0
  }
519
0
    }
520
521
0
    return CAIRO_STATUS_SUCCESS;
522
0
}
523
524
static cairo_clip_t *
525
_cairo_clip_intersect_clip_path_transformed (cairo_clip_t *clip,
526
               const cairo_clip_path_t *clip_path,
527
               const cairo_matrix_t *m)
528
0
{
529
0
    cairo_path_fixed_t path;
530
531
0
    if (clip_path->prev)
532
0
  clip = _cairo_clip_intersect_clip_path_transformed (clip,
533
0
                  clip_path->prev,
534
0
                  m);
535
536
0
    if (_cairo_path_fixed_init_copy (&path, &clip_path->path))
537
0
  return _cairo_clip_set_all_clipped (clip);
538
539
0
    _cairo_path_fixed_transform (&path, m);
540
541
0
    clip =  _cairo_clip_intersect_path (clip,
542
0
               &path,
543
0
               clip_path->fill_rule,
544
0
               clip_path->tolerance,
545
0
               clip_path->antialias);
546
0
    _cairo_path_fixed_fini (&path);
547
548
0
    return clip;
549
0
}
550
551
cairo_clip_t *
552
_cairo_clip_transform (cairo_clip_t *clip, const cairo_matrix_t *m)
553
0
{
554
0
    cairo_clip_t *copy;
555
556
0
    if (clip == NULL || _cairo_clip_is_all_clipped (clip))
557
0
  return clip;
558
559
0
    if (_cairo_matrix_is_translation (m))
560
0
  return _cairo_clip_translate (clip, m->x0, m->y0);
561
562
0
    copy = _cairo_clip_create ();
563
564
0
    if (clip->num_boxes) {
565
0
  cairo_path_fixed_t path;
566
0
  cairo_boxes_t boxes;
567
568
0
  _cairo_boxes_init_for_array (&boxes, clip->boxes, clip->num_boxes);
569
0
  _cairo_path_fixed_init_from_boxes (&path, &boxes);
570
0
  _cairo_path_fixed_transform (&path, m);
571
572
0
  copy = _cairo_clip_intersect_path (copy, &path,
573
0
             CAIRO_FILL_RULE_WINDING,
574
0
             0.1,
575
0
             CAIRO_ANTIALIAS_DEFAULT);
576
577
0
  _cairo_path_fixed_fini (&path);
578
0
    }
579
580
0
    if (clip->path)
581
0
  copy = _cairo_clip_intersect_clip_path_transformed (copy, clip->path,m);
582
583
0
    _cairo_clip_destroy (clip);
584
0
    return copy;
585
0
}
586
587
cairo_clip_t *
588
_cairo_clip_copy_with_translation (const cairo_clip_t *clip, int tx, int ty)
589
0
{
590
0
    cairo_clip_t *copy;
591
0
    int fx, fy, i;
592
593
0
    if (clip == NULL || _cairo_clip_is_all_clipped (clip))
594
0
  return (cairo_clip_t *)clip;
595
596
0
    if (tx == 0 && ty == 0)
597
0
  return _cairo_clip_copy (clip);
598
599
0
    copy = _cairo_clip_create ();
600
0
    if (copy == NULL)
601
0
      return _cairo_clip_set_all_clipped (copy);
602
603
0
    fx = _cairo_fixed_from_int (tx);
604
0
    fy = _cairo_fixed_from_int (ty);
605
606
0
    if (clip->num_boxes) {
607
0
  if (clip->num_boxes == 1) {
608
0
      copy->boxes = &copy->embedded_box;
609
0
  } else {
610
0
      copy->boxes = _cairo_malloc_ab (clip->num_boxes, sizeof (cairo_box_t));
611
0
      if (unlikely (copy->boxes == NULL))
612
0
    return _cairo_clip_set_all_clipped (copy);
613
0
  }
614
615
0
  for (i = 0; i < clip->num_boxes; i++) {
616
0
      copy->boxes[i].p1.x = clip->boxes[i].p1.x + fx;
617
0
      copy->boxes[i].p2.x = clip->boxes[i].p2.x + fx;
618
0
      copy->boxes[i].p1.y = clip->boxes[i].p1.y + fy;
619
0
      copy->boxes[i].p2.y = clip->boxes[i].p2.y + fy;
620
0
  }
621
0
  copy->num_boxes = clip->num_boxes;
622
0
    }
623
624
0
    copy->extents = clip->extents;
625
0
    copy->extents.x += tx;
626
0
    copy->extents.y += ty;
627
628
0
    if (clip->path == NULL)
629
0
  return copy;
630
631
0
    return _cairo_clip_path_copy_with_translation (copy, clip->path, fx, fy);
632
0
}
633
634
cairo_bool_t
635
_cairo_clip_contains_extents (const cairo_clip_t *clip,
636
            const cairo_composite_rectangles_t *extents)
637
0
{
638
0
    const cairo_rectangle_int_t *rect;
639
640
0
    rect = extents->is_bounded ? &extents->bounded : &extents->unbounded;
641
0
    return _cairo_clip_contains_rectangle (clip, rect);
642
0
}
643
644
void
645
_cairo_debug_print_clip (FILE *stream, const cairo_clip_t *clip)
646
0
{
647
0
    int i;
648
649
0
    if (clip == NULL) {
650
0
  fprintf (stream, "no clip\n");
651
0
  return;
652
0
    }
653
654
0
    if (_cairo_clip_is_all_clipped (clip)) {
655
0
  fprintf (stream, "clip: all-clipped\n");
656
0
  return;
657
0
    }
658
659
0
    fprintf (stream, "clip:\n");
660
0
    fprintf (stream, "  extents: (%d, %d) x (%d, %d), is-region? %d",
661
0
       clip->extents.x, clip->extents.y,
662
0
       clip->extents.width, clip->extents.height,
663
0
       clip->is_region);
664
665
0
    fprintf (stream, "  num_boxes = %d\n", clip->num_boxes);
666
0
    for (i = 0; i < clip->num_boxes; i++) {
667
0
  fprintf (stream, "  [%d] = (%f, %f), (%f, %f)\n", i,
668
0
     _cairo_fixed_to_double (clip->boxes[i].p1.x),
669
0
     _cairo_fixed_to_double (clip->boxes[i].p1.y),
670
0
     _cairo_fixed_to_double (clip->boxes[i].p2.x),
671
0
     _cairo_fixed_to_double (clip->boxes[i].p2.y));
672
0
    }
673
674
0
    if (clip->path) {
675
0
  cairo_clip_path_t *clip_path = clip->path;
676
0
  do {
677
0
      fprintf (stream, "path: aa=%d, tolerance=%f, rule=%d: ",
678
0
         clip_path->antialias,
679
0
         clip_path->tolerance,
680
0
         clip_path->fill_rule);
681
0
      _cairo_debug_print_path (stream, &clip_path->path);
682
0
      fprintf (stream, "\n");
683
0
  } while ((clip_path = clip_path->prev) != NULL);
684
0
    }
685
0
}
686
687
const cairo_rectangle_int_t *
688
_cairo_clip_get_extents (const cairo_clip_t *clip)
689
2.59M
{
690
2.59M
    if (clip == NULL)
691
0
  return &_cairo_unbounded_rectangle;
692
693
2.59M
    if (_cairo_clip_is_all_clipped (clip))
694
0
  return &_cairo_empty_rectangle;
695
696
2.59M
    return &clip->extents;
697
2.59M
}
698
699
const cairo_rectangle_list_t _cairo_rectangles_nil =
700
  { CAIRO_STATUS_NO_MEMORY, NULL, 0 };
701
static const cairo_rectangle_list_t _cairo_rectangles_not_representable =
702
  { CAIRO_STATUS_CLIP_NOT_REPRESENTABLE, NULL, 0 };
703
704
static cairo_bool_t
705
_cairo_clip_int_rect_to_user (cairo_gstate_t *gstate,
706
            cairo_rectangle_int_t *clip_rect,
707
            cairo_rectangle_t *user_rect)
708
0
{
709
0
    cairo_bool_t is_tight;
710
711
0
    double x1 = clip_rect->x;
712
0
    double y1 = clip_rect->y;
713
0
    double x2 = clip_rect->x + (int) clip_rect->width;
714
0
    double y2 = clip_rect->y + (int) clip_rect->height;
715
716
0
    _cairo_gstate_backend_to_user_rectangle (gstate,
717
0
               &x1, &y1, &x2, &y2,
718
0
               &is_tight);
719
720
0
    user_rect->x = x1;
721
0
    user_rect->y = y1;
722
0
    user_rect->width  = x2 - x1;
723
0
    user_rect->height = y2 - y1;
724
725
0
    return is_tight;
726
0
}
727
728
cairo_rectangle_list_t *
729
_cairo_rectangle_list_create_in_error (cairo_status_t status)
730
0
{
731
0
    cairo_rectangle_list_t *list;
732
733
0
    if (status == CAIRO_STATUS_NO_MEMORY)
734
0
  return (cairo_rectangle_list_t*) &_cairo_rectangles_nil;
735
0
    if (status == CAIRO_STATUS_CLIP_NOT_REPRESENTABLE)
736
0
  return (cairo_rectangle_list_t*) &_cairo_rectangles_not_representable;
737
738
0
    list = _cairo_malloc (sizeof (*list));
739
0
    if (unlikely (list == NULL)) {
740
0
  status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
741
0
  return (cairo_rectangle_list_t*) &_cairo_rectangles_nil;
742
0
    }
743
744
0
    list->status = status;
745
0
    list->rectangles = NULL;
746
0
    list->num_rectangles = 0;
747
748
0
    return list;
749
0
}
750
751
cairo_rectangle_list_t *
752
_cairo_clip_copy_rectangle_list (cairo_clip_t *clip, cairo_gstate_t *gstate)
753
0
{
754
0
#define ERROR_LIST(S) _cairo_rectangle_list_create_in_error (_cairo_error (S))
755
756
0
    cairo_rectangle_list_t *list;
757
0
    cairo_rectangle_t *rectangles = NULL;
758
0
    cairo_region_t *region = NULL;
759
0
    int n_rects = 0;
760
0
    int i;
761
762
0
    if (clip == NULL)
763
0
  return ERROR_LIST (CAIRO_STATUS_CLIP_NOT_REPRESENTABLE);
764
765
0
    if (_cairo_clip_is_all_clipped (clip))
766
0
  goto DONE;
767
768
0
    if (! _cairo_clip_is_region (clip))
769
0
  return ERROR_LIST (CAIRO_STATUS_CLIP_NOT_REPRESENTABLE);
770
771
0
    region = _cairo_clip_get_region (clip);
772
0
    if (region == NULL)
773
0
  return ERROR_LIST (CAIRO_STATUS_NO_MEMORY);
774
775
0
    n_rects = cairo_region_num_rectangles (region);
776
0
    if (n_rects) {
777
0
  rectangles = _cairo_malloc_ab (n_rects, sizeof (cairo_rectangle_t));
778
0
  if (unlikely (rectangles == NULL)) {
779
0
      return ERROR_LIST (CAIRO_STATUS_NO_MEMORY);
780
0
  }
781
782
0
  for (i = 0; i < n_rects; ++i) {
783
0
      cairo_rectangle_int_t clip_rect;
784
785
0
      cairo_region_get_rectangle (region, i, &clip_rect);
786
787
0
      if (! _cairo_clip_int_rect_to_user (gstate,
788
0
            &clip_rect,
789
0
            &rectangles[i]))
790
0
      {
791
0
    free (rectangles);
792
0
    return ERROR_LIST (CAIRO_STATUS_CLIP_NOT_REPRESENTABLE);
793
0
      }
794
0
  }
795
0
    }
796
797
0
 DONE:
798
0
    list = _cairo_malloc (sizeof (cairo_rectangle_list_t));
799
0
    if (unlikely (list == NULL)) {
800
0
        free (rectangles);
801
0
  return ERROR_LIST (CAIRO_STATUS_NO_MEMORY);
802
0
    }
803
804
0
    list->status = CAIRO_STATUS_SUCCESS;
805
0
    list->rectangles = rectangles;
806
0
    list->num_rectangles = n_rects;
807
0
    return list;
808
809
0
#undef ERROR_LIST
810
0
}
811
812
/**
813
 * cairo_rectangle_list_destroy:
814
 * @rectangle_list: a rectangle list, as obtained from cairo_copy_clip_rectangle_list()
815
 *
816
 * Unconditionally frees @rectangle_list and all associated
817
 * references. After this call, the @rectangle_list pointer must not
818
 * be dereferenced.
819
 *
820
 * Since: 1.4
821
 **/
822
void
823
cairo_rectangle_list_destroy (cairo_rectangle_list_t *rectangle_list)
824
0
{
825
0
    if (rectangle_list == NULL || rectangle_list == &_cairo_rectangles_nil ||
826
0
        rectangle_list == &_cairo_rectangles_not_representable)
827
0
        return;
828
829
0
    free (rectangle_list->rectangles);
830
0
    free (rectangle_list);
831
0
}
832
833
void
834
_cairo_clip_reset_static_data (void)
835
0
{
836
0
    _freed_pool_reset (&clip_path_pool);
837
0
    _freed_pool_reset (&clip_pool);
838
0
}