557b3f73d7afaaaf634794a05e27ad1b3bbd58fa
[WebKit-https.git] / WebCore / svg / SVGAnimateMotionElement.cpp
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.
5
6     This file is part of the WebKit project
7
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.
12
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.
17
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.
22 */
23
24 #include "config.h"
25 #if ENABLE(SVG) && ENABLE(SVG_ANIMATION)
26 #include "SVGAnimateMotionElement.h"
27
28 #include "FloatConversion.h"
29 #include "RenderObject.h"
30 #include "SVGMPathElement.h"
31 #include "SVGParserUtilities.h"
32 #include "SVGPathElement.h"
33 #include "SVGTransformList.h"
34 #include <math.h>
35
36 namespace WebCore {
37     
38 using namespace SVGNames;
39
40 SVGAnimateMotionElement::SVGAnimateMotionElement(const QualifiedName& tagName, Document* doc)
41     : SVGAnimationElement(tagName, doc)
42     , m_baseIndexInTransformList(0)
43     , m_rotateMode(AngleMode)
44     , m_angle(0)
45 {
46 }
47
48 SVGAnimateMotionElement::~SVGAnimateMotionElement()
49 {
50 }
51
52 bool SVGAnimateMotionElement::hasValidTarget() const
53 {
54     if (!SVGAnimationElement::hasValidTarget())
55         return false;
56     if (!targetElement()->isStyledTransformable())
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
78         )
79         return true;
80     return false;
81 }
82
83 void SVGAnimateMotionElement::parseMappedAttribute(MappedAttribute* attr)
84 {
85     if (attr->name() == SVGNames::rotateAttr) {
86         if (attr->value() == "auto")
87             m_rotateMode = AutoMode;
88         else if (attr->value() == "auto-reverse")
89             m_rotateMode = AutoReverseMode;
90         else {
91             m_rotateMode = AngleMode;
92             m_angle = attr->value().toFloat();
93         }
94     } else if (attr->name() == SVGNames::keyPointsAttr) {
95         // FIXME: Implement key points.
96     } else if (attr->name() == SVGNames::dAttr) {
97         m_path = Path();
98         pathFromSVGData(m_path, attr->value());
99     } else
100         SVGAnimationElement::parseMappedAttribute(attr);
101 }
102
103 Path SVGAnimateMotionElement::animationPath()
104 {
105     for (Node* child = firstChild(); child; child->nextSibling()) {
106         if (child->hasTagName(SVGNames::mpathTag)) {
107             SVGMPathElement* mPath = static_cast<SVGMPathElement*>(child);
108             SVGPathElement* pathElement = mPath->pathElement();
109             if (pathElement)
110                 return pathElement->toPathData();
111             // The spec would probably have us throw up an error here, but instead we try to fall back to the d value
112         }
113     }
114     if (hasAttribute(SVGNames::dAttr))
115         return m_path;
116     return Path();
117 }
118
119 static bool parsePoint(const String& s, FloatPoint& point)
120 {
121     if (s.isEmpty())
122         return false;
123     const UChar* cur = s.characters();
124     const UChar* end = cur + s.length();
125     
126     if (!skipOptionalSpaces(cur, end))
127         return false;
128     
129     float x = 0.0f;
130     if (!parseNumber(cur, end, x))
131         return false;
132     
133     float y = 0.0f;
134     if (!parseNumber(cur, end, y))
135         return false;
136     
137     point = FloatPoint(x, y);
138     
139     // disallow anything except spaces at the end
140     return !skipOptionalSpaces(cur, end);
141 }
142     
143 void SVGAnimateMotionElement::resetToBaseValue(const String&)
144 {
145     if (!hasValidTarget())
146         return;
147     SVGStyledTransformableElement* transformableElement = static_cast<SVGStyledTransformableElement*>(targetElement());
148     // FIXME: This should modify supplemental transform, not the transform attribute!
149     ExceptionCode ec;
150     transformableElement->transform()->clear(ec);
151 }
152
153 bool SVGAnimateMotionElement::calculateFromAndToValues(const String& fromString, const String& toString)
154 {
155     parsePoint(fromString, m_fromPoint);
156     parsePoint(toString, m_toPoint);
157     return true;
158 }
159     
160 bool SVGAnimateMotionElement::calculateFromAndByValues(const String& fromString, const String& byString)
161 {
162     parsePoint(fromString, m_fromPoint);
163     FloatPoint byPoint;
164     parsePoint(byString, byPoint);
165     m_toPoint = FloatPoint(m_fromPoint.x() + byPoint.x(), m_fromPoint.y() + byPoint.y());
166     return true;
167 }
168
169 void SVGAnimateMotionElement::calculateAnimatedValue(float percentage, unsigned repeat, SVGSMILElement* resultElement)
170 {
171     if (!resultElement->targetElement()->isStyledTransformable())
172         return;
173     
174     // FIXME: This should modify supplemental transform, not the transform attribute!
175     SVGStyledTransformableElement* transformableElement = static_cast<SVGStyledTransformableElement*>(resultElement->targetElement());
176     RefPtr<SVGTransformList> transformList = transformableElement->transform();
177     if (!transformList)
178         return;
179     
180     ExceptionCode ec;
181     if (!isAdditive()) {
182         ASSERT(this == resultElement);
183         transformList->clear(ec);
184     }
185     
186     FloatSize diff = m_toPoint - m_fromPoint;
187     AffineTransform transform;
188     // FIXME: Animate angles
189     transform.translate(diff.width() * percentage + m_fromPoint.x(), diff.height() * percentage + m_fromPoint.y());
190     
191     // FIXME: Accumulate.
192
193     if (!transform.isIdentity())
194         transformList->appendItem(SVGTransform(transform), ec);
195
196     if (transformableElement->renderer())
197         transformableElement->renderer()->setNeedsLayout(true); // should be part of setTransform
198 }
199     
200 void SVGAnimateMotionElement::applyResultsToTarget()
201 {
202     
203 }
204
205 float SVGAnimateMotionElement::calculateDistance(const String& fromString, const String& toString)
206 {
207     FloatPoint from;
208     FloatPoint to;
209     if (!parsePoint(fromString, from))
210         return -1.f;
211     if (!parsePoint(toString, to))
212         return -1.f;
213     FloatSize diff = to - from;
214     return narrowPrecisionToFloat(sqrt(diff.width() * diff.width() + diff.height() * diff.height()));
215 }
216
217 }
218
219 #endif // ENABLE(SVG)
220
221 // vim:ts=4:noet