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.
7 * This library is free software; you can redistribute it and/or
8 * modify it either under the terms of the GNU Lesser General Public
9 * License version 2.1 as published by the Free Software Foundation
10 * (the "LGPL") or, at your option, under the terms of the Mozilla
11 * Public License Version 1.1 (the "MPL"). If you do not alter this
12 * notice, a recipient may use your version of this file under either
13 * the MPL or the LGPL.
15 * You should have received a copy of the LGPL along with this library
16 * in the file COPYING-LGPL-2.1; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 * You should have received a copy of the MPL along with this library
19 * in the file COPYING-MPL-1.1
21 * The contents of this file are subject to the Mozilla Public License
22 * Version 1.1 (the "License"); you may not use this file except in
23 * compliance with the License. You may obtain a copy of the License at
24 * http://www.mozilla.org/MPL/
26 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
27 * OF ANY KIND, either express or implied. See the LGPL or the MPL for
28 * the specific language governing rights and limitations.
30 * The Original Code is the cairo graphics library.
32 * The Initial Developer of the Original Code is University of Southern
36 * Carl D. Worth <cworth@cworth.org>
37 * Kristian Høgsberg <krh@redhat.com>
41 #include "cairo-clip-private.h"
43 static cairo_clip_path_t
*
44 _cairo_clip_path_reference (cairo_clip_path_t
*clip_path
);
47 _cairo_clip_path_destroy (cairo_clip_path_t
*clip_path
);
50 _cairo_clip_init (cairo_clip_t
*clip
, cairo_surface_t
*target
)
52 if (target
&& target
->backend
)
53 clip
->mode
= _cairo_surface_get_clip_mode (target
);
55 clip
->mode
= CAIRO_CLIP_MODE_MASK
;
57 clip
->all_clipped
= FALSE
;
60 clip
->surface_rect
.x
= 0;
61 clip
->surface_rect
.y
= 0;
62 clip
->surface_rect
.width
= 0;
63 clip
->surface_rect
.height
= 0;
73 _cairo_clip_init_copy (cairo_clip_t
*clip
, cairo_clip_t
*other
)
75 clip
->mode
= other
->mode
;
77 clip
->all_clipped
= other
->all_clipped
;
79 clip
->surface
= cairo_surface_reference (other
->surface
);
80 clip
->surface_rect
= other
->surface_rect
;
82 clip
->serial
= other
->serial
;
85 cairo_status_t status
;
87 clip
->region
= cairo_region_copy (other
->region
);
89 status
= cairo_region_status (clip
->region
);
90 if (unlikely (status
)) {
91 cairo_surface_destroy (clip
->surface
);
92 cairo_region_destroy (clip
->region
);
101 clip
->path
= _cairo_clip_path_reference (other
->path
);
103 return CAIRO_STATUS_SUCCESS
;
107 _cairo_clip_reset (cairo_clip_t
*clip
)
109 clip
->all_clipped
= FALSE
;
111 /* destroy any existing clip-region artifacts */
112 cairo_surface_destroy (clip
->surface
);
113 clip
->surface
= NULL
;
118 cairo_region_destroy (clip
->region
);
123 _cairo_clip_path_destroy (clip
->path
);
128 _cairo_clip_set_all_clipped (cairo_clip_t
*clip
, cairo_surface_t
*target
)
130 _cairo_clip_reset (clip
);
132 clip
->all_clipped
= TRUE
;
133 clip
->serial
= _cairo_surface_allocate_clip_serial (target
);
137 static cairo_status_t
138 _cairo_clip_path_intersect_to_rectangle (cairo_clip_path_t
*clip_path
,
139 cairo_rectangle_int_t
*rectangle
)
142 cairo_rectangle_int_t extents
;
144 _cairo_path_fixed_approximate_clip_extents (&clip_path
->path
, &extents
);
146 if (! _cairo_rectangle_intersect (rectangle
, &extents
))
147 return CAIRO_STATUS_SUCCESS
;
149 clip_path
= clip_path
->prev
;
152 return CAIRO_STATUS_SUCCESS
;
156 _cairo_clip_intersect_to_rectangle (cairo_clip_t
*clip
,
157 cairo_rectangle_int_t
*rectangle
)
159 cairo_status_t status
;
160 cairo_bool_t is_empty
;
163 return CAIRO_STATUS_SUCCESS
;
165 if (clip
->all_clipped
) {
166 *rectangle
= clip
->surface_rect
;
167 return CAIRO_STATUS_SUCCESS
;
171 status
= _cairo_clip_path_intersect_to_rectangle (clip
->path
,
173 if (unlikely (status
))
178 cairo_rectangle_int_t extents
;
180 cairo_region_get_extents (clip
->region
, &extents
);
181 is_empty
= _cairo_rectangle_intersect (rectangle
, &extents
);
183 return CAIRO_STATUS_SUCCESS
;
187 is_empty
= _cairo_rectangle_intersect (rectangle
, &clip
->surface_rect
);
189 return CAIRO_STATUS_SUCCESS
;
193 _cairo_clip_intersect_to_region (cairo_clip_t
*clip
,
194 cairo_region_t
*region
)
196 cairo_status_t status
;
199 return CAIRO_STATUS_SUCCESS
;
201 if (clip
->all_clipped
)
202 return cairo_region_intersect_rectangle (region
, &clip
->surface_rect
);
205 /* Intersect clip path into region. */
209 status
= cairo_region_intersect (region
, clip
->region
);
210 if (unlikely (status
))
215 return cairo_region_intersect_rectangle (region
, &clip
->surface_rect
);
217 return CAIRO_STATUS_SUCCESS
;
220 /* Combines the region of clip->surface given by extents in
221 * device backend coordinates into the given temporary surface,
222 * which has its origin at dst_x, dst_y in backend coordinates
225 _cairo_clip_combine_to_surface (cairo_clip_t
*clip
,
227 cairo_surface_t
*dst
,
230 const cairo_rectangle_int_t
*extents
)
232 cairo_surface_pattern_t pattern
;
233 cairo_status_t status
;
235 if (clip
->all_clipped
)
236 return CAIRO_STATUS_SUCCESS
;
238 _cairo_pattern_init_for_surface (&pattern
, clip
->surface
);
240 status
= _cairo_surface_composite (op
,
244 extents
->x
- clip
->surface_rect
.x
,
245 extents
->y
- clip
->surface_rect
.y
,
249 extents
->width
, extents
->height
);
251 _cairo_pattern_fini (&pattern
.base
);
256 static cairo_status_t
257 _cairo_clip_intersect_path (cairo_clip_t
*clip
,
258 cairo_path_fixed_t
*path
,
259 cairo_fill_rule_t fill_rule
,
261 cairo_antialias_t antialias
)
263 cairo_clip_path_t
*clip_path
;
264 cairo_status_t status
;
266 if (clip
->mode
!= CAIRO_CLIP_MODE_PATH
)
267 return CAIRO_INT_STATUS_UNSUPPORTED
;
269 clip_path
= malloc (sizeof (cairo_clip_path_t
));
270 if (unlikely (clip_path
== NULL
))
271 return _cairo_error (CAIRO_STATUS_NO_MEMORY
);
273 status
= _cairo_path_fixed_init_copy (&clip_path
->path
, path
);
274 if (unlikely (status
)) {
279 CAIRO_REFERENCE_COUNT_INIT (&clip_path
->ref_count
, 1);
280 clip_path
->fill_rule
= fill_rule
;
281 clip_path
->tolerance
= tolerance
;
282 clip_path
->antialias
= antialias
;
283 clip_path
->prev
= clip
->path
;
284 clip
->path
= clip_path
;
286 return CAIRO_STATUS_SUCCESS
;
289 static cairo_clip_path_t
*
290 _cairo_clip_path_reference (cairo_clip_path_t
*clip_path
)
292 if (clip_path
== NULL
)
295 assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&clip_path
->ref_count
));
297 _cairo_reference_count_inc (&clip_path
->ref_count
);
303 _cairo_clip_path_destroy (cairo_clip_path_t
*clip_path
)
305 if (clip_path
== NULL
)
308 assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&clip_path
->ref_count
));
310 if (! _cairo_reference_count_dec_and_test (&clip_path
->ref_count
))
313 _cairo_path_fixed_fini (&clip_path
->path
);
314 _cairo_clip_path_destroy (clip_path
->prev
);
319 static cairo_int_status_t
320 _cairo_clip_intersect_region (cairo_clip_t
*clip
,
321 cairo_traps_t
*traps
,
322 cairo_surface_t
*target
)
324 cairo_region_t
*region
;
325 cairo_int_status_t status
;
327 if (clip
->all_clipped
)
328 return CAIRO_STATUS_SUCCESS
;
330 if (clip
->mode
!= CAIRO_CLIP_MODE_REGION
)
331 return CAIRO_INT_STATUS_UNSUPPORTED
;
333 status
= _cairo_traps_extract_region (traps
, ®ion
);
338 status
= cairo_region_intersect (clip
->region
, region
);
339 cairo_region_destroy (region
);
341 clip
->region
= region
;
344 clip
->serial
= _cairo_surface_allocate_clip_serial (target
);
346 if (!clip
->region
|| cairo_region_is_empty (clip
->region
))
347 _cairo_clip_set_all_clipped (clip
, target
);
352 static cairo_status_t
353 _cairo_clip_intersect_mask (cairo_clip_t
*clip
,
354 cairo_traps_t
*traps
,
355 cairo_antialias_t antialias
,
356 cairo_surface_t
*target
)
358 cairo_pattern_union_t pattern
;
360 cairo_rectangle_int_t surface_rect
, target_rect
;
361 cairo_surface_t
*surface
= NULL
;
362 cairo_status_t status
= CAIRO_STATUS_SUCCESS
;
364 if (clip
->all_clipped
)
365 return CAIRO_STATUS_SUCCESS
;
367 /* Represent the clip as a mask surface. We create a new surface
368 * the size of the intersection of the old mask surface and the
369 * extents of the new clip path. */
371 _cairo_traps_extents (traps
, &extents
);
372 _cairo_box_round_to_rectangle (&extents
, &surface_rect
);
374 if (clip
->surface
!= NULL
) {
375 if (! _cairo_rectangle_intersect (&surface_rect
, &clip
->surface_rect
))
379 /* Intersect with the target surface rectangle so we don't use
380 * more memory and time than we need to. */
381 status
= _cairo_surface_get_extents (target
, &target_rect
);
382 if (status
== CAIRO_STATUS_SUCCESS
) {
383 if (! _cairo_rectangle_intersect (&surface_rect
, &target_rect
))
387 if (surface_rect
.width
== 0 || surface_rect
.height
== 0)
390 _cairo_pattern_init_solid (&pattern
.solid
, CAIRO_COLOR_WHITE
,
391 CAIRO_CONTENT_COLOR
);
392 /* The clipping operation should ideally be something like the following to
393 * avoid having to do as many passes over the data
395 if (clip->surface != NULL) {
396 _cairo_pattern_init_for_surface (&pattern.surface, clip->surface);
398 _cairo_pattern_init_solid (&pattern.solid, CAIRO_COLOR_WHITE,
399 CAIRO_CONTENT_COLOR);
401 status = _cairo_surface_composite_trapezoids (CAIRO_OPERATOR_IN,
412 However this operation is not accelerated by pixman
414 I believe the best possible operation would probably an unbounded SRC
415 operator. Using SRC we could potentially avoid having to initialize
416 the surface which would be ideal from an efficiency point of view.
417 However, CAIRO_OPERATOR_SOURCE is bounded by the trapezoid mask and
418 _cairo_surface_composite_trapezoids (CAIRO_OPERATOR_SOURCE) will assert
419 because it assumes CAIRO_OPERATOR_SOURCE has been converted into other
423 surface
= _cairo_surface_create_similar_solid (target
,
427 CAIRO_COLOR_TRANSPARENT
);
428 if (surface
->status
) {
429 _cairo_pattern_fini (&pattern
.base
);
430 return surface
->status
;
433 /* Render the new clipping path into the new mask surface. */
435 _cairo_traps_translate (traps
, -surface_rect
.x
, -surface_rect
.y
);
437 status
= _cairo_surface_composite_trapezoids (CAIRO_OPERATOR_ADD
,
448 _cairo_pattern_fini (&pattern
.base
);
450 if (unlikely (status
)) {
451 cairo_surface_destroy (surface
);
455 /* If there was a clip surface already, combine it with the new
456 * mask surface using the IN operator, so we get the intersection
457 * of the old and new clipping paths. */
459 if (clip
->surface
!= NULL
) {
460 _cairo_pattern_init_for_surface (&pattern
.surface
, clip
->surface
);
462 status
= _cairo_surface_composite (CAIRO_OPERATOR_IN
,
466 surface_rect
.x
- clip
->surface_rect
.x
,
467 surface_rect
.y
- clip
->surface_rect
.y
,
471 surface_rect
.height
);
473 _cairo_pattern_fini (&pattern
.base
);
475 if (unlikely (status
)) {
476 cairo_surface_destroy (surface
);
482 cairo_surface_destroy (clip
->surface
);
483 clip
->surface
= surface
;
484 clip
->surface_rect
= surface_rect
;
485 clip
->serial
= _cairo_surface_allocate_clip_serial (target
);
487 if (surface_rect
.width
== 0 || surface_rect
.height
== 0)
488 _cairo_clip_set_all_clipped (clip
, target
);
493 static cairo_status_t
494 _cairo_clip_intersect_mask_using_spans (cairo_clip_t
*clip
,
495 cairo_path_fixed_t
*path
,
496 cairo_fill_rule_t fill_rule
,
498 cairo_antialias_t antialias
,
499 cairo_surface_t
*target
)
501 cairo_span_renderer_t
*renderer
= NULL
;
502 cairo_pattern_union_t pattern
;
503 cairo_rectangle_int_t surface_rect
;
504 cairo_surface_t
*surface
= NULL
;
505 cairo_status_t status
;
507 cairo_composite_rectangles_t rects
;
509 if (clip
->all_clipped
)
510 return CAIRO_STATUS_SUCCESS
;
512 _cairo_pattern_init_solid (&pattern
.solid
, CAIRO_COLOR_WHITE
,
513 CAIRO_CONTENT_COLOR
);
515 /* If we have a clip surface we're going to use IN to combine our
516 * new clip with the old clip. The ADD is done to a transparent
517 * surface, as that's a fast way of doing it currently. We should
518 * really be using SOURCE instead, but _cairo_surface_composite()
519 * checks that it's not called with SOURCE or DEST. */
520 op
= clip
->surface
? CAIRO_OPERATOR_IN
: CAIRO_OPERATOR_ADD
;
522 /* Test if the target can composite spans. We're going to assume
523 * this is a good indicator of whether a similar surface is going
524 * to be able to composite spans too. */
525 if ( !_cairo_surface_check_span_renderer (op
,
531 status
= CAIRO_INT_STATUS_UNSUPPORTED
;
535 status
= _cairo_surface_get_extents (target
, &surface_rect
);
539 /* We'll create a new surface the size of the intersection of the
540 * old mask surface and the extents of the new clip path. */
542 cairo_rectangle_int_t extents
;
544 _cairo_path_fixed_approximate_clip_extents (path
, &extents
);
545 if (! _cairo_rectangle_intersect (&surface_rect
, &extents
))
548 if (clip
->surface
!= NULL
&&
549 ! _cairo_rectangle_intersect (&surface_rect
, &clip
->surface_rect
))
553 /* Make the new mask surface and optionally initialise it from the
554 * previous clip if we have one. */
555 surface
= _cairo_surface_create_similar_solid (target
,
559 CAIRO_COLOR_TRANSPARENT
);
560 if (surface
->status
) {
561 _cairo_pattern_fini (&pattern
.base
);
562 return surface
->status
;
566 cairo_surface_pattern_t old_clip
;
567 _cairo_pattern_init_for_surface (&old_clip
, clip
->surface
);
568 status
= _cairo_surface_composite (CAIRO_OPERATOR_ADD
,
572 surface_rect
.x
- clip
->surface_rect
.x
,
573 surface_rect
.y
- clip
->surface_rect
.y
,
577 surface_rect
.height
);
578 _cairo_pattern_fini (&old_clip
.base
);
583 _cairo_composite_rectangles_init (&rects
,
587 surface_rect
.height
);
591 /* Render the new clipping path into the new mask surface. We've
592 * chosen op to either combine the new clip path with the existing
593 * clip mask (if there is one) or just render it. */
594 status
=_cairo_path_fixed_fill_using_spans (op
, &pattern
.base
,
596 fill_rule
, tolerance
,
602 if (clip
->surface
!= NULL
)
603 cairo_surface_destroy (clip
->surface
);
604 clip
->surface
= surface
;
605 clip
->surface_rect
= surface_rect
;
606 clip
->serial
= _cairo_surface_allocate_clip_serial (target
);
609 if (surface_rect
.width
== 0 || surface_rect
.height
== 0)
610 _cairo_clip_set_all_clipped (clip
, target
);
614 renderer
->destroy(renderer
);
616 cairo_surface_destroy (surface
);
617 _cairo_pattern_fini (&pattern
.base
);
622 _cairo_clip_clip (cairo_clip_t
*clip
,
623 cairo_path_fixed_t
*path
,
624 cairo_fill_rule_t fill_rule
,
626 cairo_antialias_t antialias
,
627 cairo_surface_t
*target
)
629 cairo_status_t status
;
630 cairo_rectangle_int_t limits
, extents
;
632 cairo_box_t ignored_box
;
633 cairo_bool_t have_limits
;
635 if (clip
->all_clipped
)
636 return CAIRO_STATUS_SUCCESS
;
638 /* catch the empty clip path */
639 if (! path
->has_current_point
) {
640 _cairo_clip_set_all_clipped (clip
, target
);
641 return CAIRO_STATUS_SUCCESS
;
644 status
= _cairo_clip_intersect_path (clip
,
645 path
, fill_rule
, tolerance
,
647 if (status
== CAIRO_STATUS_SUCCESS
)
648 clip
->serial
= _cairo_surface_allocate_clip_serial (target
);
650 if (status
!= CAIRO_INT_STATUS_UNSUPPORTED
)
653 /* TODO: allow ANTIALIAS_NONE when we have a mono scan converter
655 if (antialias
!= CAIRO_ANTIALIAS_NONE
&&
656 !_cairo_path_fixed_is_box (path
, &ignored_box
) &&
657 !_cairo_path_fixed_is_region (path
))
659 status
= _cairo_clip_intersect_mask_using_spans (
660 clip
, path
, fill_rule
, tolerance
, antialias
, target
);
661 if (status
!= CAIRO_INT_STATUS_UNSUPPORTED
)
665 _cairo_traps_init (&traps
);
667 /* Limit the traps to the target surface and current clip
668 * - so we don't add more traps than needed. */
670 if (clip
->region
!= NULL
) {
671 cairo_region_get_extents (clip
->region
, &limits
);
675 if (clip
->surface
!= NULL
) {
677 if (! _cairo_rectangle_intersect (&limits
, &clip
->surface_rect
)) {
678 _cairo_clip_set_all_clipped (clip
, target
);
679 return CAIRO_STATUS_SUCCESS
;
682 limits
= clip
->surface_rect
;
687 status
= _cairo_surface_get_extents (target
, &extents
);
688 if (status
== CAIRO_STATUS_SUCCESS
) {
690 if (! _cairo_rectangle_intersect (&limits
, &extents
)) {
691 _cairo_clip_set_all_clipped (clip
, target
);
692 return CAIRO_STATUS_SUCCESS
;
703 _cairo_box_from_rectangle (&box
, &limits
);
704 _cairo_traps_limit (&traps
, &box
);
707 status
= _cairo_path_fixed_fill_to_traps (path
,
711 if (unlikely (status
))
714 status
= _cairo_clip_intersect_region (clip
, &traps
, target
);
715 if (status
!= CAIRO_INT_STATUS_UNSUPPORTED
)
718 status
= _cairo_clip_intersect_mask (clip
, &traps
, antialias
, target
);
721 _cairo_traps_fini (&traps
);
727 _cairo_clip_translate (cairo_clip_t
*clip
,
731 if (clip
->all_clipped
)
735 cairo_region_translate (clip
->region
,
736 _cairo_fixed_integer_part (tx
),
737 _cairo_fixed_integer_part (ty
));
741 clip
->surface_rect
.x
+= _cairo_fixed_integer_part (tx
);
742 clip
->surface_rect
.y
+= _cairo_fixed_integer_part (ty
);
746 cairo_clip_path_t
*clip_path
= clip
->path
;
747 cairo_matrix_t matrix
;
749 cairo_matrix_init_translate (&matrix
,
750 _cairo_fixed_to_double (tx
),
751 _cairo_fixed_to_double (ty
));
754 _cairo_path_fixed_transform (&clip_path
->path
, &matrix
);
755 clip_path
= clip_path
->prev
;
760 static cairo_status_t
761 _cairo_clip_path_reapply_clip_path (cairo_clip_t
*clip
,
762 cairo_clip_path_t
*clip_path
)
764 cairo_status_t status
;
766 if (clip_path
->prev
) {
767 status
= _cairo_clip_path_reapply_clip_path (clip
, clip_path
->prev
);
768 if (_cairo_status_is_error (status
))
772 return _cairo_clip_intersect_path (clip
,
774 clip_path
->fill_rule
,
775 clip_path
->tolerance
,
776 clip_path
->antialias
);
780 _cairo_clip_init_deep_copy (cairo_clip_t
*clip
,
782 cairo_surface_t
*target
)
784 cairo_status_t status
;
786 _cairo_clip_init (clip
, target
);
788 if (other
->mode
!= clip
->mode
) {
789 /* We should reapply the original clip path in this case, and let
790 * whatever the right handling is happen */
793 clip
->region
= cairo_region_copy (other
->region
);
794 if (unlikely ((status
= cairo_region_status (clip
->region
))))
798 if (other
->surface
) {
800 status
= _cairo_surface_clone_similar (target
, other
->surface
,
804 other
->surface_rect
.width
,
805 other
->surface_rect
.height
,
808 if (unlikely (status
))
811 clip
->surface_rect
= other
->surface_rect
;
813 /* src offset was 0, so we expect an exact replica of the surface */
819 status
= _cairo_clip_path_reapply_clip_path (clip
, other
->path
);
820 if (_cairo_status_is_error (status
))
825 return CAIRO_STATUS_SUCCESS
;
829 cairo_region_destroy (clip
->region
);
831 cairo_surface_destroy (clip
->surface
);
836 const cairo_rectangle_list_t _cairo_rectangles_nil
=
837 { CAIRO_STATUS_NO_MEMORY
, NULL
, 0 };
838 static const cairo_rectangle_list_t _cairo_rectangles_not_representable
=
839 { CAIRO_STATUS_CLIP_NOT_REPRESENTABLE
, NULL
, 0 };
842 _cairo_clip_int_rect_to_user (cairo_gstate_t
*gstate
,
843 cairo_rectangle_int_t
*clip_rect
,
844 cairo_rectangle_t
*user_rect
)
846 cairo_bool_t is_tight
;
848 double x1
= clip_rect
->x
;
849 double y1
= clip_rect
->y
;
850 double x2
= clip_rect
->x
+ (int) clip_rect
->width
;
851 double y2
= clip_rect
->y
+ (int) clip_rect
->height
;
853 _cairo_gstate_backend_to_user_rectangle (gstate
,
859 user_rect
->width
= x2
- x1
;
860 user_rect
->height
= y2
- y1
;
865 cairo_rectangle_list_t
*
866 _cairo_clip_copy_rectangle_list (cairo_clip_t
*clip
, cairo_gstate_t
*gstate
)
868 cairo_rectangle_list_t
*list
;
869 cairo_rectangle_t
*rectangles
= NULL
;
872 if (clip
->all_clipped
)
875 if (clip
->path
|| clip
->surface
) {
876 _cairo_error_throw (CAIRO_STATUS_CLIP_NOT_REPRESENTABLE
);
877 return (cairo_rectangle_list_t
*) &_cairo_rectangles_not_representable
;
883 n_rects
= cairo_region_num_rectangles (clip
->region
);
886 rectangles
= _cairo_malloc_ab (n_rects
, sizeof (cairo_rectangle_t
));
887 if (unlikely (rectangles
== NULL
)) {
888 _cairo_error_throw (CAIRO_STATUS_NO_MEMORY
);
889 return (cairo_rectangle_list_t
*) &_cairo_rectangles_nil
;
892 for (i
= 0; i
< n_rects
; ++i
) {
893 cairo_rectangle_int_t clip_rect
;
895 cairo_region_get_rectangle (clip
->region
, i
, &clip_rect
);
897 if (!_cairo_clip_int_rect_to_user(gstate
, &clip_rect
, &rectangles
[i
])) {
898 _cairo_error_throw (CAIRO_STATUS_CLIP_NOT_REPRESENTABLE
);
900 return (cairo_rectangle_list_t
*) &_cairo_rectangles_not_representable
;
905 cairo_rectangle_int_t extents
;
909 rectangles
= malloc(sizeof (cairo_rectangle_t
));
910 if (unlikely (rectangles
== NULL
)) {
911 _cairo_error_throw (CAIRO_STATUS_NO_MEMORY
);
912 return (cairo_rectangle_list_t
*) &_cairo_rectangles_nil
;
915 if (_cairo_surface_get_extents (_cairo_gstate_get_target (gstate
), &extents
) ||
916 !_cairo_clip_int_rect_to_user(gstate
, &extents
, rectangles
))
918 _cairo_error_throw (CAIRO_STATUS_CLIP_NOT_REPRESENTABLE
);
920 return (cairo_rectangle_list_t
*) &_cairo_rectangles_not_representable
;
925 list
= malloc (sizeof (cairo_rectangle_list_t
));
926 if (unlikely (list
== NULL
)) {
927 _cairo_error_throw (CAIRO_STATUS_NO_MEMORY
);
929 return (cairo_rectangle_list_t
*) &_cairo_rectangles_nil
;
932 list
->status
= CAIRO_STATUS_SUCCESS
;
933 list
->rectangles
= rectangles
;
934 list
->num_rectangles
= n_rects
;
939 * cairo_rectangle_list_destroy:
940 * @rectangle_list: a rectangle list, as obtained from cairo_copy_clip_rectangles()
942 * Unconditionally frees @rectangle_list and all associated
943 * references. After this call, the @rectangle_list pointer must not
949 cairo_rectangle_list_destroy (cairo_rectangle_list_t
*rectangle_list
)
951 if (rectangle_list
== NULL
|| rectangle_list
== &_cairo_rectangles_nil
||
952 rectangle_list
== &_cairo_rectangles_not_representable
)
955 free (rectangle_list
->rectangles
);
956 free (rectangle_list
);