Bug 1036287 part 3 - Make GetLocalTimeAt return a nullable time duration; r=dholbert
authorBrian Birtles <birtles@gmail.com>
Wed, 16 Jul 2014 09:02:32 +0900
changeset 216198 4a342071fd1aa777626a3b17b22ed4d06228976b
parent 216197 8ac5d63123ae209c527698fca0cadc71613c0f2f
child 216199 3d6e547234ace59fa28f92125c042fdc3a36feb2
push id515
push userraliiev@mozilla.com
push dateMon, 06 Oct 2014 12:51:51 +0000
treeherdermozilla-release@267c7a481bef [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdholbert
bugs1036287
milestone33.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 1036287 part 3 - Make GetLocalTimeAt return a nullable time duration; r=dholbert Once we support arbitrary timelines which can return null current time values, the local time of an animation can also become null so this patch updates ElementAnimation::GetLocalTimeAt to return a Nullable<TimeDuration>. Doing this also allows us to pass the result of GetLocalTimeAt directly to GetComputedTimingAt.
gfx/layers/composite/AsyncCompositionManager.cpp
layout/style/AnimationCommon.cpp
layout/style/AnimationCommon.h
layout/style/nsAnimationManager.cpp
layout/style/nsTransitionManager.cpp
--- a/gfx/layers/composite/AsyncCompositionManager.cpp
+++ b/gfx/layers/composite/AsyncCompositionManager.cpp
@@ -443,17 +443,18 @@ SampleAnimations(Layer* aLayer, TimeStam
     timing.mDirection = animation.direction();
     // Animations typically only run on the compositor during their active
     // interval but if we end up sampling them outside that range (for
     // example, while they are waiting to be removed) we currently just
     // assume that we should fill.
     timing.mFillMode = NS_STYLE_ANIMATION_FILL_MODE_BOTH;
 
     ComputedTiming computedTiming =
-      ElementAnimation::GetComputedTimingAt(elapsedDuration, timing);
+      ElementAnimation::GetComputedTimingAt(
+        Nullable<TimeDuration>(elapsedDuration), timing);
 
     NS_ABORT_IF_FALSE(0.0 <= computedTiming.mTimeFraction &&
                       computedTiming.mTimeFraction <= 1.0,
                       "time fraction should be in [0-1]");
 
     int segmentIndex = 0;
     AnimationSegment* segment = animation.segments().Elements();
     while (segment->endPortion() < computedTiming.mTimeFraction) {
--- a/layout/style/AnimationCommon.cpp
+++ b/layout/style/AnimationCommon.cpp
@@ -424,33 +424,39 @@ ElementAnimation::StartTime() const
 {
   Nullable<double> startTime = mTimeline->ToTimelineTime(mStartTime);
   return startTime.IsNull() ? 0.0 : startTime.Value();
 }
 
 double
 ElementAnimation::CurrentTime() const
 {
-  TimeStamp now = mTimeline->GetCurrentTimeStamp();
-  // |now| should only be null when we don't have a refresh driver.
-  //
-  // If we previously had a refresh driver, the correct thing would be to store
-  // the last refresh time in the AnimationTimeline, return that from
-  // GetCurrentTimeStamp and use that here.
+  // In Web Animations, AnimationPlayers have a *current* time and Animations
+  // have a *local* time. However, since we have a 1:1 correspondence between
+  // AnimationPlayers and Animations, and since the startTime of *Animations*
+  // (but not AnimationPlayers) is always 0, these are currently identical.
+  Nullable<TimeDuration> currentTime =
+    GetLocalTimeAt(mTimeline->GetCurrentTimeStamp());
+
+  // The current time is currently only going to be null when don't have a
+  // refresh driver (e.g. because we are in a display:none iframe).
   //
-  // If we never had a refresh driver then any start times would be null we can
-  // do here is return 0 (that is, until we allow returning a null start time).
+  // Web Animations says that in this case we should use a timeline time of
+  // 0 (the "effective timeline time") and calculate the current time from that.
+  // Doing that, however, requires storing the start time as an offset rather
+  // than a timestamp so for now we just return 0.
   //
-  // Since we don't yet record the last refresh time we just return 0 in both
-  // cases.
-  if (now.IsNull()) {
+  // FIXME: Store player start time and pause start as offsets rather than
+  // timestamps and return the appropriate current time when the timeline time
+  // is null.
+  if (currentTime.IsNull()) {
     return 0.0;
   }
 
-  return GetLocalTimeAt(now).ToMilliseconds();
+  return currentTime.Value().ToMilliseconds();
 }
 
 bool
 ElementAnimation::IsRunningAt(TimeStamp aTime) const
 {
   if (IsPaused() || IsFinishedTransition()) {
     return false;
   }
@@ -838,17 +844,17 @@ ElementAnimationCollection::EnsureStyleR
       // Skip finished transitions or animations whose @keyframes rule
       // is empty.
       if (anim->IsFinishedTransition() || anim->mProperties.IsEmpty()) {
         continue;
       }
 
       // The GetLocalTimeAt() call here handles pausing.  But:
       // FIXME: avoid recalculating every time when paused.
-      TimeDuration localTime = anim->GetLocalTimeAt(aRefreshTime);
+      Nullable<TimeDuration> localTime = anim->GetLocalTimeAt(aRefreshTime);
       ComputedTiming computedTiming =
         ElementAnimation::GetComputedTimingAt(localTime, anim->mTiming);
 
       // XXX We shouldn't really be using mLastNotification as a general
       // indicator that the animation has finished, it should be reserved for
       // events. If we use it differently in the future this use might need
       // changing.
       if (!anim->mIsRunningOnCompositor ||
@@ -882,17 +888,17 @@ ElementAnimationCollection::EnsureStyleR
       ElementAnimation* anim = mAnimations[animIdx];
 
       if (anim->IsFinishedTransition()) {
         continue;
       }
 
       // The GetLocalTimeAt() call here handles pausing.  But:
       // FIXME: avoid recalculating every time when paused.
-      TimeDuration localTime = anim->GetLocalTimeAt(aRefreshTime);
+      Nullable<TimeDuration> localTime = anim->GetLocalTimeAt(aRefreshTime);
       ComputedTiming computedTiming =
         ElementAnimation::GetComputedTimingAt(localTime, anim->mTiming);
 
       if ((computedTiming.mPhase == ComputedTiming::AnimationPhase_Before ||
            computedTiming.mPhase == ComputedTiming::AnimationPhase_Active) &&
           !anim->IsPaused()) {
         mNeedsRefreshes = true;
       }
--- a/layout/style/AnimationCommon.h
+++ b/layout/style/AnimationCommon.h
@@ -360,20 +360,27 @@ public:
   }
 
   bool HasAnimationOfProperty(nsCSSProperty aProperty) const;
   bool IsRunningAt(mozilla::TimeStamp aTime) const;
   bool IsCurrentAt(mozilla::TimeStamp aTime) const;
 
   // Return the duration at aTime (or, if paused, mPauseStart) since
   // the start of the delay period.  May be negative.
-  mozilla::TimeDuration GetLocalTimeAt(mozilla::TimeStamp aTime) const {
-    MOZ_ASSERT(!IsPaused() || aTime >= mPauseStart,
-               "if paused, aTime must be at least mPauseStart");
-    return (IsPaused() ? mPauseStart : aTime) - mStartTime;
+  // Returns a null value if and only if the passed-in TimeStamp IsNull().
+  Nullable<mozilla::TimeDuration>
+  GetLocalTimeAt(mozilla::TimeStamp aTime) const {
+    MOZ_ASSERT(aTime.IsNull() || !IsPaused() || aTime >= mPauseStart,
+               "if paused, any non-null value of aTime must be at least"
+               " mPauseStart");
+    Nullable<mozilla::TimeDuration> result; // Initializes to null
+    if (!aTime.IsNull()) {
+      result.SetValue((IsPaused() ? mPauseStart : aTime) - mStartTime);
+    }
+    return result;
   }
 
   // Return the duration from the start the active interval to the point where
   // the animation begins playback. This is zero unless the animation has
   // a negative delay in which case it is the absolute value of the delay.
   // This is used for setting the elapsedTime member of AnimationEvents.
   mozilla::TimeDuration InitialAdvance() const {
     return std::max(TimeDuration(), mTiming.mDelay * -1);
@@ -388,25 +395,16 @@ public:
   //
   // This function returns ComputedTiming::kNullTimeFraction for the
   // mTimeFraction member of the return value if the animation should not be
   // run (because it is not currently active and is not filling at this time).
   static ComputedTiming
   GetComputedTimingAt(const Nullable<mozilla::TimeDuration>& aLocalTime,
                       const AnimationTiming& aTiming);
 
-  // Convenience wrapper method to save changing all call sites. Removed in
-  // a subsequent patch.
-  static ComputedTiming
-  GetComputedTimingAt(mozilla::TimeDuration aLocalTime,
-                      const AnimationTiming& aTiming) {
-    return GetComputedTimingAt(Nullable<mozilla::TimeDuration>(aLocalTime),
-                               aTiming);
-  }
-
   // Return the duration of the active interval for the given timing parameters.
   static mozilla::TimeDuration ActiveDuration(const AnimationTiming& aTiming);
 
   nsString mName;
   AnimationTiming mTiming;
   // The beginning of the delay period.
   mozilla::TimeStamp mStartTime;
   mozilla::TimeStamp mPauseStart;
--- a/layout/style/nsAnimationManager.cpp
+++ b/layout/style/nsAnimationManager.cpp
@@ -38,17 +38,17 @@ nsAnimationManager::UpdateStyleAndEvents
 void
 nsAnimationManager::GetEventsAt(ElementAnimationCollection* aCollection,
                                 TimeStamp aRefreshTime,
                                 EventArray& aEventsToDispatch)
 {
   for (uint32_t animIdx = aCollection->mAnimations.Length(); animIdx-- != 0; ) {
     ElementAnimation* anim = aCollection->mAnimations[animIdx];
 
-    TimeDuration localTime = anim->GetLocalTimeAt(aRefreshTime);
+    Nullable<TimeDuration> localTime = anim->GetLocalTimeAt(aRefreshTime);
     ComputedTiming computedTiming =
       ElementAnimation::GetComputedTimingAt(localTime, anim->mTiming);
 
     switch (computedTiming.mPhase) {
       case ComputedTiming::AnimationPhase_Null:
       case ComputedTiming::AnimationPhase_Before:
         // Do nothing
         break;
--- a/layout/style/nsTransitionManager.cpp
+++ b/layout/style/nsTransitionManager.cpp
@@ -40,17 +40,20 @@ double
 ElementPropertyTransition::ValuePortionFor(TimeStamp aRefreshTime) const
 {
   // It would be easy enough to handle finished transitions by using a time
   // fraction of 1 but currently we should not be called for finished
   // transitions.
   MOZ_ASSERT(!IsFinishedTransition(),
              "Getting the value portion of a finished transition");
 
-  TimeDuration localTime = GetLocalTimeAt(aRefreshTime);
+  Nullable<TimeDuration> localTime = GetLocalTimeAt(aRefreshTime);
+  MOZ_ASSERT(!localTime.IsNull(),
+             "Getting the value portion of an animation that's not being "
+             "sampled");
 
   // Transitions use a fill mode of 'backwards' so GetComputedTimingAt will
   // never return a null time fraction due to being *before* the animation
   // interval. However, it might be possible that we're behind on flushing
   // causing us to get called *after* the animation interval. So, just in
   // case, we override the fill mode to 'both' to ensure the time fraction
   // is never null.
   AnimationTiming timingToUse = mTiming;
@@ -815,17 +818,17 @@ nsTransitionManager::FlushTransitions(Fl
           // completion. We only clear on a throttle-able cycle because that
           // means it is a regular restyle tick and thus it is safe to discard
           // the transition. If the flush is not throttle-able, we might still
           // have new transitions left to process. See comment below.
           if (aFlags == Can_Throttle) {
             collection->mAnimations.RemoveElementAt(i);
           }
         } else {
-          TimeDuration localTime = anim->GetLocalTimeAt(now);
+          Nullable<TimeDuration> localTime = anim->GetLocalTimeAt(now);
           ComputedTiming computedTiming =
             ElementAnimation::GetComputedTimingAt(localTime, anim->mTiming);
           if (computedTiming.mPhase == ComputedTiming::AnimationPhase_After) {
             MOZ_ASSERT(anim->mProperties.Length() == 1,
                        "Should have one animation property for a transition");
             nsCSSProperty prop = anim->mProperties[0].mProperty;
             if (nsCSSProps::PropHasFlags(prop, CSS_PROPERTY_REPORT_OTHER_NAME))
             {