LCOV - code coverage report
Current view: top level - gfx/cairo/cairo/src - cairo-path-fill.c (source / functions) Hit Total Coverage
Test: output.info Lines: 0 182 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 13 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* cairo - a vector graphics library with display and print output
       2             :  *
       3             :  * Copyright © 2002 University of Southern California
       4             :  *
       5             :  * This library is free software; you can redistribute it and/or
       6             :  * modify it either under the terms of the GNU Lesser General Public
       7             :  * License version 2.1 as published by the Free Software Foundation
       8             :  * (the "LGPL") or, at your option, under the terms of the Mozilla
       9             :  * Public License Version 1.1 (the "MPL"). If you do not alter this
      10             :  * notice, a recipient may use your version of this file under either
      11             :  * the MPL or the LGPL.
      12             :  *
      13             :  * You should have received a copy of the LGPL along with this library
      14             :  * in the file COPYING-LGPL-2.1; if not, write to the Free Software
      15             :  * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
      16             :  * You should have received a copy of the MPL along with this library
      17             :  * in the file COPYING-MPL-1.1
      18             :  *
      19             :  * The contents of this file are subject to the Mozilla Public License
      20             :  * Version 1.1 (the "License"); you may not use this file except in
      21             :  * compliance with the License. You may obtain a copy of the License at
      22             :  * http://www.mozilla.org/MPL/
      23             :  *
      24             :  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
      25             :  * OF ANY KIND, either express or implied. See the LGPL or the MPL for
      26             :  * the specific language governing rights and limitations.
      27             :  *
      28             :  * The Original Code is the cairo graphics library.
      29             :  *
      30             :  * The Initial Developer of the Original Code is University of Southern
      31             :  * California.
      32             :  *
      33             :  * Contributor(s):
      34             :  *      Carl D. Worth <cworth@cworth.org>
      35             :  */
      36             : 
      37             : #include "cairoint.h"
      38             : #include "cairo-boxes-private.h"
      39             : #include "cairo-error-private.h"
      40             : #include "cairo-path-fixed-private.h"
      41             : #include "cairo-region-private.h"
      42             : 
      43             : typedef struct cairo_filler {
      44             :     double tolerance;
      45             :     cairo_polygon_t *polygon;
      46             : } cairo_filler_t;
      47             : 
      48             : static void
      49           0 : _cairo_filler_init (cairo_filler_t *filler,
      50             :                     double tolerance,
      51             :                     cairo_polygon_t *polygon)
      52             : {
      53           0 :     filler->tolerance = tolerance;
      54           0 :     filler->polygon = polygon;
      55           0 : }
      56             : 
      57             : static void
      58           0 : _cairo_filler_fini (cairo_filler_t *filler)
      59             : {
      60           0 : }
      61             : 
      62             : static cairo_status_t
      63           0 : _cairo_filler_move_to (void *closure,
      64             :                        const cairo_point_t *point)
      65             : {
      66           0 :     cairo_filler_t *filler = closure;
      67           0 :     cairo_polygon_t *polygon = filler->polygon;
      68             : 
      69           0 :     return _cairo_polygon_close (polygon) ||
      70           0 :            _cairo_polygon_move_to (polygon, point);
      71             : }
      72             : 
      73             : static cairo_status_t
      74           0 : _cairo_filler_line_to (void *closure,
      75             :                        const cairo_point_t *point)
      76             : {
      77           0 :     cairo_filler_t *filler = closure;
      78           0 :     return _cairo_polygon_line_to (filler->polygon, point);
      79             : }
      80             : 
      81             : static cairo_status_t
      82           0 : _cairo_filler_curve_to (void *closure,
      83             :                         const cairo_point_t *b,
      84             :                         const cairo_point_t *c,
      85             :                         const cairo_point_t *d)
      86             : {
      87           0 :     cairo_filler_t *filler = closure;
      88             :     cairo_spline_t spline;
      89             : 
      90           0 :     if (! _cairo_spline_init (&spline,
      91             :                               _cairo_filler_line_to, filler,
      92           0 :                               &filler->polygon->current_point, b, c, d))
      93             :     {
      94           0 :         return _cairo_filler_line_to (closure, d);
      95             :     }
      96             : 
      97           0 :     return _cairo_spline_decompose (&spline, filler->tolerance);
      98             : }
      99             : 
     100             : static cairo_status_t
     101           0 : _cairo_filler_close_path (void *closure)
     102             : {
     103           0 :     cairo_filler_t *filler = closure;
     104           0 :     return _cairo_polygon_close (filler->polygon);
     105             : }
     106             : 
     107             : cairo_status_t
     108           0 : _cairo_path_fixed_fill_to_polygon (const cairo_path_fixed_t *path,
     109             :                                    double tolerance,
     110             :                                    cairo_polygon_t *polygon)
     111             : {
     112             :     cairo_filler_t filler;
     113             :     cairo_status_t status;
     114             : 
     115           0 :     _cairo_filler_init (&filler, tolerance, polygon);
     116             : 
     117           0 :     status = _cairo_path_fixed_interpret (path,
     118             :                                           CAIRO_DIRECTION_FORWARD,
     119             :                                           _cairo_filler_move_to,
     120             :                                           _cairo_filler_line_to,
     121             :                                           _cairo_filler_curve_to,
     122             :                                           _cairo_filler_close_path,
     123             :                                           &filler);
     124           0 :     if (unlikely (status))
     125           0 :         return status;
     126             : 
     127           0 :     status = _cairo_polygon_close (polygon);
     128           0 :     _cairo_filler_fini (&filler);
     129             : 
     130           0 :     return status;
     131             : }
     132             : 
     133             : cairo_status_t
     134           0 : _cairo_path_fixed_fill_to_traps (const cairo_path_fixed_t *path,
     135             :                                  cairo_fill_rule_t fill_rule,
     136             :                                  double tolerance,
     137             :                                  cairo_traps_t *traps)
     138             : {
     139             :     cairo_polygon_t polygon;
     140             :     cairo_status_t status;
     141             : 
     142           0 :     if (path->is_empty_fill)
     143           0 :         return CAIRO_STATUS_SUCCESS;
     144             : 
     145           0 :     _cairo_polygon_init (&polygon);
     146           0 :     if (traps->num_limits)
     147           0 :         _cairo_polygon_limit (&polygon, traps->limits, traps->num_limits);
     148             : 
     149           0 :     status = _cairo_path_fixed_fill_to_polygon (path,
     150             :                                                 tolerance,
     151             :                                                 &polygon);
     152           0 :     if (unlikely (status || polygon.num_edges == 0))
     153             :         goto CLEANUP;
     154             : 
     155           0 :     if (path->is_rectilinear) {
     156           0 :         status = _cairo_bentley_ottmann_tessellate_rectilinear_polygon (traps,
     157             :                                                                         &polygon,
     158             :                                                                         fill_rule);
     159             :     } else {
     160           0 :         status = _cairo_bentley_ottmann_tessellate_polygon (traps,
     161             :                                                             &polygon,
     162             :                                                             fill_rule);
     163             :     }
     164             : 
     165             :   CLEANUP:
     166           0 :     _cairo_polygon_fini (&polygon);
     167           0 :     return status;
     168             : }
     169             : 
     170             : static cairo_region_t *
     171           0 : _cairo_path_fixed_fill_rectilinear_tessellate_to_region (const cairo_path_fixed_t       *path,
     172             :                                                          cairo_fill_rule_t       fill_rule,
     173             :                                                          const cairo_rectangle_int_t *extents)
     174             : {
     175             :     cairo_box_t box;
     176             :     cairo_polygon_t polygon;
     177             :     cairo_traps_t traps;
     178             :     cairo_status_t status;
     179             :     cairo_region_t *region;
     180             : 
     181             :     /* first try to bypass fill-to-polygon */
     182           0 :     _cairo_traps_init (&traps);
     183           0 :     status = _cairo_path_fixed_fill_rectilinear_to_traps (path,
     184             :                                                           fill_rule,
     185             :                                                           &traps);
     186           0 :     if (_cairo_status_is_error (status))
     187           0 :         goto CLEANUP_TRAPS;
     188             : 
     189           0 :     if (status == CAIRO_STATUS_SUCCESS) {
     190           0 :         status = _cairo_traps_extract_region (&traps, &region);
     191           0 :         goto CLEANUP_TRAPS;
     192             :     }
     193             : 
     194             :     /* path is not rectangular, try extracting clipped rectilinear edges */
     195           0 :     _cairo_polygon_init (&polygon);
     196           0 :     if (extents != NULL) {
     197           0 :         _cairo_box_from_rectangle (&box, extents);
     198           0 :         _cairo_polygon_limit (&polygon, &box, 1);
     199             :     }
     200             : 
     201             :     /* tolerance will be ignored as the path is rectilinear */
     202           0 :     status = _cairo_path_fixed_fill_to_polygon (path, 0., &polygon);
     203           0 :     if (unlikely (status))
     204           0 :         goto CLEANUP_POLYGON;
     205             : 
     206           0 :     if (polygon.num_edges == 0) {
     207           0 :         region = cairo_region_create ();
     208             :     } else {
     209           0 :         status =
     210             :             _cairo_bentley_ottmann_tessellate_rectilinear_polygon (&traps,
     211             :                                                                    &polygon,
     212             :                                                                    fill_rule);
     213           0 :         if (likely (status == CAIRO_STATUS_SUCCESS))
     214           0 :             status = _cairo_traps_extract_region (&traps, &region);
     215             :     }
     216             : 
     217             :   CLEANUP_POLYGON:
     218           0 :     _cairo_polygon_fini (&polygon);
     219             : 
     220             :   CLEANUP_TRAPS:
     221           0 :     _cairo_traps_fini (&traps);
     222             : 
     223           0 :     if (unlikely (status))
     224           0 :         region = _cairo_region_create_in_error (status);
     225             : 
     226           0 :     return region;
     227             : }
     228             : 
     229             : /* This special-case filler supports only a path that describes a
     230             :  * device-axis aligned rectangle. It exists to avoid the overhead of
     231             :  * the general tessellator when drawing very common rectangles.
     232             :  *
     233             :  * If the path described anything but a device-axis aligned rectangle,
     234             :  * this function will abort.
     235             :  */
     236             : cairo_region_t *
     237           0 : _cairo_path_fixed_fill_rectilinear_to_region (const cairo_path_fixed_t  *path,
     238             :                                               cairo_fill_rule_t  fill_rule,
     239             :                                               const cairo_rectangle_int_t *extents)
     240             : {
     241             :     cairo_rectangle_int_t rectangle_stack[CAIRO_STACK_ARRAY_LENGTH (cairo_rectangle_int_t)];
     242             :     cairo_box_t box;
     243           0 :     cairo_region_t *region = NULL;
     244             : 
     245           0 :     assert (path->maybe_fill_region);
     246           0 :     assert (! path->is_empty_fill);
     247             : 
     248           0 :     if (_cairo_path_fixed_is_box (path, &box)) {
     249           0 :         rectangle_stack[0].x = _cairo_fixed_integer_part (box.p1.x);
     250           0 :         rectangle_stack[0].y = _cairo_fixed_integer_part (box.p1.y);
     251           0 :         rectangle_stack[0].width = _cairo_fixed_integer_part (box.p2.x) -
     252           0 :                                     rectangle_stack[0].x;
     253           0 :         rectangle_stack[0].height = _cairo_fixed_integer_part (box.p2.y) -
     254           0 :                                     rectangle_stack[0].y;
     255           0 :         if (! _cairo_rectangle_intersect (&rectangle_stack[0], extents))
     256           0 :             region = cairo_region_create ();
     257             :         else
     258           0 :             region = cairo_region_create_rectangle (&rectangle_stack[0]);
     259           0 :     } else if (fill_rule == CAIRO_FILL_RULE_WINDING) {
     260           0 :         cairo_rectangle_int_t *rects = rectangle_stack;
     261             :         cairo_path_fixed_iter_t iter;
     262           0 :         int last_cw = -1;
     263           0 :         int size = ARRAY_LENGTH (rectangle_stack);
     264           0 :         int count = 0;
     265             : 
     266             :         /* Support a series of rectangles as can be expected to describe a
     267             :          * GdkRegion clip region during exposes.
     268             :          */
     269           0 :         _cairo_path_fixed_iter_init (&iter, path);
     270           0 :         while (_cairo_path_fixed_iter_is_fill_box (&iter, &box)) {
     271           0 :             int cw = 0;
     272             : 
     273           0 :             if (box.p1.x > box.p2.x) {
     274             :                 cairo_fixed_t t;
     275             : 
     276           0 :                 t = box.p1.x;
     277           0 :                 box.p1.x = box.p2.x;
     278           0 :                 box.p2.x = t;
     279             : 
     280           0 :                 cw = ! cw;
     281             :             }
     282             : 
     283           0 :             if (box.p1.y > box.p2.y) {
     284             :                 cairo_fixed_t t;
     285             : 
     286           0 :                 t = box.p1.y;
     287           0 :                 box.p1.y = box.p2.y;
     288           0 :                 box.p2.y = t;
     289             : 
     290           0 :                 cw = ! cw;
     291             :             }
     292             : 
     293           0 :             if (last_cw < 0)
     294           0 :                 last_cw = cw;
     295           0 :             else if (last_cw != cw)
     296           0 :                 goto TESSELLATE;
     297             : 
     298           0 :             if (count == size) {
     299             :                 cairo_rectangle_int_t *new_rects;
     300             : 
     301           0 :                 size *= 4;
     302           0 :                 if (rects == rectangle_stack) {
     303           0 :                     new_rects = _cairo_malloc_ab (size,
     304             :                                                   sizeof (cairo_rectangle_int_t));
     305           0 :                     if (unlikely (new_rects == NULL)) {
     306             :                         /* XXX _cairo_region_nil */
     307           0 :                         break;
     308             :                     }
     309           0 :                     memcpy (new_rects, rects, sizeof (rectangle_stack));
     310             :                 } else {
     311           0 :                     new_rects = _cairo_realloc_ab (rects, size,
     312             :                                                    sizeof (cairo_rectangle_int_t));
     313           0 :                     if (unlikely (new_rects == NULL)) {
     314             :                         /* XXX _cairo_region_nil */
     315           0 :                         break;
     316             :                     }
     317             :                 }
     318           0 :                 rects = new_rects;
     319             :             }
     320             : 
     321           0 :             rects[count].x = _cairo_fixed_integer_part (box.p1.x);
     322           0 :             rects[count].y = _cairo_fixed_integer_part (box.p1.y);
     323           0 :             rects[count].width = _cairo_fixed_integer_part (box.p2.x) - rects[count].x;
     324           0 :             rects[count].height = _cairo_fixed_integer_part (box.p2.y) - rects[count].y;
     325           0 :             if (_cairo_rectangle_intersect (&rects[count], extents))
     326           0 :                 count++;
     327             :         }
     328             : 
     329           0 :         if (_cairo_path_fixed_iter_at_end (&iter))
     330           0 :             region = cairo_region_create_rectangles (rects, count);
     331             : 
     332             : TESSELLATE:
     333           0 :         if (rects != rectangle_stack)
     334           0 :             free (rects);
     335             :     }
     336             : 
     337           0 :     if (region == NULL) {
     338             :         /* Hmm, complex polygon */
     339           0 :         region = _cairo_path_fixed_fill_rectilinear_tessellate_to_region (path,
     340             :                                                                           fill_rule,
     341             :                                                                           extents);
     342             : 
     343             : 
     344             :     }
     345             : 
     346           0 :     return region;
     347             : }
     348             : 
     349             : cairo_int_status_t
     350           0 : _cairo_path_fixed_fill_rectilinear_to_traps (const cairo_path_fixed_t *path,
     351             :                                              cairo_fill_rule_t fill_rule,
     352             :                                              cairo_traps_t *traps)
     353             : {
     354             :     cairo_box_t box;
     355             :     cairo_status_t status;
     356             : 
     357           0 :     traps->is_rectilinear = TRUE;
     358           0 :     traps->is_rectangular = TRUE;
     359             : 
     360           0 :     if (_cairo_path_fixed_is_box (path, &box)) {
     361           0 :         return _cairo_traps_tessellate_rectangle (traps, &box.p1, &box.p2);
     362             :     } else {
     363             :         cairo_path_fixed_iter_t iter;
     364             : 
     365           0 :         _cairo_path_fixed_iter_init (&iter, path);
     366           0 :         while (_cairo_path_fixed_iter_is_fill_box (&iter, &box)) {
     367           0 :             if (box.p1.y > box.p2.y) {
     368             :                 cairo_fixed_t t;
     369             : 
     370           0 :                 t = box.p1.y;
     371           0 :                 box.p1.y = box.p2.y;
     372           0 :                 box.p2.y = t;
     373             : 
     374           0 :                 t = box.p1.x;
     375           0 :                 box.p1.x = box.p2.x;
     376           0 :                 box.p2.x = t;
     377             :             }
     378             : 
     379           0 :             status = _cairo_traps_tessellate_rectangle (traps,
     380             :                                                         &box.p1, &box.p2);
     381           0 :             if (unlikely (status)) {
     382           0 :                 _cairo_traps_clear (traps);
     383           0 :                 return status;
     384             :             }
     385             :         }
     386             : 
     387           0 :         if (_cairo_path_fixed_iter_at_end (&iter))
     388           0 :             return _cairo_bentley_ottmann_tessellate_rectangular_traps (traps, fill_rule);
     389             : 
     390           0 :         _cairo_traps_clear (traps);
     391           0 :         return CAIRO_INT_STATUS_UNSUPPORTED;
     392             :     }
     393             : }
     394             : 
     395             : static cairo_status_t
     396           0 : _cairo_path_fixed_fill_rectilinear_tessellate_to_boxes (const cairo_path_fixed_t *path,
     397             :                                                         cairo_fill_rule_t fill_rule,
     398             :                                                         cairo_boxes_t *boxes)
     399             : {
     400             :     cairo_polygon_t polygon;
     401             :     cairo_status_t status;
     402             : 
     403           0 :     _cairo_polygon_init (&polygon);
     404           0 :     if (boxes->num_limits) {
     405           0 :         _cairo_polygon_limit (&polygon, boxes->limits, boxes->num_limits);
     406           0 :         boxes->num_limits = 0;
     407             :     }
     408             : 
     409             :     /* tolerance will be ignored as the path is rectilinear */
     410           0 :     status = _cairo_path_fixed_fill_to_polygon (path, 0., &polygon);
     411           0 :     if (likely (status == CAIRO_STATUS_SUCCESS)) {
     412           0 :         status =
     413             :             _cairo_bentley_ottmann_tessellate_rectilinear_polygon_to_boxes (&polygon,
     414             :                                                                             fill_rule,
     415             :                                                                             boxes);
     416             :     }
     417             : 
     418           0 :     _cairo_polygon_fini (&polygon);
     419             : 
     420           0 :     return status;
     421             : }
     422             : 
     423             : cairo_status_t
     424           0 : _cairo_path_fixed_fill_rectilinear_to_boxes (const cairo_path_fixed_t *path,
     425             :                                              cairo_fill_rule_t fill_rule,
     426             :                                              cairo_boxes_t *boxes)
     427             : {
     428             :     cairo_path_fixed_iter_t iter;
     429             :     cairo_status_t status;
     430             :     cairo_box_t box;
     431             : 
     432           0 :     if (_cairo_path_fixed_is_box (path, &box))
     433           0 :         return _cairo_boxes_add (boxes, &box);
     434             : 
     435           0 :     _cairo_path_fixed_iter_init (&iter, path);
     436           0 :     while (_cairo_path_fixed_iter_is_fill_box (&iter, &box)) {
     437           0 :         if (box.p1.y == box.p2.y || box.p1.x == box.p2.x)
     438           0 :             continue;
     439             : 
     440           0 :         if (box.p1.y > box.p2.y) {
     441             :             cairo_fixed_t t;
     442             : 
     443           0 :             t = box.p1.y;
     444           0 :             box.p1.y = box.p2.y;
     445           0 :             box.p2.y = t;
     446             : 
     447           0 :             t = box.p1.x;
     448           0 :             box.p1.x = box.p2.x;
     449           0 :             box.p2.x = t;
     450             :         }
     451             : 
     452           0 :         status = _cairo_boxes_add (boxes, &box);
     453           0 :         if (unlikely (status))
     454           0 :             return status;
     455             :     }
     456             : 
     457           0 :     if (_cairo_path_fixed_iter_at_end (&iter))
     458           0 :         return _cairo_bentley_ottmann_tessellate_boxes (boxes, fill_rule, boxes);
     459             : 
     460             :     /* path is not rectangular, try extracting clipped rectilinear edges */
     461           0 :     _cairo_boxes_clear (boxes);
     462           0 :     return _cairo_path_fixed_fill_rectilinear_tessellate_to_boxes (path,
     463             :                                                                    fill_rule,
     464             :                                                                    boxes);
     465             : }

Generated by: LCOV version 1.13