Title: [246367] trunk
Revision
246367
Author
[email protected]
Date
2019-06-12 11:27:35 -0700 (Wed, 12 Jun 2019)

Log Message

(Async scrolling) Handle 'position:fixed' inside 'position:sticky' correctly.
https://bugs.webkit.org/show_bug.cgi?id=198788
<rdar://problem/51589759>

Reviewed by Simon Fraser.

Source/WebCore:

Handle 'position:fixed' inside 'position:sticky' correctly.

Also fix nested 'position:fixed' in case where there is an overflow scroller between them.

Tests: scrollingcoordinator/ios/fixed-inside-overflow-inside-fixed.html
       scrollingcoordinator/ios/fixed-inside-sticky-frame.html
       scrollingcoordinator/ios/fixed-inside-sticky-no-stacking-context-2.html
       scrollingcoordinator/ios/fixed-inside-sticky-no-stacking-context.html
       scrollingcoordinator/ios/fixed-inside-sticky-stacking-context.html

* page/scrolling/cocoa/ScrollingTreeFixedNode.mm:
(WebCore::ScrollingTreeFixedNode::applyLayerPositions):

Take offsets from sticky nodes into account.

* page/scrolling/cocoa/ScrollingTreeStickyNode.h:
(WebCore::ScrollingTreeStickyNode::layer):
* page/scrolling/cocoa/ScrollingTreeStickyNode.mm:
(WebCore::ScrollingTreeStickyNode::computeLayerPosition const):

Factor into a function.

(WebCore::ScrollingTreeStickyNode::applyLayerPositions):
(WebCore::ScrollingTreeStickyNode::scrollDeltaSinceLastCommit const):
* rendering/RenderLayerCompositor.cpp:
(WebCore::RenderLayerCompositor::isViewportConstrainedFixedOrStickyLayer const):

We need to generate a scrolling tree node for position:fixed in nested case if there is an overflow scroller
between the layers.

LayoutTests:

* scrollingcoordinator/ios/fixed-inside-overflow-inside-fixed-expected.html: Added.
* scrollingcoordinator/ios/fixed-inside-overflow-inside-fixed.html: Added.
* scrollingcoordinator/ios/fixed-inside-sticky-frame-expected.html: Added.
* scrollingcoordinator/ios/fixed-inside-sticky-frame.html: Added.
* scrollingcoordinator/ios/fixed-inside-sticky-no-stacking-context-2-expected.html: Added.
* scrollingcoordinator/ios/fixed-inside-sticky-no-stacking-context-2.html: Added.
* scrollingcoordinator/ios/fixed-inside-sticky-no-stacking-context-expected.html: Added.
* scrollingcoordinator/ios/fixed-inside-sticky-no-stacking-context.html: Added.
* scrollingcoordinator/ios/fixed-inside-sticky-stacking-context-expected.html: Added.
* scrollingcoordinator/ios/fixed-inside-sticky-stacking-context.html: Added.

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (246366 => 246367)


--- trunk/LayoutTests/ChangeLog	2019-06-12 18:17:26 UTC (rev 246366)
+++ trunk/LayoutTests/ChangeLog	2019-06-12 18:27:35 UTC (rev 246367)
@@ -1,3 +1,22 @@
+2019-06-12  Antti Koivisto  <[email protected]>
+
+        (Async scrolling) Handle 'position:fixed' inside 'position:sticky' correctly.
+        https://bugs.webkit.org/show_bug.cgi?id=198788
+        <rdar://problem/51589759>
+
+        Reviewed by Simon Fraser.
+
+        * scrollingcoordinator/ios/fixed-inside-overflow-inside-fixed-expected.html: Added.
+        * scrollingcoordinator/ios/fixed-inside-overflow-inside-fixed.html: Added.
+        * scrollingcoordinator/ios/fixed-inside-sticky-frame-expected.html: Added.
+        * scrollingcoordinator/ios/fixed-inside-sticky-frame.html: Added.
+        * scrollingcoordinator/ios/fixed-inside-sticky-no-stacking-context-2-expected.html: Added.
+        * scrollingcoordinator/ios/fixed-inside-sticky-no-stacking-context-2.html: Added.
+        * scrollingcoordinator/ios/fixed-inside-sticky-no-stacking-context-expected.html: Added.
+        * scrollingcoordinator/ios/fixed-inside-sticky-no-stacking-context.html: Added.
+        * scrollingcoordinator/ios/fixed-inside-sticky-stacking-context-expected.html: Added.
+        * scrollingcoordinator/ios/fixed-inside-sticky-stacking-context.html: Added.
+
 2019-06-12  Youenn Fablet  <[email protected]>
 
         Update WPT service workers test up to 0df7c68

Added: trunk/LayoutTests/scrollingcoordinator/ios/fixed-inside-overflow-inside-fixed-expected.html (0 => 246367)


