| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | /** | ||
| 2 | * \file | ||
| 3 | * \brief parse SVG path specifications | ||
| 4 | * | ||
| 5 | * Copyright 2007 MenTaLguY <mental@rydia.net> | ||
| 6 | * Copyright 2007 Aaron Spike <aaron@ekips.org> | ||
| 7 | * | ||
| 8 | * This library is free software; you can redistribute it and/or | ||
| 9 | * modify it either under the terms of the GNU Lesser General Public | ||
| 10 | * License version 2.1 as published by the Free Software Foundation | ||
| 11 | * (the "LGPL") or, at your option, under the terms of the Mozilla | ||
| 12 | * Public License Version 1.1 (the "MPL"). If you do not alter this | ||
| 13 | * notice, a recipient may use your version of this file under either | ||
| 14 | * the MPL or the LGPL. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the LGPL along with this library | ||
| 17 | * in the file COPYING-LGPL-2.1; if not, write to the Free Software | ||
| 18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 19 | * You should have received a copy of the MPL along with this library | ||
| 20 | * in the file COPYING-MPL-1.1 | ||
| 21 | * | ||
| 22 | * The contents of this file are subject to the Mozilla Public License | ||
| 23 | * Version 1.1 (the "License"); you may not use this file except in | ||
| 24 | * compliance with the License. You may obtain a copy of the License at | ||
| 25 | * http://www.mozilla.org/MPL/ | ||
| 26 | * | ||
| 27 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY | ||
| 28 | * OF ANY KIND, either express or implied. See the LGPL or the MPL for | ||
| 29 | * the specific language governing rights and limitations. | ||
| 30 | * | ||
| 31 | */ | ||
| 32 | |||
| 33 | #include <cstdio> | ||
| 34 | #include <cmath> | ||
| 35 | #include <vector> | ||
| 36 | #include <glib.h> | ||
| 37 | |||
| 38 | #include <2geom/point.h> | ||
| 39 | #include <2geom/svg-path-parser.h> | ||
| 40 | #include <2geom/angle.h> | ||
| 41 | |||
| 42 | namespace Geom { | ||
| 43 | |||
| 44 | %%{ | ||
| 45 | machine svg_path; | ||
| 46 | write data noerror; | ||
| 47 | }%% | ||
| 48 | |||
| 49 | 836 | SVGPathParser::SVGPathParser(PathSink &sink) | |
| 50 | 836 | : _absolute(false) | |
| 51 | 836 | , _sink(sink) | |
| 52 | 836 | , _z_snap_threshold(0) | |
| 53 | 836 | , _curve(NULL) | |
| 54 | { | ||
| 55 |
1/2✓ Branch 1 taken 836 times.
✗ Branch 2 not taken.
|
836 | reset(); |
| 56 | 836 | } | |
| 57 | |||
| 58 | 836 | SVGPathParser::~SVGPathParser() | |
| 59 | { | ||
| 60 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 836 times.
|
836 | delete _curve; |
| 61 | 836 | } | |
| 62 | |||
| 63 | 1672 | void SVGPathParser::reset() { | |
| 64 | 1672 | _absolute = false; | |
| 65 | 1672 | _current = _initial = Point(0, 0); | |
| 66 | 1672 | _quad_tangent = _cubic_tangent = Point(0, 0); | |
| 67 | 1672 | _params.clear(); | |
| 68 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1672 times.
|
1672 | delete _curve; |
| 69 | 1672 | _curve = NULL; | |
| 70 | |||
| 71 | %%{ | ||
| 72 | write init; | ||
| 73 | }%% | ||
| 74 | 1672 | } | |
| 75 | |||
| 76 | 836 | void SVGPathParser::parse(char const *str, int len) | |
| 77 | { | ||
| 78 |
1/2✓ Branch 0 taken 836 times.
✗ Branch 1 not taken.
|
836 | if (len < 0) { |
| 79 | 836 | len = std::strlen(str); | |
| 80 | } | ||
| 81 | 836 | _parse(str, str + len, true); | |
| 82 | 836 | } | |
| 83 | |||
| 84 | ✗ | void SVGPathParser::parse(std::string const &s) | |
| 85 | { | ||
| 86 | ✗ | _parse(s.c_str(), s.c_str() + s.size(), true); | |
| 87 | ✗ | } | |
| 88 | |||
| 89 | ✗ | void SVGPathParser::feed(char const *str, int len) | |
| 90 | { | ||
| 91 | ✗ | if (len < 0) { | |
| 92 | ✗ | len = std::strlen(str); | |
| 93 | } | ||
| 94 | ✗ | _parse(str, str + len, false); | |
| 95 | ✗ | } | |
| 96 | |||
| 97 | ✗ | void SVGPathParser::feed(std::string const &s) | |
| 98 | { | ||
| 99 | ✗ | _parse(s.c_str(), s.c_str() + s.size(), false); | |
| 100 | ✗ | } | |
| 101 | |||
| 102 | ✗ | void SVGPathParser::finish() | |
| 103 | { | ||
| 104 | ✗ | char const *empty = ""; | |
| 105 | ✗ | _parse(empty, empty, true); | |
| 106 | ✗ | } | |
| 107 | |||
| 108 | 146005 | void SVGPathParser::_push(Coord value) | |
| 109 | { | ||
| 110 | 146005 | _params.push_back(value); | |
| 111 | 146005 | } | |
| 112 | |||
| 113 | 146005 | Coord SVGPathParser::_pop() | |
| 114 | { | ||
| 115 | 146005 | Coord value = _params.back(); | |
| 116 | 146005 | _params.pop_back(); | |
| 117 | 146005 | return value; | |
| 118 | } | ||
| 119 | |||
| 120 | 376 | bool SVGPathParser::_pop_flag() | |
| 121 | { | ||
| 122 | 376 | return _pop() != 0.0; | |
| 123 | } | ||
| 124 | |||
| 125 | 145065 | Coord SVGPathParser::_pop_coord(Dim2 axis) | |
| 126 | { | ||
| 127 |
2/2✓ Branch 0 taken 143781 times.
✓ Branch 1 taken 1284 times.
|
145065 | if (_absolute) { |
| 128 | 143781 | return _pop(); | |
| 129 | } else { | ||
| 130 | 1284 | return _pop() + _current[axis]; | |
| 131 | } | ||
| 132 | } | ||
| 133 | |||
| 134 | 72333 | Point SVGPathParser::_pop_point() | |
| 135 | { | ||
| 136 | 72333 | Coord y = _pop_coord(Y); | |
| 137 | 72333 | Coord x = _pop_coord(X); | |
| 138 | 72333 | return Point(x, y); | |
| 139 | } | ||
| 140 | |||
| 141 | 1406 | void SVGPathParser::_moveTo(Point const &p) | |
| 142 | { | ||
| 143 | 1406 | _pushCurve(NULL); // flush | |
| 144 | 1406 | _sink.moveTo(p); | |
| 145 | 1406 | _quad_tangent = _cubic_tangent = _current = _initial = p; | |
| 146 | 1406 | } | |
| 147 | |||
| 148 | 1652 | void SVGPathParser::_lineTo(Point const &p) | |
| 149 | { | ||
| 150 |
2/6✓ Branch 2 taken 1652 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 1652 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
|
1652 | _pushCurve(new LineSegment(_current, p)); |
| 151 | 1652 | _quad_tangent = _cubic_tangent = _current = p; | |
| 152 | 1652 | } | |
| 153 | |||
| 154 | 23136 | void SVGPathParser::_curveTo(Point const &c0, Point const &c1, Point const &p) | |
| 155 | { | ||
| 156 |
2/6✓ Branch 2 taken 23136 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 23136 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
|
23136 | _pushCurve(new CubicBezier(_current, c0, c1, p)); |
| 157 | 23136 | _quad_tangent = _current = p; | |
| 158 | 23136 | _cubic_tangent = p + ( p - c1 ); | |
| 159 | 23136 | } | |
| 160 | |||
| 161 | 61 | void SVGPathParser::_quadTo(Point const &c, Point const &p) | |
| 162 | { | ||
| 163 |
2/6✓ Branch 2 taken 61 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 61 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
|
61 | _pushCurve(new QuadraticBezier(_current, c, p)); |
| 164 | 61 | _cubic_tangent = _current = p; | |
| 165 | 61 | _quad_tangent = p + ( p - c ); | |
| 166 | 61 | } | |
| 167 | |||
| 168 | 188 | void SVGPathParser::_arcTo(Coord rx, Coord ry, Coord angle, | |
| 169 | bool large_arc, bool sweep, Point const &p) | ||
| 170 | { | ||
| 171 |
2/2✓ Branch 1 taken 31 times.
✓ Branch 2 taken 157 times.
|
188 | if (_current == p) { |
| 172 | 31 | return; // ignore invalid (ambiguous) arc segments where start and end point are the same (per SVG spec) | |
| 173 | } | ||
| 174 | |||
| 175 |
2/6✓ Branch 2 taken 157 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 157 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
|
157 | _pushCurve(new EllipticalArc(_current, fabs(rx), fabs(ry), angle, large_arc, sweep, p)); |
| 176 | 157 | _quad_tangent = _cubic_tangent = _current = p; | |
| 177 | } | ||
| 178 | |||
| 179 | 282 | void SVGPathParser::_closePath() | |
| 180 | { | ||
| 181 |
7/8✓ Branch 0 taken 281 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 192 times.
✓ Branch 3 taken 89 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 192 times.
✓ Branch 6 taken 58 times.
✓ Branch 7 taken 224 times.
|
371 | if (_curve && (!_absolute || !_moveto_was_absolute) && |
| 182 |
2/2✓ Branch 1 taken 58 times.
✓ Branch 2 taken 31 times.
|
89 | are_near(_initial, _current, _z_snap_threshold)) |
| 183 | { | ||
| 184 | 58 | _curve->setFinal(_initial); | |
| 185 | } | ||
| 186 | |||
| 187 | 282 | _pushCurve(NULL); // flush | |
| 188 | 282 | _sink.closePath(); | |
| 189 | 282 | _quad_tangent = _cubic_tangent = _current = _initial; | |
| 190 | 282 | } | |
| 191 | |||
| 192 | 27530 | void SVGPathParser::_pushCurve(Curve *c) | |
| 193 | { | ||
| 194 |
2/2✓ Branch 0 taken 25006 times.
✓ Branch 1 taken 2524 times.
|
27530 | if (_curve) { |
| 195 | 25006 | _sink.feed(*_curve, false); | |
| 196 |
1/2✓ Branch 0 taken 25006 times.
✗ Branch 1 not taken.
|
25006 | delete _curve; |
| 197 | } | ||
| 198 | 27530 | _curve = c; | |
| 199 | 27530 | } | |
| 200 | |||
| 201 | 836 | void SVGPathParser::_parse(char const *str, char const *strend, bool finish) | |
| 202 | { | ||
| 203 | 836 | char const *p = str; | |
| 204 | 836 | char const *pe = strend; | |
| 205 |
1/2✓ Branch 0 taken 836 times.
✗ Branch 1 not taken.
|
836 | char const *eof = finish ? pe : NULL; |
| 206 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 836 times.
|
836 | char const *start = NULL; |
| 207 | |||
| 208 | %%{ | ||
| 209 | action start_number { | ||
| 210 | 145629 | start = p; | |
| 211 | } | ||
| 212 | 145629 | ||
| 213 | 145070 | action push_number { | |
| 214 |
2/4✓ Branch 0 taken 145070 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 559 times.
✗ Branch 3 not taken.
|
145629 | if (start) { |
| 215 |
2/4✓ Branch 3 taken 145070 times.
✗ Branch 4 not taken.
✓ Branch 9 taken 559 times.
✗ Branch 10 not taken.
|
436887 | std::string buf(start, p); |
| 216 |
4/8✓ Branch 2 taken 145070 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 145070 times.
✗ Branch 6 not taken.
✓ Branch 9 taken 559 times.
✗ Branch 10 not taken.
✓ Branch 12 taken 559 times.
✗ Branch 13 not taken.
|
145629 | _push(g_ascii_strtod(buf.c_str(), NULL)); |
| 217 | 145629 | start = NULL; | |
| 218 | 145629 | } else { | |
| 219 | ✗ | std::string buf(str, p); | |
| 220 | ✗ | _push(g_ascii_strtod((_number_part + buf).c_str(), NULL)); | |
| 221 | ✗ | _number_part.clear(); | |
| 222 | ✗ | } | |
| 223 | } | ||
| 224 | 145629 | ||
| 225 | 273 | action push_true { | |
| 226 | 243 | _push(1.0); | |
| 227 | } | ||
| 228 | 243 | ||
| 229 | 133 | action push_false { | |
| 230 | 133 | _push(0.0); | |
| 231 | } | ||
| 232 | 133 | ||
| 233 | 3601 | action mode_abs { | |
| 234 | 3601 | _absolute = true; | |
| 235 | } | ||
| 236 | 3601 | ||
| 237 | 265 | action mode_rel { | |
| 238 | 265 | _absolute = false; | |
| 239 | } | ||
| 240 | 265 | ||
| 241 | 1376 | action moveto { | |
| 242 | 1406 | _moveto_was_absolute = _absolute; | |
| 243 |
4/8✓ Branch 2 taken 1376 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 1376 times.
✗ Branch 6 not taken.
✓ Branch 10 taken 30 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 30 times.
✗ Branch 14 not taken.
|
1406 | _moveTo(_pop_point()); |
| 244 | } | ||
| 245 | 1406 | ||
| 246 | 1253 | action lineto { | |
| 247 |
4/8✓ Branch 2 taken 1134 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 1134 times.
✗ Branch 6 not taken.
✓ Branch 10 taken 119 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 119 times.
✗ Branch 14 not taken.
|
1253 | _lineTo(_pop_point()); |
| 248 | } | ||
| 249 | 1253 | ||
| 250 | 192 | action horizontal_lineto { | |
| 251 |
4/8✓ Branch 3 taken 181 times.
✗ Branch 4 not taken.
✓ Branch 7 taken 181 times.
✗ Branch 8 not taken.
✓ Branch 13 taken 11 times.
✗ Branch 14 not taken.
✓ Branch 17 taken 11 times.
✗ Branch 18 not taken.
|
192 | _lineTo(Point(_pop_coord(X), _current[Y])); |
| 252 | } | ||
| 253 | 192 | ||
| 254 | 207 | action vertical_lineto { | |
| 255 |
4/8✓ Branch 2 taken 200 times.
✗ Branch 3 not taken.
✓ Branch 7 taken 200 times.
✗ Branch 8 not taken.
✓ Branch 12 taken 7 times.
✗ Branch 13 not taken.
✓ Branch 17 taken 7 times.
✗ Branch 18 not taken.
|
207 | _lineTo(Point(_current[X], _pop_coord(Y))); |
| 256 | } | ||
| 257 | 207 | ||
| 258 | 23092 | action curveto { | |
| 259 |
2/4✓ Branch 2 taken 22762 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 330 times.
✗ Branch 7 not taken.
|
23092 | Point p = _pop_point(); |
| 260 |
2/4✓ Branch 2 taken 22762 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 330 times.
✗ Branch 7 not taken.
|
23092 | Point c1 = _pop_point(); |
| 261 |
2/4✓ Branch 2 taken 22762 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 330 times.
✗ Branch 7 not taken.
|
23092 | Point c0 = _pop_point(); |
| 262 |
2/4✓ Branch 1 taken 22762 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 330 times.
✗ Branch 5 not taken.
|
23092 | _curveTo(c0, c1, p); |
| 263 | } | ||
| 264 | |||
| 265 | 44 | action smooth_curveto { | |
| 266 |
2/4✓ Branch 2 taken 13 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 31 times.
✗ Branch 7 not taken.
|
44 | Point p = _pop_point(); |
| 267 |
2/4✓ Branch 2 taken 13 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 31 times.
✗ Branch 7 not taken.
|
44 | Point c1 = _pop_point(); |
| 268 |
2/4✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 31 times.
✗ Branch 5 not taken.
|
44 | _curveTo(_cubic_tangent, c1, p); |
| 269 | } | ||
| 270 | |||
| 271 | 61 | action quadratic_bezier_curveto { | |
| 272 |
2/4✓ Branch 2 taken 40 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 21 times.
✗ Branch 7 not taken.
|
61 | Point p = _pop_point(); |
| 273 |
2/4✓ Branch 2 taken 40 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 21 times.
✗ Branch 7 not taken.
|
61 | Point c = _pop_point(); |
| 274 |
2/4✓ Branch 1 taken 40 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 21 times.
✗ Branch 5 not taken.
|
61 | _quadTo(c, p); |
| 275 | } | ||
| 276 | |||
| 277 | ✗ | action smooth_quadratic_bezier_curveto { | |
| 278 | ✗ | Point p = _pop_point(); | |
| 279 | ✗ | _quadTo(_quad_tangent, p); | |
| 280 | } | ||
| 281 | |||
| 282 | 188 | action elliptical_arc { | |
| 283 |
2/4✓ Branch 2 taken 178 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 10 times.
✗ Branch 7 not taken.
|
188 | Point point = _pop_point(); |
| 284 |
2/4✓ Branch 1 taken 178 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 10 times.
✗ Branch 5 not taken.
|
188 | bool sweep = _pop_flag(); |
| 285 |
2/4✓ Branch 1 taken 178 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 10 times.
✗ Branch 5 not taken.
|
188 | bool large_arc = _pop_flag(); |
| 286 |
2/4✓ Branch 1 taken 178 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 10 times.
✗ Branch 6 not taken.
|
188 | double angle = rad_from_deg(_pop()); |
| 287 |
2/4✓ Branch 1 taken 178 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 10 times.
✗ Branch 5 not taken.
|
188 | double ry = _pop(); |
| 288 |
2/4✓ Branch 1 taken 178 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 10 times.
✗ Branch 5 not taken.
|
188 | double rx = _pop(); |
| 289 | |||
| 290 |
2/4✓ Branch 1 taken 178 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 10 times.
✗ Branch 5 not taken.
|
188 | _arcTo(rx, ry, angle, large_arc, sweep, point); |
| 291 | } | ||
| 292 | |||
| 293 | 282 | action closepath { | |
| 294 | 282 | _closePath(); | |
| 295 | } | ||
| 296 | 282 | ||
| 297 | wsp = (' ' | 9 | 10 | 13); | ||
| 298 | sign = ('+' | '-'); | ||
| 299 | digit_sequence = digit+; | ||
| 300 | exponent = ('e' | 'E') sign? digit_sequence; | ||
| 301 | fractional_constant = | ||
| 302 | digit_sequence? '.' digit_sequence | ||
| 303 | | digit_sequence '.'; | ||
| 304 | floating_point_constant = | ||
| 305 | fractional_constant exponent? | ||
| 306 | | digit_sequence exponent; | ||
| 307 | integer_constant = digit_sequence; | ||
| 308 | comma = ','; | ||
| 309 | comma_wsp = (wsp+ comma? wsp*) | (comma wsp*); | ||
| 310 | |||
| 311 | flag = ('0' %push_false | '1' %push_true); | ||
| 312 | |||
| 313 | number = | ||
| 314 | ( sign? integer_constant | ||
| 315 | | sign? floating_point_constant ) | ||
| 316 | >start_number %push_number; | ||
| 317 | |||
| 318 | nonnegative_number = | ||
| 319 | ( integer_constant | ||
| 320 | | floating_point_constant) | ||
| 321 | >start_number %push_number; | ||
| 322 | |||
| 323 | coordinate = number $(number,1) %(number,0); | ||
| 324 | coordinate_pair = (coordinate $(coordinate_pair_a,1) %(coordinate_pair_a,0) comma_wsp? coordinate $(coordinate_pair_b,1) %(coordinate_pair_b,0)) $(coordinate_pair,1) %(coordinate_pair,0); | ||
| 325 | elliptical_arc_argument = | ||
| 326 | (number $(elliptical_arg_a,1) %(elliptical_arg_a,0) comma_wsp? | ||
| 327 | number $(elliptical_arg_b,1) %(elliptical_arg_b,0) comma_wsp? | ||
| 328 | number comma_wsp | ||
| 329 | flag comma_wsp? flag comma_wsp? | ||
| 330 | coordinate_pair) | ||
| 331 | %elliptical_arc; | ||
| 332 | elliptical_arc_argument_sequence = | ||
| 333 | elliptical_arc_argument $1 %0 | ||
| 334 | (comma_wsp? elliptical_arc_argument $1 %0)*; | ||
| 335 | elliptical_arc = | ||
| 336 | ('A' %mode_abs| 'a' %mode_rel) wsp* | ||
| 337 | elliptical_arc_argument_sequence; | ||
| 338 | |||
| 339 | smooth_quadratic_bezier_curveto_argument = | ||
| 340 | coordinate_pair %smooth_quadratic_bezier_curveto; | ||
| 341 | smooth_quadratic_bezier_curveto_argument_sequence = | ||
| 342 | smooth_quadratic_bezier_curveto_argument $1 %0 | ||
| 343 | (comma_wsp? | ||
| 344 | smooth_quadratic_bezier_curveto_argument $1 %0)*; | ||
| 345 | smooth_quadratic_bezier_curveto = | ||
| 346 | ('T' %mode_abs| 't' %mode_rel) wsp* | ||
| 347 | smooth_quadratic_bezier_curveto_argument_sequence; | ||
| 348 | |||
| 349 | quadratic_bezier_curveto_argument = | ||
| 350 | (coordinate_pair $1 %0 comma_wsp? coordinate_pair) | ||
| 351 | %quadratic_bezier_curveto; | ||
| 352 | quadratic_bezier_curveto_argument_sequence = | ||
| 353 | quadratic_bezier_curveto_argument $1 %0 | ||
| 354 | (comma_wsp? quadratic_bezier_curveto_argument $1 %0)*; | ||
| 355 | quadratic_bezier_curveto = | ||
| 356 | ('Q' %mode_abs| 'q' %mode_rel) wsp* | ||
| 357 | quadratic_bezier_curveto_argument_sequence; | ||
| 358 | |||
| 359 | smooth_curveto_argument = | ||
| 360 | (coordinate_pair $1 %0 comma_wsp? coordinate_pair) | ||
| 361 | %smooth_curveto; | ||
| 362 | smooth_curveto_argument_sequence = | ||
| 363 | smooth_curveto_argument $1 %0 | ||
| 364 | (comma_wsp? smooth_curveto_argument $1 %0)*; | ||
| 365 | smooth_curveto = | ||
| 366 | ('S' %mode_abs| 's' %mode_rel) | ||
| 367 | wsp* smooth_curveto_argument_sequence; | ||
| 368 | |||
| 369 | curveto_argument = | ||
| 370 | (coordinate_pair $1 %0 comma_wsp? | ||
| 371 | coordinate_pair $1 %0 comma_wsp? | ||
| 372 | coordinate_pair) | ||
| 373 | %curveto; | ||
| 374 | curveto_argument_sequence = | ||
| 375 | curveto_argument $1 %0 | ||
| 376 | (comma_wsp? curveto_argument $1 %0)*; | ||
| 377 | curveto = | ||
| 378 | ('C' %mode_abs| 'c' %mode_rel) | ||
| 379 | wsp* curveto_argument_sequence; | ||
| 380 | |||
| 381 | vertical_lineto_argument = coordinate %vertical_lineto; | ||
| 382 | vertical_lineto_argument_sequence = | ||
| 383 | vertical_lineto_argument $(vertical_lineto_argument_a,1) %(vertical_lineto_argument_a,0) | ||
| 384 | (comma_wsp? vertical_lineto_argument $(vertical_lineto_argument_b,1) %(vertical_lineto_argument_b,0))*; | ||
| 385 | vertical_lineto = | ||
| 386 | ('V' %mode_abs| 'v' %mode_rel) | ||
| 387 | wsp* vertical_lineto_argument_sequence; | ||
| 388 | |||
| 389 | horizontal_lineto_argument = coordinate %horizontal_lineto; | ||
| 390 | horizontal_lineto_argument_sequence = | ||
| 391 | horizontal_lineto_argument $(horizontal_lineto_argument_a,1) %(horizontal_lineto_argument_a,0) | ||
| 392 | (comma_wsp? horizontal_lineto_argument $(horizontal_lineto_argument_b,1) %(horizontal_lineto_argument_b,0))*; | ||
| 393 | horizontal_lineto = | ||
| 394 | ('H' %mode_abs| 'h' %mode_rel) | ||
| 395 | wsp* horizontal_lineto_argument_sequence; | ||
| 396 | |||
| 397 | lineto_argument = coordinate_pair %lineto; | ||
| 398 | lineto_argument_sequence = | ||
| 399 | lineto_argument $1 %0 | ||
| 400 | (comma_wsp? lineto_argument $1 %0)*; | ||
| 401 | lineto = | ||
| 402 | ('L' %mode_abs| 'l' %mode_rel) wsp* | ||
| 403 | lineto_argument_sequence; | ||
| 404 | |||
| 405 | closepath = ('Z' | 'z') %closepath; | ||
| 406 | |||
| 407 | moveto_argument = coordinate_pair %moveto; | ||
| 408 | moveto_argument_sequence = | ||
| 409 | moveto_argument $1 %0 | ||
| 410 | (comma_wsp? lineto_argument $1 %0)*; | ||
| 411 | moveto = | ||
| 412 | ('M' %mode_abs | 'm' %mode_rel) | ||
| 413 | wsp* moveto_argument_sequence; | ||
| 414 | |||
| 415 | drawto_command = | ||
| 416 | closepath | lineto | | ||
| 417 | horizontal_lineto | vertical_lineto | | ||
| 418 | curveto | smooth_curveto | | ||
| 419 | quadratic_bezier_curveto | | ||
| 420 | smooth_quadratic_bezier_curveto | | ||
| 421 | elliptical_arc; | ||
| 422 | |||
| 423 | drawto_commands = drawto_command (wsp* drawto_command)*; | ||
| 424 | moveto_drawto_command_group = moveto wsp* drawto_commands?; | ||
| 425 | moveto_drawto_command_groups = | ||
| 426 | moveto_drawto_command_group | ||
| 427 | (wsp* moveto_drawto_command_group)*; | ||
| 428 | |||
| 429 | svg_path = wsp* moveto_drawto_command_groups? wsp*; | ||
| 430 | |||
| 431 | |||
| 432 | main := svg_path; | ||
| 433 | |||
| 434 | write exec; | ||
| 435 | }%% | ||
| 436 | |||
| 437 |
1/2✓ Branch 0 taken 836 times.
✗ Branch 1 not taken.
|
836 | if (finish) { |
| 438 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 836 times.
|
836 | if (cs < svg_path_first_final) { |
| 439 | ✗ | throw SVGPathParseError(); | |
| 440 | } | ||
| 441 | ✗ | } else if (start != NULL) { | |
| 442 | ✗ | _number_part = std::string(start, pe); | |
| 443 | } | ||
| 444 | |||
| 445 |
1/2✓ Branch 0 taken 836 times.
✗ Branch 1 not taken.
|
836 | if (finish) { |
| 446 | 836 | _pushCurve(NULL); | |
| 447 | 836 | _sink.flush(); | |
| 448 | 836 | reset(); | |
| 449 | } | ||
| 450 | 836 | } | |
| 451 | |||
| 452 | 836 | void parse_svg_path(char const *str, PathSink &sink) | |
| 453 | { | ||
| 454 |
1/2✓ Branch 2 taken 836 times.
✗ Branch 3 not taken.
|
836 | SVGPathParser parser(sink); |
| 455 |
1/2✓ Branch 1 taken 836 times.
✗ Branch 2 not taken.
|
836 | parser.parse(str); |
| 456 | 1672 | } | |
| 457 | |||
| 458 | ✗ | void parse_svg_path_file(FILE *fi, PathSink &sink) | |
| 459 | { | ||
| 460 | static const size_t BUFFER_SIZE = 4096; | ||
| 461 | ✗ | char buffer[BUFFER_SIZE]; | |
| 462 | size_t bytes_read; | ||
| 463 | ✗ | SVGPathParser parser(sink); | |
| 464 | |||
| 465 | while (true) { | ||
| 466 | ✗ | bytes_read = fread(buffer, 1, BUFFER_SIZE, fi); | |
| 467 | ✗ | if (bytes_read < BUFFER_SIZE) { | |
| 468 | ✗ | parser.parse(buffer, bytes_read); | |
| 469 | ✗ | break; | |
| 470 | } else { | ||
| 471 | ✗ | parser.feed(buffer, bytes_read); | |
| 472 | } | ||
| 473 | } | ||
| 474 | ✗ | } | |
| 475 | |||
| 476 | } // namespace Geom | ||
| 477 | |||
| 478 | /* | ||
| 479 | Local Variables: | ||
| 480 | mode:c++ | ||
| 481 | c-file-style:"stroustrup" | ||
| 482 | c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) | ||
| 483 | indent-tabs-mode:nil | ||
| 484 | fill-column:99 | ||
| 485 | End: | ||
| 486 | */ | ||
| 487 | // vim: filetype=ragel:cindent:expandtab:shiftwidth=4:softtabstop=4:fileencoding=utf-8:textwidth=99 : | ||
| 488 |