Bug 1436659 - Factor out static time calculation methods on Animation; r=hiro
authorBrian Birtles <birtles@gmail.com>
Tue, 13 Feb 2018 15:04:18 +0900
changeset 403904 e11bc080108c4362a2f2afc828f4a1cfc7cd33c2
parent 403903 5ec4adb145cfadbd26a906d04d0aa3d984280578
child 403905 2be0189e2e8e2e5c03a23b64771f49f76c15f207
push id99885
push userapavel@mozilla.com
push dateThu, 15 Feb 2018 10:38:09 +0000
treeherdermozilla-inbound@99495614cba7 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewershiro
bugs1436659
milestone60.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
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
dom/animation/Animation.cpp
dom/animation/Animation.h
gfx/layers/AnimationInfo.cpp
--- 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)