--- trunk/LayoutTests/scrollingcoordinator/ios/fixed-inside-overflow-inside-fixed-expected.html	                        (rev 0)
+++ trunk/LayoutTests/scrollingcoordinator/ios/fixed-inside-overflow-inside-fixed-expected.html	2019-06-12 18:27:35 UTC (rev 246367)
@@ -0,0 +1,71 @@
+<!DOCTYPE html> <!-- webkit-test-runner [ useFlexibleViewport=true internal:AsyncOverflowScrollingEnabled=true internal:AsyncFrameScrollingEnabled=true ] -->
+<html>
+<head>
+    <meta name="viewport" content="initial-scale=1.0">
+    <style>
+        .scroller {
+            margin: 10px;
+            height: 300px;
+            width: 300px;
+            border: 1px solid black;
+            overflow: scroll;
+            z-index: 0;
+            position: relative;
+        }
+        
+        .fixed-outer {
+            position: fixed;
+            top: 0px;
+            width: 200px;
+            height: 200px;
+            background-color: green;
+        }
+
+        .fixed {
+            position: fixed;
+            top: 100px;
+            left: 100px;
+            width: 50px;
+            height: 50px;
+            background-color: blue;
+        }
+
+        .container {
+            margin: 40px;
+            border: 2px solid red;
+            height: 5000px;
+        }
+    </style>
+    <script src=""
+    <script>
+        if (window.testRunner)
+            testRunner.waitUntilDone();
+
+        async function doTest()
+        {
+            if (!window.testRunner)
+                return;
+
+            if (!testRunner.runUIScript)
+                return;
+
+            await UIHelper.ensurePresentationUpdate();
+            document.querySelector('.scroller').scrollTo(0, 200);
+            await UIHelper.ensurePresentationUpdate();
+            testRunner.notifyDone();
+        }
+        
+        window.addEventListener('load', doTest, false);
+    </script>
+</head>
+<body>
+    <div class="fixed-outer">
+        <div class="scroller">
+            <div class="container">
+                <div class="fixed">
+                </div>
+            </div>
+        </div>
+    </div>
+</body>
+</html>

Added: trunk/LayoutTests/scrollingcoordinator/ios/fixed-inside-overflow-inside-fixed.html (0 => 246367)


--- trunk/LayoutTests/scrollingcoordinator/ios/fixed-inside-overflow-inside-fixed.html	                        (rev 0)
+++ trunk/LayoutTests/scrollingcoordinator/ios/fixed-inside-overflow-inside-fixed.html	2019-06-12 18:27:35 UTC (rev 246367)
@@ -0,0 +1,70 @@
+<!DOCTYPE html> <!-- webkit-test-runner [ useFlexibleViewport=true internal:AsyncOverflowScrollingEnabled=true internal:AsyncFrameScrollingEnabled=true ] -->
+<html>
+<head>
+    <meta name="viewport" content="initial-scale=1.0">
+    <style>
+        .scroller {
+            margin: 10px;
+            height: 300px;
+            width: 300px;
+            border: 1px solid black;
+            overflow: scroll;
+            z-index: 0;
+            position: relative;
+        }
+        
+        .fixed-outer {
+            position: fixed;
+            top: 0px;
+            width: 200px;
+            height: 200px;
+            background-color: green;
+        }
+
+        .fixed {
+            position: fixed;
+            top: 100px;
+            left: 100px;
+            width: 50px;
+            height: 50px;
+            background-color: blue;
+        }
+
+        .container {
+            margin: 40px;
+            border: 2px solid red;
+            height: 5000px;
+        }
+    </style>
+    <script src=""
+    <script>
+        if (window.testRunner)
+            testRunner.waitUntilDone();
+
+        async function doTest()
+        {
+            if (!window.testRunner)
+                return;
+
+            if (!testRunner.runUIScript)
+                return;
+
+            const scrollUpdatesDisabled = true;
+            await UIHelper.immediateScrollElementAtContentPointToOffset(50, 50, 0, 200, scrollUpdatesDisabled);
+            testRunner.notifyDone();
+        }
+        
+        window.addEventListener('load', doTest, false);
+    </script>
+</head>
+<body>
+    <div class="fixed-outer">
+        <div class="scroller">
+            <div class="container">
+                <div class="fixed">
+                </div>
+            </div>
+        </div>
+    </div>
+</body>
+</html>

Added: trunk/LayoutTests/scrollingcoordinator/ios/fixed-inside-sticky-frame-expected.html (0 => 246367)


