LCOV - code coverage report
Current view: top level - gfx/cairo/cairo/src - cairo-clip.c (source / functions) Hit Total Coverage
Test: output.info Lines: 4 767 0.5 %
Date: 2017-07-14 16:53:18 Functions: 1 42 2.4 %
Legend: Lines: hit not hit

          Line data    Source code
       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-private.h"
      44             : #include "cairo-error-private.h"
      45             : #include "cairo-freed-pool-private.h"
      46             : #include "cairo-gstate-private.h"
      47             : #include "cairo-path-fixed-private.h"
      48             : #include "cairo-composite-rectangles-private.h"
      49             : #include "cairo-region-private.h"
      50             : 
      51             : #if HAS_FREED_POOL
      52             : static freed_pool_t clip_path_pool;
      53             : #endif
      54             : 
      55             : static cairo_clip_path_t *
      56           0 : _cairo_clip_path_create (cairo_clip_t *clip)
      57             : {
      58             :     cairo_clip_path_t *clip_path;
      59             : 
      60           0 :     clip_path = _freed_pool_get (&clip_path_pool);
      61           0 :     if (unlikely (clip_path == NULL)) {
      62           0 :         clip_path = malloc (sizeof (cairo_clip_path_t));
      63           0 :         if (unlikely (clip_path == NULL))
      64           0 :             return NULL;
      65             :     }
      66             : 
      67           0 :     CAIRO_REFERENCE_COUNT_INIT (&clip_path->ref_count, 1);
      68             : 
      69           0 :     clip_path->flags = 0;
      70           0 :     clip_path->region = NULL;
      71           0 :     clip_path->surface = NULL;
      72             : 
      73           0 :     clip_path->prev = clip->path;
      74           0 :     clip->path = clip_path;
      75             : 
      76           0 :     return clip_path;
      77             : }
      78             : 
      79             : static cairo_clip_path_t *
      80           0 : _cairo_clip_path_reference (cairo_clip_path_t *clip_path)
      81             : {
      82           0 :     assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&clip_path->ref_count));
      83             : 
      84           0 :     _cairo_reference_count_inc (&clip_path->ref_count);
      85             : 
      86           0 :     return clip_path;
      87             : }
      88             : 
      89             : static void
      90           0 : _cairo_clip_path_destroy (cairo_clip_path_t *clip_path)
      91             : {
      92           0 :     assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&clip_path->ref_count));
      93             : 
      94           0 :     if (! _cairo_reference_count_dec_and_test (&clip_path->ref_count))
      95           0 :         return;
      96             : 
      97           0 :     _cairo_path_fixed_fini (&clip_path->path);
      98           0 :     if (clip_path->region != NULL)
      99           0 :         cairo_region_destroy (clip_path->region);
     100           0 :     if (clip_path->surface != NULL)
     101           0 :         cairo_surface_destroy (clip_path->surface);
     102             : 
     103           0 :     if (clip_path->prev != NULL)
     104           0 :         _cairo_clip_path_destroy (clip_path->prev);
     105             : 
     106           0 :     _freed_pool_put (&clip_path_pool, clip_path);
     107             : }
     108             : 
     109             : void
     110           2 : _cairo_clip_init (cairo_clip_t *clip)
     111             : {
     112           2 :     clip->all_clipped = FALSE;
     113           2 :     clip->path = NULL;
     114           2 : }
     115             : 
     116             : static void
     117           0 : _cairo_clip_set_all_clipped (cairo_clip_t *clip)
     118             : {
     119           0 :     clip->all_clipped = TRUE;
     120           0 :     if (clip->path != NULL) {
     121           0 :         _cairo_clip_path_destroy (clip->path);
     122           0 :         clip->path = NULL;
     123             :     }
     124           0 : }
     125             : 
     126             : static cairo_status_t
     127           0 : _cairo_clip_intersect_rectangle (cairo_clip_t *clip,
     128             :                                  const cairo_rectangle_int_t *rect)
     129             : {
     130             :     cairo_clip_path_t *clip_path;
     131             :     cairo_status_t status;
     132             : 
     133           0 :     if (clip->path != NULL) {
     134           0 :         if (rect->x <= clip->path->extents.x &&
     135           0 :             rect->y <= clip->path->extents.y &&
     136           0 :             rect->x + rect->width >= clip->path->extents.x + clip->path->extents.width &&
     137           0 :             rect->y + rect->height >= clip->path->extents.y + clip->path->extents.height)
     138             :         {
     139           0 :             return CAIRO_STATUS_SUCCESS;
     140             :         }
     141             :     }
     142             : 
     143           0 :     clip_path = _cairo_clip_path_create (clip);
     144           0 :     if (unlikely (clip_path == NULL))
     145           0 :         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
     146             : 
     147           0 :     _cairo_path_fixed_init (&clip_path->path);
     148             : 
     149           0 :     status = _cairo_path_fixed_move_to (&clip_path->path,
     150             :                                         _cairo_fixed_from_int (rect->x),
     151             :                                         _cairo_fixed_from_int (rect->y));
     152           0 :     assert (status == CAIRO_STATUS_SUCCESS);
     153           0 :     status = _cairo_path_fixed_rel_line_to (&clip_path->path,
     154             :                                             _cairo_fixed_from_int (rect->width),
     155             :                                             _cairo_fixed_from_int (0));
     156           0 :     assert (status == CAIRO_STATUS_SUCCESS);
     157           0 :     status = _cairo_path_fixed_rel_line_to (&clip_path->path,
     158             :                                             _cairo_fixed_from_int (0),
     159             :                                             _cairo_fixed_from_int (rect->height));
     160           0 :     assert (status == CAIRO_STATUS_SUCCESS);
     161           0 :     status = _cairo_path_fixed_rel_line_to (&clip_path->path,
     162           0 :                                             _cairo_fixed_from_int (-rect->width),
     163             :                                             _cairo_fixed_from_int (0));
     164           0 :     assert (status == CAIRO_STATUS_SUCCESS);
     165           0 :     status = _cairo_path_fixed_close_path (&clip_path->path);
     166           0 :     assert (status == CAIRO_STATUS_SUCCESS);
     167             : 
     168           0 :     clip_path->fill_rule = CAIRO_FILL_RULE_WINDING;
     169           0 :     clip_path->tolerance = 1;
     170           0 :     clip_path->antialias = CAIRO_ANTIALIAS_DEFAULT;
     171           0 :     clip_path->flags |= CAIRO_CLIP_PATH_IS_BOX;
     172             : 
     173           0 :     clip_path->extents = *rect;
     174           0 :     if (clip_path->prev != NULL) {
     175           0 :         if (! _cairo_rectangle_intersect (&clip_path->extents,
     176           0 :                                           &clip_path->prev->extents))
     177             :         {
     178           0 :             _cairo_clip_set_all_clipped (clip);
     179             :         }
     180             :     }
     181             : 
     182             :     /* could preallocate the region if it proves worthwhile */
     183             : 
     184           0 :     return CAIRO_STATUS_SUCCESS;
     185             : }
     186             : 
     187             : cairo_clip_t *
     188           0 : _cairo_clip_init_copy (cairo_clip_t *clip, cairo_clip_t *other)
     189             : {
     190           0 :     if (other != NULL) {
     191           0 :         clip->all_clipped = other->all_clipped;
     192           0 :         if (other->path == NULL) {
     193           0 :             clip->path = NULL;
     194           0 :             if (! clip->all_clipped)
     195           0 :                 clip = NULL;
     196             :         } else {
     197           0 :             clip->path = _cairo_clip_path_reference (other->path);
     198             :         }
     199             :     } else {
     200           0 :         _cairo_clip_init (clip);
     201           0 :         clip = NULL;
     202             :     }
     203             : 
     204           0 :     return clip;
     205             : }
     206             : 
     207             : void
     208           0 : _cairo_clip_reset (cairo_clip_t *clip)
     209             : {
     210           0 :     clip->all_clipped = FALSE;
     211           0 :     if (clip->path != NULL) {
     212           0 :         _cairo_clip_path_destroy (clip->path);
     213           0 :         clip->path = NULL;
     214             :     }
     215           0 : }
     216             : 
     217             : static cairo_status_t
     218           0 : _cairo_clip_intersect_path (cairo_clip_t       *clip,
     219             :                             const cairo_path_fixed_t *path,
     220             :                             cairo_fill_rule_t   fill_rule,
     221             :                             double              tolerance,
     222             :                             cairo_antialias_t   antialias)
     223             : {
     224             :     cairo_clip_path_t *clip_path;
     225             :     cairo_status_t status;
     226             :     cairo_rectangle_int_t extents;
     227             :     cairo_box_t box;
     228           0 :     cairo_bool_t is_box = FALSE;
     229             : 
     230           0 :     if (clip->path != NULL) {
     231           0 :         if (clip->path->fill_rule == fill_rule &&
     232           0 :             (path->is_rectilinear || tolerance == clip->path->tolerance) &&
     233           0 :             antialias == clip->path->antialias &&
     234           0 :             _cairo_path_fixed_equal (&clip->path->path, path))
     235             :         {
     236           0 :             return CAIRO_STATUS_SUCCESS;
     237             :         }
     238             :     }
     239             : 
     240           0 :     _cairo_path_fixed_approximate_clip_extents (path, &extents);
     241           0 :     if (extents.width == 0 || extents.height == 0) {
     242           0 :         _cairo_clip_set_all_clipped (clip);
     243           0 :         return CAIRO_STATUS_SUCCESS;
     244             :     }
     245             : 
     246           0 :     is_box = _cairo_path_fixed_is_box (path, &box);
     247           0 :     if (clip->path != NULL) {
     248           0 :         if (! _cairo_rectangle_intersect (&extents, &clip->path->extents)) {
     249           0 :             _cairo_clip_set_all_clipped (clip);
     250           0 :             return CAIRO_STATUS_SUCCESS;
     251             :         }
     252             : 
     253             :         /* does this clip wholly subsume the others? */
     254           0 :         if (is_box &&
     255           0 :             box.p1.x <= _cairo_fixed_from_int (clip->path->extents.x) &&
     256           0 :             box.p2.x >= _cairo_fixed_from_int (clip->path->extents.x + clip->path->extents.width) &&
     257           0 :             box.p1.y <= _cairo_fixed_from_int (clip->path->extents.y) &&
     258           0 :             box.p2.y >= _cairo_fixed_from_int (clip->path->extents.y + clip->path->extents.height))
     259             :         {
     260           0 :             return CAIRO_STATUS_SUCCESS;
     261             :         }
     262             :     }
     263             : 
     264           0 :     clip_path = _cairo_clip_path_create (clip);
     265           0 :     if (unlikely (clip_path == NULL))
     266           0 :         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
     267             : 
     268           0 :     status = _cairo_path_fixed_init_copy (&clip_path->path, path);
     269           0 :     if (unlikely (status)) {
     270           0 :         clip->path = clip->path->prev;
     271           0 :         _cairo_clip_path_destroy (clip_path);
     272           0 :         return status;
     273             :     }
     274             : 
     275           0 :     clip_path->extents = extents;
     276           0 :     clip_path->fill_rule = fill_rule;
     277           0 :     clip_path->tolerance = tolerance;
     278           0 :     clip_path->antialias = antialias;
     279           0 :     if (is_box)
     280           0 :         clip_path->flags |= CAIRO_CLIP_PATH_IS_BOX;
     281             : 
     282           0 :     return CAIRO_STATUS_SUCCESS;
     283             : }
     284             : 
     285             : cairo_bool_t
     286           0 : _cairo_clip_equal (const cairo_clip_t *clip_a,
     287             :                    const cairo_clip_t *clip_b)
     288             : {
     289             :     const cairo_clip_path_t *clip_path_a, *clip_path_b;
     290             : 
     291           0 :     clip_path_a = clip_a->path;
     292           0 :     clip_path_b = clip_b->path;
     293             : 
     294           0 :     while (clip_path_a && clip_path_b) {
     295           0 :         if (clip_path_a == clip_path_b)
     296           0 :             return TRUE;
     297             : 
     298           0 :         if (clip_path_a->fill_rule != clip_path_b->fill_rule)
     299           0 :             return FALSE;
     300             : 
     301           0 :         if (clip_path_a->tolerance != clip_path_b->tolerance)
     302           0 :             return FALSE;
     303             : 
     304           0 :         if (clip_path_a->antialias != clip_path_b->antialias)
     305           0 :             return FALSE;
     306             : 
     307           0 :         if (! _cairo_path_fixed_equal (&clip_path_a->path, &clip_path_b->path))
     308           0 :             return FALSE;
     309             : 
     310           0 :         clip_path_a = clip_path_a->prev;
     311           0 :         clip_path_b = clip_path_b->prev;
     312             :     }
     313             : 
     314           0 :     return clip_path_a == clip_path_b; /* ie both NULL */
     315             : }
     316             : 
     317             : cairo_status_t
     318           0 : _cairo_clip_clip (cairo_clip_t       *clip,
     319             :                   const cairo_path_fixed_t *path,
     320             :                   cairo_fill_rule_t   fill_rule,
     321             :                   double              tolerance,
     322             :                   cairo_antialias_t   antialias)
     323             : {
     324           0 :     if (clip->all_clipped)
     325           0 :         return CAIRO_STATUS_SUCCESS;
     326             : 
     327             :     /* catch the empty clip path */
     328           0 :     if (_cairo_path_fixed_fill_is_empty (path)) {
     329           0 :         _cairo_clip_set_all_clipped (clip);
     330           0 :         return CAIRO_STATUS_SUCCESS;
     331             :     }
     332             : 
     333           0 :     return _cairo_clip_intersect_path (clip,
     334             :                                        path, fill_rule, tolerance,
     335             :                                        antialias);
     336             : }
     337             : 
     338             : cairo_status_t
     339           0 : _cairo_clip_rectangle (cairo_clip_t       *clip,
     340             :                        const cairo_rectangle_int_t *rectangle)
     341             : {
     342           0 :     if (clip->all_clipped)
     343           0 :         return CAIRO_STATUS_SUCCESS;
     344             : 
     345           0 :     if (rectangle->width == 0 || rectangle->height == 0) {
     346           0 :         _cairo_clip_set_all_clipped (clip);
     347           0 :         return CAIRO_STATUS_SUCCESS;
     348             :     }
     349             : 
     350             :     /* if a smaller clip has already been set, ignore the new path */
     351           0 :     if (clip->path != NULL) {
     352           0 :         if (rectangle->x <= clip->path->extents.x &&
     353           0 :             rectangle->y <= clip->path->extents.y &&
     354           0 :             rectangle->x + rectangle->width  >= clip->path->extents.x + clip->path->extents.width &&
     355           0 :             rectangle->y + rectangle->height >= clip->path->extents.y + clip->path->extents.height)
     356             :         {
     357           0 :             return CAIRO_STATUS_SUCCESS;
     358             :         }
     359             :     }
     360             : 
     361           0 :     return _cairo_clip_intersect_rectangle (clip, rectangle);
     362             : }
     363             : 
     364             : static cairo_status_t
     365           0 : _cairo_clip_path_reapply_clip_path_transform (cairo_clip_t      *clip,
     366             :                                               cairo_clip_path_t *other_path,
     367             :                                               const cairo_matrix_t *matrix)
     368             : {
     369             :     cairo_status_t status;
     370             :     cairo_clip_path_t *clip_path;
     371             :     cairo_bool_t is_empty;
     372             : 
     373           0 :     if (other_path->prev != NULL) {
     374           0 :         status = _cairo_clip_path_reapply_clip_path_transform (clip,
     375             :                                                                other_path->prev,
     376             :                                                                matrix);
     377           0 :         if (unlikely (status))
     378           0 :             return status;
     379             :     }
     380             : 
     381           0 :     clip_path = _cairo_clip_path_create (clip);
     382           0 :     if (unlikely (clip_path == NULL))
     383           0 :         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
     384             : 
     385           0 :     status = _cairo_path_fixed_init_copy (&clip_path->path,
     386           0 :                                           &other_path->path);
     387           0 :     if (unlikely (status)) {
     388           0 :         clip->path = clip->path->prev;
     389           0 :         _cairo_clip_path_destroy (clip_path);
     390           0 :         return status;
     391             :     }
     392             : 
     393           0 :     _cairo_path_fixed_transform (&clip_path->path, matrix);
     394           0 :     _cairo_path_fixed_approximate_clip_extents (&clip_path->path,
     395             :                                                 &clip_path->extents);
     396           0 :     if (clip_path->prev != NULL) {
     397           0 :         is_empty = _cairo_rectangle_intersect (&clip_path->extents,
     398           0 :                                                &clip_path->prev->extents);
     399             :     }
     400             : 
     401           0 :     clip_path->fill_rule = other_path->fill_rule;
     402           0 :     clip_path->tolerance = other_path->tolerance;
     403           0 :     clip_path->antialias = other_path->antialias;
     404             : 
     405           0 :     return CAIRO_STATUS_SUCCESS;
     406             : }
     407             : 
     408             : static cairo_status_t
     409           0 : _cairo_clip_path_reapply_clip_path_translate (cairo_clip_t      *clip,
     410             :                                               cairo_clip_path_t *other_path,
     411             :                                               int tx, int ty)
     412             : {
     413             :     cairo_status_t status;
     414             :     cairo_clip_path_t *clip_path;
     415             : 
     416           0 :     if (other_path->prev != NULL) {
     417           0 :         status = _cairo_clip_path_reapply_clip_path_translate (clip,
     418             :                                                                other_path->prev,
     419             :                                                                tx, ty);
     420           0 :         if (unlikely (status))
     421           0 :             return status;
     422             :     }
     423             : 
     424           0 :     clip_path = _cairo_clip_path_create (clip);
     425           0 :     if (unlikely (clip_path == NULL))
     426           0 :         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
     427             : 
     428           0 :     status = _cairo_path_fixed_init_copy (&clip_path->path,
     429           0 :                                           &other_path->path);
     430           0 :     if (unlikely (status)) {
     431           0 :         clip->path = clip->path->prev;
     432           0 :         _cairo_clip_path_destroy (clip_path);
     433           0 :         return status;
     434             :     }
     435             : 
     436           0 :     _cairo_path_fixed_translate (&clip_path->path,
     437             :                                  _cairo_fixed_from_int (tx),
     438             :                                  _cairo_fixed_from_int (ty));
     439             : 
     440           0 :     clip_path->fill_rule = other_path->fill_rule;
     441           0 :     clip_path->tolerance = other_path->tolerance;
     442           0 :     clip_path->antialias = other_path->antialias;
     443             : 
     444           0 :     clip_path->flags = other_path->flags;
     445           0 :     if (other_path->region != NULL) {
     446           0 :         clip_path->region = cairo_region_copy (other_path->region);
     447           0 :         status = clip_path->region->status;
     448           0 :         if (unlikely (status)) {
     449           0 :             clip->path = clip->path->prev;
     450           0 :             _cairo_clip_path_destroy (clip_path);
     451           0 :             return status;
     452             :         }
     453             : 
     454           0 :         cairo_region_translate (clip_path->region, tx, ty);
     455             :     }
     456           0 :     clip_path->surface = cairo_surface_reference (other_path->surface);
     457             : 
     458           0 :     clip_path->extents = other_path->extents;
     459           0 :     clip_path->extents.x += tx;
     460           0 :     clip_path->extents.y += ty;
     461             : 
     462           0 :     return CAIRO_STATUS_SUCCESS;
     463             : }
     464             : 
     465             : cairo_status_t
     466           0 : _cairo_clip_init_copy_transformed (cairo_clip_t    *clip,
     467             :                                    cairo_clip_t    *other,
     468             :                                    const cairo_matrix_t *matrix)
     469             : {
     470           0 :     cairo_status_t status = CAIRO_STATUS_SUCCESS;
     471             :     int tx, ty;
     472             : 
     473           0 :     if (other == NULL) {
     474           0 :         _cairo_clip_init (clip);
     475           0 :         return CAIRO_STATUS_SUCCESS;
     476             :     }
     477             : 
     478           0 :     if (other->all_clipped) {
     479           0 :         _cairo_clip_init (clip);
     480           0 :         clip->all_clipped = TRUE;
     481           0 :         return CAIRO_STATUS_SUCCESS;
     482             :     }
     483             : 
     484           0 :     if (_cairo_matrix_is_identity (matrix)) {
     485           0 :         _cairo_clip_init_copy (clip, other);
     486           0 :         return CAIRO_STATUS_SUCCESS;
     487             :     }
     488             : 
     489           0 :     if (other->path != NULL) {
     490           0 :         _cairo_clip_init (clip);
     491             : 
     492             :         /* if we only need to translate, so we can reuse the caches... */
     493             :         /* XXX we still loose the benefit of constructs when the copy is
     494             :          * deleted though. Indirect clip_paths?
     495             :          */
     496           0 :         if (_cairo_matrix_is_integer_translation (matrix, &tx, &ty)) {
     497           0 :             status = _cairo_clip_path_reapply_clip_path_translate (clip,
     498             :                                                                    other->path,
     499             :                                                                    tx, ty);
     500             :         } else {
     501           0 :             status = _cairo_clip_path_reapply_clip_path_transform (clip,
     502             :                                                                    other->path,
     503             :                                                                    matrix);
     504           0 :             if (clip->path->extents.width == 0 &&
     505           0 :                 clip->path->extents.height == 0)
     506             :             {
     507           0 :                 _cairo_clip_set_all_clipped (clip);
     508             :             }
     509             :         }
     510             :     }
     511             : 
     512           0 :     return status;
     513             : }
     514             : 
     515             : static cairo_status_t
     516           0 : _cairo_clip_apply_clip_path (cairo_clip_t *clip,
     517             :                              const cairo_clip_path_t *path)
     518             : {
     519             :     cairo_status_t status;
     520             : 
     521           0 :     if (path->prev != NULL)
     522           0 :         status = _cairo_clip_apply_clip_path (clip, path->prev);
     523             : 
     524           0 :     return _cairo_clip_intersect_path (clip,
     525             :                                        &path->path,
     526             :                                        path->fill_rule,
     527             :                                        path->tolerance,
     528             :                                        path->antialias);
     529             : }
     530             : 
     531             : cairo_status_t
     532           0 : _cairo_clip_apply_clip (cairo_clip_t *clip,
     533             :                         const cairo_clip_t *other)
     534             : {
     535             :     cairo_status_t status;
     536             : 
     537           0 :     if (clip->all_clipped)
     538           0 :         return CAIRO_STATUS_SUCCESS;
     539             : 
     540           0 :     if (other->all_clipped) {
     541           0 :         _cairo_clip_set_all_clipped (clip);
     542           0 :         return CAIRO_STATUS_SUCCESS;
     543             :     }
     544             : 
     545           0 :     status = CAIRO_STATUS_SUCCESS;
     546           0 :     if (other->path != NULL)
     547           0 :         status = _cairo_clip_apply_clip_path (clip, other->path);
     548             : 
     549           0 :     return status;
     550             : }
     551             : 
     552             : static inline cairo_bool_t
     553           0 : _clip_paths_are_rectilinear (cairo_clip_path_t *clip_path)
     554             : {
     555           0 :     while (clip_path != NULL) {
     556           0 :         if (! clip_path->path.is_rectilinear)
     557           0 :             return FALSE;
     558             : 
     559           0 :         clip_path = clip_path->prev;
     560             :     }
     561             : 
     562           0 :     return TRUE;
     563             : }
     564             : 
     565             : static cairo_int_status_t
     566           0 : _cairo_clip_path_to_region_geometric (cairo_clip_path_t *clip_path)
     567             : {
     568             :     cairo_traps_t traps;
     569             :     cairo_box_t stack_boxes[CAIRO_STACK_ARRAY_LENGTH (cairo_box_t)];
     570           0 :     cairo_box_t *boxes = stack_boxes;
     571             :     cairo_status_t status;
     572             :     int n;
     573             : 
     574             :     /* If we have nothing to intersect with this path, then it cannot
     575             :      * magically be reduced into a region.
     576             :      */
     577           0 :     if (clip_path->prev == NULL)
     578           0 :         goto UNSUPPORTED;
     579             : 
     580             :     /* Start simple... Intersect some boxes with an arbitrary path. */
     581           0 :     if (! clip_path->path.is_rectilinear)
     582           0 :         goto UNSUPPORTED;
     583           0 :     if (clip_path->prev->prev != NULL)
     584           0 :         goto UNSUPPORTED;
     585             : 
     586           0 :     _cairo_traps_init (&traps);
     587           0 :     _cairo_box_from_rectangle (&boxes[0], &clip_path->extents);
     588           0 :     _cairo_traps_limit (&traps, boxes, 1);
     589             : 
     590           0 :     status = _cairo_path_fixed_fill_rectilinear_to_traps (&clip_path->path,
     591             :                                                           clip_path->fill_rule,
     592             :                                                           &traps);
     593           0 :     if (unlikely (_cairo_status_is_error (status)))
     594           0 :         return status;
     595           0 :     if (status == CAIRO_INT_STATUS_UNSUPPORTED)
     596           0 :         goto UNSUPPORTED;
     597             : 
     598           0 :     if (unlikely (traps.num_traps == 0)) {
     599           0 :         clip_path->region = cairo_region_create ();
     600           0 :         clip_path->flags |= CAIRO_CLIP_PATH_HAS_REGION;
     601           0 :         return CAIRO_STATUS_SUCCESS;
     602             :     }
     603             : 
     604           0 :     if (traps.num_traps > ARRAY_LENGTH (stack_boxes)) {
     605           0 :         boxes = _cairo_malloc_ab (traps.num_traps, sizeof (cairo_box_t));
     606           0 :         if (unlikely (boxes == NULL))
     607           0 :             return _cairo_error (CAIRO_STATUS_NO_MEMORY);
     608             :     }
     609             : 
     610           0 :     for (n = 0; n < traps.num_traps; n++) {
     611           0 :         boxes[n].p1.x = traps.traps[n].left.p1.x;
     612           0 :         boxes[n].p1.y = traps.traps[n].top;
     613           0 :         boxes[n].p2.x = traps.traps[n].right.p1.x;
     614           0 :         boxes[n].p2.y = traps.traps[n].bottom;
     615             :     }
     616             : 
     617           0 :     _cairo_traps_clear (&traps);
     618           0 :     _cairo_traps_limit (&traps, boxes, n);
     619           0 :     status = _cairo_path_fixed_fill_to_traps (&clip_path->prev->path,
     620           0 :                                               clip_path->prev->fill_rule,
     621           0 :                                               clip_path->prev->tolerance,
     622             :                                               &traps);
     623           0 :     if (boxes != stack_boxes)
     624           0 :         free (boxes);
     625             : 
     626           0 :     if (unlikely (status))
     627           0 :         return status;
     628             : 
     629           0 :     status = _cairo_traps_extract_region (&traps, &clip_path->region);
     630           0 :     _cairo_traps_fini (&traps);
     631             : 
     632           0 :     if (status == CAIRO_INT_STATUS_UNSUPPORTED)
     633           0 :         goto UNSUPPORTED;
     634           0 :     if (unlikely (status))
     635           0 :         return status;
     636             : 
     637           0 :     clip_path->flags |= CAIRO_CLIP_PATH_HAS_REGION;
     638           0 :     return CAIRO_STATUS_SUCCESS;
     639             : 
     640             : UNSUPPORTED:
     641           0 :     clip_path->flags |= CAIRO_CLIP_PATH_REGION_IS_UNSUPPORTED;
     642           0 :     return CAIRO_INT_STATUS_UNSUPPORTED;
     643             : }
     644             : 
     645             : static cairo_int_status_t
     646           0 : _cairo_clip_path_to_region (cairo_clip_path_t *clip_path)
     647             : {
     648             :     cairo_int_status_t status;
     649           0 :     cairo_region_t *prev = NULL;
     650             : 
     651           0 :     if (clip_path->flags &
     652             :         (CAIRO_CLIP_PATH_HAS_REGION |
     653             :          CAIRO_CLIP_PATH_REGION_IS_UNSUPPORTED))
     654             :     {
     655           0 :         return clip_path->flags & CAIRO_CLIP_PATH_REGION_IS_UNSUPPORTED ?
     656           0 :             CAIRO_INT_STATUS_UNSUPPORTED :
     657             :             CAIRO_STATUS_SUCCESS;
     658             :     }
     659             : 
     660           0 :     if (! clip_path->path.maybe_fill_region)
     661           0 :         return _cairo_clip_path_to_region_geometric (clip_path);
     662             : 
     663             :     /* first retrieve the region for our antecedents */
     664           0 :     if (clip_path->prev != NULL) {
     665           0 :         status = _cairo_clip_path_to_region (clip_path->prev);
     666           0 :         if (status) {
     667           0 :             if (status == CAIRO_INT_STATUS_UNSUPPORTED)
     668           0 :                 return _cairo_clip_path_to_region_geometric (clip_path);
     669             : 
     670           0 :             return status;
     671             :         }
     672             : 
     673           0 :         prev = clip_path->prev->region;
     674             :     }
     675             : 
     676             :     /* now extract the region for ourselves */
     677           0 :     clip_path->region =
     678           0 :         _cairo_path_fixed_fill_rectilinear_to_region (&clip_path->path,
     679             :                                                       clip_path->fill_rule,
     680           0 :                                                       &clip_path->extents);
     681           0 :     assert (clip_path->region != NULL);
     682             : 
     683           0 :     status = clip_path->region->status;
     684           0 :     if (unlikely (status))
     685           0 :         return status;
     686             : 
     687           0 :     if (prev != NULL) {
     688           0 :         status = cairo_region_intersect (clip_path->region, prev);
     689           0 :         if (unlikely (status))
     690           0 :             return status;
     691             :     }
     692             : 
     693           0 :     clip_path->flags |= CAIRO_CLIP_PATH_HAS_REGION;
     694           0 :     return CAIRO_STATUS_SUCCESS;
     695             : }
     696             : 
     697             : static inline int
     698           0 : pot (int v)
     699             : {
     700           0 :     v--;
     701           0 :     v |= v >> 1;
     702           0 :     v |= v >> 2;
     703           0 :     v |= v >> 4;
     704           0 :     v |= v >> 8;
     705           0 :     v |= v >> 16;
     706           0 :     v++;
     707           0 :     return v;
     708             : }
     709             : 
     710             : /* XXX there is likely a faster method! ;-) */
     711             : static cairo_status_t
     712           0 : _region_clip_to_boxes (const cairo_region_t *region,
     713             :                        cairo_box_t **boxes,
     714             :                        int *num_boxes,
     715             :                        int *size_boxes)
     716             : {
     717             :     cairo_traps_t traps;
     718             :     cairo_status_t status;
     719             :     int n, num_rects;
     720             : 
     721           0 :     _cairo_traps_init (&traps);
     722           0 :     _cairo_traps_limit (&traps, *boxes, *num_boxes);
     723           0 :     traps.is_rectilinear = TRUE;
     724           0 :     traps.is_rectangular = TRUE;
     725             : 
     726           0 :     num_rects = cairo_region_num_rectangles (region);
     727           0 :     for (n = 0; n < num_rects; n++) {
     728             :         cairo_rectangle_int_t rect;
     729             :         cairo_point_t p1, p2;
     730             : 
     731           0 :         cairo_region_get_rectangle (region, n, &rect);
     732             : 
     733           0 :         p1.x = _cairo_fixed_from_int (rect.x);
     734           0 :         p1.y = _cairo_fixed_from_int (rect.y);
     735           0 :         p2.x = _cairo_fixed_from_int (rect.x + rect.width);
     736           0 :         p2.y = _cairo_fixed_from_int (rect.y + rect.height);
     737             : 
     738           0 :         status = _cairo_traps_tessellate_rectangle (&traps, &p1, &p2);
     739           0 :         if (unlikely (status))
     740           0 :             goto CLEANUP;
     741             :     }
     742             : 
     743           0 :     status = _cairo_bentley_ottmann_tessellate_rectangular_traps (&traps, CAIRO_FILL_RULE_WINDING);
     744           0 :     if (unlikely (status))
     745           0 :         goto CLEANUP;
     746             : 
     747           0 :     n = *size_boxes;
     748           0 :     if (n < 0)
     749           0 :         n = -n;
     750             : 
     751           0 :     if (traps.num_traps > n) {
     752             :         cairo_box_t *new_boxes;
     753             : 
     754           0 :         new_boxes = _cairo_malloc_ab (traps.num_traps, sizeof (cairo_box_t));
     755           0 :         if (unlikely (new_boxes == NULL)) {
     756           0 :             status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
     757           0 :             goto CLEANUP;
     758             :         }
     759             : 
     760           0 :         if (*size_boxes > 0)
     761           0 :             free (*boxes);
     762             : 
     763           0 :         *boxes = new_boxes;
     764           0 :         *size_boxes = traps.num_traps;
     765             :     }
     766             : 
     767           0 :     for (n = 0; n < traps.num_traps; n++) {
     768           0 :         (*boxes)[n].p1.x = traps.traps[n].left.p1.x;
     769           0 :         (*boxes)[n].p1.y = traps.traps[n].top;
     770           0 :         (*boxes)[n].p2.x = traps.traps[n].right.p1.x;
     771           0 :         (*boxes)[n].p2.y = traps.traps[n].bottom;
     772             :     }
     773           0 :     *num_boxes = n;
     774             : 
     775             :   CLEANUP:
     776           0 :     _cairo_traps_fini (&traps);
     777             : 
     778           0 :     return status;
     779             : }
     780             : 
     781             : static cairo_status_t
     782           0 : _rectilinear_clip_to_boxes (const cairo_path_fixed_t *path,
     783             :                             cairo_fill_rule_t fill_rule,
     784             :                             cairo_box_t **boxes,
     785             :                             int *num_boxes,
     786             :                             int *size_boxes)
     787             : {
     788             :     cairo_polygon_t polygon;
     789             :     cairo_traps_t traps;
     790             :     cairo_status_t status;
     791             : 
     792           0 :     _cairo_traps_init (&traps);
     793           0 :     _cairo_traps_limit (&traps, *boxes, *num_boxes);
     794             : 
     795           0 :     _cairo_polygon_init (&polygon);
     796           0 :     _cairo_polygon_limit (&polygon, *boxes, *num_boxes);
     797             : 
     798           0 :     status = _cairo_path_fixed_fill_rectilinear_to_traps (path,
     799             :                                                           fill_rule,
     800             :                                                           &traps);
     801           0 :     if (unlikely (_cairo_status_is_error (status)))
     802           0 :         goto CLEANUP;
     803           0 :     if (status == CAIRO_STATUS_SUCCESS)
     804           0 :         goto BOXES;
     805             : 
     806             :     /* tolerance will be ignored as the path is rectilinear */
     807           0 :     status = _cairo_path_fixed_fill_to_polygon (path, 0., &polygon);
     808           0 :     if (unlikely (status))
     809           0 :         goto CLEANUP;
     810             : 
     811           0 :     if (polygon.num_edges == 0) {
     812           0 :         *num_boxes = 0;
     813             :     } else {
     814           0 :         status = _cairo_bentley_ottmann_tessellate_rectilinear_polygon (&traps,
     815             :                                                                         &polygon,
     816             :                                                                         fill_rule);
     817           0 :         if (likely (status == CAIRO_STATUS_SUCCESS)) {
     818             :             int i;
     819             : 
     820             :           BOXES:
     821           0 :             i = *size_boxes;
     822           0 :             if (i < 0)
     823           0 :                 i = -i;
     824             : 
     825           0 :             if (traps.num_traps > i) {
     826             :                 cairo_box_t *new_boxes;
     827             :                 int new_size;
     828             : 
     829           0 :                 new_size = pot (traps.num_traps);
     830           0 :                 new_boxes = _cairo_malloc_ab (new_size, sizeof (cairo_box_t));
     831           0 :                 if (unlikely (new_boxes == NULL)) {
     832           0 :                     status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
     833           0 :                     goto CLEANUP;
     834             :                 }
     835             : 
     836           0 :                 if (*size_boxes > 0)
     837           0 :                     free (*boxes);
     838             : 
     839           0 :                 *boxes = new_boxes;
     840           0 :                 *size_boxes = new_size;
     841             :             }
     842             : 
     843           0 :             for (i = 0; i < traps.num_traps; i++) {
     844           0 :                 (*boxes)[i].p1.x = traps.traps[i].left.p1.x;
     845           0 :                 (*boxes)[i].p1.y = traps.traps[i].top;
     846           0 :                 (*boxes)[i].p2.x = traps.traps[i].right.p1.x;
     847           0 :                 (*boxes)[i].p2.y = traps.traps[i].bottom;
     848             :             }
     849           0 :             *num_boxes = i;
     850             :         }
     851             :     }
     852             : 
     853             :   CLEANUP:
     854           0 :     _cairo_polygon_fini (&polygon);
     855           0 :     _cairo_traps_fini (&traps);
     856             : 
     857           0 :     return status;
     858             : }
     859             : 
     860             : static cairo_int_status_t
     861           0 : _cairo_clip_path_to_boxes (cairo_clip_path_t *clip_path,
     862             :                            cairo_box_t **boxes,
     863             :                            int *count)
     864             : {
     865           0 :     int size = -*count;
     866           0 :     int num_boxes = 0;
     867             :     cairo_status_t status;
     868             : 
     869           0 :     if (clip_path->region != NULL) {
     870             :         int num_rects, n;
     871             : 
     872           0 :         num_rects = cairo_region_num_rectangles (clip_path->region);
     873           0 :         if (num_rects > -size) {
     874             :             cairo_box_t *new_boxes;
     875             : 
     876           0 :             new_boxes = _cairo_malloc_ab (num_rects, sizeof (cairo_box_t));
     877           0 :             if (unlikely (new_boxes == NULL))
     878           0 :                 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
     879             : 
     880           0 :             *boxes = new_boxes;
     881             :         }
     882             : 
     883           0 :         for (n = 0; n < num_rects; n++) {
     884             :             cairo_rectangle_int_t rect;
     885             : 
     886           0 :             cairo_region_get_rectangle (clip_path->region, n, &rect);
     887           0 :             (*boxes)[n].p1.x = _cairo_fixed_from_int (rect.x);
     888           0 :             (*boxes)[n].p1.y = _cairo_fixed_from_int (rect.y);
     889           0 :             (*boxes)[n].p2.x = _cairo_fixed_from_int (rect.x + rect.width);
     890           0 :             (*boxes)[n].p2.y = _cairo_fixed_from_int (rect.y + rect.height);
     891             :         }
     892             : 
     893           0 :         *count = num_rects;
     894           0 :         return CAIRO_STATUS_SUCCESS;
     895             :     }
     896             : 
     897             :     /* keep it simple at first */
     898           0 :     if (! _clip_paths_are_rectilinear (clip_path))
     899           0 :         return CAIRO_INT_STATUS_UNSUPPORTED;
     900             : 
     901           0 :     assert (-size >= 1);
     902           0 :     if (_cairo_path_fixed_is_box (&clip_path->path, *boxes)) {
     903           0 :         num_boxes = 1;
     904             :     } else {
     905           0 :         status = _rectilinear_clip_to_boxes (&clip_path->path,
     906             :                                              clip_path->fill_rule,
     907             :                                              boxes, &num_boxes, &size);
     908           0 :         if (unlikely (status))
     909           0 :             return status;
     910             :     }
     911             : 
     912           0 :     while (num_boxes > 0 && (clip_path = clip_path->prev) != NULL) {
     913             :         cairo_box_t box;
     914             : 
     915           0 :         if (clip_path->region != NULL) {
     916           0 :             status = _region_clip_to_boxes (clip_path->region,
     917             :                                             boxes, &num_boxes, &size);
     918           0 :             if (unlikely (status))
     919           0 :                 return status;
     920             : 
     921           0 :             break;
     922           0 :         } else if (_cairo_path_fixed_is_box (&clip_path->path, &box)) {
     923             :             int i, j;
     924             : 
     925           0 :             for (i = j = 0; i < num_boxes; i++) {
     926           0 :                 if (j != i)
     927           0 :                     (*boxes)[j] = (*boxes)[i];
     928             : 
     929           0 :                 if (box.p1.x > (*boxes)[j].p1.x)
     930           0 :                     (*boxes)[j].p1.x = box.p1.x;
     931           0 :                 if (box.p2.x < (*boxes)[j].p2.x)
     932           0 :                     (*boxes)[j].p2.x = box.p2.x;
     933             : 
     934           0 :                 if (box.p1.y > (*boxes)[j].p1.y)
     935           0 :                     (*boxes)[j].p1.y = box.p1.y;
     936           0 :                 if (box.p2.y < (*boxes)[j].p2.y)
     937           0 :                     (*boxes)[j].p2.y = box.p2.y;
     938             : 
     939           0 :                 j += (*boxes)[j].p2.x > (*boxes)[j].p1.x &&
     940           0 :                      (*boxes)[j].p2.y > (*boxes)[j].p1.y;
     941             :             }
     942             : 
     943           0 :             num_boxes = j;
     944             :         } else {
     945           0 :             status = _rectilinear_clip_to_boxes (&clip_path->path,
     946             :                                                  clip_path->fill_rule,
     947             :                                                  boxes, &num_boxes, &size);
     948           0 :             if (unlikely (status))
     949           0 :                 return status;
     950             :         }
     951             :     }
     952             : 
     953           0 :     *count = num_boxes;
     954           0 :     return CAIRO_STATUS_SUCCESS;
     955             : }
     956             : 
     957             : static cairo_surface_t *
     958           0 : _cairo_clip_path_get_surface (cairo_clip_path_t *clip_path,
     959             :                               cairo_surface_t *target,
     960             :                               int *tx, int *ty)
     961             : {
     962           0 :     const cairo_rectangle_int_t *clip_extents = &clip_path->extents;
     963             :     cairo_bool_t need_translate;
     964             :     cairo_surface_t *surface;
     965             :     cairo_clip_path_t *prev;
     966             :     cairo_status_t status;
     967             : 
     968           0 :     while (clip_path->prev != NULL &&
     969           0 :            clip_path->flags & CAIRO_CLIP_PATH_IS_BOX &&
     970             :            clip_path->path.maybe_fill_region)
     971             :     {
     972           0 :         clip_path = clip_path->prev;
     973             :     }
     974             : 
     975           0 :     clip_extents = &clip_path->extents;
     976           0 :     if (clip_path->surface != NULL &&
     977           0 :         clip_path->surface->backend == target->backend)
     978             :     {
     979           0 :         *tx = clip_extents->x;
     980           0 :         *ty = clip_extents->y;
     981           0 :         return clip_path->surface;
     982             :     }
     983             : 
     984           0 :     surface = _cairo_surface_create_similar_scratch (target,
     985             :                                                      CAIRO_CONTENT_ALPHA,
     986             :                                                      clip_extents->width,
     987             :                                                      clip_extents->height);
     988           0 :     if (surface == NULL) {
     989           0 :         surface = cairo_image_surface_create (CAIRO_FORMAT_A8,
     990             :                                               clip_extents->width,
     991             :                                               clip_extents->height);
     992             :     }
     993           0 :     if (unlikely (surface->status))
     994           0 :         return surface;
     995             : 
     996           0 :     need_translate = clip_extents->x | clip_extents->y;
     997           0 :     if (clip_path->flags & CAIRO_CLIP_PATH_IS_BOX &&
     998             :         clip_path->path.maybe_fill_region)
     999             :     {
    1000           0 :         status = _cairo_surface_paint (surface,
    1001             :                                        CAIRO_OPERATOR_SOURCE,
    1002             :                                        &_cairo_pattern_white.base,
    1003             :                                        NULL);
    1004           0 :         if (unlikely (status))
    1005           0 :             goto BAIL;
    1006             :     }
    1007             :     else
    1008             :     {
    1009           0 :         status = _cairo_surface_paint (surface,
    1010             :                                        CAIRO_OPERATOR_CLEAR,
    1011             :                                        &_cairo_pattern_clear.base,
    1012             :                                        NULL);
    1013           0 :         if (unlikely (status))
    1014           0 :             goto BAIL;
    1015             : 
    1016           0 :         if (need_translate) {
    1017           0 :             _cairo_path_fixed_translate (&clip_path->path,
    1018           0 :                                          _cairo_fixed_from_int (-clip_extents->x),
    1019           0 :                                          _cairo_fixed_from_int (-clip_extents->y));
    1020             :         }
    1021           0 :         status = _cairo_surface_fill (surface,
    1022             :                                       CAIRO_OPERATOR_ADD,
    1023             :                                       &_cairo_pattern_white.base,
    1024             :                                       &clip_path->path,
    1025             :                                       clip_path->fill_rule,
    1026             :                                       clip_path->tolerance,
    1027             :                                       clip_path->antialias,
    1028             :                                       NULL);
    1029           0 :         if (need_translate) {
    1030           0 :             _cairo_path_fixed_translate (&clip_path->path,
    1031             :                                          _cairo_fixed_from_int (clip_extents->x),
    1032             :                                          _cairo_fixed_from_int (clip_extents->y));
    1033             :         }
    1034             : 
    1035           0 :         if (unlikely (status))
    1036           0 :             goto BAIL;
    1037             :     }
    1038             : 
    1039           0 :     prev = clip_path->prev;
    1040           0 :     while (prev != NULL) {
    1041           0 :         if (prev->flags & CAIRO_CLIP_PATH_IS_BOX &&
    1042             :             prev->path.maybe_fill_region)
    1043             :         {
    1044             :             /* a simple box only affects the extents */
    1045             :         }
    1046           0 :         else if (prev->path.is_rectilinear ||
    1047           0 :                 prev->surface == NULL ||
    1048           0 :                 prev->surface->backend != target->backend)
    1049             :         {
    1050           0 :             if (need_translate) {
    1051           0 :                 _cairo_path_fixed_translate (&prev->path,
    1052           0 :                                              _cairo_fixed_from_int (-clip_extents->x),
    1053           0 :                                              _cairo_fixed_from_int (-clip_extents->y));
    1054             :             }
    1055           0 :             status = _cairo_surface_fill (surface,
    1056             :                                           CAIRO_OPERATOR_IN,
    1057             :                                           &_cairo_pattern_white.base,
    1058             :                                           &prev->path,
    1059             :                                           prev->fill_rule,
    1060             :                                           prev->tolerance,
    1061             :                                           prev->antialias,
    1062             :                                           NULL);
    1063           0 :             if (need_translate) {
    1064           0 :                 _cairo_path_fixed_translate (&prev->path,
    1065             :                                              _cairo_fixed_from_int (clip_extents->x),
    1066             :                                              _cairo_fixed_from_int (clip_extents->y));
    1067             :             }
    1068             : 
    1069           0 :             if (unlikely (status))
    1070           0 :                 goto BAIL;
    1071             :         }
    1072             :         else
    1073             :         {
    1074             :             cairo_surface_pattern_t pattern;
    1075             :             cairo_surface_t *prev_surface;
    1076             :             int prev_tx, prev_ty;
    1077             : 
    1078           0 :             prev_surface = _cairo_clip_path_get_surface (prev, target, &prev_tx, &prev_ty);
    1079           0 :             status = prev_surface->status;
    1080           0 :             if (unlikely (status))
    1081           0 :                 goto BAIL;
    1082             : 
    1083           0 :             _cairo_pattern_init_for_surface (&pattern, prev_surface);
    1084           0 :             pattern.base.filter = CAIRO_FILTER_NEAREST;
    1085           0 :             cairo_matrix_init_translate (&pattern.base.matrix,
    1086           0 :                                          clip_extents->x - prev_tx,
    1087           0 :                                          clip_extents->y - prev_ty);
    1088           0 :             status = _cairo_surface_paint (surface,
    1089             :                                            CAIRO_OPERATOR_IN,
    1090             :                                            &pattern.base,
    1091             :                                            NULL);
    1092           0 :             _cairo_pattern_fini (&pattern.base);
    1093             : 
    1094           0 :             if (unlikely (status))
    1095           0 :                 goto BAIL;
    1096             : 
    1097           0 :             break;
    1098             :         }
    1099             : 
    1100           0 :         prev = prev->prev;
    1101             :     }
    1102             : 
    1103           0 :     *tx = clip_extents->x;
    1104           0 :     *ty = clip_extents->y;
    1105           0 :     cairo_surface_destroy (clip_path->surface);
    1106           0 :     return clip_path->surface = surface;
    1107             : 
    1108             :   BAIL:
    1109           0 :     cairo_surface_destroy (surface);
    1110           0 :     return _cairo_surface_create_in_error (status);
    1111             : }
    1112             : 
    1113             : cairo_bool_t
    1114           0 : _cairo_clip_contains_rectangle (cairo_clip_t *clip,
    1115             :                                 const cairo_rectangle_int_t *rect)
    1116             : {
    1117             :     cairo_clip_path_t *clip_path;
    1118             : 
    1119           0 :     if (clip == NULL)
    1120           0 :         return FALSE;
    1121             : 
    1122           0 :     clip_path = clip->path;
    1123           0 :     if (clip_path->extents.x > rect->x ||
    1124           0 :         clip_path->extents.y > rect->y ||
    1125           0 :         clip_path->extents.x + clip_path->extents.width  < rect->x + rect->width ||
    1126           0 :         clip_path->extents.y + clip_path->extents.height < rect->y + rect->height)
    1127             :     {
    1128           0 :         return FALSE;
    1129             :     }
    1130             : 
    1131             :     do {
    1132             :         cairo_box_t box;
    1133             : 
    1134           0 :         if ((clip_path->flags & CAIRO_CLIP_PATH_IS_BOX) == 0)
    1135           0 :             return FALSE;
    1136             : 
    1137           0 :         if (! _cairo_path_fixed_is_box (&clip_path->path, &box))
    1138           0 :             return FALSE;
    1139             : 
    1140           0 :         if (box.p1.x > _cairo_fixed_from_int (rect->x) ||
    1141           0 :             box.p1.y > _cairo_fixed_from_int (rect->y) ||
    1142           0 :             box.p2.x < _cairo_fixed_from_int (rect->x + rect->width) ||
    1143           0 :             box.p2.y < _cairo_fixed_from_int (rect->y + rect->height))
    1144             :         {
    1145           0 :             return FALSE;
    1146             :         }
    1147           0 :     } while ((clip_path = clip_path->prev) != NULL);
    1148             : 
    1149           0 :     return TRUE;
    1150             : }
    1151             : 
    1152             : cairo_bool_t
    1153           0 : _cairo_clip_contains_extents (cairo_clip_t *clip,
    1154             :                               const cairo_composite_rectangles_t *extents)
    1155             : {
    1156             :     const cairo_rectangle_int_t *rect;
    1157             : 
    1158           0 :     if (clip == NULL)
    1159           0 :         return FALSE;
    1160             : 
    1161           0 :     rect = extents->is_bounded ? &extents->bounded : &extents->unbounded;
    1162           0 :     return _cairo_clip_contains_rectangle (clip, rect);
    1163             : }
    1164             : 
    1165             : void
    1166           0 : _cairo_debug_print_clip (FILE *stream, cairo_clip_t *clip)
    1167             : {
    1168             :     cairo_clip_path_t *clip_path;
    1169             : 
    1170           0 :     if (clip == NULL) {
    1171           0 :         fprintf (stream, "no clip\n");
    1172           0 :         return;
    1173             :     }
    1174             : 
    1175           0 :     if (clip->all_clipped) {
    1176           0 :         fprintf (stream, "clip: all-clipped\n");
    1177           0 :         return;
    1178             :     }
    1179             : 
    1180           0 :     if (clip->path == NULL) {
    1181           0 :         fprintf (stream, "clip: empty\n");
    1182           0 :         return;
    1183             :     }
    1184             : 
    1185           0 :     fprintf (stream, "clip:\n");
    1186             : 
    1187           0 :     clip_path = clip->path;
    1188             :     do {
    1189           0 :         fprintf (stream, "path: has region? %s, has surface? %s, aa=%d, tolerance=%f, rule=%d: ",
    1190           0 :                  clip_path->region == NULL ? "no" : "yes",
    1191           0 :                  clip_path->surface == NULL ? "no" : "yes",
    1192           0 :                  clip_path->antialias,
    1193             :                  clip_path->tolerance,
    1194           0 :                  clip_path->fill_rule);
    1195           0 :         _cairo_debug_print_path (stream, &clip_path->path);
    1196           0 :         fprintf (stream, "\n");
    1197           0 :     } while ((clip_path = clip_path->prev) != NULL);
    1198             : }
    1199             : 
    1200             : cairo_surface_t *
    1201           0 : _cairo_clip_get_surface (cairo_clip_t *clip, cairo_surface_t *target, int *tx, int *ty)
    1202             : {
    1203             :     /* XXX is_clear -> all_clipped */
    1204           0 :     assert (clip->path != NULL);
    1205           0 :     return _cairo_clip_path_get_surface (clip->path, target, tx, ty);
    1206             : }
    1207             : 
    1208             : cairo_status_t
    1209           0 : _cairo_clip_combine_with_surface (cairo_clip_t *clip,
    1210             :                                   cairo_surface_t *dst,
    1211             :                                   int dst_x, int dst_y)
    1212             : {
    1213           0 :     cairo_clip_path_t *clip_path = clip->path;
    1214             :     cairo_bool_t need_translate;
    1215             :     cairo_status_t status;
    1216             : 
    1217           0 :     assert (clip_path != NULL);
    1218             : 
    1219           0 :     need_translate = dst_x | dst_y;
    1220             :     do {
    1221           0 :         if (clip_path->surface != NULL &&
    1222           0 :             clip_path->surface->backend == dst->backend)
    1223             :         {
    1224             :             cairo_surface_pattern_t pattern;
    1225             : 
    1226           0 :             _cairo_pattern_init_for_surface (&pattern, clip_path->surface);
    1227           0 :             cairo_matrix_init_translate (&pattern.base.matrix,
    1228           0 :                                          dst_x - clip_path->extents.x,
    1229           0 :                                          dst_y - clip_path->extents.y);
    1230           0 :             pattern.base.filter = CAIRO_FILTER_NEAREST;
    1231           0 :             status = _cairo_surface_paint (dst,
    1232             :                                            CAIRO_OPERATOR_IN,
    1233             :                                            &pattern.base,
    1234             :                                            NULL);
    1235             : 
    1236           0 :             _cairo_pattern_fini (&pattern.base);
    1237             : 
    1238           0 :             return status;
    1239             :         }
    1240             : 
    1241           0 :         if (clip_path->flags & CAIRO_CLIP_PATH_IS_BOX &&
    1242             :             clip_path->path.maybe_fill_region)
    1243             :         {
    1244           0 :             continue;
    1245             :         }
    1246             : 
    1247           0 :         if (need_translate) {
    1248           0 :             _cairo_path_fixed_translate (&clip_path->path,
    1249             :                                          _cairo_fixed_from_int (-dst_x),
    1250             :                                          _cairo_fixed_from_int (-dst_y));
    1251             :         }
    1252           0 :         status = _cairo_surface_fill (dst,
    1253             :                                       CAIRO_OPERATOR_IN,
    1254             :                                       &_cairo_pattern_white.base,
    1255             :                                       &clip_path->path,
    1256             :                                       clip_path->fill_rule,
    1257             :                                       clip_path->tolerance,
    1258             :                                       clip_path->antialias,
    1259             :                                       NULL);
    1260           0 :         if (need_translate) {
    1261           0 :             _cairo_path_fixed_translate (&clip_path->path,
    1262             :                                          _cairo_fixed_from_int (dst_x),
    1263             :                                          _cairo_fixed_from_int (dst_y));
    1264             :         }
    1265             : 
    1266           0 :         if (unlikely (status))
    1267           0 :             return status;
    1268           0 :     } while ((clip_path = clip_path->prev) != NULL);
    1269             : 
    1270           0 :     return CAIRO_STATUS_SUCCESS;
    1271             : }
    1272             : 
    1273             : static const cairo_rectangle_int_t _cairo_empty_rectangle_int = { 0, 0, 0, 0 };
    1274             : 
    1275             : const cairo_rectangle_int_t *
    1276           0 : _cairo_clip_get_extents (const cairo_clip_t *clip)
    1277             : {
    1278           0 :     if (clip->all_clipped)
    1279           0 :         return &_cairo_empty_rectangle_int;
    1280             : 
    1281           0 :     if (clip->path == NULL)
    1282           0 :         return NULL;
    1283             : 
    1284           0 :     return &clip->path->extents;
    1285             : }
    1286             : 
    1287             : void
    1288           0 : _cairo_clip_drop_cache (cairo_clip_t  *clip)
    1289             : {
    1290             :     cairo_clip_path_t *clip_path;
    1291             : 
    1292           0 :     if (clip->path == NULL)
    1293           0 :         return;
    1294             : 
    1295           0 :     clip_path = clip->path;
    1296             :     do {
    1297           0 :         if (clip_path->region != NULL) {
    1298           0 :             cairo_region_destroy (clip_path->region);
    1299           0 :             clip_path->region = NULL;
    1300             :         }
    1301             : 
    1302           0 :         if (clip_path->surface != NULL) {
    1303           0 :             cairo_surface_destroy (clip_path->surface);
    1304           0 :             clip_path->surface = NULL;
    1305             :         }
    1306             : 
    1307           0 :         clip_path->flags &= ~CAIRO_CLIP_PATH_HAS_REGION;
    1308           0 :     } while ((clip_path = clip_path->prev) != NULL);
    1309             : }
    1310             : 
    1311             : const cairo_rectangle_list_t _cairo_rectangles_nil =
    1312             :   { CAIRO_STATUS_NO_MEMORY, NULL, 0 };
    1313             : static const cairo_rectangle_list_t _cairo_rectangles_not_representable =
    1314             :   { CAIRO_STATUS_CLIP_NOT_REPRESENTABLE, NULL, 0 };
    1315             : 
    1316             : static cairo_bool_t
    1317           0 : _cairo_clip_int_rect_to_user (cairo_gstate_t *gstate,
    1318             :                               cairo_rectangle_int_t *clip_rect,
    1319             :                               cairo_rectangle_t *user_rect)
    1320             : {
    1321             :     cairo_bool_t is_tight;
    1322             : 
    1323           0 :     double x1 = clip_rect->x;
    1324           0 :     double y1 = clip_rect->y;
    1325           0 :     double x2 = clip_rect->x + (int) clip_rect->width;
    1326           0 :     double y2 = clip_rect->y + (int) clip_rect->height;
    1327             : 
    1328           0 :     _cairo_gstate_backend_to_user_rectangle (gstate,
    1329             :                                              &x1, &y1, &x2, &y2,
    1330             :                                              &is_tight);
    1331             : 
    1332           0 :     user_rect->x = x1;
    1333           0 :     user_rect->y = y1;
    1334           0 :     user_rect->width  = x2 - x1;
    1335           0 :     user_rect->height = y2 - y1;
    1336             : 
    1337           0 :     return is_tight;
    1338             : }
    1339             : 
    1340             : cairo_int_status_t
    1341           0 : _cairo_clip_get_region (cairo_clip_t *clip,
    1342             :                         cairo_region_t **region)
    1343             : {
    1344             :     cairo_int_status_t status;
    1345             : 
    1346           0 :     if (clip->all_clipped)
    1347           0 :         goto CLIPPED;
    1348             : 
    1349           0 :     assert (clip->path != NULL);
    1350             : 
    1351           0 :     status = _cairo_clip_path_to_region (clip->path);
    1352           0 :     if (status)
    1353           0 :         return status;
    1354             : 
    1355           0 :     if (cairo_region_is_empty (clip->path->region)) {
    1356           0 :         _cairo_clip_set_all_clipped (clip);
    1357           0 :         goto CLIPPED;
    1358             :     }
    1359             : 
    1360           0 :     if (region)
    1361           0 :         *region = clip->path->region;
    1362           0 :     return CAIRO_STATUS_SUCCESS;
    1363             : 
    1364             :   CLIPPED:
    1365           0 :     if (region)
    1366           0 :         *region = NULL;
    1367           0 :     return CAIRO_INT_STATUS_NOTHING_TO_DO;
    1368             : }
    1369             : 
    1370             : cairo_int_status_t
    1371           0 : _cairo_clip_get_boxes (cairo_clip_t *clip,
    1372             :                        cairo_box_t **boxes,
    1373             :                        int *count)
    1374             : {
    1375             :     cairo_int_status_t status;
    1376             : 
    1377           0 :     if (clip->all_clipped)
    1378           0 :         return CAIRO_INT_STATUS_NOTHING_TO_DO;
    1379             : 
    1380           0 :     assert (clip->path != NULL);
    1381             : 
    1382           0 :     status = _cairo_clip_path_to_boxes (clip->path, boxes, count);
    1383           0 :     if (status)
    1384           0 :         return status;
    1385             : 
    1386           0 :     if (*count == 0) {
    1387           0 :         _cairo_clip_set_all_clipped (clip);
    1388           0 :         return CAIRO_INT_STATUS_NOTHING_TO_DO;
    1389             :     }
    1390             : 
    1391           0 :     return CAIRO_STATUS_SUCCESS;
    1392             : }
    1393             : 
    1394             : static cairo_bool_t
    1395           0 : box_is_aligned (const cairo_box_t *box)
    1396             : {
    1397             :     return
    1398           0 :         _cairo_fixed_is_integer (box->p1.x) &&
    1399           0 :         _cairo_fixed_is_integer (box->p1.y) &&
    1400           0 :         _cairo_fixed_is_integer (box->p2.x) &&
    1401           0 :         _cairo_fixed_is_integer (box->p2.y);
    1402             : }
    1403             : 
    1404             : static void
    1405           0 : intersect_with_boxes (cairo_composite_rectangles_t *extents,
    1406             :                       cairo_box_t *boxes,
    1407             :                       int num_boxes)
    1408             : {
    1409             :     cairo_rectangle_int_t rect;
    1410             :     cairo_box_t box;
    1411             :     cairo_bool_t is_empty;
    1412             : 
    1413           0 :     box.p1.x = box.p1.y = INT_MIN;
    1414           0 :     box.p2.x = box.p2.y = INT_MAX;
    1415           0 :     while (num_boxes--) {
    1416           0 :         if (boxes->p1.x < box.p1.x)
    1417           0 :             box.p1.x = boxes->p1.x;
    1418           0 :         if (boxes->p1.y < box.p1.y)
    1419           0 :             box.p1.y = boxes->p1.y;
    1420             : 
    1421           0 :         if (boxes->p2.x > box.p2.x)
    1422           0 :             box.p2.x = boxes->p2.x;
    1423           0 :         if (boxes->p2.y > box.p2.y)
    1424           0 :             box.p2.y = boxes->p2.y;
    1425             :     }
    1426             : 
    1427           0 :     _cairo_box_round_to_rectangle (&box, &rect);
    1428           0 :     is_empty = _cairo_rectangle_intersect (&extents->bounded, &rect);
    1429           0 :     is_empty = _cairo_rectangle_intersect (&extents->unbounded, &rect);
    1430           0 : }
    1431             : 
    1432             : cairo_status_t
    1433           0 : _cairo_clip_to_boxes (cairo_clip_t **clip,
    1434             :                       cairo_composite_rectangles_t *extents,
    1435             :                       cairo_box_t **boxes,
    1436             :                       int *num_boxes)
    1437             : {
    1438             :     cairo_status_t status;
    1439             :     const cairo_rectangle_int_t *rect;
    1440             : 
    1441           0 :     rect = extents->is_bounded ? &extents->bounded : &extents->unbounded;
    1442             : 
    1443           0 :     if (*clip == NULL)
    1444           0 :         goto EXTENTS;
    1445             : 
    1446           0 :     status = _cairo_clip_rectangle (*clip, rect);
    1447           0 :     if (unlikely (status))
    1448           0 :         return status;
    1449             : 
    1450           0 :     status = _cairo_clip_get_boxes (*clip, boxes, num_boxes);
    1451           0 :     switch ((int) status) {
    1452             :     case CAIRO_STATUS_SUCCESS:
    1453           0 :         intersect_with_boxes (extents, *boxes, *num_boxes);
    1454           0 :         if (rect->width == 0 || rect->height == 0 ||
    1455           0 :             extents->is_bounded ||
    1456           0 :             (*num_boxes == 1 && box_is_aligned (*boxes)))
    1457             :         {
    1458           0 :             *clip = NULL;
    1459             :         }
    1460           0 :         goto DONE;
    1461             : 
    1462             :     case CAIRO_INT_STATUS_UNSUPPORTED:
    1463           0 :         goto EXTENTS;
    1464             : 
    1465             :     default:
    1466           0 :         return status;
    1467             :     }
    1468             : 
    1469             :   EXTENTS:
    1470           0 :     status = CAIRO_STATUS_SUCCESS;
    1471           0 :     _cairo_box_from_rectangle (&(*boxes)[0], rect);
    1472           0 :     *num_boxes = 1;
    1473             :   DONE:
    1474           0 :     return status;
    1475             : }
    1476             : 
    1477             : 
    1478             : static cairo_rectangle_list_t *
    1479           0 : _cairo_rectangle_list_create_in_error (cairo_status_t status)
    1480             : {
    1481             :     cairo_rectangle_list_t *list;
    1482             : 
    1483           0 :     if (status == CAIRO_STATUS_NO_MEMORY)
    1484           0 :         return (cairo_rectangle_list_t*) &_cairo_rectangles_nil;
    1485           0 :     if (status == CAIRO_STATUS_CLIP_NOT_REPRESENTABLE)
    1486           0 :         return (cairo_rectangle_list_t*) &_cairo_rectangles_not_representable;
    1487             : 
    1488           0 :     list = malloc (sizeof (*list));
    1489           0 :     if (unlikely (list == NULL)) {
    1490           0 :         _cairo_error_throw (status);
    1491           0 :         return (cairo_rectangle_list_t*) &_cairo_rectangles_nil;
    1492             :     }
    1493             : 
    1494           0 :     list->status = status;
    1495           0 :     list->rectangles = NULL;
    1496           0 :     list->num_rectangles = 0;
    1497             : 
    1498           0 :     return list;
    1499             : }
    1500             : 
    1501             : cairo_rectangle_list_t *
    1502           0 : _cairo_clip_copy_rectangle_list (cairo_clip_t *clip, cairo_gstate_t *gstate)
    1503             : {
    1504             : #define ERROR_LIST(S) _cairo_rectangle_list_create_in_error (_cairo_error (S))
    1505             : 
    1506             :     cairo_rectangle_list_t *list;
    1507           0 :     cairo_rectangle_t *rectangles = NULL;
    1508           0 :     cairo_region_t *region = NULL;
    1509             :     cairo_int_status_t status;
    1510           0 :     int n_rects = 0;
    1511             :     int i;
    1512             : 
    1513           0 :     if (clip->all_clipped)
    1514           0 :         goto DONE;
    1515             : 
    1516           0 :     if (!clip->path)
    1517           0 :         return ERROR_LIST (CAIRO_STATUS_CLIP_NOT_REPRESENTABLE);
    1518             : 
    1519           0 :     status = _cairo_clip_get_region (clip, &region);
    1520           0 :     if (status == CAIRO_INT_STATUS_NOTHING_TO_DO) {
    1521           0 :         goto DONE;
    1522           0 :     } else if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
    1523           0 :         return ERROR_LIST (CAIRO_STATUS_CLIP_NOT_REPRESENTABLE);
    1524           0 :     } else if (unlikely (status)) {
    1525           0 :         return ERROR_LIST (status);
    1526             :     }
    1527             : 
    1528           0 :     n_rects = cairo_region_num_rectangles (region);
    1529           0 :     if (n_rects) {
    1530           0 :         rectangles = _cairo_malloc_ab (n_rects, sizeof (cairo_rectangle_t));
    1531           0 :         if (unlikely (rectangles == NULL)) {
    1532           0 :             return ERROR_LIST (CAIRO_STATUS_NO_MEMORY);
    1533             :         }
    1534             : 
    1535           0 :         for (i = 0; i < n_rects; ++i) {
    1536             :             cairo_rectangle_int_t clip_rect;
    1537             : 
    1538           0 :             cairo_region_get_rectangle (region, i, &clip_rect);
    1539             : 
    1540           0 :             if (! _cairo_clip_int_rect_to_user (gstate,
    1541             :                                                 &clip_rect,
    1542           0 :                                                 &rectangles[i]))
    1543             :             {
    1544           0 :                 free (rectangles);
    1545           0 :                 return ERROR_LIST (CAIRO_STATUS_CLIP_NOT_REPRESENTABLE);
    1546             :             }
    1547             :         }
    1548             :     }
    1549             : 
    1550             :  DONE:
    1551           0 :     list = malloc (sizeof (cairo_rectangle_list_t));
    1552           0 :     if (unlikely (list == NULL)) {
    1553           0 :         free (rectangles);
    1554           0 :         return ERROR_LIST (CAIRO_STATUS_NO_MEMORY);
    1555             :     }
    1556             : 
    1557           0 :     list->status = CAIRO_STATUS_SUCCESS;
    1558           0 :     list->rectangles = rectangles;
    1559           0 :     list->num_rectangles = n_rects;
    1560           0 :     return list;
    1561             : 
    1562             : #undef ERROR_LIST
    1563             : }
    1564             : 
    1565             : /**
    1566             :  * cairo_rectangle_list_destroy:
    1567             :  * @rectangle_list: a rectangle list, as obtained from cairo_copy_clip_rectangles()
    1568             :  *
    1569             :  * Unconditionally frees @rectangle_list and all associated
    1570             :  * references. After this call, the @rectangle_list pointer must not
    1571             :  * be dereferenced.
    1572             :  *
    1573             :  * Since: 1.4
    1574             :  **/
    1575             : void
    1576           0 : cairo_rectangle_list_destroy (cairo_rectangle_list_t *rectangle_list)
    1577             : {
    1578           0 :     if (rectangle_list == NULL || rectangle_list == &_cairo_rectangles_nil ||
    1579             :         rectangle_list == &_cairo_rectangles_not_representable)
    1580           0 :         return;
    1581             : 
    1582           0 :     free (rectangle_list->rectangles);
    1583           0 :     free (rectangle_list);
    1584             : }
    1585             : 
    1586             : void
    1587           0 : _cairo_clip_reset_static_data (void)
    1588             : {
    1589           0 :     _freed_pool_reset (&clip_path_pool);
    1590           0 : }

Generated by: LCOV version 1.13