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