--- trunk/LayoutTests/scrollingcoordinator/ios/fixed-inside-sticky-frame-expected.html	                        (rev 0)
+++ trunk/LayoutTests/scrollingcoordinator/ios/fixed-inside-sticky-frame-expected.html	2019-06-12 18:27:35 UTC (rev 246367)
@@ -0,0 +1,70 @@
+<!DOCTYPE html> <!-- webkit-test-runner [ useFlexibleViewport=true internal:AsyncOverflowScrollingEnabled=true internal:AsyncFrameScrollingEnabled=true ] -->
+<html>
+<head>
+    <meta name="viewport" content="initial-scale=1.0">
+    <style>
+        .scroller {
+            margin: 10px;
+            height: 300px;
+            width: 300px;
+            border: 1px solid black;
+            overflow: scroll;
+            z-index: 0;
+            position: relative;
+        }
+        
+        .sticky {
+            position: -webkit-sticky;
+            top: 0px;
+            width: 200px;
+            height: 200px;
+            background-color: green;
+        }
+
+        .fixed {
+            position: fixed;
+            top: 100px;
+            left: 100px;
+            width: 50px;
+            height: 50px;
+            background-color: blue;
+        }
+
+        .container {
+            margin: 40px;
+            border: 2px solid red;
+            height: 5000px;
+        }
+    </style>
+    <script src=""
+    <script>
+        if (window.testRunner)
+            testRunner.waitUntilDone();
+
+        async function doTest()
+        {
+            if (!window.testRunner)
+                return;
+
+            if (!testRunner.runUIScript)
+                return;
+
+            await UIHelper.ensurePresentationUpdate();
+            window.scrollTo(0, 200);
+            await UIHelper.ensurePresentationUpdate();
+
+            testRunner.notifyDone();
+        }
+        
+        window.addEventListener('load', doTest, false);
+    </script>
+</head>
+<body>
+    <div class="container">
+        <div class="sticky">
+            <div class="fixed">
+            </div>
+        </div>
+    </div>
+</body>
+</html>

Added: trunk/LayoutTests/scrollingcoordinator/ios/fixed-inside-sticky-frame.html (0 => 246367)


--- trunk/LayoutTests/scrollingcoordinator/ios/fixed-inside-sticky-frame.html	                        (rev 0)
+++ trunk/LayoutTests/scrollingcoordinator/ios/fixed-inside-sticky-frame.html	2019-06-12 18:27:35 UTC (rev 246367)
@@ -0,0 +1,68 @@
+<!DOCTYPE html> <!-- webkit-test-runner [ useFlexibleViewport=true internal:AsyncOverflowScrollingEnabled=true internal:AsyncFrameScrollingEnabled=true ] -->
+<html>
+<head>
+    <meta name="viewport" content="initial-scale=1.0">
+    <style>
+        .scroller {
+            margin: 10px;
+            height: 300px;
+            width: 300px;
+            border: 1px solid black;
+            overflow: scroll;
+            z-index: 0;
+            position: relative;
+        }
+        
+        .sticky {
+            position: -webkit-sticky;
+            top: 0px;
+            width: 200px;
+            height: 200px;
+            background-color: green;
+        }
+
+        .fixed {
+            position: fixed;
+            top: 100px;
+            left: 100px;
+            width: 50px;
+            height: 50px;
+            background-color: blue;
+        }
+
+        .container {
+            margin: 40px;
+            border: 2px solid red;
+            height: 5000px;
+        }
+    </style>
+    <script src=""
+    <script>
+        if (window.testRunner)
+            testRunner.waitUntilDone();
+
+        async function doTest()
+        {
+            if (!window.testRunner)
+                return;
+
+            if (!testRunner.runUIScript)
+                return;
+
+            const scrollUpdatesDisabled = true;
+            await UIHelper.immediateScrollElementAtContentPointToOffset(50, 50, 0, 200, scrollUpdatesDisabled);
+            testRunner.notifyDone();
+        }
+        
+        window.addEventListener('load', doTest, false);
+    </script>
+</head>
+<body>
+    <div class="container">
+        <div class="sticky">
+            <div class="fixed">
+            </div>
+        </div>
+    </div>
+</body>
+</html>

Added: trunk/LayoutTests/scrollingcoordinator/ios/fixed-inside-sticky-no-stacking-context-2-expected.html (0 => 246367)


--- trunk/LayoutTests/scrollingcoordinator/ios/fixed-inside-sticky-no-stacking-context-2-expected.html	                        (rev 0)
+++ trunk/LayoutTests/scrollingcoordinator/ios/fixed-inside-sticky-no-stacking-context-2-expected.html	2019-06-12 18:27:35 UTC (rev 246367)
@@ -0,0 +1,71 @@
+<!DOCTYPE html> <!-- webkit-test-runner [ useFlexibleViewport=true internal:AsyncOverflowScrollingEnabled=true internal:AsyncFrameScrollingEnabled=true ] -->
+<html>
+<head>
+    <meta name="viewport" content="initial-scale=1.0">
+    <style>
+        .scroller {
+            margin: 10px;
+            height: 300px;
+            width: 300px;
+            border: 1px solid black;
+            overflow: scroll;
+            position: relative;
+        }
+        
+        .sticky {
+            position: -webkit-sticky;
+            top: 0px;
+            width: 200px;
+            height: 200px;
+            background-color: green;
+        }
+
+        .fixed {
+            position: fixed;
+            top: 100px;
+            left: 100px;
+            width: 50px;
+            height: 50px;
+            background-color: blue;
+        }
+
+        .container {
+            margin: 40px;
+            border: 2px solid red;
+            height: 5000px;
+            will-change: transform;
+        }
+    </style>
+    <script src=""
+    <script>
+        if (window.testRunner)
+            testRunner.waitUntilDone();
+
+        async function doTest()
+        {
+            if (!window.testRunner)
+                return;
+
+            if (!testRunner.runUIScript)
+                return;
+
+            await UIHelper.ensurePresentationUpdate();
+            document.querySelector('.scroller').scrollTo(0, 200);
+            await UIHelper.ensurePresentationUpdate();
+            testRunner.notifyDone();
+        }
+        
+        window.addEventListener('load', doTest, false);
+    </script>
+</head>
+<body>
+    <div class="scroller">
+        <div class="container">
+            <div class="sticky">
+                <div class="fixed">
+                </div>
+            </div>
+        </div>
+    </div>
+</body>
+</html>

