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, ExceptionCode
& ec
)
56 // FIXME : to be useful this will need to support non-normalized SVGPathSegLists
57 int len
= numberOfItems();
58 // FIXME: Eventually this will likely move to a "path applier"-like model, until then PathTraversalState is less useful as we could just use locals
59 PathTraversalState
traversalState(PathTraversalState::TraversalSegmentAtLength
);
60 for (int i
= 0; i
< len
; ++i
) {
61 SVGPathSeg
* segment
= getItem(i
, ec
).get();
64 float segmentLength
= 0;
65 switch (segment
->pathSegType()) {
66 case SVGPathSeg::PATHSEG_MOVETO_ABS
:
68 SVGPathSegMovetoAbs
* moveTo
= static_cast<SVGPathSegMovetoAbs
*>(segment
);
69 segmentLength
= traversalState
.moveTo(FloatPoint(moveTo
->x(), moveTo
->y()));
72 case SVGPathSeg::PATHSEG_LINETO_ABS
:
74 SVGPathSegLinetoAbs
* lineTo
= static_cast<SVGPathSegLinetoAbs
*>(segment
);
75 segmentLength
= traversalState
.lineTo(FloatPoint(lineTo
->x(), lineTo
->y()));
78 case SVGPathSeg::PATHSEG_CURVETO_CUBIC_ABS
:
80 SVGPathSegCurvetoCubicAbs
* curveTo
= static_cast<SVGPathSegCurvetoCubicAbs
*>(segment
);
81 segmentLength
= traversalState
.cubicBezierTo(FloatPoint(curveTo
->x1(), curveTo
->y1()),
82 FloatPoint(curveTo
->x2(), curveTo
->y2()),
83 FloatPoint(curveTo
->x(), curveTo
->y()));
86 case SVGPathSeg::PATHSEG_CLOSEPATH
:
87 segmentLength
= traversalState
.closeSubpath();
90 ASSERT(false); // FIXME: This only works with normalized/processed path data.
93 traversalState
.m_totalLength
+= segmentLength
;
94 if ((traversalState
.m_action
== PathTraversalState::TraversalSegmentAtLength
)
95 && (traversalState
.m_totalLength
> traversalState
.m_desiredLength
)) {
96 return traversalState
.m_segmentIndex
;
98 traversalState
.m_segmentIndex
++;
101 return 0; // The SVG spec is unclear as to what to return when the distance is not on the path
104 Path
SVGPathSegList::toPathData()
106 // FIXME : This should also support non-normalized PathSegLists
108 int len
= numberOfItems();
109 ExceptionCode ec
= 0;
110 for (int i
= 0; i
< len
; ++i
) {
111 SVGPathSeg
* segment
= getItem(i
, ec
).get();
114 switch (segment
->pathSegType()) {
115 case SVGPathSeg::PATHSEG_MOVETO_ABS
:
117 SVGPathSegMovetoAbs
* moveTo
= static_cast<SVGPathSegMovetoAbs
*>(segment
);
118 pathData
.moveTo(FloatPoint(moveTo
->x(), moveTo
->y()));
121 case SVGPathSeg::PATHSEG_LINETO_ABS
:
123 SVGPathSegLinetoAbs
* lineTo
= static_cast<SVGPathSegLinetoAbs
*>(segment
);
124 pathData
.addLineTo(FloatPoint(lineTo
->x(), lineTo
->y()));
127 case SVGPathSeg::PATHSEG_CURVETO_CUBIC_ABS
:
129 SVGPathSegCurvetoCubicAbs
* curveTo
= static_cast<SVGPathSegCurvetoCubicAbs
*>(segment
);
130 pathData
.addBezierCurveTo(FloatPoint(curveTo
->x1(), curveTo
->y1()),
131 FloatPoint(curveTo
->x2(), curveTo
->y2()),
132 FloatPoint(curveTo
->x(), curveTo
->y()));
135 case SVGPathSeg::PATHSEG_CLOSEPATH
:
136 pathData
.closeSubpath();
139 ASSERT(false); // FIXME: This only works with normalized/processed path data.
147 static inline float blendFunc(float from
, float to
, float progress
)
149 return (to
- from
) * progress
+ from
;
152 #define BLENDPATHSEG1(class, attr1) \
153 class::create(blendFunc(static_cast<class*>(from)->attr1(), static_cast<class*>(to)->attr1(), progress))
155 #define BLENDPATHSEG2(class, attr1, attr2) \
156 class::create(blendFunc(static_cast<class*>(from)->attr1(), static_cast<class*>(to)->attr1(), progress), \
157 blendFunc(static_cast<class*>(from)->attr2(), static_cast<class*>(to)->attr2(), progress))
159 #define BLENDPATHSEG4(class, attr1, attr2, attr3, attr4) \
160 class::create(blendFunc(static_cast<class*>(from)->attr1(), static_cast<class*>(to)->attr1(), progress), \
161 blendFunc(static_cast<class*>(from)->attr2(), static_cast<class*>(to)->attr2(), progress), \
162 blendFunc(static_cast<class*>(from)->attr3(), static_cast<class*>(to)->attr3(), progress), \
163 blendFunc(static_cast<class*>(from)->attr4(), static_cast<class*>(to)->attr4(), progress))
165 #define BLENDPATHSEG6(class, attr1, attr2, attr3, attr4, attr5, attr6) \
166 class::create(blendFunc(static_cast<class*>(from)->attr1(), static_cast<class*>(to)->attr1(), progress), \
167 blendFunc(static_cast<class*>(from)->attr2(), static_cast<class*>(to)->attr2(), progress), \
168 blendFunc(static_cast<class*>(from)->attr3(), static_cast<class*>(to)->attr3(), progress), \
169 blendFunc(static_cast<class*>(from)->attr4(), static_cast<class*>(to)->attr4(), progress), \
170 blendFunc(static_cast<class*>(from)->attr5(), static_cast<class*>(to)->attr5(), progress), \
171 blendFunc(static_cast<class*>(from)->attr6(), static_cast<class*>(to)->attr6(), progress))
173 #define BLENDPATHSEG7(class, attr1, attr2, attr3, attr4, attr5, bool1, bool2) \
174 class::create(blendFunc(static_cast<class*>(from)->attr1(), static_cast<class*>(to)->attr1(), progress), \
175 blendFunc(static_cast<class*>(from)->attr2(), static_cast<class*>(to)->attr2(), progress), \
176 blendFunc(static_cast<class*>(from)->attr3(), static_cast<class*>(to)->attr3(), progress), \
177 blendFunc(static_cast<class*>(from)->attr4(), static_cast<class*>(to)->attr4(), progress), \
178 blendFunc(static_cast<class*>(from)->attr5(), static_cast<class*>(to)->attr5(), progress), \
179 static_cast<bool>(blendFunc(static_cast<class*>(from)->bool1(), static_cast<class*>(to)->bool1(), progress)), \
180 static_cast<bool>(blendFunc(static_cast<class*>(from)->bool2(), static_cast<class*>(to)->bool2(), progress)))
182 PassRefPtr
<SVGPathSegList
> SVGPathSegList::createAnimated(const SVGPathSegList
* fromList
, const SVGPathSegList
* toList
, float progress
)
184 unsigned itemCount
= fromList
->numberOfItems();
185 if (!itemCount
|| itemCount
!= toList
->numberOfItems())
187 RefPtr
<SVGPathSegList
> result
= create(fromList
->associatedAttributeName());
188 ExceptionCode ec
= 0;
189 for (unsigned n
= 0; n
< itemCount
; ++n
) {
190 SVGPathSeg
* from
= fromList
->getItem(n
, ec
).get();
193 SVGPathSeg
* to
= toList
->getItem(n
, ec
).get();
196 if (from
->pathSegType() == SVGPathSeg::PATHSEG_UNKNOWN
|| from
->pathSegType() != to
->pathSegType())
198 RefPtr
<SVGPathSeg
> segment
= 0;
199 switch (static_cast<SVGPathSeg::SVGPathSegType
>(from
->pathSegType())) {
200 case SVGPathSeg::PATHSEG_CLOSEPATH
:
201 segment
= SVGPathSegClosePath::create();
203 case SVGPathSeg::PATHSEG_LINETO_HORIZONTAL_ABS
:
204 segment
= BLENDPATHSEG1(SVGPathSegLinetoHorizontalAbs
, x
);
206 case SVGPathSeg::PATHSEG_LINETO_HORIZONTAL_REL
:
207 segment
= BLENDPATHSEG1(SVGPathSegLinetoHorizontalRel
, x
);
209 case SVGPathSeg::PATHSEG_LINETO_VERTICAL_ABS
:
210 segment
= BLENDPATHSEG1(SVGPathSegLinetoVerticalAbs
, y
);
212 case SVGPathSeg::PATHSEG_LINETO_VERTICAL_REL
:
213 segment
= BLENDPATHSEG1(SVGPathSegLinetoVerticalRel
, y
);
215 case SVGPathSeg::PATHSEG_MOVETO_ABS
:
216 segment
= BLENDPATHSEG2(SVGPathSegMovetoAbs
, x
, y
);
218 case SVGPathSeg::PATHSEG_MOVETO_REL
:
219 segment
= BLENDPATHSEG2(SVGPathSegMovetoRel
, x
, y
);
221 case SVGPathSeg::PATHSEG_LINETO_ABS
:
222 segment
= BLENDPATHSEG2(SVGPathSegLinetoAbs
, x
, y
);
224 case SVGPathSeg::PATHSEG_LINETO_REL
:
225 segment
= BLENDPATHSEG2(SVGPathSegLinetoRel
, x
, y
);
227 case SVGPathSeg::PATHSEG_CURVETO_CUBIC_ABS
:
228 segment
= BLENDPATHSEG6(SVGPathSegCurvetoCubicAbs
, x
, y
, x1
, y1
, x2
, y2
);
230 case SVGPathSeg::PATHSEG_CURVETO_CUBIC_REL
:
231 segment
= BLENDPATHSEG6(SVGPathSegCurvetoCubicRel
, x
, y
, x1
, y1
, x2
, y2
);
233 case SVGPathSeg::PATHSEG_CURVETO_CUBIC_SMOOTH_ABS
:
234 segment
= BLENDPATHSEG4(SVGPathSegCurvetoCubicSmoothAbs
, x
, y
, x2
, y2
);
236 case SVGPathSeg::PATHSEG_CURVETO_CUBIC_SMOOTH_REL
:
237 segment
= BLENDPATHSEG4(SVGPathSegCurvetoCubicSmoothRel
, x
, y
, x2
, y2
);
239 case SVGPathSeg::PATHSEG_CURVETO_QUADRATIC_ABS
:
240 segment
= BLENDPATHSEG4(SVGPathSegCurvetoQuadraticAbs
, x
, y
, x1
, y1
);
242 case SVGPathSeg::PATHSEG_CURVETO_QUADRATIC_REL
:
243 segment
= BLENDPATHSEG4(SVGPathSegCurvetoQuadraticRel
, x
, y
, x1
, y1
);
245 case SVGPathSeg::PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS
:
246 segment
= BLENDPATHSEG2(SVGPathSegCurvetoQuadraticSmoothAbs
, x
, y
);
248 case SVGPathSeg::PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL
:
249 segment
= BLENDPATHSEG2(SVGPathSegCurvetoQuadraticSmoothRel
, x
, y
);
251 case SVGPathSeg::PATHSEG_ARC_ABS
:
252 segment
= BLENDPATHSEG7(SVGPathSegArcAbs
, x
, y
, r1
, r2
, angle
, largeArcFlag
, sweepFlag
);
254 case SVGPathSeg::PATHSEG_ARC_REL
:
255 segment
= BLENDPATHSEG7(SVGPathSegArcRel
, x
, y
, r1
, r2
, angle
, largeArcFlag
, sweepFlag
);
257 case SVGPathSeg::PATHSEG_UNKNOWN
:
258 ASSERT_NOT_REACHED();
260 result
->appendItem(segment
, ec
);
264 return result
.release();
269 #endif // ENABLE(SVG)