Back to index

lightning-sunbird  0.9+nobinonly
cairo-path-data.c
Go to the documentation of this file.
00001 /* cairo - a vector graphics library with display and print output
00002  *
00003  * Copyright © 2005 Red Hat, Inc.
00004  *
00005  * This library is free software; you can redistribute it and/or
00006  * modify it either under the terms of the GNU Lesser General Public
00007  * License version 2.1 as published by the Free Software Foundation
00008  * (the "LGPL") or, at your option, under the terms of the Mozilla
00009  * Public License Version 1.1 (the "MPL"). If you do not alter this
00010  * notice, a recipient may use your version of this file under either
00011  * the MPL or the LGPL.
00012  *
00013  * You should have received a copy of the LGPL along with this library
00014  * in the file COPYING-LGPL-2.1; if not, write to the Free Software
00015  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
00016  * You should have received a copy of the MPL along with this library
00017  * in the file COPYING-MPL-1.1
00018  *
00019  * The contents of this file are subject to the Mozilla Public License
00020  * Version 1.1 (the "License"); you may not use this file except in
00021  * compliance with the License. You may obtain a copy of the License at
00022  * http://www.mozilla.org/MPL/
00023  *
00024  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
00025  * OF ANY KIND, either express or implied. See the LGPL or the MPL for
00026  * the specific language governing rights and limitations.
00027  *
00028  * The Original Code is the cairo graphics library.
00029  *
00030  * The Initial Developer of the Original Code is Red Hat, Inc.
00031  *
00032  * Contributor(s):
00033  *     Carl D. Worth <cworth@redhat.com>
00034  */
00035 
00036 #include "cairo-path-data-private.h"
00037 #include "cairo-path-fixed-private.h"
00038 #include "cairo-gstate-private.h"
00039 
00040 const cairo_path_t _cairo_path_nil = { CAIRO_STATUS_NO_MEMORY, NULL, 0 };
00041 
00042 /* Closure for path interpretation. */
00043 typedef struct cairo_path_data_count {
00044     int count;
00045     double tolerance;
00046     cairo_point_t current_point;
00047 } cpdc_t;
00048 
00049 static cairo_status_t
00050 _cpdc_move_to (void *closure, cairo_point_t *point)
00051 {
00052     cpdc_t *cpdc = closure;
00053 
00054     cpdc->count += 2;
00055 
00056     cpdc->current_point = *point;
00057 
00058     return CAIRO_STATUS_SUCCESS;
00059 }
00060 
00061 static cairo_status_t
00062 _cpdc_line_to (void *closure, cairo_point_t *point)
00063 {
00064     cpdc_t *cpdc = closure;
00065 
00066     cpdc->count += 2;
00067 
00068     cpdc->current_point = *point;
00069 
00070     return CAIRO_STATUS_SUCCESS;
00071 }
00072 
00073 static cairo_status_t
00074 _cpdc_curve_to (void       *closure,
00075               cairo_point_t *p1,
00076               cairo_point_t *p2,
00077               cairo_point_t *p3)
00078 {
00079     cpdc_t *cpdc = closure;
00080 
00081     cpdc->count += 4;
00082 
00083     cpdc->current_point = *p3;
00084 
00085     return CAIRO_STATUS_SUCCESS;
00086 }
00087 
00088 static cairo_status_t
00089 _cpdc_curve_to_flatten (void             *closure,
00090                      cairo_point_t *p1,
00091                      cairo_point_t *p2,
00092                      cairo_point_t *p3)
00093 {
00094     cpdc_t *cpdc = closure;
00095     cairo_status_t status;
00096     cairo_spline_t spline;
00097     int i;
00098 
00099     cairo_point_t *p0 = &cpdc->current_point;
00100 
00101     status = _cairo_spline_init (&spline, p0, p1, p2, p3);
00102     if (status == CAIRO_INT_STATUS_DEGENERATE)
00103        return CAIRO_STATUS_SUCCESS;
00104 
00105     status = _cairo_spline_decompose (&spline, cpdc->tolerance);
00106     if (status)
00107       goto out;
00108 
00109     for (i=1; i < spline.num_points; i++)
00110        _cpdc_line_to (cpdc, &spline.points[i]);
00111 
00112     cpdc->current_point = *p3;
00113 
00114     status = CAIRO_STATUS_SUCCESS;
00115 
00116  out:
00117     _cairo_spline_fini (&spline);
00118     return status;
00119 }
00120 
00121 static cairo_status_t
00122 _cpdc_close_path (void *closure)
00123 {
00124     cpdc_t *cpdc = closure;
00125 
00126     cpdc->count += 1;
00127 
00128     cpdc->current_point.x = 0;
00129     cpdc->current_point.y = 0;
00130 
00131     return CAIRO_STATUS_SUCCESS;
00132 }
00133 
00134 static int
00135 _cairo_path_data_count (cairo_path_t         *path,
00136                      cairo_path_fixed_t *path_fixed,
00137                      double            tolerance,
00138                      cairo_bool_t      flatten)
00139 {
00140     cpdc_t cpdc;
00141 
00142     cpdc.count = 0;
00143     cpdc.tolerance = tolerance;
00144     cpdc.current_point.x = 0;
00145     cpdc.current_point.y = 0;
00146 
00147     _cairo_path_fixed_interpret (path_fixed,
00148                              CAIRO_DIRECTION_FORWARD,
00149                              _cpdc_move_to,
00150                              _cpdc_line_to,
00151                              flatten ?
00152                              _cpdc_curve_to_flatten :
00153                              _cpdc_curve_to,
00154                              _cpdc_close_path,
00155                              &cpdc);
00156 
00157     return cpdc.count;
00158 }
00159 
00160 /* Closure for path interpretation. */
00161 typedef struct cairo_path_data_populate {
00162     cairo_path_data_t *data;
00163     cairo_gstate_t    *gstate;
00164     cairo_point_t      current_point;
00165 } cpdp_t;
00166 
00167 static cairo_status_t
00168 _cpdp_move_to (void *closure, cairo_point_t *point)
00169 {
00170     cpdp_t *cpdp = closure;
00171     cairo_path_data_t *data = cpdp->data;
00172     double x, y;
00173 
00174     x = _cairo_fixed_to_double (point->x);
00175     y = _cairo_fixed_to_double (point->y);
00176 
00177     _cairo_gstate_backend_to_user (cpdp->gstate, &x, &y);
00178 
00179     data->header.type = CAIRO_PATH_MOVE_TO;
00180     data->header.length = 2;
00181 
00182     /* We index from 1 to leave room for data->header */
00183     data[1].point.x = x;
00184     data[1].point.y = y;
00185 
00186     cpdp->data += data->header.length;
00187 
00188     cpdp->current_point = *point;
00189 
00190     return CAIRO_STATUS_SUCCESS;
00191 }
00192 
00193 static cairo_status_t
00194 _cpdp_line_to (void *closure, cairo_point_t *point)
00195 {
00196     cpdp_t *cpdp = closure;
00197     cairo_path_data_t *data = cpdp->data;
00198     double x, y;
00199 
00200     x = _cairo_fixed_to_double (point->x);
00201     y = _cairo_fixed_to_double (point->y);
00202 
00203     _cairo_gstate_backend_to_user (cpdp->gstate, &x, &y);
00204 
00205     data->header.type = CAIRO_PATH_LINE_TO;
00206     data->header.length = 2;
00207 
00208     /* We index from 1 to leave room for data->header */
00209     data[1].point.x = x;
00210     data[1].point.y = y;
00211 
00212     cpdp->data += data->header.length;
00213 
00214     cpdp->current_point = *point;
00215 
00216     return CAIRO_STATUS_SUCCESS;
00217 }
00218 
00219 static cairo_status_t
00220 _cpdp_curve_to (void       *closure,
00221               cairo_point_t *p1,
00222               cairo_point_t *p2,
00223               cairo_point_t *p3)
00224 {
00225     cpdp_t *cpdp = closure;
00226     cairo_path_data_t *data = cpdp->data;
00227     double x1, y1;
00228     double x2, y2;
00229     double x3, y3;
00230 
00231     x1 = _cairo_fixed_to_double (p1->x);
00232     y1 = _cairo_fixed_to_double (p1->y);
00233     _cairo_gstate_backend_to_user (cpdp->gstate, &x1, &y1);
00234 
00235     x2 = _cairo_fixed_to_double (p2->x);
00236     y2 = _cairo_fixed_to_double (p2->y);
00237     _cairo_gstate_backend_to_user (cpdp->gstate, &x2, &y2);
00238 
00239     x3 = _cairo_fixed_to_double (p3->x);
00240     y3 = _cairo_fixed_to_double (p3->y);
00241     _cairo_gstate_backend_to_user (cpdp->gstate, &x3, &y3);
00242 
00243     data->header.type = CAIRO_PATH_CURVE_TO;
00244     data->header.length = 4;
00245 
00246     /* We index from 1 to leave room for data->header */
00247     data[1].point.x = x1;
00248     data[1].point.y = y1;
00249 
00250     data[2].point.x = x2;
00251     data[2].point.y = y2;
00252 
00253     data[3].point.x = x3;
00254     data[3].point.y = y3;
00255 
00256     cpdp->data += data->header.length;
00257 
00258     cpdp->current_point = *p3;
00259 
00260     return CAIRO_STATUS_SUCCESS;
00261 }
00262 
00263 static cairo_status_t
00264 _cpdp_curve_to_flatten (void             *closure,
00265                      cairo_point_t *p1,
00266                      cairo_point_t *p2,
00267                      cairo_point_t *p3)
00268 {
00269     cpdp_t *cpdp = closure;
00270     cairo_status_t status;
00271     cairo_spline_t spline;
00272     int i;
00273 
00274     cairo_point_t *p0 = &cpdp->current_point;
00275 
00276     status = _cairo_spline_init (&spline, p0, p1, p2, p3);
00277     if (status == CAIRO_INT_STATUS_DEGENERATE)
00278        return CAIRO_STATUS_SUCCESS;
00279 
00280     status = _cairo_spline_decompose (&spline, cpdp->gstate->tolerance);
00281     if (status)
00282       goto out;
00283 
00284     for (i=1; i < spline.num_points; i++)
00285        _cpdp_line_to (cpdp, &spline.points[i]);
00286 
00287     cpdp->current_point = *p3;
00288 
00289     status = CAIRO_STATUS_SUCCESS;
00290 
00291  out:
00292     _cairo_spline_fini (&spline);
00293     return status;
00294 }
00295 
00296 static cairo_status_t
00297 _cpdp_close_path (void *closure)
00298 {
00299     cpdp_t *cpdp = closure;
00300     cairo_path_data_t *data = cpdp->data;
00301 
00302     data->header.type = CAIRO_PATH_CLOSE_PATH;
00303     data->header.length = 1;
00304 
00305     cpdp->data += data->header.length;
00306 
00307     cpdp->current_point.x = 0;
00308     cpdp->current_point.y = 0;
00309 
00310     return CAIRO_STATUS_SUCCESS;
00311 }
00312 
00313 static void
00314 _cairo_path_data_populate (cairo_path_t   *path,
00315                         cairo_path_fixed_t *path_fixed,
00316                         cairo_gstate_t *gstate,
00317                         cairo_bool_t         flatten)
00318 {
00319     cpdp_t cpdp;
00320 
00321     cpdp.data = path->data;
00322     cpdp.gstate = gstate;
00323     cpdp.current_point.x = 0;
00324     cpdp.current_point.y = 0;
00325 
00326     _cairo_path_fixed_interpret (path_fixed,
00327                              CAIRO_DIRECTION_FORWARD,
00328                              _cpdp_move_to,
00329                              _cpdp_line_to,
00330                              flatten ?
00331                              _cpdp_curve_to_flatten :
00332                              _cpdp_curve_to,
00333                              _cpdp_close_path,
00334                              &cpdp);
00335 
00336     /* Sanity check the count */
00337     assert (cpdp.data - path->data == path->num_data);
00338 }
00339 
00340 static cairo_path_t *
00341 _cairo_path_data_create_real (cairo_path_fixed_t *path_fixed,
00342                            cairo_gstate_t     *gstate,
00343                            cairo_bool_t     flatten)
00344 {
00345     cairo_path_t *path;
00346 
00347     path = malloc (sizeof (cairo_path_t));
00348     if (path == NULL)
00349        return (cairo_path_t*) &_cairo_path_nil;
00350 
00351     path->num_data = _cairo_path_data_count (path, path_fixed,
00352                                         gstate->tolerance, flatten);
00353 
00354     path->data = malloc (path->num_data * sizeof (cairo_path_data_t));
00355     if (path->data == NULL) {
00356        free (path);
00357        return (cairo_path_t*) &_cairo_path_nil;
00358     }
00359 
00360     path->status = CAIRO_STATUS_SUCCESS;
00361 
00362     _cairo_path_data_populate (path, path_fixed,
00363                             gstate, flatten);
00364 
00365     return path;
00366 }
00367 
00382 void
00383 cairo_path_destroy (cairo_path_t *path)
00384 {
00385     if (path == NULL || path == &_cairo_path_nil)
00386        return;
00387 
00388     free (path->data);
00389     path->num_data = 0;
00390     free (path);
00391 }
00392 
00407 cairo_path_t *
00408 _cairo_path_data_create (cairo_path_fixed_t *path,
00409                       cairo_gstate_t     *gstate)
00410 {
00411     return _cairo_path_data_create_real (path, gstate, FALSE);
00412 }
00413 
00429 cairo_path_t *
00430 _cairo_path_data_create_flat (cairo_path_fixed_t *path,
00431                            cairo_gstate_t     *gstate)
00432 {
00433     return _cairo_path_data_create_real (path, gstate, TRUE);
00434 }
00435 
00446 cairo_status_t
00447 _cairo_path_data_append_to_context (cairo_path_t *path,
00448                                 cairo_t    *cr)
00449 {
00450     int i;
00451     cairo_path_data_t *p;
00452 
00453     for (i=0; i < path->num_data; i += path->data[i].header.length) {
00454        p = &path->data[i];
00455        switch (p->header.type) {
00456        case CAIRO_PATH_MOVE_TO:
00457            if (p->header.length != 2)
00458               return CAIRO_STATUS_INVALID_PATH_DATA;
00459            cairo_move_to (cr,
00460                         p[1].point.x, p[1].point.y);
00461            break;
00462        case CAIRO_PATH_LINE_TO:
00463            if (p->header.length != 2)
00464               return CAIRO_STATUS_INVALID_PATH_DATA;
00465            cairo_line_to (cr,
00466                         p[1].point.x, p[1].point.y);
00467            break;
00468        case CAIRO_PATH_CURVE_TO:
00469            if (p->header.length != 4)
00470               return CAIRO_STATUS_INVALID_PATH_DATA;
00471            cairo_curve_to (cr,
00472                          p[1].point.x, p[1].point.y,
00473                          p[2].point.x, p[2].point.y,
00474                          p[3].point.x, p[3].point.y);
00475            break;
00476        case CAIRO_PATH_CLOSE_PATH:
00477            if (p->header.length != 1)
00478               return CAIRO_STATUS_INVALID_PATH_DATA;
00479            cairo_close_path (cr);
00480            break;
00481        default:
00482            return CAIRO_STATUS_INVALID_PATH_DATA;
00483        }
00484     }
00485 
00486     return CAIRO_STATUS_SUCCESS;
00487 }