~reviczky/luatex/texlive-bin-git

« back to all changes in this revision

Viewing changes to libs/cairo/cairo-1.12.16/src/cairo-clip.c

  • Committer: Adam Reviczky
  • Date: 2015-04-26 22:40:47 UTC
  • Revision ID: adam.reviczky@kclalumni.net-20150426224047-i2p26n3wqphupq6z
TeX Live 2015 import (rev. 37052)

Show diffs side-by-side

added added

removed removed

Lines of Context:
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
 
{
61
 
    cairo_clip_path_t *clip_path;
62
 
 
63
 
    clip_path = _freed_pool_get (&clip_path_pool);
64
 
    if (unlikely (clip_path == NULL)) {
65
 
        clip_path = malloc (sizeof (cairo_clip_path_t));
66
 
        if (unlikely (clip_path == NULL))
67
 
            return NULL;
68
 
    }
69
 
 
70
 
    CAIRO_REFERENCE_COUNT_INIT (&clip_path->ref_count, 1);
71
 
 
72
 
    clip_path->prev = clip->path;
73
 
    clip->path = clip_path;
74
 
 
75
 
    return clip_path;
76
 
}
77
 
 
78
 
cairo_clip_path_t *
79
 
_cairo_clip_path_reference (cairo_clip_path_t *clip_path)
80
 
{
81
 
    assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&clip_path->ref_count));
82
 
 
83
 
    _cairo_reference_count_inc (&clip_path->ref_count);
84
 
 
85
 
    return clip_path;
86
 
}
87
 
 
88
 
void
89
 
_cairo_clip_path_destroy (cairo_clip_path_t *clip_path)
90
 
{
91
 
    assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&clip_path->ref_count));
92
 
 
93
 
    if (! _cairo_reference_count_dec_and_test (&clip_path->ref_count))
94
 
        return;
95
 
 
96
 
    _cairo_path_fixed_fini (&clip_path->path);
97
 
 
98
 
    if (clip_path->prev != NULL)
99
 
        _cairo_clip_path_destroy (clip_path->prev);
100
 
 
101
 
    _freed_pool_put (&clip_path_pool, clip_path);
102
 
}
103
 
 
104
 
cairo_clip_t *
105
 
_cairo_clip_create (void)
106
 
{
107
 
    cairo_clip_t *clip;
108
 
 
109
 
    clip = _freed_pool_get (&clip_pool);
110
 
    if (unlikely (clip == NULL)) {
111
 
        clip = malloc (sizeof (cairo_clip_t));
112
 
        if (unlikely (clip == NULL))
113
 
            return NULL;
114
 
    }
115
 
 
116
 
    clip->extents = _cairo_unbounded_rectangle;
117
 
 
118
 
    clip->path = NULL;
119
 
    clip->boxes = NULL;
120
 
    clip->num_boxes = 0;
121
 
    clip->region = NULL;
122
 
    clip->is_region = FALSE;
123
 
 
124
 
    return clip;
125
 
}
126
 
 
127
 
void
128
 
_cairo_clip_destroy (cairo_clip_t *clip)
129
 
{
130
 
    if (clip == NULL || _cairo_clip_is_all_clipped (clip))
131
 
        return;
132
 
 
133
 
    if (clip->path != NULL)
134
 
        _cairo_clip_path_destroy (clip->path);
135
 
 
136
 
    if (clip->boxes != &clip->embedded_box)
137
 
        free (clip->boxes);
138
 
    cairo_region_destroy (clip->region);
139
 
 
140
 
    _freed_pool_put (&clip_pool, clip);
141
 
}
142
 
 
143
 
cairo_clip_t *
144
 
_cairo_clip_copy (const cairo_clip_t *clip)
145
 
