2 Copyright (C) 2007 Eric Seidel <eric@webkit.org>
3 (C) 2007 Rob Buis <buis@kde.org>
4 Copyright (C) 2008 Apple Inc. All Rights Reserved.
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.
25 #if ENABLE(SVG) && ENABLE(SVG_ANIMATION)
26 #include "SVGAnimateMotionElement.h"
28 #include "RenderObject.h"
29 #include "SVGElementInstance.h"
30 #include "SVGMPathElement.h"
31 #include "SVGParserUtilities.h"
32 #include "SVGPathElement.h"
33 #include "SVGTransformList.h"
38 using namespace SVGNames
;
40 SVGAnimateMotionElement::SVGAnimateMotionElement(const QualifiedName
& tagName
, Document
* doc
)
41 : SVGAnimationElement(tagName
, doc
)
42 , m_baseIndexInTransformList(0)
47 SVGAnimateMotionElement::~SVGAnimateMotionElement()
51 bool SVGAnimateMotionElement::hasValidTarget() const
53 if (!SVGAnimationElement::hasValidTarget())
55 SVGElement
* targetElement
= this->targetElement();
56 if (!targetElement
->isStyledTransformable() && !targetElement
->hasTagName(SVGNames::textTag
))
58 // Spec: SVG 1.1 section 19.2.15
59 if (targetElement
->hasTagName(gTag
)
60 || targetElement
->hasTagName(defsTag
)
61 || targetElement
->hasTagName(useTag
)
62 || targetElement
->hasTagName(imageTag
)
63 || targetElement
->hasTagName(switchTag
)
64 || targetElement
->hasTagName(pathTag
)
65 || targetElement
->hasTagName(rectTag
)
66 || targetElement
->hasTagName(circleTag
)
67 || targetElement
->hasTagName(ellipseTag
)
68 || targetElement
->hasTagName(lineTag
)
69 || targetElement
->hasTagName(polylineTag
)
70 || targetElement
->hasTagName(polygonTag
)
71 || targetElement
->hasTagName(textTag
)
72 || targetElement
->hasTagName(clipPathTag
)
73 || targetElement
->hasTagName(maskTag
)
74 || targetElement
->hasTagName(aTag
)
75 #if ENABLE(SVG_FOREIGN_OBJECT)
76 || targetElement
->hasTagName(foreignObjectTag
)
83 void SVGAnimateMotionElement::parseMappedAttribute(MappedAttribute
* attr
)
85 if (attr
->name() == SVGNames::pathAttr
) {
87 pathFromSVGData(m_path
, attr
->value());
89 SVGAnimationElement::parseMappedAttribute(attr
);
92 SVGAnimateMotionElement::RotateMode
SVGAnimateMotionElement::rotateMode() const
94 static const AtomicString
autoVal("auto");
95 static const AtomicString
autoReverse("auto-reverse");
96 String rotate
= getAttribute(SVGNames::rotateAttr
);
97 if (rotate
== autoVal
)
99 if (rotate
== autoReverse
)
100 return RotateAutoReverse
;
104 Path
SVGAnimateMotionElement::animationPath() const
106 for (Node
* child
= firstChild(); child
; child
= child
->nextSibling()) {
107 if (child
->hasTagName(SVGNames::mpathTag
)) {
108 SVGMPathElement
* mPath
= static_cast<SVGMPathElement
*>(child
);
109 SVGPathElement
* pathElement
= mPath
->pathElement();
111 return pathElement
->toPathData();
115 if (hasAttribute(SVGNames::pathAttr
))
120 static bool parsePoint(const String
& s
, FloatPoint
& point
)
124 const UChar
* cur
= s
.characters();
125 const UChar
* end
= cur
+ s
.length();
127 if (!skipOptionalSpaces(cur
, end
))
131 if (!parseNumber(cur
, end
, x
))
135 if (!parseNumber(cur
, end
, y
))
138 point
= FloatPoint(x
, y
);
140 // disallow anything except spaces at the end
141 return !skipOptionalSpaces(cur
, end
);
144 void SVGAnimateMotionElement::resetToBaseValue(const String
&)
146 if (!hasValidTarget())
148 SVGElement
* target
= targetElement();
149 AffineTransform
* transform
= target
->supplementalTransform();
155 bool SVGAnimateMotionElement::calculateFromAndToValues(const String
& fromString
, const String
& toString
)
157 parsePoint(fromString
, m_fromPoint
);
158 parsePoint(toString
, m_toPoint
);
162 bool SVGAnimateMotionElement::calculateFromAndByValues(const String
& fromString
, const String
& byString
)
164 parsePoint(fromString
, m_fromPoint
);
166 parsePoint(byString
, byPoint
);
167 m_toPoint
= FloatPoint(m_fromPoint
.x() + byPoint
.x(), m_fromPoint
.y() + byPoint
.y());
171 void SVGAnimateMotionElement::calculateAnimatedValue(float percentage
, unsigned repeat
, SVGSMILElement
*)
173 SVGElement
* target
= targetElement();
176 AffineTransform
* transform
= target
->supplementalTransform();
183 // FIXME: Implement accumulate.
185 if (animationMode() == PathAnimation
) {
186 ASSERT(!animationPath().isEmpty());
187 Path path
= animationPath();
188 float positionOnPath
= path
.length() * percentage
;
190 FloatPoint position
= path
.pointAtLength(positionOnPath
, ok
);
192 transform
->translate(position
.x(), position
.y());
193 RotateMode rotateMode
= this->rotateMode();
194 if (rotateMode
== RotateAuto
|| rotateMode
== RotateAutoReverse
) {
195 float angle
= path
.normalAngleAtLength(positionOnPath
, ok
);
196 if (rotateMode
== RotateAutoReverse
)
198 transform
->rotate(angle
);
203 FloatSize diff
= m_toPoint
- m_fromPoint
;
204 transform
->translate(diff
.width() * percentage
+ m_fromPoint
.x(), diff
.height() * percentage
+ m_fromPoint
.y());
207 void SVGAnimateMotionElement::applyResultsToTarget()
209 // We accumulate to the target element transform list so there is not much to do here.
210 SVGElement
* targetElement
= this->targetElement();
211 if (targetElement
&& targetElement
->renderer())
212 targetElement
->renderer()->setNeedsLayout(true);
214 // ...except in case where we have additional instances in <use> trees.
215 HashSet
<SVGElementInstance
*>* instances
= document()->accessSVGExtensions()->instancesForElement(targetElement
);
218 HashSet
<SVGElementInstance
*>::iterator end
= instances
->end();
219 for (HashSet
<SVGElementInstance
*>::iterator it
= instances
->begin(); it
!= end
; ++it
) {
220 SVGElement
* shadowTreeElement
= (*it
)->shadowTreeElement();
221 ASSERT(shadowTreeElement
);
222 AffineTransform
* transform
= shadowTreeElement
->supplementalTransform();
223 AffineTransform
* t
= targetElement
->supplementalTransform();
224 transform
->setMatrix(t
->a(), t
->b(), t
->c(), t
->d(), t
->e(), t
->f());
225 if (shadowTreeElement
->renderer())
226 shadowTreeElement
->renderer()->setNeedsLayout(true);
230 float SVGAnimateMotionElement::calculateDistance(const String
& fromString
, const String
& toString
)
234 if (!parsePoint(fromString
, from
))
236 if (!parsePoint(toString
, to
))
238 FloatSize diff
= to
- from
;
239 return sqrtf(diff
.width() * diff
.width() + diff
.height() * diff
.height());
244 #endif // ENABLE(SVG)