1 /*
2 * Copyright (C) Research In Motion Limited 2010, 2012. All rights reserved.
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
13 *
14 * You should have received a copy of the GNU Library General Public License
15 * along with this library; see the file COPYING.LIB. If not, write to
16 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
18 */
19
20 #include "config.h"
21
22 #include "core/svg/SVGPathUtilities.h"
23
24 #include "core/svg/SVGPathBlender.h"
25 #include "core/svg/SVGPathBuilder.h"
26 #include "core/svg/SVGPathByteStreamBuilder.h"
27 #include "core/svg/SVGPathByteStreamSource.h"
28 #include "core/svg/SVGPathParser.h"
29 #include "core/svg/SVGPathSegListBuilder.h"
30 #include "core/svg/SVGPathSegListSource.h"
31 #include "core/svg/SVGPathStringBuilder.h"
32 #include "core/svg/SVGPathStringSource.h"
33 #include "core/svg/SVGPathTraversalStateBuilder.h"
34 #include "platform/graphics/PathTraversalState.h"
35
36 namespace WebCore {
37
globalSVGPathBuilder(Path & result)38 static SVGPathBuilder* globalSVGPathBuilder(Path& result)
39 {
40 static SVGPathBuilder* s_builder = 0;
41 if (!s_builder)
42 s_builder = new SVGPathBuilder;
43
44 s_builder->setCurrentPath(&result);
45 return s_builder;
46 }
47
globalSVGPathSegListBuilder(SVGPathElement * element,SVGPathSegRole role,SVGPathSegList & result)48 static SVGPathSegListBuilder* globalSVGPathSegListBuilder(SVGPathElement* element, SVGPathSegRole role, SVGPathSegList& result)
49 {
50 static SVGPathSegListBuilder* s_builder = 0;
51 if (!s_builder)
52 s_builder = new SVGPathSegListBuilder;
53
54 s_builder->setCurrentSVGPathElement(element);
55 s_builder->setCurrentSVGPathSegList(result);
56 s_builder->setCurrentSVGPathSegRole(role);
57 return s_builder;
58 }
59
globalSVGPathByteStreamBuilder(SVGPathByteStream * result)60 static SVGPathByteStreamBuilder* globalSVGPathByteStreamBuilder(SVGPathByteStream* result)
61 {
62 static SVGPathByteStreamBuilder* s_builder = 0;
63 if (!s_builder)
64 s_builder = new SVGPathByteStreamBuilder;
65
66 s_builder->setCurrentByteStream(result);
67 return s_builder;
68 }
69
globalSVGPathStringBuilder()70 static SVGPathStringBuilder* globalSVGPathStringBuilder()
71 {
72 static SVGPathStringBuilder* s_builder = 0;
73 if (!s_builder)
74 s_builder = new SVGPathStringBuilder;
75
76 return s_builder;
77 }
78
globalSVGPathTraversalStateBuilder(PathTraversalState & traversalState,float length)79 static SVGPathTraversalStateBuilder* globalSVGPathTraversalStateBuilder(PathTraversalState& traversalState, float length)
80 {
81 static SVGPathTraversalStateBuilder* s_builder = 0;
82 if (!s_builder)
83 s_builder = new SVGPathTraversalStateBuilder;
84
85 s_builder->setCurrentTraversalState(&traversalState);
86 s_builder->setDesiredLength(length);
87 return s_builder;
88 }
89
globalSVGPathParser(SVGPathSource * source,SVGPathConsumer * consumer)90 static SVGPathParser* globalSVGPathParser(SVGPathSource* source, SVGPathConsumer* consumer)
91 {
92 static SVGPathParser* s_parser = 0;
93 if (!s_parser)
94 s_parser = new SVGPathParser;
95
96 s_parser->setCurrentSource(source);
97 s_parser->setCurrentConsumer(consumer);
98 return s_parser;
99 }
100
globalSVGPathBlender()101 static SVGPathBlender* globalSVGPathBlender()
102 {
103 static SVGPathBlender* s_blender = 0;
104 if (!s_blender)
105 s_blender = new SVGPathBlender;
106
107 return s_blender;
108 }
109
buildPathFromString(const String & d,Path & result)110 bool buildPathFromString(const String& d, Path& result)
111 {
112 if (d.isEmpty())
113 return false;
114
115 SVGPathBuilder* builder = globalSVGPathBuilder(result);
116
117 OwnPtr<SVGPathStringSource> source = SVGPathStringSource::create(d);
118 SVGPathParser* parser = globalSVGPathParser(source.get(), builder);
119 bool ok = parser->parsePathDataFromSource(NormalizedParsing);
120 parser->cleanup();
121 return ok;
122 }
123
buildSVGPathByteStreamFromSVGPathSegList(const SVGPathSegList & list,SVGPathByteStream * result,PathParsingMode parsingMode)124 bool buildSVGPathByteStreamFromSVGPathSegList(const SVGPathSegList& list, SVGPathByteStream* result, PathParsingMode parsingMode)
125 {
126 ASSERT(result);
127 result->clear();
128 if (list.isEmpty())
129 return false;
130
131 SVGPathByteStreamBuilder* builder = globalSVGPathByteStreamBuilder(result);
132
133 OwnPtr<SVGPathSegListSource> source = SVGPathSegListSource::create(list);
134 SVGPathParser* parser = globalSVGPathParser(source.get(), builder);
135 bool ok = parser->parsePathDataFromSource(parsingMode);
136 parser->cleanup();
137 return ok;
138 }
139
appendSVGPathByteStreamFromSVGPathSeg(PassRefPtr<SVGPathSeg> pathSeg,SVGPathByteStream * result,PathParsingMode parsingMode)140 bool appendSVGPathByteStreamFromSVGPathSeg(PassRefPtr<SVGPathSeg> pathSeg, SVGPathByteStream* result, PathParsingMode parsingMode)
141 {
142 ASSERT(result);
143 // FIXME: https://bugs.webkit.org/show_bug.cgi?id=15412 - Implement normalized path segment lists!
144 ASSERT(parsingMode == UnalteredParsing);
145
146 SVGPathSegList appendedItemList(PathSegUnalteredRole);
147 appendedItemList.append(pathSeg);
148 OwnPtr<SVGPathByteStream> appendedByteStream = SVGPathByteStream::create();
149
150 SVGPathByteStreamBuilder* builder = globalSVGPathByteStreamBuilder(appendedByteStream.get());
151 OwnPtr<SVGPathSegListSource> source = SVGPathSegListSource::create(appendedItemList);
152 SVGPathParser* parser = globalSVGPathParser(source.get(), builder);
153 bool ok = parser->parsePathDataFromSource(parsingMode, false);
154 parser->cleanup();
155
156 if (ok)
157 result->append(appendedByteStream.get());
158
159 return ok;
160 }
161
buildPathFromByteStream(SVGPathByteStream * stream,Path & result)162 bool buildPathFromByteStream(SVGPathByteStream* stream, Path& result)
163 {
164 ASSERT(stream);
165 if (stream->isEmpty())
166 return false;
167
168 SVGPathBuilder* builder = globalSVGPathBuilder(result);
169
170 OwnPtr<SVGPathByteStreamSource> source = SVGPathByteStreamSource::create(stream);
171 SVGPathParser* parser = globalSVGPathParser(source.get(), builder);
172 bool ok = parser->parsePathDataFromSource(NormalizedParsing);
173 parser->cleanup();
174 return ok;
175 }
176
buildSVGPathSegListFromByteStream(SVGPathByteStream * stream,SVGPathElement * element,SVGPathSegList & result,PathParsingMode parsingMode)177 bool buildSVGPathSegListFromByteStream(SVGPathByteStream* stream, SVGPathElement* element, SVGPathSegList& result, PathParsingMode parsingMode)
178 {
179 ASSERT(stream);
180 if (stream->isEmpty())
181 return false;
182
183 SVGPathSegListBuilder* builder = globalSVGPathSegListBuilder(element, parsingMode == NormalizedParsing ? PathSegNormalizedRole : PathSegUnalteredRole, result);
184
185 OwnPtr<SVGPathByteStreamSource> source = SVGPathByteStreamSource::create(stream);
186 SVGPathParser* parser = globalSVGPathParser(source.get(), builder);
187 bool ok = parser->parsePathDataFromSource(parsingMode);
188 parser->cleanup();
189 return ok;
190 }
191
buildStringFromByteStream(SVGPathByteStream * stream,String & result,PathParsingMode parsingMode)192 bool buildStringFromByteStream(SVGPathByteStream* stream, String& result, PathParsingMode parsingMode)
193 {
194 ASSERT(stream);
195 if (stream->isEmpty())
196 return false;
197
198 SVGPathStringBuilder* builder = globalSVGPathStringBuilder();
199
200 OwnPtr<SVGPathByteStreamSource> source = SVGPathByteStreamSource::create(stream);
201 SVGPathParser* parser = globalSVGPathParser(source.get(), builder);
202 bool ok = parser->parsePathDataFromSource(parsingMode);
203 result = builder->result();
204 parser->cleanup();
205 return ok;
206 }
207
buildStringFromSVGPathSegList(const SVGPathSegList & list,String & result,PathParsingMode parsingMode)208 bool buildStringFromSVGPathSegList(const SVGPathSegList& list, String& result, PathParsingMode parsingMode)
209 {
210 result = String();
211 if (list.isEmpty())
212 return false;
213
214 SVGPathStringBuilder* builder = globalSVGPathStringBuilder();
215
216 OwnPtr<SVGPathSegListSource> source = SVGPathSegListSource::create(list);
217 SVGPathParser* parser = globalSVGPathParser(source.get(), builder);
218 bool ok = parser->parsePathDataFromSource(parsingMode);
219 result = builder->result();
220 parser->cleanup();
221 return ok;
222 }
223
buildSVGPathByteStreamFromString(const String & d,SVGPathByteStream * result,PathParsingMode parsingMode)224 bool buildSVGPathByteStreamFromString(const String& d, SVGPathByteStream* result, PathParsingMode parsingMode)
225 {
226 ASSERT(result);
227 result->clear();
228 if (d.isEmpty())
229 return false;
230
231 SVGPathByteStreamBuilder* builder = globalSVGPathByteStreamBuilder(result);
232
233 OwnPtr<SVGPathStringSource> source = SVGPathStringSource::create(d);
234 SVGPathParser* parser = globalSVGPathParser(source.get(), builder);
235 bool ok = parser->parsePathDataFromSource(parsingMode);
236 parser->cleanup();
237 return ok;
238 }
239
buildAnimatedSVGPathByteStream(SVGPathByteStream * fromStream,SVGPathByteStream * toStream,SVGPathByteStream * result,float progress)240 bool buildAnimatedSVGPathByteStream(SVGPathByteStream* fromStream, SVGPathByteStream* toStream, SVGPathByteStream* result, float progress)
241 {
242 ASSERT(fromStream);
243 ASSERT(toStream);
244 ASSERT(result);
245 ASSERT(toStream != result);
246
247 result->clear();
248 if (toStream->isEmpty())
249 return false;
250
251 SVGPathByteStreamBuilder* builder = globalSVGPathByteStreamBuilder(result);
252
253 OwnPtr<SVGPathByteStreamSource> fromSource = SVGPathByteStreamSource::create(fromStream);
254 OwnPtr<SVGPathByteStreamSource> toSource = SVGPathByteStreamSource::create(toStream);
255 SVGPathBlender* blender = globalSVGPathBlender();
256 bool ok = blender->blendAnimatedPath(progress, fromSource.get(), toSource.get(), builder);
257 blender->cleanup();
258 return ok;
259 }
260
addToSVGPathByteStream(SVGPathByteStream * fromStream,SVGPathByteStream * byStream,unsigned repeatCount)261 bool addToSVGPathByteStream(SVGPathByteStream* fromStream, SVGPathByteStream* byStream, unsigned repeatCount)
262 {
263 ASSERT(fromStream);
264 ASSERT(byStream);
265 if (fromStream->isEmpty() || byStream->isEmpty())
266 return false;
267
268 SVGPathByteStreamBuilder* builder = globalSVGPathByteStreamBuilder(fromStream);
269
270 OwnPtr<SVGPathByteStream> fromStreamCopy = fromStream->copy();
271 fromStream->clear();
272
273 OwnPtr<SVGPathByteStreamSource> fromSource = SVGPathByteStreamSource::create(fromStreamCopy.get());
274 OwnPtr<SVGPathByteStreamSource> bySource = SVGPathByteStreamSource::create(byStream);
275 SVGPathBlender* blender = globalSVGPathBlender();
276 bool ok = blender->addAnimatedPath(fromSource.get(), bySource.get(), builder, repeatCount);
277 blender->cleanup();
278 return ok;
279 }
280
getSVGPathSegAtLengthFromSVGPathByteStream(SVGPathByteStream * stream,float length,unsigned & pathSeg)281 bool getSVGPathSegAtLengthFromSVGPathByteStream(SVGPathByteStream* stream, float length, unsigned& pathSeg)
282 {
283 ASSERT(stream);
284 if (stream->isEmpty())
285 return false;
286
287 PathTraversalState traversalState(PathTraversalState::TraversalSegmentAtLength);
288 SVGPathTraversalStateBuilder* builder = globalSVGPathTraversalStateBuilder(traversalState, length);
289
290 OwnPtr<SVGPathByteStreamSource> source = SVGPathByteStreamSource::create(stream);
291 SVGPathParser* parser = globalSVGPathParser(source.get(), builder);
292 bool ok = parser->parsePathDataFromSource(NormalizedParsing);
293 pathSeg = builder->pathSegmentIndex();
294 parser->cleanup();
295 return ok;
296 }
297
getTotalLengthOfSVGPathByteStream(SVGPathByteStream * stream,float & totalLength)298 bool getTotalLengthOfSVGPathByteStream(SVGPathByteStream* stream, float& totalLength)
299 {
300 ASSERT(stream);
301 if (stream->isEmpty())
302 return false;
303
304 PathTraversalState traversalState(PathTraversalState::TraversalTotalLength);
305 SVGPathTraversalStateBuilder* builder = globalSVGPathTraversalStateBuilder(traversalState, 0);
306
307 OwnPtr<SVGPathByteStreamSource> source = SVGPathByteStreamSource::create(stream);
308 SVGPathParser* parser = globalSVGPathParser(source.get(), builder);
309 bool ok = parser->parsePathDataFromSource(NormalizedParsing);
310 totalLength = builder->totalLength();
311 parser->cleanup();
312 return ok;
313 }
314
getPointAtLengthOfSVGPathByteStream(SVGPathByteStream * stream,float length,SVGPoint & point)315 bool getPointAtLengthOfSVGPathByteStream(SVGPathByteStream* stream, float length, SVGPoint& point)
316 {
317 ASSERT(stream);
318 if (stream->isEmpty())
319 return false;
320
321 PathTraversalState traversalState(PathTraversalState::TraversalPointAtLength);
322 SVGPathTraversalStateBuilder* builder = globalSVGPathTraversalStateBuilder(traversalState, length);
323
324 OwnPtr<SVGPathByteStreamSource> source = SVGPathByteStreamSource::create(stream);
325 SVGPathParser* parser = globalSVGPathParser(source.get(), builder);
326 bool ok = parser->parsePathDataFromSource(NormalizedParsing);
327 point = builder->currentPoint();
328 parser->cleanup();
329 return ok;
330 }
331
332 }
333