LCOV - code coverage report
Current view: directory - gfx/cairo/cairo/src - cairo-path.c (source / functions) Found Hit Coverage
Test: app.info Lines: 185 0 0.0 %
Date: 2012-06-02 Functions: 16 0 0.0 %

       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.7