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

            
44
#include "cairo-box-inline.h"
45
#include "cairo-clip-inline.h"
46
#include "cairo-clip-private.h"
47
#include "cairo-error-private.h"
48
#include "cairo-freed-pool-private.h"
49
#include "cairo-gstate-private.h"
50
#include "cairo-path-fixed-private.h"
51
#include "cairo-pattern-private.h"
52
#include "cairo-composite-rectangles-private.h"
53
#include "cairo-region-private.h"
54

            
55
static cairo_bool_t
56
1532066
_cairo_clip_contains_rectangle_box (const cairo_clip_t *clip,
57
				    const cairo_rectangle_int_t *rect,
58
				    const cairo_box_t *box)
59
{
60
    int i;
61

            
62
    /* clip == NULL means no clip, so the clip contains everything */
63
1532066
    if (clip == NULL)
64
533462
	return TRUE;
65

            
66
998604
    if (_cairo_clip_is_all_clipped (clip))
67
	return FALSE;
68

            
69
    /* If we have a non-trivial path, just say no */
70
998604
    if (clip->path)
71
3234
	return FALSE;
72

            
73
995370
    if (! _cairo_rectangle_contains_rectangle (&clip->extents, rect))
74
17879
	return FALSE;
75

            
76
977491
    if (clip->num_boxes == 0)
77
1203
	return TRUE;
78

            
79
    /* Check for a clip-box that wholly contains the rectangle */
80
1009978
    for (i = 0; i < clip->num_boxes; i++) {
81
1002910
	if (box->p1.x >= clip->boxes[i].p1.x &&
82
975159
	    box->p1.y >= clip->boxes[i].p1.y &&
83
971592
	    box->p2.x <= clip->boxes[i].p2.x &&
84
969856
	    box->p2.y <= clip->boxes[i].p2.y)
85
	{
86
969220
	    return TRUE;
87
	}
88
    }
89

            
90
7068
    return FALSE;
91
}
92

            
93
cairo_bool_t
94
5736
_cairo_clip_contains_box (const cairo_clip_t *clip,
95
			  const cairo_box_t *box)
96
{
97
    cairo_rectangle_int_t rect;
98

            
99
5736
    _cairo_box_round_to_rectangle (box, &rect);
100
5736
    return _cairo_clip_contains_rectangle_box(clip, &rect, box);
101
}
102

            
103
cairo_bool_t
104
1526330
_cairo_clip_contains_rectangle (const cairo_clip_t *clip,
105
				const cairo_rectangle_int_t *rect)
106
{
107
    cairo_box_t box;
108

            
109
1526330
    _cairo_box_from_rectangle_int (&box, rect);
110
1526330
    return _cairo_clip_contains_rectangle_box (clip, rect, &box);
111
}
112

            
113
cairo_clip_t *
114
985
_cairo_clip_intersect_rectilinear_path (cairo_clip_t *clip,
115
					const cairo_path_fixed_t *path,
116
					cairo_fill_rule_t fill_rule,
117
					cairo_antialias_t antialias)
118
{
119
    cairo_status_t status;
120
    cairo_boxes_t boxes;
121

            
122
985
    _cairo_boxes_init (&boxes);
123
985
    status = _cairo_path_fixed_fill_rectilinear_to_boxes (path,
124
							  fill_rule,
125
							  antialias,
126
							  &boxes);
127
985
    if (likely (status == CAIRO_STATUS_SUCCESS && boxes.num_boxes))
128
979
	clip = _cairo_clip_intersect_boxes (clip, &boxes);
129
    else
130
6
	clip = _cairo_clip_set_all_clipped (clip);
131
985
    _cairo_boxes_fini (&boxes);
132

            
133
985
    return clip;
134
}
135

            
136
static cairo_clip_t *
137
1763013
_cairo_clip_intersect_rectangle_box (cairo_clip_t *clip,
138
				     const cairo_rectangle_int_t *r,
139
				     const cairo_box_t *box)
