initial import
[vuplus_webkit] / Source / WebCore / svg / SVGAnimateElement.cpp
1 /*
2  * Copyright (C) 2004, 2005 Nikolas Zimmermann <zimmermann@kde.org>
3  * Copyright (C) 2004, 2005, 2006 Rob Buis <buis@kde.org>
4  * Copyright (C) 2008 Apple Inc. All rights reserved.
5  * Copyright (C) Research In Motion Limited 2011. All rights reserved.
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Library General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Library General Public License for more details.
16  *
17  * You should have received a copy of the GNU Library General Public License
18  * along with this library; see the file COPYING.LIB.  If not, write to
19  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20  * Boston, MA 02110-1301, USA.
21  */
22
23 #include "config.h"
24
25 #if ENABLE(SVG) && ENABLE(SVG_ANIMATION)
26 #include "SVGAnimateElement.h"
27
28 #include "CSSComputedStyleDeclaration.h"
29 #include "CSSParser.h"
30 #include "CSSPropertyNames.h"
31 #include "QualifiedName.h"
32 #include "RenderObject.h"
33 #include "SVGAnimatorFactory.h"
34 #include "SVGNames.h"
35 #include "SVGStyledElement.h"
36
37 using namespace std;
38
39 namespace WebCore {
40
41 SVGAnimateElement::SVGAnimateElement(const QualifiedName& tagName, Document* document)
42     : SVGAnimationElement(tagName, document)
43     , m_animatedPropertyType(AnimatedString)
44     , m_fromPropertyValueType(RegularPropertyValue)
45     , m_toPropertyValueType(RegularPropertyValue)
46 {
47     ASSERT(hasTagName(SVGNames::animateTag) || hasTagName(SVGNames::setTag) || hasTagName(SVGNames::animateColorTag));
48 }
49
50 PassRefPtr<SVGAnimateElement> SVGAnimateElement::create(const QualifiedName& tagName, Document* document)
51 {
52     return adoptRef(new SVGAnimateElement(tagName, document));
53 }
54
55 SVGAnimateElement::~SVGAnimateElement()
56 {
57 }
58
59 static inline void getPropertyValue(SVGElement* svgParent, const QualifiedName& attributeName, String& value)
60 {
61     ASSERT(svgParent->isStyled());
62     value = computedStyle(svgParent)->getPropertyValue(cssPropertyID(attributeName.localName()));
63 }
64
65 static bool inheritsFromProperty(SVGElement* targetElement, const QualifiedName& attributeName, const String& value)
66 {
67     ASSERT(targetElement);
68     DEFINE_STATIC_LOCAL(const AtomicString, inherit, ("inherit"));
69     
70     if (value.isEmpty() || value != inherit || !targetElement->isStyled())
71         return false;
72     return SVGStyledElement::isAnimatableCSSProperty(attributeName);
73 }
74
75 static bool attributeValueIsCurrentColor(const String& value)
76 {
77     DEFINE_STATIC_LOCAL(const AtomicString, currentColor, ("currentColor"));
78     return value == currentColor;
79 }
80
81 void SVGAnimateElement::adjustForCurrentColor(SVGElement* targetElement, Color& color)
82 {
83     ASSERT(targetElement);
84
85     if (RenderObject* targetRenderer = targetElement->renderer())
86         color = targetRenderer->style()->visitedDependentColor(CSSPropertyColor);
87     else
88         color = Color();
89 }
90
91 void SVGAnimateElement::adjustForInheritance(SVGElement* targetElement, const QualifiedName& attributeName, String& value)
92 {
93     // FIXME: At the moment the computed style gets returned as a String and needs to get parsed again.
94     // In the future we might want to work with the value type directly to avoid the String parsing.
95     ASSERT(targetElement);
96
97     Element* parent = targetElement->parentElement();
98     if (!parent || !parent->isSVGElement())
99         return;
100
101     SVGElement* svgParent = static_cast<SVGElement*>(parent);
102     if (svgParent->isStyled())
103         getPropertyValue(svgParent, attributeName, value);
104 }
105
106 bool SVGAnimateElement::hasValidAttributeType()
107 {
108     SVGElement* targetElement = this->targetElement();
109     if (!targetElement)
110         return false;
111     
112     return determineAnimatedPropertyType(targetElement) != AnimatedUnknown;
113 }
114
115 AnimatedPropertyType SVGAnimateElement::determineAnimatedPropertyType(SVGElement* targetElement) const
116 {
117     ASSERT(targetElement);
118
119     Vector<AnimatedPropertyType> propertyTypes;
120     targetElement->animatedPropertyTypeForAttribute(attributeName(), propertyTypes);
121     if (propertyTypes.isEmpty())
122         return AnimatedUnknown;
123
124     AnimatedPropertyType type = propertyTypes[0];
125     if (hasTagName(SVGNames::animateColorTag) && type != AnimatedColor)
126         return AnimatedUnknown;
127
128     // FIXME: Animator for AnimatedEnumeration missing. Falling back to String animation.
129     if (type == AnimatedEnumeration)
130         return AnimatedString;
131
132     // Animations of transform lists are not allowed for <animate> or <set>
133     // http://www.w3.org/TR/SVG/animate.html#AnimationAttributesAndProperties
134     if (type == AnimatedTransformList)
135         return AnimatedUnknown;
136
137     return type;
138 }
139
140 void SVGAnimateElement::determinePropertyValueTypes(const String& from, const String& to)
141 {
142     SVGElement* targetElement = this->targetElement();
143     ASSERT(targetElement);
144
145     if (inheritsFromProperty(targetElement, attributeName(), from))
146         m_fromPropertyValueType = InheritValue;
147     if (inheritsFromProperty(targetElement, attributeName(), to))
148         m_toPropertyValueType = InheritValue;
149
150     if (m_animatedPropertyType != AnimatedColor)
151         return;
152     
153     if (attributeValueIsCurrentColor(from))
154         m_fromPropertyValueType = CurrentColorValue;
155     if (attributeValueIsCurrentColor(to))
156         m_toPropertyValueType = CurrentColorValue;
157 }
158
159 void SVGAnimateElement::calculateAnimatedValue(float percentage, unsigned repeat, SVGSMILElement* resultElement)
160 {
161     ASSERT(resultElement);
162     ASSERT(percentage >= 0 && percentage <= 1);
163     ASSERT(m_animatedPropertyType != AnimatedEnumeration);
164     ASSERT(m_animatedPropertyType != AnimatedTransformList);
165     ASSERT(m_animatedPropertyType != AnimatedUnknown);
166     ASSERT(m_animator);
167     ASSERT(m_fromType);
168     ASSERT(m_toType);
169
170     SVGAnimateElement* resultAnimationElement = static_cast<SVGAnimateElement*>(resultElement);
171     ASSERT(resultAnimationElement->m_animatedType);
172     ASSERT(resultAnimationElement->m_animatedPropertyType == m_animatedPropertyType);
173     ASSERT(resultAnimationElement->hasTagName(SVGNames::animateTag)
174         || resultAnimationElement->hasTagName(SVGNames::animateColorTag) 
175         || resultAnimationElement->hasTagName(SVGNames::setTag));
176
177     if (hasTagName(SVGNames::setTag))
178         percentage = 1;
179
180     SVGElement* targetElement = this->targetElement();
181     if (!targetElement)
182         return;
183
184     // Target element might have changed.
185     m_animator->setContextElement(targetElement);
186     m_animator->calculateAnimatedValue(percentage, repeat, m_fromType, m_toType, resultAnimationElement->m_animatedType);
187 }
188
189 bool SVGAnimateElement::calculateFromAndToValues(const String& fromString, const String& toString)
190 {
191     SVGElement* targetElement = this->targetElement();
192     if (!targetElement)
193         return false;
194
195     m_animatedPropertyType = determineAnimatedPropertyType(targetElement);
196
197     ensureAnimator()->calculateFromAndToValues(m_fromType, m_toType, fromString, toString);
198     return true;
199 }
200
201 bool SVGAnimateElement::calculateFromAndByValues(const String& fromString, const String& byString)
202 {
203     SVGElement* targetElement = this->targetElement();
204     if (!targetElement)
205         return false;
206
207     ASSERT(!hasTagName(SVGNames::setTag));
208     m_animatedPropertyType = determineAnimatedPropertyType(targetElement);
209
210     ensureAnimator()->calculateFromAndByValues(m_fromType, m_toType, fromString, byString);
211     return true;
212 }
213
214 void SVGAnimateElement::resetToBaseValue(const String& baseString)
215 {
216     SVGElement* targetElement = this->targetElement();
217     ASSERT(targetElement);
218     m_animatedPropertyType = determineAnimatedPropertyType(targetElement);
219
220     if (!m_animatedType)
221         m_animatedType = ensureAnimator()->constructFromString(baseString);
222     else
223         m_animatedType->setValueAsString(attributeName(), baseString);
224 }
225     
226 void SVGAnimateElement::applyResultsToTarget()
227 {
228     ASSERT(m_animatedPropertyType != AnimatedEnumeration);
229     ASSERT(m_animatedPropertyType != AnimatedTransformList);
230     ASSERT(m_animatedPropertyType != AnimatedUnknown);
231     ASSERT(m_animatedType);
232
233     setTargetAttributeAnimatedValue(m_animatedType->valueAsString());
234 }
235     
236 float SVGAnimateElement::calculateDistance(const String& fromString, const String& toString)
237 {
238     // FIXME: A return value of float is not enough to support paced animations on lists.
239     SVGElement* targetElement = this->targetElement();
240     if (!targetElement)
241         return -1;
242     m_animatedPropertyType = determineAnimatedPropertyType(targetElement);
243     
244     return ensureAnimator()->calculateDistance(fromString, toString);
245 }
246
247 SVGAnimatedTypeAnimator* SVGAnimateElement::ensureAnimator()
248 {
249     if (!m_animator)
250         m_animator = SVGAnimatorFactory::create(this, targetElement(), m_animatedPropertyType);
251     return m_animator.get();
252 }
253
254 }
255 #endif // ENABLE(SVG)