| 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 | #ifndef LIB2GEOM_SEEN_SVG_PATH_PARSER_H | ||
| 34 | #define LIB2GEOM_SEEN_SVG_PATH_PARSER_H | ||
| 35 | |||
| 36 | #include <iostream> | ||
| 37 | #include <iterator> | ||
| 38 | #include <stdexcept> | ||
| 39 | #include <vector> | ||
| 40 | #include <cstdio> | ||
| 41 | #include <2geom/exception.h> | ||
| 42 | #include <2geom/point.h> | ||
| 43 | #include <2geom/path-sink.h> | ||
| 44 | #include <2geom/forward.h> | ||
| 45 | |||
| 46 | namespace Geom { | ||
| 47 | |||
| 48 | /** @brief Read SVG path data and feed it to a PathSink | ||
| 49 | * | ||
| 50 | * This class provides an interface to an SVG path data parser written in Ragel. | ||
| 51 | * It supports parsing the path data either at once or block-by-block. | ||
| 52 | * Use the parse() functions to parse complete data and the feed() and finish() | ||
| 53 | * functions to parse partial data. | ||
| 54 | * | ||
| 55 | * The parser will call the appropriate methods on the PathSink supplied | ||
| 56 | * at construction. To store the path in memory as a PathVector, pass | ||
| 57 | * a PathBuilder. You can also use one of the freestanding helper functions | ||
| 58 | * if you don't need to parse data block-by-block. | ||
| 59 | * | ||
| 60 | * @ingroup Paths | ||
| 61 | */ | ||
| 62 | class SVGPathParser { | ||
| 63 | public: | ||
| 64 | SVGPathParser(PathSink &sink); | ||
| 65 | ~SVGPathParser(); | ||
| 66 | |||
| 67 | /** @brief Reset internal state. | ||
| 68 | * Discards the internal state associated with partially parsed data, | ||
| 69 | * letting you start from scratch. Note that any partial data written | ||
| 70 | * to the path sink is not affected - you need to clear it yourself. */ | ||
| 71 | void reset(); | ||
| 72 | |||
| 73 | /** @brief Parse a C-style string. | ||
| 74 | * The path sink is flushed and the internal state is reset after this call. | ||
| 75 | * Note that the state is not reset before this method, so you can use it to | ||
| 76 | * process the last block of partial data. | ||
| 77 | * @param str String to parse | ||
| 78 | * @param len Length of string or -1 if null-terminated */ | ||
| 79 | void parse(char const *str, int len = -1); | ||
| 80 | /** @brief Parse an STL string. */ | ||
| 81 | void parse(std::string const &s); | ||
| 82 | |||
| 83 | /** @brief Parse a part of path data stored in a C-style string. | ||
| 84 | * This method does not reset internal state, so it can be called multiple | ||
| 85 | * times to parse successive blocks of a longer SVG path data string. | ||
| 86 | * To finish parsing, call finish() after the final block or call parse() | ||
| 87 | * with the last block of data. | ||
| 88 | * @param str String to parse | ||
| 89 | * @param len Length of string or -1 if null-terminated */ | ||
| 90 | void feed(char const *str, int len = -1); | ||
| 91 | /** @brief Parse a part of path data stored in an STL string. */ | ||
| 92 | void feed(std::string const &s); | ||
| 93 | |||
| 94 | /** @brief Finalize parsing. | ||
| 95 | * After the last block of data was submitted with feed(), call this method | ||
| 96 | * to finalize parsing, flush the path sink and reset internal state. | ||
| 97 | * You should not call this after parse(). */ | ||
| 98 | void finish(); | ||
| 99 | |||
| 100 | /** @brief Set the threshold for considering the closing segment degenerate. | ||
| 101 | * When the current point was reached by a relative command, is closer | ||
| 102 | * to the initial point of the path than the specified threshold | ||
| 103 | * and a 'z' is encountered, the last segment will be adjusted instead so that | ||
| 104 | * the closing segment has exactly zero length. This is useful when reading | ||
| 105 | * SVG 1.1 paths that have non-linear final segments written in relative | ||
| 106 | * coordinates, which always suffer from some loss of precision. SVG 2 | ||
| 107 | * allows alternate placement of 'z' which does not have this problem. */ | ||
| 108 | void setZSnapThreshold(Coord threshold) { _z_snap_threshold = threshold; } | ||
| 109 | Coord zSnapThreshold() const { return _z_snap_threshold; } | ||
| 110 | |||
| 111 | private: | ||
| 112 | bool _absolute; | ||
| 113 | bool _moveto_was_absolute; | ||
| 114 | Point _current; | ||
| 115 | Point _initial; | ||
| 116 | Point _cubic_tangent; | ||
| 117 | Point _quad_tangent; | ||
| 118 | std::vector<Coord> _params; | ||
| 119 | PathSink &_sink; | ||
| 120 | Coord _z_snap_threshold; | ||
| 121 | Curve *_curve; | ||
| 122 | |||
| 123 | int cs; | ||
| 124 | std::string _number_part; | ||
| 125 | |||
| 126 | void _push(Coord value); | ||
| 127 | Coord _pop(); | ||
| 128 | bool _pop_flag(); | ||
| 129 | Coord _pop_coord(Geom::Dim2 axis); | ||
| 130 | Point _pop_point(); | ||
| 131 | void _moveTo(Point const &p); | ||
| 132 | void _lineTo(Point const &p); | ||
| 133 | void _curveTo(Point const &c0, Point const &c1, Point const &p); | ||
| 134 | void _quadTo(Point const &c, Point const &p); | ||
| 135 | void _arcTo(double rx, double ry, double angle, | ||
| 136 | bool large_arc, bool sweep, Point const &p); | ||
| 137 | void _closePath(); | ||
| 138 | void _pushCurve(Curve *c); | ||
| 139 | |||
| 140 | void _parse(char const *str, char const *strend, bool finish); | ||
| 141 | }; | ||
| 142 | |||
| 143 | /** @brief Feed SVG path data to the specified sink | ||
| 144 | * @ingroup Paths */ | ||
| 145 | void parse_svg_path(char const *str, PathSink &sink); | ||
| 146 | /** @brief Feed SVG path data to the specified sink | ||
| 147 | * @ingroup Paths */ | ||
| 148 | inline void parse_svg_path(std::string const &str, PathSink &sink) { | ||
| 149 | parse_svg_path(str.c_str(), sink); | ||
| 150 | } | ||
| 151 | /** Feed SVG path data from a C stream to the specified sink | ||
| 152 | * @ingroup Paths */ | ||
| 153 | void parse_svg_path_file(FILE *fi, PathSink &sink); | ||
| 154 | |||
| 155 | /** @brief Create path vector from SVG path data stored in a C string | ||
| 156 | * @ingroup Paths */ | ||
| 157 | 315 | inline PathVector parse_svg_path(char const *str) { | |
| 158 | 315 | PathVector ret; | |
| 159 | 315 | SubpathInserter iter(ret); | |
| 160 |
1/2✓ Branch 2 taken 315 times.
✗ Branch 3 not taken.
|
315 | PathIteratorSink<SubpathInserter> generator(iter); |
| 161 | |||
| 162 |
1/2✓ Branch 1 taken 315 times.
✗ Branch 2 not taken.
|
315 | parse_svg_path(str, generator); |
| 163 | 630 | return ret; | |
| 164 | 315 | } | |
| 165 | |||
| 166 | /** @brief Create path vector from a C stream with SVG path data | ||
| 167 | * @ingroup Paths */ | ||
| 168 | ✗ | inline PathVector read_svgd_f(FILE * fi) { | |
| 169 | ✗ | PathVector ret; | |
| 170 | ✗ | SubpathInserter iter(ret); | |
| 171 | ✗ | PathIteratorSink<SubpathInserter> generator(iter); | |
| 172 | |||
| 173 | ✗ | parse_svg_path_file(fi, generator); | |
| 174 | ✗ | return ret; | |
| 175 | ✗ | } | |
| 176 | |||
| 177 | /** @brief Create path vector from SVG path data stored in a file | ||
| 178 | * @ingroup Paths */ | ||
| 179 | ✗ | inline PathVector read_svgd(char const *filename) { | |
| 180 | ✗ | FILE* fi = fopen(filename, "r"); | |
| 181 | ✗ | if(fi == NULL) throw(std::runtime_error("Error opening file")); | |
| 182 | ✗ | PathVector out = read_svgd_f(fi); | |
| 183 | ✗ | fclose(fi); | |
| 184 | ✗ | return out; | |
| 185 | ✗ | } | |
| 186 | |||
| 187 | } // end namespace Geom | ||
| 188 | |||
| 189 | #endif | ||
| 190 | /* | ||
| 191 | Local Variables: | ||
| 192 | mode:c++ | ||
| 193 | c-file-style:"stroustrup" | ||
| 194 | c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) | ||
| 195 | indent-tabs-mode:nil | ||
| 196 | fill-column:99 | ||
| 197 | End: | ||
| 198 | */ | ||
| 199 | // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : | ||
| 200 |