{
146
 
    cairo_clip_t *copy;
147
 
 
148
 
    if (clip == NULL || _cairo_clip_is_all_clipped (clip))
149
 
        return (cairo_clip_t *) clip;
150
 
 
151
 
    copy = _cairo_clip_create ();
152
 
 
153
 
    if (clip->path)
154
 
        copy->path = _cairo_clip_path_reference (clip->path);
155
 
 
156
 
    if (clip->num_boxes) {
157
 
        if (clip->num_boxes == 1) {
158
 
            copy->boxes = &copy->embedded_box;
159
 
        } else {
160
 
            copy->boxes = _cairo_malloc_ab (clip->num_boxes, sizeof (cairo_box_t));
161
 
            if (unlikely (copy->boxes == NULL))
162
 
                return _cairo_clip_set_all_clipped (copy);
163
 
        }
164
 
 
165
 
        memcpy (copy->boxes, clip->boxes,
166
 
                clip->num_boxes * sizeof (cairo_box_t));
167
 
        copy->num_boxes = clip->num_boxes;
168
 
    }
169
 
 
170
 
    copy->extents = clip->extents;
171
 
    copy->region = cairo_region_reference (clip->region);
172
 
    copy->is_region = clip->is_region;
173
 
 
174
 
    return copy;
175
 
}
176
 
 
177
 
cairo_clip_t *
178
 
_cairo_clip_copy_path (const cairo_clip_t *clip)
179
 
{
180
 
    cairo_clip_t *copy;
181
 
 
182
 
    if (clip == NULL || _cairo_clip_is_all_clipped (clip))
183
 
        return (cairo_clip_t *) clip;
184
 
 
185
 
    assert (clip->num_boxes);
186
 
 
187
 
    copy = _cairo_clip_create ();
188
 
    copy->extents = clip->extents;
189
 
    if (clip->path)
190
 
        copy->path = _cairo_clip_path_reference (clip->path);
191
 
 
192
 
    return copy;
193
 
}
194
 
 
195
 
cairo_clip_t *
196
 
_cairo_clip_copy_region (const cairo_clip_t *clip)
197
 
{
198
 
    cairo_clip_t *copy;
199
 
    int i;
200
 
 
201
 
    if (clip == NULL || _cairo_clip_is_all_clipped (clip))
202
 
        return (cairo_clip_t *) clip;
203
 
 
204
 
    assert (clip->num_boxes);
205
 
 
206
 
    copy = _cairo_clip_create ();
207
 
    copy->extents = clip->extents;
208
 
 
209
 
    if (clip->num_boxes == 1) {
210
 
        copy->boxes = &copy->embedded_box;
211
 
    } else {
212
 
        copy->boxes = _cairo_malloc_ab (clip->num_boxes, sizeof (cairo_box_t));
213
 
        if (unlikely (copy->boxes == NULL))
214
 
            return _cairo_clip_set_all_clipped (copy);
215
 
    }
216
 
 
217
 
    for (i = 0; i < clip->num_boxes; i++) {
218
 
        copy->boxes[i].p1.x = _cairo_fixed_floor (clip->boxes[i].p1.x);
219
 
        copy->boxes[i].p1.y = _cairo_fixed_floor (clip->boxes[i].p1.y);
220
 
        copy->boxes[i].p2.x = _cairo_fixed_ceil (clip->boxes[i].p2.x);
221
 
        copy->boxes[i].p2.y = _cairo_fixed_ceil (clip->boxes[i].p2.y);
222
 
    }
223
 
    copy->num_boxes = clip->num_boxes;
224
 
 
225
 
    copy->region = cairo_region_reference (clip->region);
226
 
    copy->is_region = TRUE;
227
 
 
228
 
    return copy;
229
 
}
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
 
