Bug 1134163 - Part1.Modify animationstart event timing in order to fire event after end of pending task. r?birtles draft
authorMantaroh Yoshinaga <mantaroh@gmail.com>
Wed, 27 Apr 2016 09:13:40 +0900
changeset 356725 e90efc2d12f4d4db52569449b08fee6c230dcab5
parent 356700 52072b6bec1416578615ec73027eb80a65d3fcd4
child 356726 072082e92efdf6629260bdc765c1900d835d264f
push id16581
push usermantaroh@gmail.com
push dateWed, 27 Apr 2016 00:16:56 +0000
reviewersbirtles
bugs1134163
milestone49.0a1
Bug 1134163 - Part1.Modify animationstart event timing in order to fire event after end of pending task. r?birtles MozReview-Commit-ID: KwkacemsRlL
layout/base/nsPresShell.cpp
layout/style/nsAnimationManager.cpp
--- a/layout/base/nsPresShell.cpp
+++ b/layout/base/nsPresShell.cpp
@@ -4054,22 +4054,16 @@ PresShell::FlushPendingNotifications(moz
 
       // The FlushResampleRequests() above flushed style changes.
       if (!mIsDestroying) {
         nsAutoScriptBlocker scriptBlocker;
         mPresContext->RestyleManager()->ProcessPendingRestyles();
       }
     }
 
-    // Dispatch any 'animationstart' events those (or earlier) restyles
-    // queued up.
-    if (!mIsDestroying) {
-      mPresContext->AnimationManager()->DispatchEvents();
-    }
-
     // Process whatever XBL constructors those restyles queued up.  This
     // ensures that onload doesn't fire too early and that we won't do extra
     // reflows after those constructors run.
     if (!mIsDestroying) {
       mDocument->BindingManager()->ProcessAttachedQueue();
     }
 
     // Now those constructors or events might have posted restyle
--- a/layout/style/nsAnimationManager.cpp
+++ b/layout/style/nsAnimationManager.cpp
@@ -191,48 +191,70 @@ CSSAnimation::QueueEvents()
   // is dispatched if we enter the active phase (regardless if that is from
   // before or after the animation's active phase). An 'animationend' is
   // dispatched if we leave the active phase (regardless if that is to before
   // or after the animation's active phase).
 
   bool wasActive = mPreviousPhaseOrIteration != PREVIOUS_PHASE_BEFORE &&
                    mPreviousPhaseOrIteration != PREVIOUS_PHASE_AFTER;
   bool isActive =
-         computedTiming.mPhase == ComputedTiming::AnimationPhase::Active;
+         computedTiming.mPhase == ComputedTiming::AnimationPhase::Active &&
+         mPendingState == PendingState::NotPending;
   bool isSameIteration =
          computedTiming.mCurrentIteration == mPreviousPhaseOrIteration;
   bool skippedActivePhase =
     (mPreviousPhaseOrIteration == PREVIOUS_PHASE_BEFORE &&
      computedTiming.mPhase == ComputedTiming::AnimationPhase::After) ||
     (mPreviousPhaseOrIteration == PREVIOUS_PHASE_AFTER &&
      computedTiming.mPhase == ComputedTiming::AnimationPhase::Before);
+  bool skippedBeforePhase =
+    (mPendingState == PendingState::NotPending) &&
+    (mPreviousPhaseOrIteration == PREVIOUS_PHASE_BEFORE) &&
+    (computedTiming.mCurrentIteration > 0);
 
   MOZ_ASSERT(!skippedActivePhase || (!isActive && !wasActive),
              "skippedActivePhase only makes sense if we were & are inactive");
 
-  if (computedTiming.mPhase == ComputedTiming::AnimationPhase::Before) {
-    mPreviousPhaseOrIteration = PREVIOUS_PHASE_BEFORE;
-  } else if (computedTiming.mPhase == ComputedTiming::AnimationPhase::Active) {
-    mPreviousPhaseOrIteration = computedTiming.mCurrentIteration;
-  } else if (computedTiming.mPhase == ComputedTiming::AnimationPhase::After) {
-    mPreviousPhaseOrIteration = PREVIOUS_PHASE_AFTER;
+  // If the animation is pending, keep the same "previous phase or iteration",
+  if (mPendingState == PendingState::NotPending) {
+    if (computedTiming.mPhase == ComputedTiming::AnimationPhase::Before) {
+      mPreviousPhaseOrIteration = PREVIOUS_PHASE_BEFORE;
+    } else if (computedTiming.mPhase == ComputedTiming::AnimationPhase::Active) {
+      mPreviousPhaseOrIteration = computedTiming.mCurrentIteration;
+    }
+  }
+  // Except After phase, already finish position of animation when start it.
+  // e.g. 'anim 1s -1s'
+  if (computedTiming.mPhase == ComputedTiming::AnimationPhase::After) {
+      mPreviousPhaseOrIteration = PREVIOUS_PHASE_AFTER;
   }
 
   EventMessage message;
 
-  if (!wasActive && isActive) {
+  if (forceFireStartAndIteration) {
+    // Notify animationstart and animationiteration in same tick.
+       StickyTimeDuration elapsedTime =
+      std::min(StickyTimeDuration(InitialAdvance()),
+               computedTiming.mActiveDuration);
+    manager->QueueEvent(AnimationEventInfo(owningElement, owningPseudoType,
+                                           eAnimationStart, mAnimationName,
+                                           elapsedTime,
+                                           ElapsedTimeToTimeStamp(elapsedTime),
+                                           this));
+    message = eAnimationIteration;
+  } else if (!wasActive && isActive) {
     message = eAnimationStart;
   } else if (wasActive && !isActive) {
     message = eAnimationEnd;
   } else if (wasActive && isActive && !isSameIteration) {
     message = eAnimationIteration;
   } else if (skippedActivePhase) {
     // First notifying for start of 0th iteration by appending an
     // 'animationstart':
-    StickyTimeDuration elapsedTime =
+   StickyTimeDuration elapsedTime =
       std::min(StickyTimeDuration(InitialAdvance()),
                computedTiming.mActiveDuration);
     manager->QueueEvent(AnimationEventInfo(owningElement, owningPseudoType,
                                            eAnimationStart, mAnimationName,
                                            elapsedTime,
                                            ElapsedTimeToTimeStamp(elapsedTime),
                                            this));
     // Then have the shared code below append an 'animationend':
@@ -658,23 +680,16 @@ CSSAnimationBuilder::Build(nsPresContext
   animation->SetTimeline(mTimeline);
   animation->SetEffect(effect);
 
   if (isStylePaused) {
     animation->PauseFromStyle();
   } else {
     animation->PlayFromStyle();
   }
-  // FIXME: Bug 1134163 - We shouldn't queue animationstart events
-  // until the animation is actually ready to run. However, we
-  // currently have some tests that assume that these events are
-  // dispatched within the same tick as the animation is added
-  // so we need to queue up any animationstart events from newly-created
-  // animations.
-  animation->QueueEvents();
 
   return animation.forget();
 }
 
 nsTArray<Keyframe>
 CSSAnimationBuilder::BuildAnimationFrames(nsPresContext* aPresContext,
                                           const StyleAnimation& aSrc,
                                           const nsCSSKeyframesRule* aRule)