Title: [269506] trunk
Revision
269506
Author
[email protected]
Date
2020-11-06 01:44:54 -0800 (Fri, 06 Nov 2020)

Log Message

Scroll snap specified on :root doesn't work
https://bugs.webkit.org/show_bug.cgi?id=210469
<rdar://problem/61746676>

Source/WebCore:

Properly handle scroll-snap-type on the root element.

This change is originally based on a patch by Simon Fraser.

Patch by Martin Robinson <[email protected]> on 2020-11-06
Reviewed by Simon Fraser.

Tests: tiled-drawing/scrolling/scroll-snap/scroll-snap-mandatory-mainframe-horizontal-legacy.html
       tiled-drawing/scrolling/scroll-snap/scroll-snap-mandatory-mainframe-vertical-legacy.html
       tiled-drawing/scrolling/scroll-snap/scroll-snap-proximity-mainframe-legacy.html

* page/FrameView.cpp:
(WebCore::FrameView::updateSnapOffsets): Send the body or root element style depending
on where the scroll-snap properties are set, but always use the FrameView viewport
when calculating geometry for scroll snap.
* page/scrolling/AxisScrollSnapOffsets.cpp:
(WebCore::updateSnapOffsetsForScrollableArea): Accept a viewport rectangle from the
caller and also eliminate redundant argument that was causing a bit of confusion.
* page/scrolling/AxisScrollSnapOffsets.h: Update the function declaration.
* platform/ScrollableArea.cpp:
(WebCore::ScrollableArea::clearSnapOffsets):  Added a helper to clear both vertical and horizontal snap info.
* platform/ScrollableArea.h:
* rendering/RenderBox.cpp:
(WebCore::RenderBox::findEnclosingScrollableContainerForSnapping const): Renamed findEnclosingScrollableContainer
to this because now it is only useful for scroll snapping. The only preexisting caller was
the scroll snap code.
(WebCore::RenderBox::findEnclosingScrollableContainer const): Deleted.
* rendering/RenderBox.h: Updated method name.
* rendering/RenderLayer.cpp:
(WebCore::RenderLayer::updateSnapOffsets): Update to reflect changes to updateSnapOffsetsForScrollableArea.
* rendering/RenderObject.cpp:
(WebCore::RenderObject::enclosingScrollableContainerForSnapping const): Always return the
document root as the container instead of the body. The body never captures scroll
snap points.

LayoutTests:

Patch by Martin Robinson <[email protected]> on 2020-11-06
Reviewed by Simon Fraser.

Modified main frame scroll snap tests to reflect the specification and add a
few more tests to test the legacy behavior which this change maintains for
backwards compatibility.

* css3/scroll-snap/scroll-snap-positions-mainframe.html:
* tiled-drawing/scrolling/scroll-snap/scroll-snap-mandatory-mainframe-horizontal-legacy-expected.txt: Added.
* tiled-drawing/scrolling/scroll-snap/scroll-snap-mandatory-mainframe-horizontal-legacy.html: Copied from LayoutTests/tiled-drawing/scrolling/scroll-snap/scroll-snap-mandatory-mainframe-horizontal.html.
* tiled-drawing/scrolling/scroll-snap/scroll-snap-mandatory-mainframe-horizontal.html:
* tiled-drawing/scrolling/scroll-snap/scroll-snap-mandatory-mainframe-slow-horizontal.html:
* tiled-drawing/scrolling/scroll-snap/scroll-snap-mandatory-mainframe-slow-vertical.html:
* tiled-drawing/scrolling/scroll-snap/scroll-snap-mandatory-mainframe-vertical-legacy-expected.txt: Added.
* tiled-drawing/scrolling/scroll-snap/scroll-snap-mandatory-mainframe-vertical-legacy.html: Copied from LayoutTests/tiled-drawing/scrolling/scroll-snap/scroll-snap-mandatory-mainframe-vertical.html.
* tiled-drawing/scrolling/scroll-snap/scroll-snap-mandatory-mainframe-vertical-then-horizontal.html:
* tiled-drawing/scrolling/scroll-snap/scroll-snap-mandatory-mainframe-vertical.html:
* tiled-drawing/scrolling/scroll-snap/scroll-snap-proximity-mainframe-legacy-expected.txt: Added.
* tiled-drawing/scrolling/scroll-snap/scroll-snap-proximity-mainframe-legacy.html: Copied from LayoutTests/tiled-drawing/scrolling/scroll-snap/scroll-snap-proximity-mainframe.html.
* tiled-drawing/scrolling/scroll-snap/scroll-snap-proximity-mainframe.html:

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (269505 => 269506)


--- trunk/LayoutTests/ChangeLog	2020-11-06 09:09:31 UTC (rev 269505)
+++ trunk/LayoutTests/ChangeLog	2020-11-06 09:44:54 UTC (rev 269506)
@@ -1,3 +1,29 @@
+2020-11-06  Martin Robinson  <[email protected]>
+
+        Scroll snap specified on :root doesn't work
+        https://bugs.webkit.org/show_bug.cgi?id=210469
+        <rdar://problem/61746676>
+
+        Reviewed by Simon Fraser.
+
+        Modified main frame scroll snap tests to reflect the specification and add a
+        few more tests to test the legacy behavior which this change maintains for
+        backwards compatibility.
+
+        * css3/scroll-snap/scroll-snap-positions-mainframe.html:
+        * tiled-drawing/scrolling/scroll-snap/scroll-snap-mandatory-mainframe-horizontal-legacy-expected.txt: Added.
+        * tiled-drawing/scrolling/scroll-snap/scroll-snap-mandatory-mainframe-horizontal-legacy.html: Copied from LayoutTests/tiled-drawing/scrolling/scroll-snap/scroll-snap-mandatory-mainframe-horizontal.html.
+        * tiled-drawing/scrolling/scroll-snap/scroll-snap-mandatory-mainframe-horizontal.html:
+        * tiled-drawing/scrolling/scroll-snap/scroll-snap-mandatory-mainframe-slow-horizontal.html:
+        * tiled-drawing/scrolling/scroll-snap/scroll-snap-mandatory-mainframe-slow-vertical.html:
+        * tiled-drawing/scrolling/scroll-snap/scroll-snap-mandatory-mainframe-vertical-legacy-expected.txt: Added.
+        * tiled-drawing/scrolling/scroll-snap/scroll-snap-mandatory-mainframe-vertical-legacy.html: Copied from LayoutTests/tiled-drawing/scrolling/scroll-snap/scroll-snap-mandatory-mainframe-vertical.html.
+        * tiled-drawing/scrolling/scroll-snap/scroll-snap-mandatory-mainframe-vertical-then-horizontal.html:
+        * tiled-drawing/scrolling/scroll-snap/scroll-snap-mandatory-mainframe-vertical.html:
+        * tiled-drawing/scrolling/scroll-snap/scroll-snap-proximity-mainframe-legacy-expected.txt: Added.
+        * tiled-drawing/scrolling/scroll-snap/scroll-snap-proximity-mainframe-legacy.html: Copied from LayoutTests/tiled-drawing/scrolling/scroll-snap/scroll-snap-proximity-mainframe.html.
+        * tiled-drawing/scrolling/scroll-snap/scroll-snap-proximity-mainframe.html:
+
 2020-11-05  Alex Christensen  <[email protected]>
 
         Align GBK and gb18030 encoder and decoder with specification and other browsers