{
238
 
    cairo_clip_path_t *clip_path;
239
 
    cairo_status_t status;
240
 
    cairo_rectangle_int_t extents;
241
 
    cairo_box_t box;
242
 
 
243
 
    if (_cairo_clip_is_all_clipped (clip))
244
 
        return clip;
245
 
 
246
 
    /* catch the empty clip path */
247
 
    if (_cairo_path_fixed_fill_is_empty (path))
248
 
        return _cairo_clip_set_all_clipped (clip);
249
 
 
250
 
    if (_cairo_path_fixed_is_box (path, &box)) {
251
 
        if (antialias == CAIRO_ANTIALIAS_NONE) {
252
 
            box.p1.x = _cairo_fixed_round_down (box.p1.x);
253
 
            box.p1.y = _cairo_fixed_round_down (box.p1.y);
254
 
            box.p2.x = _cairo_fixed_round_down (box.p2.x);
255
 
            box.p2.y = _cairo_fixed_round_down (box.p2.y);
256
 
        }
257
 
 
258
 
        return _cairo_clip_intersect_box (clip, &box);
259
 
    }
260
 
    if (_cairo_path_fixed_fill_is_rectilinear (path))
261
 
        return _cairo_clip_intersect_rectilinear_path (clip, path,
262
 
                                                       fill_rule, antialias);
263
 
 
264
 
    _cairo_path_fixed_approximate_clip_extents (path, &extents);
265
 
    if (extents.width == 0 || extents.height == 0)
266
 
        return _cairo_clip_set_all_clipped (clip);
267
 
 
268
 
    clip = _cairo_clip_intersect_rectangle (clip, &extents);
269
 
    if (_cairo_clip_is_all_clipped (clip))
270
 
        return clip;
271
 
 
272
 
    clip_path = _cairo_clip_path_create (clip);
273
 
    if (unlikely (clip_path == NULL))
274
 
        return _cairo_clip_set_all_clipped (clip);
275
 
 
276
 
    status = _cairo_path_fixed_init_copy (&clip_path->path, path);
277
 
    if (unlikely (status))
278
 
        return _cairo_clip_set_all_clipped (clip);
279
 
 
280
 
    clip_path->fill_rule = fill_rule;
281
 
    clip_path->tolerance = tolerance;
282
 
    clip_path->antialias = antialias;
283
 
 
284
 
    if (clip->region) {
285
 
        cairo_region_destroy (clip->region);
286
 
        clip->region = NULL;
287
 
    }
288
 
 
289
 
    clip->is_region = FALSE;
290
 
    return clip;
291
 
}
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
 
{
297
 
    if (clip_path->prev)
298
 
        clip = _cairo_clip_intersect_clip_path (clip, clip_path->prev);
299
 
 
300
 
    return _cairo_clip_intersect_path (clip,
301
 
                                       &clip_path->path,
302
 
                                       clip_path->fill_rule,
303
 
                                       clip_path->tolerance,
304
 
                                       clip_path->antialias);
305
 
}
306
 
 
307
 
cairo_clip_t *
308
 
_cairo_clip_intersect_clip (cairo_clip_t *clip,
309
 
                            const cairo_clip_t *other)
310
 
{
311
 
    if (_cairo_clip_is_all_clipped (clip))
312
 
        return clip;
313
 
 
314
 
    if (other == NULL)
315
 
        return clip;
316
 
 
317
 
    if (clip == NULL)
318
 
        return _cairo_clip_copy (other);
319
 
 
320
 
    if (_cairo_clip_is_all_clipped (other))
321
 
        return _cairo_clip_set_all_clipped (clip);
322
 
 
323
 
    if (! _cairo_rectangle_intersect (&clip->extents, &other->extents))
324
 
        return _cairo_clip_set_all_clipped (clip);
325
 
 
326
 
    if (other->num_boxes) {
327
 
        cairo_boxes_t boxes;
328
 
 
329
 
        _cairo_boxes_init_for_array (&boxes, other->boxes, other->num_boxes);
330
 
        clip = _cairo_clip_intersect_boxes (clip, &boxes);
331
 
    }
332
 
 
333
 
    if (! _cairo_clip_is_all_clipped (clip)) {
334
 
        if (other->path) {
335
 
            if (clip->path == NULL)
336
 
                clip->path = _cairo_clip_path_reference (other->path);
337
 
            else
338
 
                clip = _cairo_clip_intersect_clip_path (clip, other->path);
339
 
        }
340
 
    }
341
 
 
342
 
    if (clip->region) {
343
 
        cairo_region_destroy (clip->region);
344
 
        clip->region = NULL;
345
 
    }
346
 
    clip->is_region = FALSE;
347
 
 
348
 
    return clip;
349
 
}
350
 
 
351
 
