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
2813
_cairo_clip_path_create (cairo_clip_t *clip)
60
{
61
    cairo_clip_path_t *clip_path;
62

            
63
2813
    clip_path = _freed_pool_get (&clip_path_pool);
64
2813
    if (unlikely (clip_path == NULL)) {
65
220
	clip_path = _cairo_calloc (sizeof (cairo_clip_path_t));
66
220
	if (unlikely (clip_path == NULL))
67
	    return NULL;
68
    }
69

            
70
2813
    CAIRO_REFERENCE_COUNT_INIT (&clip_path->ref_count, 1);
71

            
72
2813
    clip_path->prev = clip->path;
73
2813
    clip->path = clip_path;
74

            
75
2813
    return clip_path;
76
}
77

            
78
cairo_clip_path_t *
79
6770
_cairo_clip_path_reference (cairo_clip_path_t *clip_path)
80
{
81
13540
    assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&clip_path->ref_count));
82

            
83
6770
    _cairo_reference_count_inc (&clip_path->ref_count);
84

            
85
6770
    return clip_path;
86
}
87

            
88
void
89
9541
_cairo_clip_path_destroy (cairo_clip_path_t *clip_path)
90
{
91
19082
    assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&clip_path->ref_count));
92

            
93
9541
    if (! _cairo_reference_count_dec_and_test (&clip_path->ref_count))
94
6746
	return;
95

            
96
2795
    _cairo_path_fixed_fini (&clip_path->path);
97

            
98
2795
    if (clip_path->prev != NULL)
99
303
	_cairo_clip_path_destroy (clip_path->prev);
100

            
101
2795
    _freed_pool_put (&clip_path_pool, clip_path);
