Bug 1253860 - Don't update the scrollbar unless we're actually painting. r?mstange
MozReview-Commit-ID: IzO0O4cervB
--- 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 SuppressScrollbarRepaints() 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 SuppressScrollbarRepaints() const override {
+ return mHelper.SuppressScrollbarRepaints();
+ }
+
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 SuppressScrollbarRepaints() const override {
+ return mHelper.SuppressScrollbarRepaints();
+ }
+
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 SuppressScrollbarRepaints() 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 SuppressScrollbarRepaints() 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->SuppressScrollbarRepaints()) {
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 SuppressScrollbarRepaints() 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,