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