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
4 * Copyright © 2002 University of Southern California
5 * Copyright © 2005 Red Hat, Inc.
6 * Copyright © 2009 Chris Wilson
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.
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
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/
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.
31 * The Original Code is the cairo graphics library.
33 * The Initial Developer of the Original Code is University of Southern
37 * Carl D. Worth <cworth@cworth.org>
38 * Kristian Høgsberg <krh@redhat.com>
39 * Chris Wilson <chris@chris-wilson.co.uk>
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"
69 _cairo_clip_contains_rectangle_box (const cairo_clip_t
*clip
,
70 const cairo_rectangle_int_t
*rect
,
71 const cairo_box_t
*box
)
75 /* clip == NULL means no clip, so the clip contains everything */
79 if (_cairo_clip_is_all_clipped (clip
))
82 /* If we have a non-trivial path, just say no */
86 if (! _cairo_rectangle_contains_rectangle (&clip
->extents
, rect
))
89 if (clip
->num_boxes
== 0)
92 /* Check for a clip-box that wholly contains the rectangle */
93 for (i
= 0; i
< clip
->num_boxes
; i
++) {
94 if (box
->p1
.x
>= clip
->boxes
[i
].p1
.x
&&
95 box
->p1
.y
>= clip
->boxes
[i
].p1
.y
&&
96 box
->p2
.x
<= clip
->boxes
[i
].p2
.x
&&
97 box
->p2
.y
<= clip
->boxes
[i
].p2
.y
)
107 _cairo_clip_contains_box (const cairo_clip_t
*clip
,
108 const cairo_box_t
*box
)
110 cairo_rectangle_int_t rect
;
112 _cairo_box_round_to_rectangle (box
, &rect
);
113 return _cairo_clip_contains_rectangle_box(clip
, &rect
, box
);
117 _cairo_clip_contains_rectangle (const cairo_clip_t
*clip
,
118 const cairo_rectangle_int_t
*rect
)
122 box
.p1
.x
= _cairo_fixed_from_int (rect
->x
);
123 box
.p1
.y
= _cairo_fixed_from_int (rect
->y
);
124 box
.p2
.x
= _cairo_fixed_from_int (rect
->x
+ rect
->width
);
125 box
.p2
.y
= _cairo_fixed_from_int (rect
->y
+ rect
->height
);
127 return _cairo_clip_contains_rectangle_box (clip
, rect
, &box
);
131 _cairo_clip_intersect_rectilinear_path (cairo_clip_t
*clip
,
132 const cairo_path_fixed_t
*path
,
133 cairo_fill_rule_t fill_rule
,
134 cairo_antialias_t antialias
)
136 cairo_status_t status
;
139 _cairo_boxes_init (&boxes
);
140 status
= _cairo_path_fixed_fill_rectilinear_to_boxes (path
,
144 if (likely (status
== CAIRO_STATUS_SUCCESS
&& boxes
.num_boxes
))
145 clip
= _cairo_clip_intersect_boxes (clip
, &boxes
);
147 clip
= _cairo_clip_set_all_clipped (clip
);
148 _cairo_boxes_fini (&boxes
);
153 static cairo_clip_t
*
154 _cairo_clip_intersect_rectangle_box (cairo_clip_t
*clip
,
155 const cairo_rectangle_int_t
*r
,
156 const cairo_box_t
*box
)
158 cairo_box_t extents_box
;
159 cairo_bool_t changed
= FALSE
;
163 clip
= _cairo_clip_create ();
165 return _cairo_clip_set_all_clipped (clip
);
168 if (clip
->num_boxes
== 0) {
169 clip
->boxes
= &clip
->embedded_box
;
170 clip
->boxes
[0] = *box
;
172 if (clip
->path
== NULL
) {
175 if (! _cairo_rectangle_intersect (&clip
->extents
, r
))
176 return _cairo_clip_set_all_clipped (clip
);
178 if (clip
->path
== NULL
)
179 clip
->is_region
= _cairo_box_is_pixel_aligned (box
);
183 /* Does the new box wholly subsume the clip? Perform a cheap check
184 * for the common condition of a single clip rectangle.
186 if (clip
->num_boxes
== 1 &&
187 clip
->boxes
[0].p1
.x
>= box
->p1
.x
&&
188 clip
->boxes
[0].p1
.y
>= box
->p1
.y
&&
189 clip
->boxes
[0].p2
.x
<= box
->p2
.x
&&
190 clip
->boxes
[0].p2
.y
<= box
->p2
.y
)
195 for (i
= j
= 0; i
< clip
->num_boxes
; i
++) {
196 cairo_box_t
*b
= &clip
->boxes
[j
];
201 if (box
->p1
.x
> b
->p1
.x
)
202 b
->p1
.x
= box
->p1
.x
, changed
= TRUE
;
203 if (box
->p2
.x
< b
->p2
.x
)
204 b
->p2
.x
= box
->p2
.x
, changed
= TRUE
;
206 if (box
->p1
.y
> b
->p1
.y
)
207 b
->p1
.y
= box
->p1
.y
, changed
= TRUE
;
208 if (box
->p2
.y
< b
->p2
.y
)
209 b
->p2
.y
= box
->p2
.y
, changed
= TRUE
;
211 j
+= b
->p2
.x
> b
->p1
.x
&& b
->p2
.y
> b
->p1
.y
;
215 if (clip
->num_boxes
== 0)
216 return _cairo_clip_set_all_clipped (clip
);
221 extents_box
= clip
->boxes
[0];
222 for (i
= 1; i
< clip
->num_boxes
; i
++) {
223 if (clip
->boxes
[i
].p1
.x
< extents_box
.p1
.x
)
224 extents_box
.p1
.x
= clip
->boxes
[i
].p1
.x
;
226 if (clip
->boxes
[i
].p1
.y
< extents_box
.p1
.y
)
227 extents_box
.p1
.y
= clip
->boxes
[i
].p1
.y
;
229 if (clip
->boxes
[i
].p2
.x
> extents_box
.p2
.x
)
230 extents_box
.p2
.x
= clip
->boxes
[i
].p2
.x
;
232 if (clip
->boxes
[i
].p2
.y
> extents_box
.p2
.y
)
233 extents_box
.p2
.y
= clip
->boxes
[i
].p2
.y
;
236 if (clip
->path
== NULL
) {
237 _cairo_box_round_to_rectangle (&extents_box
, &clip
->extents
);
239 cairo_rectangle_int_t extents_rect
;
241 _cairo_box_round_to_rectangle (&extents_box
, &extents_rect
);
242 if (! _cairo_rectangle_intersect (&clip
->extents
, &extents_rect
))
243 return _cairo_clip_set_all_clipped (clip
);
247 cairo_region_destroy (clip
->region
);
251 clip
->is_region
= FALSE
;
256 _cairo_clip_intersect_box (cairo_clip_t
*clip
,
257 const cairo_box_t
*box
)
259 cairo_rectangle_int_t r
;
261 if (_cairo_clip_is_all_clipped (clip
))
264 _cairo_box_round_to_rectangle (box
, &r
);
265 if (r
.width
== 0 || r
.height
== 0)
266 return _cairo_clip_set_all_clipped (clip
);
268 return _cairo_clip_intersect_rectangle_box (clip
, &r
, box
);
272 _cairo_clip_intersect_boxes (cairo_clip_t
*clip
,
273 const cairo_boxes_t
*boxes
)
275 cairo_boxes_t clip_boxes
;
277 cairo_rectangle_int_t extents
;
279 if (_cairo_clip_is_all_clipped (clip
))
282 if (boxes
->num_boxes
== 0)
283 return _cairo_clip_set_all_clipped (clip
);
285 if (boxes
->num_boxes
== 1)
286 return _cairo_clip_intersect_box (clip
, boxes
->chunks
.base
);
289 clip
= _cairo_clip_create ();
291 if (clip
->num_boxes
) {
292 _cairo_boxes_init_for_array (&clip_boxes
, clip
->boxes
, clip
->num_boxes
);
293 if (unlikely (_cairo_boxes_intersect (&clip_boxes
, boxes
, &clip_boxes
))) {
294 clip
= _cairo_clip_set_all_clipped (clip
);
298 if (clip
->boxes
!= &clip
->embedded_box
)
305 if (boxes
->num_boxes
== 0) {
306 clip
= _cairo_clip_set_all_clipped (clip
);
308 } else if (boxes
->num_boxes
== 1) {
309 clip
->boxes
= &clip
->embedded_box
;
310 clip
->boxes
[0] = boxes
->chunks
.base
[0];
313 clip
->boxes
= _cairo_boxes_to_array (boxes
, &clip
->num_boxes
, TRUE
);
315 _cairo_boxes_extents (boxes
, &limits
);
317 _cairo_box_round_to_rectangle (&limits
, &extents
);
318 if (clip
->path
== NULL
) {
319 clip
->extents
= extents
;
320 } else if (! _cairo_rectangle_intersect (&clip
->extents
, &extents
)) {
321 clip
= _cairo_clip_set_all_clipped (clip
);
326 cairo_region_destroy (clip
->region
);
329 clip
->is_region
= FALSE
;
332 if (boxes
== &clip_boxes
)
333 _cairo_boxes_fini (&clip_boxes
);
339 _cairo_clip_intersect_rectangle (cairo_clip_t
*clip
,
340 const cairo_rectangle_int_t
*r
)
344 if (_cairo_clip_is_all_clipped (clip
))
347 if (r
->width
== 0 || r
->height
== 0)
348 return _cairo_clip_set_all_clipped (clip
);
350 box
.p1
.x
= _cairo_fixed_from_int (r
->x
);
351 box
.p1
.y
= _cairo_fixed_from_int (r
->y
);
352 box
.p2
.x
= _cairo_fixed_from_int (r
->x
+ r
->width
);
353 box
.p2
.y
= _cairo_fixed_from_int (r
->y
+ r
->height
);
355 return _cairo_clip_intersect_rectangle_box (clip
, r
, &box
);
364 cairo_point_t current_point
;
365 cairo_point_t last_move_to
;
369 _add_clipped_edge (struct reduce
*r
,
370 const cairo_point_t
*p1
,
371 const cairo_point_t
*p2
,
376 x
= _cairo_edge_compute_intersection_x_for_y (p1
, p2
, y1
);
377 if (x
< r
->extents
.p1
.x
)
380 x
= _cairo_edge_compute_intersection_x_for_y (p1
, p2
, y2
);
381 if (x
> r
->extents
.p2
.x
)
384 if (y1
< r
->extents
.p1
.y
)
385 r
->extents
.p1
.y
= y1
;
387 if (y2
> r
->extents
.p2
.y
)
388 r
->extents
.p2
.y
= y2
;
394 _add_edge (struct reduce
*r
,
395 const cairo_point_t
*p1
,
396 const cairo_point_t
*p2
)
410 if (bottom
< r
->limit
.p1
.y
|| top
> r
->limit
.p2
.y
)
414 const cairo_point_t
*t
= p1
;
419 if (p2
->x
<= r
->limit
.p1
.x
|| p1
->x
>= r
->limit
.p2
.x
)
422 for (n
= 0; n
< r
->clip
->num_boxes
; n
++) {
423 const cairo_box_t
*limits
= &r
->clip
->boxes
[n
];
425 if (bottom
< limits
->p1
.y
|| top
> limits
->p2
.y
)
428 if (p2
->x
<= limits
->p1
.x
|| p1
->x
>= limits
->p2
.x
)
431 if (p1
->x
>= limits
->p1
.x
&& p2
->x
<= limits
->p1
.x
) {
437 p1_y
= _cairo_edge_compute_intersection_y_for_x (p1
, p2
,
439 p2_y
= _cairo_edge_compute_intersection_y_for_x (p1
, p2
,
455 if (top_y
< limits
->p1
.y
)
456 top_y
= limits
->p1
.y
;
458 if (bot_y
> limits
->p2
.y
)
459 bot_y
= limits
->p2
.y
;
461 _add_clipped_edge (r
, p1
, p2
, top_y
, bot_y
);
465 static cairo_status_t
466 _reduce_line_to (void *closure
,
467 const cairo_point_t
*point
)
469 struct reduce
*r
= closure
;
471 _add_edge (r
, &r
->current_point
, point
);
472 r
->current_point
= *point
;
474 return CAIRO_STATUS_SUCCESS
;
477 static cairo_status_t
478 _reduce_close (void *closure
)
480 struct reduce
*r
= closure
;
482 return _reduce_line_to (r
, &r
->last_move_to
);
485 static cairo_status_t
486 _reduce_move_to (void *closure
,
487 const cairo_point_t
*point
)
489 struct reduce
*r
= closure
;
490 cairo_status_t status
;
492 /* close current subpath */
493 status
= _reduce_close (closure
);
495 /* make sure that the closure represents a degenerate path */
496 r
->current_point
= *point
;
497 r
->last_move_to
= *point
;
502 static cairo_clip_t
*
503 _cairo_clip_reduce_to_boxes (cairo_clip_t
*clip
)
506 cairo_clip_path_t
*clip_path
;
507 cairo_status_t status
;
510 if (clip
->path
== NULL
)
514 r
.extents
.p1
.x
= r
.extents
.p1
.y
= INT_MAX
;
515 r
.extents
.p2
.x
= r
.extents
.p2
.y
= INT_MIN
;
518 r
.limit
.p1
.x
= _cairo_fixed_from_int (clip
->extents
.x
);
519 r
.limit
.p1
.y
= _cairo_fixed_from_int (clip
->extents
.y
);
520 r
.limit
.p2
.x
= _cairo_fixed_from_int (clip
->extents
.x
+ clip
->extents
.width
);
521 r
.limit
.p2
.y
= _cairo_fixed_from_int (clip
->extents
.y
+ clip
->extents
.height
);
523 clip_path
= clip
->path
;
525 r
.current_point
.x
= 0;
526 r
.current_point
.y
= 0;
527 r
.last_move_to
= r
.current_point
;
529 status
= _cairo_path_fixed_interpret_flat (&clip_path
->path
,
534 clip_path
->tolerance
);
535 assert (status
== CAIRO_STATUS_SUCCESS
);
537 } while ((clip_path
= clip_path
->prev
));
540 _cairo_clip_path_destroy (clip
->path
);
544 return _cairo_clip_intersect_box (clip
, &r
.extents
);
548 _cairo_clip_reduce_to_rectangle (const cairo_clip_t
*clip
,
549 const cairo_rectangle_int_t
*r
)
553 if (_cairo_clip_is_all_clipped (clip
))
554 return (cairo_clip_t
*) clip
;
556 if (_cairo_clip_contains_rectangle (clip
, r
))
557 return _cairo_clip_intersect_rectangle (NULL
, r
);
559 copy
= _cairo_clip_copy_intersect_rectangle (clip
, r
);
560 if (_cairo_clip_is_all_clipped (copy
))
563 return _cairo_clip_reduce_to_boxes (copy
);
567 _cairo_clip_reduce_for_composite (const cairo_clip_t
*clip
,
568 cairo_composite_rectangles_t
*extents
)
570 const cairo_rectangle_int_t
*r
;
572 r
= extents
->is_bounded
? &extents
->bounded
: &extents
->unbounded
;
573 return _cairo_clip_reduce_to_rectangle (clip
, r
);
577 _cairo_clip_from_boxes (const cairo_boxes_t
*boxes
)
580 cairo_clip_t
*clip
= _cairo_clip_create ();
582 return _cairo_clip_set_all_clipped (clip
);
585 if(boxes
->num_boxes
== 1) {
586 clip
->boxes
= &clip
->embedded_box
;
587 clip
->boxes
[0] = boxes
->chunks
.base
[0];
590 clip
->boxes
= _cairo_boxes_to_array (boxes
, &clip
->num_boxes
, TRUE
);
591 if (clip
->boxes
== NULL
)
592 return _cairo_clip_set_all_clipped (clip
);
595 _cairo_boxes_extents (boxes
, &extents
);
596 _cairo_box_round_to_rectangle (&extents
, &clip
->extents
);