LCOV - app.info - gfx/cairo/cairo/src/cairo-path.c

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