Backed out changeset 3366d180e8ee (bug 1145439) for test_scroll_event_ordering.html failures.
authorRyan VanderMeulen <ryanvm@gmail.com>
Thu, 09 Apr 2015 22:59:10 -0400
changeset 238537 84f8e788e55dc9e7b518e0c609dc36463329c53c
parent 238536 9e6cd4b0253e1c7d2bbc304ded69b2ba0fcb0467
child 238538 b2e2a9ff51e92d723537c8a878201727313b60c3
push id28567
push userryanvm@gmail.com
push dateFri, 10 Apr 2015 19:24:04 +0000
treeherdermozilla-central@eb3a1c0262e4 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs1145439
milestone40.0a1
backs out3366d180e8eedf2e69c5dc8f3c80c772b1d55505
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 3366d180e8ee (bug 1145439) for test_scroll_event_ordering.html failures.
dom/base/nsDocument.cpp
dom/base/nsIDocument.h
layout/base/nsRefreshDriver.cpp
layout/base/nsRefreshDriver.h
layout/generic/nsIFrame.h
--- a/dom/base/nsDocument.cpp
+++ b/dom/base/nsDocument.cpp
@@ -3916,52 +3916,16 @@ nsDocument::MaybeRescheduleAnimationFram
 
 void
 nsIDocument::TakeFrameRequestCallbacks(FrameRequestCallbackList& aCallbacks)
 {
   aCallbacks.AppendElements(mFrameRequestCallbacks);
   mFrameRequestCallbacks.Clear();
 }
 
-bool
-nsIDocument::ShouldThrottleFrameRequests()
-{
-  if (!mIsShowing) {
-    // We're not showing (probably in a background tab or the bf cache).
-    return true;
-  }
-
-  if (!mPresShell) {
-    return false;  // Can't do anything smarter.
-  }
-
-  nsIFrame* frame = mPresShell->GetRootFrame();
-  if (!frame) {
-    return false;  // Can't do anything smarter.
-  }
-
-  nsIFrame* displayRootFrame = nsLayoutUtils::GetDisplayRootFrame(frame);
-  if (!displayRootFrame) {
-    return false;  // Can't do anything smarter.
-  }
-
-  if (!displayRootFrame->DidPaintPresShell(mPresShell)) {
-    // We didn't get painted during the last paint, so we're not visible.
-    // Throttle. Note that because we have to paint this document at least
-    // once to unthrottle it, we will drop one requestAnimationFrame frame
-    // when a document that previously wasn't visible scrolls into view. This
-    // is acceptable since it would happen outside the viewport on APZ
-    // platforms and is unlikely to be human-perceivable on non-APZ platforms.
-    return true;
-  }
-
-  // We got painted during the last paint, so run at full speed.
-  return false;
-}
-
 PLDHashOperator RequestDiscardEnumerator(imgIRequest* aKey,
                                          uint32_t aData,
                                          void* userArg)
 {
   aKey->RequestDiscard();
   return PL_DHASH_NEXT;
 }
 
--- a/dom/base/nsIDocument.h
+++ b/dom/base/nsIDocument.h
@@ -2098,23 +2098,16 @@ public:
 
   typedef nsTArray<FrameRequestCallbackHolder> FrameRequestCallbackList;
   /**
    * Put this document's frame request callbacks into the provided
    * list, and forget about them.
    */
   void TakeFrameRequestCallbacks(FrameRequestCallbackList& aCallbacks);
 