102
}
103

            
104
cairo_clip_t *
105
2331537
_cairo_clip_create (void)
106
{
107
    cairo_clip_t *clip;
108

            
109
2331537
    clip = _freed_pool_get (&clip_pool);
110
2331537
    if (unlikely (clip == NULL)) {
111
4457
	clip = _cairo_calloc (sizeof (cairo_clip_t));
112
4457
	if (unlikely (clip == NULL))
113
	    return NULL;
114
    }
115

            
116
2331537
    clip->extents = _cairo_unbounded_rectangle;
117

            
118
2331537
    clip->path = NULL;
119
2331537
    clip->boxes = NULL;
120
2331537
    clip->num_boxes = 0;
121
2331537
    clip->region = NULL;
122
2331537
    clip->is_region = FALSE;
123

            
124
2331537
    return clip;
125
}
126

            
127
void
128
2528433
_cairo_clip_destroy (cairo_clip_t *clip)
129
{
130
2528433
    if (clip == NULL || _cairo_clip_is_all_clipped (clip))
131
196938
	return;
132

            
133
2331495
    if (clip->path != NULL)
134
6946
	_cairo_clip_path_destroy (clip->path);
135

            
136
2331495
    if (clip->boxes != &clip->embedded_box)
137
21120
	free (clip->boxes);
138
2331495
    cairo_region_destroy (clip->region);
139

            
140
2331495
    _freed_pool_put (&clip_pool, clip);
141
}
142

            
143
cairo_clip_t *
144
822055
_cairo_clip_copy (const cairo_clip_t *clip)
145
{
146
    cairo_clip_t *copy;
147

            
148
822055
    if (clip == NULL || _cairo_clip_is_all_clipped (clip))
149
438166
	return (cairo_clip_t *) clip;
150

            
151
383889
    copy = _cairo_clip_create ();
152

            
153
383889
    if (clip->path)
154
6623
	copy->path = _cairo_clip_path_reference (clip->path);
155

            
156
383889
    if (clip->num_boxes) {
157
381744
	if (clip->num_boxes == 1) {
158
380006
	    copy->boxes = &copy->embedded_box;
159
	} else {
160
1738
	    copy->boxes = _cairo_malloc_ab (clip->num_boxes, sizeof (cairo_box_t));
161
1738
	    if (unlikely (copy->boxes == NULL))
162
		return _cairo_clip_set_all_clipped (copy);
163
	}
164

            
165
381744
	memcpy (copy->boxes, clip->boxes,
166
381744
		clip->num_boxes * sizeof (cairo_box_t));
167
381744
	copy->num_boxes = clip->num_boxes;
168
    }
169

            
170
383889
    copy->extents = clip->extents;
171
383889
    copy->region = cairo_region_reference (clip->region);
172
383889
    copy->is_region = clip->is_region;
173

            
174
383889
    return copy;
175
}
176

            
177
cairo_clip_t *
178
195573
_cairo_clip_copy_path (const cairo_clip_t *clip)
179
{
180
    cairo_clip_t *copy;
181

            
182
195573
    if (clip == NULL || _cairo_clip_is_all_clipped (clip))
183
	return (cairo_clip_t *) clip;
184

            
185
195573
    assert (clip->num_boxes);
186

            
187
195573
    copy = _cairo_clip_create ();
188
195573
    copy->extents = clip->extents;
189
195573
    if (clip->path)
190
147
	copy->path = _cairo_clip_path_reference (clip->path);
191

            
192
195573
    return copy;
193
}
194

            
195
cairo_clip_t *
196
144
_cairo_clip_copy_region (const cairo_clip_t *clip)
197
{
198
    cairo_clip_t *copy;
199
    int i;
200

            
201
144
    if (clip == NULL || _cairo_clip_is_all_clipped (clip))
202
	return (cairo_clip_t *) clip;
203

            
204
144
    assert (clip->num_boxes);
205

            
206
144
    copy = _cairo_clip_create ();
207
144
    copy->extents = clip->extents;
208

            
209
144
    if (clip->num_boxes == 1) {
210
144
	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
288
    for (i = 0; i < clip->num_boxes; i++) {
218
144
	copy->boxes[i].p1.x = _cairo_fixed_floor (clip->boxes[i].p1.x);
219
144
	copy->boxes[i].p1.y = _cairo_fixed_floor (clip->boxes[i].p1.y);
220
144
	copy->boxes[i].p2.x = _cairo_fixed_ceil (clip->boxes[i].p2.x);
221
144
	copy->boxes[i].p2.y = _cairo_fixed_ceil (clip->boxes[i].p2.y);
222
    }
223
144
    copy->num_boxes = clip->num_boxes;
224

            
225
144
    copy->region = cairo_region_reference (clip->region);
226
144
    copy->is_region = TRUE;
227

            
228
144
    return copy;
229
}
230

            
231
cairo_clip_t *
232
311580
_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
311580
    if (_cairo_clip_is_all_clipped (clip))
244
	return clip;
245

            
246
    /* catch the empty clip path */
247
311580
    if (_cairo_path_fixed_fill_is_empty (path))
248
19
	return _cairo_clip_set_all_clipped (clip);
249

            
250
311561
    if (_cairo_path_fixed_is_box (path, &box)) {
251
307811
	if (antialias == CAIRO_ANTIALIAS_NONE) {
252
1311
	    box.p1.x = _cairo_fixed_round_down (box.p1.x);
253
1311
	    box.p1.y = _cairo_fixed_round_down (box.p1.y);
254
1311
	    box.p2.x = _cairo_fixed_round_down (box.p2.x);
255
1311
	    box.p2.y = _cairo_fixed_round_down (box.p2.y);
256
	}
257

            
258
307811
	return _cairo_clip_intersect_box (clip, &box);
259
    }
260
3750
    if (_cairo_path_fixed_fill_is_rectilinear (path))
261
985
	return _cairo_clip_intersect_rectilinear_path (clip, path,
262
						       fill_rule, antialias);
263

            
264
2765
    _cairo_path_fixed_approximate_clip_extents (path, &extents);
265
2765
    if (extents.width == 0 || extents.height == 0)
266
	return _cairo_clip_set_all_clipped (clip);
267

            
268
2765
    clip = _cairo_clip_intersect_rectangle (clip, &extents);
269
2765
    if (_cairo_clip_is_all_clipped (clip))
270
3
	return clip;
271

            
272
2762
    clip_path = _cairo_clip_path_create (clip);
273
2762
    if (unlikely (clip_path == NULL))
274
	return _cairo_clip_set_all_clipped (clip);
275

            
276
2762
    status = _cairo_path_fixed_init_copy (&clip_path->path, path);
277
2762
    if (unlikely (status))
278
	return _cairo_clip_set_all_clipped (clip);
279

            
280
2762
    clip_path->fill_rule = fill_rule;
281
2762
    clip_path->tolerance = tolerance;
282
2762
    clip_path->antialias = antialias;
283

            
284
2762
    if (clip->region) {
285
	cairo_region_destroy (clip->region);
286
	clip->region = NULL;
287
    }
288

            
289
2762
    clip->is_region = FALSE;
290
2762
    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
370131
_cairo_clip_intersect_clip (cairo_clip_t *clip,
309
			    const cairo_clip_t *other)
310
{
311
370131
    if (_cairo_clip_is_all_clipped (clip))
312
	return clip;
313

            
314
370131
    if (other == NULL)
315
	return clip;
316

            
317
370131
    if (clip == NULL)
318
325521
	return _cairo_clip_copy (other);
319

            
320
44610
    if (_cairo_clip_is_all_clipped (other))
321
	return _cairo_clip_set_all_clipped (clip);
322

            
323
44610
    if (! _cairo_rectangle_intersect (&clip->extents, &other->extents))
324
210
	return _cairo_clip_set_all_clipped (clip);
325

            
326
44400
    if (other->num_boxes) {
327
	cairo_boxes_t boxes;
328

            
329
44400
	_cairo_boxes_init_for_array (&boxes, other->boxes, other->num_boxes);
330
44400
	clip = _cairo_clip_intersect_boxes (clip, &boxes);
331
    }
332

            
333
44400
    if (! _cairo_clip_is_all_clipped (clip)) {
334
44400
	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
44400
    if (clip->region) {
343
	cairo_region_destroy (clip->region);
344
	clip->region = NULL;
345
    }
346
44400
    clip->is_region = FALSE;
347

            
348
44400
    return clip;
349
}
350

            
351
cairo_bool_t
352
100
_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
100
    if (clip_a == clip_b)
359
15
	return TRUE;
360

            
361
    /* or just one of them? */
362
135
    if (clip_a == NULL || clip_b == NULL ||
363
100
	_cairo_clip_is_all_clipped (clip_a) ||
364
50
	_cairo_clip_is_all_clipped (clip_b))
365
    {
366
35
	return FALSE;
367
    }
368

            
369
    /* We have a pair of normal clips, check their contents */
370

            
371
50
    if (clip_a->num_boxes != clip_b->num_boxes)
372
6
	return FALSE;
373

            
374
44
    if (memcmp (clip_a->boxes, clip_b->boxes,
375
44
		sizeof (cairo_box_t) * clip_a->num_boxes))
376
39
	return FALSE;
377

            
378
5
    cp_a = clip_a->path;
379
5
    cp_b = clip_b->path;
380
5
    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
5
    return cp_a == NULL && cp_b == NULL;
404
}
405

            
406
static cairo_clip_t *
407
51
_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
51
    if (other_path->prev != NULL)
415
3
	clip = _cairo_clip_path_copy_with_translation (clip, other_path->prev,
416
						       fx, fy);
417
51
    if (_cairo_clip_is_all_clipped (clip))
418
	return clip;
419

            
420
51
    clip_path = _cairo_clip_path_create (clip);
421
51
    if (unlikely (clip_path == NULL))
422
	return _cairo_clip_set_all_clipped (clip);
423

            
424
51
    status = _cairo_path_fixed_init_copy (&clip_path->path,
425
51
					  &other_path->path);
426
51
    if (unlikely (status))
427
	return _cairo_clip_set_all_clipped (clip);
428

            
429
51
    _cairo_path_fixed_translate (&clip_path->path, fx, fy);
430

            
431
51
    clip_path->fill_rule = other_path->fill_rule;
432
51
    clip_path->tolerance = other_path->tolerance;
433
51
    clip_path->antialias = other_path->antialias;
434

            
435
51
    return clip;
436
}
437

            
438
cairo_clip_t *
439
84350
_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
84350
    if (clip == NULL || _cairo_clip_is_all_clipped (clip))
