Bug 1253860 - Don't update the scrollbar unless we're actually painting. r=mstange
authorKartikaya Gupta <kgupta@mozilla.com>
Wed, 09 Mar 2016 22:57:15 -0500
changeset 313180 cd65b31bdeb565c34ae8e9d56107289ce71d9885
parent 313179 542181856257c0852bd29cacc34726a38fb47fd7
child 313181 7dc9b4f0a84f795e9e50fde363add0dd1a9801fd
push id6048
push userkmoir@mozilla.com
push dateMon, 06 Jun 2016 19:02:08 +0000
treeherdermozilla-esr52@46d72a56c57d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmstange
bugs1253860
milestone48.0a1
Bug 1253860 - Don't update the scrollbar unless we're actually painting. r=mstange MozReview-Commit-ID: 3JIcp2NFwRn
layout/generic/nsGfxScrollFrame.cpp
layout/generic/nsGfxScrollFrame.h
layout/xul/nsIScrollbarMediator.h
layout/xul/nsListBoxBodyFrame.h
layout/xul/nsSliderFrame.cpp
layout/xul/tree/nsTreeBodyFrame.h
--- a/layout/generic/nsGfxScrollFrame.cpp
+++ b/layout/generic/nsGfxScrollFrame.cpp
@@ -2725,21 +2725,26 @@ ScrollFrameHelper::ScrollToImpl(nsPoint 
 
   if (mOuter->ChildrenHavePerspective()) {
     // The overflow areas of descendants may depend on the scroll position,
     // so ensure they get updated.
     mOuter->RecomputePerspectiveChildrenOverflow(mOuter, nullptr);
   }
 
   ScheduleSyntheticMouseMove();
-  nsWeakFrame weakFrame(mOuter);
-  UpdateScrollbarPosition();
-  if (!weakFrame.IsAlive()) {
-    return;
-  }
+
+  { // scope the AutoScrollbarRepaintSuppression
+    AutoScrollbarRepaintSuppression repaintSuppression(this, !schedulePaint);
+    nsWeakFrame weakFrame(mOuter);
+    UpdateScrollbarPosition();
+    if (!weakFrame.IsAlive()) {
+      return;
+    }
+  }
+
   PostScrollEvent();
 
   // notify the listeners.
   for (uint32_t i = 0; i < mListeners.Length(); i++) {
     mListeners[i]->ScrollPositionDidChange(pt.x, pt.y);
   }
 
   nsCOMPtr<nsIDocShell> docShell = presContext->GetDocShell();
--- a/layout/generic/nsGfxScrollFrame.h
+++ b/layout/generic/nsGfxScrollFrame.h
@@ -436,16 +436,19 @@ public:
                   nscoord aNewPos);
   void ScrollbarReleased(nsScrollbarFrame* aScrollbar);
   void ScrollByUnit(nsScrollbarFrame* aScrollbar,
                     nsIScrollableFrame::ScrollMode aMode,
                     int32_t aDirection,
                     nsIScrollableFrame::ScrollUnit aUnit,
                     nsIScrollbarMediator::ScrollSnapMode aSnap
                       = nsIScrollbarMediator::DISABLE_SNAP);
+  bool ShouldSuppressScrollbarRepaints() const {
+    return mSuppressScrollbarRepaints;
+  }
 
   // owning references to the nsIAnonymousContentCreator-built content
   nsCOMPtr<nsIContent> mHScrollbarContent;
   nsCOMPtr<nsIContent> mVScrollbarContent;
   nsCOMPtr<nsIContent> mScrollCornerContent;
   nsCOMPtr<nsIContent> mResizerContent;
 
   RefPtr<ScrollEvent> mScrollEvent;
@@ -568,19 +571,43 @@ public:
 
   // True if APZ can scroll this frame asynchronously (i.e. it has an APZC
   // set up for this frame and it's not a scrollinfo layer).
   bool mScrollableByAPZ:1;
 
   // True if the APZ is allowed to zoom this scrollframe.
   bool mZoomableByAPZ:1;
 
+  // True if we don't want the scrollbar to repaint itself right now.
+  bool mSuppressScrollbarRepaints:1;
+
   mozilla::layout::ScrollVelocityQueue mVelocityQueue;
 
 protected:
+  class AutoScrollbarRepaintSuppression;
+  friend class AutoScrollbarRepaintSuppression;
+  class AutoScrollbarRepaintSuppression {
+  public:
+    AutoScrollbarRepaintSuppression(ScrollFrameHelper* aHelper, bool aSuppress)
+      : mHelper(aHelper)
+      , mOldSuppressValue(aHelper->mSuppressScrollbarRepaints)
+    {
+      mHelper->mSuppressScrollbarRepaints = aSuppress;
+    }
+
+    ~AutoScrollbarRepaintSuppression()
+    {
+      mHelper->mSuppressScrollbarRepaints = mOldSuppressValue;
+    }
+
+  private:
+    ScrollFrameHelper* mHelper;
+    bool mOldSuppressValue;
+  };
+
   /**
    * @note This method might destroy the frame, pres shell and other objects.
    */
   void ScrollToWithOrigin(nsPoint aScrollPosition,
                           nsIScrollableFrame::ScrollMode aMode,
                           nsIAtom *aOrigin, // nullptr indicates "other" origin
                           const nsRect* aRange,
                           nsIScrollbarMediator::ScrollSnapMode aSnap
@@ -956,16 +983,20 @@ public:
   }
   virtual void ScrollbarActivityStarted() const override;
   virtual void ScrollbarActivityStopped() const override;
 
   virtual bool IsScrollbarOnRight() const override {
     return mHelper.IsScrollbarOnRight();
   }
 
