Backed out changeset 3b8a666e351e (bug 702463)
authorJared Wein <jwein@mozilla.com>
Tue, 03 Apr 2012 16:50:25 -0700
changeset 94260 01c41b9cd6509a2f4dec672a854df448bfd162a4
parent 94259 9638f8e27e0009619a23fb837a034e2418596a1c
child 94261 17deb5f61b4dd0a8455e1931f394de1221564b3f
push id886
push userlsblakk@mozilla.com
push dateMon, 04 Jun 2012 19:57:52 +0000
treeherdermozilla-beta@bbd8d5efd6d1 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs702463
milestone14.0a1
backs out3b8a666e351e1121ac71accf157c44d0b4c93957
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 3b8a666e351e (bug 702463)
layout/generic/nsGfxScrollFrame.cpp
layout/generic/nsGfxScrollFrame.h
--- a/layout/generic/nsGfxScrollFrame.cpp
+++ b/layout/generic/nsGfxScrollFrame.cpp
@@ -1307,42 +1307,41 @@ NS_QUERYFRAME_TAIL_INHERITING(nsBoxFrame
  
 //-------------------- Inner ----------------------
 
 #define SMOOTH_SCROLL_PREF_NAME "general.smoothScroll"
 
 const double kCurrentVelocityWeighting = 0.25;
 const double kStopDecelerationWeighting = 0.4;
 
-// AsyncScroll has ref counting.
-class nsGfxScrollFrameInner::AsyncScroll : public nsARefreshObserver {
+class nsGfxScrollFrameInner::AsyncScroll {
 public:
   typedef mozilla::TimeStamp TimeStamp;
   typedef mozilla::TimeDuration TimeDuration;
 
-  AsyncScroll()
-    : mIsFirstIteration(true)
-    , mCallee(nsnull)
-  {}
+  AsyncScroll():
+    mIsFirstIteration(true)
+    {}
 
   ~AsyncScroll() {
-    RemoveObserver();
+    if (mScrollTimer) mScrollTimer->Cancel();
   }
 
   nsPoint PositionAt(TimeStamp aTime);
   nsSize VelocityAt(TimeStamp aTime); // In nscoords per second
 
   void InitSmoothScroll(TimeStamp aTime, nsPoint aCurrentPos,
                         nsSize aCurrentVelocity, nsPoint aDestination,
                         nsIAtom *aOrigin);
 
   bool IsFinished(TimeStamp aTime) {
     return aTime > mStartTime + mDuration; // XXX or if we've hit the wall
   }
 
+  nsCOMPtr<nsITimer> mScrollTimer;
   TimeStamp mStartTime;
 
   // mPrevStartTime holds previous 3 timestamps for intervals averaging (to
   // reduce duration fluctuations). When AsyncScroll is constructed and no
   // previous timestamps are available (indicated with mIsFirstIteration),
   // initialize mPrevStartTime using imaginary previous timestamps with maximum
   // relevant intervals between them.
   TimeStamp mPrevStartTime[3];
@@ -1378,61 +1377,16 @@ protected:
 
   // Initializes the timing function in such a way that the current velocity is
   // preserved.
   void InitTimingFunction(nsSMILKeySpline& aTimingFunction,
                           nscoord aCurrentPos, nscoord aCurrentVelocity,
                           nscoord aDestination);
 
   void InitDuration(nsIAtom *aOrigin);
-
-// The next section is observer/callback management
-// Bodies of WillRefresh and RefreshDriver contain nsGfxScrollFrameInner specific code.
-public:
-  NS_INLINE_DECL_REFCOUNTING(AsyncScroll)
-
-  /*
-   * Set a refresh observer for smooth scroll iterations (and start observing).
-   * Should be used at most once during the lifetime of this object.
-   * Return value: true on success, false otherwise.
-   */
-  bool SetRefreshObserver(nsGfxScrollFrameInner *aCallee) {
-    NS_ASSERTION(aCallee && !mCallee, "AsyncScroll::SetRefreshObserver - Invalid usage.");
-
-    if (!RefreshDriver(aCallee)->AddRefreshObserver(this, Flush_Display)) {
-      return false;
-    }
-
-    mCallee = aCallee;
-    return true;
-  }
-
-  virtual void WillRefresh(mozilla::TimeStamp aTime) {
-    // The callback may release "this".
-    // We don't access members after returning, so no need for KungFuDeathGrip.
-    nsGfxScrollFrameInner::AsyncScrollCallback(mCallee, aTime);
-  }
-
-private:
-  nsGfxScrollFrameInner *mCallee;
-
-  nsRefreshDriver* RefreshDriver(nsGfxScrollFrameInner* aCallee) {
-    return aCallee->mOuter->PresContext()->RefreshDriver();
-  }
-
-  /* 
-   * The refresh driver doesn't hold a reference to its observers,
-   *   so releasing this object can (and is) used to remove the observer on DTOR.
-   * Currently, this object is released once the scrolling ends.
-   */
-  void RemoveObserver() {
-    if (mCallee) {
-      RefreshDriver(mCallee)->RemoveRefreshObserver(this, Flush_Display);
-    }
-  }
 };
 
 nsPoint
 nsGfxScrollFrameInner::AsyncScroll::PositionAt(TimeStamp aTime) {
   double progressX = mTimingFunctionX.GetSplineValue(ProgressAt(aTime));
   double progressY = mTimingFunctionY.GetSplineValue(ProgressAt(aTime));
   return nsPoint((1 - progressX) * mStartPos.x + progressX * mDestination.x,
                  (1 - progressY) * mStartPos.y + progressY * mDestination.y);
@@ -1636,16 +1590,17 @@ nsGfxScrollFrameInner::~nsGfxScrollFrame
   if (mActivityExpirationState.IsTracked()) {
     gScrollFrameActivityTracker->RemoveObject(this);
   }
   if (gScrollFrameActivityTracker &&
       gScrollFrameActivityTracker->IsEmpty()) {
     delete gScrollFrameActivityTracker;
     gScrollFrameActivityTracker = nsnull;
   }
+  delete mAsyncScroll;
 
   if (mScrollActivityTimer) {
     mScrollActivityTimer->Cancel();
     mScrollActivityTimer = nsnull;
   }
 }
 
 static nscoord
@@ -1662,33 +1617,38 @@ nsPoint
 nsGfxScrollFrameInner::ClampScrollPosition(const nsPoint& aPt) const
 {
   nsRect range = GetScrollRange();
   return nsPoint(Clamp(range.x, aPt.x, range.XMost()),
                  Clamp(range.y, aPt.y, range.YMost()));
 }
 
 /*
- * Callback function from AsyncScroll, used in nsGfxScrollFrameInner::ScrollTo
+ * Callback function from timer used in nsGfxScrollFrameInner::ScrollTo
  */
 void
-nsGfxScrollFrameInner::AsyncScrollCallback(void* anInstance, mozilla::TimeStamp aTime)
+nsGfxScrollFrameInner::AsyncScrollCallback(nsITimer *aTimer, void* anInstance)
 {
   nsGfxScrollFrameInner* self = static_cast<nsGfxScrollFrameInner*>(anInstance);
   if (!self || !self->mAsyncScroll)
     return;
 
   if (self->mAsyncScroll->mIsSmoothScroll) {
-    nsPoint destination = self->mAsyncScroll->PositionAt(aTime);
-    if (self->mAsyncScroll->IsFinished(aTime)) {
+    TimeStamp now = TimeStamp::Now();
+    nsPoint destination = self->mAsyncScroll->PositionAt(now);
+    if (self->mAsyncScroll->IsFinished(now)) {
+      delete self->mAsyncScroll;
       self->mAsyncScroll = nsnull;
     }
+
     self->ScrollToImpl(destination);
   } else {
+    delete self->mAsyncScroll;
     self->mAsyncScroll = nsnull;
+
     self->ScrollToImpl(self->mDestination);
   }
 }
 
 /*
  * this method wraps calls to ScrollToImpl(), either in one shot or incrementally,
  *  based on the setting of the smoothness scroll pref
  */
@@ -1701,16 +1661,17 @@ nsGfxScrollFrameInner::ScrollToWithOrigi
     mDestination = ClampScrollPosition(aScrollPosition);
   } else {
     mDestination = aScrollPosition;
   }
 
   if (aMode == nsIScrollableFrame::INSTANT) {
     // Asynchronous scrolling is not allowed, so we'll kill any existing
     // async-scrolling process and do an instant scroll
+    delete mAsyncScroll;
     mAsyncScroll = nsnull;
     ScrollToImpl(mDestination);
     return;
   }
 
   TimeStamp now = TimeStamp::Now();
   nsPoint currentPosition = GetScrollPosition();
   nsSize currentVelocity(0, 0);
@@ -1719,22 +1680,32 @@ nsGfxScrollFrameInner::ScrollToWithOrigi
 
   if (mAsyncScroll) {
     if (mAsyncScroll->mIsSmoothScroll) {
       currentPosition = mAsyncScroll->PositionAt(now);
       currentVelocity = mAsyncScroll->VelocityAt(now);
     }
   } else {
     mAsyncScroll = new AsyncScroll;
-    if (!mAsyncScroll->SetRefreshObserver(this)) {
+    mAsyncScroll->mScrollTimer = do_CreateInstance("@mozilla.org/timer;1");
+    if (!mAsyncScroll->mScrollTimer) {
+      delete mAsyncScroll;
       mAsyncScroll = nsnull;
-      // Observer setup failed. Scroll the normal way.
+      // allocation failed. Scroll the normal way.
       ScrollToImpl(mDestination);
       return;
     }
+    if (isSmoothScroll) {
+      mAsyncScroll->mScrollTimer->InitWithFuncCallback(
+        AsyncScrollCallback, this, 1000 / 60,
+        nsITimer::TYPE_REPEATING_SLACK);
+    } else {
+      mAsyncScroll->mScrollTimer->InitWithFuncCallback(
+        AsyncScrollCallback, this, 0, nsITimer::TYPE_ONE_SHOT);
+    }
   }
 
   mAsyncScroll->mIsSmoothScroll = isSmoothScroll;
 
   if (isSmoothScroll) {
     mAsyncScroll->InitSmoothScroll(now, currentPosition, currentVelocity,
                                    mDestination, aOrigin);
   }
--- a/layout/generic/nsGfxScrollFrame.h
+++ b/layout/generic/nsGfxScrollFrame.h
@@ -174,17 +174,17 @@ public:
       mScrollPort.XMost() - mScrolledFrame->GetRect().XMost();
     pt.y = mScrollPort.y - mScrolledFrame->GetPosition().y;
     return pt;
   }
   nsRect GetScrollRange() const;
 
   nsPoint RestrictToDevPixels(const nsPoint& aPt, nsIntPoint* aPtDevPx, bool aShouldClamp) const;
   nsPoint ClampScrollPosition(const nsPoint& aPt) const;
-  static void AsyncScrollCallback(void* anInstance, mozilla::TimeStamp aTime);
+  static void AsyncScrollCallback(nsITimer *aTimer, void* anInstance);
   void ScrollTo(nsPoint aScrollPosition, nsIScrollableFrame::ScrollMode aMode) {
     ScrollToWithOrigin(aScrollPosition, aMode, nsGkAtoms::other);
   };
   void ScrollToImpl(nsPoint aScrollPosition);
   void ScrollVisual(nsPoint aOldScrolledFramePosition);
   void ScrollBy(nsIntPoint aDelta, nsIScrollableFrame::ScrollUnit aUnit,
                 nsIScrollableFrame::ScrollMode aMode, nsIntPoint* aOverflow, nsIAtom *aOrigin = nsnull);
   void ScrollToRestoredPosition();
@@ -283,17 +283,17 @@ public:
   nsRevocableEventPtr<AsyncScrollPortEvent> mAsyncScrollPortEvent;
   nsRevocableEventPtr<ScrolledAreaEvent> mScrolledAreaEvent;
   nsIBox* mHScrollbarBox;
   nsIBox* mVScrollbarBox;
   nsIFrame* mScrolledFrame;
   nsIBox* mScrollCornerBox;
   nsIBox* mResizerBox;
   nsContainerFrame* mOuter;
-  nsRefPtr<AsyncScroll> mAsyncScroll;
+  AsyncScroll* mAsyncScroll;
   nsTArray<nsIScrollPositionListener*> mListeners;
   nsRect mScrollPort;
   // Where we're currently scrolling to, if we're scrolling asynchronously.
   // If we're not in the middle of an asynchronous scroll then this is
   // just the current scroll position. ScrollBy will choose its
   // destination based on this value.
   nsPoint mDestination;
   nsPoint mScrollPosAtLastPaint;