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 blink {
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 SVGPathByteStreamBuilder* globalSVGPathByteStreamBuilder(SVGPathByteStream* result)
49{
50    static SVGPathByteStreamBuilder* s_builder = 0;
51    if (!s_builder)
52        s_builder = new SVGPathByteStreamBuilder;
53
54    s_builder->setCurrentByteStream(result);
55    return s_builder;
56}
57
58static SVGPathStringBuilder* globalSVGPathStringBuilder()
59{
60    static SVGPathStringBuilder* s_builder = 0;
61    if (!s_builder)
62        s_builder = new SVGPathStringBuilder;
63
64    return s_builder;
65}
66
67static SVGPathTraversalStateBuilder* globalSVGPathTraversalStateBuilder(PathTraversalState& traversalState, float length)
68{
69    static SVGPathTraversalStateBuilder* s_builder = 0;
70    if (!s_builder)
71        s_builder = new SVGPathTraversalStateBuilder;
72
73    s_builder->setCurrentTraversalState(&traversalState);
74    s_builder->setDesiredLength(length);
75    return s_builder;
76}
77
78static SVGPathParser* globalSVGPathParser(SVGPathSource* source, SVGPathConsumer* consumer)
79{
80    static SVGPathParser* s_parser = 0;
81    if (!s_parser)
82        s_parser = new SVGPathParser;
83
84    s_parser->setCurrentSource(source);
85    s_parser->setCurrentConsumer(consumer);
86    return s_parser;
87}
88
89static SVGPathBlender* globalSVGPathBlender()
90{
91    static SVGPathBlender* s_blender = 0;
92    if (!s_blender)
93        s_blender = new SVGPathBlender;
94
95    return s_blender;
96}
97
98bool buildPathFromString(const String& d, Path& result)
99{
100    if (d.isEmpty())
101        return true;
102
103    SVGPathBuilder* builder = globalSVGPathBuilder(result);
104
105    OwnPtr<SVGPathStringSource> source = SVGPathStringSource::create(d);
106    SVGPathParser* parser = globalSVGPathParser(source.get(), builder);
107    bool ok = parser->parsePathDataFromSource(NormalizedParsing);
108    parser->cleanup();
109    return ok;
110}
111
112bool buildPathFromByteStream(const SVGPathByteStream* stream, Path& result)
113{
114    ASSERT(stream);
115    if (stream->isEmpty())
116        return true;
117
118    SVGPathBuilder* builder = globalSVGPathBuilder(result);
119
120    SVGPathByteStreamSource source(stream);
121    SVGPathParser* parser = globalSVGPathParser(&source, builder);
122    bool ok = parser->parsePathDataFromSource(NormalizedParsing);
123    parser->cleanup();
124    return ok;
125}
126
127bool buildStringFromByteStream(const SVGPathByteStream* stream, String& result, PathParsingMode parsingMode)
128{
129    ASSERT(stream);
130    if (stream->isEmpty())
131        return true;
132
133    SVGPathStringBuilder* builder = globalSVGPathStringBuilder();
134
135    SVGPathByteStreamSource source(stream);
136    SVGPathParser* parser = globalSVGPathParser(&source, builder);
137    bool ok = parser->parsePathDataFromSource(parsingMode);
138    result = builder->result();
139    parser->cleanup();
140    return ok;
141}
142
143bool buildSVGPathByteStreamFromString(const String& d, SVGPathByteStream* result, PathParsingMode parsingMode)
144{
145    ASSERT(result);
146    result->clear();
147    if (d.isEmpty())
148        return true;
149
150    // The string length is typically a minor overestimate of eventual byte stream size, so it avoids us a lot of reallocs.
151    result->reserveInitialCapacity(d.length());
152
153    SVGPathByteStreamBuilder* builder = globalSVGPathByteStreamBuilder(result);
154
155    OwnPtr<SVGPathStringSource> source = SVGPathStringSource::create(d);
156    SVGPathParser* parser = globalSVGPathParser(source.get(), builder);
157    bool ok = parser->parsePathDataFromSource(parsingMode);
158    parser->cleanup();
159
160    result->shrinkToFit();
161
162    return ok;
163}
164
165bool addToSVGPathByteStream(SVGPathByteStream* fromStream, const SVGPathByteStream* byStream, unsigned repeatCount)
166{
167    ASSERT(fromStream);
168    ASSERT(byStream);
169    if (fromStream->isEmpty() || byStream->isEmpty())
170        return true;
171
172    SVGPathByteStreamBuilder* builder = globalSVGPathByteStreamBuilder(fromStream);
173
174    OwnPtr<SVGPathByteStream> fromStreamCopy = fromStream->copy();
175    fromStream->clear();
176
177    SVGPathByteStreamSource fromSource(fromStreamCopy.get());
178    SVGPathByteStreamSource bySource(byStream);
179    SVGPathBlender* blender = globalSVGPathBlender();
180    bool ok = blender->addAnimatedPath(&fromSource, &bySource, builder, repeatCount);
181    blender->cleanup();
182    return ok;
183}
184
185bool getSVGPathSegAtLengthFromSVGPathByteStream(const SVGPathByteStream* stream, float length, unsigned& pathSeg)
186{
187    ASSERT(stream);
188    if (stream->isEmpty())
189        return false;
190
191    PathTraversalState traversalState(PathTraversalState::TraversalSegmentAtLength);
192    SVGPathTraversalStateBuilder* builder = globalSVGPathTraversalStateBuilder(traversalState, length);
193
194    SVGPathByteStreamSource source(stream);
195    SVGPathParser* parser = globalSVGPathParser(&source, builder);
196    bool ok = parser->parsePathDataFromSource(NormalizedParsing);
197    pathSeg = builder->pathSegmentIndex();
198    parser->cleanup();
199    return ok;
200}
201
202bool getTotalLengthOfSVGPathByteStream(const SVGPathByteStream* stream, float& totalLength)
203{
204    ASSERT(stream);
205    if (stream->isEmpty())
206        return false;
207
208    PathTraversalState traversalState(PathTraversalState::TraversalTotalLength);
209    SVGPathTraversalStateBuilder* builder = globalSVGPathTraversalStateBuilder(traversalState, 0);
210
211    SVGPathByteStreamSource source(stream);
212    SVGPathParser* parser = globalSVGPathParser(&source, builder);
213    bool ok = parser->parsePathDataFromSource(NormalizedParsing);
214    totalLength = builder->totalLength();
215    parser->cleanup();
216    return ok;
217}
218
219bool getPointAtLengthOfSVGPathByteStream(const SVGPathByteStream* stream, float length, FloatPoint& point)
220{
221    ASSERT(stream);
222    if (stream->isEmpty())
223        return false;
224
225    PathTraversalState traversalState(PathTraversalState::TraversalPointAtLength);
226    SVGPathTraversalStateBuilder* builder = globalSVGPathTraversalStateBuilder(traversalState, length);
227
228    SVGPathByteStreamSource source(stream);
229    SVGPathParser* parser = globalSVGPathParser(&source, builder);
230    bool ok = parser->parsePathDataFromSource(NormalizedParsing);
231    point = builder->currentPoint();
232    parser->cleanup();
233    return ok;
234}
235
236}
237