diff --git a/layout/generic/nsGfxScrollFrame.cpp b/layout/generic/nsGfxScrollFrame.cpp index 20cfcc932900..c849409c6157 100644 --- a/layout/generic/nsGfxScrollFrame.cpp +++ b/layout/generic/nsGfxScrollFrame.cpp @@ -6525,10 +6525,17 @@ uint32_t nsIScrollableFrame::GetPerceivedScrollingDirections() const { */ static void AppendScrollPositionsForSnap(const nsIFrame* aFrame, const nsIFrame* aScrolledFrame, + const Maybe& aSnapport, ScrollSnapInfo& aSnapInfo) { // FIXME: Bug 1373833: This target rect should be inflated by scroll-margin. nsRect targetRect = nsLayoutUtils::TransformFrameRectToAncestor( aFrame, aFrame->GetRectRelativeToSelf(), aScrolledFrame); + // Ignore elements outside of the snapport when we scroll to the given + // destination. + // https://drafts.csswg.org/css-scroll-snap-1/#snap-scope + if (aSnapport && !aSnapport->Intersects(targetRect)) { + return; + } WritingMode writingMode = aScrolledFrame->GetWritingMode(); LogicalRect logicalTargetRect(writingMode, targetRect, @@ -6634,9 +6641,12 @@ static void AppendScrollPositionsForSnap(const nsIFrame* aFrame, /** * Collect the scroll positions corresponding to snap positions of frames in the * subtree rooted at |aFrame|, relative to |aScrolledFrame|, into |aSnapInfo|. + * If |aSnapport| is given, elements outside of the range of |aSnapport| will be + * ignored. */ static void CollectScrollPositionsForSnap(nsIFrame* aFrame, nsIFrame* aScrolledFrame, + const Maybe& aSnapport, ScrollSnapInfo& aSnapInfo) { MOZ_ASSERT(StaticPrefs::layout_css_scroll_snap_v1_enabled()); @@ -6651,9 +6661,9 @@ static void CollectScrollPositionsForSnap(nsIFrame* aFrame, StyleScrollSnapAlignKeyword::None || styleDisplay->mScrollSnapAlign.block != StyleScrollSnapAlignKeyword::None) { - AppendScrollPositionsForSnap(f, aScrolledFrame, aSnapInfo); + AppendScrollPositionsForSnap(f, aScrolledFrame, aSnapport, aSnapInfo); } - CollectScrollPositionsForSnap(f, aScrolledFrame, aSnapInfo); + CollectScrollPositionsForSnap(f, aScrolledFrame, aSnapport, aSnapInfo); } } } @@ -6697,7 +6707,8 @@ static void CollectScrollSnapCoordinates(nsIFrame* aFrame, } } -layers::ScrollSnapInfo ScrollFrameHelper::ComputeScrollSnapInfo() const { +layers::ScrollSnapInfo ScrollFrameHelper::ComputeScrollSnapInfo( + const Maybe& aDestination) const { ScrollSnapInfo result; ScrollStyles styles = GetScrollStylesFromFrame(); @@ -6730,9 +6741,20 @@ layers::ScrollSnapInfo ScrollFrameHelper::ComputeScrollSnapInfo() const { if (StaticPrefs::layout_css_scroll_snap_v1_enabled()) { // FIXME: Bug 1373832: The snapport should be deflated by scroll-padding. - result.mSnapportSize = GetScrollPortRect().Size(); + nsSize snapportSize = GetScrollPortRect().Size(); - CollectScrollPositionsForSnap(mScrolledFrame, mScrolledFrame, result); + Maybe snapportOnDestination; + if (aDestination) { + snapportOnDestination.emplace( + IsPhysicalLTR() ? nsRect(aDestination.value(), snapportSize) + : nsRect(nsPoint(aDestination->x - snapportSize.width, + aDestination->y), + snapportSize)); + } + + result.mSnapportSize = snapportSize; + CollectScrollPositionsForSnap(mScrolledFrame, mScrolledFrame, + snapportOnDestination, result); return result; } @@ -6742,17 +6764,18 @@ layers::ScrollSnapInfo ScrollFrameHelper::ComputeScrollSnapInfo() const { return result; } -layers::ScrollSnapInfo ScrollFrameHelper::GetScrollSnapInfo() const { +layers::ScrollSnapInfo ScrollFrameHelper::GetScrollSnapInfo( + const Maybe& aDestination) const { // TODO(botond): Should we cache it? - return ComputeScrollSnapInfo(); + return ComputeScrollSnapInfo(aDestination); } bool ScrollFrameHelper::GetSnapPointForDestination( nsIScrollableFrame::ScrollUnit aUnit, nsPoint aStartPos, nsPoint& aDestination) { Maybe snapPoint = ScrollSnapUtils::GetSnapPointForDestination( - GetScrollSnapInfo(), aUnit, GetLayoutScrollRange(), aStartPos, - aDestination); + GetScrollSnapInfo(Some(aDestination)), aUnit, GetLayoutScrollRange(), + aStartPos, aDestination); if (snapPoint) { aDestination = snapPoint.ref(); return true; diff --git a/layout/generic/nsGfxScrollFrame.h b/layout/generic/nsGfxScrollFrame.h index 0af928f5048d..56c40c31b1e5 100644 --- a/layout/generic/nsGfxScrollFrame.h +++ b/layout/generic/nsGfxScrollFrame.h @@ -409,7 +409,8 @@ class ScrollFrameHelper : public nsIReflowCallback { nsIFrame* GetFrameForDir() const; // helper for Is{Physical,Bidi}LTR to find // the frame whose directionality we use - ScrollSnapInfo ComputeScrollSnapInfo() const; + ScrollSnapInfo ComputeScrollSnapInfo( + const Maybe& aDestination) const; public: bool IsScrollbarOnRight() const; @@ -473,7 +474,11 @@ class ScrollFrameHelper : public nsIReflowCallback { bool UsesContainerScrolling() const; - ScrollSnapInfo GetScrollSnapInfo() const; + // In the case where |aDestination| is given, elements which are entirely out + // of view when the scroll position is moved to |aDestination| are not going + // to be used for snap positions. + ScrollSnapInfo GetScrollSnapInfo( + const mozilla::Maybe& aDestination) const; bool DecideScrollableLayer(nsDisplayListBuilder* aBuilder, nsRect* aVisibleRect, nsRect* aDirtyRect, @@ -1182,7 +1187,7 @@ class nsHTMLScrollFrame : public nsContainerFrame, } ScrollSnapInfo GetScrollSnapInfo() const override { - return mHelper.GetScrollSnapInfo(); + return mHelper.GetScrollSnapInfo(Nothing()); } virtual bool DragScroll(mozilla::WidgetEvent* aEvent) override { @@ -1668,7 +1673,7 @@ class nsXULScrollFrame final : public nsBoxFrame, } ScrollSnapInfo GetScrollSnapInfo() const override { - return mHelper.GetScrollSnapInfo(); + return mHelper.GetScrollSnapInfo(Nothing()); } virtual bool DragScroll(mozilla::WidgetEvent* aEvent) override { diff --git a/testing/web-platform/meta/css/css-scroll-snap/overflowing-snap-areas.html.ini b/testing/web-platform/meta/css/css-scroll-snap/overflowing-snap-areas.html.ini deleted file mode 100644 index 02f9bfb1889d..000000000000 --- a/testing/web-platform/meta/css/css-scroll-snap/overflowing-snap-areas.html.ini +++ /dev/null @@ -1,7 +0,0 @@ -[overflowing-snap-areas.html] - [Snap to current scroll position which is a valid snap position, as the snap area covers snapport on x and the distance between the previous(800) and next(1400) is larger than snapport(500).] - expected: FAIL - - [Snap to current scroll position which is a valid snap position, as the snap area covers snapport on y and the distance between the previous(800) and next(1400) is larger than snapport(500).] - expected: FAIL - diff --git a/testing/web-platform/meta/css/css-scroll-snap/snap-to-visible-areas.html.ini b/testing/web-platform/meta/css/css-scroll-snap/snap-to-visible-areas.html.ini deleted file mode 100644 index 8827913a976b..000000000000 --- a/testing/web-platform/meta/css/css-scroll-snap/snap-to-visible-areas.html.ini +++ /dev/null @@ -1,7 +0,0 @@ -[snap-to-visible-areas.html] - [Only snap to visible area on X axis, even when the non-visible ones are closer] - expected: FAIL - - [Only snap to visible area on Y axis, even when the non-visible ones are closer] - expected: FAIL -