diff options
Diffstat (limited to 'librsvg/rsvg-path.c')
-rw-r--r-- | librsvg/rsvg-path.c | 609 |
1 files changed, 0 insertions, 609 deletions
diff --git a/librsvg/rsvg-path.c b/librsvg/rsvg-path.c deleted file mode 100644 index deb8d639b..000000000 --- a/librsvg/rsvg-path.c +++ /dev/null @@ -1,609 +0,0 @@ -/* - rsvg-path.c: Parse SVG path element data into bezier path. - - Copyright (C) 2000 Eazel, Inc. - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public - License along with this program; if not, write to the - Free Software Foundation, Inc., 59 Temple Place - Suite 330, - Boston, MA 02111-1307, USA. - - Author: Raph Levien <raph@artofcode.com> -*/ - -/* This is adapted from svg-path in Gill. */ - -#include <string.h> -#include <stdlib.h> -#include <math.h> - -#include <glib.h> - -#include "rsvg-bpath-util.h" -#include "rsvg-path.h" - -/* This module parses an SVG path element into an RsvgBpathDef. - - At present, there is no support for <marker> or any other contextual - information from the SVG file. The API will need to change rather - significantly to support these. - - Reference: SVG working draft 3 March 2000, section 8. -*/ - -#ifndef M_PI -#define M_PI 3.14159265358979323846 -#endif /* M_PI */ - -typedef struct _RSVGParsePathCtx RSVGParsePathCtx; - -struct _RSVGParsePathCtx { - RsvgBpathDef *bpath; - double cpx, cpy; /* current point */ - double rpx, rpy; /* reflection point (for 's' and 't' commands) */ - char cmd; /* current command (lowercase) */ - int param; /* parameter number */ - gboolean rel; /* true if relative coords */ - double params[7]; /* parameters that have been parsed */ -}; - -static void -rsvg_path_arc_segment (RSVGParsePathCtx *ctx, - double xc, double yc, - double th0, double th1, - double rx, double ry, double x_axis_rotation) -{ - double sin_th, cos_th; - double a00, a01, a10, a11; - double x1, y1, x2, y2, x3, y3; - double t; - double th_half; - - sin_th = sin (x_axis_rotation * (M_PI / 180.0)); - cos_th = cos (x_axis_rotation * (M_PI / 180.0)); - /* inverse transform compared with rsvg_path_arc */ - a00 = cos_th * rx; - a01 = -sin_th * ry; - a10 = sin_th * rx; - a11 = cos_th * ry; - - th_half = 0.5 * (th1 - th0); - t = (8.0 / 3.0) * sin (th_half * 0.5) * sin (th_half * 0.5) / sin (th_half); - x1 = xc + cos (th0) - t * sin (th0); - y1 = yc + sin (th0) + t * cos (th0); - x3 = xc + cos (th1); - y3 = yc + sin (th1); - x2 = x3 + t * sin (th1); - y2 = y3 - t * cos (th1); - rsvg_bpath_def_curveto (ctx->bpath, - a00 * x1 + a01 * y1, a10 * x1 + a11 * y1, - a00 * x2 + a01 * y2, a10 * x2 + a11 * y2, - a00 * x3 + a01 * y3, a10 * x3 + a11 * y3); -} - -/** - * rsvg_path_arc: Add an RSVG arc to the path context. - * @ctx: Path context. - * @rx: Radius in x direction (before rotation). - * @ry: Radius in y direction (before rotation). - * @x_axis_rotation: Rotation angle for axes. - * @large_arc_flag: 0 for arc length <= 180, 1 for arc >= 180. - * @sweep: 0 for "negative angle", 1 for "positive angle". - * @x: New x coordinate. - * @y: New y coordinate. - * - **/ -static void -rsvg_path_arc (RSVGParsePathCtx *ctx, - double rx, double ry, double x_axis_rotation, - int large_arc_flag, int sweep_flag, - double x, double y) -{ - double sin_th, cos_th; - double a00, a01, a10, a11; - double x0, y0, x1, y1, xc, yc; - double d, sfactor, sfactor_sq; - double th0, th1, th_arc; - int i, n_segs; - - sin_th = sin (x_axis_rotation * (M_PI / 180.0)); - cos_th = cos (x_axis_rotation * (M_PI / 180.0)); - a00 = cos_th / rx; - a01 = sin_th / rx; - a10 = -sin_th / ry; - a11 = cos_th / ry; - x0 = a00 * ctx->cpx + a01 * ctx->cpy; - y0 = a10 * ctx->cpx + a11 * ctx->cpy; - x1 = a00 * x + a01 * y; - y1 = a10 * x + a11 * y; - /* (x0, y0) is current point in transformed coordinate space. - (x1, y1) is new point in transformed coordinate space. - - The arc fits a unit-radius circle in this space. - */ - d = (x1 - x0) * (x1 - x0) + (y1 - y0) * (y1 - y0); - sfactor_sq = 1.0 / d - 0.25; - if (sfactor_sq < 0) sfactor_sq = 0; - sfactor = sqrt (sfactor_sq); - if (sweep_flag == large_arc_flag) sfactor = -sfactor; - xc = 0.5 * (x0 + x1) - sfactor * (y1 - y0); - yc = 0.5 * (y0 + y1) + sfactor * (x1 - x0); - /* (xc, yc) is center of the circle. */ - - th0 = atan2 (y0 - yc, x0 - xc); - th1 = atan2 (y1 - yc, x1 - xc); - - th_arc = th1 - th0; - if (th_arc < 0 && sweep_flag) - th_arc += 2 * M_PI; - else if (th_arc > 0 && !sweep_flag) - th_arc -= 2 * M_PI; - - n_segs = ceil (fabs (th_arc / (M_PI * 0.5 + 0.001))); - - for (i = 0; i < n_segs; i++) - rsvg_path_arc_segment (ctx, xc, yc, - th0 + i * th_arc / n_segs, - th0 + (i + 1) * th_arc / n_segs, - rx, ry, x_axis_rotation); - - ctx->cpx = x; - ctx->cpy = y; -} - - -/* supply defaults for missing parameters, assuming relative coordinates - are to be interpreted as x,y */ -static void -rsvg_parse_path_default_xy (RSVGParsePathCtx *ctx, int n_params) -{ - int i; - - if (ctx->rel) - { - for (i = ctx->param; i < n_params; i++) - { - if (i > 2) - ctx->params[i] = ctx->params[i - 2]; - else if (i == 1) - ctx->params[i] = ctx->cpy; - else if (i == 0) - /* we shouldn't get here (usually ctx->param > 0 as - precondition) */ - ctx->params[i] = ctx->cpx; - } - } - else - { - for (i = ctx->param; i < n_params; i++) - ctx->params[i] = 0.0; - } -} - -static void -rsvg_parse_path_do_cmd (RSVGParsePathCtx *ctx, gboolean final) -{ - double x1, y1, x2, y2, x3, y3; - -#ifdef VERBOSE - int i; - - g_print ("parse_path %c:", ctx->cmd); - for (i = 0; i < ctx->param; i++) - g_print (" %f", ctx->params[i]); - g_print (final ? ".\n" : "\n"); -#endif - - switch (ctx->cmd) - { - case 'm': - /* moveto */ - if (ctx->param == 2 || final) - { - rsvg_parse_path_default_xy (ctx, 2); -#ifdef VERBOSE - g_print ("'m' moveto %g,%g\n", - ctx->params[0], ctx->params[1]); -#endif - rsvg_bpath_def_moveto (ctx->bpath, - ctx->params[0], ctx->params[1]); - ctx->cpx = ctx->rpx = ctx->params[0]; - ctx->cpy = ctx->rpy = ctx->params[1]; - ctx->param = 0; - } - break; - case 'l': - /* lineto */ - if (ctx->param == 2 || final) - { - rsvg_parse_path_default_xy (ctx, 2); -#ifdef VERBOSE - g_print ("'l' lineto %g,%g\n", - ctx->params[0], ctx->params[1]); -#endif - rsvg_bpath_def_lineto (ctx->bpath, - ctx->params[0], ctx->params[1]); - ctx->cpx = ctx->rpx = ctx->params[0]; - ctx->cpy = ctx->rpy = ctx->params[1]; - ctx->param = 0; - } - break; - case 'c': - /* curveto */ - if (ctx->param == 6 || final) - { - rsvg_parse_path_default_xy (ctx, 6); - x1 = ctx->params[0]; - y1 = ctx->params[1]; - x2 = ctx->params[2]; - y2 = ctx->params[3]; - x3 = ctx->params[4]; - y3 = ctx->params[5]; -#ifdef VERBOSE - g_print ("'c' curveto %g,%g %g,%g, %g,%g\n", - x1, y1, x2, y2, x3, y3); -#endif - rsvg_bpath_def_curveto (ctx->bpath, - x1, y1, x2, y2, x3, y3); - ctx->rpx = x2; - ctx->rpy = y2; - ctx->cpx = x3; - ctx->cpy = y3; - ctx->param = 0; - } - break; - case 's': - /* smooth curveto */ - if (ctx->param == 4 || final) - { - rsvg_parse_path_default_xy (ctx, 4); - x1 = 2 * ctx->cpx - ctx->rpx; - y1 = 2 * ctx->cpy - ctx->rpy; - x2 = ctx->params[0]; - y2 = ctx->params[1]; - x3 = ctx->params[2]; - y3 = ctx->params[3]; -#ifdef VERBOSE - g_print ("'s' curveto %g,%g %g,%g, %g,%g\n", - x1, y1, x2, y2, x3, y3); -#endif - rsvg_bpath_def_curveto (ctx->bpath, - x1, y1, x2, y2, x3, y3); - ctx->rpx = x2; - ctx->rpy = y2; - ctx->cpx = x3; - ctx->cpy = y3; - ctx->param = 0; - } - break; - case 'h': - /* horizontal lineto */ - if (ctx->param == 1) - { -#ifdef VERBOSE - g_print ("'h' lineto %g,%g\n", - ctx->params[0], ctx->cpy); -#endif - rsvg_bpath_def_lineto (ctx->bpath, - ctx->params[0], ctx->cpy); - ctx->cpx = ctx->rpx = ctx->params[0]; - ctx->param = 0; - } - break; - case 'v': - /* vertical lineto */ - if (ctx->param == 1) - { -#ifdef VERBOSE - g_print ("'v' lineto %g,%g\n", - ctx->cpx, ctx->params[0]); -#endif - rsvg_bpath_def_lineto (ctx->bpath, - ctx->cpx, ctx->params[0]); - ctx->cpy = ctx->rpy = ctx->params[0]; - ctx->param = 0; - } - break; - case 'q': - /* quadratic bezier curveto */ - - /* non-normative reference: - http://www.icce.rug.nl/erikjan/bluefuzz/beziers/beziers/beziers.html - */ - if (ctx->param == 4 || final) - { - rsvg_parse_path_default_xy (ctx, 4); - /* raise quadratic bezier to cubic */ - x1 = (ctx->cpx + 2 * ctx->params[0]) * (1.0 / 3.0); - y1 = (ctx->cpy + 2 * ctx->params[1]) * (1.0 / 3.0); - x3 = ctx->params[2]; - y3 = ctx->params[3]; - x2 = (x3 + 2 * ctx->params[0]) * (1.0 / 3.0); - y2 = (y3 + 2 * ctx->params[1]) * (1.0 / 3.0); -#ifdef VERBOSE - g_print ("'q' curveto %g,%g %g,%g, %g,%g\n", - x1, y1, x2, y2, x3, y3); -#endif - rsvg_bpath_def_curveto (ctx->bpath, - x1, y1, x2, y2, x3, y3); - ctx->rpx = x2; - ctx->rpy = y2; - ctx->cpx = x3; - ctx->cpy = y3; - ctx->param = 0; - } - break; - case 't': - /* Truetype quadratic bezier curveto */ - if (ctx->param == 2 || final) - { - double xc, yc; /* quadratic control point */ - - xc = 2 * ctx->cpx - ctx->rpx; - yc = 2 * ctx->cpy - ctx->rpy; - /* generate a quadratic bezier with control point = xc, yc */ - x1 = (ctx->cpx + 2 * xc) * (1.0 / 3.0); - y1 = (ctx->cpy + 2 * yc) * (1.0 / 3.0); - x3 = ctx->params[0]; - y3 = ctx->params[1]; - x2 = (x3 + 2 * xc) * (1.0 / 3.0); - y2 = (y3 + 2 * yc) * (1.0 / 3.0); -#ifdef VERBOSE - g_print ("'t' curveto %g,%g %g,%g, %g,%g\n", - x1, y1, x2, y2, x3, y3); -#endif - rsvg_bpath_def_curveto (ctx->bpath, - x1, y1, x2, y2, x3, y3); - ctx->rpx = xc; - ctx->rpy = yc; - ctx->cpx = x3; - ctx->cpy = y3; - ctx->param = 0; - } - else if (final) - { - if (ctx->param > 2) - { - rsvg_parse_path_default_xy (ctx, 4); - /* raise quadratic bezier to cubic */ - x1 = (ctx->cpx + 2 * ctx->params[0]) * (1.0 / 3.0); - y1 = (ctx->cpy + 2 * ctx->params[1]) * (1.0 / 3.0); - x3 = ctx->params[2]; - y3 = ctx->params[3]; - x2 = (x3 + 2 * ctx->params[0]) * (1.0 / 3.0); - y2 = (y3 + 2 * ctx->params[1]) * (1.0 / 3.0); -#ifdef VERBOSE - g_print ("'t' curveto %g,%g %g,%g, %g,%g\n", - x1, y1, x2, y2, x3, y3); -#endif - rsvg_bpath_def_curveto (ctx->bpath, - x1, y1, x2, y2, x3, y3); - ctx->rpx = x2; - ctx->rpy = y2; - ctx->cpx = x3; - ctx->cpy = y3; - } - else - { - rsvg_parse_path_default_xy (ctx, 2); -#ifdef VERBOSE - g_print ("'t' lineto %g,%g\n", - ctx->params[0], ctx->params[1]); -#endif - rsvg_bpath_def_lineto (ctx->bpath, - ctx->params[0], ctx->params[1]); - ctx->cpx = ctx->rpx = ctx->params[0]; - ctx->cpy = ctx->rpy = ctx->params[1]; - } - ctx->param = 0; - } - break; - case 'a': - if (ctx->param == 7 || final) - { - rsvg_path_arc (ctx, - ctx->params[0], ctx->params[1], ctx->params[2], - ctx->params[3], ctx->params[4], - ctx->params[5], ctx->params[6]); - ctx->param = 0; - } - break; - default: - ctx->param = 0; - } -} - -static void -rsvg_parse_path_data (RSVGParsePathCtx *ctx, const char *data) -{ - int i = 0; - double val = 0; - char c = 0; - gboolean in_num = FALSE; - gboolean in_frac = FALSE; - gboolean in_exp = FALSE; - gboolean exp_wait_sign = FALSE; - int sign = 0; - int exp = 0; - int exp_sign = 0; - double frac = 0.0; - - in_num = FALSE; - for (i = 0; ; i++) - { - c = data[i]; - if (c >= '0' && c <= '9') - { - /* digit */ - if (in_num) - { - if (in_exp) - { - exp = (exp * 10) + c - '0'; - exp_wait_sign = FALSE; - } - else if (in_frac) - val += (frac *= 0.1) * (c - '0'); - else - val = (val * 10) + c - '0'; - } - else - { - in_num = TRUE; - in_frac = FALSE; - in_exp = FALSE; - exp = 0; - exp_sign = 1; - exp_wait_sign = FALSE; - val = c - '0'; - sign = 1; - } - } - else if (c == '.') - { - if (!in_num) - { - in_num = TRUE; - val = 0; - } - in_frac = TRUE; - frac = 1; - } - else if ((c == 'E' || c == 'e') && in_num) - { - in_exp = TRUE; - exp_wait_sign = TRUE; - exp = 0; - exp_sign = 1; - } - else if ((c == '+' || c == '-') && in_exp) - { - exp_sign = c == '+' ? 1 : -1; - } - else if (in_num) - { - /* end of number */ - - val *= sign * pow (10, exp_sign * exp); - if (ctx->rel) - { - /* Handle relative coordinates. This switch statement attempts - to determine _what_ the coords are relative to. This is - underspecified in the 12 Apr working draft. */ - switch (ctx->cmd) - { - case 'l': - case 'm': - case 'c': - case 's': - case 'q': - case 't': -#ifndef RSVGV_RELATIVE - /* rule: even-numbered params are x-relative, odd-numbered - are y-relative */ - if ((ctx->param & 1) == 0) - val += ctx->cpx; - else if ((ctx->param & 1) == 1) - val += ctx->cpy; - break; -#else - /* rule: even-numbered params are x-relative, odd-numbered - are y-relative */ - if (ctx->param == 0 || (ctx->param % 2 ==0)) - val += ctx->cpx; - else - val += ctx->cpy; - break; -#endif - case 'a': - /* rule: sixth and seventh are x and y, rest are not - relative */ - if (ctx->param == 5) - val += ctx->cpx; - else if (ctx->param == 6) - val += ctx->cpy; - break; - case 'h': - /* rule: x-relative */ - val += ctx->cpx; - break; - case 'v': - /* rule: y-relative */ - val += ctx->cpy; - break; - } - } - ctx->params[ctx->param++] = val; - rsvg_parse_path_do_cmd (ctx, FALSE); - in_num = FALSE; - } - - if (c == '\0') - break; - else if ((c == '+' || c == '-') && !exp_wait_sign) - { - sign = c == '+' ? 1 : -1;; - val = 0; - in_num = TRUE; - in_frac = FALSE; - in_exp = FALSE; - exp = 0; - exp_sign = 1; - exp_wait_sign = FALSE; - } - else if (c == 'z' || c == 'Z') - { - if (ctx->param) - rsvg_parse_path_do_cmd (ctx, TRUE); -#ifdef VERBOSE - g_print ("'z' closepath\n"); -#endif - rsvg_bpath_def_closepath (ctx->bpath); - } - else if (c >= 'A' && c <= 'Z' && c != 'E') - { - if (ctx->param) - rsvg_parse_path_do_cmd (ctx, TRUE); - ctx->cmd = c + 'a' - 'A'; - ctx->rel = FALSE; - } - else if (c >= 'a' && c <= 'z' && c != 'e') - { - if (ctx->param) - rsvg_parse_path_do_cmd (ctx, TRUE); - ctx->cmd = c; - ctx->rel = TRUE; - } - /* else c _should_ be whitespace or , */ - } -} - -RsvgBpathDef * -rsvg_parse_path (const char *path_str) -{ - RSVGParsePathCtx ctx; - - ctx.bpath = rsvg_bpath_def_new (); - ctx.cpx = 0.0; - ctx.cpy = 0.0; - ctx.cmd = 0; - ctx.param = 0; - - rsvg_parse_path_data (&ctx, path_str); - - if (ctx.param) - rsvg_parse_path_do_cmd (&ctx, TRUE); - - return ctx.bpath; -} - |