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) 2007 Eric Seidel <eric@webkit.org>
5 * Copyright (C) 2008 Apple Inc. All rights reserved.
6 * Copyright (C) 2008 Cameron McCormack <cam@mcc.id.au>
7 * Copyright (C) Research In Motion Limited 2011. All rights reserved.
8 *
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Library General Public
11 * License as published by the Free Software Foundation; either
12 * version 2 of the License, or (at your option) any later version.
13 *
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17 * Library General Public License for more details.
18 *
19 * You should have received a copy of the GNU Library General Public License
20 * along with this library; see the file COPYING.LIB.  If not, write to
21 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
22 * Boston, MA 02110-1301, USA.
23 */
24
25#ifndef SVGAnimationElement_h
26#define SVGAnimationElement_h
27
28#if ENABLE(SVG)
29#include "ElementTimeControl.h"
30#include "SMILTime.h"
31#include "SVGAnimatedBoolean.h"
32#include "SVGExternalResourcesRequired.h"
33#include "SVGSMILElement.h"
34#include "SVGStringList.h"
35#include "SVGTests.h"
36#include "UnitBezier.h"
37
38namespace WebCore {
39
40enum AnimationMode {
41    NoAnimation,
42    FromToAnimation,
43    FromByAnimation,
44    ToAnimation,
45    ByAnimation,
46    ValuesAnimation,
47    PathAnimation // Used by AnimateMotion.
48};
49
50// If we have 'currentColor' or 'inherit' as animation value, we need to grab
51// the value during the animation since the value can be animated itself.
52enum AnimatedPropertyValueType {
53    RegularPropertyValue,
54    CurrentColorValue,
55    InheritValue
56};
57
58enum CalcMode {
59    CalcModeDiscrete,
60    CalcModeLinear,
61    CalcModePaced,
62    CalcModeSpline
63};
64
65class ConditionEventListener;
66class TimeContainer;
67class SVGAnimatedType;
68
69class SVGAnimationElement : public SVGSMILElement,
70                            public SVGTests,
71                            public SVGExternalResourcesRequired,
72                            public ElementTimeControl {
73public:
74    // SVGAnimationElement
75    float getStartTime() const;
76    float getCurrentTime() const;
77    float getSimpleDuration(ExceptionCode&) const;
78
79    // ElementTimeControl
80    virtual void beginElement();
81    virtual void beginElementAt(float offset);
82    virtual void endElement();
83    virtual void endElementAt(float offset);
84
85    static bool isTargetAttributeCSSProperty(SVGElement*, const QualifiedName&);
86
87    virtual bool isAdditive() const;
88    bool isAccumulated() const;
89    AnimationMode animationMode() const { return m_animationMode; }
90    CalcMode calcMode() const { return m_calcMode; }
91
92    enum ShouldApplyAnimation {
93        DontApplyAnimation,
94        ApplyCSSAnimation,
95        ApplyXMLAnimation
96    };
97
98    ShouldApplyAnimation shouldApplyAnimation(SVGElement* targetElement, const QualifiedName& attributeName);
99
100    AnimatedPropertyValueType fromPropertyValueType() const { return m_fromPropertyValueType; }
101    AnimatedPropertyValueType toPropertyValueType() const { return m_toPropertyValueType; }
102
103    template<typename AnimatedType>
104    void adjustForInheritance(AnimatedType (*parseTypeFromString)(SVGAnimationElement*, const String&),
105                              AnimatedPropertyValueType valueType, AnimatedType& animatedType, SVGElement* contextElement)
106    {
107        if (valueType != InheritValue)
108            return;
109        // Replace 'inherit' by its computed property value.
110        ASSERT(parseTypeFromString);
111        String typeString;
112        adjustForInheritance(contextElement, attributeName(), typeString);
113        animatedType = (*parseTypeFromString)(this, typeString);
114    }
115
116    template<typename AnimatedType>
117    bool adjustFromToListValues(const AnimatedType& fromList, const AnimatedType& toList, AnimatedType& animatedList, float percentage, bool resizeAnimatedListIfNeeded = true)
118    {
119        // If no 'to' value is given, nothing to animate.
120        unsigned toListSize = toList.size();
121        if (!toListSize)
122            return false;
123
124        // If the 'from' value is given and it's length doesn't match the 'to' value list length, fallback to a discrete animation.
125        unsigned fromListSize = fromList.size();
126        if (fromListSize != toListSize && fromListSize) {
127            if (percentage < 0.5) {
128                if (animationMode() != ToAnimation)
129                    animatedList = AnimatedType(fromList);
130            } else
131                animatedList = AnimatedType(toList);
132
133            return false;
134        }
135
136        ASSERT(!fromListSize || fromListSize == toListSize);
137        if (resizeAnimatedListIfNeeded && animatedList.size() < toListSize)
138            animatedList.resize(toListSize);
139
140        return true;
141    }
142
143    template<typename AnimatedType>
144    void animateDiscreteType(float percentage, const AnimatedType& fromType, const AnimatedType& toType, AnimatedType& animatedType)
145    {
146        if ((animationMode() == FromToAnimation && percentage > 0.5) || animationMode() == ToAnimation || percentage == 1) {
147            animatedType = AnimatedType(toType);
148            return;
149        }
150        animatedType = AnimatedType(fromType);
151    }
152
153    void animateAdditiveNumber(float percentage, unsigned repeatCount, float fromNumber, float toNumber, float toAtEndOfDurationNumber, float& animatedNumber)
154    {
155        float number;
156        if (calcMode() == CalcModeDiscrete)
157            number = percentage < 0.5 ? fromNumber : toNumber;
158        else
159            number = (toNumber - fromNumber) * percentage + fromNumber;
160
161        if (isAccumulated() && repeatCount)
162            number += toAtEndOfDurationNumber * repeatCount;
163
164        if (isAdditive() && animationMode() != ToAnimation)
165            animatedNumber += number;
166        else
167            animatedNumber = number;
168    }
169
170protected:
171    SVGAnimationElement(const QualifiedName&, Document*);
172
173    void computeCSSPropertyValue(SVGElement*, CSSPropertyID, String& value);
174    virtual void determinePropertyValueTypes(const String& from, const String& to);
175
176    bool isSupportedAttribute(const QualifiedName&);
177    virtual void parseAttribute(const QualifiedName&, const AtomicString&) OVERRIDE;
178    virtual void svgAttributeChanged(const QualifiedName&) OVERRIDE;
179
180    enum AttributeType {
181        AttributeTypeCSS,
182        AttributeTypeXML,
183        AttributeTypeAuto
184    };
185    AttributeType attributeType() const { return m_attributeType; }
186
187    String toValue() const;
188    String byValue() const;
189    String fromValue() const;
190
191    String targetAttributeBaseValue();
192
193    // from SVGSMILElement
194    virtual void startedActiveInterval() OVERRIDE;
195    virtual void updateAnimation(float percent, unsigned repeat, SVGSMILElement* resultElement) OVERRIDE;
196
197    AnimatedPropertyValueType m_fromPropertyValueType;
198    AnimatedPropertyValueType m_toPropertyValueType;
199
200    virtual void setTargetElement(SVGElement*) OVERRIDE;
201    virtual void setAttributeName(const QualifiedName&) OVERRIDE;
202    bool hasInvalidCSSAttributeType() const { return m_hasInvalidCSSAttributeType; }
203
204    virtual void updateAnimationMode();
205    void setAnimationMode(AnimationMode animationMode) { m_animationMode = animationMode; }
206    void setCalcMode(CalcMode calcMode) { m_calcMode = calcMode; }
207
208private:
209    virtual void animationAttributeChanged() OVERRIDE;
210    void setAttributeType(const AtomicString&);
211
212    void checkInvalidCSSAttributeType(SVGElement*);
213
214    virtual bool calculateToAtEndOfDurationValue(const String& toAtEndOfDurationString) = 0;
215    virtual bool calculateFromAndToValues(const String& fromString, const String& toString) = 0;
216    virtual bool calculateFromAndByValues(const String& fromString, const String& byString) = 0;
217    virtual void calculateAnimatedValue(float percent, unsigned repeatCount, SVGSMILElement* resultElement) = 0;
218    virtual float calculateDistance(const String& /*fromString*/, const String& /*toString*/) { return -1.f; }
219
220    void currentValuesForValuesAnimation(float percent, float& effectivePercent, String& from, String& to);
221    void calculateKeyTimesForCalcModePaced();
222    float calculatePercentFromKeyPoints(float percent) const;
223    void currentValuesFromKeyPoints(float percent, float& effectivePercent, String& from, String& to) const;
224    float calculatePercentForSpline(float percent, unsigned splineIndex) const;
225    float calculatePercentForFromTo(float percent) const;
226    unsigned calculateKeyTimesIndex(float percent) const;
227
228    void applyAnimatedValue(ShouldApplyAnimation, SVGElement* targetElement, const QualifiedName& attributeName, SVGAnimatedType*);
229    void adjustForInheritance(SVGElement* targetElement, const QualifiedName& attributeName, String&);
230
231    BEGIN_DECLARE_ANIMATED_PROPERTIES(SVGAnimationElement)
232        DECLARE_ANIMATED_BOOLEAN(ExternalResourcesRequired, externalResourcesRequired)
233    END_DECLARE_ANIMATED_PROPERTIES
234
235    // SVGTests
236    virtual void synchronizeRequiredFeatures() { SVGTests::synchronizeRequiredFeatures(this); }
237    virtual void synchronizeRequiredExtensions() { SVGTests::synchronizeRequiredExtensions(this); }
238    virtual void synchronizeSystemLanguage() { SVGTests::synchronizeSystemLanguage(this); }
239
240    void setCalcMode(const AtomicString&);
241
242    bool m_animationValid;
243
244    AttributeType m_attributeType;
245    Vector<String> m_values;
246    Vector<float> m_keyTimes;
247    Vector<float> m_keyPoints;
248    Vector<UnitBezier> m_keySplines;
249    String m_lastValuesAnimationFrom;
250    String m_lastValuesAnimationTo;
251    bool m_hasInvalidCSSAttributeType;
252    CalcMode m_calcMode;
253    AnimationMode m_animationMode;
254};
255
256} // namespace WebCore
257
258#endif // ENABLE(SVG)
259#endif // SVGAnimationElement_h
260