Subversion Repositories Kolibri OS

Rev

Rev 1892 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
1892 serge 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 
38
 *	Kristian Høgsberg 
39
 *	Chris Wilson 
40
 */
41
 
42
#include "cairoint.h"
3959 Serge 43
#include "cairo-clip-inline.h"
1892 serge 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"
3959 Serge 49
#include "cairo-pattern-private.h"
1892 serge 50
#include "cairo-composite-rectangles-private.h"
51
#include "cairo-region-private.h"
52
 
53
static freed_pool_t clip_path_pool;
3959 Serge 54
static freed_pool_t clip_pool;
1892 serge 55
 
3959 Serge 56
const cairo_clip_t __cairo_clip_all;
57
 
1892 serge 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
 
3959 Serge 78
cairo_clip_path_t *
1892 serge 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
 
3959 Serge 88
void
1892 serge 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
 
3959 Serge 104
cairo_clip_t *
105
_cairo_clip_create (void)
1892 serge 106
{
3959 Serge 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
 
1892 serge 118
    clip->path = NULL;
3959 Serge 119
    clip->boxes = NULL;
120
    clip->num_boxes = 0;
121
    clip->region = NULL;
122
    clip->is_region = FALSE;
123
 
124
    return clip;
1892 serge 125
}
126
 
3959 Serge 127
void
128
_cairo_clip_destroy (cairo_clip_t *clip)
1892 serge 129
{
3959 Serge 130
    if (clip == NULL || _cairo_clip_is_all_clipped (clip))
131
	return;
132
 
133
    if (clip->path != NULL)
1892 serge 134
	_cairo_clip_path_destroy (clip->path);
3959 Serge 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);
1892 serge 141
}
142
 
3959 Serge 143
cairo_clip_t *
144
_cairo_clip_copy (const cairo_clip_t *clip)
1892 serge 145
{
3959 Serge 146
    cairo_clip_t *copy;
1892 serge 147
 
3959 Serge 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 = ©->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);
1892 serge 163
	}
3959 Serge 164
 
165
	memcpy (copy->boxes, clip->boxes,
166
		clip->num_boxes * sizeof (cairo_box_t));
167
	copy->num_boxes = clip->num_boxes;
1892 serge 168
    }
169
 
3959 Serge 170
    copy->extents = clip->extents;
171
    copy->region = cairo_region_reference (clip->region);
172
    copy->is_region = clip->is_region;
1892 serge 173
 
3959 Serge 174
    return copy;
175
}
1892 serge 176
 
3959 Serge 177
cairo_clip_t *
178
_cairo_clip_copy_path (const cairo_clip_t *clip)
179
{
180
    cairo_clip_t *copy;
1892 serge 181
 
3959 Serge 182
    if (clip == NULL || _cairo_clip_is_all_clipped (clip))
183
	return (cairo_clip_t *) clip;
1892 serge 184
 
3959 Serge 185
    assert (clip->num_boxes);
1892 serge 186
 
3959 Serge 187
    copy = _cairo_clip_create ();
188
    copy->extents = clip->extents;
189
    if (clip->path)
190
	copy->path = _cairo_clip_path_reference (clip->path);
1892 serge 191
 
3959 Serge 192
    return copy;
1892 serge 193
}
194
 
195
cairo_clip_t *
3959 Serge 196
_cairo_clip_copy_region (const cairo_clip_t *clip)
1892 serge 197
{
3959 Serge 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 = ©->embedded_box;
1892 serge 211
    } else {
3959 Serge 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);
1892 serge 215
    }
216
 
3959 Serge 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;
1892 serge 224
 
3959 Serge 225
    copy->region = cairo_region_reference (clip->region);
226
    copy->is_region = TRUE;
227
 
228
    return copy;
1892 serge 229
}
230
 
3959 Serge 231
cairo_clip_t *
1892 serge 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
 
3959 Serge 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);
1892 serge 256
	}
3959 Serge 257
 
258
	return _cairo_clip_intersect_box (clip, &box);
1892 serge 259
    }
3959 Serge 260
    if (_cairo_path_fixed_fill_is_rectilinear (path))
261
	return _cairo_clip_intersect_rectilinear_path (clip, path,
262
						       fill_rule, antialias);
1892 serge 263
 
264
    _cairo_path_fixed_approximate_clip_extents (path, &extents);
3959 Serge 265
    if (extents.width == 0 || extents.height == 0)
266
	return _cairo_clip_set_all_clipped (clip);
1892 serge 267
 
3959 Serge 268
    clip = _cairo_clip_intersect_rectangle (clip, &extents);
269
    if (_cairo_clip_is_all_clipped (clip))
