Subversion Repositories Scribus

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
14952 fschmid 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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-private.h"
44
#include "cairo-path-fixed-private.h"
45
#include "cairo-region-private.h"
46
 
47
/* Keep a stash of recently freed clip_paths, since we need to
48
 * reallocate them frequently.
49
 */
50
#define MAX_FREED_POOL_SIZE 4
51
typedef struct {
52
    void *pool[MAX_FREED_POOL_SIZE];
53
    int top;
54
} freed_pool_t;
55
 
56
static freed_pool_t clip_path_pool;
57
 
58
static void *
59
_atomic_fetch (void **slot)
60
{
61
    return _cairo_atomic_ptr_cmpxchg (slot, *slot, NULL);
62
}
63
 
64
static cairo_bool_t
65
_atomic_store (void **slot, void *ptr)
66
{
67
    return _cairo_atomic_ptr_cmpxchg (slot, NULL, ptr) == NULL;
68
}
69
 
70
static void *
71
_freed_pool_get (freed_pool_t *pool)
72
{
73
    void *ptr;
74
    int i;
75
 
76
    i = pool->top - 1;
77
    if (i < 0)
78
        i = 0;
79
 
80
    ptr = _atomic_fetch (&pool->pool[i]);
81
    if (ptr != NULL) {
82
        pool->top = i;
83
        return ptr;
84
    }
85
 
86
    /* either empty or contended */
87
    for (i = ARRAY_LENGTH (pool->pool); i--;) {
88
        ptr = _atomic_fetch (&pool->pool[i]);
89
        if (ptr != NULL) {
90
            pool->top = i;
91
            return ptr;
92
        }
93
    }
94
 
95
    /* empty */
96
    pool->top = 0;
97
    return NULL;
98
}
99
 
100
static void
101
_freed_pool_put (freed_pool_t *pool, void *ptr)
102
{
103
    int i = pool->top;
104
 
105
    if (_atomic_store (&pool->pool[i], ptr)) {
106
        pool->top = i + 1;
107
        return;
108
    }
109
 
110
    /* either full or contended */
111
    for (i = 0; i < ARRAY_LENGTH (pool->pool); i++) {
112
        if (_atomic_store (&pool->pool[i], ptr)) {
113
            pool->top = i + 1;
114
            return;
115
        }
116
    }
117
 
118
    /* full */
119
    pool->top = ARRAY_LENGTH (pool->pool);
120
    free (ptr);
121
}
122
 
123
static void
124
_freed_pool_reset (freed_pool_t *pool)
125
{
126
    int i;
127
 
128
    for (i = 0; i < ARRAY_LENGTH (pool->pool); i++) {
129
        free (pool->pool[i]);
130
        pool->pool[i] = NULL;
131
    }
132
}
133
 
134
static cairo_clip_path_t *
135
_cairo_clip_path_create (cairo_clip_t *clip)
136
{
137
    cairo_clip_path_t *clip_path;
138
 
139
    clip_path = _freed_pool_get (&clip_path_pool);
140
    if (unlikely (clip_path == NULL)) {
141
        clip_path = malloc (sizeof (cairo_clip_path_t));
142
        if (unlikely (clip_path == NULL))
143
            return NULL;
144
    }
145
 
146
    CAIRO_REFERENCE_COUNT_INIT (&clip_path->ref_count, 1);
147
 
148
    clip_path->flags = 0;
149
    clip_path->region = NULL;
150
    clip_path->surface = NULL;
151
 
152
    clip_path->prev = clip->path;
153
    clip->path = clip_path;
154
 
155
    return clip_path;
156
}
157
 
158
static cairo_clip_path_t *
159
_cairo_clip_path_reference (cairo_clip_path_t *clip_path)
160
{
161
    if (clip_path == NULL)
162
        return NULL;
163
 
164
    assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&clip_path->ref_count));
165
 
166
    _cairo_reference_count_inc (&clip_path->ref_count);
167
 
168
    return clip_path;
169
}
170
 
171
static void
172
_cairo_clip_path_destroy (cairo_clip_path_t *clip_path)
173
{
174
    assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&clip_path->ref_count));
175
 
176
    if (! _cairo_reference_count_dec_and_test (&clip_path->ref_count))
177
        return;
178
 
179
    _cairo_path_fixed_fini (&clip_path->path);
180
    if (clip_path->region != NULL)
181
        cairo_region_destroy (clip_path->region);
182
    if (clip_path->surface != NULL)
183
        cairo_surface_destroy (clip_path->surface);
184
 
185
    if (clip_path->prev != NULL)
186
        _cairo_clip_path_destroy (clip_path->prev);
187
 
188
    _freed_pool_put (&clip_path_pool, clip_path);
189
}
190
 
191
void
192
_cairo_clip_init (cairo_clip_t *clip)
193
{
194
    clip->all_clipped = FALSE;
195
    clip->path = NULL;
196
}
197
 
198
static void
199
_cairo_clip_set_all_clipped (cairo_clip_t *clip)
200
{
201
    clip->all_clipped = TRUE;
202
    if (clip->path != NULL) {
203
        _cairo_clip_path_destroy (clip->path);
204
        clip->path = NULL;
205
    }
206
}
207
 
208
static cairo_status_t
209
_cairo_clip_intersect_rectangle (cairo_clip_t *clip,
210
                                 const cairo_rectangle_int_t *rect)
211
{
212
    cairo_clip_path_t *clip_path;
213
    cairo_status_t status;
214
 
215
    if (clip->path != NULL) {
216
        cairo_box_t box;
217
 
218
        if (_cairo_path_fixed_is_box (&clip->path->path, &box)) {
219
            if (box.p1.x >= _cairo_fixed_from_int (rect->x) &&
220
                box.p1.y >= _cairo_fixed_from_int (rect->y) &&
221
                box.p2.x <= _cairo_fixed_from_int (rect->x + rect->width) &&
222
                box.p2.y <= _cairo_fixed_from_int (rect->y + rect->height))
223
            {
224
                return CAIRO_STATUS_SUCCESS;
225
            }
226
        }
227
    }
228
 
229
    clip_path = _cairo_clip_path_create (clip);
230
    if (unlikely (clip_path == NULL))
231
        return _cairo_error (CAIRO_STATUS_NO_MEMORY);
232
 
233
    _cairo_path_fixed_init (&clip_path->path);
234
 
235
    status = _cairo_path_fixed_move_to (&clip_path->path,
236
                                        _cairo_fixed_from_int (rect->x),
237
                                        _cairo_fixed_from_int (rect->y));
238
    assert (status == CAIRO_STATUS_SUCCESS);
239
    status = _cairo_path_fixed_rel_line_to (&clip_path->path,
240
                                            _cairo_fixed_from_int (rect->width),
241
                                            _cairo_fixed_from_int (0));
242
    assert (status == CAIRO_STATUS_SUCCESS);
243
    status = _cairo_path_fixed_rel_line_to (&clip_path->path,
244
                                            _cairo_fixed_from_int (0),
245
                                            _cairo_fixed_from_int (rect->height));
246
    assert (status == CAIRO_STATUS_SUCCESS);
247
    status = _cairo_path_fixed_rel_line_to (&clip_path->path,
248
                                            _cairo_fixed_from_int (-rect->width),
249
                                            _cairo_fixed_from_int (0));
250
    assert (status == CAIRO_STATUS_SUCCESS);
251
    status = _cairo_path_fixed_close_path (&clip_path->path);
252
    assert (status == CAIRO_STATUS_SUCCESS);
253
 
254
    clip_path->extents = *rect;
255
    clip_path->fill_rule = CAIRO_FILL_RULE_WINDING;
256
    clip_path->tolerance = 1;
257
    clip_path->antialias = CAIRO_ANTIALIAS_NONE;
258
 
259
    /* could preallocate the region if it proves worthwhile */
260
 
261
    return CAIRO_STATUS_SUCCESS;
262
}
263
 
