2008-10-09 Chris Marrin <cmarrin@apple.com>
[WebKit-https.git] / WebCore / page / animation / KeyframeAnimation.cpp
1 /*
2  * Copyright (C) 2007 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *
8  * 1.  Redistributions of source code must retain the above copyright
9  *     notice, this list of conditions and the following disclaimer. 
10  * 2.  Redistributions in binary form must reproduce the above copyright
11  *     notice, this list of conditions and the following disclaimer in the
12  *     documentation and/or other materials provided with the distribution. 
13  * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
14  *     its contributors may be used to endorse or promote products derived
15  *     from this software without specific prior written permission. 
16  *
17  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
18  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
21  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28
29 #include "config.h"
30 #include "KeyframeAnimation.h"
31
32 #include "CSSPropertyNames.h"
33 #include "CSSStyleSelector.h"
34 #include "CompositeAnimation.h"
35 #include "EventNames.h"
36 #include "RenderObject.h"
37 #include "SystemTime.h"
38
39 namespace WebCore {
40
41 KeyframeAnimation::KeyframeAnimation(const Animation* animation, RenderObject* renderer, int index, CompositeAnimation* compAnim, const RenderStyle* unanimatedStyle)
42     : AnimationBase(animation, renderer, compAnim)
43     , m_keyframes(renderer, animation->name())
44     , m_index(index)
45     , m_unanimatedStyle(0)
46 {
47     if (unanimatedStyle) {
48         const_cast<RenderStyle*>(unanimatedStyle)->ref();
49         m_unanimatedStyle = unanimatedStyle;
50     }
51     
52     // Get the keyframe RenderStyles
53     if (m_object && m_object->element() && m_object->element()->isElementNode())
54         m_object->document()->styleSelector()->keyframeStylesForAnimation(static_cast<Element*>(m_object->element()), unanimatedStyle, m_keyframes);
55
56     // Update the m_transformFunctionListValid flag based on whether the function lists in the keyframes match.
57     validateTransformFunctionList();
58 }
59
60 KeyframeAnimation::~KeyframeAnimation()
61 {
62     // Do the cleanup here instead of in the base class so the specialized methods get called
63     if (!postActive())
64         updateStateMachine(AnimationStateInputEndAnimation, -1);
65
66     if (m_unanimatedStyle)
67         const_cast<RenderStyle*>(m_unanimatedStyle)->deref(renderer()->renderArena());
68 }
69
70 void KeyframeAnimation::animate(CompositeAnimation* animation, RenderObject* renderer, const RenderStyle* currentStyle, 
71                                     const RenderStyle* targetStyle, RenderStyle*& animatedStyle)
72 {
73     // If we have not yet started, we will not have a valid start time, so just start the animation if needed.
74     if (isNew() && m_animation->playState() == AnimPlayStatePlaying)
75         updateStateMachine(AnimationStateInputStartAnimation, -1);
76
77     // If we get this far and the animation is done, it means we are cleaning up a just finished animation.
78     // If so, we need to send back the targetStyle.
79     if (postActive()) {
80         if (!animatedStyle)
81             animatedStyle = const_cast<RenderStyle*>(targetStyle);
82         return;
83     }
84
85     // If we are waiting for the start timer, we don't want to change the style yet.
86     // Special case - if the delay time is 0, then we do want to set the first frame of the
87     // animation right away. This avoids a flash when the animation starts.
88     if (waitingToStart() && m_animation->delay() > 0)
89         return;
90
91     // FIXME: we need to be more efficient about determining which keyframes we are animating between.
92     // We should cache the last pair or something.
93
94     // Find the first key
95     double elapsedTime = (m_startTime > 0) ? ((!paused() ? currentTime() : m_pauseTime) - m_startTime) : 0;
96     if (elapsedTime < 0)
97         elapsedTime = 0;
98
99     double t = m_animation->duration() ? (elapsedTime / m_animation->duration()) : 1;
100     int i = static_cast<int>(t);
101     t -= i;
102     if (m_animation->direction() && (i & 1))
103         t = 1 - t;
104
105     RenderStyle* fromStyle = 0;
106     RenderStyle* toStyle = 0;
107     double scale = 1;
108     double offset = 0;
109     Vector<KeyframeValue>::const_iterator endKeyframes = m_keyframes.endKeyframes();
110     for (Vector<KeyframeValue>::const_iterator it = m_keyframes.beginKeyframes(); it != endKeyframes; ++it) {
111         if (t < it->key) {
112             // The first key should always be 0, so we should never succeed on the first key
113             if (!fromStyle)
114                 break;
115             scale = 1.0 / (it->key - offset);
116             toStyle = it->style;
117             break;
118         }
119
120         offset = it->key;
121         fromStyle = it->style;
122     }
123
124     // If either style is 0 we have an invalid case, just stop the animation.
125     if (!fromStyle || !toStyle) {
126         updateStateMachine(AnimationStateInputEndAnimation, -1);
127         return;
128     }
129
130     // Run a cycle of animation.
131     // We know we will need a new render style, so make one if needed.
132     if (!animatedStyle)
133         animatedStyle = new (renderer->renderArena()) RenderStyle(*targetStyle);
134
135     const TimingFunction* timingFunction = 0;
136     if (fromStyle->animations() && fromStyle->animations()->size() > 0)
137         timingFunction = &(fromStyle->animations()->animation(0)->timingFunction());
138
139     double prog = progress(scale, offset, timingFunction);
140
141     HashSet<int>::const_iterator endProperties = m_keyframes.endProperties();
142     for (HashSet<int>::const_iterator it = m_keyframes.beginProperties(); it != endProperties; ++it) {
143         if (blendProperties(this, *it, animatedStyle, fromStyle, toStyle, prog))
144             setAnimating();
145     }
146 }
147
148 bool KeyframeAnimation::hasAnimationForProperty(int property) const
149 {
150     HashSet<int>::const_iterator end = m_keyframes.endProperties();
151     for (HashSet<int>::const_iterator it = m_keyframes.beginProperties(); it != end; ++it) {
152         if (*it == property)
153             return true;
154     }
155     
156     return false;
157 }
158
159 void KeyframeAnimation::endAnimation(bool)
160 {
161     // Restore the original (unanimated) style
162     if (m_object)
163         setChanged(m_object->element());
164 }
165
166 bool KeyframeAnimation::shouldSendEventForListener(Document::ListenerType listenerType)
167 {
168     return m_object->document()->hasListenerType(listenerType);
169 }
170
171 void KeyframeAnimation::onAnimationStart(double elapsedTime)
172 {
173     sendAnimationEvent(EventNames::webkitAnimationStartEvent, elapsedTime);
174 }
175
176 void KeyframeAnimation::onAnimationIteration(double elapsedTime)
177 {
178     sendAnimationEvent(EventNames::webkitAnimationIterationEvent, elapsedTime);
179 }
180
181 void KeyframeAnimation::onAnimationEnd(double elapsedTime)
182 {
183     if (!sendAnimationEvent(EventNames::webkitAnimationEndEvent, elapsedTime)) {
184         // We didn't dispatch an event, which would call endAnimation(), so we'll just call it here.
185         endAnimation(true);
186     }
187 }
188
189 bool KeyframeAnimation::sendAnimationEvent(const AtomicString& eventType, double elapsedTime)
190 {
191     Document::ListenerType listenerType;
192     if (eventType == EventNames::webkitAnimationIterationEvent)
193         listenerType = Document::ANIMATIONITERATION_LISTENER;
194     else if (eventType == EventNames::webkitAnimationEndEvent)
195         listenerType = Document::ANIMATIONEND_LISTENER;
196     else {
197         ASSERT(eventType == EventNames::webkitAnimationStartEvent);
198         listenerType = Document::ANIMATIONSTART_LISTENER;
199     }
200
201     if (shouldSendEventForListener(listenerType)) {
202         if (Element* element = elementForEventDispatch()) {
203             m_waitingForEndEvent = true;
204             m_animationEventDispatcher.startTimer(element, m_keyframes.animationName(), -1, true, eventType, elapsedTime);
205             return true; // Did dispatch an event
206         }
207     }
208
209     return false; // Did not dispatch an event
210 }
211
212 void KeyframeAnimation::overrideAnimations()
213 {
214     // This will override implicit animations that match the properties in the keyframe animation
215     HashSet<int>::const_iterator end = m_keyframes.endProperties();
216     for (HashSet<int>::const_iterator it = m_keyframes.beginProperties(); it != end; ++it)
217         compositeAnimation()->overrideImplicitAnimations(*it);
218 }
219
220 void KeyframeAnimation::resumeOverriddenAnimations()
221 {
222     // This will resume overridden implicit animations
223     HashSet<int>::const_iterator end = m_keyframes.endProperties();
224     for (HashSet<int>::const_iterator it = m_keyframes.beginProperties(); it != end; ++it)
225         compositeAnimation()->resumeOverriddenImplicitAnimations(*it);
226 }
227
228 bool KeyframeAnimation::affectsProperty(int property) const
229 {
230     HashSet<int>::const_iterator end = m_keyframes.endProperties();
231     for (HashSet<int>::const_iterator it = m_keyframes.beginProperties(); it != end; ++it) {
232         if (*it == property)
233             return true;
234     }
235     return false;
236 }
237
238 void KeyframeAnimation::validateTransformFunctionList()
239 {
240     m_transformFunctionListValid = false;
241     
242     if (m_keyframes.size() < 2 || !m_keyframes.containsProperty(CSSPropertyWebkitTransform))
243         return;
244
245     Vector<KeyframeValue>::const_iterator end = m_keyframes.endKeyframes();
246
247     // Empty transforms match anything, so find the first non-empty entry as the reference
248     size_t firstIndex = 0;
249     Vector<KeyframeValue>::const_iterator firstIt = end;
250     
251     for (Vector<KeyframeValue>::const_iterator it = m_keyframes.beginKeyframes(); it != end; ++it, ++firstIndex) {
252         if (it->style->transform().operations().size() > 0) {
253             firstIt = it;
254             break;
255         }
256     }
257     
258     if (firstIt == end)
259         return;
260         
261     const TransformOperations* firstVal = &firstIt->style->transform();
262     
263     // See if the keyframes are valid
264     for (Vector<KeyframeValue>::const_iterator it = firstIt+1; it != end; ++it) {
265         const TransformOperations* val = &it->style->transform();
266         
267         // A null transform matches anything
268         if (val->operations().isEmpty())
269             continue;
270         
271         // If the sizes of the function lists don't match, the lists don't match
272         if (firstVal->operations().size() != val->operations().size())
273             return;
274         
275         // If the types of each function are not the same, the lists don't match
276         for (size_t j = 0; j < firstVal->operations().size(); ++j) {
277             if (!firstVal->operations()[j]->isSameType(*val->operations()[j]))
278                 return;
279         }
280     }
281
282     // Keyframes are valid
283     m_transformFunctionListValid = true;
284 }
285
286 } // namespace WebCore