diff --git a/layout/generic/nsGfxScrollFrame.cpp b/layout/generic/nsGfxScrollFrame.cpp index c849409c6157..34b7437e97b4 100644 --- a/layout/generic/nsGfxScrollFrame.cpp +++ b/layout/generic/nsGfxScrollFrame.cpp @@ -6519,15 +6519,31 @@ uint32_t nsIScrollableFrame::GetPerceivedScrollingDirections() const { return directions; } +static nsRect InflateByScrollMargin(const nsRect& aTargetRect, + const StyleRect& aScrollMargin, + const nsRect& aScrolledRect) { + nsMargin scrollMargin(aScrollMargin.Get(eSideTop).ToAppUnits(), + aScrollMargin.Get(eSideRight).ToAppUnits(), + aScrollMargin.Get(eSideBottom).ToAppUnits(), + aScrollMargin.Get(eSideLeft).ToAppUnits()); + + // Inflate the rect by scroll-margin. + nsRect result = aTargetRect; + result.Inflate(scrollMargin); + + // But don't be beyond the limit boundary. + return result.Intersect(aScrolledRect); +} + /** * Append scroll positions for valid snap positions into |aSnapInfo| if * applicable. */ static void AppendScrollPositionsForSnap(const nsIFrame* aFrame, const nsIFrame* aScrolledFrame, + const nsRect& aScrolledRect, 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 @@ -6537,6 +6553,20 @@ static void AppendScrollPositionsForSnap(const nsIFrame* aFrame, return; } + // These snap range shouldn't be involved with scroll-margin since we just + // need the visible range of the target element. + if (targetRect.width > aSnapInfo.mSnapportSize.width) { + aSnapInfo.mXRangeWiderThanSnapport.AppendElement( + ScrollSnapInfo::ScrollSnapRange(targetRect.X(), targetRect.XMost())); + } + if (targetRect.height > aSnapInfo.mSnapportSize.height) { + aSnapInfo.mYRangeWiderThanSnapport.AppendElement( + ScrollSnapInfo::ScrollSnapRange(targetRect.Y(), targetRect.YMost())); + } + + targetRect = InflateByScrollMargin( + targetRect, aFrame->StyleMargin()->mScrollMargin, aScrolledRect); + WritingMode writingMode = aScrolledFrame->GetWritingMode(); LogicalRect logicalTargetRect(writingMode, targetRect, aSnapInfo.mSnapportSize); @@ -6627,15 +6657,6 @@ static void AppendScrollPositionsForSnap(const nsIFrame* aFrame, : aSnapInfo.mSnapPositionY) .AppendElement(blockDirectionPosition.value()); } - - if (targetRect.width > aSnapInfo.mSnapportSize.width) { - aSnapInfo.mXRangeWiderThanSnapport.AppendElement( - ScrollSnapInfo::ScrollSnapRange(targetRect.X(), targetRect.XMost())); - } - if (targetRect.height > aSnapInfo.mSnapportSize.height) { - aSnapInfo.mYRangeWiderThanSnapport.AppendElement( - ScrollSnapInfo::ScrollSnapRange(targetRect.Y(), targetRect.YMost())); - } } /** @@ -6646,6 +6667,7 @@ static void AppendScrollPositionsForSnap(const nsIFrame* aFrame, */ static void CollectScrollPositionsForSnap(nsIFrame* aFrame, nsIFrame* aScrolledFrame, + const nsRect& aScrolledRect, const Maybe& aSnapport, ScrollSnapInfo& aSnapInfo) { MOZ_ASSERT(StaticPrefs::layout_css_scroll_snap_v1_enabled()); @@ -6661,9 +6683,11 @@ static void CollectScrollPositionsForSnap(nsIFrame* aFrame, StyleScrollSnapAlignKeyword::None || styleDisplay->mScrollSnapAlign.block != StyleScrollSnapAlignKeyword::None) { - AppendScrollPositionsForSnap(f, aScrolledFrame, aSnapport, aSnapInfo); + AppendScrollPositionsForSnap(f, aScrolledFrame, aScrolledRect, + aSnapport, aSnapInfo); } - CollectScrollPositionsForSnap(f, aScrolledFrame, aSnapport, aSnapInfo); + CollectScrollPositionsForSnap(f, aScrolledFrame, aScrolledRect, aSnapport, + aSnapInfo); } } } @@ -6754,7 +6778,8 @@ layers::ScrollSnapInfo ScrollFrameHelper::ComputeScrollSnapInfo( result.mSnapportSize = snapportSize; CollectScrollPositionsForSnap(mScrolledFrame, mScrolledFrame, - snapportOnDestination, result); + GetScrolledRect(), snapportOnDestination, + result); return result; } diff --git a/layout/style/nsStyleStruct.cpp b/layout/style/nsStyleStruct.cpp index c9adb0bfc5f9..d7138be48f67 100644 --- a/layout/style/nsStyleStruct.cpp +++ b/layout/style/nsStyleStruct.cpp @@ -202,13 +202,25 @@ nsStyleMargin::nsStyleMargin(const nsStyleMargin& aSrc) nsChangeHint nsStyleMargin::CalcDifference( const nsStyleMargin& aNewData) const { - if (mMargin == aNewData.mMargin) { + if (mMargin == aNewData.mMargin && mScrollMargin == aNewData.mScrollMargin) { return nsChangeHint(0); } - // Margin differences can't affect descendant intrinsic sizes and - // don't need to force children to reflow. - return nsChangeHint_NeedReflow | nsChangeHint_ReflowChangesSizeOrPosition | - nsChangeHint_ClearAncestorIntrinsics; + + nsChangeHint hint = nsChangeHint(0); + + if (mMargin != aNewData.mMargin) { + // Margin differences can't affect descendant intrinsic sizes and + // don't need to force children to reflow. + hint |= nsChangeHint_NeedReflow | nsChangeHint_ReflowChangesSizeOrPosition | + nsChangeHint_ClearAncestorIntrinsics; + } + + if (mScrollMargin != aNewData.mScrollMargin) { + // FIXME: Bug 1530253 Support re-snapping when scroll-margin changes. + hint |= nsChangeHint_NeutralChange; + } + + return hint; } nsStylePadding::nsStylePadding(const Document& aDocument) diff --git a/testing/web-platform/tests/css/css-scroll-snap/scroll-margin.html b/testing/web-platform/tests/css/css-scroll-snap/scroll-margin.html new file mode 100644 index 000000000000..c85232edf238 --- /dev/null +++ b/testing/web-platform/tests/css/css-scroll-snap/scroll-margin.html @@ -0,0 +1,73 @@ + + + + + + +
+
+
+
+
+ +