1 /*
2  * Copyright (C) 2007, 2008, 2009 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 "AnimationController.h"
31 
32 #include "AnimationBase.h"
33 #include "AnimationControllerPrivate.h"
34 #include "CSSParser.h"
35 #include "CompositeAnimation.h"
36 #include "EventNames.h"
37 #include "Frame.h"
38 #include "RenderView.h"
39 #include "WebKitAnimationEvent.h"
40 #include "WebKitAnimationList.h"
41 #include "WebKitTransitionEvent.h"
42 #include <wtf/CurrentTime.h>
43 #include <wtf/UnusedParam.h>
44 
45 namespace WebCore {
46 
47 // FIXME: Why isn't this set to 60fps or something?
48 static const double cAnimationTimerDelay = 0.025;
49 static const double cBeginAnimationUpdateTimeNotSet = -1;
50 
AnimationControllerPrivate(Frame * frame)51 AnimationControllerPrivate::AnimationControllerPrivate(Frame* frame)
52     : m_animationTimer(this, &AnimationControllerPrivate::animationTimerFired)
53     , m_updateStyleIfNeededDispatcher(this, &AnimationControllerPrivate::updateStyleIfNeededDispatcherFired)
54     , m_frame(frame)
55     , m_beginAnimationUpdateTime(cBeginAnimationUpdateTimeNotSet)
56     , m_animationsWaitingForStyle()
57     , m_animationsWaitingForStartTimeResponse()
58     , m_waitingForAsyncStartNotification(false)
59 {
60 }
61 
~AnimationControllerPrivate()62 AnimationControllerPrivate::~AnimationControllerPrivate()
63 {
64 }
65 
accessCompositeAnimation(RenderObject * renderer)66 PassRefPtr<CompositeAnimation> AnimationControllerPrivate::accessCompositeAnimation(RenderObject* renderer)
67 {
68     RefPtr<CompositeAnimation> animation = m_compositeAnimations.get(renderer);
69     if (!animation) {
70         animation = CompositeAnimation::create(this);
71         m_compositeAnimations.set(renderer, animation);
72     }
73     return animation;
74 }
75 
clear(RenderObject * renderer)76 bool AnimationControllerPrivate::clear(RenderObject* renderer)
77 {
78     // Return false if we didn't do anything OR we are suspended (so we don't try to
79     // do a setNeedsStyleRecalc() when suspended).
80     PassRefPtr<CompositeAnimation> animation = m_compositeAnimations.take(renderer);
81     if (!animation)
82         return false;
83     animation->clearRenderer();
84     return animation->suspended();
85 }
86 
updateAnimationTimer(bool callSetChanged)87 void AnimationControllerPrivate::updateAnimationTimer(bool callSetChanged/* = false*/)
88 {
89     double needsService = -1;
90     bool calledSetChanged = false;
91 
92     RenderObjectAnimationMap::const_iterator animationsEnd = m_compositeAnimations.end();
93     for (RenderObjectAnimationMap::const_iterator it = m_compositeAnimations.begin(); it != animationsEnd; ++it) {
94         CompositeAnimation* compAnim = it->second.get();
95         if (!compAnim->suspended() && compAnim->hasAnimations()) {
96             double t = compAnim->timeToNextService();
97             if (t != -1 && (t < needsService || needsService == -1))
98                 needsService = t;
99             if (needsService == 0) {
100                 if (callSetChanged) {
101                     Node* node = it->first->node();
102                     ASSERT(!node || (node->document() && !node->document()->inPageCache()));
103                     node->setNeedsStyleRecalc(SyntheticStyleChange);
104                     calledSetChanged = true;
105                 }
106                 else
107                     break;
108             }
109         }
110     }
111 
112     if (calledSetChanged)
113         m_frame->document()->updateStyleIfNeeded();
114 
115     // If we want service immediately, we start a repeating timer to reduce the overhead of starting
116     if (needsService == 0) {
117         if (!m_animationTimer.isActive() || m_animationTimer.repeatInterval() == 0)
118             m_animationTimer.startRepeating(cAnimationTimerDelay);
119         return;
120     }
121 
122     // If we don't need service, we want to make sure the timer is no longer running
123     if (needsService < 0) {
124         if (m_animationTimer.isActive())
125             m_animationTimer.stop();
126         return;
127     }
128 
129     // Otherwise, we want to start a one-shot timer so we get here again
130     if (m_animationTimer.isActive())
131         m_animationTimer.stop();
132     m_animationTimer.startOneShot(needsService);
133 }
134 
updateStyleIfNeededDispatcherFired(Timer<AnimationControllerPrivate> *)135 void AnimationControllerPrivate::updateStyleIfNeededDispatcherFired(Timer<AnimationControllerPrivate>*)
136 {
137     fireEventsAndUpdateStyle();
138 }
139 
fireEventsAndUpdateStyle()140 void AnimationControllerPrivate::fireEventsAndUpdateStyle()
141 {
142     // Protect the frame from getting destroyed in the event handler
143     RefPtr<Frame> protector = m_frame;
144 
145     bool updateStyle = !m_eventsToDispatch.isEmpty() || !m_nodeChangesToDispatch.isEmpty();
146 
147     // fire all the events
148     Vector<EventToDispatch> eventsToDispatch = m_eventsToDispatch;
149     m_eventsToDispatch.clear();
150     Vector<EventToDispatch>::const_iterator eventsToDispatchEnd = eventsToDispatch.end();
151     for (Vector<EventToDispatch>::const_iterator it = eventsToDispatch.begin(); it != eventsToDispatchEnd; ++it) {
152         if (it->eventType == eventNames().webkitTransitionEndEvent)
153             it->element->dispatchEvent(WebKitTransitionEvent::create(it->eventType, it->name, it->elapsedTime));
154         else
155             it->element->dispatchEvent(WebKitAnimationEvent::create(it->eventType, it->name, it->elapsedTime));
156     }
157 
158     // call setChanged on all the elements
159     Vector<RefPtr<Node> >::const_iterator nodeChangesToDispatchEnd = m_nodeChangesToDispatch.end();
160     for (Vector<RefPtr<Node> >::const_iterator it = m_nodeChangesToDispatch.begin(); it != nodeChangesToDispatchEnd; ++it)
161         (*it)->setNeedsStyleRecalc(SyntheticStyleChange);
162 
163     m_nodeChangesToDispatch.clear();
164 
165     if (updateStyle && m_frame)
166         m_frame->document()->updateStyleIfNeeded();
167 }
168 
startUpdateStyleIfNeededDispatcher()169 void AnimationControllerPrivate::startUpdateStyleIfNeededDispatcher()
170 {
171     if (!m_updateStyleIfNeededDispatcher.isActive())
172         m_updateStyleIfNeededDispatcher.startOneShot(0);
173 }
174 
addEventToDispatch(PassRefPtr<Element> element,const AtomicString & eventType,const String & name,double elapsedTime)175 void AnimationControllerPrivate::addEventToDispatch(PassRefPtr<Element> element, const AtomicString& eventType, const String& name, double elapsedTime)
176 {
177     m_eventsToDispatch.grow(m_eventsToDispatch.size()+1);
178     EventToDispatch& event = m_eventsToDispatch[m_eventsToDispatch.size()-1];
179     event.element = element;
180     event.eventType = eventType;
181     event.name = name;
182     event.elapsedTime = elapsedTime;
183 
184     startUpdateStyleIfNeededDispatcher();
185 }
186 
addNodeChangeToDispatch(PassRefPtr<Node> node)187 void AnimationControllerPrivate::addNodeChangeToDispatch(PassRefPtr<Node> node)
188 {
189     ASSERT(!node || (node->document() && !node->document()->inPageCache()));
190     if (!node)
191         return;
192 
193     m_nodeChangesToDispatch.append(node);
194     startUpdateStyleIfNeededDispatcher();
195 }
196 
animationTimerFired(Timer<AnimationControllerPrivate> *)197 void AnimationControllerPrivate::animationTimerFired(Timer<AnimationControllerPrivate>*)
198 {
199     // Make sure animationUpdateTime is updated, so that it is current even if no
200     // styleChange has happened (e.g. accelerated animations)
201     setBeginAnimationUpdateTime(cBeginAnimationUpdateTimeNotSet);
202 
203     // When the timer fires, all we do is call setChanged on all DOM nodes with running animations and then do an immediate
204     // updateStyleIfNeeded.  It will then call back to us with new information.
205     updateAnimationTimer(true);
206 
207     // Fire events right away, to avoid a flash of unanimated style after an animation completes, and before
208     // the 'end' event fires.
209     fireEventsAndUpdateStyle();
210 }
211 
isRunningAnimationOnRenderer(RenderObject * renderer,CSSPropertyID property,bool isRunningNow) const212 bool AnimationControllerPrivate::isRunningAnimationOnRenderer(RenderObject* renderer, CSSPropertyID property, bool isRunningNow) const
213 {
214     RefPtr<CompositeAnimation> animation = m_compositeAnimations.get(renderer);
215     if (!animation)
216         return false;
217 
218     return animation->isAnimatingProperty(property, false, isRunningNow);
219 }
220 
isRunningAcceleratedAnimationOnRenderer(RenderObject * renderer,CSSPropertyID property,bool isRunningNow) const221 bool AnimationControllerPrivate::isRunningAcceleratedAnimationOnRenderer(RenderObject* renderer, CSSPropertyID property, bool isRunningNow) const
222 {
223     RefPtr<CompositeAnimation> animation = m_compositeAnimations.get(renderer);
224     if (!animation)
225         return false;
226 
227     return animation->isAnimatingProperty(property, true, isRunningNow);
228 }
229 
suspendAnimations()230 void AnimationControllerPrivate::suspendAnimations()
231 {
232     suspendAnimationsForDocument(m_frame->document());
233 
234     // Traverse subframes
235     for (Frame* child = m_frame->tree()->firstChild(); child; child = child->tree()->nextSibling())
236         child->animation()->suspendAnimations();
237 }
238 
resumeAnimations()239 void AnimationControllerPrivate::resumeAnimations()
240 {
241     resumeAnimationsForDocument(m_frame->document());
242 
243     // Traverse subframes
244     for (Frame* child = m_frame->tree()->firstChild(); child; child = child->tree()->nextSibling())
245         child->animation()->resumeAnimations();
246 }
247 
suspendAnimationsForDocument(Document * document)248 void AnimationControllerPrivate::suspendAnimationsForDocument(Document* document)
249 {
250     setBeginAnimationUpdateTime(cBeginAnimationUpdateTimeNotSet);
251 
252     RenderObjectAnimationMap::const_iterator animationsEnd = m_compositeAnimations.end();
253     for (RenderObjectAnimationMap::const_iterator it = m_compositeAnimations.begin(); it != animationsEnd; ++it) {
254         RenderObject* renderer = it->first;
255         if (renderer->document() == document) {
256             CompositeAnimation* compAnim = it->second.get();
257             compAnim->suspendAnimations();
258         }
259     }
260 
261     updateAnimationTimer();
262 }
263 
resumeAnimationsForDocument(Document * document)264 void AnimationControllerPrivate::resumeAnimationsForDocument(Document* document)
265 {
266     setBeginAnimationUpdateTime(cBeginAnimationUpdateTimeNotSet);
267 
268     RenderObjectAnimationMap::const_iterator animationsEnd = m_compositeAnimations.end();
269     for (RenderObjectAnimationMap::const_iterator it = m_compositeAnimations.begin(); it != animationsEnd; ++it) {
270         RenderObject* renderer = it->first;
271         if (renderer->document() == document) {
272             CompositeAnimation* compAnim = it->second.get();
273             compAnim->resumeAnimations();
274         }
275     }
276 
277     updateAnimationTimer();
278 }
279 
pauseAnimationAtTime(RenderObject * renderer,const String & name,double t)280 bool AnimationControllerPrivate::pauseAnimationAtTime(RenderObject* renderer, const String& name, double t)
281 {
282     if (!renderer)
283         return false;
284 
285     RefPtr<CompositeAnimation> compAnim = accessCompositeAnimation(renderer);
286     if (!compAnim)
287         return false;
288 
289     if (compAnim->pauseAnimationAtTime(name, t)) {
290         renderer->node()->setNeedsStyleRecalc(SyntheticStyleChange);
291         startUpdateStyleIfNeededDispatcher();
292         return true;
293     }
294 
295     return false;
296 }
297 
pauseTransitionAtTime(RenderObject * renderer,const String & property,double t)298 bool AnimationControllerPrivate::pauseTransitionAtTime(RenderObject* renderer, const String& property, double t)
299 {
300     if (!renderer)
301         return false;
302 
303     RefPtr<CompositeAnimation> compAnim = accessCompositeAnimation(renderer);
304     if (!compAnim)
305         return false;
306 
307     if (compAnim->pauseTransitionAtTime(cssPropertyID(property), t)) {
308         renderer->node()->setNeedsStyleRecalc(SyntheticStyleChange);
309         startUpdateStyleIfNeededDispatcher();
310         return true;
311     }
312 
313     return false;
314 }
315 
beginAnimationUpdateTime()316 double AnimationControllerPrivate::beginAnimationUpdateTime()
317 {
318     if (m_beginAnimationUpdateTime == cBeginAnimationUpdateTimeNotSet)
319         m_beginAnimationUpdateTime = currentTime();
320     return m_beginAnimationUpdateTime;
321 }
322 
endAnimationUpdate()323 void AnimationControllerPrivate::endAnimationUpdate()
324 {
325     styleAvailable();
326     if (!m_waitingForAsyncStartNotification)
327         startTimeResponse(beginAnimationUpdateTime());
328 }
329 
receivedStartTimeResponse(double time)330 void AnimationControllerPrivate::receivedStartTimeResponse(double time)
331 {
332     m_waitingForAsyncStartNotification = false;
333     startTimeResponse(time);
334 }
335 
getAnimatedStyleForRenderer(RenderObject * renderer)336 PassRefPtr<RenderStyle> AnimationControllerPrivate::getAnimatedStyleForRenderer(RenderObject* renderer)
337 {
338     if (!renderer)
339         return 0;
340 
341     RefPtr<CompositeAnimation> rendererAnimations = m_compositeAnimations.get(renderer);
342     if (!rendererAnimations)
343         return renderer->style();
344 
345     // Make sure animationUpdateTime is updated, so that it is current even if no
346     // styleChange has happened (e.g. accelerated animations).
347     setBeginAnimationUpdateTime(cBeginAnimationUpdateTimeNotSet);
348     RefPtr<RenderStyle> animatingStyle = rendererAnimations->getAnimatedStyle();
349     if (!animatingStyle)
350         animatingStyle = renderer->style();
351 
352     return animatingStyle.release();
353 }
354 
numberOfActiveAnimations() const355 unsigned AnimationControllerPrivate::numberOfActiveAnimations() const
356 {
357     unsigned count = 0;
358 
359     RenderObjectAnimationMap::const_iterator animationsEnd = m_compositeAnimations.end();
360     for (RenderObjectAnimationMap::const_iterator it = m_compositeAnimations.begin(); it != animationsEnd; ++it) {
361         CompositeAnimation* compAnim = it->second.get();
362         count += compAnim->numberOfActiveAnimations();
363     }
364 
365     return count;
366 }
367 
addToAnimationsWaitingForStyle(AnimationBase * animation)368 void AnimationControllerPrivate::addToAnimationsWaitingForStyle(AnimationBase* animation)
369 {
370     // Make sure this animation is not in the start time waiters
371     m_animationsWaitingForStartTimeResponse.remove(animation);
372 
373     m_animationsWaitingForStyle.add(animation);
374 }
375 
removeFromAnimationsWaitingForStyle(AnimationBase * animationToRemove)376 void AnimationControllerPrivate::removeFromAnimationsWaitingForStyle(AnimationBase* animationToRemove)
377 {
378     m_animationsWaitingForStyle.remove(animationToRemove);
379 }
380 
styleAvailable()381 void AnimationControllerPrivate::styleAvailable()
382 {
383     // Go through list of waiters and send them on their way
384     WaitingAnimationsSet::const_iterator it = m_animationsWaitingForStyle.begin();
385     WaitingAnimationsSet::const_iterator end = m_animationsWaitingForStyle.end();
386     for (; it != end; ++it)
387         (*it)->styleAvailable();
388 
389     m_animationsWaitingForStyle.clear();
390 }
391 
addToAnimationsWaitingForStartTimeResponse(AnimationBase * animation,bool willGetResponse)392 void AnimationControllerPrivate::addToAnimationsWaitingForStartTimeResponse(AnimationBase* animation, bool willGetResponse)
393 {
394     // If willGetResponse is true, it means this animation is actually waiting for a response
395     // (which will come in as a call to notifyAnimationStarted()).
396     // In that case we don't need to add it to this list. We just set a waitingForAResponse flag
397     // which says we are waiting for the response. If willGetResponse is false, this animation
398     // is not waiting for a response for itself, but rather for a notifyXXXStarted() call for
399     // another animation to which it will sync.
400     //
401     // When endAnimationUpdate() is called we check to see if the waitingForAResponse flag is
402     // true. If so, we just return and will do our work when the first notifyXXXStarted() call
403     // comes in. If it is false, we will not be getting a notifyXXXStarted() call, so we will
404     // do our work right away. In both cases we call the onAnimationStartResponse() method
405     // on each animation. In the first case we send in the time we got from notifyXXXStarted().
406     // In the second case, we just pass in the beginAnimationUpdateTime().
407     //
408     // This will synchronize all software and accelerated animations started in the same
409     // updateStyleIfNeeded cycle.
410     //
411 
412     if (willGetResponse)
413         m_waitingForAsyncStartNotification = true;
414 
415     m_animationsWaitingForStartTimeResponse.add(animation);
416 }
417 
removeFromAnimationsWaitingForStartTimeResponse(AnimationBase * animationToRemove)418 void AnimationControllerPrivate::removeFromAnimationsWaitingForStartTimeResponse(AnimationBase* animationToRemove)
419 {
420     m_animationsWaitingForStartTimeResponse.remove(animationToRemove);
421 
422     if (m_animationsWaitingForStartTimeResponse.isEmpty())
423         m_waitingForAsyncStartNotification = false;
424 }
425 
startTimeResponse(double time)426 void AnimationControllerPrivate::startTimeResponse(double time)
427 {
428     // Go through list of waiters and send them on their way
429 
430     WaitingAnimationsSet::const_iterator it = m_animationsWaitingForStartTimeResponse.begin();
431     WaitingAnimationsSet::const_iterator end = m_animationsWaitingForStartTimeResponse.end();
432     for (; it != end; ++it)
433         (*it)->onAnimationStartResponse(time);
434 
435     m_animationsWaitingForStartTimeResponse.clear();
436     m_waitingForAsyncStartNotification = false;
437 }
438 
animationWillBeRemoved(AnimationBase * animation)439 void AnimationControllerPrivate::animationWillBeRemoved(AnimationBase* animation)
440 {
441     removeFromAnimationsWaitingForStyle(animation);
442     removeFromAnimationsWaitingForStartTimeResponse(animation);
443 }
444 
animationsForRenderer(RenderObject * renderer) const445 PassRefPtr<WebKitAnimationList> AnimationControllerPrivate::animationsForRenderer(RenderObject* renderer) const
446 {
447     RefPtr<CompositeAnimation> animation = m_compositeAnimations.get(renderer);
448 
449     if (!animation)
450         return 0;
451 
452     return animation->animations();
453 }
454 
AnimationController(Frame * frame)455 AnimationController::AnimationController(Frame* frame)
456     : m_data(new AnimationControllerPrivate(frame))
457 {
458 }
459 
~AnimationController()460 AnimationController::~AnimationController()
461 {
462     delete m_data;
463 }
464 
cancelAnimations(RenderObject * renderer)465 void AnimationController::cancelAnimations(RenderObject* renderer)
466 {
467     if (!m_data->hasAnimations())
468         return;
469 
470     if (m_data->clear(renderer)) {
471         Node* node = renderer->node();
472         ASSERT(!node || (node->document() && !node->document()->inPageCache()));
473         node->setNeedsStyleRecalc(SyntheticStyleChange);
474     }
475 }
476 
updateAnimations(RenderObject * renderer,RenderStyle * newStyle)477 PassRefPtr<RenderStyle> AnimationController::updateAnimations(RenderObject* renderer, RenderStyle* newStyle)
478 {
479     // Don't do anything if we're in the cache
480     if (!renderer->document() || renderer->document()->inPageCache())
481         return newStyle;
482 
483     RenderStyle* oldStyle = renderer->style();
484 
485     if ((!oldStyle || (!oldStyle->animations() && !oldStyle->transitions())) && (!newStyle->animations() && !newStyle->transitions()))
486         return newStyle;
487 
488     // Don't run transitions when printing.
489     if (renderer->view()->printing())
490         return newStyle;
491 
492     // Fetch our current set of implicit animations from a hashtable.  We then compare them
493     // against the animations in the style and make sure we're in sync.  If destination values
494     // have changed, we reset the animation.  We then do a blend to get new values and we return
495     // a new style.
496     ASSERT(renderer->node()); // FIXME: We do not animate generated content yet.
497 
498     RefPtr<CompositeAnimation> rendererAnimations = m_data->accessCompositeAnimation(renderer);
499     RefPtr<RenderStyle> blendedStyle = rendererAnimations->animate(renderer, oldStyle, newStyle);
500 
501     m_data->updateAnimationTimer();
502 
503     if (blendedStyle != newStyle) {
504         // If the animations/transitions change opacity or transform, we need to update
505         // the style to impose the stacking rules. Note that this is also
506         // done in CSSStyleSelector::adjustRenderStyle().
507         if (blendedStyle->hasAutoZIndex() && (blendedStyle->opacity() < 1.0f || blendedStyle->hasTransform()))
508             blendedStyle->setZIndex(0);
509     }
510     return blendedStyle.release();
511 }
512 
getAnimatedStyleForRenderer(RenderObject * renderer)513 PassRefPtr<RenderStyle> AnimationController::getAnimatedStyleForRenderer(RenderObject* renderer)
514 {
515     return m_data->getAnimatedStyleForRenderer(renderer);
516 }
517 
notifyAnimationStarted(RenderObject *,double startTime)518 void AnimationController::notifyAnimationStarted(RenderObject*, double startTime)
519 {
520     m_data->receivedStartTimeResponse(startTime);
521 }
522 
pauseAnimationAtTime(RenderObject * renderer,const String & name,double t)523 bool AnimationController::pauseAnimationAtTime(RenderObject* renderer, const String& name, double t)
524 {
525     return m_data->pauseAnimationAtTime(renderer, name, t);
526 }
527 
numberOfActiveAnimations() const528 unsigned AnimationController::numberOfActiveAnimations() const
529 {
530     return m_data->numberOfActiveAnimations();
531 }
532 
pauseTransitionAtTime(RenderObject * renderer,const String & property,double t)533 bool AnimationController::pauseTransitionAtTime(RenderObject* renderer, const String& property, double t)
534 {
535     return m_data->pauseTransitionAtTime(renderer, property, t);
536 }
537 
isRunningAnimationOnRenderer(RenderObject * renderer,CSSPropertyID property,bool isRunningNow) const538 bool AnimationController::isRunningAnimationOnRenderer(RenderObject* renderer, CSSPropertyID property, bool isRunningNow) const
539 {
540     return m_data->isRunningAnimationOnRenderer(renderer, property, isRunningNow);
541 }
542 
isRunningAcceleratedAnimationOnRenderer(RenderObject * renderer,CSSPropertyID property,bool isRunningNow) const543 bool AnimationController::isRunningAcceleratedAnimationOnRenderer(RenderObject* renderer, CSSPropertyID property, bool isRunningNow) const
544 {
545     return m_data->isRunningAcceleratedAnimationOnRenderer(renderer, property, isRunningNow);
546 }
547 
suspendAnimations()548 void AnimationController::suspendAnimations()
549 {
550     m_data->suspendAnimations();
551 }
552 
resumeAnimations()553 void AnimationController::resumeAnimations()
554 {
555     m_data->resumeAnimations();
556 }
557 
suspendAnimationsForDocument(Document * document)558 void AnimationController::suspendAnimationsForDocument(Document* document)
559 {
560     m_data->suspendAnimationsForDocument(document);
561 }
562 
resumeAnimationsForDocument(Document * document)563 void AnimationController::resumeAnimationsForDocument(Document* document)
564 {
565     m_data->resumeAnimationsForDocument(document);
566 }
567 
beginAnimationUpdate()568 void AnimationController::beginAnimationUpdate()
569 {
570     m_data->setBeginAnimationUpdateTime(cBeginAnimationUpdateTimeNotSet);
571 }
572 
endAnimationUpdate()573 void AnimationController::endAnimationUpdate()
574 {
575     m_data->endAnimationUpdate();
576 }
577 
supportsAcceleratedAnimationOfProperty(CSSPropertyID property)578 bool AnimationController::supportsAcceleratedAnimationOfProperty(CSSPropertyID property)
579 {
580 #if USE(ACCELERATED_COMPOSITING)
581     return AnimationBase::animationOfPropertyIsAccelerated(property);
582 #else
583     UNUSED_PARAM(property);
584     return false;
585 #endif
586 }
587 
animationsForRenderer(RenderObject * renderer) const588 PassRefPtr<WebKitAnimationList> AnimationController::animationsForRenderer(RenderObject* renderer) const
589 {
590     return m_data->animationsForRenderer(renderer);
591 }
592 
593 } // namespace WebCore
594