Bug 1302648 part 5 - Queue animationcancel when animation status is idle. r?birtles draft
authorMantaroh Yoshinaga <mantaroh@gmail.com>
Fri, 10 Feb 2017 12:32:44 +0900
changeset 481637 e15baf78be03d20bffd1113f2a7129bcb33a2929
parent 481636 8b7ba1a464a19d9f66b2a253e036647eaa2a534e
child 481638 ca5aa204837e3100bf98b123ce1370f53bdfdef7
push id44889
push usermantaroh@gmail.com
push dateFri, 10 Feb 2017 08:41:14 +0000
reviewersbirtles
bugs1302648
milestone54.0a1
Bug 1302648 part 5 - Queue animationcancel when animation status is idle. r?birtles MozReview-Commit-ID: DRjWboQwR0A
layout/style/AnimationCommon.h
layout/style/nsAnimationManager.cpp
layout/style/nsAnimationManager.h
layout/style/nsTransitionManager.cpp
layout/style/nsTransitionManager.h
--- a/layout/style/AnimationCommon.h
+++ b/layout/style/AnimationCommon.h
@@ -246,11 +246,31 @@ inline void
 ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& aCallback,
                             DelayedEventDispatcher<EventInfo>& aField,
                             const char* aName,
                             uint32_t aFlags = 0)
 {
   aField.Traverse(&aCallback, aName);
 }
 
+// Return the TransitionPhase or AnimationPhase to use when the animation
+// doesn't have a target effect.
+template <typename PhaseType>
+PhaseType GetAnimationPhaseWithoutEffect(const dom::Animation& aAnimation)
+{
+  MOZ_ASSERT(!aAnimation.GetEffect(),
+             "Should only be called when we do not have an effect");
+
+  Nullable<TimeDuration> currentTime = aAnimation.GetCurrentTime();
+  if (currentTime.IsNull()) {
+    return PhaseType::Idle;
+  }
+
+  // If we don't have a target effect, the duration will be zero so the phase is
+  // 'before' if the current time is less than zero.
+  return currentTime.Value() < TimeDuration()
+         ? PhaseType::Before
+         : PhaseType::After;
+};
+
 } // namespace mozilla
 
 #endif /* !defined(mozilla_css_AnimationCommon_h) */
--- a/layout/style/nsAnimationManager.cpp
+++ b/layout/style/nsAnimationManager.cpp
@@ -154,22 +154,18 @@ CSSAnimation::HasLowerCompositeOrderThan
     return mOwningElement.LessThan(aOther.mOwningElement);
   }
 
   // 2. (Same element and pseudo): Sort by position in animation-name
   return mAnimationIndex < aOther.mAnimationIndex;
 }
 
 void
