Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  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. #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"
  52.  
  53. static freed_pool_t clip_path_pool;
  54. static freed_pool_t clip_pool;
  55.  
  56. const cairo_clip_t __cairo_clip_all;
  57.  
  58. static cairo_clip_path_t *
  59. _cairo_clip_path_create (cairo_clip_t *clip)
  60. {
  61.     cairo_clip_path_t *clip_path;
  62.  
  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))
  67.             return NULL;
  68.     }
  69.  
  70.     CAIRO_REFERENCE_COUNT_INIT (&clip_path->ref_count, 1);
  71.  
  72.     clip_path->prev = clip->path;
  73.     clip->path = clip_path;
  74.  
  75.     return clip_path;
  76. }
  77.  
  78. cairo_clip_path_t *
  79. _cairo_clip_path_reference (cairo_clip_path_t *clip_path)
  80. {
  81.     assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&clip_path->ref_count));
  82.  
  83.     _cairo_reference_count_inc (&clip_path->ref_count);
  84.  
  85.     return clip_path;
  86. }
  87.  
  88. void
  89. _cairo_clip_path_destroy (cairo_clip_path_t *clip_path)
  90. {
  91.     assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&clip_path->ref_count));
  92.  
  93.     if (! _cairo_reference_count_dec_and_test (&clip_path->ref_count))
  94.         return;
  95.  
  96.     _cairo_path_fixed_fini (&clip_path->path);
  97.  
  98.     if (clip_path->prev != NULL)
  99.         _cairo_clip_path_destroy (clip_path->prev);
  100.  
  101.     _freed_pool_put (&clip_path_pool, clip_path);
  102. }
  103.  
  104. cairo_clip_t *
  105. _cairo_clip_create (void)
  106. {
  107.     cairo_clip_t *clip;
  108.  
  109.     clip = _freed_pool_get (&clip_pool);
  110.     if (unlikely (clip == NULL)) {
  111.         clip = malloc (sizeof (cairo_clip_t));
  112.         if (unlikely (clip == NULL))
  113.             return NULL;
  114.     }
  115.  
  116.     clip->extents = _cairo_unbounded_rectangle;
  117.  
  118.     clip->path = NULL;
  119.     clip->boxes = NULL;
  120.     clip->num_boxes = 0;
  121.     clip->region = NULL;
  122.     clip->is_region = FALSE;
  123.  
  124.     return clip;
  125. }
  126.  
  127. void
  128. _cairo_clip_destroy (cairo_clip_t *clip)
  129. {
  130.     if (clip == NULL || _cairo_clip_is_all_clipped (clip))
  131.         return;
  132.  
  133.     if (clip->path != NULL)
  134.         _cairo_clip_path_destroy (clip->path);
  135.  
  136.     if (clip->boxes != &clip->embedded_box)
  137.         free (clip->boxes);
  138.     cairo_region_destroy (clip->region);
  139.  
  140.     _freed_pool_put (&clip_pool, clip);
  141. }
  142.  
  143. cairo_clip_t *
  144. _cairo_clip_copy (const cairo_clip_t *clip)
  145. {
  146.     cairo_clip_t *copy;
  147.  
  148.     if (clip == NULL || _cairo_clip_is_all_clipped (clip))
  149.         return (cairo_clip_t *) clip;
  150.  
  151.     copy = _cairo_clip_create ();
  152.  
  153.     if (clip->path)
  154.         copy->path = _cairo_clip_path_reference (clip->path);
  155.  
  156.     if (clip->num_boxes) {
  157.         if (clip->num_boxes == 1) {
  158.             copy->boxes = &copy->embedded_box;
  159.         } else {
  160.             copy->boxes = _cairo_malloc_ab (clip->num_boxes, sizeof (cairo_box_t));
  161.             if (unlikely (copy->boxes == NULL))
  162.                 return _cairo_clip_set_all_clipped (copy);
  163.         }
  164.  
  165.         memcpy (copy->boxes, clip->boxes,
  166.                 clip->num_boxes * sizeof (cairo_box_t));
  167.         copy->num_boxes = clip->num_boxes;
  168.     }
  169.  
  170.     copy->extents = clip->extents;
  171.     copy->region = cairo_region_reference (clip->region);
  172.     copy->is_region = clip->is_region;
  173.  
  174.     return copy;
  175. }
  176.  
  177. cairo_clip_t *
  178. _cairo_clip_copy_path (const cairo_clip_t *clip)
  179. {
  180.     cairo_clip_t *copy;
  181.  
  182.     if (clip == NULL || _cairo_clip_is_all_clipped (clip))
  183.         return (cairo_clip_t *) clip;
  184.  
  185.     assert (clip->num_boxes);
  186.  
  187.     copy = _cairo_clip_create ();
  188.     copy->extents = clip->extents;
  189.     if (clip->path)
  190.         copy->path = _cairo_clip_path_reference (clip->path);
  191.  
  192.     return copy;
  193. }
  194.  
  195. cairo_clip_t *
  196. _cairo_clip_copy_region (const cairo_clip_t *clip)
  197. {
  198.     cairo_clip_t *copy;
  199.     int i;
  200.  
  201.     if (clip == NULL || _cairo_clip_is_all_clipped (clip))
  202.         return (cairo_clip_t *) clip;
  203.  
  204.     assert (clip->num_boxes);
  205.  
  206.     copy = _cairo_clip_create ();
  207.     copy->extents = clip->extents;
  208.  
  209.     if (clip->num_boxes == 1) {
  210.         copy->boxes = &copy->embedded_box;
  211.     } else {
  212.         copy->boxes = _cairo_malloc_ab (clip->num_boxes, sizeof (cairo_box_t));
  213.         if (unlikely (copy->boxes == NULL))
  214.             return _cairo_clip_set_all_clipped (copy);
  215.     }
  216.  
  217.     for (i = 0; i < clip->num_boxes; i++) {
  218.         copy->boxes[i].p1.x = _cairo_fixed_floor (clip->boxes[i].p1.x);
  219.         copy->boxes[i].p1.y = _cairo_fixed_floor (clip->boxes[i].p1.y);
  220.         copy->boxes[i].p2.x = _cairo_fixed_ceil (clip->boxes[i].p2.x);
  221.         copy->boxes[i].p2.y = _cairo_fixed_ceil (clip->boxes[i].p2.y);
  222.     }
  223.     copy->num_boxes = clip->num_boxes;
  224.  
  225.     copy->region = cairo_region_reference (clip->region);
  226.     copy->is_region = TRUE;
  227.  
  228.     return copy;
  229. }
  230.  
  231. cairo_clip_t *
  232. _cairo_clip_intersect_path (cairo_clip_t       *clip,
  233.                             const cairo_path_fixed_t *path,
  234.                             cairo_fill_rule_t   fill_rule,
  235.                             double              tolerance,
  236.                             cairo_antialias_t   antialias)
  237. {
  238.     cairo_clip_path_t *clip_path;
  239.     cairo_status_t status;
  240.     cairo_rectangle_int_t extents;
  241.     cairo_box_t box;
  242.  
  243.     if (_cairo_clip_is_all_clipped (clip))
  244.         return clip;
  245.  
  246.     /* catch the empty clip path */
  247.     if (_cairo_path_fixed_fill_is_empty (path))
  248.         return _cairo_clip_set_all_clipped (clip);
  249.  
  250.     if (_cairo_path_fixed_is_box (path, &box)) {
  251.         if (antialias == CAIRO_ANTIALIAS_NONE) {
  252.             box.p1.x = _cairo_fixed_round_down (box.p1.x);
  253.             box.p1.y = _cairo_fixed_round_down (box.p1.y);
  254.             box.p2.x = _cairo_fixed_round_down (box.p2.x);
  255.             box.p2.y = _cairo_fixed_round_down (box.p2.y);
  256.         }
  257.  
  258.         return _cairo_clip_intersect_box (clip, &box);
  259.     }
  260.     if (_cairo_path_fixed_fill_is_rectilinear (path))
  261.         return _cairo_clip_intersect_rectilinear_path (clip, path,
  262.                                                        fill_rule, antialias);
  263.  
  264.     _cairo_path_fixed_approximate_clip_extents (path, &extents);
  265.     if (extents.width == 0 || extents.height == 0)
  266.         return _cairo_clip_set_all_clipped (clip);
  267.  
  268.     clip = _cairo_clip_intersect_rectangle (clip, &extents);
  269.     if (_cairo_clip_is_all_clipped (clip))
  270.         return clip;
  271.  
  272.     clip_path = _cairo_clip_path_create (clip);
  273.     if (unlikely (clip_path == NULL))
  274.         return _cairo_clip_set_all_clipped (clip);
  275.  
  276.     status = _cairo_path_fixed_init_copy (&clip_path->path, path);
  277.     if (unlikely (status))
  278.         return _cairo_clip_set_all_clipped (clip);
  279.  
  280.     clip_path->fill_rule = fill_rule;
  281.     clip_path->tolerance = tolerance;
  282.     clip_path->antialias = antialias;
  283.  
  284.     if (clip->region) {
  285.         cairo_region_destroy (clip->region);
  286.         clip->region = NULL;
  287.     }
  288.  
  289.     clip->is_region = FALSE;
  290.     return clip;
  291. }
  292.  
  293. static cairo_clip_t *
  294. _cairo_clip_intersect_clip_path (cairo_clip_t *clip,
  295.                                  const cairo_clip_path_t *clip_path)
  296. {
  297.     if (clip_path->prev)
  298.         clip = _cairo_clip_intersect_clip_path (clip, clip_path->prev);
  299.  
  300.     return _cairo_clip_intersect_path (clip,
  301.                                        &clip_path->path,
  302.                                        clip_path->fill_rule,
  303.                                        clip_path->tolerance,
  304.                                        clip_path->antialias);
  305. }
  306.  
  307. cairo_clip_t *
  308. _cairo_clip_intersect_clip (cairo_clip_t *clip,
  309.                             const cairo_clip_t *other)
  310. {
  311.     if (_cairo_clip_is_all_clipped (clip))
  312.         return clip;
  313.  
  314.     if (other == NULL)
  315.         return clip;
  316.  
  317.     if (clip == NULL)
  318.         return _cairo_clip_copy (other);
  319.  
  320.     if (_cairo_clip_is_all_clipped (other))
  321.         return _cairo_clip_set_all_clipped (clip);
  322.  
  323.     if (! _cairo_rectangle_intersect (&clip->extents, &other->extents))
  324.         return _cairo_clip_set_all_clipped (clip);
  325.  
  326.     if (other->num_boxes) {
  327.         cairo_boxes_t boxes;
  328.  
  329.         _cairo_boxes_init_for_array (&boxes, other->boxes, other->num_boxes);
  330.         clip = _cairo_clip_intersect_boxes (clip, &boxes);
  331.     }
  332.  
  333.     if (! _cairo_clip_is_all_clipped (clip)) {
  334.         if (other->path) {
  335.             if (clip->path == NULL)
  336.                 clip->path = _cairo_clip_path_reference (other->path);
  337.             else
  338.                 clip = _cairo_clip_intersect_clip_path (clip, other->path);
  339.         }
  340.     }
  341.  
  342.     if (clip->region) {
  343.         cairo_region_destroy (clip->region);
  344.         clip->region = NULL;
  345.     }
  346.     clip->is_region = FALSE;
  347.  
  348.     return clip;
  349. }
  350.  
  351. cairo_bool_t
  352. _cairo_clip_equal (const cairo_clip_t *clip_a,
  353.                    const cairo_clip_t *clip_b)
  354. {
  355.     const cairo_clip_path_t *cp_a, *cp_b;
  356.  
  357.     /* are both all-clipped or no-clip? */
  358.     if (clip_a == clip_b)
  359.         return TRUE;
  360.  
  361.     /* or just one of them? */
  362.     if (clip_a == NULL || clip_b == NULL ||
  363.         _cairo_clip_is_all_clipped (clip_a) ||
  364.         _cairo_clip_is_all_clipped (clip_b))
  365.     {
  366.         return FALSE;
  367.     }
  368.  
  369.     /* We have a pair of normal clips, check their contents */
  370.  
  371.     if (clip_a->num_boxes != clip_b->num_boxes)
  372.         return FALSE;
  373.  
  374.     if (memcmp (clip_a->boxes, clip_b->boxes,
  375.                 sizeof (cairo_box_t) * clip_a->num_boxes))
  376.         return FALSE;
  377.  
  378.     cp_a = clip_a->path;
  379.     cp_b = clip_b->path;
  380.     while (cp_a && cp_b) {
  381.         if (cp_a == cp_b)
  382.             return TRUE;
  383.  
  384.         /* XXX compare reduced polygons? */
  385.  
  386.         if (cp_a->antialias != cp_b->antialias)
  387.             return FALSE;
  388.  
  389.         if (cp_a->tolerance != cp_b->tolerance)
  390.             return FALSE;
  391.  
  392.         if (cp_a->fill_rule != cp_b->fill_rule)
  393.             return FALSE;
  394.  
  395.         if (! _cairo_path_fixed_equal (&cp_a->path,
  396.                                        &cp_b->path))
  397.             return FALSE;
  398.  
  399.         cp_a = cp_a->prev;
  400.         cp_b = cp_b->prev;
  401.     }
  402.  
  403.     return cp_a == NULL && cp_b == NULL;
  404. }
  405.  
  406. static cairo_clip_t *
  407. _cairo_clip_path_copy_with_translation (cairo_clip_t      *clip,
  408.                                         cairo_clip_path_t *other_path,
  409.                                         int fx, int fy)
  410. {
  411.     cairo_status_t status;
  412.     cairo_clip_path_t *clip_path;
  413.  
  414.     if (other_path->prev != NULL)
  415.         clip = _cairo_clip_path_copy_with_translation (clip, other_path->prev,
  416.                                                        fx, fy);
  417.     if (_cairo_clip_is_all_clipped (clip))
  418.         return clip;
  419.  
  420.     clip_path = _cairo_clip_path_create (clip);
  421.     if (unlikely (clip_path == NULL))
  422.         return _cairo_clip_set_all_clipped (clip);
  423.  
  424.     status = _cairo_path_fixed_init_copy (&clip_path->path,
  425.                                           &other_path->path);
  426.     if (unlikely (status))
  427.         return _cairo_clip_set_all_clipped (clip);
  428.  
  429.     _cairo_path_fixed_translate (&clip_path->path, fx, fy);
  430.  
  431.     clip_path->fill_rule = other_path->fill_rule;
  432.     clip_path->tolerance = other_path->tolerance;
  433.     clip_path->antialias = other_path->antialias;
  434.  
  435.     return clip;
  436. }
  437.  
  438. cairo_clip_t *
  439. _cairo_clip_translate (cairo_clip_t *clip, int tx, int ty)
  440. {
  441.     int fx, fy, i;
  442.     cairo_clip_path_t *clip_path;
  443.  
  444.     if (clip == NULL || _cairo_clip_is_all_clipped (clip))
  445.         return clip;
  446.  
  447.     if (tx == 0 && ty == 0)
  448.         return clip;
  449.  
  450.     fx = _cairo_fixed_from_int (tx);
  451.     fy = _cairo_fixed_from_int (ty);
  452.  
  453.     for (i = 0; i < clip->num_boxes; i++) {
  454.         clip->boxes[i].p1.x += fx;
  455.         clip->boxes[i].p2.x += fx;
  456.         clip->boxes[i].p1.y += fy;
  457.         clip->boxes[i].p2.y += fy;
  458.     }
  459.  
  460.     clip->extents.x += tx;
  461.     clip->extents.y += ty;
  462.  
  463.     if (clip->path == NULL)
  464.         return clip;
  465.  
  466.     clip_path = clip->path;
  467.     clip->path = NULL;
  468.     clip = _cairo_clip_path_copy_with_translation (clip, clip_path, fx, fy);
  469.     _cairo_clip_path_destroy (clip_path);
  470.  
  471.     return clip;
  472. }
  473.  
  474. static cairo_status_t
  475. _cairo_path_fixed_add_box (cairo_path_fixed_t *path,
  476.                            const cairo_box_t *box)
  477. {
  478.     cairo_status_t status;
  479.  
  480.     status = _cairo_path_fixed_move_to (path, box->p1.x, box->p1.y);
  481.     if (unlikely (status))
  482.         return status;
  483.  
  484.     status = _cairo_path_fixed_line_to (path, box->p2.x, box->p1.y);
  485.     if (unlikely (status))
  486.         return status;
  487.  
  488.     status = _cairo_path_fixed_line_to (path, box->p2.x, box->p2.y);
  489.     if (unlikely (status))
  490.         return status;
  491.  
  492.     status = _cairo_path_fixed_line_to (path, box->p1.x, box->p2.y);
  493.     if (unlikely (status))
  494.         return status;
  495.  
  496.     return _cairo_path_fixed_close_path (path);
  497. }
  498.  
  499. static cairo_status_t
  500. _cairo_path_fixed_init_from_boxes (cairo_path_fixed_t *path,
  501.                                    const cairo_boxes_t *boxes)
  502. {
  503.     cairo_status_t status;
  504.     const struct _cairo_boxes_chunk *chunk;
  505.     int i;
  506.  
  507.     _cairo_path_fixed_init (path);
  508.     if (boxes->num_boxes == 0)
  509.         return CAIRO_STATUS_SUCCESS;
  510.  
  511.     for (chunk = &boxes->chunks; chunk; chunk = chunk->next) {
  512.         for (i = 0; i < chunk->count; i++) {
  513.             status = _cairo_path_fixed_add_box (path, &chunk->base[i]);
  514.             if (unlikely (status)) {
  515.                 _cairo_path_fixed_fini (path);
  516.                 return status;
  517.             }
  518.         }
  519.     }
  520.  
  521.     return CAIRO_STATUS_SUCCESS;
  522. }
  523.  
  524. static cairo_clip_t *
  525. _cairo_clip_intersect_clip_path_transformed (cairo_clip_t *clip,
  526.                                              const cairo_clip_path_t *clip_path,
  527.                                              const cairo_matrix_t *m)
  528. {
  529.     cairo_path_fixed_t path;
  530.  
  531.     if (clip_path->prev)
  532.         clip = _cairo_clip_intersect_clip_path_transformed (clip,
  533.                                                             clip_path->prev,
  534.                                                             m);
  535.  
  536.     if (_cairo_path_fixed_init_copy (&path, &clip_path->path))
  537.         return _cairo_clip_set_all_clipped (clip);
  538.  
  539.     _cairo_path_fixed_transform (&path, m);
  540.  
  541.     clip =  _cairo_clip_intersect_path (clip,
  542.                                        &path,
  543.                                        clip_path->fill_rule,
  544.                                        clip_path->tolerance,
  545.                                        clip_path->antialias);
  546.     _cairo_path_fixed_fini (&path);
  547.  
  548.     return clip;
  549. }
  550.  
  551. cairo_clip_t *
  552. _cairo_clip_transform (cairo_clip_t *clip, const cairo_matrix_t *m)
  553. {
  554.     cairo_clip_t *copy;
  555.  
  556.     if (clip == NULL || _cairo_clip_is_all_clipped (clip))
  557.         return clip;
  558.  
  559.     if (_cairo_matrix_is_translation (m))
  560.         return _cairo_clip_translate (clip, m->x0, m->y0);
  561.  
  562.     copy = _cairo_clip_create ();
  563.  
  564.     if (clip->num_boxes) {
  565.         cairo_path_fixed_t path;
  566.         cairo_boxes_t boxes;
  567.  
  568.         _cairo_boxes_init_for_array (&boxes, clip->boxes, clip->num_boxes);
  569.         _cairo_path_fixed_init_from_boxes (&path, &boxes);
  570.         _cairo_path_fixed_transform (&path, m);
  571.  
  572.         copy = _cairo_clip_intersect_path (copy, &path,
  573.                                            CAIRO_FILL_RULE_WINDING,
  574.                                            0.1,
  575.                                            CAIRO_ANTIALIAS_DEFAULT);
  576.  
  577.         _cairo_path_fixed_fini (&path);
  578.     }
  579.  
  580.     if (clip->path)
  581.         copy = _cairo_clip_intersect_clip_path_transformed (copy, clip->path,m);
  582.  
  583.     _cairo_clip_destroy (clip);
  584.     return copy;
  585. }
  586.  
  587. cairo_clip_t *
  588. _cairo_clip_copy_with_translation (const cairo_clip_t *clip, int tx, int ty)
  589. {
  590.     cairo_clip_t *copy;
  591.     int fx, fy, i;
  592.  
  593.     if (clip == NULL || _cairo_clip_is_all_clipped (clip))
  594.         return (cairo_clip_t *)clip;
  595.  
  596.     if (tx == 0 && ty == 0)
  597.         return _cairo_clip_copy (clip);
  598.  
  599.     copy = _cairo_clip_create ();
  600.     if (copy == NULL)
  601.             return _cairo_clip_set_all_clipped (copy);
  602.  
  603.     fx = _cairo_fixed_from_int (tx);
  604.     fy = _cairo_fixed_from_int (ty);
  605.  
  606.     if (clip->num_boxes) {
  607.         if (clip->num_boxes == 1) {
  608.             copy->boxes = &copy->embedded_box;
  609.         } else {
  610.             copy->boxes = _cairo_malloc_ab (clip->num_boxes, sizeof (cairo_box_t));
  611.             if (unlikely (copy->boxes == NULL))
  612.                 return _cairo_clip_set_all_clipped (copy);
  613.         }
  614.  
  615.         for (i = 0; i < clip->num_boxes; i++) {
  616.             copy->boxes[i].p1.x = clip->boxes[i].p1.x + fx;
  617.             copy->boxes[i].p2.x = clip->boxes[i].p2.x + fx;
  618.             copy->boxes[i].p1.y = clip->boxes[i].p1.y + fy;
  619.             copy->boxes[i].p2.y = clip->boxes[i].p2.y + fy;
  620.         }
  621.         copy->num_boxes = clip->num_boxes;
  622.     }
  623.  
  624.     copy->extents = clip->extents;
  625.     copy->extents.x += tx;
  626.     copy->extents.y += ty;
  627.  
  628.     if (clip->path == NULL)
  629.         return copy;
  630.  
  631.     return _cairo_clip_path_copy_with_translation (copy, clip->path, fx, fy);
  632. }
  633.  
  634. cairo_bool_t
  635. _cairo_clip_contains_extents (const cairo_clip_t *clip,
  636.                               const cairo_composite_rectangles_t *extents)
  637. {
  638.     const cairo_rectangle_int_t *rect;
  639.  
  640.     rect = extents->is_bounded ? &extents->bounded : &extents->unbounded;
  641.     return _cairo_clip_contains_rectangle (clip, rect);
  642. }
  643.  
  644. void
  645. _cairo_debug_print_clip (FILE *stream, const cairo_clip_t *clip)
  646. {
  647.     int i;
  648.  
  649.     if (clip == NULL) {
  650.         fprintf (stream, "no clip\n");
  651.         return;
  652.     }
  653.  
  654.     if (_cairo_clip_is_all_clipped (clip)) {
  655.         fprintf (stream, "clip: all-clipped\n");
  656.         return;
  657.     }
  658.  
  659.     fprintf (stream, "clip:\n");
  660.     fprintf (stream, "  extents: (%d, %d) x (%d, %d), is-region? %d",
  661.              clip->extents.x, clip->extents.y,
  662.              clip->extents.width, clip->extents.height,
  663.              clip->is_region);
  664.  
  665.     fprintf (stream, "  num_boxes = %d\n", clip->num_boxes);
  666.     for (i = 0; i < clip->num_boxes; i++) {
  667.         fprintf (stream, "  [%d] = (%f, %f), (%f, %f)\n", i,
  668.                  _cairo_fixed_to_double (clip->boxes[i].p1.x),
  669.                  _cairo_fixed_to_double (clip->boxes[i].p1.y),
  670.                  _cairo_fixed_to_double (clip->boxes[i].p2.x),
  671.                  _cairo_fixed_to_double (clip->boxes[i].p2.y));
  672.     }
  673.  
  674.     if (clip->path) {
  675.         cairo_clip_path_t *clip_path = clip->path;
  676.         do {
  677.             fprintf (stream, "path: aa=%d, tolerance=%f, rule=%d: ",
  678.                      clip_path->antialias,
  679.                      clip_path->tolerance,
  680.                      clip_path->fill_rule);
  681.             _cairo_debug_print_path (stream, &clip_path->path);
  682.             fprintf (stream, "\n");
  683.         } while ((clip_path = clip_path->prev) != NULL);
  684.     }
  685. }
  686.  
  687. const cairo_rectangle_int_t *
  688. _cairo_clip_get_extents (const cairo_clip_t *clip)
  689. {
  690.     if (clip == NULL)
  691.         return &_cairo_unbounded_rectangle;
  692.  
  693.     if (_cairo_clip_is_all_clipped (clip))
  694.         return &_cairo_empty_rectangle;
  695.  
  696.     return &clip->extents;
  697. }
  698.  
  699. const cairo_rectangle_list_t _cairo_rectangles_nil =
  700.   { CAIRO_STATUS_NO_MEMORY, NULL, 0 };
  701. static const cairo_rectangle_list_t _cairo_rectangles_not_representable =
  702.   { CAIRO_STATUS_CLIP_NOT_REPRESENTABLE, NULL, 0 };
  703.  
  704. static cairo_bool_t
  705. _cairo_clip_int_rect_to_user (cairo_gstate_t *gstate,
  706.                               cairo_rectangle_int_t *clip_rect,
  707.                               cairo_rectangle_t *user_rect)
  708. {
  709.     cairo_bool_t is_tight;
  710.  
  711.     double x1 = clip_rect->x;
  712.     double y1 = clip_rect->y;
  713.     double x2 = clip_rect->x + (int) clip_rect->width;
  714.     double y2 = clip_rect->y + (int) clip_rect->height;
  715.  
  716.     _cairo_gstate_backend_to_user_rectangle (gstate,
  717.                                              &x1, &y1, &x2, &y2,
  718.                                              &is_tight);
  719.  
  720.     user_rect->x = x1;
  721.     user_rect->y = y1;
  722.     user_rect->width  = x2 - x1;
  723.     user_rect->height = y2 - y1;
  724.  
  725.     return is_tight;
  726. }
  727.  
  728. cairo_rectangle_list_t *
  729. _cairo_rectangle_list_create_in_error (cairo_status_t status)
  730. {
  731.     cairo_rectangle_list_t *list;
  732.  
  733.     if (status == CAIRO_STATUS_NO_MEMORY)
  734.         return (cairo_rectangle_list_t*) &_cairo_rectangles_nil;
  735.     if (status == CAIRO_STATUS_CLIP_NOT_REPRESENTABLE)
  736.         return (cairo_rectangle_list_t*) &_cairo_rectangles_not_representable;
  737.  
  738.     list = malloc (sizeof (*list));
  739.     if (unlikely (list == NULL)) {
  740.         status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
  741.         return (cairo_rectangle_list_t*) &_cairo_rectangles_nil;
  742.     }
  743.  
  744.     list->status = status;
  745.     list->rectangles = NULL;
  746.     list->num_rectangles = 0;
  747.  
  748.     return list;
  749. }
  750.  
  751. cairo_rectangle_list_t *
  752. _cairo_clip_copy_rectangle_list (cairo_clip_t *clip, cairo_gstate_t *gstate)
  753. {
  754. #define ERROR_LIST(S) _cairo_rectangle_list_create_in_error (_cairo_error (S))
  755.  
  756.     cairo_rectangle_list_t *list;
  757.     cairo_rectangle_t *rectangles = NULL;
  758.     cairo_region_t *region = NULL;
  759.     int n_rects = 0;
  760.     int i;
  761.  
  762.     if (clip == NULL)
  763.         return ERROR_LIST (CAIRO_STATUS_CLIP_NOT_REPRESENTABLE);
  764.  
  765.     if (_cairo_clip_is_all_clipped (clip))
  766.         goto DONE;
  767.  
  768.     if (! _cairo_clip_is_region (clip))
  769.         return ERROR_LIST (CAIRO_STATUS_CLIP_NOT_REPRESENTABLE);
  770.  
  771.     region = _cairo_clip_get_region (clip);
  772.     if (region == NULL)
  773.         return ERROR_LIST (CAIRO_STATUS_NO_MEMORY);
  774.  
  775.     n_rects = cairo_region_num_rectangles (region);
  776.     if (n_rects) {
  777.         rectangles = _cairo_malloc_ab (n_rects, sizeof (cairo_rectangle_t));
  778.         if (unlikely (rectangles == NULL)) {
  779.             return ERROR_LIST (CAIRO_STATUS_NO_MEMORY);
  780.         }
  781.  
  782.         for (i = 0; i < n_rects; ++i) {
  783.             cairo_rectangle_int_t clip_rect;
  784.  
  785.             cairo_region_get_rectangle (region, i, &clip_rect);
  786.  
  787.             if (! _cairo_clip_int_rect_to_user (gstate,
  788.                                                 &clip_rect,
  789.                                                 &rectangles[i]))
  790.             {
  791.                 free (rectangles);
  792.                 return ERROR_LIST (CAIRO_STATUS_CLIP_NOT_REPRESENTABLE);
  793.             }
  794.         }
  795.     }
  796.  
  797.  DONE:
  798.     list = malloc (sizeof (cairo_rectangle_list_t));
  799.     if (unlikely (list == NULL)) {
  800.         free (rectangles);
  801.         return ERROR_LIST (CAIRO_STATUS_NO_MEMORY);
  802.     }
  803.  
  804.     list->status = CAIRO_STATUS_SUCCESS;
  805.     list->rectangles = rectangles;
  806.     list->num_rectangles = n_rects;
  807.     return list;
  808.  
  809. #undef ERROR_LIST
  810. }
  811.  
  812. /**
  813.  * cairo_rectangle_list_destroy:
  814.  * @rectangle_list: a rectangle list, as obtained from cairo_copy_clip_rectangle_list()
  815.  *
  816.  * Unconditionally frees @rectangle_list and all associated
  817.  * references. After this call, the @rectangle_list pointer must not
  818.  * be dereferenced.
  819.  *
  820.  * Since: 1.4
  821.  **/
  822. void
  823. cairo_rectangle_list_destroy (cairo_rectangle_list_t *rectangle_list)
  824. {
  825.     if (rectangle_list == NULL || rectangle_list == &_cairo_rectangles_nil ||
  826.         rectangle_list == &_cairo_rectangles_not_representable)
  827.         return;
  828.  
  829.     free (rectangle_list->rectangles);
  830.     free (rectangle_list);
  831. }
  832.  
  833. void
  834. _cairo_clip_reset_static_data (void)
  835. {
  836.     _freed_pool_reset (&clip_path_pool);
  837.     _freed_pool_reset (&clip_pool);
  838. }
  839.