Added: trunk/LayoutTests/scrollingcoordinator/ios/fixed-inside-sticky-no-stacking-context-2.html (0 => 246367)


--- trunk/LayoutTests/scrollingcoordinator/ios/fixed-inside-sticky-no-stacking-context-2.html	                        (rev 0)
+++ trunk/LayoutTests/scrollingcoordinator/ios/fixed-inside-sticky-no-stacking-context-2.html	2019-06-12 18:27:35 UTC (rev 246367)
@@ -0,0 +1,70 @@
+<!DOCTYPE html> <!-- webkit-test-runner [ useFlexibleViewport=true internal:AsyncOverflowScrollingEnabled=true internal:AsyncFrameScrollingEnabled=true ] -->
+<html>
+<head>
+    <meta name="viewport" content="initial-scale=1.0">
+    <style>
+        .scroller {
+            margin: 10px;
+            height: 300px;
+            width: 300px;
+            border: 1px solid black;
+            overflow: scroll;
+            position: relative;
+        }
+        
+        .sticky {
+            position: -webkit-sticky;
+            top: 0px;
+            width: 200px;
+            height: 200px;
+            background-color: green;
+        }
+
+        .fixed {
+            position: fixed;
+            top: 100px;
+            left: 100px;
+            width: 50px;
+            height: 50px;
+            background-color: blue;
+        }
+
+        .container {
+            margin: 40px;
+            border: 2px solid red;
+            height: 5000px;
+            will-change: transform;
+        }
+    </style>
+    <script src=""
+    <script>
+        if (window.testRunner)
+            testRunner.waitUntilDone();
+
+        async function doTest()
+        {
+            if (!window.testRunner)
+                return;
+
+            if (!testRunner.runUIScript)
+                return;
+
+            const scrollUpdatesDisabled = true;
+            await UIHelper.immediateScrollElementAtContentPointToOffset(50, 50, 0, 200, scrollUpdatesDisabled);
+            testRunner.notifyDone();
+        }
+        
+        window.addEventListener('load', doTest, false);
+    </script>
+</head>
+<body>
+    <div class="scroller">
+        <div class="container">
+            <div class="sticky">
+                <div class="fixed">
+                </div>
+            </div>
+        </div>
+    </div>
+</body>
+</html>

Added: trunk/LayoutTests/scrollingcoordinator/ios/fixed-inside-sticky-no-stacking-context-expected.html (0 => 246367)


--- trunk/LayoutTests/scrollingcoordinator/ios/fixed-inside-sticky-no-stacking-context-expected.html	                        (rev 0)
+++ trunk/LayoutTests/scrollingcoordinator/ios/fixed-inside-sticky-no-stacking-context-expected.html	2019-06-12 18:27:35 UTC (rev 246367)
@@ -0,0 +1,71 @@
+<!DOCTYPE html> <!-- webkit-test-runner [ useFlexibleViewport=true internal:AsyncOverflowScrollingEnabled=true internal:AsyncFrameScrollingEnabled=true ] -->
+<html>
+<head>
+    <meta name="viewport" content="initial-scale=1.0">
+    <style>
+        .scroller {
+            margin: 10px;
+            height: 300px;
+            width: 300px;
+            border: 1px solid black;
+            overflow: scroll;
+            position: relative;
+        }
+        
+        .sticky {
+            position: -webkit-sticky;
+            top: 0px;
+            width: 200px;
+            height: 200px;
+            background-color: green;
+        }
+
+        .fixed {
+            position: fixed;
+            top: 100px;
+            left: 100px;
+            width: 50px;
+            height: 50px;
+            background-color: blue;
+        }
+
+        .container {
+            margin: 40px;
+            border: 2px solid red;
+            height: 5000px;
+        }
+    </style>
+    <script src=""
+    <script>
+        if (window.testRunner)
+            testRunner.waitUntilDone();
+
+        async function doTest()
+        {
+            if (!window.testRunner)
+                return;
+
+            if (!testRunner.runUIScript)
+                return;
+
+            await UIHelper.ensurePresentationUpdate();
+            document.querySelector('.scroller').scrollTo(0, 200);
+            await UIHelper.ensurePresentationUpdate();
+
+            testRunner.notifyDone();
+        }
+        
+        window.addEventListener('load', doTest, false);
+    </script>
+</head>
+<body>
+    <div class="scroller">
+        <div class="container">
+            <div class="sticky">
+                <div class="fixed">
+                </div>
+            </div>
+        </div>
+    </div>
+</body>
+</html>

