Subversion Repositories Kolibri OS

Rev

Rev 1892 | Go to most recent revision | Blame | Last modification | View Log | Download | RSS feed

  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-backend-private.h"
  41. #include "cairo-error-private.h"
  42. #include "cairo-path-private.h"
  43. #include "cairo-path-fixed-private.h"
  44.  
  45. /**
  46.  * SECTION:cairo-paths
  47.  * @Title: Paths
  48.  * @Short_Description: Creating paths and manipulating path data
  49.  *
  50.  * Paths are the most basic drawing tools and are primarily used to implicitly
  51.  * generate simple masks.
  52.  **/
  53.  
  54. static const cairo_path_t _cairo_path_nil = { CAIRO_STATUS_NO_MEMORY, NULL, 0 };
  55.  
  56. /* Closure for path interpretation. */
  57. typedef struct cairo_path_count {
  58.     int count;
  59. } cpc_t;
  60.  
  61. static cairo_status_t
  62. _cpc_move_to (void *closure,
  63.               const cairo_point_t *point)
  64. {
  65.     cpc_t *cpc = closure;
  66.  
  67.     cpc->count += 2;
  68.  
  69.     return CAIRO_STATUS_SUCCESS;
  70. }
  71.  
  72. static cairo_status_t
  73. _cpc_line_to (void *closure,
  74.               const cairo_point_t *point)
  75. {
  76.     cpc_t *cpc = closure;
  77.  
  78.     cpc->count += 2;
  79.  
  80.     return CAIRO_STATUS_SUCCESS;
  81. }
  82.  
  83. static cairo_status_t
  84. _cpc_curve_to (void             *closure,
  85.                const cairo_point_t      *p1,
  86.                const cairo_point_t      *p2,
  87.                const cairo_point_t      *p3)
  88. {
  89.     cpc_t *cpc = closure;
  90.  
  91.     cpc->count += 4;
  92.  
  93.     return CAIRO_STATUS_SUCCESS;
  94. }
  95.  
  96. static cairo_status_t
  97. _cpc_close_path (void *closure)
  98. {
  99.     cpc_t *cpc = closure;
  100.  
  101.     cpc->count += 1;
  102.  
  103.     return CAIRO_STATUS_SUCCESS;
  104. }
  105.  
  106. static int
  107. _cairo_path_count (cairo_path_t         *path,
  108.                    cairo_path_fixed_t   *path_fixed,
  109.                    double                tolerance,
  110.                    cairo_bool_t          flatten)
  111. {
  112.     cairo_status_t status;
  113.     cpc_t cpc;
  114.  
  115.     cpc.count = 0;
  116.  
  117.     if (flatten) {
  118.         status = _cairo_path_fixed_interpret_flat (path_fixed,
  119.                                                    _cpc_move_to,
  120.                                                    _cpc_line_to,
  121.                                                    _cpc_close_path,
  122.                                                    &cpc,
  123.                                                    tolerance);
  124.     } else {
  125.         status = _cairo_path_fixed_interpret (path_fixed,
  126.                                               _cpc_move_to,
  127.                                               _cpc_line_to,
  128.                                               _cpc_curve_to,
  129.                                               _cpc_close_path,
  130.                                               &cpc);
  131.     }
  132.  
  133.     if (unlikely (status))
  134.         return -1;
  135.  
  136.     return cpc.count;
  137. }
  138.  
  139. /* Closure for path interpretation. */
  140. typedef struct cairo_path_populate {
  141.     cairo_path_data_t *data;
  142.     cairo_t *cr;
  143. } cpp_t;
  144.  
  145. static cairo_status_t
  146. _cpp_move_to (void *closure,
  147.               const cairo_point_t *point)
  148. {
  149.     cpp_t *cpp = closure;
  150.     cairo_path_data_t *data = cpp->data;
  151.     double x, y;
  152.  
  153.     x = _cairo_fixed_to_double (point->x);
  154.     y = _cairo_fixed_to_double (point->y);
  155.  
  156.     _cairo_backend_to_user (cpp->cr, &x, &y);
  157.  
  158.     data->header.type = CAIRO_PATH_MOVE_TO;
  159.     data->header.length = 2;
  160.  
  161.     /* We index from 1 to leave room for data->header */
  162.     data[1].point.x = x;
  163.     data[1].point.y = y;
  164.  
  165.     cpp->data += data->header.length;
  166.  
  167.     return CAIRO_STATUS_SUCCESS;
  168. }
  169.  
  170. static cairo_status_t
  171. _cpp_line_to (void *closure,
  172.               const cairo_point_t *point)
  173. {
  174.     cpp_t *cpp = closure;
  175.     cairo_path_data_t *data = cpp->data;
  176.     double x, y;
  177.  
  178.     x = _cairo_fixed_to_double (point->x);
  179.     y = _cairo_fixed_to_double (point->y);
  180.  
  181.     _cairo_backend_to_user (cpp->cr, &x, &y);
  182.  
  183.     data->header.type = CAIRO_PATH_LINE_TO;
  184.     data->header.length = 2;
  185.  
  186.     /* We index from 1 to leave room for data->header */
  187.     data[1].point.x = x;
  188.     data[1].point.y = y;
  189.  
  190.     cpp->data += data->header.length;
  191.  
  192.     return CAIRO_STATUS_SUCCESS;
  193. }
  194.  
  195. static cairo_status_t
  196. _cpp_curve_to (void                     *closure,
  197.                const cairo_point_t      *p1,
  198.                const cairo_point_t      *p2,
  199.                const cairo_point_t      *p3)
  200. {
  201.     cpp_t *cpp = closure;
  202.     cairo_path_data_t *data = cpp->data;
  203.     double x1, y1;
  204.     double x2, y2;
  205.     double x3, y3;
  206.  
  207.     x1 = _cairo_fixed_to_double (p1->x);
  208.     y1 = _cairo_fixed_to_double (p1->y);
  209.     _cairo_backend_to_user (cpp->cr, &x1, &y1);
  210.  
  211.     x2 = _cairo_fixed_to_double (p2->x);
  212.     y2 = _cairo_fixed_to_double (p2->y);
  213.     _cairo_backend_to_user (cpp->cr, &x2, &y2);
  214.  
  215.     x3 = _cairo_fixed_to_double (p3->x);
  216.     y3 = _cairo_fixed_to_double (p3->y);
  217.     _cairo_backend_to_user (cpp->cr, &x3, &y3);
  218.  
  219.     data->header.type = CAIRO_PATH_CURVE_TO;
  220.     data->header.length = 4;
  221.  
  222.     /* We index from 1 to leave room for data->header */
  223.     data[1].point.x = x1;
  224.     data[1].point.y = y1;
  225.  
  226.     data[2].point.x = x2;
  227.     data[2].point.y = y2;
  228.  
  229.     data[3].point.x = x3;
  230.     data[3].point.y = y3;
  231.  
  232.     cpp->data += data->header.length;
  233.  
  234.     return CAIRO_STATUS_SUCCESS;
  235. }
  236.  
  237. static cairo_status_t
  238. _cpp_close_path (void *closure)
  239. {
  240.     cpp_t *cpp = closure;
  241.     cairo_path_data_t *data = cpp->data;
  242.  
  243.     data->header.type = CAIRO_PATH_CLOSE_PATH;
  244.     data->header.length = 1;
  245.  
  246.     cpp->data += data->header.length;
  247.  
  248.     return CAIRO_STATUS_SUCCESS;
  249. }
  250.  
  251. static cairo_status_t
  252. _cairo_path_populate (cairo_path_t              *path,
  253.                       cairo_path_fixed_t        *path_fixed,
  254.                       cairo_t                   *cr,
  255.                       cairo_bool_t               flatten)
  256. {
  257.     cairo_status_t status;
  258.     cpp_t cpp;
  259.  
  260.     cpp.data = path->data;
  261.     cpp.cr = cr;
  262.  
  263.     if (flatten) {
  264.         status = _cairo_path_fixed_interpret_flat (path_fixed,
  265.                                                    _cpp_move_to,
  266.                                                    _cpp_line_to,
  267.                                                    _cpp_close_path,
  268.                                                    &cpp,
  269.                                                    cairo_get_tolerance (cr));
  270.     } else {
  271.         status = _cairo_path_fixed_interpret (path_fixed,
  272.                                           _cpp_move_to,
  273.                                           _cpp_line_to,
  274.                                           _cpp_curve_to,
  275.                                           _cpp_close_path,
  276.                                           &cpp);
  277.     }
  278.  
  279.     if (unlikely (status))
  280.         return status;
  281.  
  282.     /* Sanity check the count */
  283.     assert (cpp.data - path->data == path->num_data);
  284.  
  285.     return CAIRO_STATUS_SUCCESS;
  286. }
  287.  
  288. cairo_path_t *
  289. _cairo_path_create_in_error (cairo_status_t status)
  290. {
  291.     cairo_path_t *path;
  292.  
  293.     /* special case NO_MEMORY so as to avoid allocations */
  294.     if (status == CAIRO_STATUS_NO_MEMORY)
  295.         return (cairo_path_t*) &_cairo_path_nil;
  296.  
  297.     path = malloc (sizeof (cairo_path_t));
  298.     if (unlikely (path == NULL)) {
  299.         _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
  300.         return (cairo_path_t*) &_cairo_path_nil;
  301.     }
  302.  
  303.     path->num_data = 0;
  304.     path->data = NULL;
  305.     path->status = status;
  306.  
  307.     return path;
  308. }
  309.  
  310. static cairo_path_t *
  311. _cairo_path_create_internal (cairo_path_fixed_t *path_fixed,
  312.                              cairo_t            *cr,
  313.                              cairo_bool_t        flatten)
  314. {
  315.     cairo_path_t *path;
  316.  
  317.     path = malloc (sizeof (cairo_path_t));
  318.     if (unlikely (path == NULL)) {
  319.         _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
  320.         return (cairo_path_t*) &_cairo_path_nil;
  321.     }
  322.  
  323.     path->num_data = _cairo_path_count (path, path_fixed,
  324.                                         cairo_get_tolerance (cr),
  325.                                         flatten);
  326.     if (path->num_data < 0) {
  327.         free (path);
  328.         return (cairo_path_t*) &_cairo_path_nil;
  329.     }
  330.  
  331.     if (path->num_data) {
  332.         path->data = _cairo_malloc_ab (path->num_data,
  333.                                        sizeof (cairo_path_data_t));
  334.         if (unlikely (path->data == NULL)) {
  335.             free (path);
  336.             _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
  337.             return (cairo_path_t*) &_cairo_path_nil;
  338.         }
  339.  
  340.         path->status = _cairo_path_populate (path, path_fixed, cr, flatten);
  341.     } else {
  342.         path->data = NULL;
  343.         path->status = CAIRO_STATUS_SUCCESS;
  344.     }
  345.  
  346.     return path;
  347. }
  348.  
  349. /**
  350.  * cairo_path_destroy:
  351.  * @path: a path previously returned by either cairo_copy_path() or
  352.  * cairo_copy_path_flat().
  353.  *
  354.  * Immediately releases all memory associated with @path. After a call
  355.  * to cairo_path_destroy() the @path pointer is no longer valid and
  356.  * should not be used further.
  357.  *
  358.  * Note: cairo_path_destroy() should only be called with a
  359.  * pointer to a #cairo_path_t returned by a cairo function. Any path
  360.  * that is created manually (ie. outside of cairo) should be destroyed
  361.  * manually as well.
  362.  *
  363.  * Since: 1.0
  364.  **/
  365. void
  366. cairo_path_destroy (cairo_path_t *path)
  367. {
  368.     if (path == NULL || path == &_cairo_path_nil)
  369.         return;
  370.  
  371.     free (path->data);
  372.  
  373.     free (path);
  374. }
  375. slim_hidden_def (cairo_path_destroy);
  376.  
  377. /**
  378.  * _cairo_path_create:
  379.  * @path: a fixed-point, device-space path to be converted and copied
  380.  * @cr: the current graphics context
  381.  *
  382.  * Creates a user-space #cairo_path_t copy of the given device-space
  383.  * @path. The @cr parameter provides the inverse CTM for the
  384.  * conversion.
  385.  *
  386.  * Return value: the new copy of the path. If there is insufficient
  387.  * memory a pointer to a special static nil #cairo_path_t will be
  388.  * returned instead with status==%CAIRO_STATUS_NO_MEMORY and
  389.  * data==%NULL.
  390.  **/
  391. cairo_path_t *
  392. _cairo_path_create (cairo_path_fixed_t  *path,
  393.                     cairo_t             *cr)
  394. {
  395.     return _cairo_path_create_internal (path, cr, FALSE);
  396. }
  397.  
  398. /**
  399.  * _cairo_path_create_flat:
  400.  * @path: a fixed-point, device-space path to be flattened, converted and copied
  401.  * @cr: the current graphics context
  402.  *
  403.  * Creates a flattened, user-space #cairo_path_t copy of the given
  404.  * device-space @path. The @cr parameter provide the inverse CTM
  405.  * for the conversion, as well as the tolerance value to control the
  406.  * accuracy of the flattening.
  407.  *
  408.  * Return value: the flattened copy of the path. If there is insufficient
  409.  * memory a pointer to a special static nil #cairo_path_t will be
  410.  * returned instead with status==%CAIRO_STATUS_NO_MEMORY and
  411.  * data==%NULL.
  412.  **/
  413. cairo_path_t *
  414. _cairo_path_create_flat (cairo_path_fixed_t *path,
  415.                          cairo_t            *cr)
  416. {
  417.     return _cairo_path_create_internal (path, cr, TRUE);
  418. }
  419.  
  420. /**
  421.  * _cairo_path_append_to_context:
  422.  * @path: the path data to be appended
  423.  * @cr: a cairo context
  424.  *
  425.  * Append @path to the current path within @cr.
  426.  *
  427.  * Return value: %CAIRO_STATUS_INVALID_PATH_DATA if the data in @path
  428.  * is invalid, and %CAIRO_STATUS_SUCCESS otherwise.
  429.  **/
  430. cairo_status_t
  431. _cairo_path_append_to_context (const cairo_path_t       *path,
  432.                                cairo_t                  *cr)
  433. {
  434.     const cairo_path_data_t *p, *end;
  435.  
  436.     end = &path->data[path->num_data];
  437.     for (p = &path->data[0]; p < end; p += p->header.length) {
  438.         switch (p->header.type) {
  439.         case CAIRO_PATH_MOVE_TO:
  440.             if (unlikely (p->header.length < 2))
  441.                 return _cairo_error (CAIRO_STATUS_INVALID_PATH_DATA);
  442.  
  443.             cairo_move_to (cr, p[1].point.x, p[1].point.y);
  444.             break;
  445.  
  446.         case CAIRO_PATH_LINE_TO:
  447.             if (unlikely (p->header.length < 2))
  448.                 return _cairo_error (CAIRO_STATUS_INVALID_PATH_DATA);
  449.  
  450.             cairo_line_to (cr, p[1].point.x, p[1].point.y);
  451.             break;
  452.  
  453.         case CAIRO_PATH_CURVE_TO:
  454.             if (unlikely (p->header.length < 4))
  455.                 return _cairo_error (CAIRO_STATUS_INVALID_PATH_DATA);
  456.  
  457.             cairo_curve_to (cr,
  458.                             p[1].point.x, p[1].point.y,
  459.                             p[2].point.x, p[2].point.y,
  460.                             p[3].point.x, p[3].point.y);
  461.             break;
  462.  
  463.         case CAIRO_PATH_CLOSE_PATH:
  464.             if (unlikely (p->header.length < 1))
  465.                 return _cairo_error (CAIRO_STATUS_INVALID_PATH_DATA);
  466.  
  467.             cairo_close_path (cr);
  468.             break;
  469.  
  470.         default:
  471.             return _cairo_error (CAIRO_STATUS_INVALID_PATH_DATA);
  472.         }
  473.  
  474.         if (unlikely (cr->status))
  475.             return cr->status;
  476.     }
  477.  
  478.     return CAIRO_STATUS_SUCCESS;
  479. }
  480.