Modified: trunk/LayoutTests/css3/scroll-snap/scroll-snap-positions-mainframe.html (269505 => 269506)


--- trunk/LayoutTests/css3/scroll-snap/scroll-snap-positions-mainframe.html	2020-11-06 09:09:31 UTC (rev 269505)
+++ trunk/LayoutTests/css3/scroll-snap/scroll-snap-positions-mainframe.html	2020-11-06 09:44:54 UTC (rev 269506)
@@ -1,11 +1,13 @@
 <html>
 <head>
     <style>
-        body {
+        html {
             margin: 0;
             scroll-snap-type: y mandatory;
         }
-
+        body {
+            margin: 0;
+        }
         .vertical {
             width: 100%;
             height: 600px;

Added: trunk/LayoutTests/tiled-drawing/scrolling/scroll-snap/scroll-snap-mandatory-mainframe-horizontal-legacy-expected.txt (0 => 269506)


--- trunk/LayoutTests/tiled-drawing/scrolling/scroll-snap/scroll-snap-mandatory-mainframe-horizontal-legacy-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/tiled-drawing/scrolling/scroll-snap/scroll-snap-mandatory-mainframe-horizontal-legacy-expected.txt	2020-11-06 09:44:54 UTC (rev 269506)
@@ -0,0 +1,6 @@
+PASS div scrolled to next window.
+PASS div honored snap points.
+PASS successfullyParsed is true
+
+TEST COMPLETE
+

Copied: trunk/LayoutTests/tiled-drawing/scrolling/scroll-snap/scroll-snap-mandatory-mainframe-horizontal-legacy.html (from rev 269505, trunk/LayoutTests/tiled-drawing/scrolling/scroll-snap/scroll-snap-mandatory-mainframe-horizontal.html) (0 => 269506)


--- trunk/LayoutTests/tiled-drawing/scrolling/scroll-snap/scroll-snap-mandatory-mainframe-horizontal-legacy.html	                        (rev 0)
+++ trunk/LayoutTests/tiled-drawing/scrolling/scroll-snap/scroll-snap-mandatory-mainframe-horizontal-legacy.html	2020-11-06 09:44:54 UTC (rev 269506)
@@ -0,0 +1,119 @@
+<!DOCTYPE HTML>
+<html>
+    <head>
+        <style>
+            .horizontalGallery {
+                width: 600vw;
+                height: 100vh;
+                margin: 0;
+                padding: 0;
+                scroll-snap-type: x mandatory;
+            }
+            .colorBox {
+                height: 100vh;
+                width: 100vw;
+                float: left;
+                scroll-snap-align: start;
+            }
+            #item0 { background-color: red; }
+            #item1 { background-color: green; }
+            #item2 { background-color: blue; }
+            #item3 { background-color: aqua; }
+            #item4 { background-color: yellow; }
+            #item5 { background-color: fuchsia; }
+        </style>
+        <script src=""
+        <script>
+        window.jsTestIsAsync = true;
+
+        var targetScroller;
+        var scrollPositionBeforeGlide;
+        var scrollPositionBeforeSnap;
+
+        function checkForScrollSnap()
+        {
+            // The div should have snapped back to the previous position
+            if (targetScroller.scrollLeft != scrollPositionBeforeSnap)
+                testFailed("div did not snap back to proper location. Expected " + scrollPositionBeforeSnap + ", but got " + targetScroller.scrollLeft);
+            else
+                testPassed("div honored snap points.");
+
+            finishJSTest();
+        }
+
+        function scrollSnapTest()
+        {
+            scrollPositionBeforeSnap = targetScroller.scrollLeft;
+
+            var startPosX = targetScroller.offsetLeft + 20;
+            var startPosY = targetScroller.offsetTop + 20;
+            eventSender.monitorWheelEvents();
+            eventSender.mouseMoveTo(startPosX, startPosY); // Make sure we are just outside the iFrame
+            eventSender.mouseScrollByWithWheelAndMomentumPhases(-1, 0, 'began', 'none');
+            eventSender.mouseScrollByWithWheelAndMomentumPhases(-1, 0, 'changed', 'none');
+            eventSender.mouseScrollByWithWheelAndMomentumPhases(-1, 0, 'changed', 'none');
+            eventSender.mouseScrollByWithWheelAndMomentumPhases(0, 0, 'ended', 'none');
+            eventSender.callAfterScrollingCompletes(checkForScrollSnap);
+        }
+
+        function checkForScrollGlide()
+        {
+            // The div should have scrolled (glided) to the next snap point.
+            if (targetScroller.scrollLeft == window.innerWidth)
+                testPassed("div scrolled to next window.");
+            else
+                testFailed("div did not honor snap points. Expected " + window.innerWidth + ", but got " + targetScroller.scrollLeft);
+
+            setTimeout(scrollSnapTest, 0);
+        }
+
+        function scrollGlideTest()
+        {
+            scrollPositionBeforeGlide = targetScroller.scrollLeft;
+
+            var startPosX = targetScroller.offsetLeft + 20;
+            var startPosY = targetScroller.offsetTop + 20;
+            eventSender.monitorWheelEvents();
+            eventSender.mouseMoveTo(startPosX, startPosY); // Make sure we are just outside the iFrame
+            eventSender.mouseScrollByWithWheelAndMomentumPhases(-1, 0, 'began', 'none');
+            eventSender.mouseScrollByWithWheelAndMomentumPhases(-1, 0, 'changed', 'none');
+            eventSender.mouseScrollByWithWheelAndMomentumPhases(-1, 0, 'changed', 'none');
+            eventSender.mouseScrollByWithWheelAndMomentumPhases(-1, 0, 'changed', 'none');
+            eventSender.mouseScrollByWithWheelAndMomentumPhases(0, 0, 'ended', 'none');
+            eventSender.mouseScrollByWithWheelAndMomentumPhases(-1, 0, 'none', 'begin');
+            eventSender.mouseScrollByWithWheelAndMomentumPhases(-1, 0, 'none', 'continue');
+            eventSender.mouseScrollByWithWheelAndMomentumPhases(0, 0, 'none', 'end');
+            eventSender.callAfterScrollingCompletes(checkForScrollGlide);
+        }
+
+        function onLoad()
+        {
+            targetScroller = document.scrollingElement;
+            if (window.eventSender) {
+                internals.setPlatformMomentumScrollingPredictionEnabled(false);
+                setTimeout(scrollGlideTest, 0);
+            } else {
+                var messageLocation = document.getElementById('item0');
+                var message = document.createElement('div');
+                message.innerHTML = "<p>This test is better run under DumpRenderTree. To manually test it, place the mouse pointer<br/>"
+                    + "inside the red region at the top of the page, and then use the mouse wheel or a two-finger swipe to make a<br/>"
+                    + "small swipe gesture with some momentum.<br/><br/>"
+                    + "The region should scroll to show a green region.<br/><br/>"
+                    + "Next, perform a small scroll gesture that does not involve momentum. You should begin to see one of the colors<br/>"
+                    + "to the left (or right) of the current green box. When you release the wheel, the region should scroll back so<br/>"
+                    + "that the region is a single color.<br/><br/>"
+                    + "You should also be able to repeat these test steps for the vertical region below.</p>";
+                messageLocation.appendChild(message);
+            }
+        }
+        </script>
+    </head>
+    <body _onload_="onLoad();" class="horizontalGallery">
+        <div id="item0" class="colorBox"><div id="console"></div></div>
+        <div id="item1" class="colorBox"></div>
+        <div id="item2" class="colorBox"></div>
+        <div id="item3" class="colorBox"></div>
+        <div id="item4" class="colorBox"></div>
+        <div id="item5" class="colorBox"></div>
+    </body>
+</html>

Modified: trunk/LayoutTests/tiled-drawing/scrolling/scroll-snap/scroll-snap-mandatory-mainframe-horizontal.html (269505 => 269506)


--- trunk/LayoutTests/tiled-drawing/scrolling/scroll-snap/scroll-snap-mandatory-mainframe-horizontal.html	2020-11-06 09:09:31 UTC (rev 269505)
+++ trunk/LayoutTests/tiled-drawing/scrolling/scroll-snap/scroll-snap-mandatory-mainframe-horizontal.html	2020-11-06 09:44:54 UTC (rev 269506)
@@ -2,12 +2,14 @@
 <html>
     <head>
         <style>
+            html {
+                scroll-snap-type: x mandatory;
+            }
             .horizontalGallery {
                 width: 600vw;
                 height: 100vh;
                 margin: 0;
                 padding: 0;
-                scroll-snap-type: x mandatory;
             }
             .colorBox {
                 height: 100vh;

Modified: trunk/LayoutTests/tiled-drawing/scrolling/scroll-snap/scroll-snap-mandatory-mainframe-slow-horizontal.html (269505 => 269506)


--- trunk/LayoutTests/tiled-drawing/scrolling/scroll-snap/scroll-snap-mandatory-mainframe-slow-horizontal.html	2020-11-06 09:09:31 UTC (rev 269505)
+++ trunk/LayoutTests/tiled-drawing/scrolling/scroll-snap/scroll-snap-mandatory-mainframe-slow-horizontal.html	2020-11-06 09:44:54 UTC (rev 269506)
@@ -2,12 +2,14 @@
 <html>
     <head>
         <style>
+            html {
+                scroll-snap-type: x mandatory;
+            }
             .horizontalGallery {
                 width: 600vw;
                 height: 100vh;
                 margin: 0;
                 padding: 0;
-                scroll-snap-type: x mandatory;
             }
             .colorBox {
                 height: 100vh;

Modified: trunk/LayoutTests/tiled-drawing/scrolling/scroll-snap/scroll-snap-mandatory-mainframe-slow-vertical.html (269505 => 269506)


--- trunk/LayoutTests/tiled-drawing/scrolling/scroll-snap/scroll-snap-mandatory-mainframe-slow-vertical.html	2020-11-06 09:09:31 UTC (rev 269505)
+++ trunk/LayoutTests/tiled-drawing/scrolling/scroll-snap/scroll-snap-mandatory-mainframe-slow-vertical.html	2020-11-06 09:44:54 UTC (rev 269506)
@@ -2,12 +2,14 @@
 <html>
     <head>
         <style>
+            html {
+                scroll-snap-type: y mandatory;
+            }
             .verticalGallery {
                 width: 100vw;
                 height: 600vh;
                 margin: 0;
                 padding: 0;
-                scroll-snap-type: y mandatory;
             }
             .colorBox {
                 height: 100vh;

Added: trunk/LayoutTests/tiled-drawing/scrolling/scroll-snap/scroll-snap-mandatory-mainframe-vertical-legacy-expected.txt (0 => 269506)


--- trunk/LayoutTests/tiled-drawing/scrolling/scroll-snap/scroll-snap-mandatory-mainframe-vertical-legacy-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/tiled-drawing/scrolling/scroll-snap/scroll-snap-mandatory-mainframe-vertical-legacy-expected.txt	2020-11-06 09:44:54 UTC (rev 269506)
@@ -0,0 +1,6 @@
+PASS div scrolled to next window.
+PASS div honored snap points.
+PASS successfullyParsed is true
+
+TEST COMPLETE
+

Copied: trunk/LayoutTests/tiled-drawing/scrolling/scroll-snap/scroll-snap-mandatory-mainframe-vertical-legacy.html (from rev 269505, trunk/LayoutTests/tiled-drawing/scrolling/scroll-snap/scroll-snap-mandatory-mainframe-vertical.html) (0 => 269506)


--- trunk/LayoutTests/tiled-drawing/scrolling/scroll-snap/scroll-snap-mandatory-mainframe-vertical-legacy.html	                        (rev 0)
+++ trunk/LayoutTests/tiled-drawing/scrolling/scroll-snap/scroll-snap-mandatory-mainframe-vertical-legacy.html	2020-11-06 09:44:54 UTC (rev 269506)
@@ -0,0 +1,119 @@
+<!DOCTYPE HTML>
+<html>
+    <head>
+        <style>
+            .verticalGallery {
+                width: 100vw;
+                height: 600vh;
+                margin: 0;
+                padding: 0;
+                scroll-snap-type: y mandatory;
+            }
+            .colorBox {
+                height: 100vh;
+                width: 100vw;
+                float: left;
+                scroll-snap-align: start;
+            }
+            #item0 { background-color: red; }
+            #item1 { background-color: green; }
+            #item2 { background-color: blue; }
+            #item3 { background-color: aqua; }
+            #item4 { background-color: yellow; }
+            #item5 { background-color: fuchsia; }
+        </style>
+        <script src=""
+        <script>
+        window.jsTestIsAsync = true;
+
+        var scrollingTarget;
+        var scrollPositionBeforeGlide;
+        var scrollPositionBeforeSnap;
+
+        function checkForScrollSnap()
+        {
+            // The div should have snapped back to the previous position
+            if (scrollingTarget.scrollTop != scrollPositionBeforeSnap)
+                testFailed(`div did not snap back to proper location. (${scrollingTarget.scrollTop} vs. ${scrollPositionBeforeSnap})`);
+            else
+                testPassed("div honored snap points.");
+
+            finishJSTest();
+        }
+
+        function scrollSnapTest()
+        {
+            scrollPositionBeforeSnap = scrollingTarget.scrollTop;
+
+            var startPosX = scrollingTarget.offsetLeft + 20;
+            var startPosY = scrollingTarget.offsetTop + 20;
+            eventSender.monitorWheelEvents();
+            eventSender.mouseMoveTo(startPosX, startPosY); // Make sure we are just outside the iFrame
+            eventSender.mouseScrollByWithWheelAndMomentumPhases(0, -1, 'began', 'none');
+            eventSender.mouseScrollByWithWheelAndMomentumPhases(0, -1, 'changed', 'none');
+            eventSender.mouseScrollByWithWheelAndMomentumPhases(0, -1, 'changed', 'none');
+            eventSender.mouseScrollByWithWheelAndMomentumPhases(0, 0, 'ended', 'none');
+            eventSender.callAfterScrollingCompletes(checkForScrollSnap);
+        }
+
+        function checkForScrollGlide()
+        {
+            // The div should have scrolled (glided) to the next snap point.
+            if (scrollingTarget.scrollTop == window.innerHeight)
+                testPassed("div scrolled to next window.");
+            else
+                testFailed(`div did not honor snap points. (${scrollingTarget.scrollTop} vs. ${window.innerHeight})`);
+
+            setTimeout(scrollSnapTest, 0);
+        }
+
+        function scrollGlideTest()
+        {
+            scrollPositionBeforeGlide = scrollingTarget.scrollTop;
+
+            var startPosX = scrollingTarget.offsetLeft + 20;
+            var startPosY = scrollingTarget.offsetTop + 20;
+            eventSender.monitorWheelEvents();
+            eventSender.mouseMoveTo(startPosX, startPosY); // Make sure we are just outside the iFrame
+            eventSender.mouseScrollByWithWheelAndMomentumPhases(0, -1, 'began', 'none');
+            eventSender.mouseScrollByWithWheelAndMomentumPhases(0, -1, 'changed', 'none');
+            eventSender.mouseScrollByWithWheelAndMomentumPhases(0, -1, 'changed', 'none');
+            eventSender.mouseScrollByWithWheelAndMomentumPhases(0, -1, 'changed', 'none');
+            eventSender.mouseScrollByWithWheelAndMomentumPhases(0, 0, 'ended', 'none');
+            eventSender.mouseScrollByWithWheelAndMomentumPhases(0, -1, 'none', 'begin');
+            eventSender.mouseScrollByWithWheelAndMomentumPhases(0, -4, 'none', 'continue');
+            eventSender.mouseScrollByWithWheelAndMomentumPhases(0, 0, 'none', 'end');
+            eventSender.callAfterScrollingCompletes(checkForScrollGlide);
+        }
+
+        function onLoad()
+        {
+            scrollingTarget = document.scrollingElement;
+            if (window.eventSender) {
+                internals.setPlatformMomentumScrollingPredictionEnabled(false);
+                setTimeout(scrollGlideTest, 0);
+            } else {
+                var messageLocation = document.getElementById('item0');
+                var message = document.createElement('div');
+                message.innerHTML = "<p>This test is better run under DumpRenderTree. To manually test it, place the mouse pointer<br/>"
+                    + "inside the red region at the top of the page, and then use the mouse wheel or a two-finger swipe to make a<br/>"
+                    + "small swipe gesture with some momentum.<br/><br/>"
+                    + "The region should scroll to show a green region.<br/><br/>"
+                    + "Next, perform a small scroll gesture that does not involve momentum. You should begin to see one of the colors<br/>"
+                    + "to the left (or right) of the current green box. When you release the wheel, the region should scroll back so<br/>"
+                    + "that the region is a single color.<br/><br/>"
+                    + "You should also be able to repeat these test steps for the vertical region below.</p>";
+                messageLocation.appendChild(message);
+            }
+        }
+        </script>
+    </head>
+    <body _onload_="onLoad();" class="verticalGallery">
+        <div id="item0" class="colorBox"><div id="console"></div></div>
+        <div id="item1" class="colorBox"></div>
+        <div id="item2" class="colorBox"></div>
+        <div id="item3" class="colorBox"></div>
+        <div id="item4" class="colorBox"></div>
+        <div id="item5" class="colorBox"></div>
+    </body>
+</html>

Modified: trunk/LayoutTests/tiled-drawing/scrolling/scroll-snap/scroll-snap-mandatory-mainframe-vertical-then-horizontal.html (269505 => 269506)


--- trunk/LayoutTests/tiled-drawing/scrolling/scroll-snap/scroll-snap-mandatory-mainframe-vertical-then-horizontal.html	2020-11-06 09:09:31 UTC (rev 269505)
+++ trunk/LayoutTests/tiled-drawing/scrolling/scroll-snap/scroll-snap-mandatory-mainframe-vertical-then-horizontal.html	2020-11-06 09:44:54 UTC (rev 269506)
@@ -2,12 +2,14 @@
 <html>
     <head>
         <style>
+            html {
+                scroll-snap-type: y mandatory;
+            }
             .verticalGallery {
                 width: 100vw;
                 height: 600vh;
                 margin: 0;
                 padding: 0;
-                scroll-snap-type: y mandatory;
             }
             .colorBox {
                 height: 100vh;

Modified: trunk/LayoutTests/tiled-drawing/scrolling/scroll-snap/scroll-snap-mandatory-mainframe-vertical.html (269505 => 269506)


--- trunk/LayoutTests/tiled-drawing/scrolling/scroll-snap/scroll-snap-mandatory-mainframe-vertical.html	2020-11-06 09:09:31 UTC (rev 269505)
+++ trunk/LayoutTests/tiled-drawing/scrolling/scroll-snap/scroll-snap-mandatory-mainframe-vertical.html	2020-11-06 09:44:54 UTC (rev 269506)
@@ -2,12 +2,14 @@
 <html>
     <head>
         <style>
+            html {
+                scroll-snap-type: y mandatory;
+            }
             .verticalGallery {
                 width: 100vw;
                 height: 600vh;
                 margin: 0;
                 padding: 0;
-                scroll-snap-type: y mandatory;
             }
             .colorBox {
                 height: 100vh;

Added: trunk/LayoutTests/tiled-drawing/scrolling/scroll-snap/scroll-snap-proximity-mainframe-legacy-expected.txt (0 => 269506)


--- trunk/LayoutTests/tiled-drawing/scrolling/scroll-snap/scroll-snap-proximity-mainframe-legacy-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/tiled-drawing/scrolling/scroll-snap/scroll-snap-proximity-mainframe-legacy-expected.txt	2020-11-06 09:44:54 UTC (rev 269506)
@@ -0,0 +1,10 @@
+Scrolling body with 2 drag ticks
+- Did the scrolling snap to the top? YES
+- Did scrolling snap to the second box? NO
+Scrolling body with 30 drag ticks
+- Did the scrolling snap to the top? NO
+- Did scrolling snap to the second box? NO
+Scrolling body with 60 drag ticks
+- Did the scrolling snap to the top? NO
+- Did scrolling snap to the second box? YES
+

Copied: trunk/LayoutTests/tiled-drawing/scrolling/scroll-snap/scroll-snap-proximity-mainframe-legacy.html (from rev 269505, trunk/LayoutTests/tiled-drawing/scrolling/scroll-snap/scroll-snap-proximity-mainframe.html) (0 => 269506)


--- trunk/LayoutTests/tiled-drawing/scrolling/scroll-snap/scroll-snap-proximity-mainframe-legacy.html	                        (rev 0)
+++ trunk/LayoutTests/tiled-drawing/scrolling/scroll-snap/scroll-snap-proximity-mainframe-legacy.html	2020-11-06 09:44:54 UTC (rev 269506)
@@ -0,0 +1,78 @@
+<!DOCTYPE HTML>
+<html>
+    <head>
+        <style>
+            body {
+                margin: 0;
+                width: 100%;
+                height: 100%;
+                overflow-x: none;
+                overflow-y: scroll;
+                position: absolute;
+                scroll-snap-type: y proximity;
+            }
+
+            .area {
+                width: 100%;
+                height: 100%;
+                float: left;
+                opacity: 0.5;
+                scroll-snap-align: start;
+            }
+
+            #output {
+                position: fixed;
+            }
+        </style>
+        <script>
+        let write = s => output.innerHTML += s + "<br>";
+        if (window.testRunner) {
+            testRunner.dumpAsText();
+            testRunner.waitUntilDone();
+        }
+
+        function verticalScrollInBody(dragDeltas)
+        {
+            return new Promise(resolve => {
+                write(`Scrolling body with ${dragDeltas.length} drag ticks`);
+                eventSender.monitorWheelEvents();
+                internals.setPlatformMomentumScrollingPredictionEnabled(false);
+                eventSender.mouseMoveTo(window.innerWidth / 2, window.innerHeight / 2);
+                dragDeltas.forEach((delta, i) => eventSender.mouseScrollByWithWheelAndMomentumPhases(0, delta, i == 0 ? "began" : "changed", "none"));
+                eventSender.mouseScrollByWithWheelAndMomentumPhases(0, 0, "ended", "none");
+                eventSender.callAfterScrollingCompletes(() => {
+                    let areaHeight = document.querySelector(".area").clientHeight;
+                    write(`- Did the scrolling snap to the top? ${document.scrollingElement.scrollTop == 0 ? "YES" : "NO"}`);
+                    write(`- Did scrolling snap to the second box? ${document.scrollingElement.scrollTop == areaHeight ? "YES" : "NO"}`);
+                    document.scrollingElement.scrollTop = 0;
+                    setTimeout(resolve, 0);
+                });
+            });
+        }
+
+        function run() {
+            if (!window.testRunner || !window.eventSender) {
+                write("To manually test, verify that scrolling near one of the boundaries between the colored boxes");
+                write("snaps to the edge of the nearest colored box, but scrolling somewhere near the middle of two");
+                write("boxes does not cause the scroll offset to snap.");
+                return;
+            }
+
+            let areaHeight = document.querySelector(".area").clientHeight;
+            verticalScrollInBody(new Array(2).fill(-1))
+                .then(() => verticalScrollInBody(new Array(Math.round(areaHeight / 20)).fill(-1)))
+                .then(() => verticalScrollInBody(new Array(Math.round(areaHeight / 10)).fill(-1)))
+                .then(() => testRunner.notifyDone());
+        }
+        </script>
+    </head>
+    <body _onload_=run()>
+        <div class="area" style="background-color: red;"></div>
+        <div class="area" style="background-color: green;"></div>
+        <div class="area" style="background-color: blue;"></div>
+        <div class="area" style="background-color: aqua;"></div>
+        <div class="area" style="background-color: yellow;"></div>
+        <div class="area" style="background-color: fuchsia;"></div>
+    </body>
+    <div id="output"></div>
+</html>

Modified: trunk/LayoutTests/tiled-drawing/scrolling/scroll-snap/scroll-snap-proximity-mainframe.html (269505 => 269506)


--- trunk/LayoutTests/tiled-drawing/scrolling/scroll-snap/scroll-snap-proximity-mainframe.html	2020-11-06 09:09:31 UTC (rev 269505)
+++ trunk/LayoutTests/tiled-drawing/scrolling/scroll-snap/scroll-snap-proximity-mainframe.html	2020-11-06 09:44:54 UTC (rev 269506)
@@ -2,6 +2,9 @@
 <html>
     <head>
         <style>
+            html {
+                scroll-snap-type: y proximity;
+            }
             body {
                 margin: 0;
                 width: 100%;
@@ -9,9 +12,6 @@
                 overflow-x: none;
                 overflow-y: scroll;
                 position: absolute;
-                scroll-snap-type: y proximity;
-                -webkit-scroll-snap-type: proximity;
-                scroll-snap-type: proximity;
             }
 
             .area {
@@ -20,8 +20,6 @@
                 float: left;
                 opacity: 0.5;
                 scroll-snap-align: start;
-                -webkit-scroll-snap-coordinate: 0 0;
-                scroll-snap-coordinate: 0 0;
             }
 
             #output {

Modified: trunk/Source/WebCore/ChangeLog (269505 => 269506)


--- trunk/Source/WebCore/ChangeLog	2020-11-06 09:09:31 UTC (rev 269505)
+++ trunk/Source/WebCore/ChangeLog	2020-11-06 09:44:54 UTC (rev 269506)
@@ -1,3 +1,43 @@
+2020-11-06  Martin Robinson  <[email protected]>
+
+        Scroll snap specified on :root doesn't work
+        https://bugs.webkit.org/show_bug.cgi?id=210469
+        <rdar://problem/61746676>
+
+        Properly handle scroll-snap-type on the root element.
+
+        This change is originally based on a patch by Simon Fraser.
+
+        Reviewed by Simon Fraser.
+
+        Tests: tiled-drawing/scrolling/scroll-snap/scroll-snap-mandatory-mainframe-horizontal-legacy.html
+               tiled-drawing/scrolling/scroll-snap/scroll-snap-mandatory-mainframe-vertical-legacy.html
+               tiled-drawing/scrolling/scroll-snap/scroll-snap-proximity-mainframe-legacy.html
+
+        * page/FrameView.cpp:
+        (WebCore::FrameView::updateSnapOffsets): Send the body or root element style depending
+        on where the scroll-snap properties are set, but always use the FrameView viewport
+        when calculating geometry for scroll snap.
+        * page/scrolling/AxisScrollSnapOffsets.cpp:
+        (WebCore::updateSnapOffsetsForScrollableArea): Accept a viewport rectangle from the
+        caller and also eliminate redundant argument that was causing a bit of confusion.
+        * page/scrolling/AxisScrollSnapOffsets.h: Update the function declaration.
+        * platform/ScrollableArea.cpp:
+        (WebCore::ScrollableArea::clearSnapOffsets):  Added a helper to clear both vertical and horizontal snap info.
+        * platform/ScrollableArea.h:
+        * rendering/RenderBox.cpp:
+        (WebCore::RenderBox::findEnclosingScrollableContainerForSnapping const): Renamed findEnclosingScrollableContainer
+        to this because now it is only useful for scroll snapping. The only preexisting caller was
+        the scroll snap code.
+        (WebCore::RenderBox::findEnclosingScrollableContainer const): Deleted.
+        * rendering/RenderBox.h: Updated method name.
+        * rendering/RenderLayer.cpp:
+        (WebCore::RenderLayer::updateSnapOffsets): Update to reflect changes to updateSnapOffsetsForScrollableArea.
+        * rendering/RenderObject.cpp:
+        (WebCore::RenderObject::enclosingScrollableContainerForSnapping const): Always return the
+        document root as the container instead of the body. The body never captures scroll
+        snap points.
+
 2020-11-05  Said Abou-Hallawa  <[email protected]>
 
         [GPU Process] Use the Ref counting of ImageBuffer to control its life cycle in Web Process and GPU Process

Modified: trunk/Source/WebCore/page/FrameView.cpp (269505 => 269506)


--- trunk/Source/WebCore/page/FrameView.cpp	2020-11-06 09:09:31 UTC (rev 269505)
+++ trunk/Source/WebCore/page/FrameView.cpp	2020-11-06 09:44:54 UTC (rev 269506)
@@ -919,12 +919,30 @@
     if (!frame().document())
         return;
 
-    // FIXME: Should we allow specifying snap points through <html> tags too?
-    HTMLElement* body = frame().document()->bodyOrFrameset();
-    if (!renderView() || !body || !body->renderer())
+    auto& document = *frame().document();
+    auto* documentElement = document.documentElement();
+    RenderBox* bodyRenderer = document.bodyOrFrameset() ? document.bodyOrFrameset()->renderBox() : nullptr;
+    RenderBox* rootRenderer = documentElement ? documentElement->renderBox() : nullptr;
+    auto rendererSyleHasScrollSnap = [](const RenderObject* renderer) {
+        return renderer && renderer->style().scrollSnapType().strictness != ScrollSnapStrictness::None;
+    };
+
+    const RenderStyle* styleToUse = nullptr;
+    if (rendererSyleHasScrollSnap(bodyRenderer)) {
+        //  The specification doesn't allow setting scroll-snap-type on the body, but
+        //  we do this to ensure backwards compatibility with an earlier version of the
+        //  specification: See webkit.org/b/200643.
+        styleToUse = &bodyRenderer->style();
+    } else if (rendererSyleHasScrollSnap(rootRenderer))
+        styleToUse = &rootRenderer->style();
+
+    if (!styleToUse || !documentElement) {
+        clearSnapOffsets();
         return;
-    
-    updateSnapOffsetsForScrollableArea(*this, *body, *renderView(), body->renderer()->style());
+    }
+
+    LayoutRect viewport = LayoutRect(IntPoint(), baseLayoutViewportSize());
+    updateSnapOffsetsForScrollableArea(*this, *rootRenderer, *styleToUse, viewport);
 }
 
 bool FrameView::isScrollSnapInProgress() const

Modified: trunk/Source/WebCore/page/scrolling/AxisScrollSnapOffsets.cpp (269505 => 269506)


--- trunk/Source/WebCore/page/scrolling/AxisScrollSnapOffsets.cpp	2020-11-06 09:09:31 UTC (rev 269505)
+++ trunk/Source/WebCore/page/scrolling/AxisScrollSnapOffsets.cpp	2020-11-06 09:44:54 UTC (rev 269506)
@@ -160,13 +160,12 @@
     }
 }
 
-void updateSnapOffsetsForScrollableArea(ScrollableArea& scrollableArea, HTMLElement& scrollingElement, const RenderBox& scrollingElementBox, const RenderStyle& scrollingElementStyle)
+void updateSnapOffsetsForScrollableArea(ScrollableArea& scrollableArea, const RenderBox& scrollingElementBox, const RenderStyle& scrollingElementStyle, LayoutRect viewportRectInBorderBoxCoordinates)
 {
-    auto* scrollContainer = scrollingElement.renderer();
     auto scrollSnapType = scrollingElementStyle.scrollSnapType();
-    if (!scrollContainer || scrollSnapType.strictness == ScrollSnapStrictness::None || scrollContainer->view().boxesWithScrollSnapPositions().isEmpty()) {
-        scrollableArea.clearHorizontalSnapOffsets();
-        scrollableArea.clearVerticalSnapOffsets();
+    const auto& boxesWithScrollSnapPositions = scrollingElementBox.view().boxesWithScrollSnapPositions();
+    if (scrollSnapType.strictness == ScrollSnapStrictness::None || boxesWithScrollSnapPositions.isEmpty()) {
+        scrollableArea.clearSnapOffsets();
         return;
     }
 
@@ -184,16 +183,16 @@
     bool scrollerIsRTL = !scrollingElementBox.style().isLeftToRightDirection();
 
     // The bounds of the scrolling container's snap port, where the top left of the scrolling container's border box is the origin.
-    auto scrollSnapPort = computeScrollSnapPortOrAreaRect(scrollingElementBox.paddingBoxRect(), scrollingElementStyle.scrollPadding(), InsetOrOutset::Inset);
+    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 : scrollContainer->view().boxesWithScrollSnapPositions()) {
-        if (child->enclosingScrollableContainerForSnapping() != scrollContainer)
+    for (auto* child : boxesWithScrollSnapPositions) {
+        if (child->enclosingScrollableContainerForSnapping() != &scrollingElementBox)
             continue;
 
         // The bounds of the child element's snap area, where the top left of the scrolling container's border box is the origin.
         // The snap area is the bounding box of the child element's border box, after applying transformations.
         // FIXME: For now, just consider whether the scroller is RTL. The behavior of LTR boxes inside a RTL scroller is poorly defined: https://github.com/w3c/csswg-drafts/issues/5361.
-        auto scrollSnapArea = LayoutRect(child->localToContainerQuad(FloatQuad(child->borderBoundingBox()), scrollingElement.renderBox()).boundingBox());
+        auto scrollSnapArea = LayoutRect(child->localToContainerQuad(FloatQuad(child->borderBoundingBox()), &scrollingElementBox).boundingBox());
 
         // localToContainerQuad will transform the scroll snap area by the scroll position, except in the case that this position is
         // coming from a ScrollView. We want the transformed area, but without scroll position taken into account.

Modified: trunk/Source/WebCore/page/scrolling/AxisScrollSnapOffsets.h (269505 => 269506)


--- trunk/Source/WebCore/page/scrolling/AxisScrollSnapOffsets.h	2020-11-06 09:09:31 UTC (rev 269505)
+++ trunk/Source/WebCore/page/scrolling/AxisScrollSnapOffsets.h	2020-11-06 09:44:54 UTC (rev 269506)
@@ -27,6 +27,7 @@
 
 #if ENABLE(CSS_SCROLL_SNAP)
 
+#include "LayoutRect.h"
 #include "LayoutUnit.h"
 #include "ScrollSnapOffsetsInfo.h"
 #include "ScrollTypes.h"
@@ -39,7 +40,10 @@
 class RenderStyle;
 class ScrollableArea;
 
-void updateSnapOffsetsForScrollableArea(ScrollableArea&, HTMLElement& scrollingElement, const RenderBox& scrollingElementBox, const RenderStyle& scrollingElementStyle);
+// Update the snap offsets for this scrollable area, given the RenderBox of the scroll container, the RenderStyle
+// which defines the scroll-snap properties, and the viewport rectangle with the origin at the top left of
+// the scrolling container's border box.
+void updateSnapOffsetsForScrollableArea(ScrollableArea&, const RenderBox& scrollingElementBox, const RenderStyle& scrollingElementStyle, LayoutRect viewportRectInBorderBoxCoordinates);
 
 const unsigned invalidSnapOffsetIndex = UINT_MAX;
 WEBCORE_EXPORT LayoutUnit closestSnapOffset(const Vector<LayoutUnit>& snapOffsets, const Vector<ScrollOffsetRange<LayoutUnit>>& snapOffsetRanges, LayoutUnit scrollDestination, float velocity, unsigned& activeSnapIndex);

Modified: trunk/Source/WebCore/platform/ScrollableArea.cpp (269505 => 269506)


--- trunk/Source/WebCore/platform/ScrollableArea.cpp	2020-11-06 09:09:31 UTC (rev 269505)
+++ trunk/Source/WebCore/platform/ScrollableArea.cpp	2020-11-06 09:44:54 UTC (rev 269506)
@@ -530,6 +530,12 @@
     ensureSnapOffsetsInfo().verticalSnapOffsetRanges = verticalRanges;
 }
 
+void ScrollableArea::clearSnapOffsets()
+{
+    clearHorizontalSnapOffsets();
+    clearVerticalSnapOffsets();
+}
+
 void ScrollableArea::clearHorizontalSnapOffsets()
 {
     if (!m_snapOffsetsInfo)

Modified: trunk/Source/WebCore/platform/ScrollableArea.h (269505 => 269506)


--- trunk/Source/WebCore/platform/ScrollableArea.h	2020-11-06 09:09:31 UTC (rev 269505)
+++ trunk/Source/WebCore/platform/ScrollableArea.h	2020-11-06 09:44:54 UTC (rev 269506)
@@ -96,6 +96,7 @@
     void setVerticalSnapOffsets(const Vector<LayoutUnit>&);
     void setHorizontalSnapOffsetRanges(const Vector<ScrollOffsetRange<LayoutUnit>>&);
     void setVerticalSnapOffsetRanges(const Vector<ScrollOffsetRange<LayoutUnit>>&);
+    void clearSnapOffsets();
     void clearHorizontalSnapOffsets();
     void clearVerticalSnapOffsets();
     unsigned currentHorizontalSnapPointIndex() const { return m_currentHorizontalSnapPointIndex; }

Modified: trunk/Source/WebCore/rendering/RenderBox.cpp (269505 => 269506)


--- trunk/Source/WebCore/rendering/RenderBox.cpp	2020-11-06 09:09:31 UTC (rev 269505)
+++ trunk/Source/WebCore/rendering/RenderBox.cpp	2020-11-06 09:44:54 UTC (rev 269506)
@@ -5033,17 +5033,18 @@
     return containerBlock->offsetFromLogicalTopOfFirstPage() + logicalTop();
 }
 
-const RenderBox* RenderBox::findEnclosingScrollableContainer() const
+const RenderBox* RenderBox::findEnclosingScrollableContainerForSnapping() const
 {
     for (auto& candidate : lineageOfType<RenderBox>(*this)) {
         if (candidate.hasOverflowClip())
             return &candidate;
     }
-    // If all parent elements are not overflow scrollable, check the body.
-    // FIXME: We should not treat the body as the scrollable element (see webkit.org/b/210469).
-    if (document().body() && frame().view() && frame().view()->isScrollable())
-        return document().body()->renderBox();
-    
+
+    // If all parent elements are not overflow scrollable and the frame is, then return
+    // the root element.
+    if (document().documentElement() && frame().view() && frame().view()->isScrollable())
+        return document().documentElement()->renderBox();
+
     return nullptr;
 }
 

Modified: trunk/Source/WebCore/rendering/RenderBox.h (269505 => 269506)


--- trunk/Source/WebCore/rendering/RenderBox.h	2020-11-06 09:09:31 UTC (rev 269505)
+++ trunk/Source/WebCore/rendering/RenderBox.h	2020-11-06 09:44:54 UTC (rev 269506)
@@ -637,7 +637,7 @@
     bool canHaveOutsideFragmentRange() const { return !isInFlowRenderFragmentedFlow(); }
     virtual bool needsLayoutAfterFragmentRangeChange() const { return false; }
 
-    const RenderBox* findEnclosingScrollableContainer() const;
+    const RenderBox* findEnclosingScrollableContainerForSnapping() const;
     
     bool isGridItem() const { return parent() && parent()->isRenderGrid() && !isExcludedFromNormalLayout(); }
     bool isFlexItem() const { return parent() && parent()->isFlexibleBox() && !isExcludedFromNormalLayout(); }

Modified: trunk/Source/WebCore/rendering/RenderLayer.cpp (269505 => 269506)


--- trunk/Source/WebCore/rendering/RenderLayer.cpp	2020-11-06 09:09:31 UTC (rev 269505)
+++ trunk/Source/WebCore/rendering/RenderLayer.cpp	2020-11-06 09:44:54 UTC (rev 269506)
@@ -3592,7 +3592,7 @@
         return;
 
     RenderBox* box = enclosingElement()->renderBox();
-    updateSnapOffsetsForScrollableArea(*this, *downcast<HTMLElement>(enclosingElement()), *box, box->style());
+    updateSnapOffsetsForScrollableArea(*this, *box, box->style(), box->paddingBoxRect());
 }
 
 bool RenderLayer::isScrollSnapInProgress() const

Modified: trunk/Source/WebCore/rendering/RenderObject.cpp (269505 => 269506)


--- trunk/Source/WebCore/rendering/RenderObject.cpp	2020-11-06 09:09:31 UTC (rev 269505)
+++ trunk/Source/WebCore/rendering/RenderObject.cpp	2020-11-06 09:44:54 UTC (rev 269506)
@@ -455,12 +455,12 @@
 const RenderBox* RenderObject::enclosingScrollableContainerForSnapping() const
 {
     auto& renderBox = enclosingBox();
-    if (auto* scrollableContainer = renderBox.findEnclosingScrollableContainer()) {
+    if (auto* scrollableContainer = renderBox.findEnclosingScrollableContainerForSnapping()) {
         // The scrollable container for snapping cannot be the node itself.
         if (scrollableContainer != this)
             return scrollableContainer;
         if (renderBox.parentBox())
-            return renderBox.parentBox()->findEnclosingScrollableContainer();
+            return renderBox.parentBox()->findEnclosingScrollableContainerForSnapping();
     }
     return nullptr;
 }
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to