Added: trunk/LayoutTests/scrollingcoordinator/ios/fixed-inside-sticky-no-stacking-context.html (0 => 246367)


--- trunk/LayoutTests/scrollingcoordinator/ios/fixed-inside-sticky-no-stacking-context.html	                        (rev 0)
+++ trunk/LayoutTests/scrollingcoordinator/ios/fixed-inside-sticky-no-stacking-context.html	2019-06-12 18:27:35 UTC (rev 246367)
@@ -0,0 +1,69 @@
+<!DOCTYPE html> <!-- webkit-test-runner [ useFlexibleViewport=true internal:AsyncOverflowScrollingEnabled=true internal:AsyncFrameScrollingEnabled=true ] -->
+<html>
+<head>
+    <meta name="viewport" content="initial-scale=1.0">
+    <style>
+        .scroller {
+            margin: 10px;
+            height: 300px;
+            width: 300px;
+            border: 1px solid black;
+            overflow: scroll;
+            position: relative;
+        }
+        
+        .sticky {
+            position: -webkit-sticky;
+            top: 0px;
+            width: 200px;
+            height: 200px;
+            background-color: green;
+        }
+
+        .fixed {
+            position: fixed;
+            top: 100px;
+            left: 100px;
+            width: 50px;
+            height: 50px;
+            background-color: blue;
+        }
+
+        .container {
+            margin: 40px;
+            border: 2px solid red;
+            height: 5000px;
+        }
+    </style>
+    <script src=""
+    <script>
+        if (window.testRunner)
+            testRunner.waitUntilDone();
+
+        async function doTest()
+        {
+            if (!window.testRunner)
+                return;
+
+            if (!testRunner.runUIScript)
+                return;
+
+            const scrollUpdatesDisabled = true;
+            await UIHelper.immediateScrollElementAtContentPointToOffset(50, 50, 0, 200, scrollUpdatesDisabled);
+            testRunner.notifyDone();
+        }
+        
+        window.addEventListener('load', doTest, false);
+    </script>
+</head>
+<body>
+    <div class="scroller">
+        <div class="container">
+            <div class="sticky">
+                <div class="fixed">
+                </div>
+            </div>
+        </div>
+    </div>
+</body>
+</html>

Added: trunk/LayoutTests/scrollingcoordinator/ios/fixed-inside-sticky-stacking-context-expected.html (0 => 246367)


--- trunk/LayoutTests/scrollingcoordinator/ios/fixed-inside-sticky-stacking-context-expected.html	                        (rev 0)
+++ trunk/LayoutTests/scrollingcoordinator/ios/fixed-inside-sticky-stacking-context-expected.html	2019-06-12 18:27:35 UTC (rev 246367)
@@ -0,0 +1,71 @@
+<!DOCTYPE html> <!-- webkit-test-runner [ useFlexibleViewport=true internal:AsyncOverflowScrollingEnabled=true internal:AsyncFrameScrollingEnabled=true ] -->
+<html>
+<head>
+    <meta name="viewport" content="initial-scale=1.0">
+    <style>
+        .scroller {
+            margin: 10px;
+            height: 300px;
+            width: 300px;
+            border: 1px solid black;
+            overflow: scroll;
+            z-index: 0;
+            position: relative;
+        }
+        
+        .sticky {
+            position: -webkit-sticky;
+            top: 0px;
+            width: 200px;
+            height: 200px;
+            background-color: green;
+        }
+
+        .fixed {
+            position: fixed;
+            top: 100px;
+            left: 100px;
+            width: 50px;
+            height: 50px;
+            background-color: blue;
+        }
+
+        .container {
+            margin: 40px;
+            border: 2px solid red;
+            height: 5000px;
+        }
+    </style>
+    <script src=""
+    <script>
+        if (window.testRunner)
+            testRunner.waitUntilDone();
+
+        async function doTest()
+        {
+            if (!window.testRunner)
+                return;
+
+            if (!testRunner.runUIScript)
+                return;
+
+            await UIHelper.ensurePresentationUpdate();
+            document.querySelector('.scroller').scrollTo(0, 200);
+            await UIHelper.ensurePresentationUpdate();
+            testRunner.notifyDone();
+        }
+        
+        window.addEventListener('load', doTest, false);
+    </script>
+</head>
+<body>
+    <div class="scroller">
+        <div class="container">
+            <div class="sticky">
+                <div class="fixed">
+                </div>
+            </div>
+        </div>
+    </div>
+</body>
+</html>

Added: trunk/LayoutTests/scrollingcoordinator/ios/fixed-inside-sticky-stacking-context.html (0 => 246367)