264
/* XXX consider accepting a matrix, no users yet. */
265
cairo_status_t
266
_cairo_clip_init_rectangle (cairo_clip_t *clip,
267
                            const cairo_rectangle_int_t *rect)
268
{
269
    _cairo_clip_init (clip);
270
 
271
    if (rect == NULL)
272
        return CAIRO_STATUS_SUCCESS;
273
 
274
    if (rect->width == 0 || rect->height == 0) {
275
        _cairo_clip_set_all_clipped (clip);
276
        return CAIRO_STATUS_SUCCESS;
277
    }
278
 
279
    return _cairo_clip_intersect_rectangle (clip, rect);
280
}
281
 
282
cairo_clip_t *
283
_cairo_clip_init_copy (cairo_clip_t *clip, cairo_clip_t *other)
284
{
285
    if (other != NULL) {
286
        if (other->path == NULL) {
287
            _cairo_clip_init (clip);
288
            clip = NULL;
289
        } else {
290
            clip->all_clipped = other->all_clipped;
291
            clip->path = _cairo_clip_path_reference (other->path);
292
        }
293
    } else {
294
        _cairo_clip_init (clip);
295
    }
296
 
297
    return clip;
298
}
299
 
300
void
301
_cairo_clip_reset (cairo_clip_t *clip)
302
{
303
    clip->all_clipped = FALSE;
304
    if (clip->path != NULL) {
305
        _cairo_clip_path_destroy (clip->path);
306
        clip->path = NULL;
307
    }
308
}
309
 
310
static cairo_status_t
311
_cairo_clip_intersect_path (cairo_clip_t       *clip,
312
                            const cairo_path_fixed_t *path,
313
                            cairo_fill_rule_t   fill_rule,
314
                            double              tolerance,
315
                            cairo_antialias_t   antialias)
316
{
317
    cairo_clip_path_t *clip_path;
318
    cairo_status_t status;
319
    cairo_rectangle_int_t extents;
320
 
321
    if (clip->path != NULL) {
322
        if (clip->path->fill_rule == fill_rule &&
323
            (path->is_rectilinear ||
324
             (tolerance == clip->path->tolerance &&
325
              antialias == clip->path->antialias)) &&
326
            _cairo_path_fixed_equal (&clip->path->path, path))
327
        {
328
            return CAIRO_STATUS_SUCCESS;
329
        }
330
    }
331
 
332
    _cairo_path_fixed_approximate_clip_extents (path, &extents);
333
    if (extents.width == 0 || extents.height == 0) {
334
        _cairo_clip_set_all_clipped (clip);
335
        return CAIRO_STATUS_SUCCESS;
336
    }
337
 
338
    if (clip->path != NULL) {
339
        cairo_box_t box;
340
 
341
        if (! _cairo_rectangle_intersect (&extents, &clip->path->extents)) {
342
            _cairo_clip_set_all_clipped (clip);
343
            return CAIRO_STATUS_SUCCESS;
344
        }
345
 
346
        /* does this clip wholly subsume the others? */
347
        if (_cairo_path_fixed_is_box (path, &box)) {
348
            if (box.p1.x <= _cairo_fixed_from_int (clip->path->extents.x) &&
349
                box.p2.x >= _cairo_fixed_from_int (clip->path->extents.x + clip->path->extents.width) &&
350
                box.p1.y <= _cairo_fixed_from_int (clip->path->extents.y) &&
351
                box.p2.y >= _cairo_fixed_from_int (clip->path->extents.y + clip->path->extents.height))
352
            {
353
                return CAIRO_STATUS_SUCCESS;
354
            }
355
        }
356
    }
357
 
358
    clip_path = _cairo_clip_path_create (clip);
359
    if (unlikely (clip_path == NULL))
360
        return _cairo_error (CAIRO_STATUS_NO_MEMORY);
361
 
362
    status = _cairo_path_fixed_init_copy (&clip_path->path, path);
363
    if (unlikely (status)) {
364
        clip->path = clip->path->prev;
365
        _cairo_clip_path_destroy (clip_path);
366
        return status;
367
    }
368
 
369
    clip_path->extents = extents;
370
    clip_path->fill_rule = fill_rule;
371
    clip_path->tolerance = tolerance;
372
    clip_path->antialias = antialias;
373
 
374
    return CAIRO_STATUS_SUCCESS;
375
}
376
 
377
cairo_status_t
378
_cairo_clip_clip (cairo_clip_t       *clip,
379
                  const cairo_path_fixed_t *path,
380
                  cairo_fill_rule_t   fill_rule,
381
                  double              tolerance,
382
                  cairo_antialias_t   antialias)
383
{
384
    if (clip->all_clipped)
385
        return CAIRO_STATUS_SUCCESS;
386
 
387
    /* catch the empty clip path */
388
    if (_cairo_path_fixed_fill_is_empty (path)) {
389
        _cairo_clip_set_all_clipped (clip);
390
        return CAIRO_STATUS_SUCCESS;
391
    }
392
 
393
    return _cairo_clip_intersect_path (clip,
394
                                       path, fill_rule, tolerance,
395
                                       antialias);
396
}
397
 
398
cairo_status_t
399
_cairo_clip_rectangle (cairo_clip_t       *clip,
400
                       const cairo_rectangle_int_t *rectangle)
401
{
402
    if (clip->all_clipped)
403
        return CAIRO_STATUS_SUCCESS;
404
 
405
    if (rectangle->width == 0 || rectangle->height == 0) {
406
        _cairo_clip_set_all_clipped (clip);
407
        return CAIRO_STATUS_SUCCESS;
408
    }
409
 
410
    /* if a smaller clip has already been set, ignore the new path */
411
    if (clip->path != NULL) {
412
        if (rectangle->x <= clip->path->extents.x &&
413
            rectangle->y <= clip->path->extents.x &&
414
            rectangle->x + rectangle->width >= clip->path->extents.x + clip->path->extents.width &&
415
            rectangle->y + rectangle->height >= clip->path->extents.y + clip->path->extents.height)
416
        {
417
            return CAIRO_STATUS_SUCCESS;
418
        }
419
    }
420
 
421
    return _cairo_clip_intersect_rectangle (clip, rectangle);
422
}
423
 
424
static cairo_status_t
425
_cairo_clip_path_reapply_clip_path_transform (cairo_clip_t      *clip,
426
                                              cairo_clip_path_t *other_path,
427
                                              const cairo_matrix_t *matrix)