-  /**
-   * @return true if this document's frame request callbacks should be
-   * throttled. We throttle requestAnimationFrame for documents which aren't
-   * visible (e.g. scrolled out of the viewport).
-   */
-  bool ShouldThrottleFrameRequests();
-
   // This returns true when the document tree is being teared down.
   bool InUnlinkOrDeletion() { return mInUnlinkOrDeletion; }
 
   /*
    * Image Tracking
    *
    * Style and content images register their imgIRequests with their document
    * so that the document can efficiently tell all descendant images when they
--- a/layout/base/nsRefreshDriver.cpp
+++ b/layout/base/nsRefreshDriver.cpp
@@ -961,18 +961,18 @@ nsRefreshDriver::GetRegularTimerInterval
 
   if (rate == 0) {
     rate = 10000;
   }
 
   return 1000.0 / rate;
 }
 
-/* static */ double
-nsRefreshDriver::GetThrottledTimerInterval()
+double
+nsRefreshDriver::GetThrottledTimerInterval() const
 {
   int32_t rate = Preferences::GetInt("layout.throttled_frame_rate", -1);
   if (rate <= 0) {
     rate = DEFAULT_THROTTLED_FRAME_RATE;
   }
   return 1000.0 / rate;
 }
 
@@ -1015,30 +1015,27 @@ nsRefreshDriver::nsRefreshDriver(nsPresC
   : mActiveTimer(nullptr),
     mReflowCause(nullptr),
     mStyleCause(nullptr),
     mPresContext(aPresContext),
     mRootRefresh(nullptr),
     mPendingTransaction(0),
     mCompletedTransaction(0),
     mFreezeCount(0),
-    mThrottledFrameRequestInterval(TimeDuration::FromMilliseconds(
-                                     GetThrottledTimerInterval())),
     mThrottled(false),
     mTestControllingRefreshes(false),
     mViewManagerFlushIsPending(false),
     mRequestedHighPrecision(false),
     mInRefresh(false),
     mWaitingForTransaction(false),
     mSkippedPaints(false)
 {
   mMostRecentRefreshEpochTime = JS_Now();
   mMostRecentRefresh = TimeStamp::Now();
   mMostRecentTick = mMostRecentRefresh;
-  mNextThrottledFrameRequestTick = mMostRecentTick;
 }
 
 nsRefreshDriver::~nsRefreshDriver()
 {
   MOZ_ASSERT(ObserverCount() == 0,
              "observers should have unregistered");
   MOZ_ASSERT(!mActiveTimer, "timer should be gone");
   
@@ -1252,25 +1249,23 @@ DisableHighPrecisionTimersCallback(nsITi
   timeEndPeriod(1);
   NS_RELEASE(sDisableHighPrecisionTimersTimer);
 }
 #endif
 
 void
 nsRefreshDriver::ConfigureHighPrecision()
 {
-  bool haveUnthrottledFrameRequestCallbacks =
-    mFrameRequestCallbackDocs.Length() > 0;
+  bool haveFrameRequestCallbacks = mFrameRequestCallbackDocs.Length() > 0;
 
   // if the only change that's needed is that we need high precision,
   // then just set that
-  if (!mThrottled && !mRequestedHighPrecision &&
-      haveUnthrottledFrameRequestCallbacks) {
+  if (!mThrottled && !mRequestedHighPrecision && haveFrameRequestCallbacks) {
     SetHighPrecisionTimersEnabled(true);
-  } else if (mRequestedHighPrecision && !haveUnthrottledFrameRequestCallbacks) {
+  } else if (mRequestedHighPrecision && !haveFrameRequestCallbacks) {
     SetHighPrecisionTimersEnabled(false);
   }
 }
 
 void
 nsRefreshDriver::SetHighPrecisionTimersEnabled(bool aEnable)
 {
   LOG("[%p] SetHighPrecisionTimersEnabled (%s)", this, aEnable ? "true" : "false");
@@ -1328,17 +1323,16 @@ nsRefreshDriver::ObserverCount() const
 
   // Even while throttled, we need to process layout and style changes.  Style
   // changes can trigger transitions which fire events when they complete, and
   // layout changes can affect media queries on child documents, triggering
   // style changes, etc.
   sum += mStyleFlushObservers.Length();
   sum += mLayoutFlushObservers.Length();
   sum += mFrameRequestCallbackDocs.Length();
-  sum += mThrottledFrameRequestCallbackDocs.Length();
   sum += mViewManagerFlushIsPending;
   return sum;
 }
 
 /* static */ PLDHashOperator
 nsRefreshDriver::StartTableRequestCounter(const uint32_t& aKey,
                                           ImageStartData* aEntry,
                                           void* aUserArg)
@@ -1454,115 +1448,16 @@ static void GetProfileTimelineSubDocShel
     if (!isVisible) {
       continue;
     }
 
     aShells.AppendElement(shell);
   };
 }
 
-static void
-TakeFrameRequestCallbacksFrom(nsIDocument* aDocument,
-                              nsTArray<DocumentFrameCallbacks>& aTarget)
-{
-  aTarget.AppendElement(aDocument);
-  aDocument->TakeFrameRequestCallbacks(aTarget.LastElement().mCallbacks);
-}
-
-void
-nsRefreshDriver::RunFrameRequestCallbacks(int64_t aNowEpoch, TimeStamp aNowTime)
-{
-  // Grab all of our frame request callbacks up front.
-  nsTArray<DocumentFrameCallbacks>
-    frameRequestCallbacks(mFrameRequestCallbackDocs.Length() +
-                          mThrottledFrameRequestCallbackDocs.Length());
-
-  // First, grab throttled frame request callbacks.
-  {
-    nsTArray<nsIDocument*> docsToRemove;
-
-    // We always tick throttled frame requests if the entire refresh driver is
-    // throttled, because in that situation throttled frame requests tick at the
-    // same frequency as non-throttled frame requests.
-    bool tickThrottledFrameRequests = mThrottled;
-
-    if (!tickThrottledFrameRequests &&
-        aNowTime >= mNextThrottledFrameRequestTick) {
-      mNextThrottledFrameRequestTick = aNowTime + mThrottledFrameRequestInterval;
-      tickThrottledFrameRequests = true;
-    }
-
-    for (nsIDocument* doc : mThrottledFrameRequestCallbackDocs) {
-      if (tickThrottledFrameRequests) {
-        // We're ticking throttled documents, so grab this document's requests.
-        // We don't bother appending to docsToRemove because we're going to
-        // clear mThrottledFrameRequestCallbackDocs anyway.
-        TakeFrameRequestCallbacksFrom(doc, frameRequestCallbacks);
-      } else if (!doc->ShouldThrottleFrameRequests()) {
-        // This document is no longer throttled, so grab its requests even
-        // though we're not ticking throttled frame requests right now. If
-        // this is the first unthrottled document with frame requests, we'll
-        // enter high precision mode the next time the callback is scheduled.
-        TakeFrameRequestCallbacksFrom(doc, frameRequestCallbacks);
-        docsToRemove.AppendElement(doc);
-      }
-    }
-
-    // Remove all the documents we're ticking from
-    // mThrottledFrameRequestCallbackDocs so they can be readded as needed.
-    if (tickThrottledFrameRequests) {
-      mThrottledFrameRequestCallbackDocs.Clear();
-    } else {
-      // XXX(seth): We're using this approach to avoid concurrent modification
-      // of mThrottledFrameRequestCallbackDocs. docsToRemove usually has either
-      // zero elements or a very small number, so this should be OK in practice.
-      for (nsIDocument* doc : docsToRemove) {
-        mThrottledFrameRequestCallbackDocs.RemoveElement(doc);
-      }
-    }
-  }
-
-  // Now grab unthrottled frame request callbacks.
-  for (nsIDocument* doc : mFrameRequestCallbackDocs) {
-    TakeFrameRequestCallbacksFrom(doc, frameRequestCallbacks);
-  }
-
-  // Reset mFrameRequestCallbackDocs so they can be readded as needed.
-  mFrameRequestCallbackDocs.Clear();
-
-  profiler_tracing("Paint", "Scripts", TRACING_INTERVAL_START);
-  int64_t eventTime = aNowEpoch / PR_USEC_PER_MSEC;
-  for (uint32_t i = 0; i < frameRequestCallbacks.Length(); ++i) {
-    const DocumentFrameCallbacks& docCallbacks = frameRequestCallbacks[i];
-    // XXXbz Bug 863140: GetInnerWindow can return the outer
-    // window in some cases.
-    nsPIDOMWindow* innerWindow = docCallbacks.mDocument->GetInnerWindow();
-    DOMHighResTimeStamp timeStamp = 0;
-    if (innerWindow && innerWindow->IsInnerWindow()) {
-      nsPerformance* perf = innerWindow->GetPerformance();
-      if (perf) {
-        timeStamp = perf->GetDOMTiming()->TimeStampToDOMHighRes(aNowTime);
-      }
-      // else window is partially torn down already
-    }
-    for (uint32_t j = 0; j < docCallbacks.mCallbacks.Length(); ++j) {
-      const nsIDocument::FrameRequestCallbackHolder& holder =
-        docCallbacks.mCallbacks[j];
-      nsAutoMicroTask mt;
-      if (holder.HasWebIDLCallback()) {
-        ErrorResult ignored;
-        holder.GetWebIDLCallback()->Call(timeStamp, ignored);
-      } else {
-        holder.GetXPCOMCallback()->Sample(eventTime);
-      }
-    }
-  }
-  profiler_tracing("Paint", "Scripts", TRACING_INTERVAL_END);
-}
-
 void
 nsRefreshDriver::Tick(int64_t aNowEpoch, TimeStamp aNowTime)
 {
   NS_PRECONDITION(!nsContentUtils::GetCurrentJSContext(),
                   "Shouldn't have a JSContext on the stack");
 
   if (nsNPAPIPluginInstance::InPluginCallUnsafeForReentry()) {
     NS_ERROR("Refresh driver should not run during plugin call!");
@@ -1643,17 +1538,56 @@ nsRefreshDriver::Tick(int64_t aNowEpoch,
         StopTimer();
         return;
       }
     }
 
     if (i == 0) {
       // This is the Flush_Style case.
 
-      RunFrameRequestCallbacks(aNowEpoch, aNowTime);
+      // Grab all of our frame request callbacks up front.
+      nsTArray<DocumentFrameCallbacks>
+        frameRequestCallbacks(mFrameRequestCallbackDocs.Length());
+      for (uint32_t i = 0; i < mFrameRequestCallbackDocs.Length(); ++i) {
+        frameRequestCallbacks.AppendElement(mFrameRequestCallbackDocs[i]);
+        mFrameRequestCallbackDocs[i]->
+          TakeFrameRequestCallbacks(frameRequestCallbacks.LastElement().mCallbacks);
+      }
+      // OK, now reset mFrameRequestCallbackDocs so they can be
+      // readded as needed.
+      mFrameRequestCallbackDocs.Clear();
+
+      profiler_tracing("Paint", "Scripts", TRACING_INTERVAL_START);
+      int64_t eventTime = aNowEpoch / PR_USEC_PER_MSEC;
+      for (uint32_t i = 0; i < frameRequestCallbacks.Length(); ++i) {
+        const DocumentFrameCallbacks& docCallbacks = frameRequestCallbacks[i];
+        // XXXbz Bug 863140: GetInnerWindow can return the outer
+        // window in some cases.
+        nsPIDOMWindow* innerWindow = docCallbacks.mDocument->GetInnerWindow();
+        DOMHighResTimeStamp timeStamp = 0;
+        if (innerWindow && innerWindow->IsInnerWindow()) {
+          nsPerformance* perf = innerWindow->GetPerformance();
+          if (perf) {
+            timeStamp = perf->GetDOMTiming()->TimeStampToDOMHighRes(aNowTime);
+          }
+          // else window is partially torn down already
+        }
+        for (uint32_t j = 0; j < docCallbacks.mCallbacks.Length(); ++j) {
+          const nsIDocument::FrameRequestCallbackHolder& holder =
+            docCallbacks.mCallbacks[j];
+          nsAutoMicroTask mt;
+          if (holder.HasWebIDLCallback()) {
+            ErrorResult ignored;
+            holder.GetWebIDLCallback()->Call(timeStamp, ignored);
+          } else {
+            holder.GetXPCOMCallback()->Sample(eventTime);
+          }
+        }
+      }
+      profiler_tracing("Paint", "Scripts", TRACING_INTERVAL_END);
 
       if (mPresContext && mPresContext->GetPresShell()) {
         bool tracingStyleFlush = false;
         nsAutoTArray<nsIPresShell*, 16> observers;
         observers.AppendElements(mStyleFlushObservers);
         for (uint32_t j = observers.Length();
              j && mPresContext && mPresContext->GetPresShell(); --j) {
           // Make sure to not process observers which might have been removed
@@ -2086,34 +2020,27 @@ nsRefreshDriver::ScheduleViewManagerFlus
   mViewManagerFlushIsPending = true;
   EnsureTimerStarted();
 }
 
 void
 nsRefreshDriver::ScheduleFrameRequestCallbacks(nsIDocument* aDocument)
 {
   NS_ASSERTION(mFrameRequestCallbackDocs.IndexOf(aDocument) ==
-               mFrameRequestCallbackDocs.NoIndex &&
-               mThrottledFrameRequestCallbackDocs.IndexOf(aDocument) ==
-               mThrottledFrameRequestCallbackDocs.NoIndex,
+               mFrameRequestCallbackDocs.NoIndex,
                "Don't schedule the same document multiple times");
-  if (aDocument->ShouldThrottleFrameRequests()) {
-    mThrottledFrameRequestCallbackDocs.AppendElement(aDocument);
-  } else {
-    mFrameRequestCallbackDocs.AppendElement(aDocument);
-  }
+  mFrameRequestCallbackDocs.AppendElement(aDocument);
 
   // make sure that the timer is running
   ConfigureHighPrecision();
   EnsureTimerStarted();
 }
 
 void
 nsRefreshDriver::RevokeFrameRequestCallbacks(nsIDocument* aDocument)
 {
   mFrameRequestCallbackDocs.RemoveElement(aDocument);
-  mThrottledFrameRequestCallbackDocs.RemoveElement(aDocument);
   ConfigureHighPrecision();
   // No need to worry about restarting our timer in slack mode if it's already
   // running; that will happen automatically when it fires.
 }
 
 #undef LOG
--- a/layout/base/nsRefreshDriver.h
+++ b/layout/base/nsRefreshDriver.h
@@ -303,18 +303,16 @@ private:
     {
     }
 
     mozilla::Maybe<mozilla::TimeStamp> mStartTime;
     RequestTable mEntries;
   };
   typedef nsClassHashtable<nsUint32HashKey, ImageStartData> ImageStartTable;
 
-  void RunFrameRequestCallbacks(int64_t aNowEpoch, mozilla::TimeStamp aNowTime);
-
   void Tick(int64_t aNowEpoch, mozilla::TimeStamp aNowTime);
 
   enum EnsureTimerStartedFlags {
     eNone = 0,
     eAdjustingTimer = 1 << 0,
     eAllowTimeToGoBackwards = 1 << 1
   };
   void EnsureTimerStarted(EnsureTimerStartedFlags aFlags = eNone);
@@ -333,17 +331,17 @@ private:
   static PLDHashOperator BeginRefreshingImages(nsISupportsHashKey* aEntry,
                                                void* aUserArg);
   ObserverArray& ArrayFor(mozFlushType aFlushType);
   // Trigger a refresh immediately, if haven't been disconnected or frozen.
   void DoRefresh();
 
   double GetRefreshTimerInterval() const;
   double GetRegularTimerInterval(bool *outIsDefault = nullptr) const;
-  static double GetThrottledTimerInterval();
+  double GetThrottledTimerInterval() const;
 
   bool HaveFrameRequestCallbacks() const {
     return mFrameRequestCallbackDocs.Length() != 0;
   }
 
   void FinishedWaitingForTransaction();
 
   mozilla::RefreshDriverTimer* ChooseTimer() const;
@@ -358,21 +356,16 @@ private:
   nsRefPtr<nsRefreshDriver> mRootRefresh;
 
   // The most recently allocated transaction id.
   uint64_t mPendingTransaction;
   // The most recently completed transaction id.
   uint64_t mCompletedTransaction;
 
   uint32_t mFreezeCount;
-
-  // How long we wait between ticks for throttled (which generally means
-  // non-visible) documents registered with a non-throttled refresh driver.
-  const mozilla::TimeDuration mThrottledFrameRequestInterval;
-
   bool mThrottled;
   bool mTestControllingRefreshes;
   bool mViewManagerFlushIsPending;
   bool mRequestedHighPrecision;
   bool mInRefresh;
 
   // True if the refresh driver is suspended waiting for transaction
   // id's to be returned and shouldn't do any work during Tick().
@@ -381,29 +374,27 @@ private:
   // we should schedule a new Tick immediately when resumed instead
   // of waiting until the next interval.
   bool mSkippedPaints;
 
   int64_t mMostRecentRefreshEpochTime;
   mozilla::TimeStamp mMostRecentRefresh;
   mozilla::TimeStamp mMostRecentTick;
   mozilla::TimeStamp mTickStart;
-  mozilla::TimeStamp mNextThrottledFrameRequestTick;
 
   // separate arrays for each flush type we support
   ObserverArray mObservers[3];
   RequestTable mRequests;
   ImageStartTable mStartTable;
 
   nsAutoTArray<nsIPresShell*, 16> mStyleFlushObservers;
   nsAutoTArray<nsIPresShell*, 16> mLayoutFlushObservers;
   nsAutoTArray<nsIPresShell*, 16> mPresShellsToInvalidateIfHidden;
   // nsTArray on purpose, because we want to be able to swap.
   nsTArray<nsIDocument*> mFrameRequestCallbackDocs;
-  nsTArray<nsIDocument*> mThrottledFrameRequestCallbackDocs;
   nsTArray<nsAPostRefreshObserver*> mPostRefreshObservers;
 
   // Helper struct for processing image requests
   struct ImageRequestParameters {
     mozilla::TimeStamp mCurrent;
     mozilla::TimeStamp mPrevious;
     RequestTable* mRequests;
     mozilla::TimeStamp mDesired;
--- a/layout/generic/nsIFrame.h
+++ b/layout/generic/nsIFrame.h
@@ -2803,39 +2803,27 @@ NS_PTR_TO_INT32(frame->Properties().Get(
     PaintedPresShellList()->AppendElement(do_GetWeakReference(shell));
   }
   
   /**
    * Increment the paint count of all child PresShells that were painted during
    * the last repaint.
    */  
   void UpdatePaintCountForPaintedPresShells() {
-    for (nsWeakPtr& item : *PaintedPresShellList()) {
-      nsCOMPtr<nsIPresShell> shell = do_QueryReferent(item);
+    nsTArray<nsWeakPtr> * list = PaintedPresShellList();
+    for (int i = 0, l = list->Length(); i < l; i++) {
+      nsCOMPtr<nsIPresShell> shell = do_QueryReferent(list->ElementAt(i));
+      
       if (shell) {
         shell->IncrementPaintCount();
       }
     }
   }  
 
   /**
-   * @return true if we painted @aShell during the last repaint.
-   */
-  bool DidPaintPresShell(nsIPresShell* aShell)
-  {
-    for (nsWeakPtr& item : *PaintedPresShellList()) {
-      nsCOMPtr<nsIPresShell> shell = do_QueryReferent(item);
-      if (shell == aShell) {
-        return true;
-      }
-    }
-    return false;
-  }
-
-  /**
    * Accessors for the absolute containing block.
    */
   bool IsAbsoluteContainer() const { return !!(mState & NS_FRAME_HAS_ABSPOS_CHILDREN); }
   bool HasAbsolutelyPositionedChildren() const;
   nsAbsoluteContainingBlock* GetAbsoluteContainingBlock() const;
   void MarkAsAbsoluteContainingBlock();
   void MarkAsNotAbsoluteContainingBlock();
   // Child frame types override this function to select their own child list name