Back to index

lightning-sunbird  0.9+nobinonly
cairo-path.c
Go to the documentation of this file.
00001 /* cairo - a vector graphics library with display and print output
00002  *
00003  * Copyright © 2002 University of Southern California
00004  * Copyright © 2005 Red Hat, Inc.
00005   *
00006  * This library is free software; you can redistribute it and/or
00007  * modify it either under the terms of the GNU Lesser General Public
00008  * License version 2.1 as published by the Free Software Foundation
00009  * (the "LGPL") or, at your option, under the terms of the Mozilla
00010  * Public License Version 1.1 (the "MPL"). If you do not alter this
00011  * notice, a recipient may use your version of this file under either
00012  * the MPL or the LGPL.
00013  *
00014  * You should have received a copy of the LGPL along with this library
00015  * in the file COPYING-LGPL-2.1; if not, write to the Free Software
00016  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
00017  * You should have received a copy of the MPL along with this library
00018  * in the file COPYING-MPL-1.1
00019  *
00020  * The contents of this file are subject to the Mozilla Public License
00021  * Version 1.1 (the "License"); you may not use this file except in
00022  * compliance with the License. You may obtain a copy of the License at
00023  * http://www.mozilla.org/MPL/
00024  *
00025  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
00026  * OF ANY KIND, either express or implied. See the LGPL or the MPL for
00027  * the specific language governing rights and limitations.
00028  *
00029  * The Original Code is the cairo graphics library.
00030  *
00031  * The Initial Developer of the Original Code is University of Southern
00032  * California.
00033  *
00034  * Contributor(s):
00035  *     Carl D. Worth <cworth@cworth.org>
00036  */
00037 
00038 #include <stdlib.h>
00039 #include "cairoint.h"
00040 
00041 #include "cairo-path-fixed-private.h"
00042 
00043 /* private functions */
00044 static cairo_status_t
00045 _cairo_path_fixed_add (cairo_path_fixed_t *path,
00046                      cairo_path_op_t         op,
00047                      cairo_point_t   *points,
00048                      int              num_points);
00049 
00050 static void
00051 _cairo_path_fixed_add_op_buf (cairo_path_fixed_t  *path,
00052                            cairo_path_op_buf_t *op_buf);
00053 
00054 static void
00055 _cairo_path_fixed_add_arg_buf (cairo_path_fixed_t   *path,
00056                             cairo_path_arg_buf_t *arg_buf);
00057 
00058 static cairo_path_op_buf_t *
00059 _cairo_path_op_buf_create (void);
00060 
00061 static void
00062 _cairo_path_op_buf_destroy (cairo_path_op_buf_t *op_buf);
00063 
00064 static void
00065 _cairo_path_op_buf_add_op (cairo_path_op_buf_t *op_buf,
00066                         cairo_path_op_t      op);
00067 
00068 static cairo_path_arg_buf_t *
00069 _cairo_path_arg_buf_create (void);
00070 
00071 static void
00072 _cairo_path_arg_buf_destroy (cairo_path_arg_buf_t *arg_buf);
00073 
00074 static void
00075 _cairo_path_arg_buf_add_points (cairo_path_arg_buf_t *arg_buf,
00076                             cairo_point_t      *points,
00077                             int                 num_points);
00078 
00079 void
00080 _cairo_path_fixed_init (cairo_path_fixed_t *path)
00081 {
00082     path->op_buf_head = NULL;
00083     path->op_buf_tail = NULL;
00084 
00085     path->arg_buf_head = NULL;
00086     path->arg_buf_tail = NULL;
00087 
00088     path->current_point.x = 0;
00089     path->current_point.y = 0;
00090     path->has_current_point = 0;
00091     path->last_move_point = path->current_point;
00092 }
00093 
00094 cairo_status_t
00095 _cairo_path_fixed_init_copy (cairo_path_fixed_t *path,
00096                           cairo_path_fixed_t *other)
00097 {
00098     cairo_path_op_buf_t *op_buf, *other_op_buf;
00099     cairo_path_arg_buf_t *arg_buf, *other_arg_buf;
00100 
00101     _cairo_path_fixed_init (path);
00102     path->current_point = other->current_point;
00103     path->has_current_point = other->has_current_point;
00104     path->last_move_point = other->last_move_point;
00105 
00106     for (other_op_buf = other->op_buf_head;
00107         other_op_buf;
00108         other_op_buf = other_op_buf->next)
00109     {
00110        op_buf = _cairo_path_op_buf_create ();
00111        if (op_buf == NULL) {
00112            _cairo_path_fixed_fini (path);
00113            return CAIRO_STATUS_NO_MEMORY;
00114        }
00115        memcpy (op_buf, other_op_buf, sizeof (cairo_path_op_buf_t));
00116        _cairo_path_fixed_add_op_buf (path, op_buf);
00117     }
00118 
00119     for (other_arg_buf = other->arg_buf_head;
00120         other_arg_buf;
00121         other_arg_buf = other_arg_buf->next)
00122     {
00123        arg_buf = _cairo_path_arg_buf_create ();
00124        if (arg_buf == NULL) {
00125            _cairo_path_fixed_fini (path);
00126            return CAIRO_STATUS_NO_MEMORY;
00127        }
00128        memcpy (arg_buf, other_arg_buf, sizeof (cairo_path_arg_buf_t));
00129        _cairo_path_fixed_add_arg_buf (path, arg_buf);
00130     }
00131 
00132     return CAIRO_STATUS_SUCCESS;
00133 }
00134 
00135 void
00136 _cairo_path_fixed_fini (cairo_path_fixed_t *path)
00137 {
00138     cairo_path_op_buf_t *op_buf;
00139     cairo_path_arg_buf_t *arg_buf;
00140 
00141     while (path->op_buf_head) {
00142        op_buf = path->op_buf_head;
00143        path->op_buf_head = op_buf->next;
00144        _cairo_path_op_buf_destroy (op_buf);
00145     }
00146     path->op_buf_tail = NULL;
00147 
00148     while (path->arg_buf_head) {
00149        arg_buf = path->arg_buf_head;
00150        path->arg_buf_head = arg_buf->next;
00151        _cairo_path_arg_buf_destroy (arg_buf);
00152     }
00153     path->arg_buf_tail = NULL;
00154 
00155     path->has_current_point = 0;
00156 }
00157 
00158 cairo_status_t
00159 _cairo_path_fixed_move_to (cairo_path_fixed_t  *path,
00160                         cairo_fixed_t     x,
00161                         cairo_fixed_t     y)
00162 {
00163     cairo_status_t status;
00164     cairo_point_t point;
00165 
00166     point.x = x;
00167     point.y = y;
00168 
00169     status = _cairo_path_fixed_add (path, CAIRO_PATH_OP_MOVE_TO, &point, 1);
00170     if (status)
00171        return status;
00172 
00173     path->current_point = point;
00174     path->has_current_point = 1;
00175     path->last_move_point = path->current_point;
00176 
00177     return CAIRO_STATUS_SUCCESS;
00178 }
00179 
00180 cairo_status_t
00181 _cairo_path_fixed_rel_move_to (cairo_path_fixed_t *path,
00182                             cairo_fixed_t    dx,
00183                             cairo_fixed_t    dy)
00184 {
00185     cairo_fixed_t x, y;
00186 
00187     if (!path->has_current_point)
00188        return CAIRO_STATUS_NO_CURRENT_POINT;
00189 
00190     x = path->current_point.x + dx;
00191     y = path->current_point.y + dy;
00192 
00193     return _cairo_path_fixed_move_to (path, x, y);
00194 }
00195 
00196 cairo_status_t
00197 _cairo_path_fixed_line_to (cairo_path_fixed_t *path,
00198                         cairo_fixed_t     x,
00199                         cairo_fixed_t     y)
00200 {
00201     cairo_status_t status;
00202     cairo_point_t point;
00203 
00204     point.x = x;
00205     point.y = y;
00206 
00207     status = _cairo_path_fixed_add (path, CAIRO_PATH_OP_LINE_TO, &point, 1);
00208     if (status)
00209        return status;
00210 
00211     path->current_point = point;
00212     path->has_current_point = 1;
00213 
00214     return CAIRO_STATUS_SUCCESS;
00215 }
00216 
00217 cairo_status_t
00218 _cairo_path_fixed_rel_line_to (cairo_path_fixed_t *path,
00219                             cairo_fixed_t    dx,
00220                             cairo_fixed_t    dy)
00221 {
00222     cairo_fixed_t x, y;
00223 
00224     if (!path->has_current_point)
00225        return CAIRO_STATUS_NO_CURRENT_POINT;
00226 
00227     x = path->current_point.x + dx;
00228     y = path->current_point.y + dy;
00229 
00230     return _cairo_path_fixed_line_to (path, x, y);
00231 }
00232 
00233 cairo_status_t
00234 _cairo_path_fixed_curve_to (cairo_path_fixed_t   *path,
00235                          cairo_fixed_t x0, cairo_fixed_t y0,
00236                          cairo_fixed_t x1, cairo_fixed_t y1,
00237                          cairo_fixed_t x2, cairo_fixed_t y2)
00238 {
00239     cairo_status_t status;
00240     cairo_point_t point[3];
00241 
00242     point[0].x = x0; point[0].y = y0;
00243     point[1].x = x1; point[1].y = y1;
00244     point[2].x = x2; point[2].y = y2;
00245 
00246     status = _cairo_path_fixed_add (path, CAIRO_PATH_OP_CURVE_TO, point, 3);
00247     if (status)
00248        return status;
00249 
00250     path->current_point = point[2];
00251     path->has_current_point = 1;
00252 
00253     return CAIRO_STATUS_SUCCESS;
00254 }
00255 
00256 cairo_status_t
00257 _cairo_path_fixed_rel_curve_to (cairo_path_fixed_t *path,
00258                             cairo_fixed_t dx0, cairo_fixed_t dy0,
00259                             cairo_fixed_t dx1, cairo_fixed_t dy1,
00260                             cairo_fixed_t dx2, cairo_fixed_t dy2)
00261 {
00262     cairo_fixed_t x0, y0;
00263     cairo_fixed_t x1, y1;
00264     cairo_fixed_t x2, y2;
00265 
00266     if (!path->has_current_point)
00267        return CAIRO_STATUS_NO_CURRENT_POINT;
00268 
00269     x0 = path->current_point.x + dx0;
00270     y0 = path->current_point.y + dy0;
00271 
00272     x1 = path->current_point.x + dx1;
00273     y1 = path->current_point.y + dy1;
00274 
00275     x2 = path->current_point.x + dx2;
00276     y2 = path->current_point.y + dy2;
00277 
00278     return _cairo_path_fixed_curve_to (path,
00279                                    x0, y0,
00280                                    x1, y1,
00281                                    x2, y2);
00282 }
00283 
00284 cairo_status_t
00285 _cairo_path_fixed_close_path (cairo_path_fixed_t *path)
00286 {
00287     cairo_status_t status;
00288 
00289     status = _cairo_path_fixed_add (path, CAIRO_PATH_OP_CLOSE_PATH, NULL, 0);
00290     if (status)
00291        return status;
00292 
00293     path->current_point.x = path->last_move_point.x;
00294     path->current_point.y = path->last_move_point.y;
00295     path->has_current_point = 1;
00296 
00297     return CAIRO_STATUS_SUCCESS;
00298 }
00299 
00300 cairo_status_t
00301 _cairo_path_fixed_get_current_point (cairo_path_fixed_t *path,
00302                                  cairo_fixed_t   *x,
00303                                  cairo_fixed_t   *y)
00304 {
00305     if (! path->has_current_point)
00306        return CAIRO_STATUS_NO_CURRENT_POINT;
00307 
00308     *x = path->current_point.x;
00309     *y = path->current_point.y;
00310 
00311     return CAIRO_STATUS_SUCCESS;
00312 }
00313 
00314 static cairo_status_t
00315 _cairo_path_fixed_add (cairo_path_fixed_t *path,
00316                      cairo_path_op_t         op,
00317                      cairo_point_t   *points,
00318                      int              num_points)
00319 {
00320     if (path->op_buf_tail == NULL ||
00321        path->op_buf_tail->num_ops + 1 > CAIRO_PATH_BUF_SIZE)
00322     {
00323        cairo_path_op_buf_t *op_buf;
00324 
00325        op_buf = _cairo_path_op_buf_create ();
00326        if (op_buf == NULL)
00327            return CAIRO_STATUS_NO_MEMORY;
00328 
00329        _cairo_path_fixed_add_op_buf (path, op_buf);
00330     }
00331 
00332     _cairo_path_op_buf_add_op (path->op_buf_tail, op);
00333 
00334     if (path->arg_buf_tail == NULL ||
00335        path->arg_buf_tail->num_points + num_points > CAIRO_PATH_BUF_SIZE)
00336     {
00337        cairo_path_arg_buf_t *arg_buf;
00338 
00339        arg_buf = _cairo_path_arg_buf_create ();
00340 
00341        if (arg_buf == NULL)
00342            return CAIRO_STATUS_NO_MEMORY;
00343 
00344        _cairo_path_fixed_add_arg_buf (path, arg_buf);
00345     }
00346 
00347     _cairo_path_arg_buf_add_points (path->arg_buf_tail, points, num_points);
00348 
00349     return CAIRO_STATUS_SUCCESS;
00350 }
00351 
00352 static void
00353 _cairo_path_fixed_add_op_buf (cairo_path_fixed_t  *path,
00354                            cairo_path_op_buf_t *op_buf)
00355 {
00356     op_buf->next = NULL;
00357     op_buf->prev = path->op_buf_tail;
00358 
00359     if (path->op_buf_tail) {
00360        path->op_buf_tail->next = op_buf;
00361     } else {
00362        path->op_buf_head = op_buf;
00363     }
00364 
00365     path->op_buf_tail = op_buf;
00366 }
00367 
00368 static void
00369 _cairo_path_fixed_add_arg_buf (cairo_path_fixed_t   *path,
00370                             cairo_path_arg_buf_t *arg_buf)
00371 {
00372     arg_buf->next = NULL;
00373     arg_buf->prev = path->arg_buf_tail;
00374 
00375     if (path->arg_buf_tail) {
00376        path->arg_buf_tail->next = arg_buf;
00377     } else {
00378        path->arg_buf_head = arg_buf;
00379     }
00380 
00381     path->arg_buf_tail = arg_buf;
00382 }
00383 
00384 static cairo_path_op_buf_t *
00385 _cairo_path_op_buf_create (void)
00386 {
00387     cairo_path_op_buf_t *op_buf;
00388 
00389     op_buf = malloc (sizeof (cairo_path_op_buf_t));
00390 
00391     if (op_buf) {
00392        op_buf->num_ops = 0;
00393        op_buf->next = NULL;
00394     }
00395 
00396     return op_buf;
00397 }
00398 
00399 static void
00400 _cairo_path_op_buf_destroy (cairo_path_op_buf_t *op_buf)
00401 {
00402     free (op_buf);
00403 }
00404 
00405 static void
00406 _cairo_path_op_buf_add_op (cairo_path_op_buf_t *op_buf,
00407                         cairo_path_op_t   op)
00408 {
00409     op_buf->op[op_buf->num_ops++] = op;
00410 }
00411 
00412 static cairo_path_arg_buf_t *
00413 _cairo_path_arg_buf_create (void)
00414 {
00415     cairo_path_arg_buf_t *arg_buf;
00416 
00417     arg_buf = malloc (sizeof (cairo_path_arg_buf_t));
00418 
00419     if (arg_buf) {
00420        arg_buf->num_points = 0;
00421        arg_buf->next = NULL;
00422     }
00423 
00424     return arg_buf;
00425 }
00426 
00427 static void
00428 _cairo_path_arg_buf_destroy (cairo_path_arg_buf_t *arg_buf)
00429 {
00430     free (arg_buf);
00431 }
00432 
00433 static void
00434 _cairo_path_arg_buf_add_points (cairo_path_arg_buf_t *arg_buf,
00435                             cairo_point_t      *points,
00436                             int                 num_points)
00437 {
00438     int i;
00439 
00440     for (i=0; i < num_points; i++) {
00441        arg_buf->points[arg_buf->num_points++] = points[i];
00442     }
00443 }
00444 
00445 #define CAIRO_PATH_OP_MAX_ARGS 3
00446 
00447 static int const num_args[] = 
00448 {
00449     1, /* cairo_path_move_to */
00450     1, /* cairo_path_op_line_to */
00451     3, /* cairo_path_op_curve_to */
00452     0, /* cairo_path_op_close_path */
00453 };
00454 
00455 cairo_status_t
00456 _cairo_path_fixed_interpret (cairo_path_fixed_t                *path,
00457                           cairo_direction_t                     dir,
00458                           cairo_path_fixed_move_to_func_t      *move_to,
00459                           cairo_path_fixed_line_to_func_t      *line_to,
00460                           cairo_path_fixed_curve_to_func_t     *curve_to,
00461                           cairo_path_fixed_close_path_func_t   *close_path,
00462                           void                          *closure)
00463 {
00464     cairo_status_t status;
00465     int i, arg;
00466     cairo_path_op_buf_t *op_buf;
00467     cairo_path_op_t op;
00468     cairo_path_arg_buf_t *arg_buf = path->arg_buf_head;
00469     int buf_i = 0;
00470     cairo_point_t point[CAIRO_PATH_OP_MAX_ARGS];
00471     cairo_bool_t forward = (dir == CAIRO_DIRECTION_FORWARD);
00472     int step = forward ? 1 : -1;
00473 
00474     for (op_buf = forward ? path->op_buf_head : path->op_buf_tail;
00475         op_buf;
00476         op_buf = forward ? op_buf->next : op_buf->prev)
00477     {
00478        int start, stop;
00479        if (forward) {
00480            start = 0;
00481            stop = op_buf->num_ops;
00482        } else {
00483            start = op_buf->num_ops - 1;
00484            stop = -1;
00485        }
00486 
00487        for (i=start; i != stop; i += step) {
00488            op = op_buf->op[i];
00489 
00490            if (! forward) {
00491               if (buf_i == 0) {
00492                   arg_buf = arg_buf->prev;
00493                   buf_i = arg_buf->num_points;
00494               }
00495               buf_i -= num_args[op];
00496            }
00497 
00498            for (arg = 0; arg < num_args[op]; arg++) {
00499               point[arg] = arg_buf->points[buf_i];
00500               buf_i++;
00501               if (buf_i >= arg_buf->num_points) {
00502                   arg_buf = arg_buf->next;
00503                   buf_i = 0;
00504               }
00505            }
00506 
00507            if (! forward) {
00508               buf_i -= num_args[op];
00509            }
00510 
00511            switch (op) {
00512            case CAIRO_PATH_OP_MOVE_TO:
00513               status = (*move_to) (closure, &point[0]);
00514               break;
00515            case CAIRO_PATH_OP_LINE_TO:
00516               status = (*line_to) (closure, &point[0]);
00517               break;
00518            case CAIRO_PATH_OP_CURVE_TO:
00519               status = (*curve_to) (closure, &point[0], &point[1], &point[2]);
00520               break;
00521            case CAIRO_PATH_OP_CLOSE_PATH:
00522            default:
00523               status = (*close_path) (closure);
00524               break;
00525            }
00526            if (status)
00527               return status;
00528        }
00529     }
00530 
00531     return CAIRO_STATUS_SUCCESS;
00532 }