140
{
141
    cairo_box_t extents_box;
142
1763013
    cairo_bool_t changed = FALSE;
143
    int i, j;
144

            
145
1763013
    if (clip == NULL) {
146
1522589
	clip = _cairo_clip_create ();
147
1522589
	if (clip == NULL)
148
	    return _cairo_clip_set_all_clipped (clip);
149
    }
150

            
151
1763013
    if (clip->num_boxes == 0) {
152
1706944
	clip->boxes = &clip->embedded_box;
153
1706944
	clip->boxes[0] = *box;
154
1706944
	clip->num_boxes = 1;
155
1706944
	if (clip->path == NULL) {
156
1704661
	    clip->extents = *r;
157
	} else {
158
2283
	    if (! _cairo_rectangle_intersect (&clip->extents, r))
159
		return _cairo_clip_set_all_clipped (clip);
160
	}
161
1706944
	if (clip->path == NULL)
162
1704661
	    clip->is_region = _cairo_box_is_pixel_aligned (box);
163
1706944
	return clip;
164
    }
165

            
166
    /* Does the new box wholly subsume the clip? Perform a cheap check
167
     * for the common condition of a single clip rectangle.
168
     */
169
56069
    if (clip->num_boxes == 1 &&
170
54636
	clip->boxes[0].p1.x >= box->p1.x &&
171
11249
	clip->boxes[0].p1.y >= box->p1.y &&
172
9979
	clip->boxes[0].p2.x <= box->p2.x &&
173
9799
	clip->boxes[0].p2.y <= box->p2.y)
174
    {
175
9787
	return clip;
176
    }
177

            
178
121933
    for (i = j = 0; i < clip->num_boxes; i++) {
179
75651
	cairo_box_t *b = &clip->boxes[j];
180

            
181
75651
	if (j != i)
182
447
	    *b = clip->boxes[i];
183

            
184
75651
	if (box->p1.x > b->p1.x)
185
43805
	    b->p1.x = box->p1.x, changed = TRUE;
186
75651
	if (box->p2.x < b->p2.x)
187
44198
	    b->p2.x = box->p2.x, changed = TRUE;
188

            
189
75651
	if (box->p1.y > b->p1.y)
190
43782
	    b->p1.y = box->p1.y, changed = TRUE;
191
75651
	if (box->p2.y < b->p2.y)
192
44153
	    b->p2.y = box->p2.y, changed = TRUE;
193

            
194
75651
	j += b->p2.x > b->p1.x && b->p2.y > b->p1.y;
195
    }
196
46282
    clip->num_boxes = j;
197

            
198
46282
    if (clip->num_boxes == 0)
199
42
	return _cairo_clip_set_all_clipped (clip);
200

            
201
46240
    if (! changed)
202
1015
	return clip;
203

            
204
45225
    extents_box = clip->boxes[0];
205
46807
    for (i = 1; i < clip->num_boxes; i++) {
206
1582
	    if (clip->boxes[i].p1.x < extents_box.p1.x)
207
147
		extents_box.p1.x = clip->boxes[i].p1.x;
208

            
209
1582
	    if (clip->boxes[i].p1.y < extents_box.p1.y)
210
3
		extents_box.p1.y = clip->boxes[i].p1.y;
211

            
212
1582
	    if (clip->boxes[i].p2.x > extents_box.p2.x)
213
163
		extents_box.p2.x = clip->boxes[i].p2.x;
214

            
215
1582
	    if (clip->boxes[i].p2.y > extents_box.p2.y)
216
1120
		extents_box.p2.y = clip->boxes[i].p2.y;
217
    }
218

            
219
45225
    if (clip->path == NULL) {
220
43028
	_cairo_box_round_to_rectangle (&extents_box, &clip->extents);
221
    } else {
222
	cairo_rectangle_int_t extents_rect;
223

            
224
2197
	_cairo_box_round_to_rectangle (&extents_box, &extents_rect);
225
2197
	if (! _cairo_rectangle_intersect (&clip->extents, &extents_rect))
226
	    return _cairo_clip_set_all_clipped (clip);
227
    }
228

            
229
45225
    if (clip->region) {
230
	cairo_region_destroy (clip->region);
231
	clip->region = NULL;
232
    }
233

            
234
45225
    clip->is_region = FALSE;
235
45225
    return clip;
236
}
237

            
238
cairo_clip_t *
239
550163
_cairo_clip_intersect_box (cairo_clip_t *clip,
240
			   const cairo_box_t *box)
