1/*
2 * Copyright (C) Research In Motion Limited 2011-2012. All rights reserved.
3 * Copyright (C) 2013 Samsung Electronics. All rights reserved.
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13 * Library General Public License for more details.
14 *
15 * You should have received a copy of the GNU Library General Public License
16 * along with this library; see the file COPYING.LIB.  If not, write to
17 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
19 */
20
21#ifndef SVGAnimatedTypeAnimator_h
22#define SVGAnimatedTypeAnimator_h
23
24#include "SVGAnimatedProperty.h"
25#include "SVGAnimatedType.h"
26#include "SVGElementInstance.h"
27#include <wtf/StdLibExtras.h>
28
29namespace WebCore {
30
31struct SVGElementAnimatedProperties {
32    SVGElementAnimatedProperties();
33
34    SVGElementAnimatedProperties(SVGElement*, Vector<RefPtr<SVGAnimatedProperty>>&);
35
36    SVGElement* element;
37    Vector<RefPtr<SVGAnimatedProperty>> properties;
38};
39typedef Vector<SVGElementAnimatedProperties> SVGElementAnimatedPropertyList;
40
41class SVGAnimationElement;
42
43class SVGAnimatedTypeAnimator {
44    WTF_MAKE_FAST_ALLOCATED;
45public:
46    virtual ~SVGAnimatedTypeAnimator();
47    virtual std::unique_ptr<SVGAnimatedType> constructFromString(const String&) = 0;
48
49    virtual std::unique_ptr<SVGAnimatedType> startAnimValAnimation(const SVGElementAnimatedPropertyList&) = 0;
50    virtual void stopAnimValAnimation(const SVGElementAnimatedPropertyList&) = 0;
51    virtual void resetAnimValToBaseVal(const SVGElementAnimatedPropertyList&, SVGAnimatedType*) = 0;
52    virtual void animValWillChange(const SVGElementAnimatedPropertyList&) = 0;
53    virtual void animValDidChange(const SVGElementAnimatedPropertyList&) = 0;
54    virtual void addAnimatedTypes(SVGAnimatedType*, SVGAnimatedType*) = 0;
55
56    virtual void calculateAnimatedValue(float percentage, unsigned repeatCount, SVGAnimatedType*, SVGAnimatedType*, SVGAnimatedType*, SVGAnimatedType*) = 0;
57    virtual float calculateDistance(const String& fromString, const String& toString) = 0;
58
59    void calculateFromAndToValues(std::unique_ptr<SVGAnimatedType>&, std::unique_ptr<SVGAnimatedType>&, const String& fromString, const String& toString);
60    void calculateFromAndByValues(std::unique_ptr<SVGAnimatedType>&, std::unique_ptr<SVGAnimatedType>&, const String& fromString, const String& byString);
61
62    void setContextElement(SVGElement* contextElement) { m_contextElement = contextElement; }
63    AnimatedPropertyType type() const { return m_type; }
64
65    SVGElementAnimatedPropertyList findAnimatedPropertiesForAttributeName(SVGElement*, const QualifiedName&);
66
67protected:
68    SVGAnimatedTypeAnimator(AnimatedPropertyType, SVGAnimationElement*, SVGElement*);
69
70    // Helpers for animators that operate on single types, eg. just one SVGAnimatedInteger.
71    template<typename AnimValType>
72    std::unique_ptr<typename AnimValType::ContentType> constructFromBaseValue(const SVGElementAnimatedPropertyList& animatedTypes)
73    {
74        ASSERT(animatedTypes[0].properties.size() == 1);
75        const typename AnimValType::ContentType& animatedType = castAnimatedPropertyToActualType<AnimValType>(animatedTypes[0].properties[0].get())->currentBaseValue();
76
77        auto copy = std::make_unique<typename AnimValType::ContentType>(animatedType);
78        executeAction<AnimValType>(StartAnimationAction, animatedTypes, 0, copy.get());
79        return copy;
80    }
81
82    template<typename AnimValType>
83    void resetFromBaseValue(const SVGElementAnimatedPropertyList& animatedTypes, SVGAnimatedType* type, typename AnimValType::ContentType& (SVGAnimatedType::*getter)())
84    {
85        ASSERT(animatedTypes[0].properties.size() == 1);
86        ASSERT(type);
87        ASSERT(type->type() == m_type);
88        typename AnimValType::ContentType& animatedTypeValue = (type->*getter)();
89        animatedTypeValue = castAnimatedPropertyToActualType<AnimValType>(animatedTypes[0].properties[0].get())->currentBaseValue();
90
91        executeAction<AnimValType>(StartAnimationAction, animatedTypes, 0, &animatedTypeValue);
92    }
93
94    template<typename AnimValType>
95    void stopAnimValAnimationForType(const SVGElementAnimatedPropertyList& animatedTypes)
96    {
97        ASSERT(animatedTypes[0].properties.size() == 1);
98        executeAction<AnimValType>(StopAnimationAction, animatedTypes, 0);
99    }
100
101    template<typename AnimValType>
102    void animValDidChangeForType(const SVGElementAnimatedPropertyList& animatedTypes)
103    {
104        ASSERT(animatedTypes[0].properties.size() == 1);
105        executeAction<AnimValType>(AnimValDidChangeAction, animatedTypes, 0);
106    }
107
108    template<typename AnimValType>
109    void animValWillChangeForType(const SVGElementAnimatedPropertyList& animatedTypes)
110    {
111        ASSERT(animatedTypes[0].properties.size() == 1);
112        executeAction<AnimValType>(AnimValWillChangeAction, animatedTypes, 0);
113    }
114
115    // Helpers for animators that operate on pair types, eg. a pair of SVGAnimatedIntegers.
116    template<typename AnimValType1, typename AnimValType2>
117    std::unique_ptr<std::pair<typename AnimValType1::ContentType, typename AnimValType2::ContentType>> constructFromBaseValues(const SVGElementAnimatedPropertyList& animatedTypes)
118    {
119        ASSERT(animatedTypes[0].properties.size() == 2);
120        const typename AnimValType1::ContentType& firstType = castAnimatedPropertyToActualType<AnimValType1>(animatedTypes[0].properties[0].get())->currentBaseValue();
121        const typename AnimValType2::ContentType& secondType = castAnimatedPropertyToActualType<AnimValType2>(animatedTypes[0].properties[1].get())->currentBaseValue();
122
123        auto copy = std::make_unique<std::pair<typename AnimValType1::ContentType, typename AnimValType2::ContentType>>(firstType, secondType);
124        executeAction<AnimValType1>(StartAnimationAction, animatedTypes, 0, &copy->first);
125        executeAction<AnimValType2>(StartAnimationAction, animatedTypes, 1, &copy->second);
126        return copy;
127    }
128
129    template<typename AnimValType1, typename AnimValType2>
130    void resetFromBaseValues(const SVGElementAnimatedPropertyList& animatedTypes, SVGAnimatedType* type, std::pair<typename AnimValType1::ContentType, typename AnimValType2::ContentType>& (SVGAnimatedType::*getter)())
131    {
132        ASSERT(animatedTypes[0].properties.size() == 2);
133        ASSERT(type);
134        ASSERT(type->type() == m_type);
135
136        std::pair<typename AnimValType1::ContentType, typename AnimValType2::ContentType>& animatedTypeValue = (type->*getter)();
137        animatedTypeValue.first = castAnimatedPropertyToActualType<AnimValType1>(animatedTypes[0].properties[0].get())->currentBaseValue();
138        animatedTypeValue.second = castAnimatedPropertyToActualType<AnimValType2>(animatedTypes[0].properties[1].get())->currentBaseValue();
139
140        executeAction<AnimValType1>(StartAnimationAction, animatedTypes, 0, &animatedTypeValue.first);
141        executeAction<AnimValType2>(StartAnimationAction, animatedTypes, 1, &animatedTypeValue.second);
142    }
143
144    template<typename AnimValType1, typename AnimValType2>
145    void stopAnimValAnimationForTypes(const SVGElementAnimatedPropertyList& animatedTypes)
146    {
147        ASSERT(animatedTypes[0].properties.size() == 2);
148        executeAction<AnimValType1>(StopAnimationAction, animatedTypes, 0);
149        executeAction<AnimValType2>(StopAnimationAction, animatedTypes, 1);
150    }
151
152    template<typename AnimValType1, typename AnimValType2>
153    void animValDidChangeForTypes(const SVGElementAnimatedPropertyList& animatedTypes)
154    {
155        ASSERT(animatedTypes[0].properties.size() == 2);
156        executeAction<AnimValType1>(AnimValDidChangeAction, animatedTypes, 0);
157        executeAction<AnimValType2>(AnimValDidChangeAction, animatedTypes, 1);
158    }
159
160    template<typename AnimValType1, typename AnimValType2>
161    void animValWillChangeForTypes(const SVGElementAnimatedPropertyList& animatedTypes)
162    {
163        ASSERT(animatedTypes[0].properties.size() == 2);
164        executeAction<AnimValType1>(AnimValWillChangeAction, animatedTypes, 0);
165        executeAction<AnimValType2>(AnimValWillChangeAction, animatedTypes, 1);
166    }
167
168    template<typename AnimValType>
169    AnimValType* castAnimatedPropertyToActualType(SVGAnimatedProperty* property)
170    {
171        ASSERT(property);
172        ASSERT(property->contextElement());
173        // We can't assert property->animatedPropertyType() == m_type, as there's an exception for SVGMarkerElements orient attribute.
174        if (property->animatedPropertyType() != m_type) {
175            ASSERT(m_type == AnimatedAngle);
176            ASSERT(property->animatedPropertyType() == AnimatedEnumeration);
177        }
178        return static_cast<AnimValType*>(property);
179    }
180
181    AnimatedPropertyType m_type;
182    SVGAnimationElement* m_animationElement;
183    SVGElement* m_contextElement;
184
185private:
186    enum AnimationAction {
187        StartAnimationAction,
188        StopAnimationAction,
189        AnimValWillChangeAction,
190        AnimValDidChangeAction
191    };
192
193    template<typename AnimValType>
194    void executeAction(AnimationAction action, const SVGElementAnimatedPropertyList& animatedTypes, unsigned whichProperty, typename AnimValType::ContentType* type = 0)
195    {
196        SVGElementInstance::InstanceUpdateBlocker blocker(animatedTypes[0].element);
197
198        SVGElementAnimatedPropertyList::const_iterator end = animatedTypes.end();
199        for (SVGElementAnimatedPropertyList::const_iterator it = animatedTypes.begin(); it != end; ++it) {
200            ASSERT_WITH_SECURITY_IMPLICATION(whichProperty < it->properties.size());
201            AnimValType* property = castAnimatedPropertyToActualType<AnimValType>(it->properties[whichProperty].get());
202
203            switch (action) {
204            case StartAnimationAction:
205                ASSERT(type);
206                if (!property->isAnimating())
207                    property->animationStarted(type);
208                break;
209            case StopAnimationAction:
210                ASSERT(!type);
211                property->animationEnded();
212                break;
213            case AnimValWillChangeAction:
214                ASSERT(!type);
215                property->animValWillChange();
216                break;
217            case AnimValDidChangeAction:
218                ASSERT(!type);
219                property->animValDidChange();
220                break;
221            }
222        }
223    }
224};
225
226} // namespace WebCore
227
228#endif // SVGAnimatedTypeAnimator_h
229