270
	return clip;
1892 serge 271
 
272
    clip_path = _cairo_clip_path_create (clip);
273
    if (unlikely (clip_path == NULL))
3959 Serge 274
	return _cairo_clip_set_all_clipped (clip);
1892 serge 275
 
276
    status = _cairo_path_fixed_init_copy (&clip_path->path, path);
3959 Serge 277
    if (unlikely (status))
278
	return _cairo_clip_set_all_clipped (clip);
1892 serge 279
 
280
    clip_path->fill_rule = fill_rule;
281
    clip_path->tolerance = tolerance;
282
    clip_path->antialias = antialias;
283
 
3959 Serge 284
    if (clip->region) {
285
	cairo_region_destroy (clip->region);
286
	clip->region = NULL;
287
    }
288
 
289
    clip->is_region = FALSE;
290
    return clip;
1892 serge 291
}
292
 
3959 Serge 293
static cairo_clip_t *
294
_cairo_clip_intersect_clip_path (cairo_clip_t *clip,
295
				 const cairo_clip_path_t *clip_path)
1892 serge 296
{
3959 Serge 297
    if (clip_path->prev)
298
	clip = _cairo_clip_intersect_clip_path (clip, clip_path->prev);
1892 serge 299
 
3959 Serge 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
}
1892 serge 306
 
3959 Serge 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;
1892 serge 313
 
3959 Serge 314
    if (other == NULL)
315
	return clip;
1892 serge 316
 
3959 Serge 317
    if (clip == NULL)
318
	return _cairo_clip_copy (other);
1892 serge 319
 
3959 Serge 320
    if (_cairo_clip_is_all_clipped (other))
321
	return _cairo_clip_set_all_clipped (clip);
1892 serge 322
 
3959 Serge 323
    if (! _cairo_rectangle_intersect (&clip->extents, &other->extents))
324
	return _cairo_clip_set_all_clipped (clip);
1892 serge 325
 
3959 Serge 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);
1892 serge 331
    }
332
 
3959 Serge 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
    }
1892 serge 341
 
3959 Serge 342
    if (clip->region) {
343
	cairo_region_destroy (clip->region);
344
	clip->region = NULL;
1892 serge 345
    }
3959 Serge 346
    clip->is_region = FALSE;
1892 serge 347
 
3959 Serge 348
    return clip;
1892 serge 349
}
350
 
3959 Serge 351
cairo_bool_t
352
_cairo_clip_equal (const cairo_clip_t *clip_a,
353
		   const cairo_clip_t *clip_b)
1892 serge 354
{
3959 Serge 355
    const cairo_clip_path_t *cp_a, *cp_b;
1892 serge 356
 
3959 Serge 357
    /* are both all-clipped or no-clip? */
358
    if (clip_a == clip_b)
359
	return TRUE;
1892 serge 360
 
3959 Serge 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;
1892 serge 367
    }
368
 
3959 Serge 369
    /* We have a pair of normal clips, check their contents */
1892 serge 370
 
3959 Serge 371
    if (clip_a->num_boxes != clip_b->num_boxes)
372
	return FALSE;
1892 serge 373
 
3959 Serge 374
    if (memcmp (clip_a->boxes, clip_b->boxes,
375
		sizeof (cairo_box_t) * clip_a->num_boxes))
376
	return FALSE;
1892 serge 377
 
3959 Serge 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;
1892 serge 383
 
3959 Serge 384
	/* XXX compare reduced polygons? */
1892 serge 385
 
3959 Serge 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;
1892 serge 401
    }
402
 
3959 Serge 403
    return cp_a == NULL && cp_b == NULL;
1892 serge 404
}
405
 
3959 Serge 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)
1892 serge 410
{
411
    cairo_status_t status;
412
    cairo_clip_path_t *clip_path;
413
 
3959 Serge 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;
1892 serge 419
 
420
    clip_path = _cairo_clip_path_create (clip);
421
    if (unlikely (clip_path == NULL))
3959 Serge 422
	return _cairo_clip_set_all_clipped (clip);
1892 serge 423
 
424
    status = _cairo_path_fixed_init_copy (&clip_path->path,
425
					  &other_path->path);
3959 Serge 426
    if (unlikely (status))
427
	return _cairo_clip_set_all_clipped (clip);
1892 serge 428
 
3959 Serge 429
    _cairo_path_fixed_translate (&clip_path->path, fx, fy);
1892 serge 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
 
3959 Serge 435
    return clip;
1892 serge 436
}
437
 