428
{
429
    cairo_status_t status;
430
    cairo_clip_path_t *clip_path;
431
    cairo_bool_t is_empty;
432
 
433
    if (other_path->prev != NULL) {
434
        status = _cairo_clip_path_reapply_clip_path_transform (clip,
435
                                                               other_path->prev,
436
                                                               matrix);
437
        if (unlikely (status))
438
            return status;
439
    }
440
 
441
    clip_path = _cairo_clip_path_create (clip);
442
    if (unlikely (clip_path == NULL))
443
        return _cairo_error (CAIRO_STATUS_NO_MEMORY);
444
 
445
    status = _cairo_path_fixed_init_copy (&clip_path->path,
446
                                          &other_path->path);
447
    if (unlikely (status)) {
448
        _cairo_clip_path_destroy (clip_path);
449
        return status;
450
    }
451
 
452
    _cairo_path_fixed_transform (&clip_path->path, matrix);
453
    _cairo_path_fixed_approximate_clip_extents (&clip_path->path,
454
                                                &clip_path->extents);
455
    if (clip_path->prev != NULL) {
456
        is_empty = _cairo_rectangle_intersect (&clip_path->extents,
457
                                               &clip_path->prev->extents);
458
    }
459
 
460
    clip_path->fill_rule = other_path->fill_rule;
461
    clip_path->tolerance = other_path->tolerance;
462
    clip_path->antialias = other_path->antialias;
463
 
464
    return CAIRO_STATUS_SUCCESS;
465
}
466
 
467
static cairo_status_t
468
_cairo_clip_path_reapply_clip_path_translate (cairo_clip_t      *clip,
469
                                              cairo_clip_path_t *other_path,
470
                                              int tx, int ty)
471
{
472
    cairo_status_t status;
473
    cairo_clip_path_t *clip_path;
474
 
475
    if (other_path->prev != NULL) {
476
        status = _cairo_clip_path_reapply_clip_path_translate (clip,
477
                                                               other_path->prev,
478
                                                               tx, ty);
479
        if (unlikely (status))
480
            return status;
481
    }
482
 
483
    clip_path = _cairo_clip_path_create (clip);
484
    if (unlikely (clip_path == NULL))
485
        return _cairo_error (CAIRO_STATUS_NO_MEMORY);
486
 
487
    status = _cairo_path_fixed_init_copy (&clip_path->path,
488
                                          &other_path->path);
489
    if (unlikely (status)) {
490
        _cairo_clip_path_destroy (clip_path);
491
        return status;
492
    }
493
 
494
    _cairo_path_fixed_translate (&clip_path->path,
495
                                 _cairo_fixed_from_int (tx),
496
                                 _cairo_fixed_from_int (ty));
497
 
498
    clip_path->fill_rule = other_path->fill_rule;
499
    clip_path->tolerance = other_path->tolerance;
500
    clip_path->antialias = other_path->antialias;
501
 
502
    clip_path->flags = other_path->flags;
503
    if (other_path->region != NULL) {
504
        clip_path->region = cairo_region_copy (other_path->region);
505
        cairo_region_translate (clip_path->region, tx, ty);
506
    }
507
    clip_path->surface = cairo_surface_reference (other_path->surface);
508
 
509
    clip_path->extents = other_path->extents;
510
    clip_path->extents.x += tx;
511
    clip_path->extents.y += ty;
512
 
513
    return CAIRO_STATUS_SUCCESS;
514
}
515
 
516
cairo_status_t
517
_cairo_clip_init_copy_transformed (cairo_clip_t    *clip,
518
                                   cairo_clip_t    *other,
519
                                   const cairo_matrix_t *matrix)
520
{
521
    cairo_status_t status = CAIRO_STATUS_SUCCESS;
522
    int tx, ty;
523
 
524
    if (other == NULL) {
525
        _cairo_clip_init (clip);
526
        return CAIRO_STATUS_SUCCESS;
527
    }
528
 
529
    if (other->all_clipped) {
530
        _cairo_clip_init (clip);
531
        clip->all_clipped = TRUE;
532
        return CAIRO_STATUS_SUCCESS;
533
    }
534
 
535
    if (_cairo_matrix_is_identity (matrix)) {
536
        _cairo_clip_init_copy (clip, other);
537
        return CAIRO_STATUS_SUCCESS;
538
    }
539
 
540
    if (other->path != NULL) {
541
        _cairo_clip_init (clip);
542
 
543
        /* if we only need to translate, so we can reuse the caches... */
544
        /* XXX we still loose the benefit of constructs when the copy is
545
         * deleted though. Indirect clip_paths?
546
         */
547
        if (_cairo_matrix_is_integer_translation (matrix, &tx, &ty)) {
548
            status = _cairo_clip_path_reapply_clip_path_translate (clip,
549
                                                                   other->path,
550
                                                                   tx, ty);
551
        } else {
552
            status = _cairo_clip_path_reapply_clip_path_transform (clip,
553
                                                                   other->path,
554
                                                                   matrix);
555
            if (clip->path->extents.width == 0 &&
556
                clip->path->extents.height == 0)
557
            {
558
                _cairo_clip_set_all_clipped (clip);
559
            }
560
        }
561
    }
562
 
563
    return status;
564
}
565
 
566
static cairo_status_t
567
_cairo_clip_apply_clip_path (cairo_clip_t *clip,
568
                             const cairo_clip_path_t *path)
569
{
570
    cairo_status_t status;
571
 
572
    if (path->prev != NULL)
573
        status = _cairo_clip_apply_clip_path (clip, path->prev);
574
 
575
    return _cairo_clip_intersect_path (clip,
576
                                       &path->path,
577
                                       path->fill_rule,
578
                                       path->tolerance,
579
                                       path->antialias);
580
}
581
 
582
cairo_status_t
583
_cairo_clip_apply_clip (cairo_clip_t *clip,
584
                        const cairo_clip_t *other)
585
{
586
    cairo_status_t status;
587
 
588
    if (clip->all_clipped)
589
        return CAIRO_STATUS_SUCCESS;
590
 
591
    if (other->all_clipped) {
592
        _cairo_clip_set_all_clipped (clip);
593
        return CAIRO_STATUS_SUCCESS;
594
    }
595
 
596
    status = CAIRO_STATUS_SUCCESS;
597
    if (other->path != NULL)
598
        status = _cairo_clip_apply_clip_path (clip, other->path);
599
 
600
    return status;
601
}
602
 
603
static inline cairo_bool_t
604
_clip_paths_are_rectilinear (cairo_clip_path_t *clip_path)
605
{
606
    while (clip_path != NULL) {
607
        if (! clip_path->path.is_rectilinear)
608
            return FALSE;
609
 
610
        clip_path = clip_path->prev;
611
    }
612
 
613
    return TRUE;
614
}
615
 
