Title: [269622] trunk
Revision
269622
Author
commit-qu...@webkit.org
Date
2020-11-10 01:28:40 -0800 (Tue, 10 Nov 2020)

Log Message

Scroll-snap on the root aligns to the body margin edge, not the viewport edge
https://bugs.webkit.org/show_bug.cgi?id=210476
<rdar://problem/61755103>

Patch by Martin Robinson <mrobin...@igalia.com> on 2020-11-10
Reviewed by Simon Fraser.

Source/WebCore:

When passing the frame viewport to updateSnapOffsetsForScrollableArea, be sure to put it
into the coordinate system of the root element padding box. This means offsetting it by the
margins of the root element.

Tests: tiled-drawing/scrolling/scroll-snap/scroll-snap-mandatory-mainframe-horizontal-with-margin.html
       tiled-drawing/scrolling/scroll-snap/scroll-snap-mandatory-mainframe-vertical-with-margin.html

* page/FrameView.cpp:
(WebCore::FrameView::updateSnapOffsets): Offset viewport by top and left margins of the
root element.

LayoutTests:

Added tests for new behavior.

* tiled-drawing/scrolling/scroll-snap/scroll-snap-mandatory-mainframe-horizontal-with-margin-expected.txt: Added.
* tiled-drawing/scrolling/scroll-snap/scroll-snap-mandatory-mainframe-horizontal-with-margin.html: Added.
* tiled-drawing/scrolling/scroll-snap/scroll-snap-mandatory-mainframe-vertical-with-margin-expected.txt: Added.
* tiled-drawing/scrolling/scroll-snap/scroll-snap-mandatory-mainframe-vertical-with-margin.html: Added.

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (269621 => 269622)


--- trunk/LayoutTests/ChangeLog	2020-11-10 09:05:17 UTC (rev 269621)
+++ trunk/LayoutTests/ChangeLog	2020-11-10 09:28:40 UTC (rev 269622)
@@ -1,3 +1,18 @@
+2020-11-10  Martin Robinson  <mrobin...@igalia.com>
+
+        Scroll-snap on the root aligns to the body margin edge, not the viewport edge
+        https://bugs.webkit.org/show_bug.cgi?id=210476
+        <rdar://problem/61755103>
+
+        Reviewed by Simon Fraser.
+
+        Added tests for new behavior.
+
+        * tiled-drawing/scrolling/scroll-snap/scroll-snap-mandatory-mainframe-horizontal-with-margin-expected.txt: Added.
+        * tiled-drawing/scrolling/scroll-snap/scroll-snap-mandatory-mainframe-horizontal-with-margin.html: Added.
+        * tiled-drawing/scrolling/scroll-snap/scroll-snap-mandatory-mainframe-vertical-with-margin-expected.txt: Added.
+        * tiled-drawing/scrolling/scroll-snap/scroll-snap-mandatory-mainframe-vertical-with-margin.html: Added.
+
 2020-11-09  Chris Dumez  <cdu...@apple.com>
 
         Unexpose obsolete HTMLAppletElement interface

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


--- trunk/LayoutTests/tiled-drawing/scrolling/scroll-snap/scroll-snap-mandatory-mainframe-horizontal-with-margin-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/tiled-drawing/scrolling/scroll-snap/scroll-snap-mandatory-mainframe-horizontal-with-margin-expected.txt	2020-11-10 09:28:40 UTC (rev 269622)
@@ -0,0 +1,6 @@
+PASS div scrolled to next window.
+PASS div honored snap points.
+PASS successfullyParsed is true
+
+TEST COMPLETE
+

Added: trunk/LayoutTests/tiled-drawing/scrolling/scroll-snap/scroll-snap-mandatory-mainframe-horizontal-with-margin.html (0 => 269622)


--- trunk/LayoutTests/tiled-drawing/scrolling/scroll-snap/scroll-snap-mandatory-mainframe-horizontal-with-margin.html	                        (rev 0)
+++ trunk/LayoutTests/tiled-drawing/scrolling/scroll-snap/scroll-snap-mandatory-mainframe-horizontal-with-margin.html	2020-11-10 09:28:40 UTC (rev 269622)
@@ -0,0 +1,120 @@
+<!DOCTYPE HTML>
+<html>
+    <head>
+        <style>
+            html {
+                scroll-snap-type: x mandatory;
+                margin-left: 50px;
+                /* There's a different value for the right margin to ensure that
+                   margins with different sizes are properly tested. */
+                margin-right: 100px;
+            }
+            .horizontalGallery {
+                width: 600vw;
+                height: 100vh;
+                margin: 0;
+                padding: 0;
+            }
+            .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, which should be the width
+            // of the first div plus the root element's left margin (50 pixels).
+            if (targetScroller.scrollLeft == window.innerWidth + 50)
+                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>To run this test manually, scroll the page horizontally. The page should "
+                    + "alternate between uniform colors which fill the view.<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>

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


