Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(235)

Side by Side Diff: Source/core/animation/AnimationPlayer.cpp

Issue 1113173003: Web Animations: Update naming to reflect spec changes (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: No, really. Created 5 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « Source/core/animation/AnimationPlayer.h ('k') | Source/core/animation/AnimationPlayer.idl » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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/dom/ExceptionCode.h"
38 #include "core/events/AnimationPlayerEvent.h"
39 #include "core/frame/UseCounter.h"
40 #include "core/inspector/InspectorInstrumentation.h"
41 #include "core/inspector/InspectorTraceEvents.h"
42 #include "platform/RuntimeEnabledFeatures.h"
43 #include "platform/TraceEvent.h"
44 #include "public/platform/Platform.h"
45 #include "public/platform/WebCompositorAnimationPlayer.h"
46 #include "public/platform/WebCompositorSupport.h"
47 #include "wtf/MathExtras.h"
48
49 namespace blink {
50
51 namespace {
52
53 static unsigned nextSequenceNumber()
54 {
55 static unsigned next = 0;
56 return ++next;
57 }
58
59 }
60
61 PassRefPtrWillBeRawPtr<AnimationPlayer> AnimationPlayer::create(AnimationNode* s ource, AnimationTimeline* timeline)
62 {
63 if (!timeline) {
64 // FIXME: Support creating players without a timeline.
65 return nullptr;
66 }
67
68 RefPtrWillBeRawPtr<AnimationPlayer> player = adoptRefWillBeNoop(new Animatio nPlayer(timeline->document()->contextDocument().get(), *timeline, source));
69 player->suspendIfNeeded();
70
71 if (timeline) {
72 timeline->playerAttached(*player);
73 player->attachCompositorTimeline();
74 }
75
76 return player.release();
77 }
78
79 AnimationPlayer::AnimationPlayer(ExecutionContext* executionContext, AnimationTi meline& timeline, AnimationNode* content)
80 : ActiveDOMObject(executionContext)
81 , m_playState(Idle)
82 , m_playbackRate(1)
83 , m_startTime(nullValue())
84 , m_holdTime(0)
85 , m_sequenceNumber(nextSequenceNumber())
86 , m_content(content)
87 , m_timeline(&timeline)
88 , m_paused(false)
89 , m_held(true)
90 , m_isPausedForTesting(false)
91 , m_outdated(false)
92 , m_finished(true)
93 , m_compositorState(nullptr)
94 , m_compositorPending(false)
95 , m_compositorGroup(0)
96 , m_currentTimePending(false)
97 , m_stateIsBeingUpdated(false)
98 {
99 if (m_content) {
100 if (m_content->player()) {
101 m_content->player()->cancel();
102 m_content->player()->setSource(0);
103 }
104 m_content->attach(this);
105 }
106 }
107
108 AnimationPlayer::~AnimationPlayer()
109 {
110 #if !ENABLE(OILPAN)
111 if (m_content)
112 m_content->detach();
113 if (m_timeline)
114 m_timeline->playerDestroyed(this);
115 #endif
116
117 destroyCompositorPlayer();
118 }
119
120 #if !ENABLE(OILPAN)
121 void AnimationPlayer::detachFromTimeline()
122 {
123 dispose();
124 m_timeline = nullptr;
125 }
126 #endif
127
128 double AnimationPlayer::sourceEnd() const
129 {
130 return m_content ? m_content->endTimeInternal() : 0;
131 }
132
133 bool AnimationPlayer::limited(double currentTime) const
134 {
135 return (m_playbackRate < 0 && currentTime <= 0) || (m_playbackRate > 0 && cu rrentTime >= sourceEnd());
136 }
137
138 void AnimationPlayer::setCurrentTime(double newCurrentTime)
139 {
140 PlayStateUpdateScope updateScope(*this, TimingUpdateOnDemand);
141
142 m_currentTimePending = false;
143 setCurrentTimeInternal(newCurrentTime / 1000, TimingUpdateOnDemand);
144
145 if (calculatePlayState() == Finished)
146 m_startTime = calculateStartTime(newCurrentTime);
147 }
148
149 void AnimationPlayer::setCurrentTimeInternal(double newCurrentTime, TimingUpdate Reason reason)
150 {
151 ASSERT(std::isfinite(newCurrentTime));
152
153 bool oldHeld = m_held;
154 bool outdated = false;
155 bool isLimited = limited(newCurrentTime);
156 m_held = m_paused || !m_playbackRate || isLimited || std::isnan(m_startTime) ;
157 if (m_held) {
158 if (!oldHeld || m_holdTime != newCurrentTime)
159 outdated = true;
160 m_holdTime = newCurrentTime;
161 if (m_paused || !m_playbackRate) {
162 m_startTime = nullValue();
163 } else if (isLimited && std::isnan(m_startTime) && reason == TimingUpdat eForAnimationFrame) {
164 m_startTime = calculateStartTime(newCurrentTime);
165 }
166 } else {
167 m_holdTime = nullValue();
168 m_startTime = calculateStartTime(newCurrentTime);
169 m_finished = false;
170 outdated = true;
171 }
172
173 if (outdated) {
174 setOutdated();
175 }
176 }
177
178 // Update timing to reflect updated animation clock due to tick
179 void AnimationPlayer::updateCurrentTimingState(TimingUpdateReason reason)
180 {
181 if (m_held) {
182 double newCurrentTime = m_holdTime;
183 if (playStateInternal() == Finished && !isNull(m_startTime) && m_timelin e) {
184 // Add hystersis due to floating point error accumulation
185 if (!limited(calculateCurrentTime() + 0.001 * m_playbackRate)) {
186 // The current time became unlimited, eg. due to a backwards
187 // seek of the timeline.
188 newCurrentTime = calculateCurrentTime();
189 } else if (!limited(m_holdTime)) {
190 // The hold time became unlimited, eg. due to the source content
191 // becoming longer.
192 newCurrentTime = clampTo<double>(calculateCurrentTime(), 0, sour ceEnd());
193 }
194 }
195 setCurrentTimeInternal(newCurrentTime, reason);
196 } else if (limited(calculateCurrentTime())) {
197 m_held = true;
198 m_holdTime = m_playbackRate < 0 ? 0 : sourceEnd();
199 }
200 }
201
202 double AnimationPlayer::startTime(bool& isNull) const
203 {
204 double result = startTime();
205 isNull = std::isnan(result);
206 return result;
207 }
208
209 double AnimationPlayer::startTime() const
210 {
211 return m_startTime * 1000;
212 }
213
214 double AnimationPlayer::currentTime(bool& isNull)
215 {
216 double result = currentTime();
217 isNull = std::isnan(result);
218 return result;
219 }
220
221 double AnimationPlayer::currentTime()
222 {
223 PlayStateUpdateScope updateScope(*this, TimingUpdateOnDemand);
224
225 if (m_currentTimePending || playStateInternal() == Idle)
226 return std::numeric_limits<double>::quiet_NaN();
227
228 return currentTimeInternal() * 1000;
229 }
230
231 double AnimationPlayer::currentTimeInternal() const
232 {
233 double result = m_held ? m_holdTime : calculateCurrentTime();
234 #if ENABLE(ASSERT)
235 const_cast<AnimationPlayer*>(this)->updateCurrentTimingState(TimingUpdateOnD emand);
236 ASSERT(result == (m_held ? m_holdTime : calculateCurrentTime()));
237 #endif
238 return result;
239 }
240
241 double AnimationPlayer::unlimitedCurrentTimeInternal() const
242 {
243 #if ENABLE(ASSERT)
244 currentTimeInternal();
245 #endif
246 return playStateInternal() == Paused || isNull(m_startTime)
247 ? currentTimeInternal()
248 : calculateCurrentTime();
249 }
250
251 void AnimationPlayer::preCommit(int compositorGroup, bool startOnCompositor)
252 {
253 PlayStateUpdateScope updateScope(*this, TimingUpdateOnDemand, DoNotSetCompos itorPending);
254
255 bool softChange = m_compositorState && (paused() || m_compositorState->playb ackRate != m_playbackRate);
256 bool hardChange = m_compositorState && (m_compositorState->sourceChanged || m_compositorState->startTime != m_startTime);
257
258 // FIXME: softChange && !hardChange should generate a Pause/ThenStart,
259 // not a Cancel, but we can't communicate these to the compositor yet.
260
261 bool changed = softChange || hardChange;
262 bool shouldCancel = (!playing() && m_compositorState) || changed;
263 bool shouldStart = playing() && (!m_compositorState || changed);
264
265 if (shouldCancel) {
266 cancelAnimationOnCompositor();
267 m_compositorState = nullptr;
268 }
269
270 if (m_compositorState && m_compositorState->pendingAction == Start) {
271 // Still waiting for a start time.
272 return;
273 }
274
275 ASSERT(!m_compositorState || !std::isnan(m_compositorState->startTime));
276
277 if (!shouldStart) {
278 m_currentTimePending = false;
279 }
280
281 if (shouldStart) {
282 m_compositorGroup = compositorGroup;
283 if (startOnCompositor) {
284 if (isCandidateForAnimationOnCompositor())
285 createCompositorPlayer();
286
287 if (maybeStartAnimationOnCompositor())
288 m_compositorState = adoptPtr(new CompositorState(*this));
289 else
290 cancelIncompatibleAnimationsOnCompositor();
291 }
292 }
293 }
294
295 void AnimationPlayer::postCommit(double timelineTime)
296 {
297 PlayStateUpdateScope updateScope(*this, TimingUpdateOnDemand, DoNotSetCompos itorPending);
298
299 m_compositorPending = false;
300
301 if (!m_compositorState || m_compositorState->pendingAction == None)
302 return;
303
304 switch (m_compositorState->pendingAction) {
305 case Start:
306 if (!std::isnan(m_compositorState->startTime)) {
307 ASSERT(m_startTime == m_compositorState->startTime);
308 m_compositorState->pendingAction = None;
309 }
310 break;
311 case Pause:
312 case PauseThenStart:
313 ASSERT(std::isnan(m_startTime));
314 m_compositorState->pendingAction = None;
315 setCurrentTimeInternal((timelineTime - m_compositorState->startTime) * m _playbackRate, TimingUpdateForAnimationFrame);
316 m_currentTimePending = false;
317 break;
318 default:
319 ASSERT_NOT_REACHED();
320 }
321 }
322
323 void AnimationPlayer::notifyCompositorStartTime(double timelineTime)
324 {
325 PlayStateUpdateScope updateScope(*this, TimingUpdateOnDemand, DoNotSetCompos itorPending);
326
327 if (m_compositorState) {
328 ASSERT(m_compositorState->pendingAction == Start);
329 ASSERT(std::isnan(m_compositorState->startTime));
330
331 double initialCompositorHoldTime = m_compositorState->holdTime;
332 m_compositorState->pendingAction = None;
333 m_compositorState->startTime = timelineTime + currentTimeInternal() / -m _playbackRate;
334
335 if (m_startTime == timelineTime) {
336 // The start time was set to the incoming compositor start time.
337 // Unlikely, but possible.
338 // FIXME: Depending on what changed above this might still be pendin g.
339 // Maybe...
340 m_currentTimePending = false;
341 return;
342 }
343
344 if (!std::isnan(m_startTime) || currentTimeInternal() != initialComposit orHoldTime) {
345 // A new start time or current time was set while starting.
346 setCompositorPending(true);
347 return;
348 }
349 }
350
351 notifyStartTime(timelineTime);
352 }
353
354 void AnimationPlayer::notifyStartTime(double timelineTime)
355 {
356 if (playing()) {
357 ASSERT(std::isnan(m_startTime));
358 ASSERT(m_held);
359
360 if (m_playbackRate == 0) {
361 setStartTimeInternal(timelineTime);
362 } else {
363 setStartTimeInternal(timelineTime + currentTimeInternal() / -m_playb ackRate);
364 }
365
366 // FIXME: This avoids marking this player as outdated needlessly when a start time
367 // is notified, but we should refactor how outdating works to avoid this .
368 m_outdated = false;
369
370 m_currentTimePending = false;
371 }
372 }
373
374 bool AnimationPlayer::affects(const Element& element, CSSPropertyID property) co nst
375 {
376 if (!m_content || !m_content->isAnimation())
377 return false;
378
379 const Animation* animation = toAnimation(m_content.get());
380 return (animation->target() == &element) && animation->affects(PropertyHandl e(property));
381 }
382
383 double AnimationPlayer::calculateStartTime(double currentTime) const
384 {
385 return m_timeline->effectiveTime() - currentTime / m_playbackRate;
386 }
387
388 double AnimationPlayer::calculateCurrentTime() const
389 {
390 if (isNull(m_startTime) || !m_timeline)
391 return 0;
392 return (m_timeline->effectiveTime() - m_startTime) * m_playbackRate;
393 }
394
395 void AnimationPlayer::setStartTime(double startTime)
396 {
397 PlayStateUpdateScope updateScope(*this, TimingUpdateOnDemand);
398
399 if (m_paused || playStateInternal() == Idle)
400 return;
401 if (startTime == m_startTime)
402 return;
403
404 m_currentTimePending = false;
405 setStartTimeInternal(startTime / 1000);
406 }
407
408 void AnimationPlayer::setStartTimeInternal(double newStartTime)
409 {
410 ASSERT(!m_paused);
411 ASSERT(std::isfinite(newStartTime));
412 ASSERT(newStartTime != m_startTime);
413
414 bool hadStartTime = hasStartTime();
415 double previousCurrentTime = currentTimeInternal();
416 m_startTime = newStartTime;
417 if (m_held && m_playbackRate) {
418 // If held, the start time would still be derrived from the hold time.
419 // Force a new, limited, current time.
420 m_held = false;
421 double currentTime = calculateCurrentTime();
422 if (m_playbackRate > 0 && currentTime > sourceEnd()) {
423 currentTime = sourceEnd();
424 } else if (m_playbackRate < 0 && currentTime < 0) {
425 currentTime = 0;
426 }
427 setCurrentTimeInternal(currentTime, TimingUpdateOnDemand);
428 }
429 updateCurrentTimingState(TimingUpdateOnDemand);
430 double newCurrentTime = currentTimeInternal();
431
432 if (previousCurrentTime != newCurrentTime) {
433 setOutdated();
434 } else if (!hadStartTime && m_timeline) {
435 // Even though this player is not outdated, time to effect change is
436 // infinity until start time is set.
437 m_timeline->wake();
438 }
439 }
440
441 void AnimationPlayer::setSource(AnimationNode* newSource)
442 {
443 if (m_content == newSource)
444 return;
445 PlayStateUpdateScope updateScope(*this, TimingUpdateOnDemand, SetCompositorP endingWithSourceChanged);
446
447 double storedCurrentTime = currentTimeInternal();
448 if (m_content)
449 m_content->detach();
450 m_content = newSource;
451 if (newSource) {
452 // FIXME: This logic needs to be updated once groups are implemented
453 if (newSource->player()) {
454 newSource->player()->cancel();
455 newSource->player()->setSource(0);
456 }
457 newSource->attach(this);
458 setOutdated();
459 }
460 setCurrentTimeInternal(storedCurrentTime, TimingUpdateOnDemand);
461 }
462
463 const char* AnimationPlayer::playStateString(AnimationPlayState playState)
464 {
465 switch (playState) {
466 case Idle:
467 return "idle";
468 case Pending:
469 return "pending";
470 case Running:
471 return "running";
472 case Paused:
473 return "paused";
474 case Finished:
475 return "finished";
476 default:
477 ASSERT_NOT_REACHED();
478 return "";
479 }
480 }
481
482 AnimationPlayer::AnimationPlayState AnimationPlayer::playStateInternal() const
483 {
484 return m_playState;
485 }
486
487 AnimationPlayer::AnimationPlayState AnimationPlayer::calculatePlayState()
488 {
489 if (m_playState == Idle)
490 return Idle;
491 if (m_currentTimePending || (isNull(m_startTime) && !m_paused && m_playbackR ate != 0))
492 return Pending;
493 if (m_paused)
494 return Paused;
495 if (limited())
496 return Finished;
497 return Running;
498 }
499
500 void AnimationPlayer::pause()
501 {
502 if (m_paused)
503 return;
504
505 PlayStateUpdateScope updateScope(*this, TimingUpdateOnDemand);
506
507 if (playing()) {
508 m_currentTimePending = true;
509 }
510 m_paused = true;
511 setCurrentTimeInternal(currentTimeInternal(), TimingUpdateOnDemand);
512 }
513
514 void AnimationPlayer::unpause()
515 {
516 if (!m_paused)
517 return;
518
519 PlayStateUpdateScope updateScope(*this, TimingUpdateOnDemand);
520
521 m_currentTimePending = true;
522 unpauseInternal();
523 }
524
525 void AnimationPlayer::unpauseInternal()
526 {
527 if (!m_paused)
528 return;
529 m_paused = false;
530 setCurrentTimeInternal(currentTimeInternal(), TimingUpdateOnDemand);
531 }
532
533 void AnimationPlayer::play()
534 {
535 PlayStateUpdateScope updateScope(*this, TimingUpdateOnDemand);
536
537 if (!playing())
538 m_startTime = nullValue();
539
540 if (playStateInternal() == Idle) {
541 // We may not go into the pending state, but setting it to something oth er
542 // than Idle here will force an update.
543 ASSERT(isNull(m_startTime));
544 m_playState = Pending;
545 m_held = true;
546 m_holdTime = 0;
547 }
548
549 m_finished = false;
550 unpauseInternal();
551 if (!m_content)
552 return;
553 double currentTime = this->currentTimeInternal();
554 if (m_playbackRate > 0 && (currentTime < 0 || currentTime >= sourceEnd())) {
555 m_startTime = nullValue();
556 setCurrentTimeInternal(0, TimingUpdateOnDemand);
557 } else if (m_playbackRate < 0 && (currentTime <= 0 || currentTime > sourceEn d())) {
558 m_startTime = nullValue();
559 setCurrentTimeInternal(sourceEnd(), TimingUpdateOnDemand);
560 }
561 }
562
563 void AnimationPlayer::reverse()
564 {
565 if (!m_playbackRate) {
566 return;
567 }
568
569 setPlaybackRateInternal(-m_playbackRate);
570 play();
571 }
572
573 void AnimationPlayer::finish(ExceptionState& exceptionState)
574 {
575 PlayStateUpdateScope updateScope(*this, TimingUpdateOnDemand);
576
577 if (!m_playbackRate || playStateInternal() == Idle) {
578 return;
579 }
580 if (m_playbackRate > 0 && sourceEnd() == std::numeric_limits<double>::infini ty()) {
581 exceptionState.throwDOMException(InvalidStateError, "AnimationPlayer has source content whose end time is infinity.");
582 return;
583 }
584
585 double newCurrentTime = m_playbackRate < 0 ? 0 : sourceEnd();
586 setCurrentTimeInternal(newCurrentTime, TimingUpdateOnDemand);
587 if (!paused()) {
588 m_startTime = calculateStartTime(newCurrentTime);
589 }
590
591 m_currentTimePending = false;
592 ASSERT(playStateInternal() != Idle);
593 ASSERT(limited());
594 }
595
596 ScriptPromise AnimationPlayer::finished(ScriptState* scriptState)
597 {
598 if (!m_finishedPromise) {
599 m_finishedPromise = new AnimationPlayerPromise(scriptState->executionCon text(), this, AnimationPlayerPromise::Finished);
600 if (playStateInternal() == Finished)
601 m_finishedPromise->resolve(this);
602 }
603 return m_finishedPromise->promise(scriptState->world());
604 }
605
606 ScriptPromise AnimationPlayer::ready(ScriptState* scriptState)
607 {
608 if (!m_readyPromise) {
609 m_readyPromise = new AnimationPlayerPromise(scriptState->executionContex t(), this, AnimationPlayerPromise::Ready);
610 if (playStateInternal() != Pending)
611 m_readyPromise->resolve(this);
612 }
613 return m_readyPromise->promise(scriptState->world());
614 }
615
616 const AtomicString& AnimationPlayer::interfaceName() const
617 {
618 return EventTargetNames::AnimationPlayer;
619 }
620
621 ExecutionContext* AnimationPlayer::executionContext() const
622 {
623 return ActiveDOMObject::executionContext();
624 }
625
626 bool AnimationPlayer::hasPendingActivity() const
627 {
628 return m_pendingFinishedEvent || (!m_finished && hasEventListeners(EventType Names::finish));
629 }
630
631 void AnimationPlayer::stop()
632 {
633 PlayStateUpdateScope updateScope(*this, TimingUpdateOnDemand);
634
635 m_finished = true;
636 m_pendingFinishedEvent = nullptr;
637 }
638
639 bool AnimationPlayer::dispatchEvent(PassRefPtrWillBeRawPtr<Event> event)
640 {
641 if (m_pendingFinishedEvent == event)
642 m_pendingFinishedEvent = nullptr;
643 return EventTargetWithInlineData::dispatchEvent(event);
644 }
645
646 double AnimationPlayer::playbackRate() const
647 {
648 return m_playbackRate;
649 }
650
651 void AnimationPlayer::setPlaybackRate(double playbackRate)
652 {
653 if (playbackRate == m_playbackRate)
654 return;
655
656 PlayStateUpdateScope updateScope(*this, TimingUpdateOnDemand);
657
658 setPlaybackRateInternal(playbackRate);
659 }
660
661 void AnimationPlayer::setPlaybackRateInternal(double playbackRate)
662 {
663 ASSERT(std::isfinite(playbackRate));
664 ASSERT(playbackRate != m_playbackRate);
665
666 if (!limited() && !paused() && hasStartTime())
667 m_currentTimePending = true;
668
669 double storedCurrentTime = currentTimeInternal();
670 if ((m_playbackRate < 0 && playbackRate >= 0) || (m_playbackRate > 0 && play backRate <= 0))
671 m_finished = false;
672
673 m_playbackRate = playbackRate;
674 m_startTime = std::numeric_limits<double>::quiet_NaN();
675 setCurrentTimeInternal(storedCurrentTime, TimingUpdateOnDemand);
676 }
677
678 void AnimationPlayer::setOutdated()
679 {
680 m_outdated = true;
681 if (m_timeline)
682 m_timeline->setOutdatedAnimationPlayer(this);
683 }
684
685 bool AnimationPlayer::canStartAnimationOnCompositor() const
686 {
687 // FIXME: Timeline playback rates should be compositable
688 if (m_playbackRate == 0 || (std::isinf(sourceEnd()) && m_playbackRate < 0) | | (timeline() && timeline()->playbackRate() != 1))
689 return false;
690
691 return m_timeline && m_content && m_content->isAnimation() && playing();
692 }
693
694 bool AnimationPlayer::isCandidateForAnimationOnCompositor() const
695 {
696 if (!canStartAnimationOnCompositor())
697 return false;
698
699 return toAnimation(m_content.get())->isCandidateForAnimationOnCompositor(m_p laybackRate);
700 }
701
702 bool AnimationPlayer::maybeStartAnimationOnCompositor()
703 {
704 if (!canStartAnimationOnCompositor())
705 return false;
706
707 bool reversed = m_playbackRate < 0;
708
709 double startTime = timeline()->zeroTime() + startTimeInternal();
710 if (reversed) {
711 startTime -= sourceEnd() / fabs(m_playbackRate);
712 }
713
714 double timeOffset = 0;
715 if (std::isnan(startTime)) {
716 timeOffset = reversed ? sourceEnd() - currentTimeInternal() : currentTim eInternal();
717 timeOffset = timeOffset / fabs(m_playbackRate);
718 }
719 ASSERT(m_compositorGroup != 0);
720 return toAnimation(m_content.get())->maybeStartAnimationOnCompositor(m_compo sitorGroup, startTime, timeOffset, m_playbackRate);
721 }
722
723 void AnimationPlayer::setCompositorPending(bool sourceChanged)
724 {
725 // FIXME: Animation could notify this directly?
726 if (!hasActiveAnimationsOnCompositor()) {
727 destroyCompositorPlayer();
728 m_compositorState.release();
729 }
730 if (sourceChanged && m_compositorState) {
731 m_compositorState->sourceChanged = true;
732 }
733 if (m_compositorPending || m_isPausedForTesting) {
734 return;
735 }
736
737 if (sourceChanged || !m_compositorState
738 || !playing() || m_compositorState->playbackRate != m_playbackRate
739 || m_compositorState->startTime != m_startTime) {
740 m_compositorPending = true;
741 ASSERT(timeline());
742 ASSERT(timeline()->document());
743 timeline()->document()->compositorPendingAnimations().add(this);
744 }
745 }
746
747 void AnimationPlayer::cancelAnimationOnCompositor()
748 {
749 if (hasActiveAnimationsOnCompositor())
750 toAnimation(m_content.get())->cancelAnimationOnCompositor();
751
752 destroyCompositorPlayer();
753 }
754
755 void AnimationPlayer::restartAnimationOnCompositor()
756 {
757 if (hasActiveAnimationsOnCompositor())
758 toAnimation(m_content.get())->restartAnimationOnCompositor();
759 }
760
761 void AnimationPlayer::cancelIncompatibleAnimationsOnCompositor()
762 {
763 if (m_content && m_content->isAnimation())
764 toAnimation(m_content.get())->cancelIncompatibleAnimationsOnCompositor() ;
765 }
766
767 bool AnimationPlayer::hasActiveAnimationsOnCompositor()
768 {
769 if (!m_content || !m_content->isAnimation())
770 return false;
771
772 return toAnimation(m_content.get())->hasActiveAnimationsOnCompositor();
773 }
774
775 bool AnimationPlayer::update(TimingUpdateReason reason)
776 {
777 if (!m_timeline)
778 return false;
779
780 PlayStateUpdateScope updateScope(*this, reason, DoNotSetCompositorPending);
781
782 m_outdated = false;
783 bool idle = playStateInternal() == Idle;
784
785 if (m_content) {
786 double inheritedTime = idle || isNull(m_timeline->currentTimeInternal()) ? nullValue() : currentTimeInternal();
787 // Special case for end-exclusivity when playing backwards.
788 if (inheritedTime == 0 && m_playbackRate < 0)
789 inheritedTime = -1;
790 m_content->updateInheritedTime(inheritedTime, reason);
791 }
792
793 if ((idle || limited()) && !m_finished) {
794 if (reason == TimingUpdateForAnimationFrame && (idle || hasStartTime())) {
795 const AtomicString& eventType = EventTypeNames::finish;
796 if (executionContext() && hasEventListeners(eventType)) {
797 double eventCurrentTime = currentTimeInternal() * 1000;
798 m_pendingFinishedEvent = AnimationPlayerEvent::create(eventType, eventCurrentTime, timeline()->currentTime());
799 m_pendingFinishedEvent->setTarget(this);
800 m_pendingFinishedEvent->setCurrentTarget(this);
801 m_timeline->document()->enqueueAnimationFrameEvent(m_pendingFini shedEvent);
802 }
803 m_finished = true;
804 }
805 }
806 ASSERT(!m_outdated);
807 return !m_finished;
808 }
809
810 double AnimationPlayer::timeToEffectChange()
811 {
812 ASSERT(!m_outdated);
813 if (m_held || !hasStartTime())
814 return std::numeric_limits<double>::infinity();
815 if (!m_content)
816 return -currentTimeInternal() / m_playbackRate;
817 double result = m_playbackRate > 0
818 ? m_content->timeToForwardsEffectChange() / m_playbackRate
819 : m_content->timeToReverseEffectChange() / -m_playbackRate;
820 return !hasActiveAnimationsOnCompositor() && m_content->phase() == Animation Node::PhaseActive
821 ? 0
822 : result;
823 }
824
825 void AnimationPlayer::cancel()
826 {
827 PlayStateUpdateScope updateScope(*this, TimingUpdateOnDemand);
828
829 if (playStateInternal() == Idle)
830 return;
831
832 m_holdTime = currentTimeInternal();
833 m_held = true;
834 // TODO
835 m_playState = Idle;
836 m_startTime = nullValue();
837 m_currentTimePending = false;
838
839 InspectorInstrumentation::didCancelAnimationPlayer(timeline()->document(), t his);
840 }
841
842 void AnimationPlayer::beginUpdatingState()
843 {
844 // Nested calls are not allowed!
845 ASSERT(!m_stateIsBeingUpdated);
846 m_stateIsBeingUpdated = true;
847 }
848
849 void AnimationPlayer::endUpdatingState()
850 {
851 ASSERT(m_stateIsBeingUpdated);
852 m_stateIsBeingUpdated = false;
853 }
854
855 void AnimationPlayer::createCompositorPlayer()
856 {
857 if (RuntimeEnabledFeatures::compositorAnimationTimelinesEnabled() && !m_comp ositorPlayer && Platform::current()->compositorSupport()) {
858 m_compositorPlayer = adoptPtr(Platform::current()->compositorSupport()-> createAnimationPlayer());
859 ASSERT(m_compositorPlayer);
860 m_compositorPlayer->setAnimationDelegate(this);
861 attachCompositorTimeline();
862 }
863
864 attachCompositedLayers();
865 }
866
867 void AnimationPlayer::destroyCompositorPlayer()
868 {
869 detachCompositedLayers();
870
871 if (m_compositorPlayer) {
872 detachCompositorTimeline();
873 m_compositorPlayer->setAnimationDelegate(nullptr);
874 }
875 m_compositorPlayer.clear();
876 }
877
878 void AnimationPlayer::attachCompositorTimeline()
879 {
880 if (m_compositorPlayer) {
881 WebCompositorAnimationTimeline* timeline = m_timeline ? m_timeline->comp ositorTimeline() : nullptr;
882 if (timeline)
883 timeline->playerAttached(*this);
884 }
885 }
886
887 void AnimationPlayer::detachCompositorTimeline()
888 {
889 if (m_compositorPlayer) {
890 WebCompositorAnimationTimeline* timeline = m_timeline ? m_timeline->comp ositorTimeline() : nullptr;
891 if (timeline)
892 timeline->playerDestroyed(*this);
893 }
894 }
895
896 void AnimationPlayer::attachCompositedLayers()
897 {
898 if (!RuntimeEnabledFeatures::compositorAnimationTimelinesEnabled() || !m_com positorPlayer)
899 return;
900
901 ASSERT(m_content);
902 ASSERT(m_content->isAnimation());
903
904 if (toAnimation(m_content.get())->canAttachCompositedLayers())
905 toAnimation(m_content.get())->attachCompositedLayers();
906 }
907
908 void AnimationPlayer::detachCompositedLayers()
909 {
910 if (m_compositorPlayer && m_compositorPlayer->isLayerAttached())
911 m_compositorPlayer->detachLayer();
912 }
913
914 void AnimationPlayer::notifyAnimationStarted(double monotonicTime, int group)
915 {
916 ASSERT(RuntimeEnabledFeatures::compositorAnimationTimelinesEnabled());
917 timeline()->document()->compositorPendingAnimations().notifyCompositorAnimat ionStarted(monotonicTime, group);
918 }
919
920 AnimationPlayer::PlayStateUpdateScope::PlayStateUpdateScope(AnimationPlayer& pla yer, TimingUpdateReason reason, CompositorPendingChange compositorPendingChange)
921 : m_player(player)
922 , m_initialPlayState(m_player->playStateInternal())
923 , m_compositorPendingChange(compositorPendingChange)
924 {
925 m_player->beginUpdatingState();
926 m_player->updateCurrentTimingState(reason);
927 }
928
929 AnimationPlayer::PlayStateUpdateScope::~PlayStateUpdateScope()
930 {
931 AnimationPlayState oldPlayState = m_initialPlayState;
932 AnimationPlayState newPlayState = m_player->calculatePlayState();
933
934 m_player->m_playState = newPlayState;
935 if (oldPlayState != newPlayState) {
936 bool wasActive = oldPlayState == Pending || oldPlayState == Running;
937 bool isActive = newPlayState == Pending || newPlayState == Running;
938 if (!wasActive && isActive)
939 TRACE_EVENT_NESTABLE_ASYNC_BEGIN1("blink.animations," TRACE_DISABLED _BY_DEFAULT("devtools.timeline"), "Animation", m_player, "data", InspectorAnimat ionEvent::data(*m_player));
940 else if (wasActive && !isActive)
941 TRACE_EVENT_NESTABLE_ASYNC_END1("blink.animations," TRACE_DISABLED_B Y_DEFAULT("devtools.timeline"), "Animation", m_player, "endData", InspectorAnima tionStateEvent::data(*m_player));
942 else
943 TRACE_EVENT_NESTABLE_ASYNC_INSTANT1("blink.animations," TRACE_DISABL ED_BY_DEFAULT("devtools.timeline"), "Animation", m_player, "data", InspectorAnim ationStateEvent::data(*m_player));
944 }
945
946 // Ordering is important, the ready promise should resolve/reject before
947 // the finished promise.
948 if (m_player->m_readyPromise && newPlayState != oldPlayState) {
949 if (newPlayState == Idle) {
950 if (m_player->m_readyPromise->state() == AnimationPlayerPromise::Pen ding) {
951 m_player->m_readyPromise->reject(DOMException::create(AbortError ));
952 }
953 m_player->m_readyPromise->reset();
954 m_player->m_readyPromise->resolve(m_player);
955 } else if (oldPlayState == Pending) {
956 m_player->m_readyPromise->resolve(m_player);
957 } else if (newPlayState == Pending) {
958 ASSERT(m_player->m_readyPromise->state() != AnimationPlayerPromise:: Pending);
959 m_player->m_readyPromise->reset();
960 }
961 }
962
963 if (m_player->m_finishedPromise && newPlayState != oldPlayState) {
964 if (newPlayState == Idle) {
965 if (m_player->m_finishedPromise->state() == AnimationPlayerPromise:: Pending) {
966 m_player->m_finishedPromise->reject(DOMException::create(AbortEr ror));
967 }
968 m_player->m_finishedPromise->reset();
969 } else if (newPlayState == Finished) {
970 m_player->m_finishedPromise->resolve(m_player);
971 } else if (oldPlayState == Finished) {
972 m_player->m_finishedPromise->reset();
973 }
974 }
975
976 if (oldPlayState != newPlayState && (oldPlayState == Idle || newPlayState == Idle)) {
977 m_player->setOutdated();
978 }
979
980 #if ENABLE(ASSERT)
981 // Verify that current time is up to date.
982 m_player->currentTimeInternal();
983 #endif
984
985 switch (m_compositorPendingChange) {
986 case SetCompositorPending:
987 m_player->setCompositorPending();
988 break;
989 case SetCompositorPendingWithSourceChanged:
990 m_player->setCompositorPending(true);
991 break;
992 case DoNotSetCompositorPending:
993 break;
994 default:
995 ASSERT_NOT_REACHED();
996 break;
997 }
998 m_player->endUpdatingState();
999
1000 if (oldPlayState != newPlayState && newPlayState == Running)
1001 InspectorInstrumentation::didCreateAnimationPlayer(m_player->timeline()- >document(), m_player);
1002 }
1003
1004 bool AnimationPlayer::addEventListener(const AtomicString& eventType, PassRefPtr <EventListener> listener, bool useCapture)
1005 {
1006 if (eventType == EventTypeNames::finish)
1007 UseCounter::count(executionContext(), UseCounter::AnimationPlayerFinishE vent);
1008 return EventTargetWithInlineData::addEventListener(eventType, listener, useC apture);
1009 }
1010
1011 void AnimationPlayer::pauseForTesting(double pauseTime)
1012 {
1013 RELEASE_ASSERT(!paused());
1014 setCurrentTimeInternal(pauseTime, TimingUpdateOnDemand);
1015 if (hasActiveAnimationsOnCompositor())
1016 toAnimation(m_content.get())->pauseAnimationForTestingOnCompositor(curre ntTimeInternal());
1017 m_isPausedForTesting = true;
1018 pause();
1019 }
1020
1021 DEFINE_TRACE(AnimationPlayer)
1022 {
1023 visitor->trace(m_content);
1024 visitor->trace(m_timeline);
1025 visitor->trace(m_pendingFinishedEvent);
1026 visitor->trace(m_finishedPromise);
1027 visitor->trace(m_readyPromise);
1028 EventTargetWithInlineData::trace(visitor);
1029 ActiveDOMObject::trace(visitor);
1030 }
1031
1032 } // namespace
OLDNEW
« no previous file with comments | « Source/core/animation/AnimationPlayer.h ('k') | Source/core/animation/AnimationPlayer.idl » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698