fix logic
[personal-kdelibs.git] / khtml / svg / SVGAnimateMotionElement.cpp
blob46ca654f0a8df4fa6c2a0a87c9ef14f02dc58127
1 /*
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.
24 #include "config.h"
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"
34 #include <math.h>
36 namespace WebCore {
38 using namespace SVGNames;
40 SVGAnimateMotionElement::SVGAnimateMotionElement(const QualifiedName& tagName, Document* doc)
41 : SVGAnimationElement(tagName, doc)
42 , m_baseIndexInTransformList(0)
43 , m_angle(0)
47 SVGAnimateMotionElement::~SVGAnimateMotionElement()
51 bool SVGAnimateMotionElement::hasValidTarget() const
53 if (!SVGAnimationElement::hasValidTarget())
54 return false;
55 SVGElement* targetElement = this->targetElement();
56 if (!targetElement->isStyledTransformable() && !targetElement->hasTagName(SVGNames::textTag))
57 return false;
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)
77 #endif
79 return true;
80 return false;
83 void SVGAnimateMotionElement::parseMappedAttribute(MappedAttribute* attr)
85 if (attr->name() == SVGNames::pathAttr) {
86 m_path = Path();
87 pathFromSVGData(m_path, attr->value());
88 } else
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)
98 return RotateAuto;
99 if (rotate == autoReverse)
100 return RotateAutoReverse;
101 return RotateAngle;
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();
110 if (pathElement)
111 return pathElement->toPathData();
112 return Path();
115 if (hasAttribute(SVGNames::pathAttr))
116 return m_path;
117 return Path();
120 static bool parsePoint(const String& s, FloatPoint& point)
122 if (s.isEmpty())
123 return false;
124 const UChar* cur = s.characters();
125 const UChar* end = cur + s.length();
127 if (!skipOptionalSpaces(cur, end))
128 return false;
130 float x = 0.0f;
131 if (!parseNumber(cur, end, x))
132 return false;
134 float y = 0.0f;
135 if (!parseNumber(cur, end, y))
136 return false;
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())
147 return;
148 SVGElement* target = targetElement();
149 AffineTransform* transform = target->supplementalTransform();
150 if (!transform)
151 return;
152 transform->reset();
155 bool SVGAnimateMotionElement::calculateFromAndToValues(const String& fromString, const String& toString)
157 parsePoint(fromString, m_fromPoint);
158 parsePoint(toString, m_toPoint);
159 return true;
162 bool SVGAnimateMotionElement::calculateFromAndByValues(const String& fromString, const String& byString)
164 parsePoint(fromString, m_fromPoint);
165 FloatPoint byPoint;
166 parsePoint(byString, byPoint);
167 m_toPoint = FloatPoint(m_fromPoint.x() + byPoint.x(), m_fromPoint.y() + byPoint.y());
168 return true;
171 void SVGAnimateMotionElement::calculateAnimatedValue(float percentage, unsigned repeat, SVGSMILElement*)
173 SVGElement* target = targetElement();
174 if (!target)
175 return;
176 AffineTransform* transform = target->supplementalTransform();
177 if (!transform)
178 return;
180 if (!isAdditive())
181 transform->reset();
183 // FIXME: Implement accumulate.
185 if (animationMode() == PathAnimation) {
186 ASSERT(!animationPath().isEmpty());
187 Path path = animationPath();
188 float positionOnPath = path.length() * percentage;
189 bool ok;
190 FloatPoint position = path.pointAtLength(positionOnPath, ok);
191 if (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)
197 angle += 180.f;
198 transform->rotate(angle);
201 return;
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);
216 if (!instances)
217 return;
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)
232 FloatPoint from;
233 FloatPoint to;
234 if (!parsePoint(fromString, from))
235 return -1.f;
236 if (!parsePoint(toString, to))
237 return -1.f;
238 FloatSize diff = to - from;
239 return sqrtf(diff.width() * diff.width() + diff.height() * diff.height());
244 #endif // ENABLE(SVG)
246 // vim:ts=4:noet