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>
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"
53 static freed_pool_t clip_path_pool;
54 static freed_pool_t clip_pool;
56 const cairo_clip_t __cairo_clip_all;
58 static cairo_clip_path_t *
59 _cairo_clip_path_create (cairo_clip_t *clip)
61 cairo_clip_path_t *clip_path;
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))
70 CAIRO_REFERENCE_COUNT_INIT (&clip_path->ref_count, 1);
72 clip_path->prev = clip->path;
73 clip->path = clip_path;
79 _cairo_clip_path_reference (cairo_clip_path_t *clip_path)
81 assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&clip_path->ref_count));
83 _cairo_reference_count_inc (&clip_path->ref_count);
89 _cairo_clip_path_destroy (cairo_clip_path_t *clip_path)
91 assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&clip_path->ref_count));
93 if (! _cairo_reference_count_dec_and_test (&clip_path->ref_count))
96 _cairo_path_fixed_fini (&clip_path->path);
98 if (clip_path->prev != NULL)
99 _cairo_clip_path_destroy (clip_path->prev);
101 _freed_pool_put (&clip_path_pool, clip_path);
105 _cairo_clip_create (void)
109 clip = _freed_pool_get (&clip_pool);
110 if (unlikely (clip == NULL)) {
111 clip = malloc (sizeof (cairo_clip_t));
112 if (unlikely (clip == NULL))
116 clip->extents = _cairo_unbounded_rectangle;
122 clip->is_region = FALSE;
128 _cairo_clip_destroy (cairo_clip_t *clip)
130 if (clip == NULL || _cairo_clip_is_all_clipped (clip))
133 if (clip->path != NULL)
134 _cairo_clip_path_destroy (clip->path);
136 if (clip->boxes != &clip->embedded_box)
138 cairo_region_destroy (clip->region);
140 _freed_pool_put (&clip_pool, clip);
144 _cairo_clip_copy (const cairo_clip_t *clip)
148 if (clip == NULL || _cairo_clip_is_all_clipped (clip))
149 return (cairo_clip_t *) clip;
151 copy = _cairo_clip_create ();
156 copy->path = _cairo_clip_path_reference (clip->path);
158 if (clip->num_boxes) {
159 if (clip->num_boxes == 1) {
160 copy->boxes = ©->embedded_box;
162 copy->boxes = _cairo_malloc_ab (clip->num_boxes, sizeof (cairo_box_t));
163 if (unlikely (copy->boxes == NULL))
164 return _cairo_clip_set_all_clipped (copy);
167 memcpy (copy->boxes, clip->boxes,
168 clip->num_boxes * sizeof (cairo_box_t));
169 copy->num_boxes = clip->num_boxes;
172 copy->extents = clip->extents;
173 copy->region = cairo_region_reference (clip->region);
174 copy->is_region = clip->is_region;
180 _cairo_clip_copy_path (const cairo_clip_t *clip)
184 if (clip == NULL || _cairo_clip_is_all_clipped (clip))
185 return (cairo_clip_t *) clip;
187 assert (clip->num_boxes);
189 copy = _cairo_clip_create ();
193 copy->extents = clip->extents;
195 copy->path = _cairo_clip_path_reference (clip->path);
201 _cairo_clip_copy_region (const cairo_clip_t *clip)
206 if (clip == NULL || _cairo_clip_is_all_clipped (clip))
207 return (cairo_clip_t *) clip;
209 assert (clip->num_boxes);
211 copy = _cairo_clip_create ();
215 copy->extents = clip->extents;
217 if (clip->num_boxes == 1) {
218 copy->boxes = ©->embedded_box;
220 copy->boxes = _cairo_malloc_ab (clip->num_boxes, sizeof (cairo_box_t));
221 if (unlikely (copy->boxes == NULL))
222 return _cairo_clip_set_all_clipped (copy);
225 for (i = 0; i < clip->num_boxes; i++) {
226 copy->boxes[i].p1.x = _cairo_fixed_floor (clip->boxes[i].p1.x);
227 copy->boxes[i].p1.y = _cairo_fixed_floor (clip->boxes[i].p1.y);
228 copy->boxes[i].p2.x = _cairo_fixed_ceil (clip->boxes[i].p2.x);
229 copy->boxes[i].p2.y = _cairo_fixed_ceil (clip->boxes[i].p2.y);
231 copy->num_boxes = clip->num_boxes;
233 copy->region = cairo_region_reference (clip->region);
234 copy->is_region = TRUE;
240 _cairo_clip_intersect_path (cairo_clip_t *clip,
241 const cairo_path_fixed_t *path,
242 cairo_fill_rule_t fill_rule,
244 cairo_antialias_t antialias)
246 cairo_clip_path_t *clip_path;
247 cairo_status_t status;
248 cairo_rectangle_int_t extents;
251 if (_cairo_clip_is_all_clipped (clip))
254 /* catch the empty clip path */
255 if (_cairo_path_fixed_fill_is_empty (path))
256 return _cairo_clip_set_all_clipped (clip);
258 if (_cairo_path_fixed_is_box (path, &box)) {
259 if (antialias == CAIRO_ANTIALIAS_NONE) {
260 box.p1.x = _cairo_fixed_round_down (box.p1.x);
261 box.p1.y = _cairo_fixed_round_down (box.p1.y);
262 box.p2.x = _cairo_fixed_round_down (box.p2.x);
263 box.p2.y = _cairo_fixed_round_down (box.p2.y);
266 return _cairo_clip_intersect_box (clip, &box);
268 if (_cairo_path_fixed_fill_is_rectilinear (path))
269 return _cairo_clip_intersect_rectilinear_path (clip, path,
270 fill_rule, antialias);
272 _cairo_path_fixed_approximate_clip_extents (path, &extents);
273 if (extents.width == 0 || extents.height == 0)
274 return _cairo_clip_set_all_clipped (clip);
276 clip = _cairo_clip_intersect_rectangle (clip, &extents);
277 if (_cairo_clip_is_all_clipped (clip))
280 clip_path = _cairo_clip_path_create (clip);
281 if (unlikely (clip_path == NULL))
282 return _cairo_clip_set_all_clipped (clip);
284 status = _cairo_path_fixed_init_copy (&clip_path->path, path);
285 if (unlikely (status))
286 return _cairo_clip_set_all_clipped (clip);
288 clip_path->fill_rule = fill_rule;
289 clip_path->tolerance = tolerance;
290 clip_path->antialias = antialias;
293 cairo_region_destroy (clip->region);
297 clip->is_region = FALSE;
301 static cairo_clip_t *
302 _cairo_clip_intersect_clip_path (cairo_clip_t *clip,
303 const cairo_clip_path_t *clip_path)
306 clip = _cairo_clip_intersect_clip_path (clip, clip_path->prev);
308 return _cairo_clip_intersect_path (clip,
310 clip_path->fill_rule,
311 clip_path->tolerance,
312 clip_path->antialias);
316 _cairo_clip_intersect_clip (cairo_clip_t *clip,
317 const cairo_clip_t *other)
319 if (_cairo_clip_is_all_clipped (clip))
326 return _cairo_clip_copy (other);
328 if (_cairo_clip_is_all_clipped (other))
329 return _cairo_clip_set_all_clipped (clip);
331 if (! _cairo_rectangle_intersect (&clip->extents, &other->extents))
332 return _cairo_clip_set_all_clipped (clip);
334 if (other->num_boxes) {
337 _cairo_boxes_init_for_array (&boxes, other->boxes, other->num_boxes);
338 clip = _cairo_clip_intersect_boxes (clip, &boxes);
341 if (! _cairo_clip_is_all_clipped (clip)) {
343 if (clip->path == NULL)
344 clip->path = _cairo_clip_path_reference (other->path);
346 clip = _cairo_clip_intersect_clip_path (clip, other->path);
351 cairo_region_destroy (clip->region);
354 clip->is_region = FALSE;
360 _cairo_clip_equal (const cairo_clip_t *clip_a,
361 const cairo_clip_t *clip_b)
363 const cairo_clip_path_t *cp_a, *cp_b;
365 /* are both all-clipped or no-clip? */
366 if (clip_a == clip_b)
369 /* or just one of them? */
370 if (clip_a == NULL || clip_b == NULL ||
371 _cairo_clip_is_all_clipped (clip_a) ||
372 _cairo_clip_is_all_clipped (clip_b))
377 /* We have a pair of normal clips, check their contents */
379 if (clip_a->num_boxes != clip_b->num_boxes)
382 if (memcmp (clip_a->boxes, clip_b->boxes,
383 sizeof (cairo_box_t) * clip_a->num_boxes))
388 while (cp_a && cp_b) {
392 /* XXX compare reduced polygons? */
394 if (cp_a->antialias != cp_b->antialias)
397 if (cp_a->tolerance != cp_b->tolerance)
400 if (cp_a->fill_rule != cp_b->fill_rule)
403 if (! _cairo_path_fixed_equal (&cp_a->path,
411 return cp_a == NULL && cp_b == NULL;
414 static cairo_clip_t *
415 _cairo_clip_path_copy_with_translation (cairo_clip_t *clip,
416 cairo_clip_path_t *other_path,
419 cairo_status_t status;
420 cairo_clip_path_t *clip_path;
422 if (other_path->prev != NULL)
423 clip = _cairo_clip_path_copy_with_translation (clip, other_path->prev,
425 if (_cairo_clip_is_all_clipped (clip))
428 clip_path = _cairo_clip_path_create (clip);
429 if (unlikely (clip_path == NULL))
430 return _cairo_clip_set_all_clipped (clip);
432 status = _cairo_path_fixed_init_copy (&clip_path->path,
434 if (unlikely (status))
435 return _cairo_clip_set_all_clipped (clip);
437 _cairo_path_fixed_translate (&clip_path->path, fx, fy);
439 clip_path->fill_rule = other_path->fill_rule;
440 clip_path->tolerance = other_path->tolerance;
441 clip_path->antialias = other_path->antialias;
447 _cairo_clip_translate (cairo_clip_t *clip, int tx, int ty)
450 cairo_clip_path_t *clip_path;
452 if (clip == NULL || _cairo_clip_is_all_clipped (clip))
455 if (tx == 0 && ty == 0)
458 fx = _cairo_fixed_from_int (tx);
459 fy = _cairo_fixed_from_int (ty);
461 for (i = 0; i < clip->num_boxes; i++) {
462 clip->boxes[i].p1.x += fx;
463 clip->boxes[i].p2.x += fx;
464 clip->boxes[i].p1.y += fy;
465 clip->boxes[i].p2.y += fy;
468 clip->extents.x += tx;
469 clip->extents.y += ty;
471 if (clip->path == NULL)
474 clip_path = clip->path;
476 clip = _cairo_clip_path_copy_with_translation (clip, clip_path, fx, fy);
477 _cairo_clip_path_destroy (clip_path);
482 static cairo_status_t
483 _cairo_path_fixed_add_box (cairo_path_fixed_t *path,
484 const cairo_box_t *box)
486 cairo_status_t status;
488 status = _cairo_path_fixed_move_to (path, box->p1.x, box->p1.y);
489 if (unlikely (status))
492 status = _cairo_path_fixed_line_to (path, box->p2.x, box->p1.y);
493 if (unlikely (status))
496 status = _cairo_path_fixed_line_to (path, box->p2.x, box->p2.y);
497 if (unlikely (status))
500 status = _cairo_path_fixed_line_to (path, box->p1.x, box->p2.y);
501 if (unlikely (status))
504 return _cairo_path_fixed_close_path (path);
507 static cairo_status_t
508 _cairo_path_fixed_init_from_boxes (cairo_path_fixed_t *path,
509 const cairo_boxes_t *boxes)
511 cairo_status_t status;
512 const struct _cairo_boxes_chunk *chunk;
515 _cairo_path_fixed_init (path);
516 if (boxes->num_boxes == 0)
517 return CAIRO_STATUS_SUCCESS;
519 for (chunk = &boxes->chunks; chunk; chunk = chunk->next) {
520 for (i = 0; i < chunk->count; i++) {
521 status = _cairo_path_fixed_add_box (path, &chunk->base[i]);
522 if (unlikely (status)) {
523 _cairo_path_fixed_fini (path);
529 return CAIRO_STATUS_SUCCESS;
532 static cairo_clip_t *
533 _cairo_clip_intersect_clip_path_transformed (cairo_clip_t *clip,
534 const cairo_clip_path_t *clip_path,
535 const cairo_matrix_t *m)
537 cairo_path_fixed_t path;
540 clip = _cairo_clip_intersect_clip_path_transformed (clip,
544 if (_cairo_path_fixed_init_copy (&path, &clip_path->path))
545 return _cairo_clip_set_all_clipped (clip);
547 _cairo_path_fixed_transform (&path, m);
549 clip = _cairo_clip_intersect_path (clip,
551 clip_path->fill_rule,
552 clip_path->tolerance,
553 clip_path->antialias);
554 _cairo_path_fixed_fini (&path);
560 _cairo_clip_transform (cairo_clip_t *clip, const cairo_matrix_t *m)
564 if (clip == NULL || _cairo_clip_is_all_clipped (clip))
567 if (_cairo_matrix_is_translation (m))
568 return _cairo_clip_translate (clip, m->x0, m->y0);
570 copy = _cairo_clip_create ();
572 if (clip->num_boxes) {
573 cairo_path_fixed_t path;
576 _cairo_boxes_init_for_array (&boxes, clip->boxes, clip->num_boxes);
577 _cairo_path_fixed_init_from_boxes (&path, &boxes);
578 _cairo_path_fixed_transform (&path, m);
580 copy = _cairo_clip_intersect_path (copy, &path,
581 CAIRO_FILL_RULE_WINDING,
583 CAIRO_ANTIALIAS_DEFAULT);
585 _cairo_path_fixed_fini (&path);
589 copy = _cairo_clip_intersect_clip_path_transformed (copy, clip->path,m);
591 _cairo_clip_destroy (clip);
596 _cairo_clip_copy_with_translation (const cairo_clip_t *clip, int tx, int ty)
601 if (clip == NULL || _cairo_clip_is_all_clipped (clip))
602 return (cairo_clip_t *)clip;
604 if (tx == 0 && ty == 0)
605 return _cairo_clip_copy (clip);
607 copy = _cairo_clip_create ();
609 return _cairo_clip_set_all_clipped (copy);
611 fx = _cairo_fixed_from_int (tx);
612 fy = _cairo_fixed_from_int (ty);
614 if (clip->num_boxes) {
615 if (clip->num_boxes == 1) {
616 copy->boxes = ©->embedded_box;
618 copy->boxes = _cairo_malloc_ab (clip->num_boxes, sizeof (cairo_box_t));
619 if (unlikely (copy->boxes == NULL))
620 return _cairo_clip_set_all_clipped (copy);
623 for (i = 0; i < clip->num_boxes; i++) {
624 copy->boxes[i].p1.x = clip->boxes[i].p1.x + fx;
625 copy->boxes[i].p2.x = clip->boxes[i].p2.x + fx;
626 copy->boxes[i].p1.y = clip->boxes[i].p1.y + fy;
627 copy->boxes[i].p2.y = clip->boxes[i].p2.y + fy;
629 copy->num_boxes = clip->num_boxes;
632 copy->extents = clip->extents;
633 copy->extents.x += tx;
634 copy->extents.y += ty;
636 if (clip->path == NULL)
639 return _cairo_clip_path_copy_with_translation (copy, clip->path, fx, fy);
643 _cairo_clip_contains_extents (const cairo_clip_t *clip,
644 const cairo_composite_rectangles_t *extents)
646 const cairo_rectangle_int_t *rect;
648 rect = extents->is_bounded ? &extents->bounded : &extents->unbounded;
649 return _cairo_clip_contains_rectangle (clip, rect);
653 _cairo_debug_print_clip (FILE *stream, const cairo_clip_t *clip)
658 fprintf (stream, "no clip\n");
662 if (_cairo_clip_is_all_clipped (clip)) {
663 fprintf (stream, "clip: all-clipped\n");
667 fprintf (stream, "clip:\n");
668 fprintf (stream, " extents: (%d, %d) x (%d, %d), is-region? %d",
669 clip->extents.x, clip->extents.y,
670 clip->extents.width, clip->extents.height,
673 fprintf (stream, " num_boxes = %d\n", clip->num_boxes);
674 for (i = 0; i < clip->num_boxes; i++) {
675 fprintf (stream, " [%d] = (%f, %f), (%f, %f)\n", i,
676 _cairo_fixed_to_double (clip->boxes[i].p1.x),
677 _cairo_fixed_to_double (clip->boxes[i].p1.y),
678 _cairo_fixed_to_double (clip->boxes[i].p2.x),
679 _cairo_fixed_to_double (clip->boxes[i].p2.y));
683 cairo_clip_path_t *clip_path = clip->path;
685 fprintf (stream, "path: aa=%d, tolerance=%f, rule=%d: ",
686 clip_path->antialias,
687 clip_path->tolerance,
688 clip_path->fill_rule);
689 _cairo_debug_print_path (stream, &clip_path->path);
690 fprintf (stream, "\n");
691 } while ((clip_path = clip_path->prev) != NULL);
695 const cairo_rectangle_int_t *
696 _cairo_clip_get_extents (const cairo_clip_t *clip)
699 return &_cairo_unbounded_rectangle;
701 if (_cairo_clip_is_all_clipped (clip))
702 return &_cairo_empty_rectangle;
704 return &clip->extents;
707 const cairo_rectangle_list_t _cairo_rectangles_nil =
708 { CAIRO_STATUS_NO_MEMORY, NULL, 0 };
709 static const cairo_rectangle_list_t _cairo_rectangles_not_representable =
710 { CAIRO_STATUS_CLIP_NOT_REPRESENTABLE, NULL, 0 };
713 _cairo_clip_int_rect_to_user (cairo_gstate_t *gstate,
714 cairo_rectangle_int_t *clip_rect,
715 cairo_rectangle_t *user_rect)
717 cairo_bool_t is_tight;
719 double x1 = clip_rect->x;
720 double y1 = clip_rect->y;
721 double x2 = clip_rect->x + (int) clip_rect->width;
722 double y2 = clip_rect->y + (int) clip_rect->height;
724 _cairo_gstate_backend_to_user_rectangle (gstate,
730 user_rect->width = x2 - x1;
731 user_rect->height = y2 - y1;
736 cairo_rectangle_list_t *
737 _cairo_rectangle_list_create_in_error (cairo_status_t status)
739 cairo_rectangle_list_t *list;
741 if (status == CAIRO_STATUS_NO_MEMORY)
742 return (cairo_rectangle_list_t*) &_cairo_rectangles_nil;
743 if (status == CAIRO_STATUS_CLIP_NOT_REPRESENTABLE)
744 return (cairo_rectangle_list_t*) &_cairo_rectangles_not_representable;
746 list = malloc (sizeof (*list));
747 if (unlikely (list == NULL)) {
748 status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
749 return (cairo_rectangle_list_t*) &_cairo_rectangles_nil;
752 list->status = status;
753 list->rectangles = NULL;
754 list->num_rectangles = 0;
759 cairo_rectangle_list_t *
760 _cairo_clip_copy_rectangle_list (cairo_clip_t *clip, cairo_gstate_t *gstate)
762 #define ERROR_LIST(S) _cairo_rectangle_list_create_in_error (_cairo_error (S))
764 cairo_rectangle_list_t *list;
765 cairo_rectangle_t *rectangles = NULL;
766 cairo_region_t *region = NULL;
771 return ERROR_LIST (CAIRO_STATUS_CLIP_NOT_REPRESENTABLE);
773 if (_cairo_clip_is_all_clipped (clip))
776 if (! _cairo_clip_is_region (clip))
777 return ERROR_LIST (CAIRO_STATUS_CLIP_NOT_REPRESENTABLE);
779 region = _cairo_clip_get_region (clip);
781 return ERROR_LIST (CAIRO_STATUS_NO_MEMORY);
783 n_rects = cairo_region_num_rectangles (region);
785 rectangles = _cairo_malloc_ab (n_rects, sizeof (cairo_rectangle_t));
786 if (unlikely (rectangles == NULL)) {
787 return ERROR_LIST (CAIRO_STATUS_NO_MEMORY);
790 for (i = 0; i < n_rects; ++i) {
791 cairo_rectangle_int_t clip_rect;
793 cairo_region_get_rectangle (region, i, &clip_rect);
795 if (! _cairo_clip_int_rect_to_user (gstate,
800 return ERROR_LIST (CAIRO_STATUS_CLIP_NOT_REPRESENTABLE);
806 list = malloc (sizeof (cairo_rectangle_list_t));
807 if (unlikely (list == NULL)) {
809 return ERROR_LIST (CAIRO_STATUS_NO_MEMORY);
812 list->status = CAIRO_STATUS_SUCCESS;
813 list->rectangles = rectangles;
814 list->num_rectangles = n_rects;
821 * cairo_rectangle_list_destroy:
822 * @rectangle_list: a rectangle list, as obtained from cairo_copy_clip_rectangle_list()
824 * Unconditionally frees @rectangle_list and all associated
825 * references. After this call, the @rectangle_list pointer must not
831 cairo_rectangle_list_destroy (cairo_rectangle_list_t *rectangle_list)
833 if (rectangle_list == NULL || rectangle_list == &_cairo_rectangles_nil ||
834 rectangle_list == &_cairo_rectangles_not_representable)
837 free (rectangle_list->rectangles);
838 free (rectangle_list);
842 _cairo_clip_reset_static_data (void)
844 _freed_pool_reset (&clip_path_pool);
845 _freed_pool_reset (&clip_pool);