616
static cairo_int_status_t
617
_cairo_clip_path_to_region_geometric (cairo_clip_path_t *clip_path)
618
{
619
    cairo_traps_t traps;
620
    cairo_box_t stack_boxes[CAIRO_STACK_ARRAY_LENGTH (cairo_box_t)];
621
    cairo_box_t *boxes = stack_boxes;
622
    cairo_status_t status;
623
    int n;
624
 
625
    /* If we have nothing to intersect with this path, then it cannot
626
     * magically be reduced into a region.
627
     */
628
    if (clip_path->prev == NULL)
629
        goto UNSUPPORTED;
630
 
631
    /* Start simple... Intersect some boxes with an arbitrary path. */
632
    if (! clip_path->path.is_rectilinear)
633
        goto UNSUPPORTED;
634
    if (clip_path->prev->prev != NULL)
635
        goto UNSUPPORTED;
636
 
637
    _cairo_traps_init (&traps);
638
    _cairo_box_from_rectangle (&boxes[0], &clip_path->extents);
639
    _cairo_traps_limit (&traps, boxes, 1);
640
 
641
    status = _cairo_path_fixed_fill_rectilinear_to_traps (&clip_path->path,
642
                                                          clip_path->fill_rule,
643
                                                          &traps);
644
    if (unlikely (_cairo_status_is_error (status)))
645
        return status;
646
    if (status == CAIRO_INT_STATUS_UNSUPPORTED)
647
        goto UNSUPPORTED;
648
 
649
    if (traps.num_traps > ARRAY_LENGTH (stack_boxes)) {
650
        boxes = _cairo_malloc_ab (traps.num_traps, sizeof (cairo_box_t));
651
        if (unlikely (boxes == NULL))
652
            return _cairo_error (CAIRO_STATUS_NO_MEMORY);
653
    }
654
 
655
    for (n = 0; n < traps.num_traps; n++) {
656
        boxes[n].p1.x = traps.traps[n].left.p1.x;
657
        boxes[n].p1.y = traps.traps[n].top;
658
        boxes[n].p2.x = traps.traps[n].right.p1.x;
659
        boxes[n].p2.y = traps.traps[n].bottom;
660
    }
661
 
662
    _cairo_traps_clear (&traps);
663
    _cairo_traps_limit (&traps, boxes, n);
664
    status = _cairo_path_fixed_fill_to_traps (&clip_path->prev->path,
665
                                              clip_path->prev->fill_rule,
666
                                              clip_path->prev->tolerance,
667
                                              &traps);
668
    if (boxes != stack_boxes)
669
        free (boxes);
670
 
671
    if (unlikely (status))
672
        return status;
673
 
674
    status = _cairo_traps_extract_region (&traps, &clip_path->region);
675
    _cairo_traps_fini (&traps);
676
 
677
    if (status == CAIRO_INT_STATUS_UNSUPPORTED)
678
        goto UNSUPPORTED;
679
    if (unlikely (status))
680
        return status;
681
 
682
    clip_path->flags |= CAIRO_CLIP_PATH_HAS_REGION;
683
    return CAIRO_STATUS_SUCCESS;
684
 
685
UNSUPPORTED:
686
    clip_path->flags |= CAIRO_CLIP_PATH_REGION_IS_UNSUPPORTED;
687
    return CAIRO_INT_STATUS_UNSUPPORTED;
688
}
689
 
690
static cairo_int_status_t
691
_cairo_clip_path_to_region (cairo_clip_path_t *clip_path)
692
{
693
    cairo_int_status_t status;
694
    cairo_region_t *prev = NULL;
695
 
696
    if (clip_path->flags &
697
        (CAIRO_CLIP_PATH_HAS_REGION |
698
         CAIRO_CLIP_PATH_REGION_IS_UNSUPPORTED))
699
    {
700
        return clip_path->flags & CAIRO_CLIP_PATH_REGION_IS_UNSUPPORTED ?
701
            CAIRO_INT_STATUS_UNSUPPORTED :
702
            CAIRO_STATUS_SUCCESS;
703
    }
704
 
705
    if (! clip_path->path.maybe_fill_region)
706
        return _cairo_clip_path_to_region_geometric (clip_path);
707
 
708
    /* first retrieve the region for our antecedents */
709
    if (clip_path->prev != NULL) {
710
        status = _cairo_clip_path_to_region (clip_path->prev);
711
        if (status) {
712
            if (status == CAIRO_INT_STATUS_UNSUPPORTED)
713
                return _cairo_clip_path_to_region_geometric (clip_path);
714
 
715
            return status;
716
        }
717
 
718
        prev = clip_path->prev->region;
719
    }
720
 
721
    /* now extract the region for ourselves */
722
    clip_path->region =
723
        _cairo_path_fixed_fill_rectilinear_to_region (&clip_path->path,
724
                                                      clip_path->fill_rule,
725
                                                      &clip_path->extents);
726
    assert (clip_path->region != NULL);
727
 
728
    status = clip_path->region->status;
729
    if (unlikely (status))
730
        return status;
731
 
732
    if (prev != NULL) {
733
        status = cairo_region_intersect (clip_path->region, prev);
734
        if (unlikely (status))
735
            return status;
736
    }
737
 
738
    clip_path->flags |= CAIRO_CLIP_PATH_HAS_REGION;
739
    return CAIRO_STATUS_SUCCESS;
740
}
741
 
742
static inline int
743
pot (int v)
744
{
745
    v--;
746
    v |= v >> 1;
747
    v |= v >> 2;
748
    v |= v >> 4;
749
    v |= v >> 8;
750
    v |= v >> 16;
751
    v++;
752
    return v;
753
}
754
 
755
/* XXX there is likely a faster method! ;-) */
756
static cairo_status_t
757
_region_clip_to_boxes (const cairo_region_t *region,
758
                       cairo_box_t **boxes,
759
                       int *num_boxes,
760
                       int *size_boxes)
761
{
762
    cairo_traps_t traps;
763
    cairo_status_t status;
764
    int n, num_rects;
765
 
766
    _cairo_traps_init (&traps);
767
    _cairo_traps_limit (&traps, *boxes, *num_boxes);
768
    traps.is_rectilinear = TRUE;
769
    traps.is_rectangular = TRUE;
770
 
771
    num_rects = cairo_region_num_rectangles (region);
772
    for (n = 0; n < num_rects; n++) {
773
        cairo_rectangle_int_t rect;
774
        cairo_point_t p1, p2;
775
 
776
        cairo_region_get_rectangle (region, n, &rect);
777
 
778
        p1.x = _cairo_fixed_from_int (rect.x);
779
        p1.y = _cairo_fixed_from_int (rect.y);
780
        p2.x = _cairo_fixed_from_int (rect.x + rect.width);
781
        p2.y = _cairo_fixed_from_int (rect.y + rect.height);
782
 
783
        status = _cairo_traps_tessellate_rectangle (&traps, &p1, &p2);
784
        if (unlikely (status))
785
            goto CLEANUP;
786
    }
787
 
788
    status = _cairo_bentley_ottmann_tessellate_rectangular_traps (&traps, CAIRO_FILL_RULE_WINDING);
789
    if (unlikely (status))
790
        goto CLEANUP;
791
 
792
    n = *size_boxes;
793
    if (n < 0)
794
        n = -n;
795
 
796
    if (traps.num_traps > n) {
797
        cairo_box_t *new_boxes;
798
 
799
        new_boxes = _cairo_malloc_ab (traps.num_traps, sizeof (cairo_box_t));
800
        if (unlikely (new_boxes == NULL)) {
801
            status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
802
            goto CLEANUP;
803
        }
804
 
805
        if (*size_boxes > 0)
806
            free (*boxes);
807
 
808
        *boxes = new_boxes;
809
        *size_boxes = traps.num_traps;
810
    }
811
 
812
    for (n = 0; n < traps.num_traps; n++) {
813
        (*boxes)[n].p1.x = traps.traps[n].left.p1.x;
814
        (*boxes)[n].p1.y = traps.traps[n].top;
815
        (*boxes)[n].p2.x = traps.traps[n].right.p1.x;
816
        (*boxes)[n].p2.y = traps.traps[n].bottom;
817
    }
818
    *num_boxes = n;
819
 
820
  CLEANUP:
821
    _cairo_traps_fini (&traps);
822
 
823
    return status;
824
}
825
 
