2
Copyright (C) 2004, 2005, 2006, 2007, 2008 Nikolas Zimmermann <zimmermann@kde.org>
3
2004, 2005 Rob Buis <buis@kde.org>
4
Copyright (C) 2007 Eric Seidel <eric@webkit.org>
6
This file is part of the WebKit project
8
This library is free software; you can redistribute it and/or
9
modify it under the terms of the GNU Library General Public
10
License as published by the Free Software Foundation; either
11
version 2 of the License, or (at your option) any later version.
13
This library is distributed in the hope that it will be useful,
14
but WITHOUT ANY WARRANTY; without even the implied warranty of
15
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16
Library General Public License for more details.
18
You should have received a copy of the GNU Library General Public License
19
along with this library; see the file COPYING.LIB. If not, write to
20
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21
Boston, MA 02110-1301, USA.
27
#include "SVGPathSegList.h"
29
#include "FloatPoint.h"
31
#include "PathTraversalState.h"
32
#include "SVGPathSegArc.h"
33
#include "SVGPathSegClosePath.h"
34
#include "SVGPathSegMoveto.h"
35
#include "SVGPathSegLineto.h"
36
#include "SVGPathSegLinetoHorizontal.h"
37
#include "SVGPathSegLinetoVertical.h"
38
#include "SVGPathSegCurvetoCubic.h"
39
#include "SVGPathSegCurvetoCubicSmooth.h"
40
#include "SVGPathSegCurvetoQuadratic.h"
41
#include "SVGPathSegCurvetoQuadraticSmooth.h"
45
SVGPathSegList::SVGPathSegList(const QualifiedName& attributeName)
46
: SVGList<RefPtr<SVGPathSeg> >(attributeName)
50
SVGPathSegList::~SVGPathSegList()
54
unsigned SVGPathSegList::getPathSegAtLength(double)
56
// FIXME : to be useful this will need to support non-normalized SVGPathSegLists
58
int len = numberOfItems();
59
// FIXME: Eventually this will likely move to a "path applier"-like model, until then PathTraversalState is less useful as we could just use locals
60
PathTraversalState traversalState(PathTraversalState::TraversalSegmentAtLength);
61
for (int i = 0; i < len; ++i) {
62
SVGPathSeg* segment = getItem(i, ec).get();
63
float segmentLength = 0;
64
switch (segment->pathSegType()) {
65
case SVGPathSeg::PATHSEG_MOVETO_ABS:
67
SVGPathSegMovetoAbs* moveTo = static_cast<SVGPathSegMovetoAbs*>(segment);
68
segmentLength = traversalState.moveTo(FloatPoint(moveTo->x(), moveTo->y()));
71
case SVGPathSeg::PATHSEG_LINETO_ABS:
73
SVGPathSegLinetoAbs* lineTo = static_cast<SVGPathSegLinetoAbs*>(segment);
74
segmentLength = traversalState.lineTo(FloatPoint(lineTo->x(), lineTo->y()));
77
case SVGPathSeg::PATHSEG_CURVETO_CUBIC_ABS:
79
SVGPathSegCurvetoCubicAbs* curveTo = static_cast<SVGPathSegCurvetoCubicAbs*>(segment);
80
segmentLength = traversalState.cubicBezierTo(FloatPoint(curveTo->x1(), curveTo->y1()),
81
FloatPoint(curveTo->x2(), curveTo->y2()),
82
FloatPoint(curveTo->x(), curveTo->y()));
85
case SVGPathSeg::PATHSEG_CLOSEPATH:
86
segmentLength = traversalState.closeSubpath();
89
ASSERT(false); // FIXME: This only works with normalized/processed path data.
92
traversalState.m_totalLength += segmentLength;
93
if ((traversalState.m_action == PathTraversalState::TraversalSegmentAtLength)
94
&& (traversalState.m_totalLength > traversalState.m_desiredLength)) {
95
return traversalState.m_segmentIndex;
97
traversalState.m_segmentIndex++;
100
return 0; // The SVG spec is unclear as to what to return when the distance is not on the path
103
Path SVGPathSegList::toPathData()
105
// FIXME : This should also support non-normalized PathSegLists
107
ExceptionCode ec = 0;
108
int len = numberOfItems();
109
for (int i = 0; i < len; ++i) {
110
SVGPathSeg* segment = getItem(i, ec).get();;
111
switch (segment->pathSegType())
113
case SVGPathSeg::PATHSEG_MOVETO_ABS:
115
SVGPathSegMovetoAbs* moveTo = static_cast<SVGPathSegMovetoAbs*>(segment);
116
pathData.moveTo(FloatPoint(moveTo->x(), moveTo->y()));
119
case SVGPathSeg::PATHSEG_LINETO_ABS:
121
SVGPathSegLinetoAbs* lineTo = static_cast<SVGPathSegLinetoAbs*>(segment);
122
pathData.addLineTo(FloatPoint(lineTo->x(), lineTo->y()));
125
case SVGPathSeg::PATHSEG_CURVETO_CUBIC_ABS:
127
SVGPathSegCurvetoCubicAbs* curveTo = static_cast<SVGPathSegCurvetoCubicAbs*>(segment);
128
pathData.addBezierCurveTo(FloatPoint(curveTo->x1(), curveTo->y1()),
129
FloatPoint(curveTo->x2(), curveTo->y2()),
130
FloatPoint(curveTo->x(), curveTo->y()));
133
case SVGPathSeg::PATHSEG_CLOSEPATH:
134
pathData.closeSubpath();
137
ASSERT(false); // FIXME: This only works with normalized/processed path data.
145
static inline float blendFunc(float from, float to, float progress)
147
return (to - from) * progress + from;
150
#define BLENDPATHSEG1(class, attr1) \
151
class::create(blendFunc(static_cast<class*>(from)->attr1(), static_cast<class*>(to)->attr1(), progress))
153
#define BLENDPATHSEG2(class, attr1, attr2) \
154
class::create(blendFunc(static_cast<class*>(from)->attr1(), static_cast<class*>(to)->attr1(), progress), \
155
blendFunc(static_cast<class*>(from)->attr2(), static_cast<class*>(to)->attr2(), progress))
157
#define BLENDPATHSEG4(class, attr1, attr2, attr3, attr4) \
158
class::create(blendFunc(static_cast<class*>(from)->attr1(), static_cast<class*>(to)->attr1(), progress), \
159
blendFunc(static_cast<class*>(from)->attr2(), static_cast<class*>(to)->attr2(), progress), \
160
blendFunc(static_cast<class*>(from)->attr3(), static_cast<class*>(to)->attr3(), progress), \
161
blendFunc(static_cast<class*>(from)->attr4(), static_cast<class*>(to)->attr4(), progress))
163
#define BLENDPATHSEG6(class, attr1, attr2, attr3, attr4, attr5, attr6) \
164
class::create(blendFunc(static_cast<class*>(from)->attr1(), static_cast<class*>(to)->attr1(), progress), \
165
blendFunc(static_cast<class*>(from)->attr2(), static_cast<class*>(to)->attr2(), progress), \
166
blendFunc(static_cast<class*>(from)->attr3(), static_cast<class*>(to)->attr3(), progress), \
167
blendFunc(static_cast<class*>(from)->attr4(), static_cast<class*>(to)->attr4(), progress), \
168
blendFunc(static_cast<class*>(from)->attr5(), static_cast<class*>(to)->attr5(), progress), \
169
blendFunc(static_cast<class*>(from)->attr6(), static_cast<class*>(to)->attr6(), progress))
171
#define BLENDPATHSEG7(class, attr1, attr2, attr3, attr4, attr5, bool1, bool2) \
172
class::create(blendFunc(static_cast<class*>(from)->attr1(), static_cast<class*>(to)->attr1(), progress), \
173
blendFunc(static_cast<class*>(from)->attr2(), static_cast<class*>(to)->attr2(), progress), \
174
blendFunc(static_cast<class*>(from)->attr3(), static_cast<class*>(to)->attr3(), progress), \
175
blendFunc(static_cast<class*>(from)->attr4(), static_cast<class*>(to)->attr4(), progress), \
176
blendFunc(static_cast<class*>(from)->attr5(), static_cast<class*>(to)->attr5(), progress), \
177
static_cast<bool>(blendFunc(static_cast<class*>(from)->bool1(), static_cast<class*>(to)->bool1(), progress)), \
178
static_cast<bool>(blendFunc(static_cast<class*>(from)->bool2(), static_cast<class*>(to)->bool2(), progress)))
180
PassRefPtr<SVGPathSegList> SVGPathSegList::createAnimated(const SVGPathSegList* fromList, const SVGPathSegList* toList, float progress)
182
unsigned itemCount = fromList->numberOfItems();
183
if (!itemCount || itemCount != toList->numberOfItems())
185
RefPtr<SVGPathSegList> result = create(fromList->associatedAttributeName());
187
for (unsigned n = 0; n < itemCount; ++n) {
188
SVGPathSeg* from = fromList->getItem(n, ec).get();
189
SVGPathSeg* to = toList->getItem(n, ec).get();
190
if (from->pathSegType() == SVGPathSeg::PATHSEG_UNKNOWN || from->pathSegType() != to->pathSegType())
192
RefPtr<SVGPathSeg> segment = 0;
193
switch (static_cast<SVGPathSeg::SVGPathSegType>(from->pathSegType())) {
194
case SVGPathSeg::PATHSEG_CLOSEPATH:
195
segment = SVGPathSegClosePath::create();
197
case SVGPathSeg::PATHSEG_LINETO_HORIZONTAL_ABS:
198
segment = BLENDPATHSEG1(SVGPathSegLinetoHorizontalAbs, x);
200
case SVGPathSeg::PATHSEG_LINETO_HORIZONTAL_REL:
201
segment = BLENDPATHSEG1(SVGPathSegLinetoHorizontalRel, x);
203
case SVGPathSeg::PATHSEG_LINETO_VERTICAL_ABS:
204
segment = BLENDPATHSEG1(SVGPathSegLinetoVerticalAbs, y);
206
case SVGPathSeg::PATHSEG_LINETO_VERTICAL_REL:
207
segment = BLENDPATHSEG1(SVGPathSegLinetoVerticalRel, y);
209
case SVGPathSeg::PATHSEG_MOVETO_ABS:
210
segment = BLENDPATHSEG2(SVGPathSegMovetoAbs, x, y);
212
case SVGPathSeg::PATHSEG_MOVETO_REL:
213
segment = BLENDPATHSEG2(SVGPathSegMovetoRel, x, y);
215
case SVGPathSeg::PATHSEG_LINETO_ABS:
216
segment = BLENDPATHSEG2(SVGPathSegLinetoAbs, x, y);
218
case SVGPathSeg::PATHSEG_LINETO_REL:
219
segment = BLENDPATHSEG2(SVGPathSegLinetoRel, x, y);
221
case SVGPathSeg::PATHSEG_CURVETO_CUBIC_ABS:
222
segment = BLENDPATHSEG6(SVGPathSegCurvetoCubicAbs, x, y, x1, y1, x2, y2);
224
case SVGPathSeg::PATHSEG_CURVETO_CUBIC_REL:
225
segment = BLENDPATHSEG6(SVGPathSegCurvetoCubicRel, x, y, x1, y1, x2, y2);
227
case SVGPathSeg::PATHSEG_CURVETO_CUBIC_SMOOTH_ABS:
228
segment = BLENDPATHSEG4(SVGPathSegCurvetoCubicSmoothAbs, x, y, x2, y2);
230
case SVGPathSeg::PATHSEG_CURVETO_CUBIC_SMOOTH_REL:
231
segment = BLENDPATHSEG4(SVGPathSegCurvetoCubicSmoothRel, x, y, x2, y2);
233
case SVGPathSeg::PATHSEG_CURVETO_QUADRATIC_ABS:
234
segment = BLENDPATHSEG4(SVGPathSegCurvetoQuadraticAbs, x, y, x1, y1);
236
case SVGPathSeg::PATHSEG_CURVETO_QUADRATIC_REL:
237
segment = BLENDPATHSEG4(SVGPathSegCurvetoQuadraticRel, x, y, x1, y1);
239
case SVGPathSeg::PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS:
240
segment = BLENDPATHSEG2(SVGPathSegCurvetoQuadraticSmoothAbs, x, y);
242
case SVGPathSeg::PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL:
243
segment = BLENDPATHSEG2(SVGPathSegCurvetoQuadraticSmoothRel, x, y);
245
case SVGPathSeg::PATHSEG_ARC_ABS:
246
segment = BLENDPATHSEG7(SVGPathSegArcAbs, x, y, r1, r2, angle, largeArcFlag, sweepFlag);
248
case SVGPathSeg::PATHSEG_ARC_REL:
249
segment = BLENDPATHSEG7(SVGPathSegArcRel, x, y, r1, r2, angle, largeArcFlag, sweepFlag);
251
case SVGPathSeg::PATHSEG_UNKNOWN:
252
ASSERT_NOT_REACHED();
254
result->appendItem(segment, ec);
256
return result.release();
261
#endif // ENABLE(SVG)