Backed out changeset 79bcd4f744c0 (bug 1180125)
authorCarsten "Tomcat" Book <cbook@mozilla.com>
Wed, 29 Jul 2015 17:32:24 +0200
changeset 286831 63a5d306eb923ff6a4034288f874bf2d608f8f29
parent 286830 fe818bba6c2ff2ce64e847be5cae16e3224aec8d
child 286832 79c3a66ff523d40d8d96dbeae2137a7a3b532d1f
push id5067
push userraliiev@mozilla.com
push dateMon, 21 Sep 2015 14:04:52 +0000
treeherdermozilla-beta@14221ffe5b2f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs1180125
milestone42.0a1
backs out79bcd4f744c0016206ed94123ac205410b741a16
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
Backed out changeset 79bcd4f744c0 (bug 1180125)
dom/animation/Animation.h
layout/base/nsPresShell.cpp
layout/base/nsRefreshDriver.cpp
layout/base/nsRefreshDriver.h
layout/style/AnimationCommon.cpp
layout/style/AnimationCommon.h
layout/style/nsAnimationManager.cpp
layout/style/nsAnimationManager.h
--- a/dom/animation/Animation.h
+++ b/dom/animation/Animation.h
@@ -133,17 +133,17 @@ public:
    * CSSAnimation::PauseFromJS so we leave it for now.
    */
   void PauseFromJS(ErrorResult& aRv) { Pause(aRv); }
 
   // Wrapper functions for Animation DOM methods when called from style.
 
   virtual void CancelFromStyle() { DoCancel(); }
 