--- trunk/LayoutTests/tiled-drawing/scrolling/scroll-snap/scroll-snap-mandatory-mainframe-vertical-with-margin-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/tiled-drawing/scrolling/scroll-snap/scroll-snap-mandatory-mainframe-vertical-with-margin-expected.txt	2020-11-10 09:28:40 UTC (rev 269622)
@@ -0,0 +1,6 @@
+PASS div scrolled to next window.
+PASS div honored snap points.
+PASS successfullyParsed is true
+
+TEST COMPLETE
+

Added: trunk/LayoutTests/tiled-drawing/scrolling/scroll-snap/scroll-snap-mandatory-mainframe-vertical-with-margin.html (0 => 269622)


--- trunk/LayoutTests/tiled-drawing/scrolling/scroll-snap/scroll-snap-mandatory-mainframe-vertical-with-margin.html	                        (rev 0)
+++ trunk/LayoutTests/tiled-drawing/scrolling/scroll-snap/scroll-snap-mandatory-mainframe-vertical-with-margin.html	2020-11-10 09:28:40 UTC (rev 269622)
@@ -0,0 +1,120 @@
+<!DOCTYPE HTML>
+<html>
+    <head>
+        <style>
+            html {
+                scroll-snap-type: y mandatory;
+                margin-top: 50px;
+                /* There's a different value for the bottom margin to ensure that
+                   margins with different sizes are properly tested. */
+                margin-bottom: 100px;
+            }
+            .verticalGallery {
+                width: 100vw;
+                height: 600vh;
+                margin: 0;
+                padding: 0;
+            }
+            .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, which should be the height
+            // of the first div plus the root element's top margin (50 pixels).
+            if (scrollingTarget.scrollTop == window.innerHeight + 50)
+                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>To run this test manually, scroll the page vertically. The page should "
+                    + "alternate between uniform colors which fill the view.<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/Source/WebCore/ChangeLog (269621 => 269622)


--- trunk/Source/WebCore/ChangeLog	2020-11-10 09:05:17 UTC (rev 269621)
+++ trunk/Source/WebCore/ChangeLog	2020-11-10 09:28:40 UTC (rev 269622)
@@ -1,3 +1,22 @@
+2020-11-10  Martin Robinson  <mrobin...@igalia.com>
+
+        Scroll-snap on the root aligns to the body margin edge, not the viewport edge
+        https://bugs.webkit.org/show_bug.cgi?id=210476
+        <rdar://problem/61755103>
+
+        Reviewed by Simon Fraser.
+
+        When passing the frame viewport to updateSnapOffsetsForScrollableArea, be sure to put it
+        into the coordinate system of the root element padding box. This means offsetting it by the
+        margins of the root element.
+
+        Tests: tiled-drawing/scrolling/scroll-snap/scroll-snap-mandatory-mainframe-horizontal-with-margin.html
+               tiled-drawing/scrolling/scroll-snap/scroll-snap-mandatory-mainframe-vertical-with-margin.html
+
+        * page/FrameView.cpp:
+        (WebCore::FrameView::updateSnapOffsets): Offset viewport by top and left margins of the
+        root element.
+
 2020-11-09  Tim Horton  <timothy_hor...@apple.com>
 
         Exceptions under PlatformCALayerCocoa::drawLayerContents with DisplayList-backed layers

Modified: trunk/Source/WebCore/page/FrameView.cpp (269621 => 269622)


--- trunk/Source/WebCore/page/FrameView.cpp	2020-11-10 09:05:17 UTC (rev 269621)
+++ trunk/Source/WebCore/page/FrameView.cpp	2020-11-10 09:28:40 UTC (rev 269622)
@@ -941,7 +941,13 @@
         return;
     }
 
+    // updateSnapOffsetsForScrollableArea calculates scroll offsets with all rectangles having their origin at the
+    // padding box rectangle of the scrollable element. Unlike for overflow:scroll, the FrameView viewport includes
+    // the root element margins. This means that we need to offset the viewport rectangle to make it relative to
+    // the padding box of the root element.
     LayoutRect viewport = LayoutRect(IntPoint(), baseLayoutViewportSize());
+    viewport.move(-rootRenderer->marginLeft(), -rootRenderer->marginTop());
+
     updateSnapOffsetsForScrollableArea(*this, *rootRenderer, *styleToUse, viewport);
 }
 
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to