From 4159c4a5958fc3fc437761d350ae0f12248e1b54 Mon Sep 17 00:00:00 2001 From: Brian Birtles Date: Tue, 28 Apr 2015 12:49:12 +0900 Subject: [PATCH] Bug 1150810 part 5 - Handle Timeline() returning null; r=jwatt --HG-- extra : commitid : K6pABHL7QRC extra : rebase_source : ba96781d897d28db1d2db83f73ce8c31b89638cd --- dom/animation/Animation.cpp | 31 +++++++++++++---------- dom/animation/PendingAnimationTracker.cpp | 7 +++++ layout/base/nsDisplayList.cpp | 8 +++++- 3 files changed, 32 insertions(+), 14 deletions(-) diff --git a/dom/animation/Animation.cpp b/dom/animation/Animation.cpp index ba06efccb904..a7077d712457 100644 --- a/dom/animation/Animation.cpp +++ b/dom/animation/Animation.cpp @@ -58,13 +58,7 @@ Animation::SetEffect(KeyframeEffectReadOnly* aEffect) void Animation::SetStartTime(const Nullable& aNewStartTime) { -#if 1 - // Bug 1096776: once we support inactive/missing timelines we'll want to take - // the disabled branch. - MOZ_ASSERT(mTimeline && !mTimeline->GetCurrentTime().IsNull(), - "We don't support inactive/missing timelines yet"); -#else - Nullable timelineTime = mTimeline->GetCurrentTime(); + Nullable timelineTime; if (mTimeline) { // The spec says to check if the timeline is active (has a resolved time) // before using it here, but we don't need to since it's harmless to set @@ -74,7 +68,7 @@ Animation::SetStartTime(const Nullable& aNewStartTime) if (timelineTime.IsNull() && !aNewStartTime.IsNull()) { mHoldTime.SetNull(); } -#endif + Nullable previousCurrentTime = GetCurrentTime(); mStartTime = aNewStartTime; if (!aNewStartTime.IsNull()) { @@ -106,7 +100,7 @@ Animation::GetCurrentTime() const return result; } - if (!mStartTime.IsNull()) { + if (mTimeline && !mStartTime.IsNull()) { Nullable timelineTime = mTimeline->GetCurrentTime(); if (!timelineTime.IsNull()) { result.SetValue((timelineTime.Value() - mStartTime.Value()) @@ -315,6 +309,8 @@ Animation::Tick() // resuming. if (mPendingState != PendingState::NotPending && !mPendingReadyTime.IsNull() && + mTimeline && + !mTimeline->GetCurrentTime().IsNull() && mPendingReadyTime.Value() <= mTimeline->GetCurrentTime().Value()) { FinishPendingAt(mPendingReadyTime.Value()); mPendingReadyTime.SetNull(); @@ -355,8 +351,15 @@ Animation::TriggerNow() if (PlayState() != AnimationPlayState::Pending) { return; } - MOZ_ASSERT(mTimeline && !mTimeline->GetCurrentTime().IsNull(), - "Expected an active timeline"); + + // If we don't have an active timeline we can't trigger the animation. + // However, this is a test-only method that we don't expect to be used in + // conjunction with animations without an active timeline so generate + // a warning if we do find ourselves in that situation. + if (!mTimeline || mTimeline->GetCurrentTime().IsNull()) { + NS_WARNING("Failed to trigger an animation with an active timeline"); + return; + } FinishPendingAt(mTimeline->GetCurrentTime().Value()); } @@ -797,10 +800,12 @@ Animation::UpdateFinishedState(SeekFlag aSeekFlag) mHoldTime.SetValue(0); } } else if (mPlaybackRate != 0.0 && - !currentTime.IsNull()) { + !currentTime.IsNull() && + mTimeline && + !mTimeline->GetCurrentTime().IsNull()) { if (aSeekFlag == SeekFlag::DidSeek && !mHoldTime.IsNull()) { mStartTime.SetValue(mTimeline->GetCurrentTime().Value() - - (mHoldTime.Value().MultDouble(1 / mPlaybackRate))); + (mHoldTime.Value().MultDouble(1 / mPlaybackRate))); } mHoldTime.SetNull(); } diff --git a/dom/animation/PendingAnimationTracker.cpp b/dom/animation/PendingAnimationTracker.cpp index 99191bca958b..46ab692eccbb 100644 --- a/dom/animation/PendingAnimationTracker.cpp +++ b/dom/animation/PendingAnimationTracker.cpp @@ -55,6 +55,13 @@ TriggerAnimationAtTime(nsRefPtrHashKey* aKey, dom::Animation* animation = aKey->GetKey(); dom::AnimationTimeline* timeline = animation->Timeline(); + // If the animation does not have a timeline, just drop it from the map. + // The animation will detect that it is not being tracked and will trigger + // itself on the next tick where it has a timeline. + if (!timeline) { + return PL_DHASH_REMOVE; + } + // When the timeline's refresh driver is under test control, its values // have no correspondance to wallclock times so we shouldn't try to convert // aReadyTime (which is a wallclock time) to a timeline value. Instead, the diff --git a/layout/base/nsDisplayList.cpp b/layout/base/nsDisplayList.cpp index 5a7f0d0185ca..fd449990d57c 100644 --- a/layout/base/nsDisplayList.cpp +++ b/layout/base/nsDisplayList.cpp @@ -364,6 +364,11 @@ AddAnimationForProperty(nsIFrame* aFrame, const AnimationProperty& aProperty, MOZ_ASSERT(aLayer->AsContainerLayer(), "Should only animate ContainerLayer"); MOZ_ASSERT(aAnimation->GetEffect(), "Should not be adding an animation without an effect"); + MOZ_ASSERT(!aAnimation->GetCurrentOrPendingStartTime().IsNull() || + (aAnimation->Timeline() && + aAnimation->Timeline()->TracksWallclockTime()), + "Animation should either have a resolved start time or " + "a timeline that tracks wallclock time"); nsStyleContext* styleContext = aFrame->StyleContext(); nsPresContext* presContext = aFrame->PresContext(); TransformReferenceBox refBox(aFrame); @@ -462,7 +467,8 @@ AddAnimationsForProperty(nsIFrame* aFrame, nsCSSProperty aProperty, // driver under test control. In this case, the next time the refresh // driver is advanced it will trigger any pending animations. if (anim->PlayState() == AnimationPlayState::Pending && - !anim->Timeline()->TracksWallclockTime()) { + (!anim->Timeline() || + !anim->Timeline()->TracksWallclockTime())) { continue; }