cairo_bool_t
352
 
_cairo_clip_equal (const cairo_clip_t *clip_a,
353
 
                   const cairo_clip_t *clip_b)
354
 
{
355
 
    const cairo_clip_path_t *cp_a, *cp_b;
356
 
 
357
 
    /* are both all-clipped or no-clip? */
358
 
    if (clip_a == clip_b)
359
 
        return TRUE;
360
 
 
361
 
    /* or just one of them? */
362
 
    if (clip_a == NULL || clip_b == NULL ||
363
 
        _cairo_clip_is_all_clipped (clip_a) ||
364
 
        _cairo_clip_is_all_clipped (clip_b))
365
 
    {
366
 
        return FALSE;
367
 
    }
368
 
 
369
 
    /* We have a pair of normal clips, check their contents */
370
 
 
371
 
    if (clip_a->num_boxes != clip_b->num_boxes)
372
 
        return FALSE;
373
 
 
374
 
    if (memcmp (clip_a->boxes, clip_b->boxes,
375
 
                sizeof (cairo_box_t) * clip_a->num_boxes))
376
 
        return FALSE;
377
 
 
378
 
    cp_a = clip_a->path;
379
 
    cp_b = clip_b->path;
380
 
    while (cp_a && cp_b) {
381
 
        if (cp_a == cp_b)
382
 
            return TRUE;
383
 
 
384
 
        /* XXX compare reduced polygons? */
385
 
 
386
 
        if (cp_a->antialias != cp_b->antialias)
387
 
            return FALSE;
388
 
 
389
 
        if (cp_a->tolerance != cp_b->tolerance)
390
 
            return FALSE;
391
 
 
392
 
        if (cp_a->fill_rule != cp_b->fill_rule)
393
 
            return FALSE;
394
 
 
395
 
        if (! _cairo_path_fixed_equal (&cp_a->path,
396
 
                                       &cp_b->path))
397
 
            return FALSE;
398
 
 
399
 
        cp_a = cp_a->prev;
400
 
        cp_b = cp_b->prev;
401
 
    }
402
 
 
403
 
    return cp_a == NULL && cp_b == NULL;
404
 
}
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
 
{
411
 
    cairo_status_t status;
412
 
    cairo_clip_path_t *clip_path;
413
 
 
414
 
    if (other_path->prev != NULL)
415
 
        clip = _cairo_clip_path_copy_with_translation (clip, other_path->prev,
416
 
                                                       fx, fy);
417
 
    if (_cairo_clip_is_all_clipped (clip))
418
 
        return clip;
419
 
 
420
 
    clip_path = _cairo_clip_path_create (clip);
421
 
    if (unlikely (clip_path == NULL))
422
 
        return _cairo_clip_set_all_clipped (clip);
423
 
 
424
 
    status = _cairo_path_fixed_init_copy (&clip_path->path,
425
 
                                          &other_path->path);
426
 
    if (unlikely (status))
427
 
        return _cairo_clip_set_all_clipped (clip);
428
 
 
429
 
    _cairo_path_fixed_translate (&clip_path->path, fx, fy);
430
 
 
431
 
    clip_path->fill_rule = other_path->fill_rule;
432
 
    clip_path->tolerance = other_path->tolerance;
433
 
    clip_path->antialias = other_path->antialias;
434
 
 
435
 
    return clip;
436
 
}
437
 
 
438
 
cairo_clip_t *
439
 
_cairo_clip_translate (cairo_clip_t *clip, int tx, int ty)
440
 