826
static cairo_status_t
827
_rectilinear_clip_to_boxes (const cairo_path_fixed_t *path,
828
                            cairo_fill_rule_t fill_rule,
829
                            cairo_box_t **boxes,
830
                            int *num_boxes,
831
                            int *size_boxes)
832
{
833
    cairo_polygon_t polygon;
834
    cairo_traps_t traps;
835
    cairo_status_t status;
836
 
837
    _cairo_traps_init (&traps);
838
    _cairo_traps_limit (&traps, *boxes, *num_boxes);
839
 
840
    _cairo_polygon_init (&polygon);
841
    _cairo_polygon_limit (&polygon, *boxes, *num_boxes);
842
 
843
    status = _cairo_path_fixed_fill_rectilinear_to_traps (path,
844
                                                          fill_rule,
845
                                                          &traps);
846
    if (unlikely (_cairo_status_is_error (status)))
847
        goto CLEANUP;
848
    if (status == CAIRO_STATUS_SUCCESS)
849
        goto BOXES;
850
 
851
    /* tolerance will be ignored as the path is rectilinear */
852
    status = _cairo_path_fixed_fill_to_polygon (path, 0., &polygon);
853
    if (unlikely (status))
854
        goto CLEANUP;
855
 
856
    if (polygon.num_edges == 0) {
857
        *num_boxes = 0;
858
    } else {
859
        status = _cairo_bentley_ottmann_tessellate_rectilinear_polygon (&traps,
860
                                                                        &polygon,
861
                                                                        fill_rule);
862
        if (likely (status == CAIRO_STATUS_SUCCESS)) {
863
            int i;
864
 
865
          BOXES:
866
            i = *size_boxes;
867
            if (i < 0)
868
                i = -i;
869
 
870
            if (traps.num_traps > i) {
871
                cairo_box_t *new_boxes;
872
                int new_size;
873
 
874
                new_size = pot (traps.num_traps);
875
                new_boxes = _cairo_malloc_ab (new_size, sizeof (cairo_box_t));
876
                if (unlikely (new_boxes == NULL)) {
877
                    status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
878
                    goto CLEANUP;
879
                }
880
 
881
                if (*size_boxes > 0)
882
                    free (*boxes);
883
 
884
                *boxes = new_boxes;
885
                *size_boxes = new_size;
886
            }
887
 
888
            for (i = 0; i < traps.num_traps; i++) {
889
                (*boxes)[i].p1.x = traps.traps[i].left.p1.x;
890
                (*boxes)[i].p1.y = traps.traps[i].top;
891
                (*boxes)[i].p2.x = traps.traps[i].right.p1.x;
892
                (*boxes)[i].p2.y = traps.traps[i].bottom;
893
            }
894
            *num_boxes = i;
895
        }
896
    }
897
 
898
  CLEANUP:
899
    _cairo_polygon_fini (&polygon);
900
    _cairo_traps_fini (&traps);
901
 
902
    return status;
903
}
904
 
905
static cairo_int_status_t
906
_cairo_clip_path_to_boxes (cairo_clip_path_t *clip_path,
907
                           cairo_box_t **boxes,
908
                           int *count)
909
{
910
    int size = -*count;
911
    int num_boxes = 0;
912
    cairo_status_t status;
913
 
914
    if (clip_path->region != NULL) {
915
        int num_rects, n;
916
 
917
        num_rects = cairo_region_num_rectangles (clip_path->region);
918
        if (num_rects > -size) {
919
            cairo_box_t *new_boxes;
920
 
921
            new_boxes = _cairo_malloc_ab (num_rects, sizeof (cairo_box_t));
922
            if (unlikely (new_boxes == NULL))
923
                return _cairo_error (CAIRO_STATUS_NO_MEMORY);
924
 
925
            *boxes = new_boxes;
926
        }
927
 
928
        for (n = 0; n < num_rects; n++) {
929
            cairo_rectangle_int_t rect;
930
 
931
            cairo_region_get_rectangle (clip_path->region, n, &rect);
932
            (*boxes)[n].p1.x = _cairo_fixed_from_int (rect.x);
933
            (*boxes)[n].p1.y = _cairo_fixed_from_int (rect.y);
934
            (*boxes)[n].p2.x = _cairo_fixed_from_int (rect.x + rect.width);
935
            (*boxes)[n].p2.y = _cairo_fixed_from_int (rect.y + rect.height);
936
        }
937
 
938
        *count = num_rects;
939
        return CAIRO_STATUS_SUCCESS;
940
    }
941
 
942
    /* keep it simple at first */
943
    if (! _clip_paths_are_rectilinear (clip_path))
944
        return CAIRO_INT_STATUS_UNSUPPORTED;
945
 
946
    assert (-size >= 1);
947
    if (_cairo_path_fixed_is_box (&clip_path->path, *boxes)) {
948
        num_boxes = 1;
949
    } else {
950
        status = _rectilinear_clip_to_boxes (&clip_path->path,
951
                                             clip_path->fill_rule,
952
                                             boxes, &num_boxes, &size);
953
        if (unlikely (status))
954
            return status;
955
    }
956
 
957
    while ((clip_path = clip_path->prev) != NULL) {
958
        cairo_box_t box;
959
 
960
        if (clip_path->region != NULL) {
961
            status = _region_clip_to_boxes (clip_path->region,
962
                                            boxes, &num_boxes, &size);
963
            if (unlikely (status))
964
                return status;
965
 
966
            break;
967
        } else if (_cairo_path_fixed_is_box (&clip_path->path, &box)) {
968
            int i, j;
969
 
970
            for (i = j = 0; i < num_boxes; i++) {
971
                if (j != i)
972
                    (*boxes)[j] = (*boxes)[i];
973
 
974
                if (box.p1.x > (*boxes)[j].p1.x)
975
                    (*boxes)[j].p1.x = box.p1.x;
976
                if (box.p2.x < (*boxes)[j].p2.x)
977
                    (*boxes)[j].p2.x = box.p2.x;
978
 
979
                if (box.p1.y > (*boxes)[j].p1.y)
980
                    (*boxes)[j].p1.y = box.p1.y;
981
                if (box.p2.y < (*boxes)[j].p2.y)
982
                    (*boxes)[j].p2.y = box.p2.y;
983
 
984
                j += (*boxes)[j].p2.x > (*boxes)[j].p1.x &&
985
                     (*boxes)[j].p2.y > (*boxes)[j].p1.y;
986
            }
987
 
988
            num_boxes = j;
989
        } else {
990
            status = _rectilinear_clip_to_boxes (&clip_path->path,
991
                                                 clip_path->fill_rule,
992
                                                 boxes, &num_boxes, &size);
993
            if (unlikely (status))
994
                return status;
995
        }
996
 
997
        if (num_boxes == 0)
998
            break;
999
    }
1000
 
1001
    *count = num_boxes;
1002
    return CAIRO_STATUS_SUCCESS;
1003
}
1004
 
