Use modern for-loops in WebCore/svg.
[WebKit-https.git] / Source / WebCore / svg / SVGPathUtilities.cpp
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 #include "SVGPathUtilities.h"
22
23 #include "Path.h"
24 #include "PathTraversalState.h"
25 #include "SVGPathBlender.h"
26 #include "SVGPathBuilder.h"
27 #include "SVGPathByteStreamBuilder.h"
28 #include "SVGPathByteStreamSource.h"
29 #include "SVGPathElement.h"
30 #include "SVGPathParser.h"
31 #include "SVGPathSegListBuilder.h"
32 #include "SVGPathSegListSource.h"
33 #include "SVGPathStringBuilder.h"
34 #include "SVGPathStringSource.h"
35 #include "SVGPathTraversalStateBuilder.h"
36
37 namespace WebCore {
38
39 static SVGPathBuilder* globalSVGPathBuilder(Path& result)
40 {
41     static SVGPathBuilder* s_builder = 0;
42     if (!s_builder)
43         s_builder = new SVGPathBuilder;
44
45     s_builder->setCurrentPath(&result);
46     return s_builder;
47 }
48
49 static SVGPathSegListBuilder* globalSVGPathSegListBuilder(SVGPathElement* element, SVGPathSegRole role, SVGPathSegList& result)
50 {
51     static SVGPathSegListBuilder* s_builder = 0;
52     if (!s_builder)
53         s_builder = new SVGPathSegListBuilder;
54
55     s_builder->setCurrentSVGPathElement(element);
56     s_builder->setCurrentSVGPathSegList(result);
57     s_builder->setCurrentSVGPathSegRole(role);
58     return s_builder;
59 }
60
61 static SVGPathByteStreamBuilder* globalSVGPathByteStreamBuilder(SVGPathByteStream* result)
62 {
63     static SVGPathByteStreamBuilder* s_builder = 0;
64     if (!s_builder)
65         s_builder = new SVGPathByteStreamBuilder;
66
67     s_builder->setCurrentByteStream(result);
68     return s_builder;
69 }
70
71 static SVGPathStringBuilder* globalSVGPathStringBuilder()
72 {
73     static SVGPathStringBuilder* s_builder = 0;
74     if (!s_builder)
75         s_builder = new SVGPathStringBuilder;
76
77     return s_builder;
78 }
79
80 static SVGPathTraversalStateBuilder* globalSVGPathTraversalStateBuilder(PathTraversalState& traversalState, float length)
81 {
82     static SVGPathTraversalStateBuilder* s_builder = 0;
83     if (!s_builder)
84         s_builder = new SVGPathTraversalStateBuilder;
85
86     s_builder->setCurrentTraversalState(&traversalState);
87     s_builder->setDesiredLength(length);
88     return s_builder;
89 }
90
91 static SVGPathParser* globalSVGPathParser(SVGPathSource* source, SVGPathConsumer* consumer)
92 {
93     static SVGPathParser* s_parser = 0;
94     if (!s_parser)
95         s_parser = new SVGPathParser;
96
97     s_parser->setCurrentSource(source);
98     s_parser->setCurrentConsumer(consumer);
99     return s_parser;
100 }
101
102 static SVGPathBlender* globalSVGPathBlender()
103 {
104     static SVGPathBlender* s_blender = 0;
105     if (!s_blender)
106         s_blender = new SVGPathBlender;
107
108     return s_blender;
109 }
110
111 bool buildPathFromString(const String& d, Path& result)
112 {
113     if (d.isEmpty())
114         return true;
115
116     SVGPathBuilder* builder = globalSVGPathBuilder(result);
117
118     auto source = std::make_unique<SVGPathStringSource>(d);
119     SVGPathParser* parser = globalSVGPathParser(source.get(), builder);
120     bool ok = parser->parsePathDataFromSource(NormalizedParsing);
121     parser->cleanup();
122     return ok;
123 }
124
125 bool buildSVGPathByteStreamFromSVGPathSegList(const SVGPathSegList& list, SVGPathByteStream* result, PathParsingMode parsingMode)
126 {
127     ASSERT(result);
128     result->clear();
129     if (list.isEmpty())
130         return true;
131
132     SVGPathByteStreamBuilder* builder = globalSVGPathByteStreamBuilder(result);
133
134     auto source = std::make_unique<SVGPathSegListSource>(list);
135     SVGPathParser* parser = globalSVGPathParser(source.get(), builder);
136     bool ok = parser->parsePathDataFromSource(parsingMode);
137     parser->cleanup();
138     return ok;
139 }
140
141 bool appendSVGPathByteStreamFromSVGPathSeg(PassRefPtr<SVGPathSeg> pathSeg, SVGPathByteStream* result, PathParsingMode parsingMode)
142 {
143     ASSERT(result);
144     // FIXME: https://bugs.webkit.org/show_bug.cgi?id=15412 - Implement normalized path segment lists!
145     ASSERT(parsingMode == UnalteredParsing);
146
147     SVGPathSegList appendedItemList(PathSegUnalteredRole);
148     appendedItemList.append(pathSeg);
149     auto appendedByteStream = std::make_unique<SVGPathByteStream>();
150
151     SVGPathByteStreamBuilder* builder = globalSVGPathByteStreamBuilder(appendedByteStream.get());
152     auto source = std::make_unique<SVGPathSegListSource>(appendedItemList);
153     SVGPathParser* parser = globalSVGPathParser(source.get(), builder);
154     bool ok = parser->parsePathDataFromSource(parsingMode, false);
155     parser->cleanup();
156
157     if (ok)
158         result->append(*appendedByteStream);
159
160     return ok;
161 }
162
163 bool buildPathFromByteStream(SVGPathByteStream* stream, Path& result)
164 {
165     ASSERT(stream);
166     if (stream->isEmpty())
167         return true;
168
169     SVGPathBuilder* builder = globalSVGPathBuilder(result);
170
171     auto source = std::make_unique<SVGPathByteStreamSource>(stream);
172     SVGPathParser* parser = globalSVGPathParser(source.get(), builder);
173     bool ok = parser->parsePathDataFromSource(NormalizedParsing);
174     parser->cleanup();
175     return ok;
176 }
177
178 bool buildSVGPathSegListFromByteStream(SVGPathByteStream* stream, SVGPathElement* element, SVGPathSegList& result, PathParsingMode parsingMode)
179 {
180     ASSERT(stream);
181     if (stream->isEmpty())
182         return true;
183
184     SVGPathSegListBuilder* builder = globalSVGPathSegListBuilder(element, parsingMode == NormalizedParsing ? PathSegNormalizedRole : PathSegUnalteredRole, result);
185
186     auto source = std::make_unique<SVGPathByteStreamSource>(stream);
187     SVGPathParser* parser = globalSVGPathParser(source.get(), builder);
188     bool ok = parser->parsePathDataFromSource(parsingMode);
189     parser->cleanup();
190     return ok;
191 }
192
193 bool buildStringFromByteStream(SVGPathByteStream* stream, String& result, PathParsingMode parsingMode)
194 {
195     ASSERT(stream);
196     if (stream->isEmpty())
197         return true;
198
199     SVGPathStringBuilder* builder = globalSVGPathStringBuilder();
200
201     auto source = std::make_unique<SVGPathByteStreamSource>(stream);
202     SVGPathParser* parser = globalSVGPathParser(source.get(), builder);
203     bool ok = parser->parsePathDataFromSource(parsingMode);
204     result = builder->result();
205     parser->cleanup();
206     return ok;
207 }
208
209 bool buildStringFromSVGPathSegList(const SVGPathSegList& list, String& result, PathParsingMode parsingMode)
210 {
211     result = String();
212     if (list.isEmpty())
213         return true;
214
215     SVGPathStringBuilder* builder = globalSVGPathStringBuilder();
216
217     auto source = std::make_unique<SVGPathSegListSource>(list);
218     SVGPathParser* parser = globalSVGPathParser(source.get(), builder);
219     bool ok = parser->parsePathDataFromSource(parsingMode);
220     result = builder->result();
221     parser->cleanup();
222     return ok;
223 }
224
225 bool buildSVGPathByteStreamFromString(const String& d, SVGPathByteStream* result, PathParsingMode parsingMode)
226 {
227     ASSERT(result);
228     result->clear();
229     if (d.isEmpty())
230         return true;
231
232     SVGPathByteStreamBuilder* builder = globalSVGPathByteStreamBuilder(result);
233
234     auto source = std::make_unique<SVGPathStringSource>(d);
235     SVGPathParser* parser = globalSVGPathParser(source.get(), builder);
236     bool ok = parser->parsePathDataFromSource(parsingMode);
237     parser->cleanup();
238     return ok;
239 }
240
241 bool buildAnimatedSVGPathByteStream(SVGPathByteStream* fromStream, SVGPathByteStream* toStream, SVGPathByteStream* result, float progress)
242 {
243     ASSERT(fromStream);
244     ASSERT(toStream);
245     ASSERT(result);
246     ASSERT(toStream != result);
247
248     result->clear();
249     if (toStream->isEmpty())
250         return true;
251
252     SVGPathByteStreamBuilder* builder = globalSVGPathByteStreamBuilder(result);
253
254     auto fromSource = std::make_unique<SVGPathByteStreamSource>(fromStream);
255     auto toSource = std::make_unique<SVGPathByteStreamSource>(toStream);
256     SVGPathBlender* blender = globalSVGPathBlender();
257     bool ok = blender->blendAnimatedPath(progress, fromSource.get(), toSource.get(), builder);
258     blender->cleanup();
259     return ok;
260 }
261
262 bool addToSVGPathByteStream(SVGPathByteStream* fromStream, SVGPathByteStream* byStream, unsigned repeatCount)
263 {
264     ASSERT(fromStream);
265     ASSERT(byStream);
266     if (fromStream->isEmpty() || byStream->isEmpty())
267         return true;
268
269     SVGPathByteStreamBuilder* builder = globalSVGPathByteStreamBuilder(fromStream);
270
271     auto fromStreamCopy = fromStream->copy();
272     fromStream->clear();
273
274     auto fromSource = std::make_unique<SVGPathByteStreamSource>(fromStreamCopy.get());
275     auto bySource = std::make_unique<SVGPathByteStreamSource>(byStream);
276     SVGPathBlender* blender = globalSVGPathBlender();
277     bool ok = blender->addAnimatedPath(fromSource.get(), bySource.get(), builder, repeatCount);
278     blender->cleanup();
279     return ok;
280 }
281
282 bool getSVGPathSegAtLengthFromSVGPathByteStream(SVGPathByteStream* stream, float length, unsigned& pathSeg)
283 {
284     ASSERT(stream);
285     if (stream->isEmpty())
286         return false;
287
288     PathTraversalState traversalState(PathTraversalState::Action::SegmentAtLength);
289     SVGPathTraversalStateBuilder* builder = globalSVGPathTraversalStateBuilder(traversalState, length);
290
291     auto source = std::make_unique<SVGPathByteStreamSource>(stream);
292     SVGPathParser* parser = globalSVGPathParser(source.get(), builder);
293     bool ok = parser->parsePathDataFromSource(NormalizedParsing);
294     pathSeg = builder->pathSegmentIndex();
295     parser->cleanup();
296     return ok;
297 }
298
299 bool getTotalLengthOfSVGPathByteStream(SVGPathByteStream* stream, float& totalLength)
300 {
301     ASSERT(stream);
302     if (stream->isEmpty())
303         return false;
304
305     PathTraversalState traversalState(PathTraversalState::Action::TotalLength);
306     SVGPathTraversalStateBuilder* builder = globalSVGPathTraversalStateBuilder(traversalState, 0);
307
308     auto source = std::make_unique<SVGPathByteStreamSource>(stream);
309     SVGPathParser* parser = globalSVGPathParser(source.get(), builder);
310     bool ok = parser->parsePathDataFromSource(NormalizedParsing);
311     totalLength = builder->totalLength();
312     parser->cleanup();
313     return ok;
314 }
315
316 bool getPointAtLengthOfSVGPathByteStream(SVGPathByteStream* stream, float length, SVGPoint& point)
317 {
318     ASSERT(stream);
319     if (stream->isEmpty())
320         return false;
321
322     PathTraversalState traversalState(PathTraversalState::Action::VectorAtLength);
323     SVGPathTraversalStateBuilder* builder = globalSVGPathTraversalStateBuilder(traversalState, length);
324
325     auto source = std::make_unique<SVGPathByteStreamSource>(stream);
326     SVGPathParser* parser = globalSVGPathParser(source.get(), builder);
327     bool ok = parser->parsePathDataFromSource(NormalizedParsing);
328     point = builder->currentPoint();
329     parser->cleanup();
330     return ok;
331 }
332
333 }