445
	return clip;
446

            
447
84350
    if (tx == 0 && ty == 0)
448
84206
	return clip;
449

            
450
144
    fx = _cairo_fixed_from_int (tx);
451
144
    fy = _cairo_fixed_from_int (ty);
452

            
453
300
    for (i = 0; i < clip->num_boxes; i++) {
454
156
	clip->boxes[i].p1.x += fx;
455
156
	clip->boxes[i].p2.x += fx;
456
156
	clip->boxes[i].p1.y += fy;
457
156
	clip->boxes[i].p2.y += fy;
458
    }
459

            
460
144
    clip->extents.x += tx;
461
144
    clip->extents.y += ty;
462

            
463
144
    if (clip->path == NULL)
464
102
	return clip;
465

            
466
42
    clip_path = clip->path;
467
42
    clip->path = NULL;
468
42
    clip = _cairo_clip_path_copy_with_translation (clip, clip_path, fx, fy);
469
42
    _cairo_clip_path_destroy (clip_path);
470

            
471
42
    return clip;
472
}
473

            
474
static cairo_status_t
475
5052
_cairo_path_fixed_add_box (cairo_path_fixed_t *path,
476
			   const cairo_box_t *box)
477
{
478
    cairo_status_t status;
479

            
480
5052
    status = _cairo_path_fixed_move_to (path, box->p1.x, box->p1.y);
481
5052
    if (unlikely (status))
482
	return status;
483

            
484
5052
    status = _cairo_path_fixed_line_to (path, box->p2.x, box->p1.y);
485
5052
    if (unlikely (status))
486
	return status;
487

            
488
5052
    status = _cairo_path_fixed_line_to (path, box->p2.x, box->p2.y);
489
5052
    if (unlikely (status))
490
	return status;
491

            
492
5052
    status = _cairo_path_fixed_line_to (path, box->p1.x, box->p2.y);
493
5052
    if (unlikely (status))
494
	return status;
495

            
496
5052
    return _cairo_path_fixed_close_path (path);
497
}
498

            
499
static cairo_status_t
500
5052
_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
5052
    _cairo_path_fixed_init (path);