1005
static cairo_status_t
1006
_combine_region (cairo_surface_t *surface,
1007
                 const cairo_region_t *region,
1008
                 const cairo_rectangle_int_t *extents)
1009
{
1010
    cairo_region_t clear_region;
1011
    cairo_status_t status;
1012
 
1013
    _cairo_region_init_rectangle (&clear_region, extents);
1014
    status = cairo_region_subtract (&clear_region, region);
1015
    if (unlikely (status))
1016
        return status;
1017
 
1018
    if (! cairo_region_is_empty (&clear_region)) {
1019
        cairo_region_translate (&clear_region, -extents->x, -extents->y);
1020
        status = _cairo_surface_fill_region (surface,
1021
                                             CAIRO_OPERATOR_CLEAR,
1022
                                             CAIRO_COLOR_TRANSPARENT,
1023
                                             &clear_region);
1024
    }
1025
    _cairo_region_fini (&clear_region);
1026
 
1027
    return status;
1028
}
1029
 
1030
static cairo_surface_t *
1031
_cairo_clip_path_get_surface (cairo_clip_path_t *clip_path,
1032
                              cairo_surface_t *target)
1033
{
1034
    cairo_surface_t *surface;
1035
    cairo_pattern_union_t pattern;
1036
    cairo_status_t status;
1037
    const cairo_rectangle_int_t *clip_extents = &clip_path->extents;
1038
    cairo_clip_path_t *prev;
1039
    cairo_bool_t need_translate;
1040
 
1041
    if (clip_path->surface != NULL &&
1042
        clip_path->surface->backend == target->backend)
1043
    {
1044
        return cairo_surface_reference (clip_path->surface);
1045
    }
1046
 
1047
    surface = _cairo_surface_create_similar_solid (target,
1048
                                                   CAIRO_CONTENT_ALPHA,
1049
                                                   clip_extents->width,
1050
                                                   clip_extents->height,
1051
                                                   CAIRO_COLOR_TRANSPARENT,
1052
                                                   FALSE);
1053
    if (surface == NULL) {
1054
        if (clip_path->surface != NULL &&
1055
            clip_path->surface->backend == &_cairo_image_surface_backend)
1056
        {
1057
            return cairo_surface_reference (clip_path->surface);
1058
        }
1059
 
1060
        surface =
1061
            _cairo_image_surface_create_with_content (CAIRO_CONTENT_ALPHA,
1062
                                                      clip_extents->width,
1063
                                                      clip_extents->height);
1064
    }
1065
    if (unlikely (surface->status))
1066
        return surface;
1067
 
1068
    _cairo_pattern_init_solid (&pattern.solid,
1069
                               CAIRO_COLOR_WHITE,
1070
                               CAIRO_CONTENT_COLOR);
1071
 
1072
    status = _cairo_clip_path_to_region (clip_path);
1073
    if (unlikely (_cairo_status_is_error (status)))
1074
        goto BAIL;
1075
 
1076
    need_translate = clip_extents->x | clip_extents->y;
1077
    if (status == CAIRO_STATUS_SUCCESS) {
1078
        if (need_translate) {
1079
            cairo_region_translate (clip_path->region,
1080
                                    -clip_extents->x, -clip_extents->y);
1081
        }
1082
        status = _cairo_surface_fill_region (surface,
1083
                                             CAIRO_OPERATOR_SOURCE,
1084
                                             CAIRO_COLOR_WHITE,
1085
                                             clip_path->region);
1086
        if (need_translate) {
1087
            cairo_region_translate (clip_path->region,
1088
                                    clip_extents->x, clip_extents->y);
1089
        }
1090
        if (unlikely (status))
1091
            goto BAIL;
1092
 
1093
        goto DONE;
1094
    } else {
1095
        if (need_translate) {
1096
            _cairo_path_fixed_translate (&clip_path->path,
1097
                                         _cairo_fixed_from_int (-clip_extents->x),
1098
                                         _cairo_fixed_from_int (-clip_extents->y));
1099
        }
1100
        status = _cairo_surface_fill (surface,
1101
                                      CAIRO_OPERATOR_OVER,
1102
                                      &pattern.base,
1103
                                      &clip_path->path,
1104
                                      clip_path->fill_rule,
1105
                                      clip_path->tolerance,
1106
                                      clip_path->antialias,
1107
                                      NULL);
1108
        if (need_translate) {
1109
            _cairo_path_fixed_translate (&clip_path->path,
1110
                                         _cairo_fixed_from_int (clip_extents->x),
1111
                                         _cairo_fixed_from_int (clip_extents->y));
1112
        }
1113
 
1114
        if (unlikely (status))
1115
            goto BAIL;
1116
    }
1117
 
1118
    prev = clip_path->prev;
1119
  NEXT_PATH:
1120
    if (prev != NULL) {
1121
        status = _cairo_clip_path_to_region (prev);
1122
        if (unlikely (_cairo_status_is_error (status)))
1123
            goto BAIL;
1124
 
1125
        if (status == CAIRO_STATUS_SUCCESS) {
1126
            status = _combine_region (surface, prev->region, clip_extents);
1127
            if (unlikely (status))
1128
                goto BAIL;
1129
        } else if (prev->path.is_rectilinear) {
1130
            if (need_translate) {
1131
                _cairo_path_fixed_translate (&prev->path,
1132
                                             _cairo_fixed_from_int (-clip_extents->x),
1133
                                             _cairo_fixed_from_int (-clip_extents->y));
1134
            }
1135
            status = _cairo_surface_fill (surface,
1136
                                          CAIRO_OPERATOR_IN,
1137
                                          &pattern.base,
1138
                                          &prev->path,
1139
                                          prev->fill_rule,
1140
                                          prev->tolerance,
1141
                                          prev->antialias,
1142
                                          NULL);
1143
            if (need_translate) {
1144
                _cairo_path_fixed_translate (&prev->path,
1145
                                             _cairo_fixed_from_int (clip_extents->x),
1146
                                             _cairo_fixed_from_int (clip_extents->y));
1147
            }
1148
 
1149
            if (unlikely (status))
1150
                goto BAIL;
1151
 
1152
            prev = prev->prev;
1153
            goto NEXT_PATH;
1154
        } else {
1155
            cairo_surface_t *prev_surface;
1156
 
1157
            prev_surface = _cairo_clip_path_get_surface (prev, target);
1158
            _cairo_pattern_init_for_surface (&pattern.surface, prev_surface);
1159
            cairo_surface_destroy (prev_surface);
1160
 
1161
            cairo_matrix_init_translate (&pattern.base.matrix,
1162
                                         -prev->extents.x + clip_extents->x,
1163
                                         -prev->extents.y + clip_extents->y);
1164
            status = _cairo_surface_paint (surface,
1165
                                           CAIRO_OPERATOR_IN,
1166
                                           &pattern.base,
1167
                                           NULL);
1168
            _cairo_pattern_fini (&pattern.base);
1169
 
1170
            if (unlikely (status))
1171
                goto BAIL;
1172
        }
1173
    }
1174
 
1175
  DONE:
1176
    cairo_surface_destroy (clip_path->surface);
1177
    return clip_path->surface = cairo_surface_reference (surface);
1178
 
1179
  BAIL:
1180
    cairo_surface_destroy (surface);
1181
    return _cairo_surface_create_in_error (status);
1182
}
1183
 
