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
36namespace WebCore {
37
38static 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
48static 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
60static 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
70static 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
79static 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
90static 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
101static 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
110bool 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
124bool 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
140bool 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
162bool 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
177bool 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
192bool 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
208bool 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
224bool 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
240bool 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
261bool 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
281bool 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
298bool 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
315bool 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