508
5052
    if (boxes->num_boxes == 0)
509
	return CAIRO_STATUS_SUCCESS;
510

            
511
10104
    for (chunk = &boxes->chunks; chunk; chunk = chunk->next) {
512
10104
	for (i = 0; i < chunk->count; i++) {
513
5052
	    status = _cairo_path_fixed_add_box (path, &chunk->base[i]);
514
5052
	    if (unlikely (status)) {
515
		_cairo_path_fixed_fini (path);
516
		return status;
517
	    }
518
	}
519
    }
520

            
521
5052
    return CAIRO_STATUS_SUCCESS;
522
}
523

            
524
static cairo_clip_t *
525
1065
_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
1065
    if (clip_path->prev)
532
	clip = _cairo_clip_intersect_clip_path_transformed (clip,
533
							    clip_path->prev,
534
							    m);
535

            
536
1065
    if (_cairo_path_fixed_init_copy (&path, &clip_path->path))
537
	return _cairo_clip_set_all_clipped (clip);
538

            
539
1065
    _cairo_path_fixed_transform (&path, m);
540

            
541
1065
    clip =  _cairo_clip_intersect_path (clip,
542
				       &path,
543
1065
				       clip_path->fill_rule,
544
1065
				       clip_path->tolerance,
545
1065
				       clip_path->antialias);
546
1065
    _cairo_path_fixed_fini (&path);
547

            
548
1065
    return clip;