241
{
242
    cairo_rectangle_int_t r;
243

            
244
550163
    if (_cairo_clip_is_all_clipped (clip))
245
	return clip;
246

            
247
550163
    _cairo_box_round_to_rectangle (box, &r);
248
550163
    if (r.width == 0 || r.height == 0)
249
18409
	return _cairo_clip_set_all_clipped (clip);
250

            
251
531754
    return _cairo_clip_intersect_rectangle_box (clip, &r, box);
252
}
253

            
254
/* Copy a box set to a clip
255
 *
256
 * @param boxes  The box set to copy from.
257
 * @param clip   The clip to copy to (return buffer).
258
 * @returns      Zero if the allocation failed (the clip will be set to
259
 *               all-clipped), otherwise non-zero.
260
 */
261
static cairo_bool_t
262
224137
_cairo_boxes_copy_to_clip (const cairo_boxes_t *boxes, cairo_clip_t *clip)
263
{
264
    /* XXX cow-boxes? */
265
224137
    if (boxes->num_boxes == 1) {
266
223290
	clip->boxes = &clip->embedded_box;
267
223290
	clip->boxes[0] = boxes->chunks.base[0];
268
223290
	clip->num_boxes = 1;
269
223290
	return TRUE;
270
    }
271

            
272
847
    clip->boxes = _cairo_boxes_to_array (boxes, &clip->num_boxes);
273
847
    if (unlikely (clip->boxes == NULL))
274
    {
275
	_cairo_clip_set_all_clipped (clip);
276
	return FALSE;
277
    }
278

            
279
847
    return TRUE;
280
}
281

            
282
cairo_clip_t *
283
47629
_cairo_clip_intersect_boxes (cairo_clip_t *clip,
284
			     const cairo_boxes_t *boxes)
285
{
286
    cairo_boxes_t clip_boxes;
287
    cairo_box_t limits;
288
    cairo_rectangle_int_t extents;
289

            
290
47629
    if (_cairo_clip_is_all_clipped (clip))
291
	return clip;
292

            
293
47629
    if (boxes->num_boxes == 0)
294
	return _cairo_clip_set_all_clipped (clip);
295

            
296
47629
    if (boxes->num_boxes == 1)
297
46779
	return _cairo_clip_intersect_box (clip, boxes->chunks.base);
298

            
299
850
    if (clip == NULL)
300
640
	clip = _cairo_clip_create ();
301

            
302
850
    if (clip->num_boxes) {
303
204
	_cairo_boxes_init_for_array (&clip_boxes, clip->boxes, clip->num_boxes);
304
204
	if (unlikely (_cairo_boxes_intersect (&clip_boxes, boxes, &clip_boxes))) {
305
	    clip = _cairo_clip_set_all_clipped (clip);
306
	    goto out;
307
	}
308

            
309
204
	if (clip->boxes != &clip->embedded_box)
310
9
	    free (clip->boxes);
311

            
312
204
	clip->boxes = NULL;
313
204
	boxes = &clip_boxes;
314
    }
315

            
316
850
    if (boxes->num_boxes == 0) {
317
3
	clip = _cairo_clip_set_all_clipped (clip);
318
3
	goto out;
319
    }
320

            
321
847
    if (!_cairo_boxes_copy_to_clip (boxes, clip)) {
322
	clip = _cairo_clip_set_all_clipped (clip);
323
	goto out;
324
    }
325

            
326
847
    _cairo_boxes_extents (boxes, &limits);
327

            
328
847
    _cairo_box_round_to_rectangle (&limits, &extents);
329
847
    if (clip->path == NULL) {
330
775
	clip->extents = extents;
331
72
    } else if (! _cairo_rectangle_intersect (&clip->extents, &extents)) {
332
	clip = _cairo_clip_set_all_clipped (clip);
333
	goto out;
334
    }
335

            
336
847
    if (clip->region) {
337
	cairo_region_destroy (clip->region);
338
	clip->region = NULL;
339
    }
340
847
    clip->is_region = FALSE;
341

            
342
850
out:
343
850
    if (boxes == &clip_boxes)
344
204
	_cairo_boxes_fini (&clip_boxes);
345

            
346
850
    return clip;
347
}
348

            
349
cairo_clip_t *
350
1231266
_cairo_clip_intersect_rectangle (cairo_clip_t       *clip,
351
				 const cairo_rectangle_int_t *r)
