/src/cairo/src/cairo-clip-boxes.c
Line | Count | Source (jump to first uncovered line) |
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 | | _cairo_clip_contains_rectangle_box (const cairo_clip_t *clip, |
57 | | const cairo_rectangle_int_t *rect, |
58 | | const cairo_box_t *box) |
59 | 2.51M | { |
60 | 2.51M | int i; |
61 | | |
62 | | /* clip == NULL means no clip, so the clip contains everything */ |
63 | 2.51M | if (clip == NULL) |
64 | 1.56k | return TRUE; |
65 | | |
66 | 2.51M | if (_cairo_clip_is_all_clipped (clip)) |
67 | 0 | return FALSE; |
68 | | |
69 | | /* If we have a non-trivial path, just say no */ |
70 | 2.51M | if (clip->path) |
71 | 1.15k | return FALSE; |
72 | | |
73 | 2.51M | if (! _cairo_rectangle_contains_rectangle (&clip->extents, rect)) |
74 | 2.54k | return FALSE; |
75 | | |
76 | 2.50M | if (clip->num_boxes == 0) |
77 | 2 | return TRUE; |
78 | | |
79 | | /* Check for a clip-box that wholly contains the rectangle */ |
80 | 2.52M | for (i = 0; i < clip->num_boxes; i++) { |
81 | 2.50M | if (box->p1.x >= clip->boxes[i].p1.x && |
82 | 2.50M | box->p1.y >= clip->boxes[i].p1.y && |
83 | 2.50M | box->p2.x <= clip->boxes[i].p2.x && |
84 | 2.50M | box->p2.y <= clip->boxes[i].p2.y) |
85 | 2.49M | { |
86 | 2.49M | return TRUE; |
87 | 2.49M | } |
88 | 2.50M | } |
89 | | |
90 | 11.9k | return FALSE; |
91 | 2.50M | } |
92 | | |
93 | | cairo_bool_t |
94 | | _cairo_clip_contains_box (const cairo_clip_t *clip, |
95 | | const cairo_box_t *box) |
96 | 1.00M | { |
97 | 1.00M | cairo_rectangle_int_t rect; |
98 | | |
99 | 1.00M | _cairo_box_round_to_rectangle (box, &rect); |
100 | 1.00M | return _cairo_clip_contains_rectangle_box(clip, &rect, box); |
101 | 1.00M | } |
102 | | |
103 | | cairo_bool_t |
104 | | _cairo_clip_contains_rectangle (const cairo_clip_t *clip, |
105 | | const cairo_rectangle_int_t *rect) |
106 | 1.50M | { |
107 | 1.50M | cairo_box_t box; |
108 | | |
109 | 1.50M | _cairo_box_from_rectangle_int (&box, rect); |
110 | 1.50M | return _cairo_clip_contains_rectangle_box (clip, rect, &box); |
111 | 1.50M | } |
112 | | |
113 | | cairo_clip_t * |
114 | | _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 | 144 | { |
119 | 144 | cairo_status_t status; |
120 | 144 | cairo_boxes_t boxes; |
121 | | |
122 | 144 | _cairo_boxes_init (&boxes); |
123 | 144 | status = _cairo_path_fixed_fill_rectilinear_to_boxes (path, |
124 | 144 | fill_rule, |
125 | 144 | antialias, |
126 | 144 | &boxes); |
127 | 144 | if (likely (status == CAIRO_STATUS_SUCCESS && boxes.num_boxes)) |
128 | 143 | clip = _cairo_clip_intersect_boxes (clip, &boxes); |
129 | 1 | else |
130 | 1 | clip = _cairo_clip_set_all_clipped (clip); |
131 | 144 | _cairo_boxes_fini (&boxes); |
132 | | |
133 | 144 | return clip; |
134 | 144 | } |
135 | | |
136 | | static cairo_clip_t * |
137 | | _cairo_clip_intersect_rectangle_box (cairo_clip_t *clip, |
138 | | const cairo_rectangle_int_t *r, |
139 | | const cairo_box_t *box) |
140 | 2.50M | { |
141 | 2.50M | cairo_box_t extents_box; |
142 | 2.50M | cairo_bool_t changed = FALSE; |
143 | 2.50M | int i, j; |
144 | | |
145 | 2.50M | if (clip == NULL) { |
146 | 2.48M | clip = _cairo_clip_create (); |
147 | 2.48M | if (clip == NULL) |
148 | 0 | return _cairo_clip_set_all_clipped (clip); |
149 | 2.48M | } |
150 | | |
151 | 2.50M | if (clip->num_boxes == 0) { |
152 | 2.48M | clip->boxes = &clip->embedded_box; |
153 | 2.48M | clip->boxes[0] = *box; |
154 | 2.48M | clip->num_boxes = 1; |
155 | 2.48M | if (clip->path == NULL) { |
156 | 2.48M | clip->extents = *r; |
157 | 2.48M | } else { |
158 | 5 | if (! _cairo_rectangle_intersect (&clip->extents, r)) |
159 | 0 | return _cairo_clip_set_all_clipped (clip); |
160 | 5 | } |
161 | 2.48M | if (clip->path == NULL) |
162 | 2.48M | clip->is_region = _cairo_box_is_pixel_aligned (box); |
163 | 2.48M | return clip; |
164 | 2.48M | } |
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 | 22.8k | if (clip->num_boxes == 1 && |
170 | 22.8k | clip->boxes[0].p1.x >= box->p1.x && |
171 | 22.8k | clip->boxes[0].p1.y >= box->p1.y && |
172 | 22.8k | clip->boxes[0].p2.x <= box->p2.x && |
173 | 22.8k | clip->boxes[0].p2.y <= box->p2.y) |
174 | 13.7k | { |
175 | 13.7k | return clip; |
176 | 13.7k | } |
177 | | |
178 | 19.2k | for (i = j = 0; i < clip->num_boxes; i++) { |
179 | 10.2k | cairo_box_t *b = &clip->boxes[j]; |
180 | | |
181 | 10.2k | if (j != i) |
182 | 0 | *b = clip->boxes[i]; |
183 | | |
184 | 10.2k | if (box->p1.x > b->p1.x) |
185 | 7.25k | b->p1.x = box->p1.x, changed = TRUE; |
186 | 10.2k | if (box->p2.x < b->p2.x) |
187 | 7.40k | b->p2.x = box->p2.x, changed = TRUE; |
188 | | |
189 | 10.2k | if (box->p1.y > b->p1.y) |
190 | 8.09k | b->p1.y = box->p1.y, changed = TRUE; |
191 | 10.2k | if (box->p2.y < b->p2.y) |
192 | 7.50k | b->p2.y = box->p2.y, changed = TRUE; |
193 | | |
194 | 10.2k | j += b->p2.x > b->p1.x && b->p2.y > b->p1.y; |
195 | 10.2k | } |
196 | 9.07k | clip->num_boxes = j; |
197 | | |
198 | 9.07k | if (clip->num_boxes == 0) |
199 | 7 | return _cairo_clip_set_all_clipped (clip); |
200 | | |
201 | 9.07k | if (! changed) |
202 | 636 | return clip; |
203 | | |
204 | 8.43k | extents_box = clip->boxes[0]; |
205 | 8.66k | for (i = 1; i < clip->num_boxes; i++) { |
206 | 231 | if (clip->boxes[i].p1.x < extents_box.p1.x) |
207 | 0 | extents_box.p1.x = clip->boxes[i].p1.x; |
208 | | |
209 | 231 | if (clip->boxes[i].p1.y < extents_box.p1.y) |
210 | 0 | extents_box.p1.y = clip->boxes[i].p1.y; |
211 | | |
212 | 231 | if (clip->boxes[i].p2.x > extents_box.p2.x) |
213 | 0 | extents_box.p2.x = clip->boxes[i].p2.x; |
214 | | |
215 | 231 | if (clip->boxes[i].p2.y > extents_box.p2.y) |
216 | 154 | extents_box.p2.y = clip->boxes[i].p2.y; |
217 | 231 | } |
218 | | |
219 | 8.43k | if (clip->path == NULL) { |
220 | 8.31k | _cairo_box_round_to_rectangle (&extents_box, &clip->extents); |
221 | 8.31k | } else { |
222 | 120 | cairo_rectangle_int_t extents_rect; |
223 | | |
224 | 120 | _cairo_box_round_to_rectangle (&extents_box, &extents_rect); |
225 | 120 | if (! _cairo_rectangle_intersect (&clip->extents, &extents_rect)) |
226 | 0 | return _cairo_clip_set_all_clipped (clip); |
227 | 120 | } |
228 | | |
229 | 8.43k | if (clip->region) { |
230 | 0 | cairo_region_destroy (clip->region); |
231 | 0 | clip->region = NULL; |
232 | 0 | } |
233 | | |
234 | 8.43k | clip->is_region = FALSE; |
235 | 8.43k | return clip; |
236 | 8.43k | } |
237 | | |
238 | | cairo_clip_t * |
239 | | _cairo_clip_intersect_box (cairo_clip_t *clip, |
240 | | const cairo_box_t *box) |
241 | 8.85k | { |
242 | 8.85k | cairo_rectangle_int_t r; |
243 | | |
244 | 8.85k | if (_cairo_clip_is_all_clipped (clip)) |
245 | 0 | return clip; |
246 | | |
247 | 8.85k | _cairo_box_round_to_rectangle (box, &r); |
248 | 8.85k | if (r.width == 0 || r.height == 0) |
249 | 0 | return _cairo_clip_set_all_clipped (clip); |
250 | | |
251 | 8.85k | return _cairo_clip_intersect_rectangle_box (clip, &r, box); |
252 | 8.85k | } |
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 | | _cairo_boxes_copy_to_clip (const cairo_boxes_t *boxes, cairo_clip_t *clip) |
263 | 143 | { |
264 | | /* XXX cow-boxes? */ |
265 | 143 | if (boxes->num_boxes == 1) { |
266 | 0 | clip->boxes = &clip->embedded_box; |
267 | 0 | clip->boxes[0] = boxes->chunks.base[0]; |
268 | 0 | clip->num_boxes = 1; |
269 | 0 | return TRUE; |
270 | 0 | } |
271 | | |
272 | 143 | clip->boxes = _cairo_boxes_to_array (boxes, &clip->num_boxes); |
273 | 143 | if (unlikely (clip->boxes == NULL)) |
274 | 0 | { |
275 | 0 | _cairo_clip_set_all_clipped (clip); |
276 | 0 | return FALSE; |
277 | 0 | } |
278 | | |
279 | 143 | return TRUE; |
280 | 143 | } |
281 | | |
282 | | cairo_clip_t * |
283 | | _cairo_clip_intersect_boxes (cairo_clip_t *clip, |
284 | | const cairo_boxes_t *boxes) |
285 | 146 | { |
286 | 146 | cairo_boxes_t clip_boxes; |
287 | 146 | cairo_box_t limits; |
288 | 146 | cairo_rectangle_int_t extents; |
289 | | |
290 | 146 | if (_cairo_clip_is_all_clipped (clip)) |
291 | 0 | return clip; |
292 | | |
293 | 146 | if (boxes->num_boxes == 0) |
294 | 0 | return _cairo_clip_set_all_clipped (clip); |
295 | | |
296 | 146 | if (boxes->num_boxes == 1) |
297 | 3 | return _cairo_clip_intersect_box (clip, boxes->chunks.base); |
298 | | |
299 | 143 | if (clip == NULL) |
300 | 0 | clip = _cairo_clip_create (); |
301 | | |
302 | 143 | if (clip->num_boxes) { |
303 | 143 | _cairo_boxes_init_for_array (&clip_boxes, clip->boxes, clip->num_boxes); |
304 | 143 | if (unlikely (_cairo_boxes_intersect (&clip_boxes, boxes, &clip_boxes))) { |
305 | 0 | clip = _cairo_clip_set_all_clipped (clip); |
306 | 0 | goto out; |
307 | 0 | } |
308 | | |
309 | 143 | if (clip->boxes != &clip->embedded_box) |
310 | 0 | free (clip->boxes); |
311 | | |
312 | 143 | clip->boxes = NULL; |
313 | 143 | boxes = &clip_boxes; |
314 | 143 | } |
315 | | |
316 | 143 | if (boxes->num_boxes == 0) { |
317 | 0 | clip = _cairo_clip_set_all_clipped (clip); |
318 | 0 | goto out; |
319 | 0 | } |
320 | | |
321 | 143 | if (!_cairo_boxes_copy_to_clip (boxes, clip)) { |
322 | 0 | clip = _cairo_clip_set_all_clipped (clip); |
323 | 0 | goto out; |
324 | 0 | } |
325 | | |
326 | 143 | _cairo_boxes_extents (boxes, &limits); |
327 | | |
328 | 143 | _cairo_box_round_to_rectangle (&limits, &extents); |
329 | 143 | if (clip->path == NULL) { |
330 | 143 | clip->extents = extents; |
331 | 143 | } else if (! _cairo_rectangle_intersect (&clip->extents, &extents)) { |
332 | 0 | clip = _cairo_clip_set_all_clipped (clip); |
333 | 0 | goto out; |
334 | 0 | } |
335 | | |
336 | 143 | if (clip->region) { |
337 | 0 | cairo_region_destroy (clip->region); |
338 | 0 | clip->region = NULL; |
339 | 0 | } |
340 | 143 | clip->is_region = FALSE; |
341 | | |
342 | 143 | out: |
343 | 143 | if (boxes == &clip_boxes) |
344 | 143 | _cairo_boxes_fini (&clip_boxes); |
345 | | |
346 | 143 | return clip; |
347 | 143 | } |
348 | | |
349 | | cairo_clip_t * |
350 | | _cairo_clip_intersect_rectangle (cairo_clip_t *clip, |
351 | | const cairo_rectangle_int_t *r) |
352 | 2.50M | { |
353 | 2.50M | cairo_box_t box; |
354 | | |
355 | 2.50M | if (_cairo_clip_is_all_clipped (clip)) |
356 | 0 | return clip; |
357 | | |
358 | 2.50M | if (r->width == 0 || r->height == 0) |
359 | 0 | return _cairo_clip_set_all_clipped (clip); |
360 | | |
361 | 2.50M | _cairo_box_from_rectangle_int (&box, r); |
362 | | |
363 | 2.50M | return _cairo_clip_intersect_rectangle_box (clip, r, &box); |
364 | 2.50M | } |
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 | 0 | { |
382 | 0 | cairo_fixed_t x; |
383 | 0 |
|
384 | 0 | x = _cairo_edge_compute_intersection_x_for_y (p1, p2, y1); |
385 | 0 | if (x < r->extents.p1.x) |
386 | 0 | r->extents.p1.x = x; |
387 | 0 |
|
388 | 0 | x = _cairo_edge_compute_intersection_x_for_y (p1, p2, y2); |
389 | 0 | if (x > r->extents.p2.x) |
390 | 0 | r->extents.p2.x = x; |
391 | 0 |
|
392 | 0 | if (y1 < r->extents.p1.y) |
393 | 0 | r->extents.p1.y = y1; |
394 | 0 |
|
395 | 0 | if (y2 > r->extents.p2.y) |
396 | 0 | r->extents.p2.y = y2; |
397 | 0 |
|
398 | 0 | r->inside = TRUE; |
399 | 0 | } |
400 | | |
401 | | static void |
402 | | _add_edge (struct reduce *r, |
403 | | const cairo_point_t *p1, |
404 | | const cairo_point_t *p2) |
405 | 0 | { |
406 | 0 | int top, bottom; |
407 | 0 | int top_y, bot_y; |
408 | 0 | int n; |
409 | 0 |
|
410 | 0 | if (p1->y < p2->y) { |
411 | 0 | top = p1->y; |
412 | 0 | bottom = p2->y; |
413 | 0 | } else { |
414 | 0 | top = p2->y; |
415 | 0 | bottom = p1->y; |
416 | 0 | } |
417 | 0 |
|
418 | 0 | if (bottom < r->limit.p1.y || top > r->limit.p2.y) |
419 | 0 | return; |
420 | 0 |
|
421 | 0 | if (p1->x > p2->x) { |
422 | 0 | const cairo_point_t *t = p1; |
423 | 0 | p1 = p2; |
424 | 0 | p2 = t; |
425 | 0 | } |
426 | 0 |
|
427 | 0 | if (p2->x <= r->limit.p1.x || p1->x >= r->limit.p2.x) |
428 | 0 | return; |
429 | 0 |
|
430 | 0 | for (n = 0; n < r->clip->num_boxes; n++) { |
431 | 0 | const cairo_box_t *limits = &r->clip->boxes[n]; |
432 | 0 |
|
433 | 0 | if (bottom < limits->p1.y || top > limits->p2.y) |
434 | 0 | continue; |
435 | 0 |
|
436 | 0 | if (p2->x <= limits->p1.x || p1->x >= limits->p2.x) |
437 | 0 | continue; |
438 | 0 |
|
439 | 0 | if (p1->x >= limits->p1.x && p2->x <= limits->p1.x) { |
440 | 0 | top_y = top; |
441 | 0 | bot_y = bottom; |
442 | 0 | } else { |
443 | 0 | int p1_y, p2_y; |
444 | 0 |
|
445 | 0 | p1_y = _cairo_edge_compute_intersection_y_for_x (p1, p2, |
446 | 0 | limits->p1.x); |
447 | 0 | p2_y = _cairo_edge_compute_intersection_y_for_x (p1, p2, |
448 | 0 | limits->p2.x); |
449 | 0 | if (p1_y < p2_y) { |
450 | 0 | top_y = p1_y; |
451 | 0 | bot_y = p2_y; |
452 | 0 | } else { |
453 | 0 | top_y = p2_y; |
454 | 0 | bot_y = p1_y; |
455 | 0 | } |
456 | 0 |
|
457 | 0 | if (top_y < top) |
458 | 0 | top_y = top; |
459 | 0 | if (bot_y > bottom) |
460 | 0 | bot_y = bottom; |
461 | 0 | } |
462 | 0 |
|
463 | 0 | if (top_y < limits->p1.y) |
464 | 0 | top_y = limits->p1.y; |
465 | 0 |
|
466 | 0 | if (bot_y > limits->p2.y) |
467 | 0 | bot_y = limits->p2.y; |
468 | 0 | if (bot_y > top_y) |
469 | 0 | _add_clipped_edge (r, p1, p2, top_y, bot_y); |
470 | 0 | } |
471 | 0 | } |
472 | | |
473 | | static cairo_status_t |
474 | | _reduce_line_to (void *closure, |
475 | | const cairo_point_t *point) |
476 | 0 | { |
477 | 0 | struct reduce *r = closure; |
478 | 0 |
|
479 | 0 | _add_edge (r, &r->current_point, point); |
480 | 0 | r->current_point = *point; |
481 | 0 |
|
482 | 0 | return CAIRO_STATUS_SUCCESS; |
483 | 0 | } |
484 | | |
485 | | static cairo_status_t |
486 | | _reduce_close (void *closure) |
487 | 0 | { |
488 | 0 | struct reduce *r = closure; |
489 | 0 |
|
490 | 0 | return _reduce_line_to (r, &r->last_move_to); |
491 | 0 | } |
492 | | |
493 | | static cairo_status_t |
494 | | _reduce_move_to (void *closure, |
495 | | const cairo_point_t *point) |
496 | 0 | { |
497 | 0 | struct reduce *r = closure; |
498 | 0 | cairo_status_t status; |
499 | 0 |
|
500 | 0 | /* close current subpath */ |
501 | 0 | status = _reduce_close (closure); |
502 | 0 |
|
503 | 0 | /* make sure that the closure represents a degenerate path */ |
504 | 0 | r->current_point = *point; |
505 | 0 | r->last_move_to = *point; |
506 | 0 |
|
507 | 0 | return status; |
508 | 0 | } |
509 | | |
510 | | static cairo_clip_t * |
511 | | _cairo_clip_reduce_to_boxes (cairo_clip_t *clip) |
512 | 9.11k | { |
513 | 9.11k | struct reduce r; |
514 | 9.11k | cairo_clip_path_t *clip_path; |
515 | 9.11k | cairo_status_t status; |
516 | | |
517 | 9.11k | return clip; |
518 | 0 | if (clip->path == NULL) |
519 | 0 | return clip; |
520 | | |
521 | 0 | r.clip = clip; |
522 | 0 | r.extents.p1.x = r.extents.p1.y = INT_MAX; |
523 | 0 | r.extents.p2.x = r.extents.p2.y = INT_MIN; |
524 | 0 | r.inside = FALSE; |
525 | |
|
526 | 0 | r.limit.p1.x = _cairo_fixed_from_int (clip->extents.x); |
527 | 0 | r.limit.p1.y = _cairo_fixed_from_int (clip->extents.y); |
528 | 0 | r.limit.p2.x = _cairo_fixed_from_int (clip->extents.x + clip->extents.width); |
529 | 0 | r.limit.p2.y = _cairo_fixed_from_int (clip->extents.y + clip->extents.height); |
530 | |
|
531 | 0 | clip_path = clip->path; |
532 | 0 | do { |
533 | 0 | r.current_point.x = 0; |
534 | 0 | r.current_point.y = 0; |
535 | 0 | r.last_move_to = r.current_point; |
536 | |
|
537 | 0 | status = _cairo_path_fixed_interpret_flat (&clip_path->path, |
538 | 0 | _reduce_move_to, |
539 | 0 | _reduce_line_to, |
540 | 0 | _reduce_close, |
541 | 0 | &r, |
542 | 0 | clip_path->tolerance); |
543 | 0 | assert (status == CAIRO_STATUS_SUCCESS); |
544 | 0 | _reduce_close (&r); |
545 | 0 | } while ((clip_path = clip_path->prev)); |
546 | | |
547 | 0 | if (! r.inside) { |
548 | 0 | _cairo_clip_path_destroy (clip->path); |
549 | 0 | clip->path = NULL; |
550 | 0 | } |
551 | |
|
552 | 0 | return _cairo_clip_intersect_box (clip, &r.extents); |
553 | 0 | } |
554 | | |
555 | | cairo_clip_t * |
556 | | _cairo_clip_reduce_to_rectangle (const cairo_clip_t *clip, |
557 | | const cairo_rectangle_int_t *r) |
558 | 1.50M | { |
559 | 1.50M | cairo_clip_t *copy; |
560 | | |
561 | 1.50M | if (_cairo_clip_is_all_clipped (clip)) |
562 | 0 | return (cairo_clip_t *) clip; |
563 | | |
564 | 1.50M | if (_cairo_clip_contains_rectangle (clip, r)) |
565 | 1.49M | return _cairo_clip_intersect_rectangle (NULL, r); |
566 | | |
567 | 9.11k | copy = _cairo_clip_copy_intersect_rectangle (clip, r); |
568 | 9.11k | if (_cairo_clip_is_all_clipped (copy)) |
569 | 0 | return copy; |
570 | | |
571 | 9.11k | return _cairo_clip_reduce_to_boxes (copy); |
572 | 9.11k | } |
573 | | |
574 | | cairo_clip_t * |
575 | | _cairo_clip_reduce_for_composite (const cairo_clip_t *clip, |
576 | | cairo_composite_rectangles_t *extents) |
577 | 1.50M | { |
578 | 1.50M | const cairo_rectangle_int_t *r; |
579 | | |
580 | 1.50M | r = extents->is_bounded ? &extents->bounded : &extents->unbounded; |
581 | 1.50M | return _cairo_clip_reduce_to_rectangle (clip, r); |
582 | 1.50M | } |
583 | | |
584 | | cairo_clip_t * |
585 | | _cairo_clip_from_boxes (const cairo_boxes_t *boxes) |
586 | 0 | { |
587 | 0 | cairo_box_t extents; |
588 | 0 | cairo_clip_t *clip = _cairo_clip_create (); |
589 | 0 | if (clip == NULL) |
590 | 0 | return _cairo_clip_set_all_clipped (clip); |
591 | | |
592 | 0 | if (unlikely (! _cairo_boxes_copy_to_clip (boxes, clip))) |
593 | 0 | return clip; |
594 | | |
595 | 0 | _cairo_boxes_extents (boxes, &extents); |
596 | 0 | _cairo_box_round_to_rectangle (&extents, &clip->extents); |
597 | |
|
598 | 0 | return clip; |
599 | 0 | } |