{
441
 
    int fx, fy, i;
442
 
    cairo_clip_path_t *clip_path;
443
 
 
444
 
    if (clip == NULL || _cairo_clip_is_all_clipped (clip))
445
 
        return clip;
446
 
 
447
 
    if (tx == 0 && ty == 0)
448
 
        return clip;
449
 
 
450
 
    fx = _cairo_fixed_from_int (tx);
451
 
    fy = _cairo_fixed_from_int (ty);
452
 
 
453
 
    for (i = 0; i < clip->num_boxes; i++) {
454
 
        clip->boxes[i].p1.x += fx;
455
 
        clip->boxes[i].p2.x += fx;
456
 
        clip->boxes[i].p1.y += fy;
457
 
        clip->boxes[i].p2.y += fy;
458
 
    }
459
 
 
460
 
    clip->extents.x += tx;
461
 
    clip->extents.y += ty;
462
 
 
463
 
    if (clip->path == NULL)
464
 
        return clip;
465
 
 
466
 
    clip_path = clip->path;
467
 
    clip->path = NULL;
468
 
    clip = _cairo_clip_path_copy_with_translation (clip, clip_path, fx, fy);
469
 
    _cairo_clip_path_destroy (clip_path);
470
 
 
471
 
    return clip;
472
 
}
473
 
 
474
 
static cairo_status_t
475
 
_cairo_path_fixed_add_box (cairo_path_fixed_t *path,
476
 
                           const cairo_box_t *box)
477
 
{
478
 
    cairo_status_t status;
479
 
 
480
 
    status = _cairo_path_fixed_move_to (path, box->p1.x, box->p1.y);
481
 
    if (unlikely (status))
482
 
        return status;
483
 
 
484
 
    status = _cairo_path_fixed_line_to (path, box->p2.x, box->p1.y);
485
 
    if (unlikely (status))
486
 
        return status;
487
 
 
488
 
    status = _cairo_path_fixed_line_to (path, box->p2.x, box->p2.y);
489
 
    if (unlikely (status))
490
 
        return status;
491
 
 
492
 
    status = _cairo_path_fixed_line_to (path, box->p1.x, box->p2.y);
493
 
    if (unlikely (status))
494
 
        return status;
495
 
 
496
 
    return _cairo_path_fixed_close_path (path);
497
 
}
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
 
{
503
 
    cairo_status_t status;
504
 
    const struct _cairo_boxes_chunk *chunk;
505
 
    int i;
506
 
 
507
 
    _cairo_path_fixed_init (path);
508
 
    if (boxes->num_boxes == 0)
509
 
        return CAIRO_STATUS_SUCCESS;
510
 
 
511
 
    for (chunk = &boxes->chunks; chunk; chunk = chunk->next) {
512
 
        for (i = 0; i < chunk->count; i++) {
513
 
            status = _cairo_path_fixed_add_box (path, &chunk->base[i]);
514
 
            if (unlikely (status)) {
515
 
                _cairo_path_fixed_fini (path);
516
 
                return status;
517
 
            }
518
 
        }
519
 
    }
520
 
 
521
 
    return CAIRO_STATUS_SUCCESS;
522
 
}
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
 
{
529
 
    cairo_path_fixed_t path;
530
 
 
531
 
    if (clip_path->prev)
532
 
        clip = _cairo_clip_intersect_clip_path_transformed (clip,
533
 
                                                            clip_path->prev,
534
 
                                                            m);
535
 
 
536
 
    if (_cairo_path_fixed_init_copy (&path, &clip_path->path))
537
 
        return _cairo_clip_set_all_clipped (clip);
538
 
 
539
 
    _cairo_path_fixed_transform (&path, m);
540
 
 
541
 
    clip =  _cairo_clip_intersect_path (clip,
542
 
                                       &path,
543
 
                                       clip_path->fill_rule,
544
 
                                       clip_path->tolerance,
545
 
                                       clip_path->antialias);
546
 
    _cairo_path_fixed_fini (&path);
547
 
 
548
 
    return clip;
549
 
}
550
 
 
551
 
cairo_clip_t *
552
 
