Bug 1458457 - Use the current frame time stamp instead of the previous frame's time stamp in the case where the animation was play pending state when the animation was sent to the compositor. r?birtles draft
authorHiroyuki Ikezoe <hikezoe@mozilla.com>
Thu, 03 May 2018 15:59:32 +0900
changeset 790935 814ec4967b0e1f6fab91ab366f076882ea502d95
parent 790934 4e57d321978bf805a9573111f886af0e87c4293f
push id108653
push userhikezoe@mozilla.com
push dateThu, 03 May 2018 07:00:31 +0000
reviewersbirtles
bugs1458457
milestone61.0a1
Bug 1458457 - Use the current frame time stamp instead of the previous frame's time stamp in the case where the animation was play pending state when the animation was sent to the compositor. r?birtles When we send play-pending animation to the compositor, we resolve its start time with the time at the very moment we send the animation to the compositor instead of refresh drivers' tick time. That means that it's possible that the start time indicates more future time stamp than the previous frame time stamp on the compositor. Once this situation happens, we do skip composing the initial animation value on the compositor because we consider the animation hasn't started at the previous frame time stamp so that we fail to do the initial paint for the animation. To prevent the failure, we do explicitly use the current frame time stamp for the initial painting. MozReview-Commit-ID: 8TdZ6m0gqMm
gfx/layers/AnimationHelper.cpp
gfx/layers/AnimationInfo.cpp
gfx/layers/ipc/LayersMessages.ipdlh
--- a/gfx/layers/AnimationHelper.cpp
+++ b/gfx/layers/AnimationHelper.cpp
@@ -172,24 +172,33 @@ AnimationHelper::SampleAnimationForEachN
 
     MOZ_ASSERT((!animation.originTime().IsNull() &&
                 animation.startTime().type() ==
                   MaybeTimeDuration::TTimeDuration) ||
                animation.isNotPlaying(),
                "If we are playing, we should have an origin time and a start"
                " time");
 
+    const bool wasPlayPending = animation.wasPlayPending();
     // Use a previous vsync time to make main thread animations and compositor
     // more in sync with each other.
     // On the initial frame we use the current frame time here so the timestamp
     // on the second frame are the same as the initial frame, but it does not
     // matter.
-    const TimeStamp& timeStamp = !aPreviousFrameTime.IsNull()
+    const TimeStamp& timeStamp =
+      // If the animation was play-pending state when the animation was sent to
+      // the compositor, we should use the current frame time stamp to avoid
+      // using the past time stamp (aPreviousFrameTime) for the animation that
+      // has just started.
+      !aPreviousFrameTime.IsNull() && !wasPlayPending
       ? aPreviousFrameTime
       : aCurrentFrameTime;
+    if (wasPlayPending) {
+      animation.wasPlayPending() = false;
+    }
 
     // If the animation is not currently playing, e.g. paused or
     // finished, then use the hold time to stay at the same position.
     TimeDuration elapsedDuration =
       animation.isNotPlaying() ||
       animation.startTime().type() != MaybeTimeDuration::TTimeDuration
       ? animation.holdTime()
       : (timeStamp - animation.originTime() -
--- a/gfx/layers/AnimationInfo.cpp
+++ b/gfx/layers/AnimationInfo.cpp
@@ -120,17 +120,20 @@ AnimationInfo::StartPendingAnimations(co
 
     // If the animation is play-pending, resolve the start time.
     if (anim.startTime().type() == MaybeTimeDuration::Tnull_t &&
         !anim.originTime().IsNull() &&
         !anim.isNotPlaying()) {
       TimeDuration readyTime = aReadyTime - anim.originTime();
       anim.startTime() = dom::Animation::StartTimeFromTimelineTime(
         readyTime, anim.holdTime(), anim.playbackRate());
+      anim.wasPlayPending() = true;
       updated = true;
+    } else {
+      anim.wasPlayPending() = false;
     }
   }
   return updated;
 }
 
 void
 AnimationInfo::TransferMutatedFlagToLayer(Layer* aLayer)
 {
--- a/gfx/layers/ipc/LayersMessages.ipdlh
+++ b/gfx/layers/ipc/LayersMessages.ipdlh
@@ -252,16 +252,19 @@ struct Animation {
   // to the playbackRate is being performed.
   float previousPlaybackRate;
   // This is used in the transformed progress calculation.
   TimingFunction easingFunction;
   uint8_t iterationComposite;
   // True if the animation has a fixed current time (e.g. paused and
   // forward-filling animations).
   bool isNotPlaying;
+  // True if the animation was play-pending state when the animation was sent
+  // to the compositor.
+  bool wasPlayPending;
   // The base style that animations should composite with. This is only set for
   // animations with a composite mode of additive or accumulate, and only for
   // the first animation in the set (i.e. the animation that is lowest in the
   // stack). In all other cases the value is null_t.
   Animatable baseStyle;
 };
 
 struct CompositorAnimations {