1184
void
1185
_cairo_debug_print_clip (FILE *stream, cairo_clip_t *clip)
1186
{
1187
    cairo_clip_path_t *clip_path;
1188
 
1189
    if (clip == NULL) {
1190
        fprintf (stream, "no clip\n");
1191
        return;
1192
    }
1193
 
1194
    if (clip->all_clipped) {
1195
        fprintf (stream, "clip: all-clipped\n");
1196
        return;
1197
    }
1198
 
1199
    if (clip->path == NULL) {
1200
        fprintf (stream, "clip: empty\n");
1201
        return;
1202
    }
1203
 
1204
    fprintf (stream, "clip:\n");
1205
 
1206
    clip_path = clip->path;
1207
    do {
1208
        fprintf (stream, "path: has region? %s, has surface? %s: ",
1209
                 clip_path->region == NULL ? "no" : "yes",
1210
                 clip_path->surface == NULL ? "no" : "yes");
1211
        _cairo_debug_print_path (stream, &clip_path->path);
1212
        fprintf (stream, "\n");
1213
    } while ((clip_path = clip_path->prev) != NULL);
1214
}
1215
 
1216
cairo_surface_t *
1217
_cairo_clip_get_surface (cairo_clip_t *clip, cairo_surface_t *target)
1218
{
1219
    assert (clip->path != NULL);
1220
    return _cairo_clip_path_get_surface (clip->path, target);
1221
}
1222
 
1223
cairo_status_t
1224
_cairo_clip_combine_with_surface (cairo_clip_t *clip,
1225
                                  cairo_surface_t *dst,
1226
                                  const cairo_rectangle_int_t *extents)
1227
{
1228
    cairo_pattern_union_t pattern;
1229
    cairo_clip_path_t *clip_path = clip->path;
1230
    cairo_bool_t need_translate;
1231
    cairo_status_t status;
1232
 
1233
    assert (clip_path != NULL);
1234
 
1235
    if (clip_path->surface != NULL &&
1236
        clip_path->surface->backend == dst->backend)
1237
    {
1238
        _cairo_pattern_init_for_surface (&pattern.surface,
1239
                                         clip_path->surface);
1240
        cairo_matrix_init_translate (&pattern.base.matrix,
1241
                                     extents->x - clip_path->extents.x,
1242
                                     extents->y - clip_path->extents.y);
1243
        status = _cairo_surface_paint (dst,
1244
                                       CAIRO_OPERATOR_IN,
1245
                                       &pattern.base,
1246
                                       NULL);
1247
 
1248
        _cairo_pattern_fini (&pattern.base);
1249
 
1250
        return status;
1251
    }
1252
 
1253
    _cairo_pattern_init_solid (&pattern.solid,
1254
                               CAIRO_COLOR_WHITE,
1255
                               CAIRO_CONTENT_COLOR);
1256
 
1257
    need_translate = extents->x | extents->y;
1258
    do {
1259
        status = _cairo_clip_path_to_region (clip_path);
1260
        if (unlikely (_cairo_status_is_error (status)))
1261
            return status;
1262
 
1263
        if (status == CAIRO_STATUS_SUCCESS)
1264
            return _combine_region (dst, clip_path->region, extents);
1265
 
1266
        if (clip_path->surface != NULL &&
1267
            clip_path->surface->backend == dst->backend)
1268
        {
1269
            _cairo_pattern_init_for_surface (&pattern.surface,
1270
                                             clip_path->surface);
1271
            cairo_matrix_init_translate (&pattern.base.matrix,
1272
                                         extents->x - clip_path->extents.x,
1273
                                         extents->y - clip_path->extents.y);
1274
            status = _cairo_surface_paint (dst,
1275
                                           CAIRO_OPERATOR_IN,
1276
                                           &pattern.base,
1277
                                           NULL);
1278
 
1279
            _cairo_pattern_fini (&pattern.base);
1280
 
1281
            return status;
1282
        }
1283
 
1284
        if (need_translate) {
1285
            _cairo_path_fixed_translate (&clip_path->path,
1286
                                        _cairo_fixed_from_int (-extents->x),
1287
                                        _cairo_fixed_from_int (-extents->y));
1288
        }
1289
        status = _cairo_surface_fill (dst,
1290
                                      CAIRO_OPERATOR_IN,
1291
                                      &pattern.base,
1292
                                      &clip_path->path,
1293
                                      clip_path->fill_rule,
1294
                                      clip_path->tolerance,
1295
                                      clip_path->antialias,
1296
                                      NULL);
1297
        if (need_translate) {
1298
            _cairo_path_fixed_translate (&clip_path->path,
1299
                                        _cairo_fixed_from_int (extents->x),
1300
                                        _cairo_fixed_from_int (extents->y));
1301
        }
1302
 
1303
        if (unlikely (status))
1304
            return status;
1305
    } while ((clip_path = clip_path->prev) != NULL);
1306
 
1307
    return CAIRO_STATUS_SUCCESS;
1308
}
1309
 
1310
const cairo_rectangle_int_t *
1311
_cairo_clip_get_extents (const cairo_clip_t *clip)
1312
{
1313
    if (clip->path == NULL)
1314
        return NULL;
1315
 
1316
    return &clip->path->extents;
1317
}
1318
 
1319
void
1320
_cairo_clip_drop_cache (cairo_clip_t  *clip)
1321
{
1322
    cairo_clip_path_t *clip_path;
1323
 
1324
    if (clip->path == NULL)
1325
        return;
1326
 
1327
    clip_path = clip->path;
1328
    do {
1329
        if (clip_path->region != NULL) {
1330
            cairo_region_destroy (clip_path->region);
1331
            clip_path->region = NULL;
1332
        }
1333
 
1334
        if (clip_path->surface != NULL) {
1335
            cairo_surface_destroy (clip_path->surface);
1336
            clip_path->surface = NULL;
1337
        }
1338
 
1339
        clip_path->flags = 0;
1340
    } while ((clip_path = clip_path->prev) != NULL);
1341
}
1342
 
1343
const cairo_rectangle_list_t _cairo_rectangles_nil =
1344
  { CAIRO_STATUS_NO_MEMORY, NULL, 0 };
1345
static const cairo_rectangle_list_t _cairo_rectangles_not_representable =
1346
  { CAIRO_STATUS_CLIP_NOT_REPRESENTABLE, NULL, 0 };
1347
 
1348
static cairo_bool_t
1349
_cairo_clip_int_rect_to_user (cairo_gstate_t *gstate,
1350
                              cairo_rectangle_int_t *clip_rect,
1351
                              cairo_rectangle_t *user_rect)
1352
{
1353
    cairo_bool_t is_tight;
1354
 
1355
    double x1 = clip_rect->x;
1356
    double y1 = clip_rect->y;
1357
    double x2 = clip_rect->x + (int) clip_rect->width;
1358
    double y2 = clip_rect->y + (int) clip_rect->height;
1359
 
1360
    _cairo_gstate_backend_to_user_rectangle (gstate,
1361
                                             &x1, &y1, &x2, &y2,
1362
                                             &is_tight);
1363
 
1364
    user_rect->x = x1;
1365
    user_rect->y = y1;
1366
    user_rect->width  = x2 - x1;
1367
    user_rect->height = y2 - y1;
1368
 
1369
    return is_tight;
1370
}
1371
 