-  virtual void Tick();
+  void Tick();
 
   /**
    * Set the time to use for starting or pausing a pending animation.
    *
    * Typically, when an animation is played, it does not start immediately but
    * is added to a table of pending animations on the document of its effect.
    * In the meantime it sets its hold time to the time from which playback
    * should begin.
--- a/layout/base/nsPresShell.cpp
+++ b/layout/base/nsPresShell.cpp
@@ -1245,20 +1245,16 @@ PresShell::Destroy()
     NS_ASSERTION(mDocument->GetShell() == this, "Wrong shell?");
     mDocument->DeleteShell();
 
     if (mDocument->HasAnimationController()) {
       mDocument->GetAnimationController()->NotifyRefreshDriverDestroying(rd);
     }
   }
 
-  if (mPresContext) {
-    mPresContext->AnimationManager()->ClearEventQueue();
-  }
-
   // Revoke any pending events.  We need to do this and cancel pending reflows
   // before we destroy the frame manager, since apparently frame destruction
   // sometimes spins the event queue when plug-ins are involved(!).
   rd->RemoveLayoutFlushObserver(this);
   if (mHiddenInvalidationObserverRefreshDriver) {
     mHiddenInvalidationObserverRefreshDriver->RemovePresShellToInvalidateIfHidden(this);
   }
 
--- a/layout/base/nsRefreshDriver.cpp
+++ b/layout/base/nsRefreshDriver.cpp
@@ -59,17 +59,16 @@
 #include "mozilla/ipc/PBackgroundChild.h"
 #include "nsIIPCBackgroundChildCreateCallback.h"
 #include "mozilla/layout/VsyncChild.h"
 #include "VsyncSource.h"
 #include "mozilla/VsyncDispatcher.h"
 #include "nsThreadUtils.h"
 #include "mozilla/unused.h"
 #include "mozilla/TimelineConsumers.h"
-#include "nsAnimationManager.h"
 
 #ifdef MOZ_NUWA_PROCESS
 #include "ipc/Nuwa.h"
 #endif
 
 using namespace mozilla;
 using namespace mozilla::widget;
 using namespace mozilla::ipc;
@@ -1485,50 +1484,16 @@ nsRefreshDriver::DispatchPendingEvents()
   // Swap out the current pending events
   nsTArray<PendingEvent> pendingEvents(Move(mPendingEvents));
   for (PendingEvent& event : pendingEvents) {
     bool dummy;
     event.mTarget->DispatchEvent(event.mEvent, &dummy);
   }
 }
 
-static bool
-DispatchAnimationEventsOnSubDocuments(nsIDocument* aDocument,
-                                      void* aRefreshDriver)
-{
-  nsIPresShell* shell = aDocument->GetShell();
-  if (!shell) {
-    return true;
-  }
-
-  nsPresContext* context = shell->GetPresContext();
-  if (!context || context->RefreshDriver() != aRefreshDriver) {
-    return true;
-  }
-
-  nsCOMPtr<nsIDocument> kungFuDeathGrip(aDocument);
-
-  context->AnimationManager()->DispatchEvents();
-  aDocument->EnumerateSubDocuments(DispatchAnimationEventsOnSubDocuments,
-                                   nullptr);
-
-  return true;
-}
-
-void
-nsRefreshDriver::DispatchAnimationEvents()
-{
-  if (!mPresContext) {
-    return;
-  }
-
-  nsIDocument* doc = mPresContext->Document();
-  DispatchAnimationEventsOnSubDocuments(doc, this);
-}
-
 void
 nsRefreshDriver::RunFrameRequestCallbacks(TimeStamp aNowTime)
 {
   // Grab all of our frame request callbacks up front.
   nsTArray<DocumentFrameCallbacks>
     frameRequestCallbacks(mFrameRequestCallbackDocs.Length() +
                           mThrottledFrameRequestCallbackDocs.Length());
 
@@ -1694,17 +1659,16 @@ nsRefreshDriver::Tick(int64_t aNowEpoch,
         StopTimer();
         return;
       }
     }
 
     if (i == 0) {
       // This is the Flush_Style case.
 
-      DispatchAnimationEvents();
       DispatchPendingEvents();
       RunFrameRequestCallbacks(aNowTime);
 
       if (mPresContext && mPresContext->GetPresShell()) {
         bool tracingStyleFlush = false;
         nsAutoTArray<nsIPresShell*, 16> observers;
         observers.AppendElements(mStyleFlushObservers);
         for (uint32_t j = observers.Length();
--- a/layout/base/nsRefreshDriver.h
+++ b/layout/base/nsRefreshDriver.h
@@ -317,17 +317,16 @@ private:
     }
 
     mozilla::Maybe<mozilla::TimeStamp> mStartTime;
     RequestTable mEntries;
   };
   typedef nsClassHashtable<nsUint32HashKey, ImageStartData> ImageStartTable;
 
   void DispatchPendingEvents();
-  void DispatchAnimationEvents();
   void RunFrameRequestCallbacks(mozilla::TimeStamp aNowTime);
 
   void Tick(int64_t aNowEpoch, mozilla::TimeStamp aNowTime);
 
   enum EnsureTimerStartedFlags {
     eNone = 0,
     eAdjustingTimer = 1 << 0,
     eAllowTimeToGoBackwards = 1 << 1
--- a/layout/style/AnimationCommon.cpp
+++ b/layout/style/AnimationCommon.cpp
@@ -990,29 +990,9 @@ AnimationCollection::HasCurrentAnimation
         effect->HasAnimationOfProperties(aProperties, aPropertyCount)) {
       return true;
     }
   }
 
   return false;
 }
 
-nsPresContext*
-OwningElementRef::GetRenderedPresContext() const
-{
-  if (!mElement) {
-    return nullptr;
-  }
-
-  nsIDocument* doc = mElement->GetComposedDoc();
-  if (!doc) {
-    return nullptr;
-  }
-
-  nsIPresShell* shell = doc->GetShell();
-  if (!shell) {
-    return nullptr;
-  }
-
-  return shell->GetPresContext();
-}
-
 } // namespace mozilla
--- a/layout/style/AnimationCommon.h
+++ b/layout/style/AnimationCommon.h
@@ -501,24 +501,16 @@ public:
 
     return mPseudoType == nsCSSPseudoElements::ePseudo_NotPseudoElement ||
           (mPseudoType == nsCSSPseudoElements::ePseudo_before &&
            aOther.mPseudoType == nsCSSPseudoElements::ePseudo_after);
   }
 
   bool IsSet() const { return !!mElement; }
 
-  void GetElement(dom::Element*& aElement,
-                  nsCSSPseudoElements::Type& aPseudoType) const {
-    aElement = mElement;
-    aPseudoType = mPseudoType;
-  }
-
-  nsPresContext* GetRenderedPresContext() const;
-
 private:
   dom::Element* MOZ_NON_OWNING_REF mElement;
   nsCSSPseudoElements::Type        mPseudoType;
 };
 
 } // namespace mozilla
 
 #endif /* !defined(mozilla_css_AnimationCommon_h) */
--- a/layout/style/nsAnimationManager.cpp
+++ b/layout/style/nsAnimationManager.cpp
@@ -108,23 +108,16 @@ CSSAnimation::PauseFromStyle()
   // and then updated animation-play-state. It's an unusual case and there's
   // no obvious way to pass on the exception information so we just silently
   // fail for now.
   if (rv.Failed()) {
     NS_WARNING("Unexpected exception pausing animation - silently failing");
   }
 }
 