3959 Serge 438
cairo_clip_t *
439
_cairo_clip_translate (cairo_clip_t *clip, int tx, int ty)
1892 serge 440
{
3959 Serge 441
    int fx, fy, i;
442
    cairo_clip_path_t *clip_path;
1892 serge 443
 
3959 Serge 444
    if (clip == NULL || _cairo_clip_is_all_clipped (clip))
445
	return clip;
1892 serge 446
 
3959 Serge 447
    if (tx == 0 && ty == 0)
448
	return clip;
1892 serge 449
 
3959 Serge 450
    fx = _cairo_fixed_from_int (tx);
451
    fy = _cairo_fixed_from_int (ty);
1892 serge 452
 
3959 Serge 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;
1892 serge 458
    }
459
 
3959 Serge 460
    clip->extents.x += tx;
461
    clip->extents.y += ty;
1892 serge 462
 
3959 Serge 463
    if (clip->path == NULL)
464
	return clip;
1892 serge 465
 
3959 Serge 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);
1892 serge 470
 
3959 Serge 471
    return clip;
1892 serge 472
}
473
 
3959 Serge 474
static cairo_status_t
475
_cairo_path_fixed_add_box (cairo_path_fixed_t *path,
476
			   const cairo_box_t *box)
1892 serge 477
{
478
    cairo_status_t status;
479
 
3959 Serge 480
    status = _cairo_path_fixed_move_to (path, box->p1.x, box->p1.y);
481
    if (unlikely (status))
1892 serge 482
	return status;
483
 
3959 Serge 484
    status = _cairo_path_fixed_line_to (path, box->p2.x, box->p1.y);
1892 serge 485
    if (unlikely (status))
486
	return status;
487
 
3959 Serge 488
    status = _cairo_path_fixed_line_to (path, box->p2.x, box->p2.y);
1892 serge 489
    if (unlikely (status))
490
	return status;
491
 
3959 Serge 492
    status = _cairo_path_fixed_line_to (path, box->p1.x, box->p2.y);
1892 serge 493
    if (unlikely (status))
494
	return status;
495
 
3959 Serge 496
    return _cairo_path_fixed_close_path (path);
1892 serge 497
}
498
 
499
static cairo_status_t
3959 Serge 500
_cairo_path_fixed_init_from_boxes (cairo_path_fixed_t *path,
501
				   const cairo_boxes_t *boxes)
1892 serge 502
{
503
    cairo_status_t status;
3959 Serge 504
    const struct _cairo_boxes_chunk *chunk;
505
    int i;
1892 serge 506
 
3959 Serge 507
    _cairo_path_fixed_init (path);
508
    if (boxes->num_boxes == 0)
509
	return CAIRO_STATUS_SUCCESS;
1892 serge 510
 
3959 Serge 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
	    }
1892 serge 518
	}
519
    }
520
 
3959 Serge 521
    return CAIRO_STATUS_SUCCESS;
1892 serge 522
}
523
 
3959 Serge 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)
1892 serge 528
{
3959 Serge 529
    cairo_path_fixed_t path;
1892 serge 530
 
3959 Serge 531
    if (clip_path->prev)
532
	clip = _cairo_clip_intersect_clip_path_transformed (clip,
533
							    clip_path->prev,
534
							    m);
1892 serge 535
 
3959 Serge 536
    if (_cairo_path_fixed_init_copy (&path, &clip_path->path))
537
	return _cairo_clip_set_all_clipped (clip);
1892 serge 538
 
3959 Serge 539
    _cairo_path_fixed_transform (&path, m);
1892 serge 540
 
3959 Serge 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);
1892 serge 547
 
3959 Serge 548
    return clip;
1892 serge 549
}
550
 
3959 Serge 551
cairo_clip_t *
552
_cairo_clip_transform (cairo_clip_t *clip, const cairo_matrix_t *m)
1892 serge 553
{
3959 Serge 554
    cairo_clip_t *copy;
1892 serge 555
 
3959 Serge 556
    if (clip == NULL || _cairo_clip_is_all_clipped (clip))
557
	return clip;
1892 serge 558
 
3959 Serge 559
    if (_cairo_matrix_is_translation (m))
560
	return _cairo_clip_translate (clip, m->x0, m->y0);
1892 serge 561
 
3959 Serge 562
    copy = _cairo_clip_create ();
1892 serge 563
 
3959 Serge 564
    if (clip->num_boxes) {
565
	cairo_path_fixed_t path;
566
	cairo_boxes_t boxes;
1892 serge 567
 
3959 Serge 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);
1892 serge 571
 
3959 Serge 572
	copy = _cairo_clip_intersect_path (copy, &path,
573
					   CAIRO_FILL_RULE_WINDING,
574
					   0.1,
575
					   CAIRO_ANTIALIAS_DEFAULT);
1892 serge 576
 
3959 Serge 577
	_cairo_path_fixed_fini (&path);
1892 serge 578
    }
