ShaderEffect subclasses from Effect, not DependencyObject
[moon.git] / cairo / src / cairo-clip.c
blob8a0d4db15e8cc01b8013b4cc4aa4ef29962f1248
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
33 * California.
35 * Contributor(s):
36 * Carl D. Worth <cworth@cworth.org>
37 * Kristian Høgsberg <krh@redhat.com>
40 #include "cairoint.h"
41 #include "cairo-clip-private.h"
43 static cairo_clip_path_t *
44 _cairo_clip_path_reference (cairo_clip_path_t *clip_path);
46 static void
47 _cairo_clip_path_destroy (cairo_clip_path_t *clip_path);
49 void
50 _cairo_clip_init (cairo_clip_t *clip, cairo_surface_t *target)
52 if (target)
53 clip->mode = _cairo_surface_get_clip_mode (target);
54 else
55 clip->mode = CAIRO_CLIP_MODE_MASK;
57 clip->all_clipped = FALSE;
59 clip->surface = NULL;
60 clip->surface_rect.x = 0;
61 clip->surface_rect.y = 0;
62 clip->surface_rect.width = 0;
63 clip->surface_rect.height = 0;
65 clip->serial = 0;
67 _cairo_region_init (&clip->region);
68 clip->has_region = FALSE;
70 clip->path = NULL;
73 cairo_status_t
74 _cairo_clip_init_copy (cairo_clip_t *clip, cairo_clip_t *other)
76 clip->mode = other->mode;
78 clip->all_clipped = other->all_clipped;
80 clip->surface = cairo_surface_reference (other->surface);
81 clip->surface_rect = other->surface_rect;
83 clip->serial = other->serial;
85 _cairo_region_init (&clip->region);
87 if (other->has_region) {
88 cairo_status_t status;
90 status = _cairo_region_copy (&clip->region, &other->region);
91 if (status) {
92 _cairo_region_fini (&clip->region);
93 cairo_surface_destroy (clip->surface);
94 return status;
96 clip->has_region = TRUE;
97 } else {
98 clip->has_region = FALSE;
101 clip->path = _cairo_clip_path_reference (other->path);
103 return CAIRO_STATUS_SUCCESS;
106 void
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;
115 clip->serial = 0;
117 if (clip->has_region) {
118 /* _cairo_region_fini just releases the resources used but
119 * doesn't bother with leaving the region in a valid state.
120 * So _cairo_region_init has to be called afterwards. */
121 _cairo_region_fini (&clip->region);
122 _cairo_region_init (&clip->region);
124 clip->has_region = FALSE;
127 _cairo_clip_path_destroy (clip->path);
128 clip->path = NULL;
131 static void
132 _cairo_clip_set_all_clipped (cairo_clip_t *clip, cairo_surface_t *target)
134 _cairo_clip_reset (clip);
136 clip->all_clipped = TRUE;
137 clip->serial = _cairo_surface_allocate_clip_serial (target);
141 static cairo_status_t
142 _cairo_clip_path_intersect_to_rectangle (cairo_clip_path_t *clip_path,
143 cairo_rectangle_int_t *rectangle)
145 while (clip_path) {
146 cairo_status_t status;
147 cairo_traps_t traps;
148 cairo_box_t extents;
149 cairo_rectangle_int_t extents_rect;
151 _cairo_box_from_rectangle (&extents, rectangle);
153 _cairo_traps_init (&traps);
154 _cairo_traps_limit (&traps, &extents);
156 status = _cairo_path_fixed_fill_to_traps (&clip_path->path,
157 clip_path->fill_rule,
158 clip_path->tolerance,
159 &traps);
160 if (status) {
161 _cairo_traps_fini (&traps);
162 return status;
165 _cairo_traps_extents (&traps, &extents);
166 _cairo_traps_fini (&traps);
168 _cairo_box_round_to_rectangle (&extents, &extents_rect);
169 if (! _cairo_rectangle_intersect (rectangle, &extents_rect))
170 return CAIRO_STATUS_SUCCESS;
172 clip_path = clip_path->prev;
175 return CAIRO_STATUS_SUCCESS;
178 cairo_status_t
179 _cairo_clip_intersect_to_rectangle (cairo_clip_t *clip,
180 cairo_rectangle_int_t *rectangle)
182 cairo_status_t status;
183 cairo_bool_t is_empty;
185 if (!clip)
186 return CAIRO_STATUS_SUCCESS;
188 if (clip->all_clipped) {
189 *rectangle = clip->surface_rect;
190 return CAIRO_STATUS_SUCCESS;
193 if (clip->path) {
194 status = _cairo_clip_path_intersect_to_rectangle (clip->path,
195 rectangle);
196 if (status)
197 return status;
200 if (clip->has_region) {
201 cairo_region_t intersection;
203 _cairo_region_init_rect (&intersection, rectangle);
205 status = _cairo_region_intersect (&intersection, &clip->region,
206 &intersection);
208 if (!status)
209 _cairo_region_get_extents (&intersection, rectangle);
211 _cairo_region_fini (&intersection);
213 if (status)
214 return status;
217 if (clip->surface)
218 is_empty = _cairo_rectangle_intersect (rectangle, &clip->surface_rect);
220 return CAIRO_STATUS_SUCCESS;
223 cairo_status_t
224 _cairo_clip_intersect_to_region (cairo_clip_t *clip,
225 cairo_region_t *region)
227 cairo_status_t status;
229 if (!clip)
230 return CAIRO_STATUS_SUCCESS;
232 if (clip->all_clipped) {
233 cairo_region_t clip_rect;
235 _cairo_region_init_rect (&clip_rect, &clip->surface_rect);
237 status = _cairo_region_intersect (region, &clip_rect, region);
239 _cairo_region_fini (&clip_rect);
241 return status;
244 if (clip->path) {
245 /* Intersect clip path into region. */
248 if (clip->has_region) {
249 status = _cairo_region_intersect (region, &clip->region, region);
250 if (status)
251 return status;
254 if (clip->surface) {
255 cairo_region_t clip_rect;
257 _cairo_region_init_rect (&clip_rect, &clip->surface_rect);
259 status = _cairo_region_intersect (region, &clip_rect, region);
261 _cairo_region_fini (&clip_rect);
263 if (status)
264 return status;
267 return CAIRO_STATUS_SUCCESS;
270 /* Combines the region of clip->surface given by extents in
271 * device backend coordinates into the given temporary surface,
272 * which has its origin at dst_x, dst_y in backend coordinates
274 cairo_status_t
275 _cairo_clip_combine_to_surface (cairo_clip_t *clip,
276 cairo_operator_t op,
277 cairo_surface_t *dst,
278 int dst_x,
279 int dst_y,
280 const cairo_rectangle_int_t *extents)
282 cairo_surface_pattern_t pattern;
283 cairo_status_t status;
285 if (clip->all_clipped)
286 return CAIRO_STATUS_SUCCESS;
288 _cairo_pattern_init_for_surface (&pattern, clip->surface);
290 status = _cairo_surface_composite (op,
291 &pattern.base,
292 NULL,
293 dst,
294 extents->x - clip->surface_rect.x,
295 extents->y - clip->surface_rect.y,
296 0, 0,
297 extents->x - dst_x,
298 extents->y - dst_y,
299 extents->width, extents->height);
301 _cairo_pattern_fini (&pattern.base);
303 return status;
306 static cairo_status_t
307 _cairo_clip_intersect_path (cairo_clip_t *clip,
308 cairo_path_fixed_t *path,
309 cairo_fill_rule_t fill_rule,
310 double tolerance,
311 cairo_antialias_t antialias)
313 cairo_clip_path_t *clip_path;
314 cairo_status_t status;
316 if (clip->mode != CAIRO_CLIP_MODE_PATH)
317 return CAIRO_INT_STATUS_UNSUPPORTED;
319 clip_path = malloc (sizeof (cairo_clip_path_t));
320 if (clip_path == NULL)
321 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
323 status = _cairo_path_fixed_init_copy (&clip_path->path, path);
324 if (status) {
325 free (clip_path);
326 return status;
329 CAIRO_REFERENCE_COUNT_INIT (&clip_path->ref_count, 1);
330 clip_path->fill_rule = fill_rule;
331 clip_path->tolerance = tolerance;
332 clip_path->antialias = antialias;
333 clip_path->prev = clip->path;
334 clip->path = clip_path;
336 return CAIRO_STATUS_SUCCESS;
339 static cairo_clip_path_t *
340 _cairo_clip_path_reference (cairo_clip_path_t *clip_path)
342 if (clip_path == NULL)
343 return NULL;
345 assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&clip_path->ref_count));
347 _cairo_reference_count_inc (&clip_path->ref_count);
349 return clip_path;
352 static void
353 _cairo_clip_path_destroy (cairo_clip_path_t *clip_path)
355 if (clip_path == NULL)
356 return;
358 assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&clip_path->ref_count));
360 if (! _cairo_reference_count_dec_and_test (&clip_path->ref_count))
361 return;
363 _cairo_path_fixed_fini (&clip_path->path);
364 _cairo_clip_path_destroy (clip_path->prev);
365 free (clip_path);
369 static cairo_int_status_t
370 _cairo_clip_intersect_region (cairo_clip_t *clip,
371 cairo_traps_t *traps,
372 cairo_surface_t *target)
374 cairo_region_t region;
375 cairo_int_status_t status;
377 if (clip->all_clipped)
378 return CAIRO_STATUS_SUCCESS;
380 if (clip->mode != CAIRO_CLIP_MODE_REGION)
381 return CAIRO_INT_STATUS_UNSUPPORTED;
383 status = _cairo_traps_extract_region (traps, &region);
385 if (status)
386 return status;
388 if (!clip->has_region) {
389 status = _cairo_region_copy (&clip->region, &region);
390 if (status == CAIRO_STATUS_SUCCESS)
391 clip->has_region = TRUE;
392 } else {
393 cairo_region_t intersection;
395 _cairo_region_init (&intersection);
397 status = _cairo_region_intersect (&intersection,
398 &clip->region,
399 &region);
401 if (status == CAIRO_STATUS_SUCCESS)
402 status = _cairo_region_copy (&clip->region, &intersection);
404 _cairo_region_fini (&intersection);
407 clip->serial = _cairo_surface_allocate_clip_serial (target);
408 _cairo_region_fini (&region);
410 if (! _cairo_region_not_empty (&clip->region))
411 _cairo_clip_set_all_clipped (clip, target);
413 return status;
416 static cairo_status_t
417 _cairo_clip_intersect_mask (cairo_clip_t *clip,
418 cairo_traps_t *traps,
419 cairo_antialias_t antialias,
420 cairo_surface_t *target)
422 cairo_pattern_union_t pattern;
423 cairo_box_t extents;
424 cairo_rectangle_int_t surface_rect, target_rect;
425 cairo_surface_t *surface = NULL;
426 cairo_status_t status;
428 if (clip->all_clipped)
429 return CAIRO_STATUS_SUCCESS;
431 /* Represent the clip as a mask surface. We create a new surface
432 * the size of the intersection of the old mask surface and the
433 * extents of the new clip path. */
435 _cairo_traps_extents (traps, &extents);
436 _cairo_box_round_to_rectangle (&extents, &surface_rect);
438 if (clip->surface != NULL) {
439 if (! _cairo_rectangle_intersect (&surface_rect, &clip->surface_rect))
440 goto DONE;
443 /* Intersect with the target surface rectangle so we don't use
444 * more memory and time than we need to. */
445 status = _cairo_surface_get_extents (target, &target_rect);
446 if (status == CAIRO_STATUS_SUCCESS) {
447 if (! _cairo_rectangle_intersect (&surface_rect, &target_rect))
448 goto DONE;
451 if (surface_rect.width == 0 || surface_rect.height == 0)
452 goto DONE;
454 _cairo_pattern_init_solid (&pattern.solid, CAIRO_COLOR_WHITE,
455 CAIRO_CONTENT_COLOR);
456 /* The clipping operation should ideally be something like the following to
457 * avoid having to do as many passes over the data
459 if (clip->surface != NULL) {
460 _cairo_pattern_init_for_surface (&pattern.surface, clip->surface);
461 } else {
462 _cairo_pattern_init_solid (&pattern.solid, CAIRO_COLOR_WHITE,
463 CAIRO_CONTENT_COLOR);
465 status = _cairo_surface_composite_trapezoids (CAIRO_OPERATOR_IN,
466 &pattern.base,
467 surface,
468 antialias,
469 0, 0,
470 0, 0,
471 surface_rect.width,
472 surface_rect.height,
473 traps->traps,
474 traps->num_traps);
476 However this operation is not accelerated by pixman
478 I believe the best possible operation would probably an unbounded SRC
479 operator. Using SRC we could potentially avoid having to initialize
480 the surface which would be ideal from an efficiency point of view.
481 However, _cairo_surface_composite_trapezoids (CAIRO_OPERATOR_SOURCE) is
482 bounded by the mask.
486 surface = _cairo_surface_create_similar_solid (target,
487 CAIRO_CONTENT_ALPHA,
488 surface_rect.width,
489 surface_rect.height,
490 CAIRO_COLOR_TRANSPARENT);
491 if (surface->status) {
492 _cairo_pattern_fini (&pattern.base);
493 return surface->status;
496 /* Render the new clipping path into the new mask surface. */
498 _cairo_traps_translate (traps, -surface_rect.x, -surface_rect.y);
500 status = _cairo_surface_composite_trapezoids (CAIRO_OPERATOR_ADD,
501 &pattern.base,
502 surface,
503 antialias,
504 0, 0,
505 0, 0,
506 surface_rect.width,
507 surface_rect.height,
508 traps->traps,
509 traps->num_traps);
511 _cairo_pattern_fini (&pattern.base);
513 if (status) {
514 cairo_surface_destroy (surface);
515 return status;
518 /* If there was a clip surface already, combine it with the new
519 * mask surface using the IN operator, so we get the intersection
520 * of the old and new clipping paths. */
522 if (clip->surface != NULL) {
523 _cairo_pattern_init_for_surface (&pattern.surface, clip->surface);
525 status = _cairo_surface_composite (CAIRO_OPERATOR_IN,
526 &pattern.base,
527 NULL,
528 surface,
529 surface_rect.x - clip->surface_rect.x,
530 surface_rect.y - clip->surface_rect.y,
531 0, 0,
532 0, 0,
533 surface_rect.width,
534 surface_rect.height);
536 _cairo_pattern_fini (&pattern.base);
538 if (status) {
539 cairo_surface_destroy (surface);
540 return status;
544 DONE:
545 cairo_surface_destroy (clip->surface);
546 clip->surface = surface;
547 clip->surface_rect = surface_rect;
548 clip->serial = _cairo_surface_allocate_clip_serial (target);
550 if (surface_rect.width == 0 || surface_rect.height == 0)
551 _cairo_clip_set_all_clipped (clip, target);
553 return status;
556 cairo_status_t
557 _cairo_clip_clip (cairo_clip_t *clip,
558 cairo_path_fixed_t *path,
559 cairo_fill_rule_t fill_rule,
560 double tolerance,
561 cairo_antialias_t antialias,
562 cairo_surface_t *target)
564 cairo_status_t status;
565 cairo_rectangle_int_t rectangle;
566 cairo_traps_t traps;
568 if (clip->all_clipped)
569 return CAIRO_STATUS_SUCCESS;
571 /* catch the empty clip path */
572 if (! path->has_current_point) {
573 _cairo_clip_set_all_clipped (clip, target);
574 return CAIRO_STATUS_SUCCESS;
577 status = _cairo_clip_intersect_path (clip,
578 path, fill_rule, tolerance,
579 antialias);
580 if (status == CAIRO_STATUS_SUCCESS)
581 clip->serial = _cairo_surface_allocate_clip_serial (target);
583 if (status != CAIRO_INT_STATUS_UNSUPPORTED)
584 return status;
586 _cairo_traps_init (&traps);
588 /* Limit the traps to the target surface
589 * - so we don't add more traps than needed. */
590 status = _cairo_surface_get_extents (target, &rectangle);
591 if (status == CAIRO_STATUS_SUCCESS) {
592 cairo_box_t box;
594 _cairo_box_from_rectangle (&box, &rectangle);
595 _cairo_traps_limit (&traps, &box);
598 status = _cairo_path_fixed_fill_to_traps (path,
599 fill_rule,
600 tolerance,
601 &traps);
602 if (status)
603 goto bail;
605 status = _cairo_clip_intersect_region (clip, &traps, target);
606 if (status != CAIRO_INT_STATUS_UNSUPPORTED)
607 goto bail;
609 status = _cairo_clip_intersect_mask (clip, &traps, antialias, target);
611 bail:
612 _cairo_traps_fini (&traps);
614 return status;
617 void
618 _cairo_clip_translate (cairo_clip_t *clip,
619 cairo_fixed_t tx,
620 cairo_fixed_t ty)
622 if (clip->all_clipped)
623 return;
625 if (clip->has_region) {
626 _cairo_region_translate (&clip->region,
627 _cairo_fixed_integer_part (tx),
628 _cairo_fixed_integer_part (ty));
631 if (clip->surface) {
632 clip->surface_rect.x += _cairo_fixed_integer_part (tx);
633 clip->surface_rect.y += _cairo_fixed_integer_part (ty);
636 if (clip->path) {
637 cairo_clip_path_t *clip_path = clip->path;
638 cairo_matrix_t matrix;
640 cairo_matrix_init_translate (&matrix,
641 _cairo_fixed_to_double (tx),
642 _cairo_fixed_to_double (ty));
644 while (clip_path) {
645 _cairo_path_fixed_transform (&clip_path->path, &matrix);
646 clip_path = clip_path->prev;
651 static cairo_status_t
652 _cairo_clip_path_reapply_clip_path (cairo_clip_t *clip,
653 cairo_clip_path_t *clip_path)
655 cairo_status_t status;
657 if (clip_path->prev) {
658 status = _cairo_clip_path_reapply_clip_path (clip, clip_path->prev);
659 if (status && status != CAIRO_INT_STATUS_UNSUPPORTED)
660 return status;
663 return _cairo_clip_intersect_path (clip,
664 &clip_path->path,
665 clip_path->fill_rule,
666 clip_path->tolerance,
667 clip_path->antialias);
670 cairo_status_t
671 _cairo_clip_init_deep_copy (cairo_clip_t *clip,
672 cairo_clip_t *other,
673 cairo_surface_t *target)
675 cairo_status_t status;
677 _cairo_clip_init (clip, target);
679 if (other->mode != clip->mode) {
680 /* We should reapply the original clip path in this case, and let
681 * whatever the right handling is happen */
682 } else {
683 if (other->has_region) {
684 status = _cairo_region_copy (&clip->region, &other->region);
685 if (status)
686 goto BAIL;
688 clip->has_region = TRUE;
691 if (other->surface) {
692 int dx, dy;
693 status = _cairo_surface_clone_similar (target, other->surface,
696 other->surface_rect.width,
697 other->surface_rect.height,
698 &dx, &dy,
699 &clip->surface);
700 if (status)
701 goto BAIL;
703 clip->surface_rect = other->surface_rect;
705 /* src offset was 0, so we expect an exact replica of the surface */
706 assert (dx == 0);
707 assert (dy == 0);
710 if (other->path) {
711 status = _cairo_clip_path_reapply_clip_path (clip, other->path);
712 if (status && status != CAIRO_INT_STATUS_UNSUPPORTED)
713 goto BAIL;
717 return CAIRO_STATUS_SUCCESS;
719 BAIL:
720 if (clip->has_region)
721 _cairo_region_fini (&clip->region);
722 if (clip->surface)
723 cairo_surface_destroy (clip->surface);
725 return status;
728 const cairo_rectangle_list_t _cairo_rectangles_nil =
729 { CAIRO_STATUS_NO_MEMORY, NULL, 0 };
730 static const cairo_rectangle_list_t _cairo_rectangles_not_representable =
731 { CAIRO_STATUS_CLIP_NOT_REPRESENTABLE, NULL, 0 };
733 static cairo_bool_t
734 _cairo_clip_int_rect_to_user (cairo_gstate_t *gstate,
735 cairo_rectangle_int_t *clip_rect,
736 cairo_rectangle_t *user_rect)
738 cairo_bool_t is_tight;
740 double x1 = clip_rect->x;
741 double y1 = clip_rect->y;
742 double x2 = clip_rect->x + (int) clip_rect->width;
743 double y2 = clip_rect->y + (int) clip_rect->height;
745 _cairo_gstate_backend_to_user_rectangle (gstate,
746 &x1, &y1, &x2, &y2,
747 &is_tight);
749 user_rect->x = x1;
750 user_rect->y = y1;
751 user_rect->width = x2 - x1;
752 user_rect->height = y2 - y1;
754 return is_tight;
757 cairo_rectangle_list_t *
758 _cairo_clip_copy_rectangle_list (cairo_clip_t *clip, cairo_gstate_t *gstate)
760 cairo_rectangle_list_t *list;
761 cairo_rectangle_t *rectangles = NULL;
762 int n_boxes = 0;
764 if (clip->all_clipped)
765 goto DONE;
767 if (clip->path || clip->surface) {
768 _cairo_error_throw (CAIRO_STATUS_CLIP_NOT_REPRESENTABLE);
769 return (cairo_rectangle_list_t*) &_cairo_rectangles_not_representable;
772 if (clip->has_region) {
773 cairo_box_int_t *boxes;
774 int i;
776 if (_cairo_region_get_boxes (&clip->region, &n_boxes, &boxes))
777 return (cairo_rectangle_list_t*) &_cairo_rectangles_nil;
779 if (n_boxes) {
780 rectangles = _cairo_malloc_ab (n_boxes, sizeof (cairo_rectangle_t));
781 if (rectangles == NULL) {
782 _cairo_region_boxes_fini (&clip->region, boxes);
783 _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
784 return (cairo_rectangle_list_t*) &_cairo_rectangles_nil;
787 for (i = 0; i < n_boxes; ++i) {
788 cairo_rectangle_int_t clip_rect;
790 clip_rect.x = boxes[i].p1.x;
791 clip_rect.y = boxes[i].p1.y;
792 clip_rect.width = boxes[i].p2.x - boxes[i].p1.x;
793 clip_rect.height = boxes[i].p2.y - boxes[i].p1.y;
795 if (!_cairo_clip_int_rect_to_user(gstate, &clip_rect, &rectangles[i])) {
796 _cairo_error_throw (CAIRO_STATUS_CLIP_NOT_REPRESENTABLE);
797 _cairo_region_boxes_fini (&clip->region, boxes);
798 free (rectangles);
799 return (cairo_rectangle_list_t*) &_cairo_rectangles_not_representable;
804 _cairo_region_boxes_fini (&clip->region, boxes);
805 } else {
806 cairo_rectangle_int_t extents;
808 n_boxes = 1;
810 rectangles = malloc(sizeof (cairo_rectangle_t));
811 if (rectangles == NULL) {
812 _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
813 return (cairo_rectangle_list_t*) &_cairo_rectangles_nil;
816 if (_cairo_surface_get_extents (_cairo_gstate_get_target (gstate), &extents) ||
817 !_cairo_clip_int_rect_to_user(gstate, &extents, rectangles))
819 _cairo_error_throw (CAIRO_STATUS_CLIP_NOT_REPRESENTABLE);
820 free (rectangles);
821 return (cairo_rectangle_list_t*) &_cairo_rectangles_not_representable;
825 DONE:
826 list = malloc (sizeof (cairo_rectangle_list_t));
827 if (list == NULL) {
828 _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
829 free (rectangles);
830 return (cairo_rectangle_list_t*) &_cairo_rectangles_nil;
833 list->status = CAIRO_STATUS_SUCCESS;
834 list->rectangles = rectangles;
835 list->num_rectangles = n_boxes;
836 return list;
840 * cairo_rectangle_list_destroy:
841 * @rectangle_list: a rectangle list, as obtained from cairo_copy_clip_rectangles()
843 * Unconditionally frees @rectangle_list and all associated
844 * references. After this call, the @rectangle_list pointer must not
845 * be dereferenced.
847 * Since: 1.4
849 void
850 cairo_rectangle_list_destroy (cairo_rectangle_list_t *rectangle_list)
852 if (rectangle_list == NULL || rectangle_list == &_cairo_rectangles_nil ||
853 rectangle_list == &_cairo_rectangles_not_representable)
854 return;
856 free (rectangle_list->rectangles);
857 free (rectangle_list);