--- trunk/LayoutTests/scrollingcoordinator/ios/fixed-inside-sticky-stacking-context.html	                        (rev 0)
+++ trunk/LayoutTests/scrollingcoordinator/ios/fixed-inside-sticky-stacking-context.html	2019-06-12 18:27:35 UTC (rev 246367)
@@ -0,0 +1,70 @@
+<!DOCTYPE html> <!-- webkit-test-runner [ useFlexibleViewport=true internal:AsyncOverflowScrollingEnabled=true internal:AsyncFrameScrollingEnabled=true ] -->
+<html>
+<head>
+    <meta name="viewport" content="initial-scale=1.0">
+    <style>
+        .scroller {
+            margin: 10px;
+            height: 300px;
+            width: 300px;
+            border: 1px solid black;
+            overflow: scroll;
+            z-index: 0;
+            position: relative;
+        }
+        
+        .sticky {
+            position: -webkit-sticky;
+            top: 0px;
+            width: 200px;
+            height: 200px;
+            background-color: green;
+        }
+
+        .fixed {
+            position: fixed;
+            top: 100px;
+            left: 100px;
+            width: 50px;
+            height: 50px;
+            background-color: blue;
+        }
+
+        .container {
+            margin: 40px;
+            border: 2px solid red;
+            height: 5000px;
+        }
+    </style>
+    <script src=""
+    <script>
+        if (window.testRunner)
+            testRunner.waitUntilDone();
+
+        async function doTest()
+        {
+            if (!window.testRunner)
+                return;
+
+            if (!testRunner.runUIScript)
+                return;
+
+            const scrollUpdatesDisabled = true;
+            await UIHelper.immediateScrollElementAtContentPointToOffset(50, 50, 0, 200, scrollUpdatesDisabled);
+            testRunner.notifyDone();
+        }
+        
+        window.addEventListener('load', doTest, false);
+    </script>
+</head>
+<body>
+    <div class="scroller">
+        <div class="container">
+            <div class="sticky">
+                <div class="fixed">
+                </div>
+            </div>
+        </div>
+    </div>
+</body>
+</html>

Modified: trunk/Source/WebCore/ChangeLog (246366 => 246367)


--- trunk/Source/WebCore/ChangeLog	2019-06-12 18:17:26 UTC (rev 246366)
+++ trunk/Source/WebCore/ChangeLog	2019-06-12 18:27:35 UTC (rev 246367)
@@ -1,3 +1,41 @@
+2019-06-12  Antti Koivisto  <[email protected]>
+
+        (Async scrolling) Handle 'position:fixed' inside 'position:sticky' correctly.
+        https://bugs.webkit.org/show_bug.cgi?id=198788
+        <rdar://problem/51589759>
+
+        Reviewed by Simon Fraser.
+
+        Handle 'position:fixed' inside 'position:sticky' correctly.
+
+        Also fix nested 'position:fixed' in case where there is an overflow scroller between them.
+
+        Tests: scrollingcoordinator/ios/fixed-inside-overflow-inside-fixed.html
+               scrollingcoordinator/ios/fixed-inside-sticky-frame.html
+               scrollingcoordinator/ios/fixed-inside-sticky-no-stacking-context-2.html
+               scrollingcoordinator/ios/fixed-inside-sticky-no-stacking-context.html
+               scrollingcoordinator/ios/fixed-inside-sticky-stacking-context.html
+
+        * page/scrolling/cocoa/ScrollingTreeFixedNode.mm:
+        (WebCore::ScrollingTreeFixedNode::applyLayerPositions):
+
+        Take offsets from sticky nodes into account.
+
+        * page/scrolling/cocoa/ScrollingTreeStickyNode.h:
+        (WebCore::ScrollingTreeStickyNode::layer):
+        * page/scrolling/cocoa/ScrollingTreeStickyNode.mm:
+        (WebCore::ScrollingTreeStickyNode::computeLayerPosition const):
+
+        Factor into a function.
+
+        (WebCore::ScrollingTreeStickyNode::applyLayerPositions):
+        (WebCore::ScrollingTreeStickyNode::scrollDeltaSinceLastCommit const):
+        * rendering/RenderLayerCompositor.cpp:
+        (WebCore::RenderLayerCompositor::isViewportConstrainedFixedOrStickyLayer const):
+
+        We need to generate a scrolling tree node for position:fixed in nested case if there is an overflow scroller
+        between the layers.
+
 2019-06-12  Truitt Savell  <[email protected]>
 
         Unreviewed, rolling out r246350.

Modified: trunk/Source/WebCore/page/scrolling/cocoa/ScrollingTreeFixedNode.mm (246366 => 246367)


--- trunk/Source/WebCore/page/scrolling/cocoa/ScrollingTreeFixedNode.mm	2019-06-12 18:17:26 UTC (rev 246366)
+++ trunk/Source/WebCore/page/scrolling/cocoa/ScrollingTreeFixedNode.mm	2019-06-12 18:27:35 UTC (rev 246367)
@@ -34,6 +34,7 @@
 #import "ScrollingTreeFrameScrollingNode.h"
 #import "ScrollingTreeOverflowScrollingNode.h"
 #import "ScrollingTreePositionedNode.h"