549
}
550

            
551
cairo_clip_t *
552
417924
_cairo_clip_transform (cairo_clip_t *clip, const cairo_matrix_t *m)
553
{
554
    cairo_clip_t *copy;
555

            
556
417924
    if (clip == NULL || _cairo_clip_is_all_clipped (clip))
557
328522
	return clip;
558

            
559
89402
    if (_cairo_matrix_is_translation (m))
560
84350
	return _cairo_clip_translate (clip, m->x0, m->y0);
561

            
562
5052
    copy = _cairo_clip_create ();
563

            
564
5052
    if (clip->num_boxes) {
565
	cairo_path_fixed_t path;
566
	cairo_boxes_t boxes;
567

            
568
5052
	_cairo_boxes_init_for_array (&boxes, clip->boxes, clip->num_boxes);
569
5052
	_cairo_path_fixed_init_from_boxes (&path, &boxes);
570
5052
	_cairo_path_fixed_transform (&path, m);
571

            
572
5052
	copy = _cairo_clip_intersect_path (copy, &path,
573
					   CAIRO_FILL_RULE_WINDING,
574
					   0.1,
575
					   CAIRO_ANTIALIAS_DEFAULT);
576

            
577
5052
	_cairo_path_fixed_fini (&path);
578
    }
579

            
580
5052
    if (clip->path)
581
1065
	copy = _cairo_clip_intersect_clip_path_transformed (copy, clip->path,m);
582

            
583
5052
    _cairo_clip_destroy (clip);
584
5052
    return copy;
585
}
586

            
587
cairo_clip_t *
588
734
_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
734
    if (clip == NULL || _cairo_clip_is_all_clipped (clip))
594
296
	return (cairo_clip_t *)clip;
595

            
596
438
    if (tx == 0 && ty == 0)
597
78
	return _cairo_clip_copy (clip);
598

            
599
360
    copy = _cairo_clip_create ();
600
360
    if (copy == NULL)
601
	    return _cairo_clip_set_all_clipped (copy);
602

            
603
360
    fx = _cairo_fixed_from_int (tx);
604
360
    fy = _cairo_fixed_from_int (ty);
605

            
606
360
    if (clip->num_boxes) {
607
360
	if (clip->num_boxes == 1) {
608
231
	    copy->boxes = &copy->embedded_box;
609
	} else {
610
129
	    copy->boxes = _cairo_malloc_ab (clip->num_boxes, sizeof (cairo_box_t));
611
129
	    if (unlikely (copy->boxes == NULL))
612
		return _cairo_clip_set_all_clipped (copy);
613
	}
614

            
615
1107
	for (i = 0; i < clip->num_boxes; i++) {
616
747
	    copy->boxes[i].p1.x = clip->boxes[i].p1.x + fx;
617
747
	    copy->boxes[i].p2.x = clip->boxes[i].p2.x + fx;
618
747
	    copy->boxes[i].p1.y = clip->boxes[i].p1.y + fy;
619
747
	    copy->boxes[i].p2.y = clip->boxes[i].p2.y + fy;
620
	}
621
360
	copy->num_boxes = clip->num_boxes;
622
    }
623

            
624
360
    copy->extents = clip->extents;
625
360
    copy->extents.x += tx;
626
360
    copy->extents.y += ty;
627

            
628
360
    if (clip->path == NULL)
629
354
	return copy;
630

            
631
6
    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
