svg-path.cpp revision b4501ad5a552f01e37c9b4ada286e0c5508387bd
#define __SP_SVG_PARSE_C__
/*
svg-path.c: Parse SVG path element data into bezier path.
Copyright (C) 2000 Eazel, Inc.
Copyright (C) 2000 Lauris Kaplinski
Copyright (C) 2001 Ximian, Inc.
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.
Authors:
Raph Levien <raph@artofcode.com>
Lauris Kaplinski <lauris@ximian.com>
*/
#include <cstring>
#include <string>
#include <cassert>
#include <glib/gmessages.h>
#include <glib/gstrfuncs.h>
#include <glib.h> // g_assert()
#include "libnr/n-art-bpath.h"
#include "gnome-canvas-bpath-util.h"
#include "svg/path-string.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 */
/* We are lazy ;-) (Lauris) */
struct RSVGParsePathCtx {
char cmd; /* current command (lowercase) */
int param; /* parameter number */
bool rel; /* true if relative coords */
};
{
double t;
double th_half;
/* inverse transform compared with rsvg_path_arc */
}
/**
* 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.
*
**/
int large_arc_flag, int sweep_flag,
double x, double y)
{
double d, sfactor, sfactor_sq;
int i, n_segs;
/*
Correction of out-of-range radii as described in Appendix F.6.6:
1. Ensure radii are non-zero (Done?).
2. Ensure that radii are positive.
3. Ensure that radii are large enough.
*/
if(pl > 1.0)
{
}
/* Proceed with computations as described in Appendix F.6.5 */
/* (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.
*/
if (sfactor_sq < 0) sfactor_sq = 0;
/* (xc, yc) is center of the circle. */
if (th_arc < 0 && sweep_flag)
else if (th_arc > 0 && !sweep_flag)
for (i = 0; i < n_segs; i++) {
}
}
{
case 'm':
/* moveto */
{
#ifdef VERBOSE
g_print ("'m' moveto %g,%g\n",
#endif
/* Ref: http://www.w3.org/TR/SVG11/paths.html#PathDataMovetoCommands: "If a moveto is
* followed by multiple pairs of coordinates, the subsequent pairs are treated as
* implicit lineto commands." */
}
break;
case 'l':
/* lineto */
{
#ifdef VERBOSE
g_print ("'l' lineto %g,%g\n",
#endif
}
break;
case 'c':
/* curveto */
{
#ifdef VERBOSE
g_print ("'c' curveto %g,%g %g,%g, %g,%g\n",
#endif
}
break;
case 's':
/* smooth curveto */
{
#ifdef VERBOSE
g_print ("'s' curveto %g,%g %g,%g, %g,%g\n",
#endif
}
break;
case 'h':
/* horizontal lineto */
#ifdef VERBOSE
g_print ("'h' lineto %g,%g\n",
#endif
}
break;
case 'v':
/* vertical lineto */
#ifdef VERBOSE
g_print ("'v' lineto %g,%g\n",
#endif
}
break;
case 'q':
/* quadratic bezier curveto */
/* non-normative reference:
*/
{
/* raise quadratic bezier to cubic */
#ifdef VERBOSE
g_print("'q' curveto %g,%g %g,%g, %g,%g\n",
#endif
}
break;
case 't':
/* Truetype quadratic bezier curveto */
/* generate a quadratic bezier with control point = xc, yc */
#ifdef VERBOSE
g_print ("'t' curveto %g,%g %g,%g, %g,%g\n",
#endif
}
break;
case 'a':
{
}
break;
default:
}
}
{
// This makes sure we do the right moveto if the closepath is followed by anything other than a moveto.
/* Ref: http://www.w3.org/TR/SVG11/paths.html#PathDataClosePathCommand: "If a
* "closepath" is followed immediately by a "moveto", then the "moveto" identifies
* the start point of the next subpath. If a "closepath" is followed immediately by
* any other command, then the next subpath starts at the same initial point as the
* current subpath." */
/* Any token after a closepath must be a command, not a parameter. We enforce this
* by clearing cmd rather than leaving as 'm'. */
}
}
*val *= 10;
begin++;
}
return begin;
}
*neg = false;
if (*begin == '+') {
begin++;
} else if (*begin == '-') {
*neg = true;
begin++;
}
return begin;
}
bool neg;
}
// A number is either one or more digits, optionally followed by a period and zero or more digits (and an exponent),
// or zero or more digits, followed by a period and one or more digits (and an exponent)
// See http://www.w3.org/TR/SVG/paths.html#PathDataBNF
int exp=0;
char const *begin_of_num = begin;
if (*end_of_num == '.') {
}
}
if (end_of_exp != begin_of_exp) {
}
}
return end_of_num;
}
bool neg;
}
/* fixme: Do better error processing: e.g. at least stop parsing as soon as we find an error.
* At some point we'll need to do all of
* http://www.w3.org/TR/SVG11/implnote.html#ErrorProcessing.
*/
/* Comma is always allowed after a number token (so long as it's followed by another number:
* see require_number), and never allowed anywhere else. Only one comma is allowed between
* neighbouring number tokens. */
bool comma_allowed = false;
/* After a command other than closepath, and after a comma, we require a number. */
bool require_number = false;
int const c = *cur;
if (c <= ' ') {
switch (c) {
case ' ':
case '\t':
case '\n':
case '\r':
/* wsp */
break;
case '\0':
goto error;
}
goto done;
default:
goto error;
}
} else if (c == ',') {
if (!comma_allowed) {
goto error;
}
comma_allowed = false;
require_number = true;
} else if (c <= '9') {
goto error;
}
double val;
goto error;
}
/* Special requirements for elliptical-arc arguments. */
if (c <= '-') {
/* Error: sign not allowed for first two params. */
goto error;
}
/* Error: flag must be either literally "0" or literally "1". */
goto error;
}
}
}
/* Handle relative coordinates. */
case 'l':
case 'm':
case 'c':
case 's':
case 'q':
case 't':
} else {
}
break;
case 'a':
/* rule: sixth and seventh are x and y, rest are not
relative */
break;
case 'h':
/* rule: x-relative */
break;
case 'v':
/* rule: y-relative */
break;
}
}
comma_allowed = true;
require_number = false;
} else {
/* Command. */
goto error;
}
char next_cmd;
if (c <= 'Z') {
} else {
next_cmd = c;
}
comma_allowed = false;
require_number = true;
switch (next_cmd) {
case 'z':
require_number = false;
case 'm':
case 'l':
case 'h':
case 'v':
case 'c':
case 's':
case 'q':
case 't':
case 'a':
/* valid command */
break;
default:
goto error;
}
/* Closepath is the only command that allows no arguments. */
}
}
}
done:
}
return;
/* todo: set an error indicator. */
goto done;
}
{
return bpath;
}
{
if (!str)
return pathv; // return empty pathvector when str == NULL
try {
}
catch (Geom::SVGPathParseError e) {
}
return pathv;
}
{
bool closed=false;
case NR_LINETO:
}
break;
case NR_CURVETO:
break;
case NR_MOVETO_OPEN:
case NR_MOVETO:
if (closed) {
}
break;
default:
}
}
if (closed) {
}
}
}
else if(Geom::QuadraticBezier const *quadratic_bezier = dynamic_cast<Geom::QuadraticBezier const *>(c)) {
}
}
else if(Geom::EllipticalArc const *svg_elliptical_arc = dynamic_cast<Geom::EllipticalArc const *>(c)) {
svg_elliptical_arc->finalPoint() );
/* else if(Geom::HLineSegment const *hline_segment = dynamic_cast<Geom::HLineSegment const *>(c)) {
str.horizontalLineTo( ... );
}
else if(Geom::VLineSegment const *vline_segment = dynamic_cast<Geom::VLineSegment const *>(c)) {
str.verticalLineTo( ... ); */
} else {
//this case handles sbasis as well as all other curve types
//recurse to convert the new path resulting from the sbasis to svgd
}
}
}
}
}
}
}
/*
Local Variables:
mode:c++
c-file-style:"stroustrup"
c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
indent-tabs-mode:nil
fill-column:99
End:
*/
// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :