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 "RenderStyle.h"
40 #include <wtf/UnusedParam.h>
41
42 using namespace std;
43
44 namespace WebCore {
45
KeyframeAnimation(const Animation * animation,RenderObject * renderer,int index,CompositeAnimation * compAnim,RenderStyle * unanimatedStyle)46 KeyframeAnimation::KeyframeAnimation(const Animation* animation, RenderObject* renderer, int index, CompositeAnimation* compAnim, RenderStyle* unanimatedStyle)
47 : AnimationBase(animation, renderer, compAnim)
48 , m_keyframes(renderer, animation->name())
49 , m_index(index)
50 , m_startEventDispatched(false)
51 , m_unanimatedStyle(unanimatedStyle)
52 {
53 // Get the keyframe RenderStyles
54 if (m_object && m_object->node() && m_object->node()->isElementNode())
55 m_object->document()->styleSelector()->keyframeStylesForAnimation(static_cast<Element*>(m_object->node()), unanimatedStyle, m_keyframes);
56
57 // Update the m_transformFunctionListValid flag based on whether the function lists in the keyframes match.
58 validateTransformFunctionList();
59 }
60
~KeyframeAnimation()61 KeyframeAnimation::~KeyframeAnimation()
62 {
63 // Make sure to tell the renderer that we are ending. This will make sure any accelerated animations are removed.
64 if (!postActive())
65 endAnimation();
66 }
67
fetchIntervalEndpointsForProperty(int property,const RenderStyle * & fromStyle,const RenderStyle * & toStyle,double & prog) const68 void KeyframeAnimation::fetchIntervalEndpointsForProperty(int property, const RenderStyle*& fromStyle, const RenderStyle*& toStyle, double& prog) const
69 {
70 // Find the first key
71 double elapsedTime = getElapsedTime();
72 if (m_animation->duration() && m_animation->iterationCount() != Animation::IterationCountInfinite)
73 elapsedTime = min(elapsedTime, m_animation->duration() * m_animation->iterationCount());
74
75 double fractionalTime = m_animation->duration() ? (elapsedTime / m_animation->duration()) : 1;
76
77 // FIXME: startTime can be before the current animation "frame" time. This is to sync with the frame time
78 // concept in AnimationTimeController. So we need to somehow sync the two. Until then, the possible
79 // error is small and will probably not be noticeable. Until we fix this, remove the assert.
80 // https://bugs.webkit.org/show_bug.cgi?id=52037
81 // ASSERT(fractionalTime >= 0);
82 if (fractionalTime < 0)
83 fractionalTime = 0;
84
85 // FIXME: share this code with AnimationBase::progress().
86 int iteration = static_cast<int>(fractionalTime);
87 if (m_animation->iterationCount() != Animation::IterationCountInfinite)
88 iteration = min(iteration, m_animation->iterationCount() - 1);
89 fractionalTime -= iteration;
90
91 bool reversing = (m_animation->direction() == Animation::AnimationDirectionAlternate) && (iteration & 1);
92 if (reversing)
93 fractionalTime = 1 - fractionalTime;
94
95 size_t numKeyframes = m_keyframes.size();
96 if (!numKeyframes)
97 return;
98
99 ASSERT(!m_keyframes[0].key());
100 ASSERT(m_keyframes[m_keyframes.size() - 1].key() == 1);
101
102 int prevIndex = -1;
103 int nextIndex = -1;
104
105 // FIXME: with a lot of keys, this linear search will be slow. We could binary search.
106 for (size_t i = 0; i < numKeyframes; ++i) {
107 const KeyframeValue& currKeyFrame = m_keyframes[i];
108
109 if (!currKeyFrame.containsProperty(property))
110 continue;
111
112 if (fractionalTime < currKeyFrame.key()) {
113 nextIndex = i;
114 break;
115 }
116
117 prevIndex = i;
118 }
119
120 double scale = 1;
121 double offset = 0;
122
123 if (prevIndex == -1)
124 prevIndex = 0;
125
126 if (nextIndex == -1)
127 nextIndex = m_keyframes.size() - 1;
128
129 const KeyframeValue& prevKeyframe = m_keyframes[prevIndex];
130 const KeyframeValue& nextKeyframe = m_keyframes[nextIndex];
131
132 fromStyle = prevKeyframe.style();
133 toStyle = nextKeyframe.style();
134
135 offset = prevKeyframe.key();
136 scale = 1.0 / (nextKeyframe.key() - prevKeyframe.key());
137
138 const TimingFunction* timingFunction = 0;
139 if (fromStyle->animations() && fromStyle->animations()->size() > 0) {
140 // We get the timing function from the first animation, because we've synthesized a RenderStyle for each keyframe.
141 timingFunction = fromStyle->animations()->animation(0)->timingFunction().get();
142 }
143
144 prog = progress(scale, offset, timingFunction);
145 }
146
animate(CompositeAnimation *,RenderObject *,const RenderStyle *,RenderStyle * targetStyle,RefPtr<RenderStyle> & animatedStyle)147 void KeyframeAnimation::animate(CompositeAnimation*, RenderObject*, const RenderStyle*, RenderStyle* targetStyle, RefPtr<RenderStyle>& animatedStyle)
148 {
149 // Fire the start timeout if needed
150 fireAnimationEventsIfNeeded();
151
152 // If we have not yet started, we will not have a valid start time, so just start the animation if needed.
153 if (isNew() && m_animation->playState() == AnimPlayStatePlaying)
154 updateStateMachine(AnimationStateInputStartAnimation, -1);
155
156 // If we get this far and the animation is done, it means we are cleaning up a just finished animation.
157 // If so, we need to send back the targetStyle.
158 if (postActive()) {
159 if (!animatedStyle)
160 animatedStyle = const_cast<RenderStyle*>(targetStyle);
161 return;
162 }
163
164 // If we are waiting for the start timer, we don't want to change the style yet.
165 // Special case 1 - if the delay time is 0, then we do want to set the first frame of the
166 // animation right away. This avoids a flash when the animation starts.
167 // Special case 2 - if there is a backwards fill mode, then we want to continue
168 // through to the style blend so that we get the fromStyle.
169 if (waitingToStart() && m_animation->delay() > 0 && !m_animation->fillsBackwards())
170 return;
171
172 // If we have no keyframes, don't animate.
173 if (!m_keyframes.size()) {
174 updateStateMachine(AnimationStateInputEndAnimation, -1);
175 return;
176 }
177
178 // Run a cycle of animation.
179 // We know we will need a new render style, so make one if needed.
180 if (!animatedStyle)
181 animatedStyle = RenderStyle::clone(targetStyle);
182
183 // FIXME: we need to be more efficient about determining which keyframes we are animating between.
184 // We should cache the last pair or something.
185 HashSet<int>::const_iterator endProperties = m_keyframes.endProperties();
186 for (HashSet<int>::const_iterator it = m_keyframes.beginProperties(); it != endProperties; ++it) {
187 int property = *it;
188
189 // Get the from/to styles and progress between
190 const RenderStyle* fromStyle = 0;
191 const RenderStyle* toStyle = 0;
192 double progress = 0.0;
193 fetchIntervalEndpointsForProperty(property, fromStyle, toStyle, progress);
194
195 bool needsAnim = blendProperties(this, property, animatedStyle.get(), fromStyle, toStyle, progress);
196 if (needsAnim)
197 setAnimating();
198 else {
199 #if USE(ACCELERATED_COMPOSITING)
200 // If we are running an accelerated animation, set a flag in the style
201 // to indicate it. This can be used to make sure we get an updated
202 // style for hit testing, etc.
203 animatedStyle->setIsRunningAcceleratedAnimation();
204 #endif
205 }
206 }
207 }
208
getAnimatedStyle(RefPtr<RenderStyle> & animatedStyle)209 void KeyframeAnimation::getAnimatedStyle(RefPtr<RenderStyle>& animatedStyle)
210 {
211 // If we're in the delay phase and we're not backwards filling, tell the caller
212 // to use the current style.
213 if (waitingToStart() && m_animation->delay() > 0 && !m_animation->fillsBackwards())
214 return;
215
216 if (!m_keyframes.size())
217 return;
218
219 if (!animatedStyle)
220 animatedStyle = RenderStyle::clone(m_object->style());
221
222 HashSet<int>::const_iterator endProperties = m_keyframes.endProperties();
223 for (HashSet<int>::const_iterator it = m_keyframes.beginProperties(); it != endProperties; ++it) {
224 int property = *it;
225
226 // Get the from/to styles and progress between
227 const RenderStyle* fromStyle = 0;
228 const RenderStyle* toStyle = 0;
229 double progress = 0.0;
230 fetchIntervalEndpointsForProperty(property, fromStyle, toStyle, progress);
231
232 blendProperties(this, property, animatedStyle.get(), fromStyle, toStyle, progress);
233 }
234 }
235
hasAnimationForProperty(int property) const236 bool KeyframeAnimation::hasAnimationForProperty(int property) const
237 {
238 // FIXME: why not just m_keyframes.containsProperty()?
239 HashSet<int>::const_iterator end = m_keyframes.endProperties();
240 for (HashSet<int>::const_iterator it = m_keyframes.beginProperties(); it != end; ++it) {
241 if (*it == property)
242 return true;
243 }
244
245 return false;
246 }
247
startAnimation(double timeOffset)248 bool KeyframeAnimation::startAnimation(double timeOffset)
249 {
250 #if USE(ACCELERATED_COMPOSITING)
251 if (m_object && m_object->hasLayer()) {
252 RenderLayer* layer = toRenderBoxModelObject(m_object)->layer();
253 if (layer->isComposited())
254 return layer->backing()->startAnimation(timeOffset, m_animation.get(), m_keyframes);
255 }
256 #else
257 UNUSED_PARAM(timeOffset);
258 #endif
259 return false;
260 }
261
pauseAnimation(double timeOffset)262 void KeyframeAnimation::pauseAnimation(double timeOffset)
263 {
264 if (!m_object)
265 return;
266
267 #if USE(ACCELERATED_COMPOSITING)
268 if (m_object->hasLayer()) {
269 RenderLayer* layer = toRenderBoxModelObject(m_object)->layer();
270 if (layer->isComposited())
271 layer->backing()->animationPaused(timeOffset, m_keyframes.animationName());
272 }
273 #else
274 UNUSED_PARAM(timeOffset);
275 #endif
276 // Restore the original (unanimated) style
277 if (!paused())
278 setNeedsStyleRecalc(m_object->node());
279 }
280
endAnimation()281 void KeyframeAnimation::endAnimation()
282 {
283 if (!m_object)
284 return;
285
286 #if USE(ACCELERATED_COMPOSITING)
287 if (m_object->hasLayer()) {
288 RenderLayer* layer = toRenderBoxModelObject(m_object)->layer();
289 if (layer->isComposited())
290 layer->backing()->animationFinished(m_keyframes.animationName());
291 }
292 #endif
293 // Restore the original (unanimated) style
294 if (!paused())
295 setNeedsStyleRecalc(m_object->node());
296 }
297
shouldSendEventForListener(Document::ListenerType listenerType) const298 bool KeyframeAnimation::shouldSendEventForListener(Document::ListenerType listenerType) const
299 {
300 return m_object->document()->hasListenerType(listenerType);
301 }
302
onAnimationStart(double elapsedTime)303 void KeyframeAnimation::onAnimationStart(double elapsedTime)
304 {
305 sendAnimationEvent(eventNames().webkitAnimationStartEvent, elapsedTime);
306 }
307
onAnimationIteration(double elapsedTime)308 void KeyframeAnimation::onAnimationIteration(double elapsedTime)
309 {
310 sendAnimationEvent(eventNames().webkitAnimationIterationEvent, elapsedTime);
311 }
312
onAnimationEnd(double elapsedTime)313 void KeyframeAnimation::onAnimationEnd(double elapsedTime)
314 {
315 sendAnimationEvent(eventNames().webkitAnimationEndEvent, elapsedTime);
316 // End the animation if we don't fill forwards. Forward filling
317 // animations are ended properly in the class destructor.
318 if (!m_animation->fillsForwards())
319 endAnimation();
320 }
321
sendAnimationEvent(const AtomicString & eventType,double elapsedTime)322 bool KeyframeAnimation::sendAnimationEvent(const AtomicString& eventType, double elapsedTime)
323 {
324 Document::ListenerType listenerType;
325 if (eventType == eventNames().webkitAnimationIterationEvent)
326 listenerType = Document::ANIMATIONITERATION_LISTENER;
327 else if (eventType == eventNames().webkitAnimationEndEvent)
328 listenerType = Document::ANIMATIONEND_LISTENER;
329 else {
330 ASSERT(eventType == eventNames().webkitAnimationStartEvent);
331 if (m_startEventDispatched)
332 return false;
333 m_startEventDispatched = true;
334 listenerType = Document::ANIMATIONSTART_LISTENER;
335 }
336
337 if (shouldSendEventForListener(listenerType)) {
338 // Dispatch the event
339 RefPtr<Element> element;
340 if (m_object->node() && m_object->node()->isElementNode())
341 element = static_cast<Element*>(m_object->node());
342
343 ASSERT(!element || (element->document() && !element->document()->inPageCache()));
344 if (!element)
345 return false;
346
347 // Schedule event handling
348 m_compAnim->animationController()->addEventToDispatch(element, eventType, m_keyframes.animationName(), elapsedTime);
349
350 // Restore the original (unanimated) style
351 if (eventType == eventNames().webkitAnimationEndEvent && element->renderer())
352 setNeedsStyleRecalc(element.get());
353
354 return true; // Did dispatch an event
355 }
356
357 return false; // Did not dispatch an event
358 }
359
overrideAnimations()360 void KeyframeAnimation::overrideAnimations()
361 {
362 // This will override implicit animations that match the properties in the keyframe animation
363 HashSet<int>::const_iterator end = m_keyframes.endProperties();
364 for (HashSet<int>::const_iterator it = m_keyframes.beginProperties(); it != end; ++it)
365 compositeAnimation()->overrideImplicitAnimations(*it);
366 }
367
resumeOverriddenAnimations()368 void KeyframeAnimation::resumeOverriddenAnimations()
369 {
370 // This will resume overridden implicit animations
371 HashSet<int>::const_iterator end = m_keyframes.endProperties();
372 for (HashSet<int>::const_iterator it = m_keyframes.beginProperties(); it != end; ++it)
373 compositeAnimation()->resumeOverriddenImplicitAnimations(*it);
374 }
375
affectsProperty(int property) const376 bool KeyframeAnimation::affectsProperty(int property) const
377 {
378 HashSet<int>::const_iterator end = m_keyframes.endProperties();
379 for (HashSet<int>::const_iterator it = m_keyframes.beginProperties(); it != end; ++it) {
380 if (*it == property)
381 return true;
382 }
383 return false;
384 }
385
validateTransformFunctionList()386 void KeyframeAnimation::validateTransformFunctionList()
387 {
388 m_transformFunctionListValid = false;
389
390 if (m_keyframes.size() < 2 || !m_keyframes.containsProperty(CSSPropertyWebkitTransform))
391 return;
392
393 // Empty transforms match anything, so find the first non-empty entry as the reference
394 size_t numKeyframes = m_keyframes.size();
395 size_t firstNonEmptyTransformKeyframeIndex = numKeyframes;
396
397 for (size_t i = 0; i < numKeyframes; ++i) {
398 const KeyframeValue& currentKeyframe = m_keyframes[i];
399 if (currentKeyframe.style()->transform().operations().size()) {
400 firstNonEmptyTransformKeyframeIndex = i;
401 break;
402 }
403 }
404
405 if (firstNonEmptyTransformKeyframeIndex == numKeyframes)
406 return;
407
408 const TransformOperations* firstVal = &m_keyframes[firstNonEmptyTransformKeyframeIndex].style()->transform();
409
410 // See if the keyframes are valid
411 for (size_t i = firstNonEmptyTransformKeyframeIndex + 1; i < numKeyframes; ++i) {
412 const KeyframeValue& currentKeyframe = m_keyframes[i];
413 const TransformOperations* val = ¤tKeyframe.style()->transform();
414
415 // A null transform matches anything
416 if (val->operations().isEmpty())
417 continue;
418
419 // If the sizes of the function lists don't match, the lists don't match
420 if (firstVal->operations().size() != val->operations().size())
421 return;
422
423 // If the types of each function are not the same, the lists don't match
424 for (size_t j = 0; j < firstVal->operations().size(); ++j) {
425 if (!firstVal->operations()[j]->isSameType(*val->operations()[j]))
426 return;
427 }
428 }
429
430 // Keyframes are valid
431 m_transformFunctionListValid = true;
432 }
433
timeToNextService()434 double KeyframeAnimation::timeToNextService()
435 {
436 double t = AnimationBase::timeToNextService();
437 #if USE(ACCELERATED_COMPOSITING)
438 if (t != 0 || preActive())
439 return t;
440
441 // A return value of 0 means we need service. But if we only have accelerated animations we
442 // only need service at the end of the transition
443 HashSet<int>::const_iterator endProperties = m_keyframes.endProperties();
444 bool acceleratedPropertiesOnly = true;
445
446 for (HashSet<int>::const_iterator it = m_keyframes.beginProperties(); it != endProperties; ++it) {
447 if (!animationOfPropertyIsAccelerated(*it) || !isAccelerated()) {
448 acceleratedPropertiesOnly = false;
449 break;
450 }
451 }
452
453 if (acceleratedPropertiesOnly) {
454 bool isLooping;
455 getTimeToNextEvent(t, isLooping);
456 }
457 #endif
458 return t;
459 }
460
461 } // namespace WebCore
462