2741977
_cairo_clip_get_extents (const cairo_clip_t *clip)
689
{
690
2741977
    if (clip == NULL)
691
	return &_cairo_unbounded_rectangle;
692

            
693
2741977
    if (_cairo_clip_is_all_clipped (clip))
694
1
	return &_cairo_empty_rectangle;
695

            
696
2741976
    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
7
_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
7
    double x1 = clip_rect->x;
712
7
    double y1 = clip_rect->y;
713
7
    double x2 = clip_rect->x + (int) clip_rect->width;
714
7
    double y2 = clip_rect->y + (int) clip_rect->height;
715

            
716
7
    _cairo_gstate_backend_to_user_rectangle (gstate,
717
					     &x1, &y1, &x2, &y2,
718
					     &is_tight);
719

            
720
7
    user_rect->x = x1;
721
7
    user_rect->y = y1;
722
7
    user_rect->width  = x2 - x1;
723
7
    user_rect->height = y2 - y1;
724

            
725
7
    return is_tight;
726
}
727

            
728
cairo_rectangle_list_t *
729
7
_cairo_rectangle_list_create_in_error (cairo_status_t status)
730
{
731
    cairo_rectangle_list_t *list;
732

            
733
7
    if (status == CAIRO_STATUS_NO_MEMORY)
734
	return (cairo_rectangle_list_t*) &_cairo_rectangles_nil;
735
7
    if (status == CAIRO_STATUS_CLIP_NOT_REPRESENTABLE)
736
2
	return (cairo_rectangle_list_t*) &_cairo_rectangles_not_representable;
737

            
738
5
    list = _cairo_calloc (sizeof (*list));
739
5
    if (unlikely (list == NULL)) {
740
	status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
741
	return (cairo_rectangle_list_t*) &_cairo_rectangles_nil;
742
    }
743

            
744
5
    list->status = status;
745
5
    list->rectangles = NULL;
746
5
    list->num_rectangles = 0;
747

            
748
5
    return list;
749
}
750

            
751
cairo_rectangle_list_t *
752
15
_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
15
    cairo_rectangle_t *rectangles = NULL;
758
15
    cairo_region_t *region = NULL;
759
15
    int n_rects = 0;
760
    int i;
761

            
762
15
    if (clip == NULL)
763
	return ERROR_LIST (CAIRO_STATUS_CLIP_NOT_REPRESENTABLE);
764

            
765
15
    if (_cairo_clip_is_all_clipped (clip))
766
7
	goto DONE;
767

            
768
8
    if (! _cairo_clip_is_region (clip))
769
2
	return ERROR_LIST (CAIRO_STATUS_CLIP_NOT_REPRESENTABLE);
770

            
771
6
    region = _cairo_clip_get_region (clip);
772
6
    if (region == NULL)
773
	return ERROR_LIST (CAIRO_STATUS_NO_MEMORY);
774

            
775
6
    n_rects = cairo_region_num_rectangles (region);
776
6
    if (n_rects) {
777
6
	rectangles = _cairo_calloc_ab (n_rects, sizeof (cairo_rectangle_t));
778
6
	if (unlikely (rectangles == NULL)) {
779
	    return ERROR_LIST (CAIRO_STATUS_NO_MEMORY);
780
	}
781

            
782
13
	for (i = 0; i < n_rects; ++i) {
783
	    cairo_rectangle_int_t clip_rect;
784

            
785
7
	    cairo_region_get_rectangle (region, i, &clip_rect);
786

            
787
7
	    if (! _cairo_clip_int_rect_to_user (gstate,
788
						&clip_rect,
789
7
						&rectangles[i]))
790
	    {
791
		free (rectangles);
792
		return ERROR_LIST (CAIRO_STATUS_CLIP_NOT_REPRESENTABLE);
793
	    }
794
	}
795
    }
796

            
797
6
 DONE:
798
13
    list = _cairo_calloc (sizeof (cairo_rectangle_list_t));
799
13
    if (unlikely (list == NULL)) {
800
        free (rectangles);
801
	return ERROR_LIST (CAIRO_STATUS_NO_MEMORY);
802
    }
803

            
804
13
    list->status = CAIRO_STATUS_SUCCESS;
805
13
    list->rectangles = rectangles;
806
13
    list->num_rectangles = n_rects;
807
13
    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
20
cairo_rectangle_list_destroy (cairo_rectangle_list_t *rectangle_list)
824
{
825
20
    if (rectangle_list == NULL || rectangle_list == &_cairo_rectangles_nil ||
826
        rectangle_list == &_cairo_rectangles_not_representable)
827
2
        return;
828

            
829
18
    free (rectangle_list->rectangles);
830
18
    free (rectangle_list);
831
}
832

            
833
void
834
608
_cairo_clip_reset_static_data (void)
835
{
836
608
    _freed_pool_reset (&clip_path_pool);
837
608
    _freed_pool_reset (&clip_pool);
838
608
}