+#import "ScrollingTreeStickyNode.h"
 #import "WebCoreCALayerExtras.h"
 #import <wtf/text/TextStream.h>
 
@@ -70,13 +71,8 @@
 {
     auto computeLayerPosition = [&] {
         FloatSize overflowScrollDelta;
+        ScrollingTreeStickyNode* lastStickyNode = nullptr;
         for (auto* ancestor = parent(); ancestor; ancestor = ancestor->parent()) {
-            if (is<ScrollingTreePositionedNode>(*ancestor)) {
-                auto& positioningAncestor = downcast<ScrollingTreePositionedNode>(*ancestor);
-                if (positioningAncestor.layer() != m_layer)
-                    overflowScrollDelta -= positioningAncestor.scrollDeltaSinceLastCommit();
-            }
-
             if (is<ScrollingTreeFrameScrollingNode>(*ancestor)) {
                 // Fixed nodes are positioned relative to the containing frame scrolling node.
                 // We bail out after finding one.
@@ -88,7 +84,31 @@
                 // To keep the layer still during async scrolling we adjust by how much the position has changed since layout.
                 auto& overflowNode = downcast<ScrollingTreeOverflowScrollingNode>(*ancestor);
                 overflowScrollDelta -= overflowNode.scrollDeltaSinceLastCommit();
+                continue;
             }
+
+            if (is<ScrollingTreePositionedNode>(*ancestor)) {
+                auto& positioningAncestor = downcast<ScrollingTreePositionedNode>(*ancestor);
+                // See if sticky node already handled this positioning node.
+                // FIXME: Include positioning node information to sticky/fixed node to avoid these tests.
+                if (lastStickyNode && lastStickyNode->layer() == positioningAncestor.layer())
+                    continue;
+                if (positioningAncestor.layer() != m_layer)
+                    overflowScrollDelta -= positioningAncestor.scrollDeltaSinceLastCommit();
+                continue;
+            }
+
+            if (is<ScrollingTreeStickyNode>(*ancestor)) {
+                auto& stickyNode = downcast<ScrollingTreeStickyNode>(*ancestor);
+                overflowScrollDelta += stickyNode.scrollDeltaSinceLastCommit();
+                lastStickyNode = &stickyNode;
+                continue;
+            }
+
+            if (is<ScrollingTreeFixedNode>(*ancestor)) {
+                // The ancestor fixed node has already applied the needed corrections to say put.
+                return m_constraints.layerPositionAtLastLayout() - overflowScrollDelta;
+            }
         }
         ASSERT_NOT_REACHED();
         return FloatPoint();

Modified: trunk/Source/WebCore/page/scrolling/cocoa/ScrollingTreeStickyNode.h (246366 => 246367)


--- trunk/Source/WebCore/page/scrolling/cocoa/ScrollingTreeStickyNode.h	2019-06-12 18:17:26 UTC (rev 246366)
+++ trunk/Source/WebCore/page/scrolling/cocoa/ScrollingTreeStickyNode.h	2019-06-12 18:27:35 UTC (rev 246367)
@@ -41,6 +41,10 @@
 
     virtual ~ScrollingTreeStickyNode();
 
+    FloatSize scrollDeltaSinceLastCommit() const;
+
+    CALayer *layer() { return m_layer.get(); }
+
 private:
     ScrollingTreeStickyNode(ScrollingTree&, ScrollingNodeID);
 
@@ -47,6 +51,8 @@
     void commitStateBeforeChildren(const ScrollingStateNode&) override;
     void applyLayerPositions() override;
 
+    FloatPoint computeLayerPosition() const;
+
     void dumpProperties(WTF::TextStream&, ScrollingStateTreeAsTextBehavior) const override;
 
     StickyPositionViewportConstraints m_constraints;

Modified: trunk/Source/WebCore/page/scrolling/cocoa/ScrollingTreeStickyNode.mm (246366 => 246367)


--- trunk/Source/WebCore/page/scrolling/cocoa/ScrollingTreeStickyNode.mm	2019-06-12 18:17:26 UTC (rev 246366)
+++ trunk/Source/WebCore/page/scrolling/cocoa/ScrollingTreeStickyNode.mm	2019-06-12 18:27:35 UTC (rev 246367)
@@ -66,7 +66,7 @@
         m_constraints = stickyStateNode.viewportConstraints();
 }
 
-void ScrollingTreeStickyNode::applyLayerPositions()
+FloatPoint ScrollingTreeStickyNode::computeLayerPosition() const
 {
     auto computeLayerPositionForScrollingNode = [&](ScrollingTreeNode& scrollingNode) {
         FloatRect constrainingRect;
@@ -80,41 +80,42 @@
         return m_constraints.layerPositionForConstrainingRect(constrainingRect);
     };
 
-    auto computeLayerPosition = [&] {
-        for (auto* ancestor = parent(); ancestor; ancestor = ancestor->parent()) {
-            if (is<ScrollingTreePositionedNode>(*ancestor)) {
-                auto& positioningAncestor = downcast<ScrollingTreePositionedNode>(*ancestor);
+    for (auto* ancestor = parent(); ancestor; ancestor = ancestor->parent()) {
+        if (is<ScrollingTreePositionedNode>(*ancestor)) {
+            auto& positioningAncestor = downcast<ScrollingTreePositionedNode>(*ancestor);
 
-                // FIXME: Do we need to do anything for ScrollPositioningBehavior::Stationary?
-                if (positioningAncestor.scrollPositioningBehavior() == ScrollPositioningBehavior::Moves) {
-                    if (positioningAncestor.relatedOverflowScrollingNodes().isEmpty())
-                        break;
-                    auto overflowNode = scrollingTree().nodeForID(positioningAncestor.relatedOverflowScrollingNodes()[0]);
-                    if (!overflowNode)
-                        break;
+            // FIXME: Do we need to do anything for ScrollPositioningBehavior::Stationary?
+            if (positioningAncestor.scrollPositioningBehavior() == ScrollPositioningBehavior::Moves) {
+                if (positioningAncestor.relatedOverflowScrollingNodes().isEmpty())
+                    break;
+                auto overflowNode = scrollingTree().nodeForID(positioningAncestor.relatedOverflowScrollingNodes()[0]);
+                if (!overflowNode)
+                    break;
 
-                    auto position = computeLayerPositionForScrollingNode(*overflowNode);
+                auto position = computeLayerPositionForScrollingNode(*overflowNode);
 
-                    if (positioningAncestor.layer() == m_layer) {
-                        // We'll also do the adjustment the positioning node would do.
-                        position -= positioningAncestor.scrollDeltaSinceLastCommit();
-                    }
-                    
-                    return position;
+                if (positioningAncestor.layer() == m_layer) {
+                    // We'll also do the adjustment the positioning node would do.
+                    position -= positioningAncestor.scrollDeltaSinceLastCommit();
                 }
-            }
-            if (is<ScrollingTreeScrollingNode>(*ancestor))
-                return computeLayerPositionForScrollingNode(*ancestor);
 
-            if (is<ScrollingTreeFixedNode>(*ancestor) || is<ScrollingTreeStickyNode>(*ancestor)) {
-                // FIXME: Do we need scrolling tree nodes at all for nested cases?
-                return m_constraints.layerPositionAtLastLayout();
+                return position;
             }
         }
-        ASSERT_NOT_REACHED();
-        return m_constraints.layerPositionAtLastLayout();
-    };
+        if (is<ScrollingTreeScrollingNode>(*ancestor))
+            return computeLayerPositionForScrollingNode(*ancestor);
 
+        if (is<ScrollingTreeFixedNode>(*ancestor) || is<ScrollingTreeStickyNode>(*ancestor)) {
+            // FIXME: Do we need scrolling tree nodes at all for nested cases?
+            return m_constraints.layerPositionAtLastLayout();
+        }
+    }
+    ASSERT_NOT_REACHED();
+    return m_constraints.layerPositionAtLastLayout();
+}
+
+void ScrollingTreeStickyNode::applyLayerPositions()
+{
     auto layerPosition = computeLayerPosition();
 
     LOG_WITH_STREAM(Scrolling, stream << "ScrollingTreeStickyNode " << scrollingNodeID() << " constrainingRectAtLastLayout " << m_constraints.constrainingRectAtLastLayout() << " last layer pos " << m_constraints.layerPositionAtLastLayout() << " layerPosition " << layerPosition);
@@ -122,6 +123,12 @@
     [m_layer _web_setLayerTopLeftPosition:layerPosition - m_constraints.alignmentOffset()];
 }
 
+FloatSize ScrollingTreeStickyNode::scrollDeltaSinceLastCommit() const
+{
+    auto layerPosition = computeLayerPosition();
+    return layerPosition - m_constraints.layerPositionAtLastLayout();
+}
+
 void ScrollingTreeStickyNode::dumpProperties(TextStream& ts, ScrollingStateTreeAsTextBehavior behavior) const
 {
     ts << "sticky node";

Modified: trunk/Source/WebCore/rendering/RenderLayerCompositor.cpp (246366 => 246367)


--- trunk/Source/WebCore/rendering/RenderLayerCompositor.cpp	2019-06-12 18:17:26 UTC (rev 246366)
+++ trunk/Source/WebCore/rendering/RenderLayerCompositor.cpp	2019-06-12 18:27:35 UTC (rev 246367)
@@ -3052,8 +3052,10 @@
         return false;
 
     // FIXME: Handle fixed inside of a transform, which should not behave as fixed.
-    for (auto* stackingContext = layer.stackingContext(); stackingContext; stackingContext = stackingContext->stackingContext()) {
-        if (stackingContext->isComposited() && stackingContext->renderer().isFixedPositioned())
+    for (auto* ancestor = layer.parent(); ancestor; ancestor = ancestor->parent()) {
+        if (ancestor->hasCompositedScrollableOverflow())
+            return true;
+        if (ancestor->isStackingContext() && ancestor->isComposited() && ancestor->renderer().isFixedPositioned())
             return false;
     }
 
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to