2008-12-10 Simon Fraser <simon.fraser@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, RenderStyle* unanimatedStyle)
42     : AnimationBase(animation, renderer, compAnim)
43     , m_keyframes(renderer, animation->name())
44     , m_index(index)
45     , m_unanimatedStyle(unanimatedStyle)
46 {
47     // Get the keyframe RenderStyles
48     if (m_object && m_object->element() && m_object->element()->isElementNode())
49         m_object->document()->styleSelector()->keyframeStylesForAnimation(static_cast<Element*>(m_object->element()), unanimatedStyle, m_keyframes);
50
51     // Update the m_transformFunctionListValid flag based on whether the function lists in the keyframes match.
52     validateTransformFunctionList();
53 }
54
55 KeyframeAnimation::~KeyframeAnimation()
56 {
57     // Do the cleanup here instead of in the base class so the specialized methods get called
58     if (!postActive())
59         updateStateMachine(AnimationStateInputEndAnimation, -1);
60 }
61
62 void KeyframeAnimation::animate(CompositeAnimation* animation, RenderObject* renderer, const RenderStyle* currentStyle, 
63                                     const RenderStyle* targetStyle, RefPtr<RenderStyle>& animatedStyle)
64 {
65     // If we have not yet started, we will not have a valid start time, so just start the animation if needed.
66     if (isNew() && m_animation->playState() == AnimPlayStatePlaying)
67         updateStateMachine(AnimationStateInputStartAnimation, -1);
68
69     // If we get this far and the animation is done, it means we are cleaning up a just finished animation.
70     // If so, we need to send back the targetStyle.
71     if (postActive()) {
72         if (!animatedStyle)
73             animatedStyle = const_cast<RenderStyle*>(targetStyle);
74         return;
75     }
76
77     // If we are waiting for the start timer, we don't want to change the style yet.
78     // Special case - if the delay time is 0, then we do want to set the first frame of the
79     // animation right away. This avoids a flash when the animation starts.
80     if (waitingToStart() && m_animation->delay() > 0)
81         return;
82
83     // FIXME: we need to be more efficient about determining which keyframes we are animating between.
84     // We should cache the last pair or something.
85
86     // Find the first key
87     double elapsedTime = (m_startTime > 0) ? ((!paused() ? currentTime() : m_pauseTime) - m_startTime) : 0;
88     if (elapsedTime < 0)
89         elapsedTime = 0;
90
91     double t = m_animation->duration() ? (elapsedTime / m_animation->duration()) : 1;
92     int i = static_cast<int>(t);
93     t -= i;
94     if (m_animation->direction() && (i & 1))
95         t = 1 - t;
96
97     const RenderStyle* fromStyle = 0;
98     const RenderStyle* toStyle = 0;
99     double scale = 1;
100     double offset = 0;
101     Vector<KeyframeValue>::const_iterator endKeyframes = m_keyframes.endKeyframes();
102     for (Vector<KeyframeValue>::const_iterator it = m_keyframes.beginKeyframes(); it != endKeyframes; ++it) {
103         if (t < it->key()) {
104             // The first key should always be 0, so we should never succeed on the first key
105             if (!fromStyle)
106                 break;
107             scale = 1.0 / (it->key() - offset);
108             toStyle = it->style();
109             break;
110         }
111
112         offset = it->key();
113         fromStyle = it->style();
114     }
115
116     // If either style is 0 we have an invalid case, just stop the animation.
117     if (!fromStyle || !toStyle) {
118         updateStateMachine(AnimationStateInputEndAnimation, -1);
119         return;
120     }
121
122     // Run a cycle of animation.
123     // We know we will need a new render style, so make one if needed.
124     if (!animatedStyle)
125         animatedStyle = RenderStyle::clone(targetStyle);
126
127     const TimingFunction* timingFunction = 0;
128     if (fromStyle->animations() && fromStyle->animations()->size() > 0)
129         timingFunction = &(fromStyle->animations()->animation(0)->timingFunction());
130
131     double prog = progress(scale, offset, timingFunction);
132
133     HashSet<int>::const_iterator endProperties = m_keyframes.endProperties();
134     for (HashSet<int>::const_iterator it = m_keyframes.beginProperties(); it != endProperties; ++it) {
135         if (blendProperties(this, *it, animatedStyle.get(), fromStyle, toStyle, prog))
136             setAnimating();
137     }
138 }
139
140 bool KeyframeAnimation::hasAnimationForProperty(int property) const
141 {
142     HashSet<int>::const_iterator end = m_keyframes.endProperties();
143     for (HashSet<int>::const_iterator it = m_keyframes.beginProperties(); it != end; ++it) {
144         if (*it == property)
145             return true;
146     }
147     
148     return false;
149 }
150
151 void KeyframeAnimation::endAnimation(bool)
152 {
153     // Restore the original (unanimated) style
154     if (m_object)
155         setChanged(m_object->element());
156 }
157
158 bool KeyframeAnimation::shouldSendEventForListener(Document::ListenerType listenerType)
159 {
160     return m_object->document()->hasListenerType(listenerType);
161 }
162
163 void KeyframeAnimation::onAnimationStart(double elapsedTime)
164 {
165     sendAnimationEvent(eventNames().webkitAnimationStartEvent, elapsedTime);
166 }
167
168 void KeyframeAnimation::onAnimationIteration(double elapsedTime)
169 {
170     sendAnimationEvent(eventNames().webkitAnimationIterationEvent, elapsedTime);
171 }
172
173 void KeyframeAnimation::onAnimationEnd(double elapsedTime)
174 {
175     if (!sendAnimationEvent(eventNames().webkitAnimationEndEvent, elapsedTime)) {
176         // We didn't dispatch an event, which would call endAnimation(), so we'll just call it here.
177         endAnimation(true);
178     }
179 }
180
181 bool KeyframeAnimation::sendAnimationEvent(const AtomicString& eventType, double elapsedTime)
182 {
183     Document::ListenerType listenerType;
184     if (eventType == eventNames().webkitAnimationIterationEvent)
185         listenerType = Document::ANIMATIONITERATION_LISTENER;
186     else if (eventType == eventNames().webkitAnimationEndEvent)
187         listenerType = Document::ANIMATIONEND_LISTENER;
188     else {
189         ASSERT(eventType == eventNames().webkitAnimationStartEvent);
190         listenerType = Document::ANIMATIONSTART_LISTENER;
191     }
192
193     if (shouldSendEventForListener(listenerType)) {
194         // Dispatch the event
195         RefPtr<Element> element;
196         if (m_object->node() && m_object->node()->isElementNode())
197             element = static_cast<Element*>(m_object->node());
198
199         ASSERT(!element || element->document() && !element->document()->inPageCache());
200         if (!element)
201             return false;
202
203         // Call the event handler
204         element->dispatchWebKitAnimationEvent(eventType, m_keyframes.animationName(), elapsedTime);
205
206         // Restore the original (unanimated) style
207         if (eventType == eventNames().webkitAnimationEndEvent && element->renderer())
208             setChanged(element.get());
209
210         return true; // Did dispatch an event
211     }
212
213     return false; // Did not dispatch an event
214 }
215
216 void KeyframeAnimation::overrideAnimations()
217 {
218     // This will override implicit animations that match the properties in the keyframe animation
219     HashSet<int>::const_iterator end = m_keyframes.endProperties();
220     for (HashSet<int>::const_iterator it = m_keyframes.beginProperties(); it != end; ++it)
221         compositeAnimation()->overrideImplicitAnimations(*it);
222 }
223
224 void KeyframeAnimation::resumeOverriddenAnimations()
225 {
226     // This will resume overridden implicit animations
227     HashSet<int>::const_iterator end = m_keyframes.endProperties();
228     for (HashSet<int>::const_iterator it = m_keyframes.beginProperties(); it != end; ++it)
229         compositeAnimation()->resumeOverriddenImplicitAnimations(*it);
230 }
231
232 bool KeyframeAnimation::affectsProperty(int property) const
233 {
234     HashSet<int>::const_iterator end = m_keyframes.endProperties();
235     for (HashSet<int>::const_iterator it = m_keyframes.beginProperties(); it != end; ++it) {
236         if (*it == property)
237             return true;
238     }
239     return false;
240 }
241
242 void KeyframeAnimation::validateTransformFunctionList()
243 {
244     m_transformFunctionListValid = false;
245     
246     if (m_keyframes.size() < 2 || !m_keyframes.containsProperty(CSSPropertyWebkitTransform))
247         return;
248
249     Vector<KeyframeValue>::const_iterator end = m_keyframes.endKeyframes();
250
251     // Empty transforms match anything, so find the first non-empty entry as the reference
252     size_t firstIndex = 0;
253     Vector<KeyframeValue>::const_iterator firstIt = end;
254     
255     for (Vector<KeyframeValue>::const_iterator it = m_keyframes.beginKeyframes(); it != end; ++it, ++firstIndex) {
256         if (it->style()->transform().operations().size() > 0) {
257             firstIt = it;
258             break;
259         }
260     }
261     
262     if (firstIt == end)
263         return;
264         
265     const TransformOperations* firstVal = &firstIt->style()->transform();
266     
267     // See if the keyframes are valid
268     for (Vector<KeyframeValue>::const_iterator it = firstIt+1; it != end; ++it) {
269         const TransformOperations* val = &it->style()->transform();
270         
271         // A null transform matches anything
272         if (val->operations().isEmpty())
273             continue;
274         
275         // If the sizes of the function lists don't match, the lists don't match
276         if (firstVal->operations().size() != val->operations().size())
277             return;
278         
279         // If the types of each function are not the same, the lists don't match
280         for (size_t j = 0; j < firstVal->operations().size(); ++j) {
281             if (!firstVal->operations()[j]->isSameType(*val->operations()[j]))
282                 return;
283         }
284     }
285
286     // Keyframes are valid
287     m_transformFunctionListValid = true;
288 }
289
290 } // namespace WebCore