-void
-CSSAnimation::Tick()
-{
-  Animation::Tick();
-  QueueEvents();
-}
-
 bool
 CSSAnimation::HasLowerCompositeOrderThan(const Animation& aOther) const
 {
   // 0. Object-equality case
   if (&aOther == this) {
     return false;
   }
 
@@ -160,50 +153,22 @@ CSSAnimation::HasLowerCompositeOrderThan
     return mOwningElement.LessThan(otherAnimation->OwningElement());
   }
 
   // 4. (Same element and pseudo): Sort by position in animation-name
   return mSequenceNum < otherAnimation->mSequenceNum;
 }
 
 void
-CSSAnimation::QueueEvents()
+CSSAnimation::QueueEvents(EventArray& aEventsToDispatch)
 {
   if (!mEffect) {
     return;
   }
 
-  // CSS animations dispatch events at their owning element. This allows
-  // script to repurpose a CSS animation to target a different element,
-  // to use a group effect (which has no obvious "target element"), or
-  // to remove the animation effect altogether whilst still getting
-  // animation events.
-  //
-  // It does mean, however, that for a CSS animation that has no owning
-  // element (e.g. it was created using the CSSAnimation constructor or
-  // disassociated from CSS) no events are fired. If it becomes desirable
-  // for these animations to still fire events we should spec the concept
-  // of the "original owning element" or "event target" and allow script
-  // to set it when creating a CSSAnimation object.
-  if (!mOwningElement.IsSet()) {
-    return;
-  }
-
-  dom::Element* owningElement;
-  nsCSSPseudoElements::Type owningPseudoType;
-  mOwningElement.GetElement(owningElement, owningPseudoType);
-  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();
 
   if (computedTiming.mPhase == ComputedTiming::AnimationPhase_Null) {
     return; // do nothing
   }
 
   // Note that script can change the start time, so we have to handle moving
   // backwards through the animation as well as forwards. An 'animationstart'
@@ -230,34 +195,38 @@ CSSAnimation::QueueEvents()
   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;
   }
 
+  dom::Element* target;
+  nsCSSPseudoElements::Type targetPseudoType;
+  mEffect->GetTarget(target, targetPseudoType);
+
   uint32_t message;
 
   if (!wasActive && isActive) {
     message = NS_ANIMATION_START;
   } else if (wasActive && !isActive) {
     message = NS_ANIMATION_END;
   } else if (wasActive && isActive && !isSameIteration) {
     message = NS_ANIMATION_ITERATION;
   } else if (skippedActivePhase) {
     // First notifying for start of 0th iteration by appending an
     // 'animationstart':
     StickyTimeDuration elapsedTime =
       std::min(StickyTimeDuration(mEffect->InitialAdvance()),
                computedTiming.mActiveDuration);
-    AnimationEventInfo ei(owningElement, mAnimationName, NS_ANIMATION_START,
+    AnimationEventInfo ei(target, mAnimationName, NS_ANIMATION_START,
                           elapsedTime,
-                          PseudoTypeAsString(owningPseudoType));
-    manager->QueueEvent(ei);
+                          PseudoTypeAsString(targetPseudoType));
+    aEventsToDispatch.AppendElement(ei);
     // Then have the shared code below append an 'animationend':
     message = NS_ANIMATION_END;
   } else {
     return; // No events need to be sent
   }
 
   StickyTimeDuration elapsedTime;
 
@@ -267,19 +236,19 @@ CSSAnimation::QueueEvents()
                                     computedTiming.mCurrentIteration;
     elapsedTime = StickyTimeDuration(std::max(iterationStart,
                                               mEffect->InitialAdvance()));
   } else {
     MOZ_ASSERT(message == NS_ANIMATION_END);
     elapsedTime = computedTiming.mActiveDuration;
   }
 
