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.
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.
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.
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.
25 #if ENABLE(SVG) && ENABLE(SVG_ANIMATION)
26 #include "SVGAnimateElement.h"
28 #include "CSSComputedStyleDeclaration.h"
29 #include "CSSParser.h"
30 #include "CSSPropertyNames.h"
31 #include "QualifiedName.h"
32 #include "RenderObject.h"
33 #include "SVGAnimatorFactory.h"
35 #include "SVGStyledElement.h"
41 SVGAnimateElement::SVGAnimateElement(const QualifiedName& tagName, Document* document)
42 : SVGAnimationElement(tagName, document)
43 , m_animatedPropertyType(AnimatedString)
44 , m_fromPropertyValueType(RegularPropertyValue)
45 , m_toPropertyValueType(RegularPropertyValue)
47 ASSERT(hasTagName(SVGNames::animateTag) || hasTagName(SVGNames::setTag) || hasTagName(SVGNames::animateColorTag));
50 PassRefPtr<SVGAnimateElement> SVGAnimateElement::create(const QualifiedName& tagName, Document* document)
52 return adoptRef(new SVGAnimateElement(tagName, document));
55 SVGAnimateElement::~SVGAnimateElement()
59 static inline void getPropertyValue(SVGElement* svgParent, const QualifiedName& attributeName, String& value)
61 ASSERT(svgParent->isStyled());
62 value = computedStyle(svgParent)->getPropertyValue(cssPropertyID(attributeName.localName()));
65 static bool inheritsFromProperty(SVGElement* targetElement, const QualifiedName& attributeName, const String& value)
67 ASSERT(targetElement);
68 DEFINE_STATIC_LOCAL(const AtomicString, inherit, ("inherit"));
70 if (value.isEmpty() || value != inherit || !targetElement->isStyled())
72 return SVGStyledElement::isAnimatableCSSProperty(attributeName);
75 static bool attributeValueIsCurrentColor(const String& value)
77 DEFINE_STATIC_LOCAL(const AtomicString, currentColor, ("currentColor"));
78 return value == currentColor;
81 void SVGAnimateElement::adjustForCurrentColor(SVGElement* targetElement, Color& color)
83 ASSERT(targetElement);
85 if (RenderObject* targetRenderer = targetElement->renderer())
86 color = targetRenderer->style()->visitedDependentColor(CSSPropertyColor);
91 void SVGAnimateElement::adjustForInheritance(SVGElement* targetElement, const QualifiedName& attributeName, String& value)
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);
97 Element* parent = targetElement->parentElement();
98 if (!parent || !parent->isSVGElement())
101 SVGElement* svgParent = static_cast<SVGElement*>(parent);
102 if (svgParent->isStyled())
103 getPropertyValue(svgParent, attributeName, value);
106 bool SVGAnimateElement::hasValidAttributeType()
108 SVGElement* targetElement = this->targetElement();
112 return determineAnimatedPropertyType(targetElement) != AnimatedUnknown;
115 AnimatedPropertyType SVGAnimateElement::determineAnimatedPropertyType(SVGElement* targetElement) const
117 ASSERT(targetElement);
119 Vector<AnimatedPropertyType> propertyTypes;
120 targetElement->animatedPropertyTypeForAttribute(attributeName(), propertyTypes);
121 if (propertyTypes.isEmpty())
122 return AnimatedUnknown;
124 AnimatedPropertyType type = propertyTypes[0];
125 if (hasTagName(SVGNames::animateColorTag) && type != AnimatedColor)
126 return AnimatedUnknown;
128 // FIXME: Animator for AnimatedEnumeration missing. Falling back to String animation.
129 if (type == AnimatedEnumeration)
130 return AnimatedString;
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;
140 void SVGAnimateElement::determinePropertyValueTypes(const String& from, const String& to)
142 SVGElement* targetElement = this->targetElement();
143 ASSERT(targetElement);
145 if (inheritsFromProperty(targetElement, attributeName(), from))
146 m_fromPropertyValueType = InheritValue;
147 if (inheritsFromProperty(targetElement, attributeName(), to))
148 m_toPropertyValueType = InheritValue;
150 if (m_animatedPropertyType != AnimatedColor)
153 if (attributeValueIsCurrentColor(from))
154 m_fromPropertyValueType = CurrentColorValue;
155 if (attributeValueIsCurrentColor(to))
156 m_toPropertyValueType = CurrentColorValue;
159 void SVGAnimateElement::calculateAnimatedValue(float percentage, unsigned repeat, SVGSMILElement* resultElement)
161 ASSERT(resultElement);
162 ASSERT(percentage >= 0 && percentage <= 1);
163 ASSERT(m_animatedPropertyType != AnimatedEnumeration);
164 ASSERT(m_animatedPropertyType != AnimatedTransformList);
165 ASSERT(m_animatedPropertyType != AnimatedUnknown);
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));
177 if (hasTagName(SVGNames::setTag))
180 SVGElement* targetElement = this->targetElement();
184 // Target element might have changed.
185 m_animator->setContextElement(targetElement);
186 m_animator->calculateAnimatedValue(percentage, repeat, m_fromType, m_toType, resultAnimationElement->m_animatedType);
189 bool SVGAnimateElement::calculateFromAndToValues(const String& fromString, const String& toString)
191 SVGElement* targetElement = this->targetElement();
195 m_animatedPropertyType = determineAnimatedPropertyType(targetElement);
197 ensureAnimator()->calculateFromAndToValues(m_fromType, m_toType, fromString, toString);
201 bool SVGAnimateElement::calculateFromAndByValues(const String& fromString, const String& byString)
203 SVGElement* targetElement = this->targetElement();
207 ASSERT(!hasTagName(SVGNames::setTag));
208 m_animatedPropertyType = determineAnimatedPropertyType(targetElement);
210 ensureAnimator()->calculateFromAndByValues(m_fromType, m_toType, fromString, byString);
214 void SVGAnimateElement::resetToBaseValue(const String& baseString)
216 SVGElement* targetElement = this->targetElement();
217 ASSERT(targetElement);
218 m_animatedPropertyType = determineAnimatedPropertyType(targetElement);
221 m_animatedType = ensureAnimator()->constructFromString(baseString);
223 m_animatedType->setValueAsString(attributeName(), baseString);
226 void SVGAnimateElement::applyResultsToTarget()
228 ASSERT(m_animatedPropertyType != AnimatedEnumeration);
229 ASSERT(m_animatedPropertyType != AnimatedTransformList);
230 ASSERT(m_animatedPropertyType != AnimatedUnknown);
231 ASSERT(m_animatedType);
233 setTargetAttributeAnimatedValue(m_animatedType->valueAsString());
236 float SVGAnimateElement::calculateDistance(const String& fromString, const String& toString)
238 // FIXME: A return value of float is not enough to support paced animations on lists.
239 SVGElement* targetElement = this->targetElement();
242 m_animatedPropertyType = determineAnimatedPropertyType(targetElement);
244 return ensureAnimator()->calculateDistance(fromString, toString);
247 SVGAnimatedTypeAnimator* SVGAnimateElement::ensureAnimator()
250 m_animator = SVGAnimatorFactory::create(this, targetElement(), m_animatedPropertyType);
251 return m_animator.get();
255 #endif // ENABLE(SVG)