• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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