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