_cairo_clip_transform (cairo_clip_t *clip, const cairo_matrix_t *m)
553
 
{
554
 
    cairo_clip_t *copy;
555
 
 
556
 
    if (clip == NULL || _cairo_clip_is_all_clipped (clip))
557
 
        return clip;
558
 
 
559
 
    if (_cairo_matrix_is_translation (m))
560
 
        return _cairo_clip_translate (clip, m->x0, m->y0);
561
 
 
562
 
    copy = _cairo_clip_create ();
563
 
 
564
 
    if (clip->num_boxes) {
565
 
        cairo_path_fixed_t path;
566
 
        cairo_boxes_t boxes;
567
 
 
568
 
        _cairo_boxes_init_for_array (&boxes, clip->boxes, clip->num_boxes);
569
 
        _cairo_path_fixed_init_from_boxes (&path, &boxes);
570
 
        _cairo_path_fixed_transform (&path, m);
571
 
 
572
 
        copy = _cairo_clip_intersect_path (copy, &path,
573
 
                                           CAIRO_FILL_RULE_WINDING,
574
 
                                           0.1,
575
 
                                           CAIRO_ANTIALIAS_DEFAULT);
576
 
 
577
 
        _cairo_path_fixed_fini (&path);
578
 
    }
579
 
 
580
 
    if (clip->path)
581
 
        copy = _cairo_clip_intersect_clip_path_transformed (copy, clip->path,m);
582
 
 
583
 
    _cairo_clip_destroy (clip);
584
 
    return copy;
585
 
}
586
 
 
587
 
cairo_clip_t *
588
 
_cairo_clip_copy_with_translation (const cairo_clip_t *clip, int tx, int ty)
589
 
{
590
 
    cairo_clip_t *copy;
591
 
    int fx, fy, i;
592
 
 
593
 
    if (clip == NULL || _cairo_clip_is_all_clipped (clip))
594
 
        return (cairo_clip_t *)clip;
595
 
 
596
 
    if (tx == 0 && ty == 0)
597
 
        return _cairo_clip_copy (clip);
598
 
 
599
 
    copy = _cairo_clip_create ();
600
 
    if (copy == NULL)
601
 
            return _cairo_clip_set_all_clipped (copy);
602
 
 
603
 
    fx = _cairo_fixed_from_int (tx);
604
 
    fy = _cairo_fixed_from_int (ty);
605
 
 
606
 
    if (clip->num_boxes) {
607
 
        if (clip->num_boxes == 1) {
608
 
            copy->boxes = &copy->embedded_box;
609
 
        } else {
610
 
            copy->boxes = _cairo_malloc_ab (clip->num_boxes, sizeof (cairo_box_t));
611
 
            if (unlikely (copy->boxes == NULL))
612
 
                return _cairo_clip_set_all_clipped (copy);
613
 
        }
614
 
 
615
 
        for (i = 0; i < clip->num_boxes; i++) {
616
 
            copy->boxes[i].p1.x = clip->boxes[i].p1.x + fx;
617
 
            copy->boxes[i].p2.x = clip->boxes[i].p2.x + fx;
618
 
            copy->boxes[i].p1.y = clip->boxes[i].p1.y + fy;
619
 
            copy->boxes[i].p2.y = clip->boxes[i].p2.y + fy;
620
 
        }
621
 
        copy->num_boxes = clip->num_boxes;
622
 
    }
623
 
 
624
 
    copy->extents = clip->extents;
625
 
    copy->extents.x += tx;
626
 
    copy->extents.y += ty;
627
 
 
628
 
    if (clip->path == NULL)
629
 
        return copy;
630
 
 
631
 
    return _cairo_clip_path_copy_with_translation (copy, clip->path, fx, fy);
632
 
}
633
 
 
634
 
cairo_bool_t
635
 
_cairo_clip_contains_extents (const cairo_clip_t *clip,
636
 
                              const cairo_composite_rectangles_t *extents)
637
 
