diff --git a/layout/generic/nsFrame.cpp b/layout/generic/nsFrame.cpp index 8d26aa422ade..6302d95982b6 100644 --- a/layout/generic/nsFrame.cpp +++ b/layout/generic/nsFrame.cpp @@ -2936,6 +2936,8 @@ nsIFrame::BuildDisplayListForStackingContext(nsDisplayListBuilder* aBuilder, inTransformSetter(aBuilder, inTransform); nsDisplayListBuilder::AutoSaveRestorePerspectiveIndex perspectiveIndex(aBuilder, this); + nsDisplayListBuilder::AutoFilterASRSetter + filterASRSetter(aBuilder, usingFilter); CheckForApzAwareEventHandlers(aBuilder, this); diff --git a/layout/generic/nsGfxScrollFrame.cpp b/layout/generic/nsGfxScrollFrame.cpp index 263dadc12b12..030a1fc49cd8 100644 --- a/layout/generic/nsGfxScrollFrame.cpp +++ b/layout/generic/nsGfxScrollFrame.cpp @@ -1301,6 +1301,12 @@ ScrollFrameHelper::SetZoomableByAPZ(bool aZoomable) } } +void +ScrollFrameHelper::SetHasOutOfFlowContentInsideFilter() +{ + mHasOutOfFlowContentInsideFilter = true; +} + bool ScrollFrameHelper::WantAsyncScroll() const { @@ -2075,6 +2081,7 @@ ScrollFrameHelper::ScrollFrameHelper(nsContainerFrame* aOuter, , mTransformingByAPZ(false) , mScrollableByAPZ(false) , mZoomableByAPZ(false) + , mHasOutOfFlowContentInsideFilter(false) , mSuppressScrollbarRepaints(false) , mVelocityQueue(aOuter->PresContext()) { @@ -2879,13 +2886,15 @@ ScrollFrameHelper::ScrollToImpl(nsPoint aPt, const nsRect& aRange, nsAtom* aOrig nsLayoutUtils::GetHighResolutionDisplayPort(content, &displayPort); displayPort.MoveBy(-mScrolledFrame->GetPosition()); - PAINT_SKIP_LOG("New scrollpos %s usingDP %d dpEqual %d scrollableByApz %d plugins %d perspective %d bglocal %d\n", + PAINT_SKIP_LOG("New scrollpos %s usingDP %d dpEqual %d scrollableByApz %d plugins" + "%d perspective %d bglocal %d filter %d\n", Stringify(CSSPoint::FromAppUnits(GetScrollPosition())).c_str(), usingDisplayPort, displayPort.IsEqualEdges(oldDisplayPort), mScrollableByAPZ, HasPluginFrames(), HasPerspective(), - HasBgAttachmentLocal()); + HasBgAttachmentLocal(), mHasOutOfFlowContentInsideFilter); if (usingDisplayPort && displayPort.IsEqualEdges(oldDisplayPort) && - !HasPerspective() && !HasBgAttachmentLocal()) { + !HasPerspective() && !HasBgAttachmentLocal() && + !mHasOutOfFlowContentInsideFilter) { bool haveScrollLinkedEffects = content->GetComposedDoc()->HasScrollLinkedEffect(); bool apzDisabled = haveScrollLinkedEffects && gfxPrefs::APZDisableForScrollLinkedEffects(); if (!apzDisabled && !HasPluginFrames()) { diff --git a/layout/generic/nsGfxScrollFrame.h b/layout/generic/nsGfxScrollFrame.h index 37d5cc889128..9b559ab73e5e 100644 --- a/layout/generic/nsGfxScrollFrame.h +++ b/layout/generic/nsGfxScrollFrame.h @@ -426,6 +426,7 @@ public: } void SetScrollableByAPZ(bool aScrollable); void SetZoomableByAPZ(bool aZoomable); + void SetHasOutOfFlowContentInsideFilter(); bool UsesContainerScrolling() const; @@ -632,6 +633,10 @@ public: // True if the APZ is allowed to zoom this scrollframe. bool mZoomableByAPZ:1; + // True if the scroll frame contains out-of-flow content and is inside + // a CSS filter. + bool mHasOutOfFlowContentInsideFilter:1; + // True if we don't want the scrollbar to repaint itself right now. bool mSuppressScrollbarRepaints:1; @@ -1062,6 +1067,9 @@ public: void SetZoomableByAPZ(bool aZoomable) override { mHelper.SetZoomableByAPZ(aZoomable); } + void SetHasOutOfFlowContentInsideFilter() override { + mHelper.SetHasOutOfFlowContentInsideFilter(); + } ScrollSnapInfo GetScrollSnapInfo() const override { return mHelper.GetScrollSnapInfo(); @@ -1497,6 +1505,9 @@ public: void SetZoomableByAPZ(bool aZoomable) override { mHelper.SetZoomableByAPZ(aZoomable); } + void SetHasOutOfFlowContentInsideFilter() override { + mHelper.SetHasOutOfFlowContentInsideFilter(); + } virtual bool DecideScrollableLayer(nsDisplayListBuilder* aBuilder, nsRect* aVisibleRect, nsRect* aDirtyRect, diff --git a/layout/generic/nsIScrollableFrame.h b/layout/generic/nsIScrollableFrame.h index 57657aa38088..67735edf375c 100644 --- a/layout/generic/nsIScrollableFrame.h +++ b/layout/generic/nsIScrollableFrame.h @@ -448,6 +448,13 @@ public: */ virtual void SetZoomableByAPZ(bool aZoomable) = 0; + /** + * Mark this scroll frame as having out-of-flow content inside a CSS filter. + * Such content will move incorrectly during async-scrolling; to mitigate + * this, paint skipping is disabled for such scroll frames. + */ + virtual void SetHasOutOfFlowContentInsideFilter() = 0; + /** * Whether or not this frame uses containerful scrolling. */ diff --git a/layout/painting/nsDisplayList.cpp b/layout/painting/nsDisplayList.cpp index a48dc402a62a..2adf430060dd 100644 --- a/layout/painting/nsDisplayList.cpp +++ b/layout/painting/nsDisplayList.cpp @@ -919,6 +919,17 @@ nsDisplayListBuilder::AutoCurrentActiveScrolledRootSetter::SetCurrentActiveScrol mBuilder->mCurrentContainerASR = ActiveScrolledRoot::PickAncestor( mBuilder->mCurrentContainerASR, finiteBoundsASR); + // If we are entering out-of-flow content inside a CSS filter, mark + // scroll frames wrt. which the content is fixed as containing such content. + if (mBuilder->mFilterASR && + ActiveScrolledRoot::IsAncestor(aActiveScrolledRoot, mBuilder->mFilterASR)) { + for (const ActiveScrolledRoot* asr = mBuilder->mFilterASR; + asr && asr != aActiveScrolledRoot; + asr = asr->mParent) { + asr->mScrollableFrame->SetHasOutOfFlowContentInsideFilter(); + } + } + mUsed = true; } @@ -970,6 +981,7 @@ nsDisplayListBuilder::nsDisplayListBuilder(nsIFrame* aReferenceFrame, mCurrentScrollbarFlags(nsDisplayOwnLayerFlags::eNone), mPerspectiveItemIndex(0), mSVGEffectsBuildingDepth(0), + mFilterASR(nullptr), mContainsBlendMode(false), mIsBuildingScrollbar(false), mCurrentScrollbarWillHaveLayer(false), diff --git a/layout/painting/nsDisplayList.h b/layout/painting/nsDisplayList.h index c9f011d93305..69f939680095 100644 --- a/layout/painting/nsDisplayList.h +++ b/layout/painting/nsDisplayList.h @@ -1125,6 +1125,28 @@ public: bool mOldValue; }; + /** + * A helper class to temporarily set the value of mFilterASR. + */ + class AutoFilterASRSetter; + friend class AutoFilterASRSetter; + class AutoFilterASRSetter { + public: + AutoFilterASRSetter(nsDisplayListBuilder* aBuilder, bool aUsingFilter) + : mBuilder(aBuilder), mOldValue(aBuilder->mFilterASR) + { + if (!aBuilder->mFilterASR && aUsingFilter) { + aBuilder->mFilterASR = aBuilder->CurrentActiveScrolledRoot(); + } + } + ~AutoFilterASRSetter() { + mBuilder->mFilterASR = mOldValue; + } + private: + nsDisplayListBuilder* mBuilder; + const ActiveScrolledRoot* mOldValue; + }; + class AutoSaveRestorePerspectiveIndex; friend class AutoSaveRestorePerspectiveIndex; class AutoSaveRestorePerspectiveIndex { @@ -1771,6 +1793,9 @@ private: Preserves3DContext mPreserves3DCtx; uint32_t mPerspectiveItemIndex; int32_t mSVGEffectsBuildingDepth; + // When we are inside a filter, the current ASR at the time we entered the + // filter. Otherwise nullptr. + const ActiveScrolledRoot* mFilterASR; bool mContainsBlendMode; bool mIsBuildingScrollbar; bool mCurrentScrollbarWillHaveLayer;