352
{
353
    cairo_box_t box;
354

            
355
1231266
    if (_cairo_clip_is_all_clipped (clip))
356
1
	return clip;
357

            
358
1231265
    if (r->width == 0 || r->height == 0)
359
6
	return _cairo_clip_set_all_clipped (clip);
360

            
361
1231259
    _cairo_box_from_rectangle_int (&box, r);
362

            
363
1231259
    return _cairo_clip_intersect_rectangle_box (clip, r, &box);
364
}
365

            
366
struct reduce {
367
    cairo_clip_t *clip;
368
    cairo_box_t limit;
369
    cairo_box_t extents;
370
    cairo_bool_t inside;
371

            
372
    cairo_point_t current_point;
373
    cairo_point_t last_move_to;
374
};
375

            
376
static void
377
_add_clipped_edge (struct reduce *r,
378
		   const cairo_point_t *p1,
379
		   const cairo_point_t *p2,
380
		   int y1, int y2)
381
{
382
    cairo_fixed_t x;
383

            
384
    x = _cairo_edge_compute_intersection_x_for_y (p1, p2, y1);
385
    if (x < r->extents.p1.x)
386
	r->extents.p1.x = x;
387

            
388
    x = _cairo_edge_compute_intersection_x_for_y (p1, p2, y2);
389
    if (x > r->extents.p2.x)
390
	r->extents.p2.x = x;
391

            
392
    if (y1 < r->extents.p1.y)
393
	r->extents.p1.y = y1;
394

            
395
    if (y2 > r->extents.p2.y)
396
	r->extents.p2.y = y2;
397

            
398
    r->inside = TRUE;
399
}
400

            
401
static void
402
_add_edge (struct reduce *r,
403
	   const cairo_point_t *p1,
404
	   const cairo_point_t *p2)
405
{
406
    int top, bottom;
407
    int top_y, bot_y;
408
    int n;
409

            
410
    if (p1->y < p2->y) {
411
	top = p1->y;
412
	bottom = p2->y;
413
    } else {
414
	top = p2->y;
415
	bottom = p1->y;
416
    }
417

            
418
    if (bottom < r->limit.p1.y || top > r->limit.p2.y)
419
	return;
420

            
421
    if (p1->x > p2->x) {
422
	const cairo_point_t *t = p1;
423
	p1 = p2;
424
	p2 = t;
425
    }
426

            
427
    if (p2->x <= r->limit.p1.x || p1->x >= r->limit.p2.x)
428
	return;
429

            
430
    for (n = 0; n < r->clip->num_boxes; n++) {
431
	const cairo_box_t *limits = &r->clip->boxes[n];
432

            
433
	if (bottom < limits->p1.y || top > limits->p2.y)
434
	    continue;
435

            
436
	if (p2->x <= limits->p1.x || p1->x >= limits->p2.x)
437
	    continue;
438

            
439
	if (p1->x >= limits->p1.x && p2->x <= limits->p1.x) {
440
	    top_y = top;
441
	    bot_y = bottom;
442
	} else {
443
	    int p1_y, p2_y;
444

            
445
	    p1_y = _cairo_edge_compute_intersection_y_for_x (p1, p2,
446
							     limits->p1.x);
447
	    p2_y = _cairo_edge_compute_intersection_y_for_x (p1, p2,
448
							     limits->p2.x);
449
	    if (p1_y < p2_y) {
450
		top_y = p1_y;
451
		bot_y = p2_y;
452
	    } else {
453
		top_y = p2_y;
454
		bot_y = p1_y;
455
	    }
456

            
457
	    if (top_y < top)
458
		top_y = top;
459
	    if (bot_y > bottom)
460
		bot_y = bottom;
461
	}
462

            
463
	if (top_y < limits->p1.y)
464
	    top_y = limits->p1.y;
465

            
466
	if (bot_y > limits->p2.y)
467
	    bot_y = limits->p2.y;
468
	if (bot_y > top_y)
469
	    _add_clipped_edge (r, p1, p2, top_y, bot_y);
470
    }
471
}
472

            
473
static cairo_status_t
474
_reduce_line_to (void *closure,
475
		       const cairo_point_t *point)
476
{
477
    struct reduce *r = closure;
478

            
479
    _add_edge (r, &r->current_point, point);
480
    r->current_point = *point;
481

            
482
    return CAIRO_STATUS_SUCCESS;
483
}
484

            
485
static cairo_status_t
486
_reduce_close (void *closure)
487
{
488
    struct reduce *r = closure;
489

            
490
    return _reduce_line_to (r, &r->last_move_to);
491
}
492

            
493
static cairo_status_t
494
_reduce_move_to (void *closure,
495
		 const cairo_point_t *point)