579
 
3959 Serge 580
    if (clip->path)
581
	copy = _cairo_clip_intersect_clip_path_transformed (copy, clip->path,m);
1892 serge 582
 
3959 Serge 583
    _cairo_clip_destroy (clip);
584
    return copy;
1892 serge 585
}
586
 
3959 Serge 587
cairo_clip_t *
588
_cairo_clip_copy_with_translation (const cairo_clip_t *clip, int tx, int ty)
1892 serge 589
{
3959 Serge 590
    cairo_clip_t *copy;
591
    int fx, fy, i;
1892 serge 592
 
3959 Serge 593
    if (clip == NULL || _cairo_clip_is_all_clipped (clip))
594
	return (cairo_clip_t *)clip;
1892 serge 595
 
3959 Serge 596
    if (tx == 0 && ty == 0)
597
	return _cairo_clip_copy (clip);
1892 serge 598
 
3959 Serge 599
    copy = _cairo_clip_create ();
600
    if (copy == NULL)
601
	    return _cairo_clip_set_all_clipped (copy);
1892 serge 602
 
3959 Serge 603
    fx = _cairo_fixed_from_int (tx);
604
    fy = _cairo_fixed_from_int (ty);
1892 serge 605
 
3959 Serge 606
    if (clip->num_boxes) {
607
	if (clip->num_boxes == 1) {
608
	    copy->boxes = ©->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);
1892 serge 613
	}
614
 
3959 Serge 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;
1892 serge 620
	}
3959 Serge 621
	copy->num_boxes = clip->num_boxes;
1892 serge 622
    }
623
 
3959 Serge 624
    copy->extents = clip->extents;
625
    copy->extents.x += tx;
626
    copy->extents.y += ty;
1892 serge 627
 
3959 Serge 628
    if (clip->path == NULL)
629
	return copy;
1892 serge 630
 
3959 Serge 631
    return _cairo_clip_path_copy_with_translation (copy, clip->path, fx, fy);
1892 serge 632
}
633
 
634
cairo_bool_t
3959 Serge 635
_cairo_clip_contains_extents (const cairo_clip_t *clip,
1892 serge 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
3959 Serge 645
_cairo_debug_print_clip (FILE *stream, const cairo_clip_t *clip)
1892 serge 646
{
3959 Serge 647
    int i;
1892 serge 648
 
649
    if (clip == NULL) {
650
	fprintf (stream, "no clip\n");
651
	return;
652
    }
653
 
3959 Serge 654
    if (_cairo_clip_is_all_clipped (clip)) {
1892 serge 655
	fprintf (stream, "clip: all-clipped\n");
656
	return;
657
    }
658
 
659
    fprintf (stream, "clip:\n");
3959 Serge 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);
1892 serge 664
 
3959 Serge 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
    }
1892 serge 673
 
3959 Serge 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
    }
1892 serge 685
}
686
 
687
const cairo_rectangle_int_t *
688
_cairo_clip_get_extents (const cairo_clip_t *clip)
689
{
3959 Serge 690
    if (clip == NULL)
691
	return &_cairo_unbounded_rectangle;
1892 serge 692
 
3959 Serge 693
    if (_cairo_clip_is_all_clipped (clip))
694
	return &_cairo_empty_rectangle;
1892 serge 695
 
3959 Serge 696
    return &clip->extents;
1892 serge 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
 
3959 Serge 728
cairo_rectangle_list_t *
1892 serge 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)) {
3959 Serge 740
	status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
1892 serge 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
 
3959 Serge 762
    if (clip == NULL)
1892 serge 763
	return ERROR_LIST (CAIRO_STATUS_CLIP_NOT_REPRESENTABLE);
764
 
3959 Serge 765
    if (_cairo_clip_is_all_clipped (clip))
1892 serge 766
	goto DONE;
3959 Serge 767
 
768
    if (! _cairo_clip_is_region (clip))
1892 serge 769
	return ERROR_LIST (CAIRO_STATUS_CLIP_NOT_REPRESENTABLE);
770
 
3959 Serge 771
    region = _cairo_clip_get_region (clip);
772
    if (region == NULL)
773
	return ERROR_LIST (CAIRO_STATUS_NO_MEMORY);
774
 
1892 serge 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:
3959 Serge 814
 * @rectangle_list: a rectangle list, as obtained from cairo_copy_clip_rectangle_list()
1892 serge 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);
3959 Serge 837
    _freed_pool_reset (&clip_pool);
1892 serge 838
}