Bug 1436659 - Factor out static time calculation methods on Animation; r?hiro
We will re-use these methods to perform various calculations once we introduce
the pending playback rate.
MozReview-Commit-ID: 2HV44TTNxHg
--- a/dom/animation/Animation.cpp
+++ b/dom/animation/Animation.cpp
@@ -304,18 +304,18 @@ Animation::GetCurrentTime() const
if (!mHoldTime.IsNull()) {
result = mHoldTime;
return result;
}
if (mTimeline && !mStartTime.IsNull()) {
Nullable<TimeDuration> timelineTime = mTimeline->GetCurrentTime();
if (!timelineTime.IsNull()) {
- result.SetValue((timelineTime.Value() - mStartTime.Value())
- .MultDouble(mPlaybackRate));
+ result = CurrentTimeFromTimelineTime(
+ timelineTime.Value(), mStartTime.Value(), mPlaybackRate);
}
}
return result;
}
// https://drafts.csswg.org/web-animations/#set-the-current-time
void
Animation::SetCurrentTime(const TimeDuration& aSeekTime)
@@ -473,18 +473,18 @@ Animation::Finish(ErrorResult& aRv)
//
// We only do this, however, if we have an active timeline. If we have an
// inactive timeline we can't transition into the finished state just like
// we can't transition to the running state (this finished state is really
// a substate of the running state).
if (mStartTime.IsNull() &&
mTimeline &&
!mTimeline->GetCurrentTime().IsNull()) {
- mStartTime.SetValue(mTimeline->GetCurrentTime().Value() -
- limit.MultDouble(1.0 / mPlaybackRate));
+ mStartTime = StartTimeFromTimelineTime(
+ mTimeline->GetCurrentTime().Value(), limit, mPlaybackRate);
didChange = true;
}
// If we just resolved the start time for a pause or play-pending
// animation, we need to clear the task. We don't do this as a branch of
// the above however since we can have a play-pending animation with a
// resolved start time if we aborted a pause operation.
if (!mStartTime.IsNull() &&
@@ -682,32 +682,22 @@ Animation::GetCurrentOrPendingStartTime(
return result;
}
if (mPendingReadyTime.IsNull() || mHoldTime.IsNull()) {
return result;
}
// Calculate the equivalent start time from the pending ready time.
- result = StartTimeFromReadyTime(mPendingReadyTime.Value());
+ result = StartTimeFromTimelineTime(
+ mPendingReadyTime.Value(), mHoldTime.Value(), mPlaybackRate);
return result;
}
-TimeDuration
-Animation::StartTimeFromReadyTime(const TimeDuration& aReadyTime) const
-{
- MOZ_ASSERT(!mHoldTime.IsNull(), "Hold time should be set in order to"
- " convert a ready time to a start time");
- if (mPlaybackRate == 0) {
- return aReadyTime;
- }
- return aReadyTime - mHoldTime.Value().MultDouble(1 / mPlaybackRate);
-}
-
TimeStamp
Animation::AnimationTimeToTimeStamp(const StickyTimeDuration& aTime) const
{
// Initializes to null. Return the same object every time to benefit from
// return-value-optimization.
TimeStamp result;
// We *don't* check for mTimeline->TracksWallclockTime() here because that
@@ -728,17 +718,17 @@ Animation::AnimationTimeToTimeStamp(cons
// Check the time is convertible to a timestamp
if (aTime == TimeDuration::Forever() ||
mPlaybackRate == 0.0 ||
mStartTime.IsNull()) {
return result;
}
// Invert the standard relation:
- // animation time = (timeline time - start time) * playback rate
+ // current time = (timeline time - start time) * playback rate
TimeDuration timelineTime =
TimeDuration(aTime).MultDouble(1.0 / mPlaybackRate) + mStartTime.Value();
result = mTimeline->ToTimeStamp(timelineTime);
return result;
}
TimeStamp
@@ -760,18 +750,18 @@ Animation::SilentlySetCurrentTime(const
!mTimeline ||
mTimeline->GetCurrentTime().IsNull() ||
mPlaybackRate == 0.0) {
mHoldTime.SetValue(aSeekTime);
if (!mTimeline || mTimeline->GetCurrentTime().IsNull()) {
mStartTime.SetNull();
}
} else {
- mStartTime.SetValue(mTimeline->GetCurrentTime().Value() -
- (aSeekTime.MultDouble(1 / mPlaybackRate)));
+ mStartTime = StartTimeFromTimelineTime(
+ mTimeline->GetCurrentTime().Value(), aSeekTime, mPlaybackRate);
}
mPreviousCurrentTime.SetNull();
}
void
Animation::SilentlySetPlaybackRate(double aPlaybackRate)
{
@@ -996,18 +986,18 @@ Animation::ComposeStyle(ComposeAnimation
if (pending && mHoldTime.IsNull() && !mStartTime.IsNull()) {
Nullable<TimeDuration> timeToUse = mPendingReadyTime;
if (timeToUse.IsNull() &&
mTimeline &&
mTimeline->TracksWallclockTime()) {
timeToUse = mTimeline->ToTimelineTime(TimeStamp::Now());
}
if (!timeToUse.IsNull()) {
- mHoldTime.SetValue((timeToUse.Value() - mStartTime.Value())
- .MultDouble(mPlaybackRate));
+ mHoldTime = CurrentTimeFromTimelineTime(
+ timeToUse.Value(), mStartTime.Value(), mPlaybackRate);
}
}
KeyframeEffectReadOnly* keyframeEffect = mEffect->AsKeyframeEffect();
if (keyframeEffect) {
keyframeEffect->ComposeStyle(Forward<ComposeAnimationResult>(aComposeResult),
aPropertiesToSkip);
}
@@ -1183,17 +1173,18 @@ Animation::ResumeAt(const TimeDuration&
"Expected to resume a play-pending animation");
MOZ_ASSERT(!mHoldTime.IsNull() || !mStartTime.IsNull(),
"An animation in the play-pending state should have either a"
" resolved hold time or resolved start time");
// If we aborted a pending pause operation we will already have a start time
// we should use. In all other cases, we resolve it from the ready time.
if (mStartTime.IsNull()) {
- mStartTime = StartTimeFromReadyTime(aReadyTime);
+ mStartTime =
+ StartTimeFromTimelineTime(aReadyTime, mHoldTime.Value(), mPlaybackRate);
if (mPlaybackRate != 0) {
mHoldTime.SetNull();
}
}
mPendingState = PendingState::NotPending;
UpdateTiming(SeekFlag::NoSeek, SyncNotifyFlag::Async);
@@ -1204,18 +1195,18 @@ Animation::ResumeAt(const TimeDuration&
void
Animation::PauseAt(const TimeDuration& aReadyTime)
{
MOZ_ASSERT(mPendingState == PendingState::PausePending,
"Expected to pause a pause-pending animation");
if (!mStartTime.IsNull() && mHoldTime.IsNull()) {
- mHoldTime.SetValue((aReadyTime - mStartTime.Value())
- .MultDouble(mPlaybackRate));
+ mHoldTime = CurrentTimeFromTimelineTime(
+ aReadyTime, mStartTime.Value(), mPlaybackRate);
}
mStartTime.SetNull();
mPendingState = PendingState::NotPending;
UpdateTiming(SeekFlag::NoSeek, SyncNotifyFlag::Async);
if (mReady) {
mReady->MaybeResolve(this);
@@ -1266,18 +1257,20 @@ Animation::UpdateFinishedState(SeekFlag
} else {
mHoldTime.SetValue(0);
}
} else if (mPlaybackRate != 0.0 &&
!currentTime.IsNull() &&
mTimeline &&
!mTimeline->GetCurrentTime().IsNull()) {
if (aSeekFlag == SeekFlag::DidSeek && !mHoldTime.IsNull()) {
- mStartTime.SetValue(mTimeline->GetCurrentTime().Value() -
- (mHoldTime.Value().MultDouble(1 / mPlaybackRate)));
+ mStartTime =
+ StartTimeFromTimelineTime(mTimeline->GetCurrentTime().Value(),
+ mHoldTime.Value(),
+ mPlaybackRate);
}
mHoldTime.SetNull();
}
}
bool currentFinishedState = PlayState() == AnimationPlayState::Finished;
if (currentFinishedState && !mFinishedIsResolved) {
DoFinishNotification(aSyncNotifyFlag);
--- a/dom/animation/Animation.h
+++ b/dom/animation/Animation.h
@@ -237,22 +237,56 @@ public:
* animations on the next tick and apply the start time stored here.
*
* This method returns the start time, if resolved. Otherwise, if we have
* a pending ready time, it returns the corresponding start time. If neither
* of those are available, it returns null.
*/
Nullable<TimeDuration> GetCurrentOrPendingStartTime() const;
+
/**
- * Calculates the corresponding start time to use for an animation that is
- * currently pending with current time |mHoldTime| but should behave
- * as if it began or resumed playback at timeline time |aReadyTime|.
+ * The following relationship from the definition of the 'current time' is
+ * re-used in many algorithms so we extract it here into a static method that
+ * can be re-used:
+ *
+ * current time = (timeline time - start time) * playback rate
+ *
+ * As per https://drafts.csswg.org/web-animations-1/#current-time
*/
- TimeDuration StartTimeFromReadyTime(const TimeDuration& aReadyTime) const;
+ static TimeDuration CurrentTimeFromTimelineTime(
+ const TimeDuration& aTimelineTime,
+ const TimeDuration& aStartTime,
+ float aPlaybackRate)
+ {
+ return (aTimelineTime - aStartTime).MultDouble(aPlaybackRate);
+ }
+
+ /**
+ * As with calculating the current time, we often need to calculate a start
+ * time from a current time. The following method simply inverts the current
+ * time relationship.
+ *
+ * In each case where this is used, the desired behavior for playbackRate ==
+ * 0 is to return the specified timeline time (often referred to as the ready
+ * time).
+ */
+ static TimeDuration StartTimeFromTimelineTime(
+ const TimeDuration& aTimelineTime,
+ const TimeDuration& aCurrentTime,
+ float aPlaybackRate)
+ {
+ TimeDuration result = aTimelineTime;
+ if (aPlaybackRate == 0) {
+ return result;
+ }
+
+ result -= aCurrentTime.MultDouble(1.0 / aPlaybackRate);
+ return result;
+ }
/**
* Converts a time in the timescale of this Animation's currentTime, to a
* TimeStamp. Returns a null TimeStamp if the conversion cannot be performed
* because of the current state of this Animation (e.g. it has no timeline, a
* zero playbackRate, an unresolved start time etc.) or the value of the time
* passed-in (e.g. an infinite time).
*/
--- a/gfx/layers/AnimationInfo.cpp
+++ b/gfx/layers/AnimationInfo.cpp
@@ -2,16 +2,17 @@
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "AnimationInfo.h"
#include "mozilla/layers/WebRenderLayerManager.h"
#include "mozilla/layers/AnimationHelper.h"
+#include "mozilla/dom/Animation.h"
namespace mozilla {
namespace layers {
AnimationInfo::AnimationInfo(LayerManager* aManager) :
mManager(aManager),
mCompositorAnimationsId(0),
mAnimationGeneration(0),
@@ -99,26 +100,22 @@ bool
AnimationInfo::StartPendingAnimations(const TimeStamp& aReadyTime)
{
bool updated = false;
for (size_t animIdx = 0, animEnd = mAnimations.Length();
animIdx < animEnd; animIdx++) {
Animation& anim = mAnimations[animIdx];
// If the animation is play-pending, resolve the start time.
- // This mirrors the calculation in Animation::StartTimeFromReadyTime.
if (anim.startTime().type() == MaybeTimeDuration::Tnull_t &&
!anim.originTime().IsNull() &&
!anim.isNotPlaying()) {
TimeDuration readyTime = aReadyTime - anim.originTime();
- anim.startTime() =
- anim.playbackRate() == 0
- ? readyTime
- : readyTime - anim.holdTime().MultDouble(1.0 /
- anim.playbackRate());
+ anim.startTime() = dom::Animation::StartTimeFromTimelineTime(
+ readyTime, anim.holdTime(), anim.playbackRate());
updated = true;
}
}
return updated;
}
void
AnimationInfo::TransferMutatedFlagToLayer(Layer* aLayer)