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 "AnimationControllerPrivate.h"
33 #include "CSSPropertyNames.h"
34 #include "CSSStyleSelector.h"
35 #include "CompositeAnimation.h"
36 #include "EventNames.h"
37 #include "RenderLayer.h"
38 #include "RenderLayerBacking.h"
39 #include <wtf/UnusedParam.h>
40
41 namespace WebCore {
42
KeyframeAnimation(const Animation * animation,RenderObject * renderer,int index,CompositeAnimation * compAnim,RenderStyle * unanimatedStyle)43 KeyframeAnimation::KeyframeAnimation(const Animation* animation, RenderObject* renderer, int index, CompositeAnimation* compAnim, RenderStyle* unanimatedStyle)
44 : AnimationBase(animation, renderer, compAnim)
45 , m_keyframes(renderer, animation->name())
46 , m_index(index)
47 , m_unanimatedStyle(unanimatedStyle)
48 {
49 // Get the keyframe RenderStyles
50 if (m_object && m_object->node() && m_object->node()->isElementNode())
51 m_object->document()->styleSelector()->keyframeStylesForAnimation(static_cast<Element*>(m_object->node()), unanimatedStyle, m_keyframes);
52
53 // Update the m_transformFunctionListValid flag based on whether the function lists in the keyframes match.
54 validateTransformFunctionList();
55 }
56
~KeyframeAnimation()57 KeyframeAnimation::~KeyframeAnimation()
58 {
59 // Make sure to tell the renderer that we are ending. This will make sure any accelerated animations are removed.
60 if (!postActive())
61 endAnimation(true);
62 }
63
getKeyframeAnimationInterval(const RenderStyle * & fromStyle,const RenderStyle * & toStyle,double & prog) const64 void KeyframeAnimation::getKeyframeAnimationInterval(const RenderStyle*& fromStyle, const RenderStyle*& toStyle, double& prog) const
65 {
66 // Find the first key
67 double elapsedTime = getElapsedTime();
68
69 double t = m_animation->duration() ? (elapsedTime / m_animation->duration()) : 1;
70 int i = static_cast<int>(t);
71 t -= i;
72 if (m_animation->direction() && (i & 1))
73 t = 1 - t;
74
75 double scale = 1;
76 double offset = 0;
77 Vector<KeyframeValue>::const_iterator endKeyframes = m_keyframes.endKeyframes();
78 for (Vector<KeyframeValue>::const_iterator it = m_keyframes.beginKeyframes(); it != endKeyframes; ++it) {
79 if (t < it->key()) {
80 // The first key should always be 0, so we should never succeed on the first key
81 if (!fromStyle)
82 break;
83 scale = 1.0 / (it->key() - offset);
84 toStyle = it->style();
85 break;
86 }
87
88 offset = it->key();
89 fromStyle = it->style();
90 }
91
92 if (!fromStyle || !toStyle)
93 return;
94
95 const TimingFunction* timingFunction = 0;
96 if (fromStyle->animations() && fromStyle->animations()->size() > 0) {
97 // We get the timing function from the first animation, because we've synthesized a RenderStyle for each keyframe.
98 timingFunction = &(fromStyle->animations()->animation(0)->timingFunction());
99 }
100
101 prog = progress(scale, offset, timingFunction);
102 }
103
animate(CompositeAnimation *,RenderObject *,const RenderStyle *,RenderStyle * targetStyle,RefPtr<RenderStyle> & animatedStyle)104 void KeyframeAnimation::animate(CompositeAnimation*, RenderObject*, const RenderStyle*, RenderStyle* targetStyle, RefPtr<RenderStyle>& animatedStyle)
105 {
106 // Fire the start timeout if needed
107 fireAnimationEventsIfNeeded();
108
109 // If we have not yet started, we will not have a valid start time, so just start the animation if needed.
110 if (isNew() && m_animation->playState() == AnimPlayStatePlaying)
111 updateStateMachine(AnimationStateInputStartAnimation, -1);
112
113 // If we get this far and the animation is done, it means we are cleaning up a just finished animation.
114 // If so, we need to send back the targetStyle.
115 if (postActive()) {
116 if (!animatedStyle)
117 animatedStyle = const_cast<RenderStyle*>(targetStyle);
118 return;
119 }
120
121 // If we are waiting for the start timer, we don't want to change the style yet.
122 // Special case - if the delay time is 0, then we do want to set the first frame of the
123 // animation right away. This avoids a flash when the animation starts.
124 if (waitingToStart() && m_animation->delay() > 0)
125 return;
126
127 // FIXME: we need to be more efficient about determining which keyframes we are animating between.
128 // We should cache the last pair or something.
129
130 // Get the from/to styles and progress between
131 const RenderStyle* fromStyle = 0;
132 const RenderStyle* toStyle = 0;
133 double progress;
134 getKeyframeAnimationInterval(fromStyle, toStyle, progress);
135
136 // If either style is 0 we have an invalid case, just stop the animation.
137 if (!fromStyle || !toStyle) {
138 updateStateMachine(AnimationStateInputEndAnimation, -1);
139 return;
140 }
141
142 // Run a cycle of animation.
143 // We know we will need a new render style, so make one if needed.
144 if (!animatedStyle)
145 animatedStyle = RenderStyle::clone(targetStyle);
146
147 HashSet<int>::const_iterator endProperties = m_keyframes.endProperties();
148 for (HashSet<int>::const_iterator it = m_keyframes.beginProperties(); it != endProperties; ++it) {
149 bool needsAnim = blendProperties(this, *it, animatedStyle.get(), fromStyle, toStyle, progress);
150 if (needsAnim)
151 setAnimating();
152 else {
153 #if USE(ACCELERATED_COMPOSITING)
154 // If we are running an accelerated animation, set a flag in the style
155 // to indicate it. This can be used to make sure we get an updated
156 // style for hit testing, etc.
157 animatedStyle->setIsRunningAcceleratedAnimation();
158 #endif
159 }
160 }
161 }
162
getAnimatedStyle(RefPtr<RenderStyle> & animatedStyle)163 void KeyframeAnimation::getAnimatedStyle(RefPtr<RenderStyle>& animatedStyle)
164 {
165 // Get the from/to styles and progress between
166 const RenderStyle* fromStyle = 0;
167 const RenderStyle* toStyle = 0;
168 double progress;
169 getKeyframeAnimationInterval(fromStyle, toStyle, progress);
170
171 // If either style is 0 we have an invalid case
172 if (!fromStyle || !toStyle)
173 return;
174
175 if (!animatedStyle)
176 animatedStyle = RenderStyle::clone(m_object->style());
177
178 HashSet<int>::const_iterator endProperties = m_keyframes.endProperties();
179 for (HashSet<int>::const_iterator it = m_keyframes.beginProperties(); it != endProperties; ++it)
180 blendProperties(this, *it, animatedStyle.get(), fromStyle, toStyle, progress);
181 }
182
hasAnimationForProperty(int property) const183 bool KeyframeAnimation::hasAnimationForProperty(int property) const
184 {
185 HashSet<int>::const_iterator end = m_keyframes.endProperties();
186 for (HashSet<int>::const_iterator it = m_keyframes.beginProperties(); it != end; ++it) {
187 if (*it == property)
188 return true;
189 }
190
191 return false;
192 }
193
startAnimation(double beginTime)194 bool KeyframeAnimation::startAnimation(double beginTime)
195 {
196 #if USE(ACCELERATED_COMPOSITING)
197 if (m_object && m_object->hasLayer()) {
198 RenderLayer* layer = toRenderBoxModelObject(m_object)->layer();
199 if (layer->isComposited())
200 return layer->backing()->startAnimation(beginTime, m_animation.get(), m_keyframes);
201 }
202 #else
203 UNUSED_PARAM(beginTime);
204 #endif
205 return false;
206 }
207
endAnimation(bool reset)208 void KeyframeAnimation::endAnimation(bool reset)
209 {
210 if (m_object) {
211 #if USE(ACCELERATED_COMPOSITING)
212 if (m_object->hasLayer()) {
213 RenderLayer* layer = toRenderBoxModelObject(m_object)->layer();
214 if (layer->isComposited()) {
215 if (reset)
216 layer->backing()->animationFinished(m_keyframes.animationName());
217 else
218 layer->backing()->animationPaused(m_keyframes.animationName());
219 }
220 }
221 #else
222 UNUSED_PARAM(reset);
223 #endif
224 // Restore the original (unanimated) style
225 if (!paused())
226 setNeedsStyleRecalc(m_object->node());
227 }
228 }
229
shouldSendEventForListener(Document::ListenerType listenerType) const230 bool KeyframeAnimation::shouldSendEventForListener(Document::ListenerType listenerType) const
231 {
232 return m_object->document()->hasListenerType(listenerType);
233 }
234
onAnimationStart(double elapsedTime)235 void KeyframeAnimation::onAnimationStart(double elapsedTime)
236 {
237 sendAnimationEvent(eventNames().webkitAnimationStartEvent, elapsedTime);
238 }
239
onAnimationIteration(double elapsedTime)240 void KeyframeAnimation::onAnimationIteration(double elapsedTime)
241 {
242 sendAnimationEvent(eventNames().webkitAnimationIterationEvent, elapsedTime);
243 }
244
onAnimationEnd(double elapsedTime)245 void KeyframeAnimation::onAnimationEnd(double elapsedTime)
246 {
247 if (!sendAnimationEvent(eventNames().webkitAnimationEndEvent, elapsedTime)) {
248 // We didn't dispatch an event, which would call endAnimation(), so we'll just call it here.
249 endAnimation(true);
250 }
251 }
252
sendAnimationEvent(const AtomicString & eventType,double elapsedTime)253 bool KeyframeAnimation::sendAnimationEvent(const AtomicString& eventType, double elapsedTime)
254 {
255 Document::ListenerType listenerType;
256 if (eventType == eventNames().webkitAnimationIterationEvent)
257 listenerType = Document::ANIMATIONITERATION_LISTENER;
258 else if (eventType == eventNames().webkitAnimationEndEvent)
259 listenerType = Document::ANIMATIONEND_LISTENER;
260 else {
261 ASSERT(eventType == eventNames().webkitAnimationStartEvent);
262 listenerType = Document::ANIMATIONSTART_LISTENER;
263 }
264
265 if (shouldSendEventForListener(listenerType)) {
266 // Dispatch the event
267 RefPtr<Element> element;
268 if (m_object->node() && m_object->node()->isElementNode())
269 element = static_cast<Element*>(m_object->node());
270
271 ASSERT(!element || element->document() && !element->document()->inPageCache());
272 if (!element)
273 return false;
274
275 // Schedule event handling
276 m_compAnim->animationController()->addEventToDispatch(element, eventType, m_keyframes.animationName(), elapsedTime);
277
278 // Restore the original (unanimated) style
279 if (eventType == eventNames().webkitAnimationEndEvent && element->renderer())
280 setNeedsStyleRecalc(element.get());
281
282 return true; // Did dispatch an event
283 }
284
285 return false; // Did not dispatch an event
286 }
287
overrideAnimations()288 void KeyframeAnimation::overrideAnimations()
289 {
290 // This will override implicit animations that match the properties in the keyframe animation
291 HashSet<int>::const_iterator end = m_keyframes.endProperties();
292 for (HashSet<int>::const_iterator it = m_keyframes.beginProperties(); it != end; ++it)
293 compositeAnimation()->overrideImplicitAnimations(*it);
294 }
295
resumeOverriddenAnimations()296 void KeyframeAnimation::resumeOverriddenAnimations()
297 {
298 // This will resume overridden implicit animations
299 HashSet<int>::const_iterator end = m_keyframes.endProperties();
300 for (HashSet<int>::const_iterator it = m_keyframes.beginProperties(); it != end; ++it)
301 compositeAnimation()->resumeOverriddenImplicitAnimations(*it);
302 }
303
affectsProperty(int property) const304 bool KeyframeAnimation::affectsProperty(int property) const
305 {
306 HashSet<int>::const_iterator end = m_keyframes.endProperties();
307 for (HashSet<int>::const_iterator it = m_keyframes.beginProperties(); it != end; ++it) {
308 if (*it == property)
309 return true;
310 }
311 return false;
312 }
313
validateTransformFunctionList()314 void KeyframeAnimation::validateTransformFunctionList()
315 {
316 m_transformFunctionListValid = false;
317
318 if (m_keyframes.size() < 2 || !m_keyframes.containsProperty(CSSPropertyWebkitTransform))
319 return;
320
321 Vector<KeyframeValue>::const_iterator end = m_keyframes.endKeyframes();
322
323 // Empty transforms match anything, so find the first non-empty entry as the reference
324 size_t firstIndex = 0;
325 Vector<KeyframeValue>::const_iterator firstIt = end;
326
327 for (Vector<KeyframeValue>::const_iterator it = m_keyframes.beginKeyframes(); it != end; ++it, ++firstIndex) {
328 if (it->style()->transform().operations().size() > 0) {
329 firstIt = it;
330 break;
331 }
332 }
333
334 if (firstIt == end)
335 return;
336
337 const TransformOperations* firstVal = &firstIt->style()->transform();
338
339 // See if the keyframes are valid
340 for (Vector<KeyframeValue>::const_iterator it = firstIt+1; it != end; ++it) {
341 const TransformOperations* val = &it->style()->transform();
342
343 // A null transform matches anything
344 if (val->operations().isEmpty())
345 continue;
346
347 // If the sizes of the function lists don't match, the lists don't match
348 if (firstVal->operations().size() != val->operations().size())
349 return;
350
351 // If the types of each function are not the same, the lists don't match
352 for (size_t j = 0; j < firstVal->operations().size(); ++j) {
353 if (!firstVal->operations()[j]->isSameType(*val->operations()[j]))
354 return;
355 }
356 }
357
358 // Keyframes are valid
359 m_transformFunctionListValid = true;
360 }
361
timeToNextService()362 double KeyframeAnimation::timeToNextService()
363 {
364 double t = AnimationBase::timeToNextService();
365 #if USE(ACCELERATED_COMPOSITING)
366 if (t != 0 || preActive())
367 return t;
368
369 // A return value of 0 means we need service. But if we only have accelerated animations we
370 // only need service at the end of the transition
371 HashSet<int>::const_iterator endProperties = m_keyframes.endProperties();
372 bool acceleratedPropertiesOnly = true;
373
374 for (HashSet<int>::const_iterator it = m_keyframes.beginProperties(); it != endProperties; ++it) {
375 if (!animationOfPropertyIsAccelerated(*it) || isFallbackAnimating()) {
376 acceleratedPropertiesOnly = false;
377 break;
378 }
379 }
380
381 if (acceleratedPropertiesOnly) {
382 bool isLooping;
383 getTimeToNextEvent(t, isLooping);
384 }
385 #endif
386 return t;
387 }
388
389 } // namespace WebCore
390