-CSSAnimation::QueueEvents()
+CSSAnimation::QueueEvents(StickyTimeDuration aActiveTime)
 {
-  if (!mEffect) {
-    return;
-  }
-
   // If the animation is pending, we ignore animation events until we finish
   // pending.
   if (mPendingState != PendingState::NotPending) {
     return;
   }
 
   // CSS animations dispatch events at their owning element. This allows
   // script to repurpose a CSS animation to target a different element,
@@ -193,47 +189,68 @@ CSSAnimation::QueueEvents()
   MOZ_ASSERT(owningElement, "Owning element should be set");
 
   // Get the nsAnimationManager so we can queue events on it
   nsPresContext* presContext = mOwningElement.GetRenderedPresContext();
   if (!presContext) {
     return;
   }
   nsAnimationManager* manager = presContext->AnimationManager();
-  ComputedTiming computedTiming = mEffect->GetComputedTiming();
-
-  AnimationPhase currentPhase = computedTiming.mPhase;
-  uint64_t currentIteration  = computedTiming.mCurrentIteration;
-  if (currentPhase == mPreviousPhase &&
-      currentIteration == mPreviousIteration) {
-    return;
-  }
 
   const StickyTimeDuration zeroDuration;
-  StickyTimeDuration intervalStartTime =
-    std::max(std::min(StickyTimeDuration(-mEffect->SpecifiedTiming().mDelay),
-                      computedTiming.mActiveDuration),
-             zeroDuration);
-  StickyTimeDuration intervalEndTime =
-    std::max(std::min((EffectEnd() - mEffect->SpecifiedTiming().mDelay),
-                      computedTiming.mActiveDuration),
-             zeroDuration);
+  uint64_t currentIteration = 0;
+  ComputedTiming::AnimationPhase currentPhase;
+  StickyTimeDuration intervalStartTime;
+  StickyTimeDuration intervalEndTime;
+  StickyTimeDuration iterationStartTime;
 
-  uint64_t iterationBoundary = mPreviousIteration > currentIteration
-                               ? currentIteration + 1
-                               : currentIteration;
-  StickyTimeDuration iterationStartTime  =
-    computedTiming.mDuration.MultDouble(
-      (iterationBoundary - computedTiming.mIterationStart));
+  if (!mEffect) {
+    currentPhase = GetAnimationPhaseWithoutEffect
+      <ComputedTiming::AnimationPhase>(*this);
+  } else {
+    ComputedTiming computedTiming = mEffect->GetComputedTiming();
+    currentPhase = computedTiming.mPhase;
+    currentIteration = computedTiming.mCurrentIteration;
+    if (currentPhase == mPreviousPhase &&
+        currentIteration == mPreviousIteration) {
+      return;
+    }
+    intervalStartTime =
+      std::max(std::min(StickyTimeDuration(-mEffect->SpecifiedTiming().mDelay),
+                        computedTiming.mActiveDuration),
+               zeroDuration);
+    intervalEndTime =
+      std::max(std::min((EffectEnd() - mEffect->SpecifiedTiming().mDelay),
+                        computedTiming.mActiveDuration),
+               zeroDuration);
+
+    uint64_t iterationBoundary = mPreviousIteration > currentIteration
+                                 ? currentIteration + 1
+                                 : currentIteration;
+    iterationStartTime  =
+      computedTiming.mDuration.MultDouble(
+        (iterationBoundary - computedTiming.mIterationStart));
+  }
 
   TimeStamp startTimeStamp     = ElapsedTimeToTimeStamp(intervalStartTime);
   TimeStamp endTimeStamp       = ElapsedTimeToTimeStamp(intervalEndTime);
   TimeStamp iterationTimeStamp = ElapsedTimeToTimeStamp(iterationStartTime);
 
   AutoTArray<AnimationEventParams, 2> events;
+
+  // Handle cancel event first
+  if ((mPreviousPhase != AnimationPhase::Idle &&
+       mPreviousPhase != AnimationPhase::After) &&
+      currentPhase == AnimationPhase::Idle) {
+    TimeStamp activeTimeStamp = ElapsedTimeToTimeStamp(aActiveTime);
+    events.AppendElement(AnimationEventParams{ eAnimationCancel,
+                                               aActiveTime,
+                                               activeTimeStamp });
+  }
+
   switch (mPreviousPhase) {
     case AnimationPhase::Idle:
     case AnimationPhase::Before:
       if (currentPhase == AnimationPhase::Active) {
         events.AppendElement(AnimationEventParams{ eAnimationStart,
                                                    intervalStartTime,
                                                    startTimeStamp });
       } else if (currentPhase == AnimationPhase::After) {
--- a/layout/style/nsAnimationManager.h
+++ b/layout/style/nsAnimationManager.h
@@ -127,17 +127,17 @@ public:
 
     // We need to do this *after* calling CancelFromStyle() since
     // CancelFromStyle might synchronously trigger a cancel event for which
     // we need an owning element to target the event at.
     mOwningElement = OwningElementRef();
   }
 
   void Tick() override;
-  void QueueEvents();
+  void QueueEvents(StickyTimeDuration aActiveTime = StickyTimeDuration());
 
   bool IsStylePaused() const { return mIsStylePaused; }
 
   bool HasLowerCompositeOrderThan(const CSSAnimation& aOther) const;
 
   void SetAnimationIndex(uint64_t aIndex)
   {
     MOZ_ASSERT(IsTiedToMarkup());
@@ -156,16 +156,20 @@ public:
   void SetOwningElement(const OwningElementRef& aElement)
   {
     mOwningElement = aElement;
   }
   // True for animations that are generated from CSS markup and continue to
   // reflect changes to that markup.
   bool IsTiedToMarkup() const { return mOwningElement.IsSet(); }
 
+  void MaybeQueueCancelEvent(StickyTimeDuration aActiveTime) override {
+    QueueEvents(aActiveTime);
+  }
+
 protected:
   virtual ~CSSAnimation()
   {
     MOZ_ASSERT(!mOwningElement.IsSet(), "Owning element should be cleared "
                                         "before a CSS animation is destroyed");
   }
 
   // Animation overrides
--- a/layout/style/nsTransitionManager.cpp
+++ b/layout/style/nsTransitionManager.cpp
@@ -196,17 +196,17 @@ CSSTransition::QueueEvents(StickyTimeDur
 
   const StickyTimeDuration zeroDuration = StickyTimeDuration();
 
   TransitionPhase currentPhase;
   StickyTimeDuration intervalStartTime;
   StickyTimeDuration intervalEndTime;
 
   if (!mEffect) {
-    currentPhase      = GetTransitionPhaseWithoutEffect();
+    currentPhase = GetAnimationPhaseWithoutEffect<TransitionPhase>(*this);
   } else {
     ComputedTiming computedTiming = mEffect->GetComputedTiming();
 
     currentPhase = static_cast<TransitionPhase>(computedTiming.mPhase);
     intervalStartTime =
       std::max(std::min(StickyTimeDuration(-mEffect->SpecifiedTiming().mDelay),
                         computedTiming.mActiveDuration), zeroDuration);
     intervalEndTime =
@@ -321,33 +321,16 @@ CSSTransition::QueueEvents(StickyTimeDur
                                             evt.mMessage,
                                             TransitionProperty(),
                                             evt.mElapsedTime,
                                             evt.mTimeStamp,
                                             this));
   }
 }
 
-CSSTransition::TransitionPhase
-CSSTransition::GetTransitionPhaseWithoutEffect() const
-{
-  MOZ_ASSERT(!mEffect, "Should only be called when we do not have an effect");
-
-  Nullable<TimeDuration> currentTime = GetCurrentTime();
-  if (currentTime.IsNull()) {
-    return TransitionPhase::Idle;
-  }
-
-  // If we don't have a target effect, the duration will be zero so the phase is
-  // 'before' if the current time is less than zero.
-  return currentTime.Value() < TimeDuration()
-         ? TransitionPhase::Before
-         : TransitionPhase::After;
-}
-
 void
 CSSTransition::Tick()
 {
   Animation::Tick();
   QueueEvents();
 }
 
 nsCSSPropertyID
--- a/layout/style/nsTransitionManager.h
+++ b/layout/style/nsTransitionManager.h
@@ -228,19 +228,16 @@ protected:
   // Animation overrides
   void UpdateTiming(SeekFlag aSeekFlag,
                     SyncNotifyFlag aSyncNotifyFlag) override;
 
   void QueueEvents(StickyTimeDuration activeTime = StickyTimeDuration());
 
 
   enum class TransitionPhase;
-  // Return the TransitionPhase to use when the transition doesn't have a target
-  // effect.
-  TransitionPhase GetTransitionPhaseWithoutEffect() const;
 
   // The (pseudo-)element whose computed transition-property refers to this
   // transition (if any).
   //
   // This is used for determining the relative composite order of transitions
   // generated from CSS markup.
   //
   // Typically this will be the same as the target element of the keyframe