{
638
 
    const cairo_rectangle_int_t *rect;
639
 
 
640
 
    rect = extents->is_bounded ? &extents->bounded : &extents->unbounded;
641
 
    return _cairo_clip_contains_rectangle (clip, rect);
642
 
}
643
 
 
644
 
void
645
 
_cairo_debug_print_clip (FILE *stream, const cairo_clip_t *clip)
646
 
{
647
 
    int i;
648
 
 
649
 
    if (clip == NULL) {
650
 
        fprintf (stream, "no clip\n");
651
 
        return;
652
 
    }
653
 
 
654
 
    if (_cairo_clip_is_all_clipped (clip)) {
655
 
        fprintf (stream, "clip: all-clipped\n");
656
 
        return;
657
 
    }
658
 
 
659
 
    fprintf (stream, "clip:\n");
660
 
    fprintf (stream, "  extents: (%d, %d) x (%d, %d), is-region? %d",
661
 
             clip->extents.x, clip->extents.y,
662
 
             clip->extents.width, clip->extents.height,
663
 
             clip->is_region);
664
 
 
665
 
    fprintf (stream, "  num_boxes = %d\n", clip->num_boxes);
666
 
    for (i = 0; i < clip->num_boxes; i++) {
667
 
        fprintf (stream, "  [%d] = (%f, %f), (%f, %f)\n", i,
668
 
                 _cairo_fixed_to_double (clip->boxes[i].p1.x),
669
 
                 _cairo_fixed_to_double (clip->boxes[i].p1.y),
670
 
                 _cairo_fixed_to_double (clip->boxes[i].p2.x),
671
 
                 _cairo_fixed_to_double (clip->boxes[i].p2.y));
672
 
    }
673
 
 
674
 
    if (clip->path) {
675
 
        cairo_clip_path_t *clip_path = clip->path;
676
 
        do {
677
 
            fprintf (stream, "path: aa=%d, tolerance=%f, rule=%d: ",
678
 
                     clip_path->antialias,
679
 
                     clip_path->tolerance,
680
 
                     clip_path->fill_rule);
681
 
            _cairo_debug_print_path (stream, &clip_path->path);
682
 
            fprintf (stream, "\n");
683
 
        } while ((clip_path = clip_path->prev) != NULL);
684
 
    }
685
 
}
686
 
 
687
 
const cairo_rectangle_int_t *
688
 
_cairo_clip_get_extents (const cairo_clip_t *clip)
689
 
{
690
 
    if (clip == NULL)
691
 
        return &_cairo_unbounded_rectangle;
692
 
 
693
 
    if (_cairo_clip_is_all_clipped (clip))
694
 
        return &_cairo_empty_rectangle;
695
 
 
696
 
    return &clip->extents;
697
 
}
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
 
{
709
 
    cairo_bool_t is_tight;
710
 
 
711
 
    double x1 = clip_rect->x;
712
 
    double y1 = clip_rect->y;
713
 
    double x2 = clip_rect->x + (int) clip_rect->width;
714
 
    double y2 = clip_rect->y + (int) clip_rect->height;
715
 
 
716
 
    _cairo_gstate_backend_to_user_rectangle (gstate,
717
 
                                             &x1, &y1, &x2, &y2,
718
 
                                             &is_tight);
719
 
 
720
 
    user_rect->x = x1;
721
 
    user_rect->y = y1;
722
 
    user_rect->width  = x2 - x1;
723
 
    user_rect->height = y2 - y1;
724
 
 
725
 
    return is_tight;
726
 
}
727
 
 
728
 
cairo_rectangle_list_t *
729
 
_cairo_rectangle_list_create_in_error (cairo_status_t status)
730
 