+  virtual bool ShouldSuppressScrollbarRepaints() const override {
+    return mHelper.ShouldSuppressScrollbarRepaints();
+  }
+
   virtual void SetTransformingByAPZ(bool aTransforming) override {
     mHelper.SetTransformingByAPZ(aTransforming);
   }
   bool IsTransformingByAPZ() const override {
     return mHelper.IsTransformingByAPZ();
   }
   void SetScrollableByAPZ(bool aScrollable) override {
     mHelper.SetScrollableByAPZ(aScrollable);
@@ -1351,16 +1382,20 @@ public:
 
   virtual void ScrollbarActivityStarted() const override;
   virtual void ScrollbarActivityStopped() const override;
 
   virtual bool IsScrollbarOnRight() const override {
     return mHelper.IsScrollbarOnRight();
   }
 
+  virtual bool ShouldSuppressScrollbarRepaints() const override {
+    return mHelper.ShouldSuppressScrollbarRepaints();
+  }
+
   virtual void SetTransformingByAPZ(bool aTransforming) override {
     mHelper.SetTransformingByAPZ(aTransforming);
   }
   virtual bool UsesContainerScrolling() const override {
     return mHelper.UsesContainerScrolling();
   }
   bool IsTransformingByAPZ() const override {
     return mHelper.IsTransformingByAPZ();
--- a/layout/xul/nsIScrollbarMediator.h
+++ b/layout/xul/nsIScrollbarMediator.h
@@ -74,12 +74,18 @@ public:
   /**
    * Show or hide scrollbars on 2 fingers touch.
    * Subclasses should call their ScrollbarActivity's corresponding methods.
    */
   virtual void ScrollbarActivityStarted() const = 0;
   virtual void ScrollbarActivityStopped() const = 0;
 
   virtual bool IsScrollbarOnRight() const = 0;
+
+  /**
+   * Returns true if the mediator is asking the scrollbar to suppress
+   * repainting itself on changes.
+   */
+  virtual bool ShouldSuppressScrollbarRepaints() const = 0;
 };
 
 #endif
 
--- a/layout/xul/nsListBoxBodyFrame.h
+++ b/layout/xul/nsListBoxBodyFrame.h
@@ -70,16 +70,19 @@ public:
   virtual void ScrollbarReleased(nsScrollbarFrame* aScrollbar) override {}
   virtual void VisibilityChanged(bool aVisible) override;
   virtual nsIFrame* GetScrollbarBox(bool aVertical) override;
   virtual void ScrollbarActivityStarted() const override {}
   virtual void ScrollbarActivityStopped() const override {}
   virtual bool IsScrollbarOnRight() const override {
     return (StyleVisibility()->mDirection == NS_STYLE_DIRECTION_LTR);
   }
+  virtual bool ShouldSuppressScrollbarRepaints() const override {
+    return false;
+  }
 
 
   // nsIReflowCallback
   virtual bool ReflowFinished() override;
   virtual void ReflowCallbackCanceled() override;
 
   NS_IMETHOD DoLayout(nsBoxLayoutState& aBoxLayoutState) override;
   virtual void MarkIntrinsicISizesDirty() override;
--- a/layout/xul/nsSliderFrame.cpp
+++ b/layout/xul/nsSliderFrame.cpp
@@ -761,22 +761,21 @@ nsSliderFrame::CurrentPositionChanged()
     newThumbRect.x = snappedThumbLocation.x;
   } else {
     newThumbRect.y = snappedThumbLocation.y;
   }
 
   // set the rect
   thumbFrame->SetRect(newThumbRect);
 
-  // Request a repaint of the scrollbar unless we have paint-skipping enabled
-  // and this is an APZ scroll.
-  nsIScrollableFrame* scrollableFrame = do_QueryFrame(GetScrollbar()->GetParent());
-  if (!gfxPrefs::APZPaintSkipping() ||
-      !scrollableFrame ||
-      scrollableFrame->LastScrollOrigin() != nsGkAtoms::apz) {
+  // Request a repaint of the scrollbar
+  nsScrollbarFrame* scrollbarFrame = do_QueryFrame(scrollbarBox);
+  nsIScrollbarMediator* mediator = scrollbarFrame
+      ? scrollbarFrame->GetScrollbarMediator() : nullptr;
+  if (!mediator || !mediator->ShouldSuppressScrollbarRepaints()) {
     SchedulePaint();
   }
 
   mCurPos = curPos;
 
   // inform the parent <scale> if it exists that the value changed
   nsIFrame* parent = GetParent();
   if (parent) {
--- a/layout/xul/tree/nsTreeBodyFrame.h
+++ b/layout/xul/tree/nsTreeBodyFrame.h
@@ -155,16 +155,19 @@ public:
     ScrollParts parts = GetScrollParts();
     return aVertical ? parts.mVScrollbar : parts.mHScrollbar;
   }
   virtual void ScrollbarActivityStarted() const override;
   virtual void ScrollbarActivityStopped() const override;
   virtual bool IsScrollbarOnRight() const override {
     return (StyleVisibility()->mDirection == NS_STYLE_DIRECTION_LTR);
   }
+  virtual bool ShouldSuppressScrollbarRepaints() const override {
+    return false;
+  }
 
   // Overridden from nsIFrame to cache our pres context.
   virtual void Init(nsIContent*       aContent,
                     nsContainerFrame* aParent,
                     nsIFrame*         aPrevInFlow) override;
   virtual void DestroyFrom(nsIFrame* aDestructRoot) override;
 
   virtual nsresult GetCursor(const nsPoint& aPoint,