f10b029035b05a69060a171f67c2d32ce734e7b6
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / core / animation / AnimationPlayer.cpp
1 /*
2  * Copyright (C) 2013 Google 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 are
6  * met:
7  *
8  *     * Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  *     * Redistributions in binary form must reproduce the above
11  * copyright notice, this list of conditions and the following disclaimer
12  * in the documentation and/or other materials provided with the
13  * distribution.
14  *     * Neither the name of Google Inc. nor the names of its
15  * contributors may be used to endorse or promote products derived from
16  * this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30
31 #include "config.h"
32 #include "core/animation/AnimationPlayer.h"
33
34 #include "core/animation/Animation.h"
35 #include "core/animation/AnimationTimeline.h"
36 #include "core/dom/Document.h"
37 #include "core/events/AnimationPlayerEvent.h"
38 #include "core/frame/UseCounter.h"
39 #include "platform/TraceEvent.h"
40
41 namespace blink {
42
43 namespace {
44
45 static unsigned nextSequenceNumber()
46 {
47     static unsigned next = 0;
48     return ++next;
49 }
50
51 }
52
53 PassRefPtrWillBeRawPtr<AnimationPlayer> AnimationPlayer::create(ExecutionContext* executionContext, AnimationTimeline& timeline, AnimationNode* content)
54 {
55     RefPtrWillBeRawPtr<AnimationPlayer> player = adoptRefWillBeNoop(new AnimationPlayer(executionContext, timeline, content));
56     player->uncancel();
57     timeline.document()->compositorPendingAnimations().add(player.get());
58     player->suspendIfNeeded();
59     return player.release();
60 }
61
62 AnimationPlayer::AnimationPlayer(ExecutionContext* executionContext, AnimationTimeline& timeline, AnimationNode* content)
63     : ActiveDOMObject(executionContext)
64     , m_playbackRate(1)
65     , m_startTime(nullValue())
66     , m_holdTime(0)
67     , m_sequenceNumber(nextSequenceNumber())
68     , m_content(content)
69     , m_timeline(&timeline)
70     , m_paused(false)
71     , m_held(true)
72     , m_isPausedForTesting(false)
73     , m_outdated(true)
74     , m_finished(true)
75     , m_compositorState(nullptr)
76     , m_compositorPending(true)
77     , m_currentTimePending(false)
78     , m_idle(true)
79 {
80     if (m_content) {
81         if (m_content->player()) {
82             m_content->player()->cancel();
83             m_content->player()->setSource(0);
84         }
85         m_content->attach(this);
86     }
87 }
88
89 AnimationPlayer::~AnimationPlayer()
90 {
91 #if !ENABLE(OILPAN)
92     if (m_content)
93         m_content->detach();
94     if (m_timeline)
95         m_timeline->playerDestroyed(this);
96 #endif
97 }
98
99 double AnimationPlayer::sourceEnd() const
100 {
101     return m_content ? m_content->endTimeInternal() : 0;
102 }
103
104 bool AnimationPlayer::limited(double currentTime) const
105 {
106     return (m_playbackRate < 0 && currentTime <= 0) || (m_playbackRate > 0 && currentTime >= sourceEnd());
107 }
108
109 void AnimationPlayer::setCurrentTimeInternal(double newCurrentTime, TimingUpdateReason reason)
110 {
111     ASSERT(std::isfinite(newCurrentTime));
112
113     bool oldHeld = m_held;
114     bool outdated = false;
115     bool isLimited = limited(newCurrentTime);
116     m_held = m_paused || !m_playbackRate || isLimited || std::isnan(m_startTime);
117     if (m_held) {
118         if (!oldHeld || m_holdTime != newCurrentTime)
119             outdated = true;
120         m_holdTime = newCurrentTime;
121         if (m_paused || !m_playbackRate) {
122             m_startTime = nullValue();
123         } else if (isLimited && std::isnan(m_startTime) && reason == TimingUpdateForAnimationFrame) {
124             m_startTime = calculateStartTime(newCurrentTime);
125         }
126     } else {
127         m_holdTime = nullValue();
128         m_startTime = calculateStartTime(newCurrentTime);
129         setFinished(false);
130         outdated = true;
131     }
132
133     if (outdated) {
134         setOutdated();
135     }
136 }
137
138 // Update timing to reflect updated animation clock due to tick
139 void AnimationPlayer::updateCurrentTimingState(TimingUpdateReason reason)
140 {
141     if (m_held) {
142         setCurrentTimeInternal(m_holdTime, reason);
143         return;
144     }
145     if (!limited(calculateCurrentTime()))
146         return;
147     m_held = true;
148     m_holdTime = m_playbackRate < 0 ? 0 : sourceEnd();
149 }
150
151 double AnimationPlayer::startTime(bool& isNull) const
152 {
153     double result = startTime();
154     isNull = std::isnan(result);
155     return result;
156 }
157
158 double AnimationPlayer::startTime() const
159 {
160     UseCounter::count(executionContext(), UseCounter::AnimationPlayerGetStartTime);
161     return m_startTime * 1000;
162 }
163
164 double AnimationPlayer::currentTime(bool& isNull)
165 {
166     double result = currentTime();
167     isNull = std::isnan(result);
168     return result;
169 }
170
171 double AnimationPlayer::currentTime()
172 {
173     UseCounter::count(executionContext(), UseCounter::AnimationPlayerGetCurrentTime);
174     if (m_currentTimePending || m_idle)
175         return std::numeric_limits<double>::quiet_NaN();
176     return currentTimeInternal() * 1000;
177 }
178
179 double AnimationPlayer::currentTimeInternal()
180 {
181     updateCurrentTimingState(TimingUpdateOnDemand);
182     if (m_held)
183         return m_holdTime;
184     return calculateCurrentTime();
185 }
186
187 void AnimationPlayer::preCommit(bool startOnCompositor)
188 {
189     if (m_compositorState && m_compositorState->pendingAction == Start) {
190         // Still waiting for a start time.
191         return;
192     }
193
194     bool softChange = m_compositorState && (paused() || m_compositorState->playbackRate != m_playbackRate);
195     bool hardChange = m_compositorState && (m_compositorState->sourceChanged || (m_compositorState->startTime != m_startTime && !std::isnan(m_compositorState->startTime) && !std::isnan(m_startTime)));
196
197     // FIXME: softChange && !hardChange should generate a Pause/ThenStart,
198     // not a Cancel, but we can't communicate these to the compositor yet.
199
200     bool changed = softChange || hardChange;
201     bool shouldCancel = (!playing() && m_compositorState) || changed;
202     bool shouldStart = playing() && (!m_compositorState || changed);
203
204     if (shouldCancel) {
205         cancelAnimationOnCompositor();
206         m_compositorState = nullptr;
207
208     }
209
210     if (!shouldStart) {
211         m_currentTimePending = false;
212     }
213
214     if (shouldStart && startOnCompositor && maybeStartAnimationOnCompositor()) {
215         m_compositorState = adoptPtr(new CompositorState(*this));
216     }
217 }
218
219 void AnimationPlayer::postCommit(double timelineTime)
220 {
221     m_compositorPending = false;
222
223     if (!m_compositorState || m_compositorState->pendingAction == None)
224         return;
225
226     switch (m_compositorState->pendingAction) {
227     case Start:
228         if (!std::isnan(m_compositorState->startTime)) {
229             ASSERT(m_startTime == m_compositorState->startTime);
230             m_compositorState->pendingAction = None;
231         }
232         break;
233     case Pause:
234     case PauseThenStart:
235         ASSERT(std::isnan(m_startTime));
236         m_compositorState->pendingAction = None;
237         setCurrentTimeInternal((timelineTime - m_compositorState->startTime) * m_playbackRate, TimingUpdateForAnimationFrame);
238         m_currentTimePending = false;
239         break;
240     default:
241         ASSERT_NOT_REACHED();
242     }
243 }
244
245 void AnimationPlayer::notifyCompositorStartTime(double timelineTime)
246 {
247     if (m_compositorState) {
248         ASSERT(m_compositorState->pendingAction == Start);
249         ASSERT(std::isnan(m_compositorState->startTime));
250
251         double initialCompositorHoldTime = m_compositorState->holdTime;
252         m_compositorState->pendingAction = None;
253         m_compositorState->startTime = timelineTime;
254
255         if (paused() || m_compositorState->playbackRate != m_playbackRate || m_compositorState->sourceChanged) {
256             // Paused state, playback rate, or source changed while starting.
257             setCompositorPending();
258         }
259
260         if (m_startTime == timelineTime) {
261             // The start time was set to the incoming compositor start time.
262             // Unlikely, but possible.
263             // FIXME: Depending on what changed above this might still be pending.
264             // Maybe...
265             m_currentTimePending = false;
266             return;
267         }
268
269         if (!std::isnan(m_startTime) || currentTimeInternal() != initialCompositorHoldTime) {
270             // A new start time or current time was set while starting.
271             setCompositorPending();
272             return;
273         }
274     }
275
276     if (playing()) {
277         ASSERT(std::isnan(m_startTime));
278         ASSERT(m_held);
279
280         if (m_playbackRate == 0) {
281             setStartTimeInternal(timelineTime);
282         } else {
283             setStartTimeInternal(timelineTime + currentTimeInternal() / -m_playbackRate);
284         }
285
286         // FIXME: This avoids marking this player as outdated needlessly when a start time
287         // is notified, but we should refactor how outdating works to avoid this.
288         m_outdated = false;
289
290         m_currentTimePending = false;
291     }
292 }
293
294 double AnimationPlayer::calculateStartTime(double currentTime) const
295 {
296     return m_timeline->effectiveTime() - currentTime / m_playbackRate;
297 }
298
299 double AnimationPlayer::calculateCurrentTime() const
300 {
301     ASSERT(!m_held);
302     if (isNull(m_startTime) || !m_timeline)
303         return 0;
304     return (m_timeline->effectiveTime() - m_startTime) * m_playbackRate;
305 }
306
307 void AnimationPlayer::setCurrentTime(double newCurrentTime)
308 {
309     UseCounter::count(executionContext(), UseCounter::AnimationPlayerSetCurrentTime);
310     if (!std::isfinite(newCurrentTime))
311         return;
312
313     setCompositorPending();
314     m_currentTimePending = false;
315     setCurrentTimeInternal(newCurrentTime / 1000, TimingUpdateOnDemand);
316 }
317
318 void AnimationPlayer::setStartTime(double startTime)
319 {
320     UseCounter::count(executionContext(), UseCounter::AnimationPlayerSetStartTime);
321     if (m_paused || m_idle)
322         return;
323     if (!std::isfinite(startTime))
324         return;
325     if (startTime == m_startTime)
326         return;
327
328     setCompositorPending();
329     m_currentTimePending = false;
330     setStartTimeInternal(startTime / 1000);
331 }
332
333 void AnimationPlayer::setStartTimeInternal(double newStartTime)
334 {
335     ASSERT(!m_paused);
336     ASSERT(std::isfinite(newStartTime));
337     ASSERT(newStartTime != m_startTime);
338
339     bool hadStartTime = hasStartTime();
340     double previousCurrentTime = currentTimeInternal();
341     m_startTime = newStartTime;
342     if (m_held && m_playbackRate) {
343         // If held, the start time would still be derrived from the hold time.
344         // Force a new, limited, current time.
345         m_held = false;
346         double currentTime = calculateCurrentTime();
347         if (m_playbackRate > 0 && currentTime > sourceEnd()) {
348             currentTime = sourceEnd();
349         } else if (m_playbackRate < 0 && currentTime < 0) {
350             currentTime = 0;
351         }
352         setCurrentTimeInternal(currentTime, TimingUpdateOnDemand);
353     }
354     double newCurrentTime = currentTimeInternal();
355
356     if (previousCurrentTime != newCurrentTime) {
357         setOutdated();
358     } else if (!hadStartTime && m_timeline) {
359         // Even though this player is not outdated, time to effect change is
360         // infinity until start time is set.
361         m_timeline->wake();
362     }
363 }
364
365 void AnimationPlayer::setSource(AnimationNode* newSource)
366 {
367     if (m_content == newSource)
368         return;
369
370     setCompositorPending(true);
371
372     double storedCurrentTime = currentTimeInternal();
373     if (m_content)
374         m_content->detach();
375     m_content = newSource;
376     if (newSource) {
377         // FIXME: This logic needs to be updated once groups are implemented
378         if (newSource->player()) {
379             newSource->player()->cancel();
380             newSource->player()->setSource(0);
381         }
382         newSource->attach(this);
383         setOutdated();
384     }
385     setCurrentTimeInternal(storedCurrentTime, TimingUpdateOnDemand);
386 }
387
388 String AnimationPlayer::playState()
389 {
390     switch (playStateInternal()) {
391     case Idle:
392         return "idle";
393     case Pending:
394         return "pending";
395     case Running:
396         return "running";
397     case Paused:
398         return "paused";
399     case Finished:
400         return "finished";
401     default:
402         ASSERT_NOT_REACHED();
403         return "";
404     }
405 }
406
407 AnimationPlayer::AnimationPlayState AnimationPlayer::playStateInternal()
408 {
409     if (m_idle)
410         return Idle;
411     if (m_currentTimePending || (isNull(m_startTime) && !m_paused && m_playbackRate != 0))
412         return Pending;
413     if (m_paused)
414         return Paused;
415     if (finished())
416         return Finished;
417     return Running;
418 }
419
420 void AnimationPlayer::pause()
421 {
422     if (m_paused)
423         return;
424     if (playing()) {
425         setCompositorPending();
426         m_currentTimePending = true;
427     }
428     m_paused = true;
429     setCurrentTimeInternal(currentTimeInternal(), TimingUpdateOnDemand);
430 }
431
432 void AnimationPlayer::unpause()
433 {
434     if (!m_paused)
435         return;
436     setCompositorPending();
437     m_currentTimePending = true;
438     unpauseInternal();
439 }
440
441 void AnimationPlayer::unpauseInternal()
442 {
443     if (!m_paused)
444         return;
445     m_paused = false;
446     setCurrentTimeInternal(currentTimeInternal(), TimingUpdateOnDemand);
447 }
448
449 void AnimationPlayer::play()
450 {
451     if (!playing())
452         m_startTime = nullValue();
453
454     setCompositorPending();
455     uncancel();
456     unpauseInternal();
457     if (!m_content)
458         return;
459     double currentTime = this->currentTimeInternal();
460     if (m_playbackRate > 0 && (currentTime < 0 || currentTime >= sourceEnd()))
461         setCurrentTimeInternal(0, TimingUpdateOnDemand);
462     else if (m_playbackRate < 0 && (currentTime <= 0 || currentTime > sourceEnd()))
463         setCurrentTimeInternal(sourceEnd(), TimingUpdateOnDemand);
464     setFinished(false);
465 }
466
467 void AnimationPlayer::reverse()
468 {
469     if (!m_playbackRate) {
470         return;
471     }
472
473     uncancel();
474     setPlaybackRateInternal(-m_playbackRate);
475     play();
476 }
477
478 void AnimationPlayer::finish(ExceptionState& exceptionState)
479 {
480     if (!m_playbackRate || m_idle) {
481         return;
482     }
483     if (m_playbackRate > 0 && sourceEnd() == std::numeric_limits<double>::infinity()) {
484         exceptionState.throwDOMException(InvalidStateError, "AnimationPlayer has source content whose end time is infinity.");
485         return;
486     }
487     if (playing()) {
488         setCompositorPending();
489     }
490
491     uncancel();
492
493     double newCurrentTime = m_playbackRate < 0 ? 0 : sourceEnd();
494     setCurrentTimeInternal(newCurrentTime, TimingUpdateOnDemand);
495     if (!paused()) {
496         m_startTime = calculateStartTime(newCurrentTime);
497     }
498
499     m_currentTimePending = false;
500     ASSERT(finished());
501 }
502
503 const AtomicString& AnimationPlayer::interfaceName() const
504 {
505     return EventTargetNames::AnimationPlayer;
506 }
507
508 ExecutionContext* AnimationPlayer::executionContext() const
509 {
510     return ActiveDOMObject::executionContext();
511 }
512
513 bool AnimationPlayer::hasPendingActivity() const
514 {
515     return m_pendingFinishedEvent || (!m_finished && hasEventListeners(EventTypeNames::finish));
516 }
517
518 void AnimationPlayer::stop()
519 {
520     setFinished(true);
521     m_pendingFinishedEvent = nullptr;
522 }
523
524 bool AnimationPlayer::dispatchEvent(PassRefPtrWillBeRawPtr<Event> event)
525 {
526     if (m_pendingFinishedEvent == event)
527         m_pendingFinishedEvent = nullptr;
528     return EventTargetWithInlineData::dispatchEvent(event);
529 }
530
531 double AnimationPlayer::playbackRate() const
532 {
533     UseCounter::count(executionContext(), UseCounter::AnimationPlayerGetPlaybackRate);
534     return m_playbackRate;
535 }
536
537 void AnimationPlayer::setPlaybackRate(double playbackRate)
538 {
539     UseCounter::count(executionContext(), UseCounter::AnimationPlayerSetPlaybackRate);
540     if (!std::isfinite(playbackRate))
541         return;
542     if (playbackRate == m_playbackRate)
543         return;
544
545     setPlaybackRateInternal(playbackRate);
546 }
547
548 void AnimationPlayer::setPlaybackRateInternal(double playbackRate)
549 {
550     ASSERT(std::isfinite(playbackRate));
551     ASSERT(playbackRate != m_playbackRate);
552
553     setCompositorPending();
554     if (!finished() && !paused() && hasStartTime())
555         m_currentTimePending = true;
556
557     double storedCurrentTime = currentTimeInternal();
558     if ((m_playbackRate < 0 && playbackRate >= 0) || (m_playbackRate > 0 && playbackRate <= 0))
559         setFinished(false);
560
561     m_playbackRate = playbackRate;
562     m_startTime = std::numeric_limits<double>::quiet_NaN();
563     setCurrentTimeInternal(storedCurrentTime, TimingUpdateOnDemand);
564 }
565
566 void AnimationPlayer::setOutdated()
567 {
568     m_outdated = true;
569     if (m_timeline)
570         m_timeline->setOutdatedAnimationPlayer(this);
571 }
572
573 bool AnimationPlayer::canStartAnimationOnCompositor()
574 {
575     if (m_playbackRate == 0)
576         return false;
577
578     return m_timeline && m_content && m_content->isAnimation() && playing();
579 }
580
581 bool AnimationPlayer::maybeStartAnimationOnCompositor()
582 {
583     if (!canStartAnimationOnCompositor())
584         return false;
585
586     double startTime = timeline()->zeroTime() + startTimeInternal();
587     double timeOffset = 0;
588     if (std::isnan(startTime)) {
589         timeOffset = currentTimeInternal();
590     }
591     return toAnimation(m_content.get())->maybeStartAnimationOnCompositor(startTime, timeOffset, m_playbackRate);
592 }
593
594 void AnimationPlayer::setCompositorPending(bool sourceChanged)
595 {
596     // FIXME: Animation could notify this directly?
597     if (!hasActiveAnimationsOnCompositor()) {
598         m_compositorState.release();
599     }
600     if (!m_compositorPending) {
601         m_compositorPending = true;
602         if (sourceChanged && m_compositorState)
603             m_compositorState->sourceChanged = true;
604         timeline()->document()->compositorPendingAnimations().add(this);
605     }
606 }
607
608 bool AnimationPlayer::hasActiveAnimationsOnCompositor()
609 {
610     if (!m_content || !m_content->isAnimation())
611         return false;
612
613     return toAnimation(m_content.get())->hasActiveAnimationsOnCompositor();
614 }
615
616 void AnimationPlayer::cancelAnimationOnCompositor()
617 {
618     if (hasActiveAnimationsOnCompositor())
619         toAnimation(m_content.get())->cancelAnimationOnCompositor();
620 }
621
622 bool AnimationPlayer::update(TimingUpdateReason reason)
623 {
624     if (!m_timeline)
625         return false;
626
627     updateCurrentTimingState(reason);
628     m_outdated = false;
629
630     if (m_content) {
631         double inheritedTime = m_idle || isNull(m_timeline->currentTimeInternal()) ? nullValue() : currentTimeInternal();
632         // Special case for end-exclusivity when playing backwards.
633         if (inheritedTime == 0 && m_playbackRate < 0)
634             inheritedTime = -1;
635         m_content->updateInheritedTime(inheritedTime, reason);
636     }
637
638     if ((m_idle || finished()) && !m_finished) {
639         if (reason == TimingUpdateForAnimationFrame && (m_idle || hasStartTime())) {
640             const AtomicString& eventType = EventTypeNames::finish;
641             if (executionContext() && hasEventListeners(eventType)) {
642                 double eventCurrentTime = currentTimeInternal() * 1000;
643                 m_pendingFinishedEvent = AnimationPlayerEvent::create(eventType, eventCurrentTime, timeline()->currentTime());
644                 m_pendingFinishedEvent->setTarget(this);
645                 m_pendingFinishedEvent->setCurrentTarget(this);
646                 m_timeline->document()->enqueueAnimationFrameEvent(m_pendingFinishedEvent);
647             }
648             setFinished(true);
649         }
650     }
651     ASSERT(!m_outdated);
652     return !m_finished;
653 }
654
655 double AnimationPlayer::timeToEffectChange()
656 {
657     ASSERT(!m_outdated);
658     if (m_held || !hasStartTime())
659         return std::numeric_limits<double>::infinity();
660     if (!m_content)
661         return -currentTimeInternal() / m_playbackRate;
662     if (m_playbackRate > 0)
663         return m_content->timeToForwardsEffectChange() / m_playbackRate;
664     return m_content->timeToReverseEffectChange() / -m_playbackRate;
665 }
666
667 void AnimationPlayer::setFinished(bool finished)
668 {
669     if (m_finished && !finished) {
670         if (m_content) {
671             TRACE_EVENT_ASYNC_BEGIN1("blink", "Animation", this, "Name", TRACE_STR_COPY(m_content->name().utf8().data()));
672         } else {
673             TRACE_EVENT_ASYNC_BEGIN0("blink", "Animation", this);
674         }
675     }
676     if (!m_finished && finished) {
677         TRACE_EVENT_ASYNC_END0("blink", "Animation", this);
678     }
679     m_finished = finished;
680 }
681
682 void AnimationPlayer::cancel()
683 {
684     if (m_idle)
685         return;
686
687     m_holdTime = currentTimeInternal();
688     m_held = true;
689     m_idle = true;
690     m_startTime = nullValue();
691     m_currentTimePending = false;
692     setCompositorPending();
693 }
694
695 void AnimationPlayer::uncancel()
696 {
697     if (!m_idle)
698         return;
699
700     m_idle = false;
701     m_held = true;
702     m_holdTime = 0;
703     setFinished(false);
704 }
705
706
707 #if !ENABLE(OILPAN)
708 bool AnimationPlayer::canFree() const
709 {
710     ASSERT(m_content);
711     return hasOneRef() && m_content->isAnimation() && m_content->hasOneRef();
712 }
713 #endif
714
715 bool AnimationPlayer::addEventListener(const AtomicString& eventType, PassRefPtr<EventListener> listener, bool useCapture)
716 {
717     if (eventType == EventTypeNames::finish)
718         UseCounter::count(executionContext(), UseCounter::AnimationPlayerFinishEvent);
719     return EventTargetWithInlineData::addEventListener(eventType, listener, useCapture);
720 }
721
722 void AnimationPlayer::pauseForTesting(double pauseTime)
723 {
724     RELEASE_ASSERT(!paused());
725     setCurrentTimeInternal(pauseTime, TimingUpdateOnDemand);
726     if (hasActiveAnimationsOnCompositor())
727         toAnimation(m_content.get())->pauseAnimationForTestingOnCompositor(currentTimeInternal());
728     m_isPausedForTesting = true;
729     pause();
730 }
731
732 void AnimationPlayer::trace(Visitor* visitor)
733 {
734     visitor->trace(m_content);
735     visitor->trace(m_timeline);
736     visitor->trace(m_pendingFinishedEvent);
737     EventTargetWithInlineData::trace(visitor);
738 }
739
740 } // namespace