{
731
 
    cairo_rectangle_list_t *list;
732
 
 
733
 
    if (status == CAIRO_STATUS_NO_MEMORY)
734
 
        return (cairo_rectangle_list_t*) &_cairo_rectangles_nil;
735
 
    if (status == CAIRO_STATUS_CLIP_NOT_REPRESENTABLE)
736
 
        return (cairo_rectangle_list_t*) &_cairo_rectangles_not_representable;
737
 
 
738
 
    list = malloc (sizeof (*list));
739
 
    if (unlikely (list == NULL)) {
740
 
        status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
741
 
        return (cairo_rectangle_list_t*) &_cairo_rectangles_nil;
742
 
    }
743
 
 
744
 
    list->status = status;
745
 
    list->rectangles = NULL;
746
 
    list->num_rectangles = 0;
747
 
 
748
 
    return list;
749
 
}
750
 
 
751
 
cairo_rectangle_list_t *
752
 
_cairo_clip_copy_rectangle_list (cairo_clip_t *clip, cairo_gstate_t *gstate)
753
 
{
754
 
#define ERROR_LIST(S) _cairo_rectangle_list_create_in_error (_cairo_error (S))
755
 
 
756
 
    cairo_rectangle_list_t *list;
757
 
    cairo_rectangle_t *rectangles = NULL;
758
 
    cairo_region_t *region = NULL;
759
 
    int n_rects = 0;
760
 
    int i;
761
 
 
762
 
    if (clip == NULL)
763
 
        return ERROR_LIST (CAIRO_STATUS_CLIP_NOT_REPRESENTABLE);
764
 
 
765
 
    if (_cairo_clip_is_all_clipped (clip))
766
 
        goto DONE;
767
 
 
768
 
    if (! _cairo_clip_is_region (clip))
769
 
        return ERROR_LIST (CAIRO_STATUS_CLIP_NOT_REPRESENTABLE);
770
 
 
771
 
    region = _cairo_clip_get_region (clip);
772
 
    if (region == NULL)
773
 
        return ERROR_LIST (CAIRO_STATUS_NO_MEMORY);
774
 
 
775
 
    n_rects = cairo_region_num_rectangles (region);
776
 
    if (n_rects) {
777
 
        rectangles = _cairo_malloc_ab (n_rects, sizeof (cairo_rectangle_t));
778
 
        if (unlikely (rectangles == NULL)) {
779
 
            return ERROR_LIST (CAIRO_STATUS_NO_MEMORY);
780
 
        }
781
 
 
782
 
        for (i = 0; i < n_rects; ++i) {
783
 
            cairo_rectangle_int_t clip_rect;
784
 
 
785
 
            cairo_region_get_rectangle (region, i, &clip_rect);
786
 
 
787
 
            if (! _cairo_clip_int_rect_to_user (gstate,
788
 
                                                &clip_rect,
789
 
                                                &rectangles[i]))
790
 
            {
791
 
                free (rectangles);
792
 
                return ERROR_LIST (CAIRO_STATUS_CLIP_NOT_REPRESENTABLE);
793
 
            }
794
 
        }
795
 
    }
796
 
 
797
 
 DONE:
798
 
    list = malloc (sizeof (cairo_rectangle_list_t));
799
 
    if (unlikely (list == NULL)) {
800
 
        free (rectangles);
801
 
        return ERROR_LIST (CAIRO_STATUS_NO_MEMORY);
802
 
    }
803
 
 
804
 
    list->status = CAIRO_STATUS_SUCCESS;
805
 
    list->rectangles = rectangles;
806
 
    list->num_rectangles = n_rects;
807
 
    return list;
808
 
 
809
 
#undef ERROR_LIST
810
 
}
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
 
{
825
 
    if (rectangle_list == NULL || rectangle_list == &_cairo_rectangles_nil ||
826
 
        rectangle_list == &_cairo_rectangles_not_representable)
827
 
        return;
828
 
 
829
 
    free (rectangle_list->rectangles);
830
 
    free (rectangle_list);
831
 
}
832
 
 
833
 
void
834
 
_cairo_clip_reset_static_data (void)
835
 
{
836
 
    _freed_pool_reset (&clip_path_pool);
837
 
    _freed_pool_reset (&clip_pool);
838
 
}