-  AnimationEventInfo ei(owningElement, mAnimationName, message, elapsedTime,
-                        PseudoTypeAsString(owningPseudoType));
-  manager->QueueEvent(ei);
+  AnimationEventInfo ei(target, mAnimationName, message, elapsedTime,
+                        PseudoTypeAsString(targetPseudoType));
+  aEventsToDispatch.AppendElement(ei);
 }
 
 CommonAnimationManager*
 CSSAnimation::GetAnimationManager() const
 {
   nsPresContext* context = GetPresContext();
   if (!context) {
     return nullptr;
@@ -297,16 +266,36 @@ CSSAnimation::PseudoTypeAsString(nsCSSPs
     case nsCSSPseudoElements::ePseudo_after:
       return NS_LITERAL_STRING("::after");
     default:
       return EmptyString();
   }
 }
 
 void
+nsAnimationManager::UpdateStyleAndEvents(AnimationCollection* aCollection,
+                                         TimeStamp aRefreshTime,
+                                         EnsureStyleRuleFlags aFlags)
+{
+  aCollection->EnsureStyleRuleFor(aRefreshTime, aFlags);
+  QueueEvents(aCollection, mPendingEvents);
+}
+
+void
+nsAnimationManager::QueueEvents(AnimationCollection* aCollection,
+                                EventArray& aEventsToDispatch)
+{
+  for (size_t animIdx = aCollection->mAnimations.Length(); animIdx-- != 0; ) {
+    CSSAnimation* anim = aCollection->mAnimations[animIdx]->AsCSSAnimation();
+    MOZ_ASSERT(anim, "Expected a collection of CSS Animations");
+    anim->QueueEvents(aEventsToDispatch);
+  }
+}
+
+void
 nsAnimationManager::MaybeUpdateCascadeResults(AnimationCollection* aCollection)
 {
   for (size_t animIdx = aCollection->mAnimations.Length(); animIdx-- != 0; ) {
     CSSAnimation* anim = aCollection->mAnimations[animIdx]->AsCSSAnimation();
     if (anim->IsInEffect() != anim->mInEffectForCascadeResults) {
       // Update our own cascade results.
       mozilla::dom::Element* element = aCollection->GetElementToRestyle();
       bool updatedCascadeResults = false;
@@ -509,34 +498,29 @@ nsAnimationManager::CheckAnimationRule(n
   // Cancel removed animations
   for (size_t newAnimIdx = newAnimations.Length(); newAnimIdx-- != 0; ) {
     newAnimations[newAnimIdx]->CancelFromStyle();
   }
 
   UpdateCascadeResults(aStyleContext, collection);
 
   TimeStamp refreshTime = mPresContext->RefreshDriver()->MostRecentRefresh();
-  collection->EnsureStyleRuleFor(refreshTime, EnsureStyleRule_IsNotThrottled);
+  UpdateStyleAndEvents(collection, refreshTime,
+                       EnsureStyleRule_IsNotThrottled);
   // We don't actually dispatch the mPendingEvents now.  We'll either
   // dispatch them the next time we get a refresh driver notification
   // or the next time somebody calls
   // nsPresShell::FlushPendingNotifications.
   if (!mPendingEvents.IsEmpty()) {
     mPresContext->Document()->SetNeedStyleFlush();
   }
 
   return GetAnimationRule(aElement, aStyleContext->GetPseudoType());
 }
 
-void
-nsAnimationManager::QueueEvent(AnimationEventInfo& aEventInfo)
-{
-  mPendingEvents.AppendElement(aEventInfo);
-}
-
 struct KeyframeData {
   float mKey;
   uint32_t mIndex; // store original order since sort algorithm is not stable
   nsCSSKeyframeRule *mRule;
 };
 
 struct KeyframeDataComparator {
   bool Equals(const KeyframeData& A, const KeyframeData& B) const {
@@ -979,39 +963,40 @@ nsAnimationManager::FlushAnimations(Flus
 
     collection->Tick();
     bool canThrottleTick = aFlags == Can_Throttle &&
       collection->CanPerformOnCompositorThread(
         AnimationCollection::CanAnimateFlags(0)) &&
       collection->CanThrottleAnimation(now);
 
     nsRefPtr<css::AnimValuesStyleRule> oldStyleRule = collection->mStyleRule;
-    collection->EnsureStyleRuleFor(now, canThrottleTick
-                                        ? EnsureStyleRule_IsThrottled
-                                        : EnsureStyleRule_IsNotThrottled);
+    UpdateStyleAndEvents(collection, now, canThrottleTick
+                                          ? EnsureStyleRule_IsThrottled
+                                          : EnsureStyleRule_IsNotThrottled);
     if (oldStyleRule != collection->mStyleRule) {
       collection->PostRestyleForAnimation(mPresContext);
     } else {
       didThrottle = true;
     }
   }
 
   if (didThrottle) {
     mPresContext->Document()->SetNeedStyleFlush();
   }
 
   MaybeStartOrStopObservingRefreshDriver();
+
+  DispatchEvents(); // may destroy us
 }
 
 void
 nsAnimationManager::DoDispatchEvents()
 {
   EventArray events;
   mPendingEvents.SwapElements(events);
-  // FIXME: Sort events here in timeline order, then document order
   for (uint32_t i = 0, i_end = events.Length(); i < i_end; ++i) {
     AnimationEventInfo &info = events[i];
     EventDispatcher::Dispatch(info.mElement, mPresContext, &info.mEvent);
 
     if (!mPresContext) {
       break;
     }
   }
--- a/layout/style/nsAnimationManager.h
+++ b/layout/style/nsAnimationManager.h
@@ -96,18 +96,16 @@ public:
   void PauseFromStyle();
   void CancelFromStyle() override
   {
     mOwningElement = OwningElementRef();
     Animation::CancelFromStyle();
     MOZ_ASSERT(mSequenceNum == kUnsequenced);
   }
 
-  void Tick() override;
-
   bool IsStylePaused() const { return mIsStylePaused; }
 
   bool HasLowerCompositeOrderThan(const Animation& aOther) const override;
   bool IsUsingCustomCompositeOrder() const override
   {
     return mOwningElement.IsSet();
   }
 
@@ -118,16 +116,18 @@ public:
   }
   void CopyAnimationIndex(const CSSAnimation& aOther)
   {
     MOZ_ASSERT(IsUsingCustomCompositeOrder() &&
                aOther.IsUsingCustomCompositeOrder());
     mSequenceNum = aOther.mSequenceNum;
   }
 
+  void QueueEvents(EventArray& aEventsToDispatch);
+
   // Returns the element or pseudo-element whose animation-name property
   // this CSSAnimation corresponds to (if any). This is used for determining
   // the relative composite order of animations generated from CSS markup.
   //
   // Typically this will be the same as the target element of the keyframe
   // effect associated with this animation. However, it can differ in the
   // following circumstances:
   //
@@ -160,18 +160,16 @@ public:
 protected:
   virtual ~CSSAnimation()
   {
     MOZ_ASSERT(!mOwningElement.IsSet(), "Owning element should be cleared "
                                         "before a CSS animation is destroyed");
   }
   virtual css::CommonAnimationManager* GetAnimationManager() const override;
 
-  void QueueEvents();
-
   static nsString PseudoTypeAsString(nsCSSPseudoElements::Type aPseudoType);
 
   nsString mAnimationName;
 
   // The (pseudo-)element whose computed animation-name refers to this
   // animation (if any).
   OwningElementRef mOwningElement;
 
@@ -243,16 +241,22 @@ class nsAnimationManager final
   : public mozilla::css::CommonAnimationManager
 {
 public:
   explicit nsAnimationManager(nsPresContext *aPresContext)
     : mozilla::css::CommonAnimationManager(aPresContext)
   {
   }
 
+  void UpdateStyleAndEvents(mozilla::AnimationCollection* aEA,
+                            mozilla::TimeStamp aRefreshTime,
+                            mozilla::EnsureStyleRuleFlags aFlags);
+  void QueueEvents(mozilla::AnimationCollection* aEA,
+                   mozilla::EventArray &aEventsToDispatch);
+
   void MaybeUpdateCascadeResults(mozilla::AnimationCollection* aCollection);
 
   // nsIStyleRuleProcessor (parts)
   virtual size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf)
     const MOZ_MUST_OVERRIDE override;
   virtual size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf)
     const MOZ_MUST_OVERRIDE override;
 
@@ -271,39 +275,30 @@ public:
    *
    * aStyleContext may be a style context for aElement or for its
    * :before or :after pseudo-element.
    */
   nsIStyleRule* CheckAnimationRule(nsStyleContext* aStyleContext,
                                    mozilla::dom::Element* aElement);
 
   /**
-   * Add a pending event.
-   */
-  void QueueEvent(mozilla::AnimationEventInfo& aEventInfo);
-
-  /**
    * Dispatch any pending events.  We accumulate animationend and
    * animationiteration events only during refresh driver notifications
    * (and dispatch them at the end of such notifications), but we
    * accumulate animationstart events at other points when style
    * contexts are created.
    */
   void DispatchEvents() {
     // Fast-path the common case: no events
     if (!mPendingEvents.IsEmpty()) {
       DoDispatchEvents();
     }
   }
 
-  void ClearEventQueue() { mPendingEvents.Clear(); }
-
 protected:
-  virtual ~nsAnimationManager() {}
-
   virtual nsIAtom* GetAnimationsAtom() override {
     return nsGkAtoms::animationsProperty;
   }
   virtual nsIAtom* GetAnimationsBeforeAtom() override {
     return nsGkAtoms::animationsOfBeforeProperty;
   }
   virtual nsIAtom* GetAnimationsAfterAtom() override {
     return nsGkAtoms::animationsOfAfterProperty;