496
{
497
    struct reduce *r = closure;
498
    cairo_status_t status;
499

            
500
    /* close current subpath */
501
    status = _reduce_close (closure);
502

            
503
    /* make sure that the closure represents a degenerate path */
504
    r->current_point = *point;
505
    r->last_move_to = *point;
506

            
507
    return status;
508
}
509

            
510
static cairo_clip_t *
511
9744
_cairo_clip_reduce_to_boxes (cairo_clip_t *clip)
512
{
513
    struct reduce r;
514
    cairo_clip_path_t *clip_path;
515
    cairo_status_t status;
516

            
517
9744
	return clip;
518
    if (clip->path == NULL)
519
	return clip;
520

            
521
    r.clip = clip;
522
    r.extents.p1.x = r.extents.p1.y = INT_MAX;
523
    r.extents.p2.x = r.extents.p2.y = INT_MIN;
524
    r.inside = FALSE;
525

            
526
    r.limit.p1.x = _cairo_fixed_from_int (clip->extents.x);
527
    r.limit.p1.y = _cairo_fixed_from_int (clip->extents.y);
528
    r.limit.p2.x = _cairo_fixed_from_int (clip->extents.x + clip->extents.width);
529
    r.limit.p2.y = _cairo_fixed_from_int (clip->extents.y + clip->extents.height);
530

            
531
    clip_path = clip->path;
532
    do {
533
	r.current_point.x = 0;
534
	r.current_point.y = 0;
535
	r.last_move_to = r.current_point;
536

            
537
	status = _cairo_path_fixed_interpret_flat (&clip_path->path,
538
						   _reduce_move_to,
539
						   _reduce_line_to,
540
						   _reduce_close,
541
						   &r,
542
						   clip_path->tolerance);
543
	assert (status == CAIRO_STATUS_SUCCESS);
544
	_reduce_close (&r);
545
    } while ((clip_path = clip_path->prev));
546

            
547
    if (! r.inside) {
548
	_cairo_clip_path_destroy (clip->path);
549
	clip->path = NULL;
550
    }
551

            
552
    return _cairo_clip_intersect_box (clip, &r.extents);
553
}
554

            
555
cairo_clip_t *
556
1183643
_cairo_clip_reduce_to_rectangle (const cairo_clip_t *clip,
557
				 const cairo_rectangle_int_t *r)
558
{
559
    cairo_clip_t *copy;
560

            
561
1183643
    if (_cairo_clip_is_all_clipped (clip))
562
	return (cairo_clip_t *) clip;
563

            
564
1183643
    if (_cairo_clip_contains_rectangle (clip, r))
565
1173869
	return _cairo_clip_intersect_rectangle (NULL, r);
566

            
567
9774
    copy = _cairo_clip_copy_intersect_rectangle (clip, r);
568
9774
    if (_cairo_clip_is_all_clipped (copy))
569
30
	return copy;
570

            
571
9744
    return _cairo_clip_reduce_to_boxes (copy);
572
}
573

            
574
cairo_clip_t *
575
1183643
_cairo_clip_reduce_for_composite (const cairo_clip_t *clip,
576
				  cairo_composite_rectangles_t *extents)
577
{
578
    const cairo_rectangle_int_t *r;
579

            
580
1183643
    r = extents->is_bounded ? &extents->bounded : &extents->unbounded;
581
1183643
    return _cairo_clip_reduce_to_rectangle (clip, r);
582
}
583

            
584
cairo_clip_t *
585
223290
_cairo_clip_from_boxes (const cairo_boxes_t *boxes)
586
{
587
    cairo_box_t extents;
588
223290
    cairo_clip_t *clip = _cairo_clip_create ();
589
223290
    if (clip == NULL)
590
	return _cairo_clip_set_all_clipped (clip);
591

            
592
223290
    if (unlikely (! _cairo_boxes_copy_to_clip (boxes, clip)))
593
	return clip;
594

            
595
223290
    _cairo_boxes_extents (boxes, &extents);
596
223290
    _cairo_box_round_to_rectangle (&extents, &clip->extents);
597

            
598
223290
    return clip;
599
}