LCOV - code coverage report
Current view: top level - gfx/cairo/cairo/src - cairo-path.c (source / functions) Hit Total Coverage
Test: output.info Lines: 0 185 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 16 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 © 2005 Red Hat, Inc.
       4             :  * Copyright © 2006 Red Hat, Inc.
       5             :  *
       6             :  * This library is free software; you can redistribute it and/or
       7             :  * modify it either under the terms of the GNU Lesser General Public
       8             :  * License version 2.1 as published by the Free Software Foundation
       9             :  * (the "LGPL") or, at your option, under the terms of the Mozilla
      10             :  * Public License Version 1.1 (the "MPL"). If you do not alter this
      11             :  * notice, a recipient may use your version of this file under either
      12             :  * the MPL or the LGPL.
      13             :  *
      14             :  * You should have received a copy of the LGPL along with this library
      15             :  * in the file COPYING-LGPL-2.1; if not, write to the Free Software
      16             :  * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
      17             :  * You should have received a copy of the MPL along with this library
      18             :  * in the file COPYING-MPL-1.1
      19             :  *
      20             :  * The contents of this file are subject to the Mozilla Public License
      21             :  * Version 1.1 (the "License"); you may not use this file except in
      22             :  * compliance with the License. You may obtain a copy of the License at
      23             :  * http://www.mozilla.org/MPL/
      24             :  *
      25             :  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
      26             :  * OF ANY KIND, either express or implied. See the LGPL or the MPL for
      27             :  * the specific language governing rights and limitations.
      28             :  *
      29             :  * The Original Code is the cairo graphics library.
      30             :  *
      31             :  * The Initial Developer of the Original Code is Red Hat, Inc.
      32             :  *
      33             :  * Contributor(s):
      34             :  *      Carl D. Worth <cworth@redhat.com>
      35             :  */
      36             : 
      37             : #include "cairoint.h"
      38             : 
      39             : #include "cairo-private.h"
      40             : #include "cairo-error-private.h"
      41             : #include "cairo-path-private.h"
      42             : #include "cairo-path-fixed-private.h"
      43             : 
      44             : /**
      45             :  * SECTION:cairo-paths
      46             :  * @Title: Paths
      47             :  * @Short_Description: Creating paths and manipulating path data
      48             :  *
      49             :  * Paths are the most basic drawing tools and are primarily used to implicitly
      50             :  * generate simple masks.
      51             :  */
      52             : 
      53             : static const cairo_path_t _cairo_path_nil = { CAIRO_STATUS_NO_MEMORY, NULL, 0 };
      54             : 
      55             : /* Closure for path interpretation. */
      56             : typedef struct cairo_path_count {
      57             :     int count;
      58             :     cairo_point_t current_point;
      59             : } cpc_t;
      60             : 
      61             : static cairo_status_t
      62           0 : _cpc_move_to (void *closure,
      63             :               const cairo_point_t *point)
      64             : {
      65           0 :     cpc_t *cpc = closure;
      66             : 
      67           0 :     cpc->count += 2;
      68             : 
      69           0 :     cpc->current_point = *point;
      70             : 
      71           0 :     return CAIRO_STATUS_SUCCESS;
      72             : }
      73             : 
      74             : static cairo_status_t
      75           0 : _cpc_line_to (void *closure,
      76             :               const cairo_point_t *point)
      77             : {
      78           0 :     cpc_t *cpc = closure;
      79             : 
      80           0 :     cpc->count += 2;
      81             : 
      82           0 :     cpc->current_point = *point;
      83             : 
      84           0 :     return CAIRO_STATUS_SUCCESS;
      85             : }
      86             : 
      87             : static cairo_status_t
      88           0 : _cpc_curve_to (void             *closure,
      89             :                const cairo_point_t      *p1,
      90             :                const cairo_point_t      *p2,
      91             :                const cairo_point_t      *p3)
      92             : {
      93           0 :     cpc_t *cpc = closure;
      94             : 
      95           0 :     cpc->count += 4;
      96             : 
      97           0 :     cpc->current_point = *p3;
      98             : 
      99           0 :     return CAIRO_STATUS_SUCCESS;
     100             : }
     101             : 
     102             : static cairo_status_t
     103           0 : _cpc_close_path (void *closure)
     104             : {
     105           0 :     cpc_t *cpc = closure;
     106             : 
     107           0 :     cpc->count += 1;
     108             : 
     109           0 :     return CAIRO_STATUS_SUCCESS;
     110             : }
     111             : 
     112             : static int
     113           0 : _cairo_path_count (cairo_path_t         *path,
     114             :                    cairo_path_fixed_t   *path_fixed,
     115             :                    double                tolerance,
     116             :                    cairo_bool_t          flatten)
     117             : {
     118             :     cairo_status_t status;
     119             :     cpc_t cpc;
     120             : 
     121           0 :     cpc.count = 0;
     122           0 :     cpc.current_point.x = 0;
     123           0 :     cpc.current_point.y = 0;
     124             : 
     125           0 :     if (flatten) {
     126           0 :         status = _cairo_path_fixed_interpret_flat (path_fixed,
     127             :                                                    CAIRO_DIRECTION_FORWARD,
     128             :                                                    _cpc_move_to,
     129             :                                                    _cpc_line_to,
     130             :                                                    _cpc_close_path,
     131             :                                                    &cpc,
     132             :                                                    tolerance);
     133             :     } else {
     134           0 :         status = _cairo_path_fixed_interpret (path_fixed,
     135             :                                               CAIRO_DIRECTION_FORWARD,
     136             :                                               _cpc_move_to,
     137             :                                               _cpc_line_to,
     138             :                                               _cpc_curve_to,
     139             :                                               _cpc_close_path,
     140             :                                               &cpc);
     141             :     }
     142             : 
     143           0 :     if (unlikely (status))
     144           0 :         return -1;
     145             : 
     146           0 :     return cpc.count;
     147             : }
     148             : 
     149             : /* Closure for path interpretation. */
     150             : typedef struct cairo_path_populate {
     151             :     cairo_path_data_t *data;
     152             :     cairo_gstate_t    *gstate;
     153             :     cairo_point_t      current_point;
     154             : } cpp_t;
     155             : 
     156             : static cairo_status_t
     157           0 : _cpp_move_to (void *closure,
     158             :               const cairo_point_t *point)
     159             : {
     160           0 :     cpp_t *cpp = closure;
     161           0 :     cairo_path_data_t *data = cpp->data;
     162             :     double x, y;
     163             : 
     164           0 :     x = _cairo_fixed_to_double (point->x);
     165           0 :     y = _cairo_fixed_to_double (point->y);
     166             : 
     167           0 :     _cairo_gstate_backend_to_user (cpp->gstate, &x, &y);
     168             : 
     169           0 :     data->header.type = CAIRO_PATH_MOVE_TO;
     170           0 :     data->header.length = 2;
     171             : 
     172             :     /* We index from 1 to leave room for data->header */
     173           0 :     data[1].point.x = x;
     174           0 :     data[1].point.y = y;
     175             : 
     176           0 :     cpp->data += data->header.length;
     177             : 
     178           0 :     cpp->current_point = *point;
     179             : 
     180           0 :     return CAIRO_STATUS_SUCCESS;
     181             : }
     182             : 
     183             : static cairo_status_t
     184           0 : _cpp_line_to (void *closure,
     185             :               const cairo_point_t *point)
     186             : {
     187           0 :     cpp_t *cpp = closure;
     188           0 :     cairo_path_data_t *data = cpp->data;
     189             :     double x, y;
     190             : 
     191           0 :     x = _cairo_fixed_to_double (point->x);
     192           0 :     y = _cairo_fixed_to_double (point->y);
     193             : 
     194           0 :     _cairo_gstate_backend_to_user (cpp->gstate, &x, &y);
     195             : 
     196           0 :     data->header.type = CAIRO_PATH_LINE_TO;
     197           0 :     data->header.length = 2;
     198             : 
     199             :     /* We index from 1 to leave room for data->header */
     200           0 :     data[1].point.x = x;
     201           0 :     data[1].point.y = y;
     202             : 
     203           0 :     cpp->data += data->header.length;
     204             : 
     205           0 :     cpp->current_point = *point;
     206             : 
     207           0 :     return CAIRO_STATUS_SUCCESS;
     208             : }
     209             : 
     210             : static cairo_status_t
     211           0 : _cpp_curve_to (void                     *closure,
     212             :                const cairo_point_t      *p1,
     213             :                const cairo_point_t      *p2,
     214             :                const cairo_point_t      *p3)
     215             : {
     216           0 :     cpp_t *cpp = closure;
     217           0 :     cairo_path_data_t *data = cpp->data;
     218             :     double x1, y1;
     219             :     double x2, y2;
     220             :     double x3, y3;
     221             : 
     222           0 :     x1 = _cairo_fixed_to_double (p1->x);
     223           0 :     y1 = _cairo_fixed_to_double (p1->y);
     224           0 :     _cairo_gstate_backend_to_user (cpp->gstate, &x1, &y1);
     225             : 
     226           0 :     x2 = _cairo_fixed_to_double (p2->x);
     227           0 :     y2 = _cairo_fixed_to_double (p2->y);
     228           0 :     _cairo_gstate_backend_to_user (cpp->gstate, &x2, &y2);
     229             : 
     230           0 :     x3 = _cairo_fixed_to_double (p3->x);
     231           0 :     y3 = _cairo_fixed_to_double (p3->y);
     232           0 :     _cairo_gstate_backend_to_user (cpp->gstate, &x3, &y3);
     233             : 
     234           0 :     data->header.type = CAIRO_PATH_CURVE_TO;
     235           0 :     data->header.length = 4;
     236             : 
     237             :     /* We index from 1 to leave room for data->header */
     238           0 :     data[1].point.x = x1;
     239           0 :     data[1].point.y = y1;
     240             : 
     241           0 :     data[2].point.x = x2;
     242           0 :     data[2].point.y = y2;
     243             : 
     244           0 :     data[3].point.x = x3;
     245           0 :     data[3].point.y = y3;
     246             : 
     247           0 :     cpp->data += data->header.length;
     248             : 
     249           0 :     cpp->current_point = *p3;
     250             : 
     251           0 :     return CAIRO_STATUS_SUCCESS;
     252             : }
     253             : 
     254             : static cairo_status_t
     255           0 : _cpp_close_path (void *closure)
     256             : {
     257           0 :     cpp_t *cpp = closure;
     258           0 :     cairo_path_data_t *data = cpp->data;
     259             : 
     260           0 :     data->header.type = CAIRO_PATH_CLOSE_PATH;
     261           0 :     data->header.length = 1;
     262             : 
     263           0 :     cpp->data += data->header.length;
     264             : 
     265           0 :     return CAIRO_STATUS_SUCCESS;
     266             : }
     267             : 
     268             : static cairo_status_t
     269           0 : _cairo_path_populate (cairo_path_t              *path,
     270             :                       cairo_path_fixed_t        *path_fixed,
     271             :                       cairo_gstate_t            *gstate,
     272             :                       cairo_bool_t               flatten)
     273             : {
     274             :     cairo_status_t status;
     275             :     cpp_t cpp;
     276             : 
     277           0 :     cpp.data = path->data;
     278           0 :     cpp.gstate = gstate;
     279           0 :     cpp.current_point.x = 0;
     280           0 :     cpp.current_point.y = 0;
     281             : 
     282           0 :     if (flatten) {
     283           0 :         double tolerance = _cairo_gstate_get_tolerance (gstate);
     284           0 :         status = _cairo_path_fixed_interpret_flat (path_fixed,
     285             :                                                    CAIRO_DIRECTION_FORWARD,
     286             :                                                    _cpp_move_to,
     287             :                                                    _cpp_line_to,
     288             :                                                    _cpp_close_path,
     289             :                                                    &cpp,
     290             :                                                    tolerance);
     291             :     } else {
     292           0 :         status = _cairo_path_fixed_interpret (path_fixed,
     293             :                                           CAIRO_DIRECTION_FORWARD,
     294             :                                           _cpp_move_to,
     295             :                                           _cpp_line_to,
     296             :                                           _cpp_curve_to,
     297             :                                           _cpp_close_path,
     298             :                                           &cpp);
     299             :     }
     300             : 
     301           0 :     if (unlikely (status))
     302           0 :         return status;
     303             : 
     304             :     /* Sanity check the count */
     305           0 :     assert (cpp.data - path->data == path->num_data);
     306             : 
     307           0 :     return CAIRO_STATUS_SUCCESS;
     308             : }
     309             : 
     310             : cairo_path_t *
     311           0 : _cairo_path_create_in_error (cairo_status_t status)
     312             : {
     313             :     cairo_path_t *path;
     314             : 
     315             :     /* special case NO_MEMORY so as to avoid allocations */
     316           0 :     if (status == CAIRO_STATUS_NO_MEMORY)
     317           0 :         return (cairo_path_t*) &_cairo_path_nil;
     318             : 
     319           0 :     path = malloc (sizeof (cairo_path_t));
     320           0 :     if (unlikely (path == NULL)) {
     321           0 :         _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
     322           0 :         return (cairo_path_t*) &_cairo_path_nil;
     323             :     }
     324             : 
     325           0 :     path->num_data = 0;
     326           0 :     path->data = NULL;
     327           0 :     path->status = status;
     328             : 
     329           0 :     return path;
     330             : }
     331             : 
     332             : static cairo_path_t *
     333           0 : _cairo_path_create_internal (cairo_path_fixed_t *path_fixed,
     334             :                              cairo_gstate_t     *gstate,
     335             :                              cairo_bool_t        flatten)
     336             : {
     337             :     cairo_path_t *path;
     338             : 
     339           0 :     path = malloc (sizeof (cairo_path_t));
     340           0 :     if (unlikely (path == NULL)) {
     341           0 :         _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
     342           0 :         return (cairo_path_t*) &_cairo_path_nil;
     343             :     }
     344             : 
     345           0 :     path->num_data = _cairo_path_count (path, path_fixed,
     346             :                                         _cairo_gstate_get_tolerance (gstate),
     347             :                                         flatten);
     348           0 :     if (path->num_data < 0) {
     349           0 :         free (path);
     350           0 :         return (cairo_path_t*) &_cairo_path_nil;
     351             :     }
     352             : 
     353           0 :     if (path->num_data) {
     354           0 :         path->data = _cairo_malloc_ab (path->num_data,
     355             :                                        sizeof (cairo_path_data_t));
     356           0 :         if (unlikely (path->data == NULL)) {
     357           0 :             free (path);
     358           0 :             _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
     359           0 :             return (cairo_path_t*) &_cairo_path_nil;
     360             :         }
     361             : 
     362           0 :         path->status = _cairo_path_populate (path, path_fixed,
     363             :                                              gstate, flatten);
     364             :     } else {
     365           0 :         path->data = NULL;
     366           0 :         path->status = CAIRO_STATUS_SUCCESS;
     367             :     }
     368             : 
     369           0 :     return path;
     370             : }
     371             : 
     372             : /**
     373             :  * cairo_path_destroy:
     374             :  * @path: a path previously returned by either cairo_copy_path() or
     375             :  * cairo_copy_path_flat().
     376             :  *
     377             :  * Immediately releases all memory associated with @path. After a call
     378             :  * to cairo_path_destroy() the @path pointer is no longer valid and
     379             :  * should not be used further.
     380             :  *
     381             :  * Note: cairo_path_destroy() should only be called with a
     382             :  * pointer to a #cairo_path_t returned by a cairo function. Any path
     383             :  * that is created manually (ie. outside of cairo) should be destroyed
     384             :  * manually as well.
     385             :  **/
     386             : void
     387           0 : cairo_path_destroy (cairo_path_t *path)
     388             : {
     389           0 :     if (path == NULL || path == &_cairo_path_nil)
     390           0 :         return;
     391             : 
     392           0 :     if (path->data)
     393           0 :         free (path->data);
     394             : 
     395           0 :     free (path);
     396             : }
     397             : 
     398             : /**
     399             :  * _cairo_path_create:
     400             :  * @path: a fixed-point, device-space path to be converted and copied
     401             :  * @gstate: the current graphics state
     402             :  *
     403             :  * Creates a user-space #cairo_path_t copy of the given device-space
     404             :  * @path. The @gstate parameter provides the inverse CTM for the
     405             :  * conversion.
     406             :  *
     407             :  * Return value: the new copy of the path. If there is insufficient
     408             :  * memory a pointer to a special static nil #cairo_path_t will be
     409             :  * returned instead with status==%CAIRO_STATUS_NO_MEMORY and
     410             :  * data==%NULL.
     411             :  **/
     412             : cairo_path_t *
     413           0 : _cairo_path_create (cairo_path_fixed_t *path,
     414             :                     cairo_gstate_t     *gstate)
     415             : {
     416           0 :     return _cairo_path_create_internal (path, gstate, FALSE);
     417             : }
     418             : 
     419             : /**
     420             :  * _cairo_path_create_flat:
     421             :  * @path: a fixed-point, device-space path to be flattened, converted and copied
     422             :  * @gstate: the current graphics state
     423             :  *
     424             :  * Creates a flattened, user-space #cairo_path_t copy of the given
     425             :  * device-space @path. The @gstate parameter provide the inverse CTM
     426             :  * for the conversion, as well as the tolerance value to control the
     427             :  * accuracy of the flattening.
     428             :  *
     429             :  * Return value: the flattened copy of the path. If there is insufficient
     430             :  * memory a pointer to a special static nil #cairo_path_t will be
     431             :  * returned instead with status==%CAIRO_STATUS_NO_MEMORY and
     432             :  * data==%NULL.
     433             :  **/
     434             : cairo_path_t *
     435           0 : _cairo_path_create_flat (cairo_path_fixed_t *path,
     436             :                          cairo_gstate_t     *gstate)
     437             : {
     438           0 :     return _cairo_path_create_internal (path, gstate, TRUE);
     439             : }
     440             : 
     441             : /**
     442             :  * _cairo_path_append_to_context:
     443             :  * @path: the path data to be appended
     444             :  * @cr: a cairo context
     445             :  *
     446             :  * Append @path to the current path within @cr.
     447             :  *
     448             :  * Return value: %CAIRO_STATUS_INVALID_PATH_DATA if the data in @path
     449             :  * is invalid, and %CAIRO_STATUS_SUCCESS otherwise.
     450             :  **/
     451             : cairo_status_t
     452           0 : _cairo_path_append_to_context (const cairo_path_t       *path,
     453             :                                cairo_t                  *cr)
     454             : {
     455             :     const cairo_path_data_t *p, *end;
     456             :     cairo_fixed_t x1_fixed, y1_fixed;
     457             :     cairo_fixed_t x2_fixed, y2_fixed;
     458             :     cairo_fixed_t x3_fixed, y3_fixed;
     459             :     cairo_matrix_t user_to_backend;
     460             :     cairo_status_t status;
     461             :     double x, y;
     462             : 
     463           0 :     user_to_backend = cr->gstate->ctm;
     464           0 :     cairo_matrix_multiply (&user_to_backend,
     465             :                            &user_to_backend,
     466           0 :                            &cr->gstate->target->device_transform);
     467             : 
     468           0 :     end = &path->data[path->num_data];
     469           0 :     for (p = &path->data[0]; p < end; p += p->header.length) {
     470           0 :         switch (p->header.type) {
     471             :         case CAIRO_PATH_MOVE_TO:
     472           0 :             if (unlikely (p->header.length < 2))
     473           0 :                 return _cairo_error (CAIRO_STATUS_INVALID_PATH_DATA);
     474             : 
     475           0 :             x = p[1].point.x, y = p[1].point.y;
     476           0 :             cairo_matrix_transform_point (&user_to_backend, &x, &y);
     477           0 :             x1_fixed = _cairo_fixed_from_double (x);
     478           0 :             y1_fixed = _cairo_fixed_from_double (y);
     479             : 
     480           0 :             status = _cairo_path_fixed_move_to (cr->path, x1_fixed, y1_fixed);
     481           0 :             break;
     482             : 
     483             :         case CAIRO_PATH_LINE_TO:
     484           0 :             if (unlikely (p->header.length < 2))
     485           0 :                 return _cairo_error (CAIRO_STATUS_INVALID_PATH_DATA);
     486             : 
     487           0 :             x = p[1].point.x, y = p[1].point.y;
     488           0 :             cairo_matrix_transform_point (&user_to_backend, &x, &y);
     489           0 :             x1_fixed = _cairo_fixed_from_double (x);
     490           0 :             y1_fixed = _cairo_fixed_from_double (y);
     491             : 
     492           0 :             status = _cairo_path_fixed_line_to (cr->path, x1_fixed, y1_fixed);
     493           0 :             break;
     494             : 
     495             :         case CAIRO_PATH_CURVE_TO:
     496           0 :             if (unlikely (p->header.length < 4))
     497           0 :                 return _cairo_error (CAIRO_STATUS_INVALID_PATH_DATA);
     498             : 
     499           0 :             x = p[1].point.x, y = p[1].point.y;
     500           0 :             cairo_matrix_transform_point (&user_to_backend, &x, &y);
     501           0 :             x1_fixed = _cairo_fixed_from_double (x);
     502           0 :             y1_fixed = _cairo_fixed_from_double (y);
     503             : 
     504           0 :             x = p[2].point.x, y = p[2].point.y;
     505           0 :             cairo_matrix_transform_point (&user_to_backend, &x, &y);
     506           0 :             x2_fixed = _cairo_fixed_from_double (x);
     507           0 :             y2_fixed = _cairo_fixed_from_double (y);
     508             : 
     509           0 :             x = p[3].point.x, y = p[3].point.y;
     510           0 :             cairo_matrix_transform_point (&user_to_backend, &x, &y);
     511           0 :             x3_fixed = _cairo_fixed_from_double (x);
     512           0 :             y3_fixed = _cairo_fixed_from_double (y);
     513             : 
     514           0 :             status = _cairo_path_fixed_curve_to (cr->path,
     515             :                                                  x1_fixed, y1_fixed,
     516             :                                                  x2_fixed, y2_fixed,
     517             :                                                  x3_fixed, y3_fixed);
     518           0 :             break;
     519             : 
     520             :         case CAIRO_PATH_CLOSE_PATH:
     521           0 :             if (unlikely (p->header.length < 1))
     522           0 :                 return _cairo_error (CAIRO_STATUS_INVALID_PATH_DATA);
     523             : 
     524           0 :             status = _cairo_path_fixed_close_path (cr->path);
     525           0 :             break;
     526             : 
     527             :         default:
     528           0 :             return _cairo_error (CAIRO_STATUS_INVALID_PATH_DATA);
     529             :         }
     530             : 
     531           0 :         if (unlikely (status))
     532           0 :             return status;
     533             :     }
     534             : 
     535           0 :     return CAIRO_STATUS_SUCCESS;
     536             : }

Generated by: LCOV version 1.13