Skip to content

Commit

Permalink
[css-scroll-snap] Skip renderers with no element in updateSnapOffsets…
Browse files Browse the repository at this point in the history
…ForScrollableArea

https://bugs.webkit.org/show_bug.cgi?id=263093
rdar://111579277

Reviewed by Simon Fraser.

We should skip renderers in updateSnapOffsetsForScrollableArea if they have no related element.
For generated content we do generate an associated element as well, so the only time a renderer's
element is null is for anonymous renderers (as specified in RenderElement.h as well), which we
shouldn't snap to.

* Source/WebCore/page/scrolling/ScrollSnapOffsetsInfo.cpp:
(WebCore::updateSnapOffsetsForScrollableArea):

Canonical link: https://commits.webkit.org/275523@main
  • Loading branch information
nmoucht committed Mar 1, 2024
1 parent e7c5034 commit 2f88930
Show file tree
Hide file tree
Showing 4 changed files with 100 additions and 4 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@

PASS Only snap to visible areas in the case where taking the closest snap point of each axis does not snap to a visible area

Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
<!DOCTYPE html>
<title>
Snap to a visible area only even when there is a closer snap point for an area
that is closer but not visible (using both axes snap type), where the relevant
snap areas are pseudo-elements
</title>
<link rel="help" href="https://drafts.csswg.org/css-scroll-snap-1/#snap-scope"/>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<style>

body, html { height: 100%; }

div {
position: absolute;
margin: 0px;
}

#scroller {
height: 600px;
width: 600px;
overflow: scroll;
scroll-snap-type: both mandatory;
}

#space {
width: 2000px;
height: 2000px;
}

.snap {
width: 200px;
height: 200px;
background-color: blue;
scroll-snap-align: start;
}

#left-top {
left: 0px;
top: 0px;
}

#left-top::before {
position: absolute;
margin: 0px;
content: "";

display:block;

left: 0px;
top: 800px;
width: 200px;
height: 200px;
background-color: yellow;
scroll-snap-align: start;
}

#left-top::after {
position: absolute;
margin: 0px;
content: "";

display:block;

left: 800px;
top: 0px;
width: 200px;
height: 200px;
background-color: yellow;
scroll-snap-align: start;

}

</style>
<div id="scroller">
<div id="space"></div>
<div id="left-top" class="snap"></div>
</div>
<script>
test(t => {
const scroller = document.getElementById("scroller");
scroller.scrollTo(0, 0);
assert_equals(scroller.scrollLeft, 0);
assert_equals(scroller.scrollTop, 0);
scroller.scrollTo(500, 600);
assert_equals(scroller.scrollLeft, 0);
assert_equals(scroller.scrollTop, 800);
scroller.scrollTo(600, 500);
assert_equals(scroller.scrollLeft, 800);
assert_equals(scroller.scrollTop, 0);
}, 'Only snap to visible areas in the case where taking the closest snap point of \
each axis does not snap to a visible area');
</script>
1 change: 0 additions & 1 deletion LayoutTests/platform/mac/TestExpectations
Original file line number Diff line number Diff line change
Expand Up @@ -2524,7 +2524,6 @@ webkit.org/b/264001 [ Debug ] imported/w3c/web-platform-tests/requestidlecallbac

# webkit.org/b/264419 ([ Sonoma 14.1+ ] Multiple tests are constantly failing following update from 14.0.)
webkit.org/b/264544 [ Sonoma+ ] css3/filters/effect-opacity-hw.html [ ImageOnlyFailure ]
webkit.org/b/263783 [ Sonoma+ ] fast/scrolling/scroll-snap-crash.html [ Skip ]

webkit.org/b/264177 requestidlecallback/requestidlecallback-deadline-shortened-by-rendering-update.html [ Pass Failure ]

Expand Down
7 changes: 4 additions & 3 deletions Source/WebCore/page/scrolling/ScrollSnapOffsetsInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -347,7 +347,7 @@ void updateSnapOffsetsForScrollableArea(ScrollableArea& scrollableArea, const Re
auto scrollSnapPort = computeScrollSnapPortOrAreaRect(viewportRectInBorderBoxCoordinates, scrollingElementStyle.scrollPadding(), InsetOrOutset::Inset);
LOG_WITH_STREAM(ScrollSnap, stream << "Computing scroll snap offsets for " << scrollableArea << " in snap port " << scrollSnapPort);
for (auto& child : boxesWithScrollSnapPositions) {
if (child.enclosingScrollableContainerForSnapping() != &scrollingElementBox)
if (child.enclosingScrollableContainerForSnapping() != &scrollingElementBox || !child.element())
continue;

// The bounds of the child element's snap area, where the top left of the scrolling container's border box is the origin.
Expand All @@ -361,7 +361,7 @@ void updateSnapOffsetsForScrollableArea(ScrollableArea& scrollableArea, const Re
scrollSnapArea.moveBy(scrollPosition);

scrollSnapArea = computeScrollSnapPortOrAreaRect(scrollSnapArea, child.style().scrollMargin(), InsetOrOutset::Outset);
LOG_WITH_STREAM(ScrollSnap, stream << " Considering scroll snap target area " << scrollSnapArea);
LOG_WITH_STREAM(ScrollSnap, stream << " Considering scroll snap target area " << scrollSnapArea << " scroll snap id: " << child.element()->identifier() << " element: " << *child.element());
auto alignment = child.style().scrollSnapAlign();
auto stop = child.style().scrollSnapStop();

Expand All @@ -388,8 +388,9 @@ void updateSnapOffsetsForScrollableArea(ScrollableArea& scrollableArea, const Re
snapAreas.append(scrollSnapAreaAsOffsets);

auto isFocused = child.element() ? focusedElement == child.element() : false;
auto identifier = child.element() ? child.element()->identifier() : ObjectIdentifier<ElementIdentifierType>(0);
auto identifier = child.element()->identifier();
snapAreasIDs.append(identifier);

if (snapsHorizontally) {
auto absoluteScrollXPosition = computeScrollSnapAlignOffset(scrollSnapArea.x(), scrollSnapArea.maxX(), xAlign, areaXAxisFlipped) - computeScrollSnapAlignOffset(scrollSnapPort.x(), scrollSnapPort.maxX(), xAlign, areaXAxisFlipped);
auto absoluteScrollOffset = clampTo<int>(scrollableArea.scrollOffsetFromPosition({ roundToInt(absoluteScrollXPosition), 0 }).x(), 0, maxScrollOffset.x());
Expand Down

0 comments on commit 2f88930

Please sign in to comment.