Upstream version 11.40.277.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / core / svg / SVGAnimateMotionElement.cpp
1 /*
2  * Copyright (C) 2007 Eric Seidel <eric@webkit.org>
3  * Copyright (C) 2007 Rob Buis <buis@kde.org>
4  * Copyright (C) 2008 Apple Inc. All rights reserved.
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Library General Public License for more details.
15  *
16  * You should have received a copy of the GNU Library General Public License
17  * along with this library; see the file COPYING.LIB.  If not, write to
18  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19  * Boston, MA 02110-1301, USA.
20  */
21
22 #include "config.h"
23 #include "core/svg/SVGAnimateMotionElement.h"
24
25 #include "core/SVGNames.h"
26 #include "core/dom/ElementTraversal.h"
27 #include "core/rendering/RenderObject.h"
28 #include "core/rendering/svg/SVGPathData.h"
29 #include "core/svg/SVGMPathElement.h"
30 #include "core/svg/SVGParserUtilities.h"
31 #include "core/svg/SVGPathElement.h"
32 #include "core/svg/SVGPathUtilities.h"
33 #include "platform/transforms/AffineTransform.h"
34 #include "wtf/MathExtras.h"
35 #include "wtf/StdLibExtras.h"
36
37 namespace blink {
38
39 using namespace SVGNames;
40
41 inline SVGAnimateMotionElement::SVGAnimateMotionElement(Document& document)
42     : SVGAnimationElement(animateMotionTag, document)
43     , m_hasToPointAtEndOfDuration(false)
44 {
45     setCalcMode(CalcModePaced);
46 }
47
48 DEFINE_NODE_FACTORY(SVGAnimateMotionElement)
49
50 SVGAnimateMotionElement::~SVGAnimateMotionElement()
51 {
52 }
53
54 bool SVGAnimateMotionElement::hasValidAttributeType()
55 {
56     SVGElement* targetElement = this->targetElement();
57     if (!targetElement)
58         return false;
59
60     // We don't have a special attribute name to verify the animation type. Check the element name instead.
61     if (!targetElement->isSVGGraphicsElement())
62         return false;
63     // Spec: SVG 1.1 section 19.2.15
64     // FIXME: svgTag is missing. Needs to be checked, if transforming <svg> could cause problems.
65     return (isSVGGElement(*targetElement)
66         || isSVGDefsElement(*targetElement)
67         || isSVGUseElement(*targetElement)
68         || isSVGImageElement(*targetElement)
69         || isSVGSwitchElement(*targetElement)
70         || isSVGPathElement(*targetElement)
71         || isSVGRectElement(*targetElement)
72         || isSVGCircleElement(*targetElement)
73         || isSVGEllipseElement(*targetElement)
74         || isSVGLineElement(*targetElement)
75         || isSVGPolylineElement(*targetElement)
76         || isSVGPolygonElement(*targetElement)
77         || isSVGTextElement(*targetElement)
78         || isSVGClipPathElement(*targetElement)
79         || isSVGMaskElement(*targetElement)
80         || isSVGAElement(*targetElement)
81         || isSVGForeignObjectElement(*targetElement)
82         );
83 }
84
85 bool SVGAnimateMotionElement::hasValidAttributeName()
86 {
87     // AnimateMotion does not use attributeName so it is always valid.
88     return true;
89 }
90
91 void SVGAnimateMotionElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
92 {
93     if (name == SVGNames::pathAttr) {
94         m_path = Path();
95         buildPathFromString(value, m_path);
96         updateAnimationPath();
97         return;
98     }
99
100     SVGAnimationElement::parseAttribute(name, value);
101 }
102
103 SVGAnimateMotionElement::RotateMode SVGAnimateMotionElement::rotateMode() const
104 {
105     DEFINE_STATIC_LOCAL(const AtomicString, autoVal, ("auto", AtomicString::ConstructFromLiteral));
106     DEFINE_STATIC_LOCAL(const AtomicString, autoReverse, ("auto-reverse", AtomicString::ConstructFromLiteral));
107     const AtomicString& rotate = getAttribute(SVGNames::rotateAttr);
108     if (rotate == autoVal)
109         return RotateAuto;
110     if (rotate == autoReverse)
111         return RotateAutoReverse;
112     return RotateAngle;
113 }
114
115 void SVGAnimateMotionElement::updateAnimationPath()
116 {
117     m_animationPath = Path();
118     bool foundMPath = false;
119
120     for (SVGMPathElement* mpath = Traversal<SVGMPathElement>::firstChild(*this); mpath; mpath = Traversal<SVGMPathElement>::nextSibling(*mpath)) {
121         if (SVGPathElement* pathElement = mpath->pathElement()) {
122             updatePathFromGraphicsElement(pathElement, m_animationPath);
123             foundMPath = true;
124             break;
125         }
126     }
127
128     if (!foundMPath && fastHasAttribute(SVGNames::pathAttr))
129         m_animationPath = m_path;
130
131     updateAnimationMode();
132 }
133
134 template<typename CharType>
135 static bool parsePointInternal(const String& string, FloatPoint& point)
136 {
137     const CharType* ptr = string.getCharacters<CharType>();
138     const CharType* end = ptr + string.length();
139
140     if (!skipOptionalSVGSpaces(ptr, end))
141         return false;
142
143     float x = 0;
144     if (!parseNumber(ptr, end, x))
145         return false;
146
147     float y = 0;
148     if (!parseNumber(ptr, end, y))
149         return false;
150
151     point = FloatPoint(x, y);
152
153     // disallow anything except spaces at the end
154     return !skipOptionalSVGSpaces(ptr, end);
155 }
156
157 static bool parsePoint(const String& string, FloatPoint& point)
158 {
159     if (string.isEmpty())
160         return false;
161     if (string.is8Bit())
162         return parsePointInternal<LChar>(string, point);
163     return parsePointInternal<UChar>(string, point);
164 }
165
166 void SVGAnimateMotionElement::resetAnimatedType()
167 {
168     if (!hasValidAttributeType())
169         return;
170     SVGElement* targetElement = this->targetElement();
171     if (!targetElement)
172         return;
173     if (AffineTransform* transform = targetElement->animateMotionTransform())
174         transform->makeIdentity();
175 }
176
177 void SVGAnimateMotionElement::clearAnimatedType(SVGElement* targetElement)
178 {
179     if (!targetElement)
180         return;
181
182     AffineTransform* transform = targetElement->animateMotionTransform();
183     if (!transform)
184         return;
185
186     transform->makeIdentity();
187
188     if (RenderObject* targetRenderer = targetElement->renderer()) {
189         targetRenderer->setNeedsTransformUpdate();
190         markForLayoutAndParentResourceInvalidation(targetRenderer);
191     }
192 }
193
194 bool SVGAnimateMotionElement::calculateToAtEndOfDurationValue(const String& toAtEndOfDurationString)
195 {
196     parsePoint(toAtEndOfDurationString, m_toPointAtEndOfDuration);
197     m_hasToPointAtEndOfDuration = true;
198     return true;
199 }
200
201 bool SVGAnimateMotionElement::calculateFromAndToValues(const String& fromString, const String& toString)
202 {
203     m_hasToPointAtEndOfDuration = false;
204     parsePoint(fromString, m_fromPoint);
205     parsePoint(toString, m_toPoint);
206     return true;
207 }
208
209 bool SVGAnimateMotionElement::calculateFromAndByValues(const String& fromString, const String& byString)
210 {
211     m_hasToPointAtEndOfDuration = false;
212     if (animationMode() == ByAnimation && !isAdditive())
213         return false;
214     parsePoint(fromString, m_fromPoint);
215     FloatPoint byPoint;
216     parsePoint(byString, byPoint);
217     m_toPoint = FloatPoint(m_fromPoint.x() + byPoint.x(), m_fromPoint.y() + byPoint.y());
218     return true;
219 }
220
221 void SVGAnimateMotionElement::calculateAnimatedValue(float percentage, unsigned repeatCount, SVGSMILElement*)
222 {
223     SVGElement* targetElement = this->targetElement();
224     if (!targetElement)
225         return;
226     AffineTransform* transform = targetElement->animateMotionTransform();
227     if (!transform)
228         return;
229
230     if (RenderObject* targetRenderer = targetElement->renderer())
231         targetRenderer->setNeedsTransformUpdate();
232
233     if (!isAdditive())
234         transform->makeIdentity();
235
236     if (animationMode() != PathAnimation) {
237         FloatPoint toPointAtEndOfDuration = m_toPoint;
238         if (isAccumulated() && repeatCount && m_hasToPointAtEndOfDuration)
239             toPointAtEndOfDuration = m_toPointAtEndOfDuration;
240
241         float animatedX = 0;
242         animateAdditiveNumber(percentage, repeatCount, m_fromPoint.x(), m_toPoint.x(), toPointAtEndOfDuration.x(), animatedX);
243
244         float animatedY = 0;
245         animateAdditiveNumber(percentage, repeatCount, m_fromPoint.y(), m_toPoint.y(), toPointAtEndOfDuration.y(), animatedY);
246
247         transform->translate(animatedX, animatedY);
248         return;
249     }
250
251     ASSERT(!m_animationPath.isEmpty());
252
253     float positionOnPath = m_animationPath.length() * percentage;
254     FloatPoint position;
255     float angle;
256     bool ok = m_animationPath.pointAndNormalAtLength(positionOnPath, position, angle);
257     if (!ok)
258         return;
259
260     // Handle accumulate="sum".
261     if (isAccumulated() && repeatCount) {
262         FloatPoint positionAtEndOfDuration = m_animationPath.pointAtLength(m_animationPath.length(), ok);
263         if (ok)
264             position.move(positionAtEndOfDuration.x() * repeatCount, positionAtEndOfDuration.y() * repeatCount);
265     }
266
267     transform->translate(position.x(), position.y());
268     RotateMode rotateMode = this->rotateMode();
269     if (rotateMode != RotateAuto && rotateMode != RotateAutoReverse)
270         return;
271     if (rotateMode == RotateAutoReverse)
272         angle += 180;
273     transform->rotate(angle);
274 }
275
276 void SVGAnimateMotionElement::applyResultsToTarget()
277 {
278     // We accumulate to the target element transform list so there is not much to do here.
279     SVGElement* targetElement = this->targetElement();
280     if (!targetElement)
281         return;
282
283     if (RenderObject* renderer = targetElement->renderer())
284         markForLayoutAndParentResourceInvalidation(renderer);
285
286     AffineTransform* t = targetElement->animateMotionTransform();
287     if (!t)
288         return;
289
290     // ...except in case where we have additional instances in <use> trees.
291     const WillBeHeapHashSet<RawPtrWillBeWeakMember<SVGElement> >& instances = targetElement->instancesForElement();
292     const WillBeHeapHashSet<RawPtrWillBeWeakMember<SVGElement> >::const_iterator end = instances.end();
293     for (WillBeHeapHashSet<RawPtrWillBeWeakMember<SVGElement> >::const_iterator it = instances.begin(); it != end; ++it) {
294         SVGElement* shadowTreeElement = *it;
295         ASSERT(shadowTreeElement);
296         AffineTransform* transform = shadowTreeElement->animateMotionTransform();
297         if (!transform)
298             continue;
299         transform->setMatrix(t->a(), t->b(), t->c(), t->d(), t->e(), t->f());
300         if (RenderObject* renderer = shadowTreeElement->renderer()) {
301             renderer->setNeedsTransformUpdate();
302             markForLayoutAndParentResourceInvalidation(renderer);
303         }
304     }
305 }
306
307 float SVGAnimateMotionElement::calculateDistance(const String& fromString, const String& toString)
308 {
309     FloatPoint from;
310     FloatPoint to;
311     if (!parsePoint(fromString, from))
312         return -1;
313     if (!parsePoint(toString, to))
314         return -1;
315     FloatSize diff = to - from;
316     return sqrtf(diff.width() * diff.width() + diff.height() * diff.height());
317 }
318
319 void SVGAnimateMotionElement::updateAnimationMode()
320 {
321     if (!m_animationPath.isEmpty())
322         setAnimationMode(PathAnimation);
323     else
324         SVGAnimationElement::updateAnimationMode();
325 }
326
327 }