1372
cairo_int_status_t
1373
_cairo_clip_get_region (cairo_clip_t *clip,
1374
                        cairo_region_t **region)
1375
{
1376
    cairo_int_status_t status;
1377
 
1378
    if (clip->all_clipped)
1379
        goto CLIPPED;
1380
 
1381
    assert (clip->path != NULL);
1382
 
1383
    status = _cairo_clip_path_to_region (clip->path);
1384
    if (status)
1385
        return status;
1386
 
1387
    if (cairo_region_is_empty (clip->path->region)) {
1388
        _cairo_clip_set_all_clipped (clip);
1389
        goto CLIPPED;
1390
    }
1391
 
1392
    if (region)
1393
        *region = clip->path->region;
1394
    return CAIRO_STATUS_SUCCESS;
1395
 
1396
  CLIPPED:
1397
    if (region)
1398
        *region = NULL;
1399
    return CAIRO_INT_STATUS_NOTHING_TO_DO;
1400
}
1401
 
1402
cairo_int_status_t
1403
_cairo_clip_get_boxes (cairo_clip_t *clip,
1404
                       cairo_box_t **boxes,
1405
                       int *count)
1406
{
1407
    cairo_int_status_t status;
1408
 
1409
    if (clip->all_clipped)
1410
        return CAIRO_INT_STATUS_NOTHING_TO_DO;
1411
 
1412
    assert (clip->path != NULL);
1413
 
1414
    status = _cairo_clip_path_to_boxes (clip->path, boxes, count);
1415
    if (status)
1416
        return status;
1417
 
1418
    if (*count == 0) {
1419
        _cairo_clip_set_all_clipped (clip);
1420
        return CAIRO_INT_STATUS_NOTHING_TO_DO;
1421
    }
1422
 
1423
    return CAIRO_STATUS_SUCCESS;
1424
}
1425
 
1426
static cairo_rectangle_list_t *
1427
_cairo_rectangle_list_create_in_error (cairo_status_t status)
1428
{
1429
    cairo_rectangle_list_t *list;
1430
 
1431
    if (status == CAIRO_STATUS_NO_MEMORY)
1432
        return (cairo_rectangle_list_t*) &_cairo_rectangles_nil;
1433
    if (status == CAIRO_STATUS_CLIP_NOT_REPRESENTABLE)
1434
        return (cairo_rectangle_list_t*) &_cairo_rectangles_not_representable;
1435
 
1436
    list = malloc (sizeof (*list));
1437
    if (unlikely (list == NULL)) {
1438
        _cairo_error_throw (status);
1439
        return (cairo_rectangle_list_t*) &_cairo_rectangles_nil;
1440
    }
1441
 
1442
    list->status = status;
1443
    list->rectangles = NULL;
1444
    list->num_rectangles = 0;
1445
 
1446
    return list;
1447
}
1448
 
1449
cairo_rectangle_list_t *
1450
_cairo_clip_copy_rectangle_list (cairo_clip_t *clip, cairo_gstate_t *gstate)
1451
{
1452
#define ERROR_LIST(S) _cairo_rectangle_list_create_in_error (_cairo_error (S));
1453
 
1454
    cairo_rectangle_list_t *list;
1455
    cairo_rectangle_t *rectangles = NULL;
1456
    cairo_region_t *region = NULL;
1457
    cairo_int_status_t status;
1458
    int n_rects = 0;
1459
    int i;
1460
 
1461
    if (clip != NULL && clip->path != NULL) {
1462
        status = _cairo_clip_get_region (clip, &region);
1463
        if (status == CAIRO_INT_STATUS_NOTHING_TO_DO) {
1464
            goto DONE;
1465
        } else if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
1466
            return ERROR_LIST (CAIRO_STATUS_CLIP_NOT_REPRESENTABLE)
1467
        } else if (unlikely (status)) {
1468
            return ERROR_LIST (status);
1469
        }
1470
    }
1471
 
1472
    if (region != NULL) {
1473
        n_rects = cairo_region_num_rectangles (region);
1474
        if (n_rects) {
1475
            rectangles = _cairo_malloc_ab (n_rects, sizeof (cairo_rectangle_t));
1476
            if (unlikely (rectangles == NULL)) {
1477
                return ERROR_LIST (CAIRO_STATUS_NO_MEMORY);
1478
            }
1479
 
1480
            for (i = 0; i < n_rects; ++i) {
1481
                cairo_rectangle_int_t clip_rect;
1482
 
1483
                cairo_region_get_rectangle (region, i, &clip_rect);
1484
 
1485
                if (! _cairo_clip_int_rect_to_user (gstate,
1486
                                                    &clip_rect,
1487
                                                    &rectangles[i]))
1488
                {
1489
                    free (rectangles);
1490
                    return ERROR_LIST (CAIRO_STATUS_CLIP_NOT_REPRESENTABLE);
1491
                }
1492
            }
1493
        }
1494
    } else {
1495
        cairo_rectangle_int_t extents;
1496
 
1497
        if (! _cairo_surface_get_extents (_cairo_gstate_get_target (gstate),
1498
                                          &extents))
1499
        {
1500
            /* unbounded surface -> unclipped */
1501
            goto DONE;
1502
        }
1503
 
1504
        n_rects = 1;
1505
        rectangles = malloc(sizeof (cairo_rectangle_t));
1506
        if (unlikely (rectangles == NULL))
1507
            return ERROR_LIST (CAIRO_STATUS_NO_MEMORY);
1508
 
1509
        if (! _cairo_clip_int_rect_to_user (gstate, &extents, rectangles)) {
1510
            free (rectangles);
1511
            return ERROR_LIST (CAIRO_STATUS_CLIP_NOT_REPRESENTABLE);
1512
        }
1513
    }
1514
 
1515
 DONE:
1516
    list = malloc (sizeof (cairo_rectangle_list_t));
1517
    if (unlikely (list == NULL)) {
1518
        free (rectangles);
1519
        return ERROR_LIST (CAIRO_STATUS_NO_MEMORY);
1520
    }
1521
 
1522
    list->status = CAIRO_STATUS_SUCCESS;
1523
    list->rectangles = rectangles;
1524
    list->num_rectangles = n_rects;
1525
    return list;
1526
 
1527
#undef ERROR_LIST
1528
}
1529
 
1530
/**
1531
 * cairo_rectangle_list_destroy:
1532
 * @rectangle_list: a rectangle list, as obtained from cairo_copy_clip_rectangles()
1533
 *
1534
 * Unconditionally frees @rectangle_list and all associated
1535
 * references. After this call, the @rectangle_list pointer must not
1536
 * be dereferenced.
1537
 *
1538
 * Since: 1.4
1539
 **/
1540
void
1541
cairo_rectangle_list_destroy (cairo_rectangle_list_t *rectangle_list)
1542
{
1543
    if (rectangle_list == NULL || rectangle_list == &_cairo_rectangles_nil ||
1544
        rectangle_list == &_cairo_rectangles_not_representable)
1545
        return;
1546
 
1547
    free (rectangle_list->rectangles);
1548
    free (rectangle_list);
1549
}
1550
 
1551
void
1552
_cairo_clip_reset_static_data (void)
1553
{
1554
    _freed_pool_reset (&clip_path_pool);
1555
}