LayoutTests/ChangeLog

 12019-12-11 Cathie Chen <cathiechen@igalia.com>
 2
 3 Add support for scroll behavior relies on native scroll interfaces for iOS platform
 4 https://bugs.webkit.org/show_bug.cgi?id=204936
 5
 6 Reviewed by NOBODY (OOPS!).
 7
 8 Based on the patch by Frédéric Wang.
 9
 10 The scroll animation on iOS platform is using native scroll animation which need enable
 11 AsyncOverflowScrollingEnabled and AsyncFrameScrollingEnabled. In order to test properly,
 12 copy scroll-behavior test to fast/scrolling/ios/
 13
 14 * fast/scrolling/ios/resources/scroll-behavior.js: Added.
 15 (observeScrolling):
 16 (waitForScrollEnd):
 17 (scrollNode):
 18 (scrollWindow):
 19 * fast/scrolling/ios/scroll-behavior-default-css-expected.txt: Added.
 20 * fast/scrolling/ios/scroll-behavior-default-css.html: Copied from LayoutTests/imported/w3c/web-platform-tests/css/cssom-view/scroll-behavior-default-css.html.
 21 * fast/scrolling/ios/scroll-behavior-element-expected.txt: Added.
 22 * fast/scrolling/ios/scroll-behavior-element.html: Copied from LayoutTests/imported/w3c/web-platform-tests/css/cssom-view/scroll-behavior-element.html.
 23 * fast/scrolling/ios/scroll-behavior-main-frame-root-expected.txt: Added.
 24 * fast/scrolling/ios/scroll-behavior-main-frame-root.html: Copied from LayoutTests/imported/w3c/web-platform-tests/css/cssom-view/scroll-behavior-main-frame-root.html.
 25 * fast/scrolling/ios/scroll-behavior-main-frame-window-expected.txt: Added.
 26 * fast/scrolling/ios/scroll-behavior-main-frame-window.html: Copied from LayoutTests/imported/w3c/web-platform-tests/css/cssom-view/scroll-behavior-main-frame-window.html.
 27 * fast/scrolling/ios/scroll-behavior-scrollintoview-nested-expected.txt: Added.
 28 * fast/scrolling/ios/scroll-behavior-scrollintoview-nested.html: Copied from LayoutTests/imported/w3c/web-platform-tests/css/cssom-view/scroll-behavior-scrollintoview-nested.html.
 29 * fast/scrolling/ios/scroll-behavior-smooth-positions-expected.txt: Added.
 30 * fast/scrolling/ios/scroll-behavior-smooth-positions.html: Copied from LayoutTests/imported/w3c/web-platform-tests/css/cssom-view/scroll-behavior-smooth-positions.html.
 31 * fast/scrolling/ios/scroll-behavior-subframe-root-expected.txt: Added.
 32 * fast/scrolling/ios/scroll-behavior-subframe-root.html: Copied from LayoutTests/imported/w3c/web-platform-tests/css/cssom-view/scroll-behavior-subframe-root.html.
 33 * fast/scrolling/ios/scroll-behavior-subframe-window-expected.txt: Added.
 34 * fast/scrolling/ios/scroll-behavior-subframe-window.html: Copied from LayoutTests/imported/w3c/web-platform-tests/css/cssom-view/scroll-behavior-subframe-window.html.
 35
1362019-12-10 Cathie Chen <cathiechen@igalia.com>
237
338 Add support for scroll behavior relies on ScrollAnimation of the Web process

LayoutTests/fast/scrolling/ios/resources/scroll-behavior.js

 1function observeScrolling(elements, callback) {
 2 if (!Array.isArray(elements))
 3 elements = [elements];
 4 var lastChangedFrame = 0;
 5 var lastLeft = new Map();
 6 var lastTop = new Map();
 7 elements.forEach((element) => {
 8 lastLeft.set(element, element.scrollLeft);
 9 lastTop.set(element, element.scrollTop);
 10 });
 11 function tick(frames) {
 12 // We requestAnimationFrame either for 500 frames or until 20 frames with
 13 // no change have been observed.
 14 if (frames >= 500 || frames - lastChangedFrame > 20) {
 15 callback(true);
 16 } else {
 17 var scrollHappened = elements.some((element) => {
 18 return element.scrollLeft != lastLeft.get(element) || element.scrollTop != lastTop.get(element);
 19 });
 20 if (scrollHappened) {
 21 lastChangedFrame = frames;
 22 elements.forEach((element) => {
 23 lastLeft.set(element, element.scrollLeft);
 24 lastTop.set(element, element.scrollTop);
 25 });
 26 callback(false);
 27 }
 28 requestAnimationFrame(tick.bind(null, frames + 1));
 29 }
 30 }
 31 tick(0);
 32}
 33
 34function waitForScrollEnd(elements) {
 35 return new Promise((resolve) => {
 36 observeScrolling(elements, (done) => {
 37 if (done)
 38 resolve();
 39 });
 40 });
 41}
 42
 43function resetScroll(scrollingElement) {
 44 // Try various methods to ensure the element position is reset immediately.
 45 scrollingElement.scrollLeft = 0;
 46 scrollingElement.scrollTop = 0;
 47 scrollingElement.scroll({left: 0, top: 0, behavior: "instant"});
 48}
 49
 50function resetScrollForWindow(scrollingWindow) {
 51 // Try various methods to ensure the element position is reset immediately.
 52 scrollingWindow.document.scrollingElement.scrollLeft = 0;
 53 scrollingWindow.document.scrollingElement.scrollTop = 0;
 54 scrollingWindow.scroll({left: 0, top: 0, behavior: "instant"});
 55}
 56
 57function setScrollBehavior(styledElement, className) {
 58 styledElement.classList.remove("autoBehavior", "smoothBehavior");
 59 styledElement.classList.add(className);
 60}
 61
 62function scrollNode(scrollingElement, scrollFunction, behavior, elementToRevealLeft, elementToRevealTop) {
 63 var args = {};
 64 if (behavior)
 65 args.behavior = behavior;
 66 switch (scrollFunction) {
 67 case "scrollIntoView":
 68 args.inline = "start";
 69 args.block = "start";
 70 elementToReveal.scrollIntoView(args);
 71 break;
 72 default:
 73 args.left = elementToRevealLeft;
 74 args.top = elementToRevealTop;
 75 scrollingElement[scrollFunction](args);
 76 break;
 77 }
 78}
 79
 80function scrollWindow(scrollingWindow, scrollFunction, behavior, elementToRevealLeft, elementToRevealTop) {
 81 var args = {};
 82 if (behavior)
 83 args.behavior = behavior;
 84 args.left = elementToRevealLeft;
 85 args.top = elementToRevealTop;
 86 scrollingWindow[scrollFunction](args);
 87}

LayoutTests/fast/scrolling/ios/scroll-behavior-default-css-expected.txt

 1
 2PASS Instant scrolling of an element with default scroll-behavior
 3PASS Smooth scrolling of an element with default scroll-behavior
 4

LayoutTests/fast/scrolling/ios/scroll-behavior-default-css.html

 1<!DOCTYPE html><!-- webkit-test-runner [ experimental:CSSOMViewSmoothScrollingEnabled=true internal:AsyncOverflowScrollingEnabled=true ] -->
 2<title>Testing default value of scroll-behavior</title>
 3<meta name="timeout" content="long"/>
 4<link rel="author" title="Frédéric Wang" href="mailto:fwang@igalia.com">
 5<link rel="help" href="https://drafts.csswg.org/cssom-view/#propdef-scroll-behavior">
 6<link rel="help" href="https://drafts.csswg.org/cssom-view/#scrolling-box">
 7<script src="../../../resources/testharness.js"></script>
 8<script src="../../../resources/testharnessreport.js"></script>
 9<script src="resources/scroll-behavior.js"></script>
 10<style>
 11 .scrollable {
 12 overflow: auto;
 13 width: 400px;
 14 height: 200px;
 15 }
 16</style>
 17<div id="log">
 18</div>
 19<div id="overflowNode" class="scrollable">
 20 <div style="width: 2000px; height: 1000px; background: linear-gradient(135deg, red, green);">
 21 <span style="display: inline-block; width: 500px; height: 250px;"></span><span id="elementToReveal" style="display: inline-block; vertical-align: -15px; width: 10px; height: 15px; background: black;"></span>
 22 </div>
 23</div>
 24<script>
 25 var scrollingElement = overflowNode;
 26 var elementToRevealLeft = 500;
 27 var elementToRevealTop = 250;
 28 var scrollFunction = "scroll";
 29
 30 promise_test(() => {
 31 resetScroll(scrollingElement);
 32 assert_equals(scrollingElement.scrollLeft, 0);
 33 assert_equals(scrollingElement.scrollTop, 0);
 34 scrollNode(scrollingElement, "scroll", "instant", elementToRevealLeft, elementToRevealTop);
 35 assert_equals(scrollingElement.scrollLeft, elementToRevealLeft, "Should set scrollLeft immediately");
 36 assert_equals(scrollingElement.scrollTop, elementToRevealTop, "Should set scrollTop immediately");
 37 return new Promise((resolve) => { resolve(); });
 38 }, "Instant scrolling of an element with default scroll-behavior");
 39
 40 promise_test(() => {
 41 resetScroll(scrollingElement);
 42 assert_equals(scrollingElement.scrollLeft, 0);
 43 assert_equals(scrollingElement.scrollTop, 0);
 44 scrollNode(scrollingElement, "scroll", "smooth", elementToRevealLeft, elementToRevealTop);
 45 assert_less_than(scrollingElement.scrollLeft, elementToRevealLeft, "Should not set scrollLeft immediately");
 46 assert_less_than(scrollingElement.scrollTop, elementToRevealTop, "Should not set scrollTop immediately");
 47 return waitForScrollEnd(scrollingElement).then(() => {
 48 assert_equals(scrollingElement.scrollLeft, elementToRevealLeft, "Final value of scrollLeft");
 49 assert_equals(scrollingElement.scrollTop, elementToRevealTop, "Final value of scrollTop");
 50 });
 51 }, "Smooth scrolling of an element with default scroll-behavior");
 52</script>

LayoutTests/fast/scrolling/ios/scroll-behavior-element-expected.txt

 1
 2PASS Element with auto scroll-behavior ; scroll() with default behavior
 3PASS Element with auto scroll-behavior ; scroll() with auto behavior
 4PASS Element with auto scroll-behavior ; scroll() with instant behavior
 5PASS Element with auto scroll-behavior ; scroll() with smooth behavior
 6PASS Element with smooth scroll-behavior ; scroll() with default behavior
 7PASS Element with smooth scroll-behavior ; scroll() with auto behavior
 8PASS Element with smooth scroll-behavior ; scroll() with instant behavior
 9PASS Element with smooth scroll-behavior ; scroll() with smooth behavior
 10PASS Element with auto scroll-behavior ; scrollTo() with default behavior
 11PASS Element with auto scroll-behavior ; scrollTo() with auto behavior
 12PASS Element with auto scroll-behavior ; scrollTo() with instant behavior
 13PASS Element with auto scroll-behavior ; scrollTo() with smooth behavior
 14PASS Element with smooth scroll-behavior ; scrollTo() with default behavior
 15PASS Element with smooth scroll-behavior ; scrollTo() with auto behavior
 16PASS Element with smooth scroll-behavior ; scrollTo() with instant behavior
 17PASS Element with smooth scroll-behavior ; scrollTo() with smooth behavior
 18PASS Element with auto scroll-behavior ; scrollBy() with default behavior
 19PASS Element with auto scroll-behavior ; scrollBy() with auto behavior
 20PASS Element with auto scroll-behavior ; scrollBy() with instant behavior
 21PASS Element with auto scroll-behavior ; scrollBy() with smooth behavior
 22PASS Element with smooth scroll-behavior ; scrollBy() with default behavior
 23PASS Element with smooth scroll-behavior ; scrollBy() with auto behavior
 24PASS Element with smooth scroll-behavior ; scrollBy() with instant behavior
 25PASS Element with smooth scroll-behavior ; scrollBy() with smooth behavior
 26PASS Element with auto scroll-behavior ; scrollIntoView() with default behavior
 27PASS Element with auto scroll-behavior ; scrollIntoView() with auto behavior
 28PASS Element with auto scroll-behavior ; scrollIntoView() with instant behavior
 29PASS Element with auto scroll-behavior ; scrollIntoView() with smooth behavior
 30PASS Element with smooth scroll-behavior ; scrollIntoView() with default behavior
 31PASS Element with smooth scroll-behavior ; scrollIntoView() with auto behavior
 32PASS Element with smooth scroll-behavior ; scrollIntoView() with instant behavior
 33PASS Element with smooth scroll-behavior ; scrollIntoView() with smooth behavior
 34PASS Aborting an ongoing smooth scrolling on an element with another smooth scrolling
 35PASS Aborting an ongoing smooth scrolling on an element with an instant scrolling
 36

LayoutTests/fast/scrolling/ios/scroll-behavior-element.html

 1<!DOCTYPE html><!-- webkit-test-runner [ experimental:CSSOMViewSmoothScrollingEnabled=true internal:AsyncOverflowScrollingEnabled=true ] -->
 2<title>Testing scrollOptions' behavior for Element.scroll* and scroll-behavior on an element</title>
 3<meta name="timeout" content="long"/>
 4<link rel="author" title="Frédéric Wang" href="mailto:fwang@igalia.com">
 5<link rel="help" href="https://drafts.csswg.org/cssom-view/#propdef-scroll-behavior">
 6<link rel="help" href="https://drafts.csswg.org/cssom-view/#scrolling-box">
 7<script src="../../../resources/testharness.js"></script>
 8<script src="../../../resources/testharnessreport.js"></script>
 9<script src="resources/scroll-behavior.js"></script>
 10<style>
 11 .scrollable {
 12 overflow: auto;
 13 width: 400px;
 14 height: 200px;
 15 }
 16 .autoBehavior {
 17 scroll-behavior: auto;
 18 }
 19 .smoothBehavior {
 20 scroll-behavior: smooth;
 21 }
 22</style>
 23<div id="log">
 24</div>
 25<div id="overflowNode" class="scrollable">
 26 <div style="width: 2000px; height: 1000px; background: linear-gradient(135deg, red, green);">
 27 <span style="display: inline-block; width: 500px; height: 250px;"></span><span id="elementToReveal" style="display: inline-block; vertical-align: -15px; width: 10px; height: 15px; background: black;"></span>
 28 </div>
 29</div>
 30<script>
 31 var scrollingElement = overflowNode;
 32 var styledElement = overflowNode;
 33 var elementToRevealLeft = 500;
 34 var elementToRevealTop = 250;
 35
 36 ["scroll", "scrollTo", "scrollBy", "scrollIntoView"].forEach((scrollFunction) => {
 37 promise_test(() => {
 38 resetScroll(scrollingElement);
 39 setScrollBehavior(styledElement, "autoBehavior");
 40 assert_equals(scrollingElement.scrollLeft, 0);
 41 assert_equals(scrollingElement.scrollTop, 0);
 42 scrollNode(scrollingElement, scrollFunction, null, elementToRevealLeft, elementToRevealTop);
 43 assert_equals(scrollingElement.scrollLeft, elementToRevealLeft, "Should set scrollLeft immediately");
 44 assert_equals(scrollingElement.scrollTop, elementToRevealTop, "Should set scrollTop immediately");
 45 return new Promise((resolve) => { resolve(); });
 46 }, `Element with auto scroll-behavior ; ${scrollFunction}() with default behavior`);
 47
 48 promise_test(() => {
 49 resetScroll(scrollingElement);
 50 setScrollBehavior(styledElement, "autoBehavior");
 51 assert_equals(scrollingElement.scrollLeft, 0);
 52 assert_equals(scrollingElement.scrollTop, 0);
 53 scrollNode(scrollingElement, scrollFunction, "auto", elementToRevealLeft, elementToRevealTop);
 54 assert_equals(scrollingElement.scrollLeft, elementToRevealLeft, "Should set scrollLeft immediately");
 55 assert_equals(scrollingElement.scrollTop, elementToRevealTop, "Should set scrollTop immediately");
 56 return new Promise((resolve) => { resolve(); });
 57 }, `Element with auto scroll-behavior ; ${scrollFunction}() with auto behavior`);
 58
 59 promise_test(() => {
 60 resetScroll(scrollingElement);
 61 setScrollBehavior(styledElement, "autoBehavior");
 62 assert_equals(scrollingElement.scrollLeft, 0);
 63 assert_equals(scrollingElement.scrollTop, 0);
 64 scrollNode(scrollingElement, scrollFunction, "instant", elementToRevealLeft, elementToRevealTop);
 65 assert_equals(scrollingElement.scrollLeft, elementToRevealLeft, "Should set scrollLeft immediately");
 66 assert_equals(scrollingElement.scrollTop, elementToRevealTop, "Should set scrollTop immediately");
 67 return new Promise((resolve) => { resolve(); });
 68 }, `Element with auto scroll-behavior ; ${scrollFunction}() with instant behavior`);
 69
 70 promise_test(() => {
 71 resetScroll(scrollingElement);
 72 setScrollBehavior(styledElement, "autoBehavior");
 73 assert_equals(scrollingElement.scrollLeft, 0);
 74 assert_equals(scrollingElement.scrollTop, 0);
 75 scrollNode(scrollingElement, scrollFunction, "smooth", elementToRevealLeft, elementToRevealTop);
 76 assert_less_than(scrollingElement.scrollLeft, elementToRevealLeft, "Should not set scrollLeft immediately");
 77 assert_less_than(scrollingElement.scrollTop, elementToRevealTop, "Should not set scrollTop immediately");
 78 return waitForScrollEnd(scrollingElement).then(() => {
 79 assert_equals(scrollingElement.scrollLeft, elementToRevealLeft, "Final value of scrollLeft");
 80 assert_equals(scrollingElement.scrollTop, elementToRevealTop, "Final value of scrollTop");
 81 });
 82 }, `Element with auto scroll-behavior ; ${scrollFunction}() with smooth behavior`);
 83
 84 promise_test(() => {
 85 resetScroll(scrollingElement);
 86 setScrollBehavior(styledElement, "smoothBehavior");
 87 assert_equals(scrollingElement.scrollLeft, 0);
 88 assert_equals(scrollingElement.scrollTop, 0);
 89 scrollNode(scrollingElement, scrollFunction, null, elementToRevealLeft, elementToRevealTop);
 90 assert_less_than(scrollingElement.scrollLeft, elementToRevealLeft, "Should not set scrollLeft immediately");
 91 assert_less_than(scrollingElement.scrollTop, elementToRevealTop, "Should not set scrollTop immediately");
 92 return waitForScrollEnd(scrollingElement).then(() => {
 93 assert_equals(scrollingElement.scrollLeft, elementToRevealLeft, "Final value of scrollLeft");
 94 assert_equals(scrollingElement.scrollTop, elementToRevealTop, "Final value of scrollTop");
 95 });
 96 }, `Element with smooth scroll-behavior ; ${scrollFunction}() with default behavior`);
 97
 98 promise_test(() => {
 99 resetScroll(scrollingElement);
 100 setScrollBehavior(styledElement, "smoothBehavior");
 101 assert_equals(scrollingElement.scrollLeft, 0);
 102 assert_equals(scrollingElement.scrollTop, 0);
 103 scrollNode(scrollingElement, scrollFunction, "auto", elementToRevealLeft, elementToRevealTop);
 104 assert_less_than(scrollingElement.scrollLeft, elementToRevealLeft, "Should not set scrollLeft immediately");
 105 assert_less_than(scrollingElement.scrollTop, elementToRevealTop, "Should not set scrollTop immediately");
 106 return waitForScrollEnd(scrollingElement).then(() => {
 107 assert_equals(scrollingElement.scrollLeft, elementToRevealLeft, "Final value of scrollLeft");
 108 assert_equals(scrollingElement.scrollTop, elementToRevealTop, "Final value of scrollTop");
 109 });
 110 }, `Element with smooth scroll-behavior ; ${scrollFunction}() with auto behavior`);
 111
 112 promise_test(() => {
 113 resetScroll(scrollingElement);
 114 setScrollBehavior(styledElement, "smoothBehavior");
 115 assert_equals(scrollingElement.scrollLeft, 0);
 116 assert_equals(scrollingElement.scrollTop, 0);
 117 scrollNode(scrollingElement, scrollFunction, "instant", elementToRevealLeft, elementToRevealTop);
 118 assert_equals(scrollingElement.scrollLeft, elementToRevealLeft, "Should set scrollLeft immediately");
 119 assert_equals(scrollingElement.scrollTop, elementToRevealTop, "Should set scrollTop immediately");
 120 return new Promise((resolve) => { resolve(); });
 121 }, `Element with smooth scroll-behavior ; ${scrollFunction}() with instant behavior`);
 122
 123 promise_test(() => {
 124 resetScroll(scrollingElement);
 125 setScrollBehavior(styledElement, "smoothBehavior");
 126 assert_equals(scrollingElement.scrollLeft, 0);
 127 assert_equals(scrollingElement.scrollTop, 0);
 128 scrollNode(scrollingElement, scrollFunction, "smooth", elementToRevealLeft, elementToRevealTop);
 129 assert_less_than(scrollingElement.scrollLeft, elementToRevealLeft, "Should not set scrollLeft immediately");
 130 assert_less_than(scrollingElement.scrollTop, elementToRevealTop, "Should not set scrollTop immediately");
 131 return waitForScrollEnd(scrollingElement).then(() => {
 132 assert_equals(scrollingElement.scrollLeft, elementToRevealLeft, "Final value of scrollLeft");
 133 assert_equals(scrollingElement.scrollTop, elementToRevealTop, "Final value of scrollTop");
 134 });
 135 }, `Element with smooth scroll-behavior ; ${scrollFunction}() with smooth behavior`);
 136 });
 137
 138 promise_test(() => {
 139 resetScroll(scrollingElement);
 140 setScrollBehavior(styledElement, "smoothBehavior");
 141 assert_equals(scrollingElement.scrollLeft, 0);
 142 assert_equals(scrollingElement.scrollTop, 0);
 143 scrollNode(scrollingElement, "scroll", "smooth", elementToRevealLeft, elementToRevealTop);
 144 scrollNode(scrollingElement, "scroll", "smooth", elementToRevealLeft / 2, elementToRevealTop / 2);
 145 return waitForScrollEnd(scrollingElement).then(() => {
 146 assert_equals(scrollingElement.scrollLeft, elementToRevealLeft / 2, "Final value of scrollLeft");
 147 assert_equals(scrollingElement.scrollTop, elementToRevealTop / 2, "Final value of scrollTop");
 148 });
 149 }, "Aborting an ongoing smooth scrolling on an element with another smooth scrolling");
 150
 151 promise_test(() => {
 152 resetScroll(scrollingElement);
 153 setScrollBehavior(styledElement, "smoothBehavior");
 154 assert_equals(scrollingElement.scrollLeft, 0);
 155 assert_equals(scrollingElement.scrollTop, 0);
 156 scrollNode(scrollingElement, "scroll", "smooth", elementToRevealLeft, elementToRevealTop);
 157 scrollNode(scrollingElement, "scroll", "instant", 0, 0);
 158 return waitForScrollEnd(scrollingElement).then(() => {
 159 assert_equals(scrollingElement.scrollLeft, 0, "Final value of scrollLeft");
 160 assert_equals(scrollingElement.scrollTop, 0, "Final value of scrollTop");
 161 });
 162 }, "Aborting an ongoing smooth scrolling on an element with an instant scrolling");
 163</script>

LayoutTests/fast/scrolling/ios/scroll-behavior-main-frame-root-expected.txt

 1
 2PASS Page loaded
 3PASS Main frame with auto scroll-behavior ; scroll() with default behavior
 4PASS Main frame with auto scroll-behavior ; scroll() with auto behavior
 5PASS Main frame with auto scroll-behavior ; scroll() with instant behavior
 6PASS Main frame with auto scroll-behavior ; scroll() with smooth behavior
 7PASS Main frame with smooth scroll-behavior ; scroll() with default behavior
 8PASS Main frame with smooth scroll-behavior ; scroll() with auto behavior
 9PASS Main frame with smooth scroll-behavior ; scroll() with instant behavior
 10PASS Main frame with smooth scroll-behavior ; scroll() with smooth behavior
 11PASS Main frame with auto scroll-behavior ; scrollTo() with default behavior
 12PASS Main frame with auto scroll-behavior ; scrollTo() with auto behavior
 13PASS Main frame with auto scroll-behavior ; scrollTo() with instant behavior
 14PASS Main frame with auto scroll-behavior ; scrollTo() with smooth behavior
 15PASS Main frame with smooth scroll-behavior ; scrollTo() with default behavior
 16PASS Main frame with smooth scroll-behavior ; scrollTo() with auto behavior
 17PASS Main frame with smooth scroll-behavior ; scrollTo() with instant behavior
 18PASS Main frame with smooth scroll-behavior ; scrollTo() with smooth behavior
 19PASS Main frame with auto scroll-behavior ; scrollBy() with default behavior
 20PASS Main frame with auto scroll-behavior ; scrollBy() with auto behavior
 21PASS Main frame with auto scroll-behavior ; scrollBy() with instant behavior
 22PASS Main frame with auto scroll-behavior ; scrollBy() with smooth behavior
 23PASS Main frame with smooth scroll-behavior ; scrollBy() with default behavior
 24PASS Main frame with smooth scroll-behavior ; scrollBy() with auto behavior
 25PASS Main frame with smooth scroll-behavior ; scrollBy() with instant behavior
 26PASS Main frame with smooth scroll-behavior ; scrollBy() with smooth behavior
 27PASS Main frame with auto scroll-behavior ; scrollIntoView() with default behavior
 28PASS Main frame with auto scroll-behavior ; scrollIntoView() with auto behavior
 29PASS Main frame with auto scroll-behavior ; scrollIntoView() with instant behavior
 30PASS Main frame with auto scroll-behavior ; scrollIntoView() with smooth behavior
 31PASS Main frame with smooth scroll-behavior ; scrollIntoView() with default behavior
 32PASS Main frame with smooth scroll-behavior ; scrollIntoView() with auto behavior
 33PASS Main frame with smooth scroll-behavior ; scrollIntoView() with instant behavior
 34PASS Main frame with smooth scroll-behavior ; scrollIntoView() with smooth behavior
 35PASS Aborting an ongoing smooth scrolling on the main frame with another smooth scrolling
 36PASS Aborting an ongoing smooth scrolling on the main frame with an instant scrolling
 37

LayoutTests/fast/scrolling/ios/scroll-behavior-main-frame-root.html

 1<!DOCTYPE html><!-- webkit-test-runner [ experimental:CSSOMViewSmoothScrollingEnabled=true internal:AsyncOverflowScrollingEnabled=true ] -->
 2<title>Testing scrollOptions' behavior for Element.scroll* and scroll-behavior on the root of the main frame</title>
 3<meta name="timeout" content="long"/>
 4<link rel="author" title="Frédéric Wang" href="mailto:fwang@igalia.com">
 5<link rel="help" href="https://drafts.csswg.org/cssom-view/#propdef-scroll-behavior">
 6<link rel="help" href="https://drafts.csswg.org/cssom-view/#scrolling-box">
 7<script src="../../../resources/testharness.js"></script>
 8<script src="../../../resources/testharnessreport.js"></script>
 9<script src="resources/scroll-behavior.js"></script>
 10<style>
 11 body {
 12 margin: 0;
 13 }
 14 .autoBehavior {
 15 scroll-behavior: auto;
 16 }
 17 .smoothBehavior {
 18 scroll-behavior: smooth;
 19 }
 20</style>
 21<div id="log">
 22</div>
 23<div id="pageContent" style="position: absolute; left: 0; top: 0;">
 24 <div id="elementToReveal" style="position: absolute; display: inline-block; width: 10px; height: 15px; background: black;"></div>
 25</div>
 26<script>
 27 var pageLoaded = async_test("Page loaded");
 28 var scrollingElement, styledElement, elementToRevealLeft, elementToRevealTop;
 29 window.addEventListener("load", pageLoaded.step_func_done(function() {
 30 scrollingElement = document.scrollingElement;
 31 styledElement = document.documentElement;
 32 pageContent.style.width = (10 + window.innerWidth) * 5 + "px";
 33 pageContent.style.height = (20 + window.innerHeight) * 6 + "px";
 34 elementToRevealLeft = (10 + window.innerWidth) * 3;
 35 elementToRevealTop = (20 + window.innerHeight) * 4;
 36 elementToReveal.style.left = elementToRevealLeft + "px";
 37 elementToReveal.style.top = elementToRevealTop + "px";
 38
 39 add_completion_callback(() => { resetScroll(scrollingElement); });
 40
 41 ["scroll", "scrollTo", "scrollBy", "scrollIntoView"].forEach((scrollFunction) => {
 42 promise_test(() => {
 43 resetScroll(scrollingElement);
 44 setScrollBehavior(styledElement, "autoBehavior");
 45 assert_equals(scrollingElement.scrollLeft, 0);
 46 assert_equals(scrollingElement.scrollTop, 0);
 47 scrollNode(scrollingElement, scrollFunction, null, elementToRevealLeft, elementToRevealTop);
 48 assert_equals(scrollingElement.scrollLeft, elementToRevealLeft, "Should set scrollLeft immediately");
 49 assert_equals(scrollingElement.scrollTop, elementToRevealTop, "Should set scrollTop immediately");
 50 return new Promise((resolve) => { resolve(); });
 51 }, `Main frame with auto scroll-behavior ; ${scrollFunction}() with default behavior`);
 52
 53 promise_test(() => {
 54 resetScroll(scrollingElement);
 55 setScrollBehavior(styledElement, "autoBehavior");
 56 assert_equals(scrollingElement.scrollLeft, 0);
 57 assert_equals(scrollingElement.scrollTop, 0);
 58 scrollNode(scrollingElement, scrollFunction, "auto", elementToRevealLeft, elementToRevealTop);
 59 assert_equals(scrollingElement.scrollLeft, elementToRevealLeft, "Should set scrollLeft immediately");
 60 assert_equals(scrollingElement.scrollTop, elementToRevealTop, "Should set scrollTop immediately");
 61 return new Promise((resolve) => { resolve(); });
 62 }, `Main frame with auto scroll-behavior ; ${scrollFunction}() with auto behavior`);
 63
 64 promise_test(() => {
 65 resetScroll(scrollingElement);
 66 setScrollBehavior(styledElement, "autoBehavior");
 67 assert_equals(scrollingElement.scrollLeft, 0);
 68 assert_equals(scrollingElement.scrollTop, 0);
 69 scrollNode(scrollingElement, scrollFunction, "instant", elementToRevealLeft, elementToRevealTop);
 70 assert_equals(scrollingElement.scrollLeft, elementToRevealLeft, "Should set scrollLeft immediately");
 71 assert_equals(scrollingElement.scrollTop, elementToRevealTop, "Should set scrollTop immediately");
 72 return new Promise((resolve) => { resolve(); });
 73 }, `Main frame with auto scroll-behavior ; ${scrollFunction}() with instant behavior`);
 74
 75 promise_test(() => {
 76 resetScroll(scrollingElement);
 77 setScrollBehavior(styledElement, "autoBehavior");
 78 assert_equals(scrollingElement.scrollLeft, 0);
 79 assert_equals(scrollingElement.scrollTop, 0);
 80 scrollNode(scrollingElement, scrollFunction, "smooth", elementToRevealLeft, elementToRevealTop);
 81 assert_less_than(scrollingElement.scrollLeft, elementToRevealLeft, "Should not set scrollLeft immediately");
 82 assert_less_than(scrollingElement.scrollTop, elementToRevealTop, "Should not set scrollTop immediately");
 83 return waitForScrollEnd(scrollingElement).then(() => {
 84 assert_equals(scrollingElement.scrollLeft, elementToRevealLeft, "Final value of scrollLeft");
 85 assert_equals(scrollingElement.scrollTop, elementToRevealTop, "Final value of scrollTop");
 86 });
 87 }, `Main frame with auto scroll-behavior ; ${scrollFunction}() with smooth behavior`);
 88
 89 promise_test(() => {
 90 resetScroll(scrollingElement);
 91 setScrollBehavior(styledElement, "smoothBehavior");
 92 assert_equals(scrollingElement.scrollLeft, 0);
 93 assert_equals(scrollingElement.scrollTop, 0);
 94 scrollNode(scrollingElement, scrollFunction, null, elementToRevealLeft, elementToRevealTop);
 95 assert_less_than(scrollingElement.scrollLeft, elementToRevealLeft, "Should not set scrollLeft immediately");
 96 assert_less_than(scrollingElement.scrollTop, elementToRevealTop, "Should not set scrollTop immediately");
 97 return waitForScrollEnd(scrollingElement).then(() => {
 98 assert_equals(scrollingElement.scrollLeft, elementToRevealLeft, "Final value of scrollLeft");
 99 assert_equals(scrollingElement.scrollTop, elementToRevealTop, "Final value of scrollTop");
 100 });
 101 }, `Main frame with smooth scroll-behavior ; ${scrollFunction}() with default behavior`);
 102
 103 promise_test(() => {
 104 resetScroll(scrollingElement);
 105 setScrollBehavior(styledElement, "smoothBehavior");
 106 assert_equals(scrollingElement.scrollLeft, 0);
 107 assert_equals(scrollingElement.scrollTop, 0);
 108 scrollNode(scrollingElement, scrollFunction, "auto", elementToRevealLeft, elementToRevealTop);
 109 assert_less_than(scrollingElement.scrollLeft, elementToRevealLeft, "Should not set scrollLeft immediately");
 110 assert_less_than(scrollingElement.scrollTop, elementToRevealTop, "Should not set scrollTop immediately");
 111 return waitForScrollEnd(scrollingElement).then(() => {
 112 assert_equals(scrollingElement.scrollLeft, elementToRevealLeft, "Final value of scrollLeft");
 113 assert_equals(scrollingElement.scrollTop, elementToRevealTop, "Final value of scrollTop");
 114 });
 115 }, `Main frame with smooth scroll-behavior ; ${scrollFunction}() with auto behavior`);
 116
 117 promise_test(() => {
 118 resetScroll(scrollingElement);
 119 setScrollBehavior(styledElement, "smoothBehavior");
 120 assert_equals(scrollingElement.scrollLeft, 0);
 121 assert_equals(scrollingElement.scrollTop, 0);
 122 scrollNode(scrollingElement, scrollFunction, "instant", elementToRevealLeft, elementToRevealTop);
 123 assert_equals(scrollingElement.scrollLeft, elementToRevealLeft, "Should set scrollLeft immediately");
 124 assert_equals(scrollingElement.scrollTop, elementToRevealTop, "Should set scrollTop immediately");
 125 return new Promise((resolve) => { resolve(); });
 126 }, `Main frame with smooth scroll-behavior ; ${scrollFunction}() with instant behavior`);
 127
 128 promise_test(() => {
 129 resetScroll(scrollingElement);
 130 setScrollBehavior(styledElement, "smoothBehavior");
 131 assert_equals(scrollingElement.scrollLeft, 0);
 132 assert_equals(scrollingElement.scrollTop, 0);
 133 scrollNode(scrollingElement, scrollFunction, "smooth", elementToRevealLeft, elementToRevealTop);
 134 assert_less_than(scrollingElement.scrollLeft, elementToRevealLeft, "Should not set scrollLeft immediately");
 135 assert_less_than(scrollingElement.scrollTop, elementToRevealTop, "Should not set scrollTop immediately");
 136 return waitForScrollEnd(scrollingElement).then(() => {
 137 assert_equals(scrollingElement.scrollLeft, elementToRevealLeft, "Final value of scrollLeft");
 138 assert_equals(scrollingElement.scrollTop, elementToRevealTop, "Final value of scrollTop");
 139 });
 140 }, `Main frame with smooth scroll-behavior ; ${scrollFunction}() with smooth behavior`);
 141 });
 142
 143 promise_test(() => {
 144 resetScroll(scrollingElement);
 145 setScrollBehavior(styledElement, "smoothBehavior");
 146 assert_equals(scrollingElement.scrollLeft, 0);
 147 assert_equals(scrollingElement.scrollTop, 0);
 148 scrollNode(scrollingElement, "scroll", "smooth", elementToRevealLeft, elementToRevealTop);
 149 scrollNode(scrollingElement, "scroll", "smooth", elementToRevealLeft / 2, elementToRevealTop / 2);
 150 return waitForScrollEnd(scrollingElement).then(() => {
 151 assert_equals(scrollingElement.scrollLeft, elementToRevealLeft / 2, "Final value of scrollLeft");
 152 assert_equals(scrollingElement.scrollTop, elementToRevealTop / 2, "Final value of scrollTop");
 153 });
 154 }, "Aborting an ongoing smooth scrolling on the main frame with another smooth scrolling");
 155
 156 promise_test(() => {
 157 resetScroll(scrollingElement);
 158 setScrollBehavior(styledElement, "smoothBehavior");
 159 assert_equals(scrollingElement.scrollLeft, 0);
 160 assert_equals(scrollingElement.scrollTop, 0);
 161 scrollNode(scrollingElement, "scroll", "smooth", elementToRevealLeft, elementToRevealTop);
 162 scrollNode(scrollingElement, "scroll", "instant", 0, 0);
 163 return waitForScrollEnd(scrollingElement).then(() => {
 164 assert_equals(scrollingElement.scrollLeft, 0, "Final value of scrollLeft");
 165 assert_equals(scrollingElement.scrollTop, 0, "Final value of scrollTop");
 166 });
 167 }, "Aborting an ongoing smooth scrolling on the main frame with an instant scrolling");
 168 }));
 169</script>

LayoutTests/fast/scrolling/ios/scroll-behavior-main-frame-window-expected.txt

 1
 2PASS Page loaded
 3PASS Main frame with auto scroll-behavior ; scroll() with default behavior
 4PASS Main frame with auto scroll-behavior ; scroll() with auto behavior
 5PASS Main frame with auto scroll-behavior ; scroll() with instant behavior
 6PASS Main frame with auto scroll-behavior ; scroll() with smooth behavior
 7PASS Main frame with smooth scroll-behavior ; scroll() with default behavior
 8PASS Main frame with smooth scroll-behavior ; scroll() with auto behavior
 9PASS Main frame with smooth scroll-behavior ; scroll() with instant behavior
 10PASS Main frame with smooth scroll-behavior ; scroll() with smooth behavior
 11PASS Main frame with auto scroll-behavior ; scrollTo() with default behavior
 12PASS Main frame with auto scroll-behavior ; scrollTo() with auto behavior
 13PASS Main frame with auto scroll-behavior ; scrollTo() with instant behavior
 14PASS Main frame with auto scroll-behavior ; scrollTo() with smooth behavior
 15PASS Main frame with smooth scroll-behavior ; scrollTo() with default behavior
 16PASS Main frame with smooth scroll-behavior ; scrollTo() with auto behavior
 17PASS Main frame with smooth scroll-behavior ; scrollTo() with instant behavior
 18PASS Main frame with smooth scroll-behavior ; scrollTo() with smooth behavior
 19PASS Main frame with auto scroll-behavior ; scrollBy() with default behavior
 20PASS Main frame with auto scroll-behavior ; scrollBy() with auto behavior
 21PASS Main frame with auto scroll-behavior ; scrollBy() with instant behavior
 22PASS Main frame with auto scroll-behavior ; scrollBy() with smooth behavior
 23PASS Main frame with smooth scroll-behavior ; scrollBy() with default behavior
 24PASS Main frame with smooth scroll-behavior ; scrollBy() with auto behavior
 25PASS Main frame with smooth scroll-behavior ; scrollBy() with instant behavior
 26PASS Main frame with smooth scroll-behavior ; scrollBy() with smooth behavior
 27PASS Aborting an ongoing smooth scrolling on the main frame with another smooth scrolling
 28PASS Aborting an ongoing smooth scrolling on the main frame with an instant scrolling
 29

LayoutTests/fast/scrolling/ios/scroll-behavior-main-frame-window.html

 1<!DOCTYPE html><!-- webkit-test-runner [ experimental:CSSOMViewSmoothScrollingEnabled=true internal:AsyncOverflowScrollingEnabled=true ] -->
 2<title>Testing scrollOptions' behavior for Element.scroll* on the window of the main frame</title>
 3<meta name="timeout" content="long"/>
 4<meta name="viewport" content="width=device-width,minimum-scale=1,initial-scale=1">
 5<link rel="author" title="Frédéric Wang" href="mailto:fwang@igalia.com">
 6<link rel="help" href="https://drafts.csswg.org/cssom-view/#propdef-scroll-behavior">
 7<link rel="help" href="https://drafts.csswg.org/cssom-view/#scrolling-box">
 8<script src="../../../resources/testharness.js"></script>
 9<script src="../../../resources/testharnessreport.js"></script>
 10<script src="resources/scroll-behavior.js"></script>
 11<style>
 12 body {
 13 margin: 0;
 14 }
 15 .autoBehavior {
 16 scroll-behavior: auto;
 17 }
 18 .smoothBehavior {
 19 scroll-behavior: smooth;
 20 }
 21</style>
 22<div id="log">
 23</div>
 24<div id="pageContent" style="position: absolute; left: 0; top: 0;">
 25 <div id="elementToReveal" style="position: absolute; display: inline-block; width: 10px; height: 15px; background: black;"></div>
 26</div>
 27<script>
 28 var pageLoaded = async_test("Page loaded");
 29 var scrollingWindow, styledElement, elementToRevealLeft, elementToRevealTop;
 30 window.addEventListener("load", pageLoaded.step_func_done(function() {
 31 scrollingWindow = window;
 32 styledElement = document.documentElement;
 33 pageContent.style.width = (10 + window.innerWidth) * 5 + "px";
 34 pageContent.style.height = (20 + window.innerHeight) * 6 + "px";
 35 elementToRevealLeft = (10 + window.innerWidth) * 3;
 36 elementToRevealTop = (20 + window.innerHeight) * 4;
 37 elementToReveal.style.left = elementToRevealLeft + "px";
 38 elementToReveal.style.top = elementToRevealTop + "px";
 39
 40 add_completion_callback(() => { resetScrollForWindow(window); });
 41
 42 ["scroll", "scrollTo", "scrollBy"].forEach((scrollFunction) => {
 43 promise_test(() => {
 44 resetScrollForWindow(scrollingWindow);
 45 setScrollBehavior(styledElement, "autoBehavior");
 46 assert_equals(scrollingWindow.scrollX, 0);
 47 assert_equals(scrollingWindow.scrollY, 0);
 48 scrollWindow(scrollingWindow, scrollFunction, null, elementToRevealLeft, elementToRevealTop);
 49 assert_equals(scrollingWindow.scrollX, elementToRevealLeft, "Should set scrollLeft immediately");
 50 assert_equals(scrollingWindow.scrollY, elementToRevealTop, "Should set scrollTop immediately");
 51 return new Promise((resolve) => { resolve(); });
 52 }, `Main frame with auto scroll-behavior ; ${scrollFunction}() with default behavior`);
 53
 54 promise_test(() => {
 55 resetScrollForWindow(scrollingWindow);
 56 setScrollBehavior(styledElement, "autoBehavior");
 57 assert_equals(scrollingWindow.scrollX, 0);
 58 assert_equals(scrollingWindow.scrollY, 0);
 59 scrollWindow(scrollingWindow, scrollFunction, "auto", elementToRevealLeft, elementToRevealTop);
 60 assert_equals(scrollingWindow.scrollX, elementToRevealLeft, "Should set scrollLeft immediately");
 61 assert_equals(scrollingWindow.scrollY, elementToRevealTop, "Should set scrollTop immediately");
 62 return new Promise((resolve) => { resolve(); });
 63 }, `Main frame with auto scroll-behavior ; ${scrollFunction}() with auto behavior`);
 64
 65 promise_test(() => {
 66 resetScrollForWindow(scrollingWindow);
 67 setScrollBehavior(styledElement, "autoBehavior");
 68 assert_equals(scrollingWindow.scrollX, 0);
 69 assert_equals(scrollingWindow.scrollY, 0);
 70 scrollWindow(scrollingWindow, scrollFunction, "instant", elementToRevealLeft, elementToRevealTop);
 71 assert_equals(scrollingWindow.scrollX, elementToRevealLeft, "Should set scrollLeft immediately");
 72 assert_equals(scrollingWindow.scrollY, elementToRevealTop, "Should set scrollTop immediately");
 73 return new Promise((resolve) => { resolve(); });
 74 }, `Main frame with auto scroll-behavior ; ${scrollFunction}() with instant behavior`);
 75
 76 promise_test(() => {
 77 resetScrollForWindow(scrollingWindow);
 78 setScrollBehavior(styledElement, "autoBehavior");
 79 assert_equals(scrollingWindow.scrollX, 0);
 80 assert_equals(scrollingWindow.scrollY, 0);
 81 scrollWindow(scrollingWindow, scrollFunction, "smooth", elementToRevealLeft, elementToRevealTop);
 82 assert_less_than(scrollingWindow.scrollX, elementToRevealLeft, "Should not set scrollLeft immediately");
 83 assert_less_than(scrollingWindow.scrollY, elementToRevealTop, "Should not set scrollTop immediately");
 84 return waitForScrollEnd(scrollingWindow.document.scrollingElement).then(() => {
 85 assert_equals(scrollingWindow.scrollX, elementToRevealLeft, "Final value of scrollLeft");
 86 assert_equals(scrollingWindow.scrollY, elementToRevealTop, "Final value of scrollTop");
 87 });
 88 }, `Main frame with auto scroll-behavior ; ${scrollFunction}() with smooth behavior`);
 89
 90 promise_test(() => {
 91 resetScrollForWindow(scrollingWindow);
 92 setScrollBehavior(styledElement, "smoothBehavior");
 93 assert_equals(scrollingWindow.scrollX, 0);
 94 assert_equals(scrollingWindow.scrollY, 0);
 95 scrollWindow(scrollingWindow, scrollFunction, null, elementToRevealLeft, elementToRevealTop);
 96 assert_less_than(scrollingWindow.scrollX, elementToRevealLeft, "Should not set scrollLeft immediately");
 97 assert_less_than(scrollingWindow.scrollY, elementToRevealTop, "Should not set scrollTop immediately");
 98 return waitForScrollEnd(scrollingWindow.document.scrollingElement).then(() => {
 99 assert_equals(scrollingWindow.scrollX, elementToRevealLeft, "Final value of scrollLeft");
 100 assert_equals(scrollingWindow.scrollY, elementToRevealTop, "Final value of scrollTop");
 101 });
 102 }, `Main frame with smooth scroll-behavior ; ${scrollFunction}() with default behavior`);
 103
 104 promise_test(() => {
 105 resetScrollForWindow(scrollingWindow);
 106 setScrollBehavior(styledElement, "smoothBehavior");
 107 assert_equals(scrollingWindow.scrollX, 0);
 108 assert_equals(scrollingWindow.scrollY, 0);
 109 scrollWindow(scrollingWindow, scrollFunction, "auto", elementToRevealLeft, elementToRevealTop);
 110 assert_less_than(scrollingWindow.scrollX, elementToRevealLeft, "Should not set scrollLeft immediately");
 111 assert_less_than(scrollingWindow.scrollY, elementToRevealTop, "Should not set scrollTop immediately");
 112 return waitForScrollEnd(scrollingWindow.document.scrollingElement).then(() => {
 113 assert_equals(scrollingWindow.scrollX, elementToRevealLeft, "Final value of scrollLeft");
 114 assert_equals(scrollingWindow.scrollY, elementToRevealTop, "Final value of scrollTop");
 115 });
 116 }, `Main frame with smooth scroll-behavior ; ${scrollFunction}() with auto behavior`);
 117
 118 promise_test(() => {
 119 resetScrollForWindow(scrollingWindow);
 120 setScrollBehavior(styledElement, "smoothBehavior");
 121 assert_equals(scrollingWindow.scrollX, 0);
 122 assert_equals(scrollingWindow.scrollY, 0);
 123 scrollWindow(scrollingWindow, scrollFunction, "instant", elementToRevealLeft, elementToRevealTop);
 124 assert_equals(scrollingWindow.scrollX, elementToRevealLeft, "Should set scrollLeft immediately");
 125 assert_equals(scrollingWindow.scrollY, elementToRevealTop, "Should set scrollTop immediately");
 126 return new Promise((resolve) => { resolve(); });
 127 }, `Main frame with smooth scroll-behavior ; ${scrollFunction}() with instant behavior`);
 128
 129 promise_test(() => {
 130 resetScrollForWindow(scrollingWindow);
 131 setScrollBehavior(styledElement, "smoothBehavior");
 132 assert_equals(scrollingWindow.scrollX, 0);
 133 assert_equals(scrollingWindow.scrollY, 0);
 134 scrollWindow(scrollingWindow, scrollFunction, "smooth", elementToRevealLeft, elementToRevealTop);
 135 assert_less_than(scrollingWindow.scrollX, elementToRevealLeft, "Should not set scrollLeft immediately");
 136 assert_less_than(scrollingWindow.scrollY, elementToRevealTop, "Should not set scrollTop immediately");
 137 return waitForScrollEnd(scrollingWindow.document.scrollingElement).then(() => {
 138 assert_equals(scrollingWindow.scrollX, elementToRevealLeft, "Final value of scrollLeft");
 139 assert_equals(scrollingWindow.scrollY, elementToRevealTop, "Final value of scrollTop");
 140 });
 141 }, `Main frame with smooth scroll-behavior ; ${scrollFunction}() with smooth behavior`);
 142 });
 143
 144 promise_test(() => {
 145 resetScrollForWindow(scrollingWindow);
 146 setScrollBehavior(styledElement, "smoothBehavior");
 147 assert_equals(scrollingWindow.scrollX, 0);
 148 assert_equals(scrollingWindow.scrollY, 0);
 149 scrollWindow(scrollingWindow, "scroll", "smooth", elementToRevealLeft, elementToRevealTop);
 150 scrollWindow(scrollingWindow, "scroll", "smooth", elementToRevealLeft / 2, elementToRevealTop / 2);
 151 return waitForScrollEnd(scrollingWindow.document.scrollingElement).then(() => {
 152 assert_equals(scrollingWindow.scrollX, elementToRevealLeft / 2, "Final value of scrollLeft");
 153 assert_equals(scrollingWindow.scrollY, elementToRevealTop / 2, "Final value of scrollTop");
 154 });
 155 }, "Aborting an ongoing smooth scrolling on the main frame with another smooth scrolling");
 156
 157 promise_test(() => {
 158 resetScrollForWindow(scrollingWindow);
 159 setScrollBehavior(styledElement, "smoothBehavior");
 160 assert_equals(scrollingWindow.scrollX, 0);
 161 assert_equals(scrollingWindow.scrollY, 0);
 162 scrollWindow(scrollingWindow, "scroll", "smooth", elementToRevealLeft, elementToRevealTop);
 163 scrollWindow(scrollingWindow, "scroll", "instant", 0, 0);
 164 return waitForScrollEnd(scrollingWindow.document.scrollingElement).then(() => {
 165 assert_equals(scrollingWindow.scrollX, 0, "Final value of scrollLeft");
 166 assert_equals(scrollingWindow.scrollY, 0, "Final value of scrollTop");
 167 });
 168 }, "Aborting an ongoing smooth scrolling on the main frame with an instant scrolling");
 169 }));
 170</script>

LayoutTests/fast/scrolling/ios/scroll-behavior-scrollintoview-nested-expected.txt

 1
 2PASS scrollIntoView with nested elements with different scroll-behavior
 3

LayoutTests/fast/scrolling/ios/scroll-behavior-scrollintoview-nested.html

 1<!DOCTYPE html><!-- webkit-test-runner [ experimental:CSSOMViewSmoothScrollingEnabled=true internal:AsyncOverflowScrollingEnabled=true ] -->
 2<title>Testing scrollOptions' behavior with scrollIntoView for nested scrolling nodes</title>
 3<meta name="timeout" content="long"/>
 4<link rel="author" title="Frédéric Wang" href="mailto:fwang@igalia.com">
 5<link rel="help" href="https://drafts.csswg.org/cssom-view/#propdef-scroll-behavior">
 6<link rel="help" href="https://drafts.csswg.org/cssom-view/#scrolling-box">
 7<script src="../../../resources/testharness.js"></script>
 8<script src="../../../resources/testharnessreport.js"></script>
 9<script src="resources/scroll-behavior.js"></script>
 10<style>
 11 .scrollable {
 12 overflow: auto;
 13 height: 200px;
 14 }
 15 .smoothBehavior {
 16 scroll-behavior: smooth;
 17 }
 18 .gradient {
 19 background: linear-gradient(135deg, red, green);
 20 }
 21</style>
 22<div id="log">
 23</div>
 24<div>
 25 <div class="scrollable smoothBehavior" style="width: 450px">
 26 <div class="gradient" style="width: 100px; height: 500px;"></div>
 27 <div class="scrollable smoothBehavior" style="width: 400px">
 28 <div class="gradient" style="width: 100px; height: 500px;"></div>
 29 <div class="scrollable" style="width: 350px">
 30 <div class="gradient" style="width: 100px; height: 500px;"></div>
 31 <div class="scrollable" style="width: 300px">
 32 <div class="gradient" style="width: 100px; height: 500px;"></div>
 33 <div class="scrollable smoothBehavior" style="width: 250px">
 34 <div class="gradient" style="width: 100px; height: 500px;"></div>
 35 <div class="scrollable" style="width: 200px">
 36 <div class="gradient" style="width: 100px; height: 500px;"></div>
 37 <div id="elementToReveal" style="width: 10px; height: 10px; background: black;"></div>
 38 <div class="gradient" style="width: 100px; height: 500px;"></div>
 39 </div>
 40 <div class="gradient" style="width: 100px; height: 500px;"></div>
 41 </div>
 42 <div class="gradient" style="width: 100px; height: 500px;"></div>
 43 </div>
 44 <div class="gradient" style="width: 100px; height: 500px;"></div>
 45 </div>
 46 <div class="gradient" style="width: 100px; height: 500px;"></div>
 47 </div>
 48 </div>
 49</div>
 50<script>
 51 // The CSSOM-View spec and implementations follow different algorithms (scrolls performed in parallel, as inner-to-outer sequence or as outer-to-inner sequence).
 52 // See https://github.com/w3c/csswg-drafts/issues/3127
 53 promise_test(() => {
 54 return new Promise(function(resolve, reject) {
 55 var divs = document.querySelectorAll(".scrollable");
 56 divs.forEach((scrollableDiv) => {
 57 resetScroll(scrollableDiv);
 58 });
 59 elementToReveal.scrollIntoView({inline: "start", block: "start", behavior: "auto"});
 60 var scrollTop = new Map();
 61 var isSmooth = new Map();
 62 divs.forEach((scrollableDiv) => {
 63 scrollTop.set(scrollableDiv, scrollableDiv.scrollTop);
 64 isSmooth.set(scrollableDiv, scrollableDiv.classList.contains("smoothBehavior"));
 65 // If scroll operations are not performed in parallel, scroll boxes with instant behavior might also need to wait for their predecessors.
 66 if (isSmooth.get(scrollableDiv))
 67 assert_less_than(scrollTop.get(scrollableDiv), 500, "Element with smooth behavior should not scroll immediately");
 68 });
 69
 70 observeScrolling(Array.from(divs), function(done) {
 71 try {
 72 divs.forEach((scrollableDiv) => {
 73 assert_less_than_equal(scrollTop.get(scrollableDiv), scrollableDiv.scrollTop, "ScrollTop keeps increasing");
 74 if (!isSmooth.get(scrollableDiv))
 75 assert_any(assert_equals, scrollableDiv.scrollTop, [0, 500], "Element with instant behavior should jump to the final position");
 76 if (done)
 77 assert_equals(scrollableDiv.scrollTop, 500, "Final value of scrollTop");
 78 scrollTop.set(scrollableDiv, scrollableDiv.scrollTop);
 79 });
 80 } catch(e) {
 81 reject(e);
 82 }
 83 if (done)
 84 resolve();
 85 });
 86 });
 87 }, "scrollIntoView with nested elements with different scroll-behavior");
 88</script>

LayoutTests/fast/scrolling/ios/scroll-behavior-smooth-positions-expected.txt

 1
 2PASS Scroll positions when performing smooth scrolling from (0, 0) to (500, 250) using scroll()
 3PASS Scroll positions when performing smooth scrolling from (1000, 0) to (500, 250) using scroll()
 4PASS Scroll positions when performing smooth scrolling from (0, 500) to (500, 250) using scroll()
 5PASS Scroll positions when performing smooth scrolling from (1000, 500) to (500, 250) using scroll()
 6PASS Scroll positions when performing smooth scrolling from (0, 0) to (500, 250) using scrollTo()
 7PASS Scroll positions when performing smooth scrolling from (1000, 0) to (500, 250) using scrollTo()
 8PASS Scroll positions when performing smooth scrolling from (0, 500) to (500, 250) using scrollTo()
 9PASS Scroll positions when performing smooth scrolling from (1000, 500) to (500, 250) using scrollTo()
 10PASS Scroll positions when performing smooth scrolling from (0, 0) to (500, 250) using scrollBy()
 11PASS Scroll positions when performing smooth scrolling from (1000, 0) to (500, 250) using scrollBy()
 12PASS Scroll positions when performing smooth scrolling from (0, 500) to (500, 250) using scrollBy()
 13PASS Scroll positions when performing smooth scrolling from (1000, 500) to (500, 250) using scrollBy()
 14PASS Scroll positions when performing smooth scrolling from (0, 0) to (500, 250) using scrollIntoView()
 15PASS Scroll positions when performing smooth scrolling from (1000, 0) to (500, 250) using scrollIntoView()
 16PASS Scroll positions when performing smooth scrolling from (0, 500) to (500, 250) using scrollIntoView()
 17PASS Scroll positions when performing smooth scrolling from (1000, 500) to (500, 250) using scrollIntoView()
 18PASS Scroll positions when aborting a smooth scrolling with another smooth scrolling
 19PASS Scroll positions when aborting a smooth scrolling with an instant scrolling
 20

LayoutTests/fast/scrolling/ios/scroll-behavior-smooth-positions.html

 1<!DOCTYPE html><!-- webkit-test-runner [ experimental:CSSOMViewSmoothScrollingEnabled=true internal:AsyncOverflowScrollingEnabled=true ] -->
 2<title>Testing scroll positions when scrolling an element with smooth behavior</title>
 3<meta name="timeout" content="long"/>
 4<link rel="author" title="Frédéric Wang" href="mailto:fwang@igalia.com">
 5<link rel="help" href="https://drafts.csswg.org/cssom-view/#propdef-scroll-behavior">
 6<link rel="help" href="https://drafts.csswg.org/cssom-view/#scrolling-box">
 7<script src="../../../resources/testharness.js"></script>
 8<script src="../../../resources/testharnessreport.js"></script>
 9<script src="resources/scroll-behavior.js"></script>
 10<style>
 11 .scrollable {
 12 overflow: auto;
 13 width: 400px;
 14 height: 200px;
 15 scroll-behavior: smooth;
 16 }
 17</style>
 18<div id="log">
 19</div>
 20<div id="overflowNode" class="scrollable">
 21 <div style="width: 2000px; height: 1000px; background: linear-gradient(135deg, red, green);">
 22 <span style="display: inline-block; width: 500px; height: 250px;"></span><span id="elementToReveal" style="display: inline-block; vertical-align: -15px; width: 10px; height: 15px; background: black;"></span>
 23 </div>
 24</div>
 25<script>
 26 // For smooth behavior, evolution of scroll positions over time is not specified by CSSOM View.
 27 // This test relies on the minimal assumption that scroll position functions are monotonic.
 28 ["scroll", "scrollTo", "scrollBy", "scrollIntoView"].forEach(function(scrollFunction) {
 29 [{left:0, top:0}, {left:1000, top:0}, {left:0, top:500}, {left:1000, top:500}].forEach((initial) => {
 30 var finalLeft = 500;
 31 var finalTop = 250;
 32 promise_test(() => {
 33 return new Promise(function(resolve, reject) {
 34 scrollNode(overflowNode, "scroll", "instant", initial.left, initial.top);
 35 var oldLeft = overflowNode.scrollLeft;
 36 var oldTop = overflowNode.scrollTop;
 37 assert_equals(oldLeft, initial.left, "ScrollLeft should be at initial position");
 38 assert_equals(oldTop, initial.top, "ScrollTop should be at initial position");
 39 if (scrollFunction === "scrollBy")
 40 scrollNode(overflowNode, scrollFunction, "smooth", finalLeft - initial.left, finalTop - initial.top);
 41 else
 42 scrollNode(overflowNode, scrollFunction, "smooth", finalLeft, finalTop);
 43 observeScrolling(overflowNode, function(done) {
 44 try {
 45 var newLeft = overflowNode.scrollLeft;
 46 var newTop = overflowNode.scrollTop;
 47 assert_less_than_equal(Math.hypot(finalLeft - newLeft, finalTop - newTop), Math.hypot(finalLeft - oldLeft, finalTop - oldTop), "Scroll position should move towards the final position");
 48 if (done) {
 49 assert_equals(newLeft, finalLeft, "ScrollLeft should reach final position");
 50 assert_equals(newTop, finalTop, "ScrollTop should reach final position");
 51 }
 52 oldLeft = newLeft;
 53 oldTop = newTop;
 54 } catch(e) {
 55 reject(e);
 56 }
 57 if (done)
 58 resolve();
 59 });
 60 });
 61 }, `Scroll positions when performing smooth scrolling from (${initial.left}, ${initial.top}) to (${finalLeft}, ${finalTop}) using ${scrollFunction}() `);
 62 });
 63 });
 64
 65 promise_test(() => {
 66 return new Promise(function(resolve, reject) {
 67 resetScroll(overflowNode);
 68 var initialScrollAborted = false;
 69 var scrollDirectionChanged = false;
 70 var oldLeft = overflowNode.scrollLeft;
 71 var oldTop = overflowNode.scrollTop;
 72 assert_equals(oldLeft, 0);
 73 assert_equals(oldTop, 0);
 74 scrollNode(overflowNode, "scroll", "smooth", 1500, 750);
 75 observeScrolling(overflowNode, function(done) {
 76 try {
 77 var newLeft = overflowNode.scrollLeft;
 78 var newTop = overflowNode.scrollTop;
 79 if (initialScrollAborted) {
 80 if (scrollDirectionChanged) {
 81 assert_greater_than_equal(oldLeft, newLeft, "ScrollLeft keeps decreasing");
 82 assert_greater_than_equal(oldTop, newTop, "ScrollTop keeps decreasing");
 83 } else
 84 scrollDirectionChanged = newLeft <= oldLeft && newTop <= oldTop;
 85 } else {
 86 assert_less_than_equal(oldLeft, newLeft, "ScrollLeft keeps increasing");
 87 assert_less_than_equal(oldTop, newTop, "ScrollTop keeps increasing");
 88 if (newLeft > 1000 && newTop > 500) {
 89 // Abort the initial scroll.
 90 initialScrollAborted = true;
 91 scrollNode(overflowNode, "scroll", "smooth", 500, 250);
 92 newLeft = overflowNode.scrollLeft;
 93 newTop = overflowNode.scrollTop;
 94 }
 95 }
 96 if (done) {
 97 assert_equals(newLeft, 500, "ScrollLeft should reach final position");
 98 assert_equals(newTop, 250, "ScrollTop should reach final position");
 99 }
 100 oldLeft = newLeft;
 101 oldTop = newTop;
 102 } catch(e) {
 103 reject(e);
 104 }
 105 if (done)
 106 resolve();
 107 });
 108 });
 109 }, "Scroll positions when aborting a smooth scrolling with another smooth scrolling");
 110
 111 promise_test(() => {
 112 return new Promise(function(resolve, reject) {
 113 resetScroll(overflowNode);
 114 var initialScrollAborted = false;
 115 var oldLeft = overflowNode.scrollLeft;
 116 var oldTop = overflowNode.scrollTop;
 117 assert_equals(oldLeft, 0);
 118 assert_equals(oldTop, 0);
 119 scrollNode(overflowNode, "scroll", "smooth", 1500, 750);
 120 observeScrolling(overflowNode, function(done) {
 121 try {
 122 var newLeft = overflowNode.scrollLeft;
 123 var newTop = overflowNode.scrollTop;
 124 if (!initialScrollAborted) {
 125 assert_less_than_equal(oldLeft, newLeft, "ScrollLeft keeps increasing");
 126 assert_less_than_equal(oldTop, newTop, "ScrollTop keeps increasing");
 127 if (newLeft > 1000 && newTop > 500) {
 128 // Abort the initial scroll.
 129 initialScrollAborted = true;
 130 scrollNode(overflowNode, "scroll", "instant", 500, 250);
 131 newLeft = overflowNode.scrollLeft;
 132 newTop = overflowNode.scrollTop;
 133 assert_equals(newLeft, 500, "ScrollLeft should reach final position");
 134 assert_equals(newTop, 250, "ScrollTop should reach final position");
 135 }
 136 }
 137 if (done) {
 138 assert_equals(newLeft, 500, "ScrollLeft should stay at final position");
 139 assert_equals(newTop, 250, "ScrollTop should stay at final position");
 140 }
 141 oldLeft = newLeft;
 142 oldTop = newTop;
 143 } catch(e) {
 144 reject(e);
 145 }
 146 if (done)
 147 resolve();
 148 });
 149 });
 150 }, "Scroll positions when aborting a smooth scrolling with an instant scrolling");
 151</script>

LayoutTests/fast/scrolling/ios/scroll-behavior-subframe-root-expected.txt

 1
 2PASS iframe loaded
 3PASS Subframe with auto scroll-behavior ; scroll() with default behavior
 4PASS Subframe with auto scroll-behavior ; scroll() with auto behavior
 5PASS Subframe with auto scroll-behavior ; scroll() with instant behavior
 6PASS Subframe with auto scroll-behavior ; scroll() with smooth behavior
 7PASS Subframe with smooth scroll-behavior ; scroll() with default behavior
 8PASS Subframe with smooth scroll-behavior ; scroll() with auto behavior
 9PASS Subframe with smooth scroll-behavior ; scroll() with instant behavior
 10PASS Subframe with smooth scroll-behavior ; scroll() with smooth behavior
 11PASS Subframe with auto scroll-behavior ; scrollTo() with default behavior
 12PASS Subframe with auto scroll-behavior ; scrollTo() with auto behavior
 13PASS Subframe with auto scroll-behavior ; scrollTo() with instant behavior
 14PASS Subframe with auto scroll-behavior ; scrollTo() with smooth behavior
 15PASS Subframe with smooth scroll-behavior ; scrollTo() with default behavior
 16PASS Subframe with smooth scroll-behavior ; scrollTo() with auto behavior
 17PASS Subframe with smooth scroll-behavior ; scrollTo() with instant behavior
 18PASS Subframe with smooth scroll-behavior ; scrollTo() with smooth behavior
 19PASS Subframe with auto scroll-behavior ; scrollBy() with default behavior
 20PASS Subframe with auto scroll-behavior ; scrollBy() with auto behavior
 21PASS Subframe with auto scroll-behavior ; scrollBy() with instant behavior
 22PASS Subframe with auto scroll-behavior ; scrollBy() with smooth behavior
 23PASS Subframe with smooth scroll-behavior ; scrollBy() with default behavior
 24PASS Subframe with smooth scroll-behavior ; scrollBy() with auto behavior
 25PASS Subframe with smooth scroll-behavior ; scrollBy() with instant behavior
 26PASS Subframe with smooth scroll-behavior ; scrollBy() with smooth behavior
 27PASS Subframe with auto scroll-behavior ; scrollIntoView() with default behavior
 28PASS Subframe with auto scroll-behavior ; scrollIntoView() with auto behavior
 29PASS Subframe with auto scroll-behavior ; scrollIntoView() with instant behavior
 30PASS Subframe with auto scroll-behavior ; scrollIntoView() with smooth behavior
 31PASS Subframe with smooth scroll-behavior ; scrollIntoView() with default behavior
 32PASS Subframe with smooth scroll-behavior ; scrollIntoView() with auto behavior
 33PASS Subframe with smooth scroll-behavior ; scrollIntoView() with instant behavior
 34PASS Subframe with smooth scroll-behavior ; scrollIntoView() with smooth behavior
 35PASS Aborting an ongoing smooth scrolling on a subframe with another smooth scrolling
 36PASS Aborting an ongoing smooth scrolling on a subframe with an instant scrolling
 37

LayoutTests/fast/scrolling/ios/scroll-behavior-subframe-root.html

 1<!DOCTYPE html><!-- webkit-test-runner [ experimental:CSSOMViewSmoothScrollingEnabled=true internal:AsyncOverflowScrollingEnabled=true internal:AsyncFrameScrollingEnabled=true ] -->
 2<title>Testing scrollOptions' behavior for Element.scroll* and scroll-behavior on the root of a subframe</title>
 3<meta name="timeout" content="long"/>
 4<link rel="author" title="Frédéric Wang" href="mailto:fwang@igalia.com">
 5<link rel="help" href="https://drafts.csswg.org/cssom-view/#propdef-scroll-behavior">
 6<link rel="help" href="https://drafts.csswg.org/cssom-view/#scrolling-box">
 7<script src="../../../resources/testharness.js"></script>
 8<script src="../../../resources/testharnessreport.js"></script>
 9<script src="resources/scroll-behavior.js"></script>
 10<div id="log">
 11</div>
 12<iframe id="iframeNode" width="400px" height="200px" srcdoc="<!DOCTYPE>
 13<html>
 14 <style>
 15 body {
 16 margin: 0;
 17 }
 18 .autoBehavior {
 19 scroll-behavior: auto;
 20 }
 21 .smoothBehavior {
 22 scroll-behavior: smooth;
 23 }
 24 </style>
 25 <body>
 26 <div style='width: 2000px; height: 1000px; background: linear-gradient(135deg, red, green);'>
 27 <span style='display: inline-block; width: 500px; height: 250px;'></span><span id='elementToReveal' style='display: inline-block; vertical-align: -15px; width: 10px; height: 15px; background: black;'></span>
 28 </div>
 29 </body>
 30</html>">
 31</iframe>
 32<script>
 33 var iframeLoadTest = async_test("iframe loaded");
 34 var scrollingElement, styledElement, elementToReveal;
 35 var elementToRevealLeft = 500;
 36 var elementToRevealTop = 250;
 37 iframeNode.addEventListener("load", iframeLoadTest.step_func_done(() => {
 38 scrollingElement = iframeNode.contentDocument.scrollingElement;
 39 styledElement = iframeNode.contentDocument.documentElement;
 40 elementToReveal = iframeNode.contentDocument.getElementById("elementToReveal");
 41
 42 ["scroll", "scrollTo", "scrollBy", "scrollIntoView"].forEach((scrollFunction) => {
 43 promise_test(() => {
 44 resetScroll(scrollingElement);
 45 setScrollBehavior(styledElement, "autoBehavior");
 46 assert_equals(scrollingElement.scrollLeft, 0);
 47 assert_equals(scrollingElement.scrollTop, 0);
 48 scrollNode(scrollingElement, scrollFunction, null, elementToRevealLeft, elementToRevealTop);
 49 assert_equals(scrollingElement.scrollLeft, elementToRevealLeft, "Should set scrollLeft immediately");
 50 assert_equals(scrollingElement.scrollTop, elementToRevealTop, "Should set scrollTop immediately");
 51 return new Promise((resolve) => { resolve(); });
 52 }, `Subframe with auto scroll-behavior ; ${scrollFunction}() with default behavior`);
 53
 54 promise_test(() => {
 55 resetScroll(scrollingElement);
 56 setScrollBehavior(styledElement, "autoBehavior");
 57 assert_equals(scrollingElement.scrollLeft, 0);
 58 assert_equals(scrollingElement.scrollTop, 0);
 59 scrollNode(scrollingElement, scrollFunction, "auto", elementToRevealLeft, elementToRevealTop);
 60 assert_equals(scrollingElement.scrollLeft, elementToRevealLeft, "Should set scrollLeft immediately");
 61 assert_equals(scrollingElement.scrollTop, elementToRevealTop, "Should set scrollTop immediately");
 62 return new Promise((resolve) => { resolve(); });
 63 }, `Subframe with auto scroll-behavior ; ${scrollFunction}() with auto behavior`);
 64
 65 promise_test(() => {
 66 resetScroll(scrollingElement);
 67 setScrollBehavior(styledElement, "autoBehavior");
 68 assert_equals(scrollingElement.scrollLeft, 0);
 69 assert_equals(scrollingElement.scrollTop, 0);
 70 scrollNode(scrollingElement, scrollFunction, "instant", elementToRevealLeft, elementToRevealTop);
 71 assert_equals(scrollingElement.scrollLeft, elementToRevealLeft, "Should set scrollLeft immediately");
 72 assert_equals(scrollingElement.scrollTop, elementToRevealTop, "Should set scrollTop immediately");
 73 return new Promise((resolve) => { resolve(); });
 74 }, `Subframe with auto scroll-behavior ; ${scrollFunction}() with instant behavior`);
 75
 76 promise_test(() => {
 77 resetScroll(scrollingElement);
 78 setScrollBehavior(styledElement, "autoBehavior");
 79 assert_equals(scrollingElement.scrollLeft, 0);
 80 assert_equals(scrollingElement.scrollTop, 0);
 81 scrollNode(scrollingElement, scrollFunction, "smooth", elementToRevealLeft, elementToRevealTop);
 82 assert_less_than(scrollingElement.scrollLeft, elementToRevealLeft, "Should not set scrollLeft immediately");
 83 assert_less_than(scrollingElement.scrollTop, elementToRevealTop, "Should not set scrollTop immediately");
 84 return waitForScrollEnd(scrollingElement).then(() => {
 85 assert_equals(scrollingElement.scrollLeft, elementToRevealLeft, "Final value of scrollLeft");
 86 assert_equals(scrollingElement.scrollTop, elementToRevealTop, "Final value of scrollTop");
 87 });
 88 }, `Subframe with auto scroll-behavior ; ${scrollFunction}() with smooth behavior`);
 89
 90 promise_test(() => {
 91 resetScroll(scrollingElement);
 92 setScrollBehavior(styledElement, "smoothBehavior");
 93 assert_equals(scrollingElement.scrollLeft, 0);
 94 assert_equals(scrollingElement.scrollTop, 0);
 95 scrollNode(scrollingElement, scrollFunction, null, elementToRevealLeft, elementToRevealTop);
 96 assert_less_than(scrollingElement.scrollLeft, elementToRevealLeft, "Should not set scrollLeft immediately");
 97 assert_less_than(scrollingElement.scrollTop, elementToRevealTop, "Should not set scrollTop immediately");
 98 return waitForScrollEnd(scrollingElement).then(() => {
 99 assert_equals(scrollingElement.scrollLeft, elementToRevealLeft, "Final value of scrollLeft");
 100 assert_equals(scrollingElement.scrollTop, elementToRevealTop, "Final value of scrollTop");
 101 });
 102 }, `Subframe with smooth scroll-behavior ; ${scrollFunction}() with default behavior`);
 103
 104 promise_test(() => {
 105 resetScroll(scrollingElement);
 106 setScrollBehavior(styledElement, "smoothBehavior");
 107 assert_equals(scrollingElement.scrollLeft, 0);
 108 assert_equals(scrollingElement.scrollTop, 0);
 109 scrollNode(scrollingElement, scrollFunction, "auto", elementToRevealLeft, elementToRevealTop);
 110 assert_less_than(scrollingElement.scrollLeft, elementToRevealLeft, "Should not set scrollLeft immediately");
 111 assert_less_than(scrollingElement.scrollTop, elementToRevealTop, "Should not set scrollTop immediately");
 112 return waitForScrollEnd(scrollingElement).then(() => {
 113 assert_equals(scrollingElement.scrollLeft, elementToRevealLeft, "Final value of scrollLeft");
 114 assert_equals(scrollingElement.scrollTop, elementToRevealTop, "Final value of scrollTop");
 115 });
 116 }, `Subframe with smooth scroll-behavior ; ${scrollFunction}() with auto behavior`);
 117
 118 promise_test(() => {
 119 resetScroll(scrollingElement);
 120 setScrollBehavior(styledElement, "smoothBehavior");
 121 assert_equals(scrollingElement.scrollLeft, 0);
 122 assert_equals(scrollingElement.scrollTop, 0);
 123 scrollNode(scrollingElement, scrollFunction, "instant", elementToRevealLeft, elementToRevealTop);
 124 assert_equals(scrollingElement.scrollLeft, elementToRevealLeft, "Should set scrollLeft immediately");
 125 assert_equals(scrollingElement.scrollTop, elementToRevealTop, "Should set scrollTop immediately");
 126 return new Promise((resolve) => { resolve(); });
 127 }, `Subframe with smooth scroll-behavior ; ${scrollFunction}() with instant behavior`);
 128
 129 promise_test(() => {
 130 resetScroll(scrollingElement);
 131 setScrollBehavior(styledElement, "smoothBehavior");
 132 assert_equals(scrollingElement.scrollLeft, 0);
 133 assert_equals(scrollingElement.scrollTop, 0);
 134 scrollNode(scrollingElement, scrollFunction, "smooth", elementToRevealLeft, elementToRevealTop);
 135 assert_less_than(scrollingElement.scrollLeft, elementToRevealLeft, "Should not set scrollLeft immediately");
 136 assert_less_than(scrollingElement.scrollTop, elementToRevealTop, "Should not set scrollTop immediately");
 137 return waitForScrollEnd(scrollingElement).then(() => {
 138 assert_equals(scrollingElement.scrollLeft, elementToRevealLeft, "Final value of scrollLeft");
 139 assert_equals(scrollingElement.scrollTop, elementToRevealTop, "Final value of scrollTop");
 140 });
 141 }, `Subframe with smooth scroll-behavior ; ${scrollFunction}() with smooth behavior`);
 142 });
 143
 144 promise_test(() => {
 145 resetScroll(scrollingElement);
 146 setScrollBehavior(styledElement, "smoothBehavior");
 147 assert_equals(scrollingElement.scrollLeft, 0);
 148 assert_equals(scrollingElement.scrollTop, 0);
 149 scrollNode(scrollingElement, "scroll", "smooth", elementToRevealLeft, elementToRevealTop);
 150 scrollNode(scrollingElement, "scroll", "smooth", elementToRevealLeft / 2, elementToRevealTop / 2);
 151 return waitForScrollEnd(scrollingElement).then(() => {
 152 assert_equals(scrollingElement.scrollLeft, elementToRevealLeft / 2, "Final value of scrollLeft");
 153 assert_equals(scrollingElement.scrollTop, elementToRevealTop / 2, "Final value of scrollTop");
 154 });
 155 }, "Aborting an ongoing smooth scrolling on a subframe with another smooth scrolling");
 156
 157 promise_test(() => {
 158 resetScroll(scrollingElement);
 159 setScrollBehavior(styledElement, "smoothBehavior");
 160 assert_equals(scrollingElement.scrollLeft, 0);
 161 assert_equals(scrollingElement.scrollTop, 0);
 162 scrollNode(scrollingElement, "scroll", "smooth", elementToRevealLeft, elementToRevealTop);
 163 scrollNode(scrollingElement, "scroll", "instant", 0, 0);
 164 return waitForScrollEnd(scrollingElement).then(() => {
 165 assert_equals(scrollingElement.scrollLeft, 0, "Final value of scrollLeft");
 166 assert_equals(scrollingElement.scrollTop, 0, "Final value of scrollTop");
 167 });
 168 }, "Aborting an ongoing smooth scrolling on a subframe with an instant scrolling");
 169 }));
 170</script>

LayoutTests/fast/scrolling/ios/scroll-behavior-subframe-window-expected.txt

 1
 2PASS iframe loaded
 3PASS Main frame with auto scroll-behavior ; scroll() with default behavior
 4PASS Main frame with auto scroll-behavior ; scroll() with auto behavior
 5PASS Main frame with auto scroll-behavior ; scroll() with instant behavior
 6PASS Main frame with auto scroll-behavior ; scroll() with smooth behavior
 7PASS Main frame with smooth scroll-behavior ; scroll() with default behavior
 8PASS Main frame with smooth scroll-behavior ; scroll() with auto behavior
 9PASS Main frame with smooth scroll-behavior ; scroll() with instant behavior
 10PASS Main frame with smooth scroll-behavior ; scroll() with smooth behavior
 11PASS Main frame with auto scroll-behavior ; scrollTo() with default behavior
 12PASS Main frame with auto scroll-behavior ; scrollTo() with auto behavior
 13PASS Main frame with auto scroll-behavior ; scrollTo() with instant behavior
 14PASS Main frame with auto scroll-behavior ; scrollTo() with smooth behavior
 15PASS Main frame with smooth scroll-behavior ; scrollTo() with default behavior
 16PASS Main frame with smooth scroll-behavior ; scrollTo() with auto behavior
 17PASS Main frame with smooth scroll-behavior ; scrollTo() with instant behavior
 18PASS Main frame with smooth scroll-behavior ; scrollTo() with smooth behavior
 19PASS Main frame with auto scroll-behavior ; scrollBy() with default behavior
 20PASS Main frame with auto scroll-behavior ; scrollBy() with auto behavior
 21PASS Main frame with auto scroll-behavior ; scrollBy() with instant behavior
 22PASS Main frame with auto scroll-behavior ; scrollBy() with smooth behavior
 23PASS Main frame with smooth scroll-behavior ; scrollBy() with default behavior
 24PASS Main frame with smooth scroll-behavior ; scrollBy() with auto behavior
 25PASS Main frame with smooth scroll-behavior ; scrollBy() with instant behavior
 26PASS Main frame with smooth scroll-behavior ; scrollBy() with smooth behavior
 27PASS Aborting an ongoing smooth scrolling on the main frame with another smooth scrolling
 28PASS Aborting an ongoing smooth scrolling on the main frame with an instant scrolling
 29

LayoutTests/fast/scrolling/ios/scroll-behavior-subframe-window.html

 1<!DOCTYPE html><!-- webkit-test-runner [ experimental:CSSOMViewSmoothScrollingEnabled=true internal:AsyncOverflowScrollingEnabled=true internal:AsyncFrameScrollingEnabled=true ] -->
 2<title>Testing scrollOptions' behavior for Element.scroll* and scroll-behavior on the root of a subframe</title>
 3<meta name="timeout" content="long"/>
 4<link rel="author" title="Frédéric Wang" href="mailto:fwang@igalia.com">
 5<link rel="help" href="https://drafts.csswg.org/cssom-view/#propdef-scroll-behavior">
 6<link rel="help" href="https://drafts.csswg.org/cssom-view/#scrolling-box">
 7<script src="../../../resources/testharness.js"></script>
 8<script src="../../../resources/testharnessreport.js"></script>
 9<script src="resources/scroll-behavior.js"></script>
 10<div id="log">
 11</div>
 12<iframe id="iframeNode" width="400px" height="200px" srcdoc="<!DOCTYPE>
 13<html>
 14 <style>
 15 body {
 16 margin: 0;
 17 }
 18 .autoBehavior {
 19 scroll-behavior: auto;
 20 }
 21 .smoothBehavior {
 22 scroll-behavior: smooth;
 23 }
 24 </style>
 25 <body>
 26 <div style='width: 2000px; height: 1000px; background: linear-gradient(135deg, red, green);'>
 27 <span style='display: inline-block; width: 500px; height: 250px;'></span><span id='elementToReveal' style='display: inline-block; vertical-align: -15px; width: 10px; height: 15px; background: black;'></span>
 28 </div>
 29 </body>
 30</html>">
 31</iframe>
 32<script>
 33 var iframeLoadTest = async_test("iframe loaded");
 34 var scrollingWindow, styledElement, elementToReveal;
 35 var elementToRevealLeft = 500;
 36 var elementToRevealTop = 250;
 37 iframeNode.addEventListener("load", iframeLoadTest.step_func_done(() => {
 38 scrollingWindow = iframeNode.contentWindow;
 39 styledElement = iframeNode.contentDocument.documentElement;
 40 elementToReveal = iframeNode.contentDocument.getElementById("elementToReveal");
 41
 42 ["scroll", "scrollTo", "scrollBy"].forEach((scrollFunction) => {
 43 promise_test(() => {
 44 resetScrollForWindow(scrollingWindow);
 45 setScrollBehavior(styledElement, "autoBehavior");
 46 assert_equals(scrollingWindow.scrollX, 0);
 47 assert_equals(scrollingWindow.scrollY, 0);
 48 scrollWindow(scrollingWindow, scrollFunction, null, elementToRevealLeft, elementToRevealTop);
 49 assert_equals(scrollingWindow.scrollX, elementToRevealLeft, "Should set scrollLeft immediately");
 50 assert_equals(scrollingWindow.scrollY, elementToRevealTop, "Should set scrollTop immediately");
 51 return new Promise((resolve) => { resolve(); });
 52 }, `Main frame with auto scroll-behavior ; ${scrollFunction}() with default behavior`);
 53
 54 promise_test(() => {
 55 resetScrollForWindow(scrollingWindow);
 56 setScrollBehavior(styledElement, "autoBehavior");
 57 assert_equals(scrollingWindow.scrollX, 0);
 58 assert_equals(scrollingWindow.scrollY, 0);
 59 scrollWindow(scrollingWindow, scrollFunction, "auto", elementToRevealLeft, elementToRevealTop);
 60 assert_equals(scrollingWindow.scrollX, elementToRevealLeft, "Should set scrollLeft immediately");
 61 assert_equals(scrollingWindow.scrollY, elementToRevealTop, "Should set scrollTop immediately");
 62 return new Promise((resolve) => { resolve(); });
 63 }, `Main frame with auto scroll-behavior ; ${scrollFunction}() with auto behavior`);
 64
 65 promise_test(() => {
 66 resetScrollForWindow(scrollingWindow);
 67 setScrollBehavior(styledElement, "autoBehavior");
 68 assert_equals(scrollingWindow.scrollX, 0);
 69 assert_equals(scrollingWindow.scrollY, 0);
 70 scrollWindow(scrollingWindow, scrollFunction, "instant", elementToRevealLeft, elementToRevealTop);
 71 assert_equals(scrollingWindow.scrollX, elementToRevealLeft, "Should set scrollLeft immediately");
 72 assert_equals(scrollingWindow.scrollY, elementToRevealTop, "Should set scrollTop immediately");
 73 return new Promise((resolve) => { resolve(); });
 74 }, `Main frame with auto scroll-behavior ; ${scrollFunction}() with instant behavior`);
 75
 76 promise_test(() => {
 77 resetScrollForWindow(scrollingWindow);
 78 setScrollBehavior(styledElement, "autoBehavior");
 79 assert_equals(scrollingWindow.scrollX, 0);
 80 assert_equals(scrollingWindow.scrollY, 0);
 81 scrollWindow(scrollingWindow, scrollFunction, "smooth", elementToRevealLeft, elementToRevealTop);
 82 assert_less_than(scrollingWindow.scrollX, elementToRevealLeft, "Should not set scrollLeft immediately");
 83 assert_less_than(scrollingWindow.scrollY, elementToRevealTop, "Should not set scrollTop immediately");
 84 return waitForScrollEnd(scrollingWindow.document.scrollingElement).then(() => {
 85 assert_equals(scrollingWindow.scrollX, elementToRevealLeft, "Final value of scrollLeft");
 86 assert_equals(scrollingWindow.scrollY, elementToRevealTop, "Final value of scrollTop");
 87 });
 88 }, `Main frame with auto scroll-behavior ; ${scrollFunction}() with smooth behavior`);
 89
 90 promise_test(() => {
 91 resetScrollForWindow(scrollingWindow);
 92 setScrollBehavior(styledElement, "smoothBehavior");
 93 assert_equals(scrollingWindow.scrollX, 0);
 94 assert_equals(scrollingWindow.scrollY, 0);
 95 scrollWindow(scrollingWindow, scrollFunction, null, elementToRevealLeft, elementToRevealTop);
 96 assert_less_than(scrollingWindow.scrollX, elementToRevealLeft, "Should not set scrollLeft immediately");
 97 assert_less_than(scrollingWindow.scrollY, elementToRevealTop, "Should not set scrollTop immediately");
 98 return waitForScrollEnd(scrollingWindow.document.scrollingElement).then(() => {
 99 assert_equals(scrollingWindow.scrollX, elementToRevealLeft, "Final value of scrollLeft");
 100 assert_equals(scrollingWindow.scrollY, elementToRevealTop, "Final value of scrollTop");
 101 });
 102 }, `Main frame with smooth scroll-behavior ; ${scrollFunction}() with default behavior`);
 103
 104 promise_test(() => {
 105 resetScrollForWindow(scrollingWindow);
 106 setScrollBehavior(styledElement, "smoothBehavior");
 107 assert_equals(scrollingWindow.scrollX, 0);
 108 assert_equals(scrollingWindow.scrollY, 0);
 109 scrollWindow(scrollingWindow, scrollFunction, "auto", elementToRevealLeft, elementToRevealTop);
 110 assert_less_than(scrollingWindow.scrollX, elementToRevealLeft, "Should not set scrollLeft immediately");
 111 assert_less_than(scrollingWindow.scrollY, elementToRevealTop, "Should not set scrollTop immediately");
 112 return waitForScrollEnd(scrollingWindow.document.scrollingElement).then(() => {
 113 assert_equals(scrollingWindow.scrollX, elementToRevealLeft, "Final value of scrollLeft");
 114 assert_equals(scrollingWindow.scrollY, elementToRevealTop, "Final value of scrollTop");
 115 });
 116 }, `Main frame with smooth scroll-behavior ; ${scrollFunction}() with auto behavior`);
 117
 118 promise_test(() => {
 119 resetScrollForWindow(scrollingWindow);
 120 setScrollBehavior(styledElement, "smoothBehavior");
 121 assert_equals(scrollingWindow.scrollX, 0);
 122 assert_equals(scrollingWindow.scrollY, 0);
 123 scrollWindow(scrollingWindow, scrollFunction, "instant", elementToRevealLeft, elementToRevealTop);
 124 assert_equals(scrollingWindow.scrollX, elementToRevealLeft, "Should set scrollLeft immediately");
 125 assert_equals(scrollingWindow.scrollY, elementToRevealTop, "Should set scrollTop immediately");
 126 return new Promise((resolve) => { resolve(); });
 127 }, `Main frame with smooth scroll-behavior ; ${scrollFunction}() with instant behavior`);
 128
 129 promise_test(() => {
 130 resetScrollForWindow(scrollingWindow);
 131 setScrollBehavior(styledElement, "smoothBehavior");
 132 assert_equals(scrollingWindow.scrollX, 0);
 133 assert_equals(scrollingWindow.scrollY, 0);
 134 scrollWindow(scrollingWindow, scrollFunction, "smooth", elementToRevealLeft, elementToRevealTop);
 135 assert_less_than(scrollingWindow.scrollX, elementToRevealLeft, "Should not set scrollLeft immediately");
 136 assert_less_than(scrollingWindow.scrollY, elementToRevealTop, "Should not set scrollTop immediately");
 137 return waitForScrollEnd(scrollingWindow.document.scrollingElement).then(() => {
 138 assert_equals(scrollingWindow.scrollX, elementToRevealLeft, "Final value of scrollLeft");
 139 assert_equals(scrollingWindow.scrollY, elementToRevealTop, "Final value of scrollTop");
 140 });
 141 }, `Main frame with smooth scroll-behavior ; ${scrollFunction}() with smooth behavior`);
 142 });
 143
 144 promise_test(() => {
 145 resetScrollForWindow(scrollingWindow);
 146 setScrollBehavior(styledElement, "smoothBehavior");
 147 assert_equals(scrollingWindow.scrollX, 0);
 148 assert_equals(scrollingWindow.scrollY, 0);
 149 scrollWindow(scrollingWindow, "scroll", "smooth", elementToRevealLeft, elementToRevealTop);
 150 scrollWindow(scrollingWindow, "scroll", "smooth", elementToRevealLeft / 2, elementToRevealTop / 2);
 151 return waitForScrollEnd(scrollingWindow.document.scrollingElement).then(() => {
 152 assert_equals(scrollingWindow.scrollX, elementToRevealLeft / 2, "Final value of scrollLeft");
 153 assert_equals(scrollingWindow.scrollY, elementToRevealTop / 2, "Final value of scrollTop");
 154 });
 155 }, "Aborting an ongoing smooth scrolling on the main frame with another smooth scrolling");
 156
 157 promise_test(() => {
 158 resetScrollForWindow(scrollingWindow);
 159 setScrollBehavior(styledElement, "smoothBehavior");
 160 assert_equals(scrollingWindow.scrollX, 0);
 161 assert_equals(scrollingWindow.scrollY, 0);
 162 scrollWindow(scrollingWindow, "scroll", "smooth", elementToRevealLeft, elementToRevealTop);
 163 scrollWindow(scrollingWindow, "scroll", "instant", 0, 0);
 164 return waitForScrollEnd(scrollingWindow.document.scrollingElement).then(() => {
 165 assert_equals(scrollingWindow.scrollX, 0, "Final value of scrollLeft");
 166 assert_equals(scrollingWindow.scrollY, 0, "Final value of scrollTop");
 167 });
 168 }, "Aborting an ongoing smooth scrolling on the main frame with an instant scrolling");
 169
 170 }));
 171</script>

Source/WebCore/ChangeLog

 12019-12-11 Cathie Chen <cathiechen@igalia.com>
 2
 3 Add support for scroll behavior relies on native scroll interfaces for iOS platform
 4 https://bugs.webkit.org/show_bug.cgi?id=204936
 5
 6 Reviewed by NOBODY (OOPS!).
 7
 8 Based on the patch by Frédéric Wang.
 9
 10 This patch support native scroll animation on iOS platform. It relies on UIScrollView's
 11 native scroll animation support and is executed in the UI process.
 12
 13 Tests: fast/scrolling/ios/scroll-behavior-default-css.html
 14 fast/scrolling/ios/scroll-behavior-element.html
 15 fast/scrolling/ios/scroll-behavior-main-frame-root.html
 16 fast/scrolling/ios/scroll-behavior-main-frame-window.html
 17 fast/scrolling/ios/scroll-behavior-scrollintoview-nested.html
 18 fast/scrolling/ios/scroll-behavior-smooth-positions.html
 19 fast/scrolling/ios/scroll-behavior-subframe-root.html
 20 fast/scrolling/ios/scroll-behavior-subframe-window.html
 21
 22 * page/FrameView.cpp:
 23 (WebCore::FrameView::scrollToOffsetWithAnimation): Requests a native scroll animation by calling animated requestScrollPositionUpdate().
 24 * page/scrolling/AsyncScrollingCoordinator.cpp:
 25 (WebCore::AsyncScrollingCoordinator::requestScrollPositionUpdate): Add a flag to indicate if this is an animated scroll or not.
 26 (WebCore::AsyncScrollingCoordinator::setScrollAnimationInProgress): Update the scroll animation status from the UI process.
 27 * page/scrolling/AsyncScrollingCoordinator.h:
 28 * page/scrolling/ScrollingStateScrollingNode.cpp:
 29 (WebCore::ScrollingStateScrollingNode::ScrollingStateScrollingNode): Add m_requestedScrollPositionWithAnimation to indicate it's animated.
 30 (WebCore::ScrollingStateScrollingNode::setRequestedScrollPosition): Ditto.
 31 (WebCore::ScrollingStateScrollingNode::dumpProperties const): Ditto.
 32 * page/scrolling/ScrollingStateScrollingNode.h:
 33 (WebCore::ScrollingStateScrollingNode::requestedScrollPositionWithAnimation const): Ditto.
 34 * page/scrolling/ScrollingTree.h:
 35 (WebCore::ScrollingTree::scrollingTreeNodeIsScrollAnimationInProgressDidChange): Update the scroll animation status.
 36 (WebCore::ScrollingTree::scrollingTreeNodeRequestsScroll): Add a flag to indicate if this is an animated scroll or not.
 37 * page/scrolling/ScrollingTreeScrollingNode.cpp:
 38 (WebCore::ScrollingTreeScrollingNode::commitStateAfterChildren): Add a flag to indicate the scroll is animated or not.
 39 (WebCore::ScrollingTreeScrollingNode::scrollTo): If needSyncScrollPosition is true, send the scroll position to the Web process, even if the scroll position doesn't change.
 40 Maintain the status of m_stopScrollAnimation and m_requestAnimatedScroll.
 41 (WebCore::ScrollingTreeScrollingNode::currentScrollPositionChanged): Animated scroll won't change the scroll position immediately, so don't notify the scrolling info now.
 42 (WebCore::ScrollingTreeScrollingNode::setRequestAnimatedScroll): m_requestAnimatedScroll indicates that this is an animated scroll request.
 43 (WebCore::ScrollingTreeScrollingNode::requestAnimatedScroll const): Ditto.
 44 (WebCore::ScrollingTreeScrollingNode::setScrollAnimationInProgress): Maintain the scroll animation status.
 45 (WebCore::ScrollingTreeScrollingNode::scrollAnimationInProgress const): Ditto.
 46 (WebCore::ScrollingTreeScrollingNode::setNeedsStopCurrentScrollAnimation): If the Node is performing a scroll animation, the previous scroll animation should stop first.
 47 (WebCore::ScrollingTreeScrollingNode::needsStopCurrentScrollAnimation const): Ditto.
 48 * page/scrolling/ScrollingTreeScrollingNode.h:
 49 * platform/ScrollTypes.h: Add ScrollBehaviorType to indicate it's instant or smooth scroll.
 50 Add ScrollBehaviorStatus to indicate the status of scrolling.
 51 * platform/ScrollView.cpp:
 52 (WebCore::ScrollView::setScrollPosition): Update ScrollBehaviorType.
 53 * platform/ScrollableArea.cpp:
 54 (WebCore::ScrollableArea::ScrollableArea): Add m_currentScrollBehaviorType.
 55 * platform/ScrollableArea.h:
 56 (WebCore::ScrollableArea::currentScrollBehaviorType const): Maintain currentScrollBehaviorType.
 57 (WebCore::ScrollableArea::setCurrentScrollBehaviorType):
 58 * rendering/RenderLayer.cpp:
 59 (WebCore::RenderLayer::scrollToOffset): Send a quest of native scroll.
 60 (WebCore::RenderLayer::scrollToOffsetWithAnimation): Requests a native scroll animation by calling animated requestScrollPositionUpdate().
 61
1622019-12-10 Cathie Chen <cathiechen@igalia.com>
263
364 Add support for scroll behavior relies on ScrollAnimation of the Web process

Source/WebCore/page/FrameView.cpp

@@void FrameView::scrollToOffsetWithAnimation(const ScrollOffset& offset, ScrollTy
36683668 auto previousScrollType = currentScrollType();
36693669 setCurrentScrollType(scrollType);
36703670
 3671#if PLATFORM(IOS_FAMILY) && ENABLE(ASYNC_SCROLLING)
 3672 setCurrentScrollBehaviorType(ScrollBehaviorType::Smooth);
 3673 if (requestScrollPositionUpdate(scrollPositionFromOffset(offset))) {
 3674 setCurrentScrollType(previousScrollType);
 3675 return;
 3676 }
 3677#endif
 3678
36713679 if (currentScrollBehaviorStatus() == ScrollBehaviorStatus::InNonNativeAnimation)
36723680 scrollAnimator().cancelAnimations();
36733681 if (offset != this->scrollOffset())

Source/WebCore/page/scrolling/AsyncScrollingCoordinator.cpp

@@bool AsyncScrollingCoordinator::requestScrollPositionUpdate(ScrollableArea& scro
248248
249249 bool inBackForwardCache = frameView->frame().document()->backForwardCacheState() != Document::NotInBackForwardCache;
250250 bool inProgrammaticScroll = scrollableArea.currentScrollType() == ScrollType::Programmatic;
251  if (inProgrammaticScroll || inBackForwardCache)
 251
 252 bool updateScrollPosition = inProgrammaticScroll || inBackForwardCache;
 253#if PLATFORM(IOS_FAMILY)
 254 bool animated = scrollableArea.currentScrollBehaviorType() == ScrollBehaviorType::Smooth;
 255 // The scroll position of animated scrolling will be set by the UI process. So shouldn't set it now.
 256 updateScrollPosition = !animated && updateScrollPosition;
 257#endif
 258 if (updateScrollPosition)
252259 updateScrollPositionAfterAsyncScroll(scrollingNodeID, scrollPosition, { }, ScrollType::Programmatic, ScrollingLayerPositionAction::Set);
253260
254261 // If this frame view's document is being put into the back/forward cache, we don't want to update our

@@bool AsyncScrollingCoordinator::requestScrollPositionUpdate(ScrollableArea& scro
260267 if (!stateNode)
261268 return false;
262269
 270#if PLATFORM(IOS_FAMILY)
 271 auto status = animated ? ScrollBehaviorStatus::InNativeAnimation : ScrollBehaviorStatus::NotInAnimation;
 272 scrollableArea.setScrollBehaviorStatus(status);
 273
 274 stateNode->setRequestedScrollPosition(scrollPosition, inProgrammaticScroll, animated);
 275#else
263276 stateNode->setRequestedScrollPosition(scrollPosition, inProgrammaticScroll);
 277#endif
264278 return true;
265279}
266280

@@void AsyncScrollingCoordinator::scheduleUpdateScrollPositionAfterAsyncScroll(Scr
291305 m_updateNodeScrollPositionTimer.startOneShot(0_s);
292306}
293307
 308#if PLATFORM(IOS_FAMILY)
 309void AsyncScrollingCoordinator::setScrollAnimationInProgress(ScrollingNodeID nodeID, bool isScrollAnimationInProgress)
 310{
 311 ASSERT(isMainThread());
 312
 313 if (!m_page)
 314 return;
 315
 316 auto* frameView = frameViewForScrollingNode(nodeID);
 317 if (!frameView)
 318 return;
 319
 320 if (nodeID == frameView->scrollingNodeID()) {
 321 if (!isScrollAnimationInProgress)
 322 frameView->setScrollBehaviorStatus(ScrollBehaviorStatus::NotInAnimation);
 323 return;
 324 }
 325
 326 // Overflow-scroll area.
 327 if (auto* scrollableArea = frameView->scrollableAreaForScrollLayerID(nodeID)) {
 328 if (!isScrollAnimationInProgress)
 329 scrollableArea->setScrollBehaviorStatus(ScrollBehaviorStatus::NotInAnimation);
 330 }
 331}
 332#endif
 333
294334void AsyncScrollingCoordinator::updateScrollPositionAfterAsyncScrollTimerFired()
295335{
296336 updateScrollPositionAfterAsyncScroll(m_scheduledScrollUpdate.nodeID, m_scheduledScrollUpdate.scrollPosition, m_scheduledScrollUpdate.layoutViewportOrigin, ScrollType::User, m_scheduledScrollUpdate.updateLayerPositionAction);

Source/WebCore/page/scrolling/AsyncScrollingCoordinator.h

@@public:
5252 void scrollingStateTreePropertiesChanged();
5353
5454 WEBCORE_EXPORT void scheduleUpdateScrollPositionAfterAsyncScroll(ScrollingNodeID, const FloatPoint&, const Optional<FloatPoint>& layoutViewportOrigin, ScrollingLayerPositionAction);
 55#if PLATFORM(IOS_FAMILY)
 56 WEBCORE_EXPORT void setScrollAnimationInProgress(ScrollingNodeID, bool isScrollAnimationInProgress);
 57#endif
5558
5659#if PLATFORM(COCOA)
5760 WEBCORE_EXPORT void setActiveScrollSnapIndices(ScrollingNodeID, unsigned horizontalIndex, unsigned verticalIndex);

Source/WebCore/page/scrolling/ScrollingStateScrollingNode.cpp

@@ScrollingStateScrollingNode::ScrollingStateScrollingNode(const ScrollingStateScr
5656#endif
5757 , m_scrollableAreaParameters(stateNode.scrollableAreaParameters())
5858 , m_requestedScrollPositionRepresentsProgrammaticScroll(stateNode.requestedScrollPositionRepresentsProgrammaticScroll())
 59#if PLATFORM(IOS_FAMILY)
 60 , m_requestedScrollPositionWithAnimation(stateNode.requestedScrollPositionWithAnimation())
 61#endif
5962 , m_isMonitoringWheelEvents(stateNode.isMonitoringWheelEvents())
6063{
6164 if (hasChangedProperty(ScrollContainerLayer))

@@void ScrollingStateScrollingNode::setScrollableAreaParameters(const ScrollableAr
219222 setPropertyChanged(ScrollableAreaParams);
220223}
221224
 225#if PLATFORM(IOS_FAMILY)
 226void ScrollingStateScrollingNode::setRequestedScrollPosition(const FloatPoint& requestedScrollPosition, bool representsProgrammaticScroll, bool requestedWithAnimation)
 227{
 228 m_requestedScrollPosition = requestedScrollPosition;
 229 m_requestedScrollPositionRepresentsProgrammaticScroll = representsProgrammaticScroll;
 230 m_requestedScrollPositionWithAnimation = requestedWithAnimation;
 231 setPropertyChanged(RequestedScrollPosition);
 232}
 233#else
222234void ScrollingStateScrollingNode::setRequestedScrollPosition(const FloatPoint& requestedScrollPosition, bool representsProgrammaticScroll)
223235{
224236 m_requestedScrollPosition = requestedScrollPosition;
225237 m_requestedScrollPositionRepresentsProgrammaticScroll = representsProgrammaticScroll;
226238 setPropertyChanged(RequestedScrollPosition);
227239}
 240#endif
228241
229242void ScrollingStateScrollingNode::setIsMonitoringWheelEvents(bool isMonitoringWheelEvents)
230243{

@@void ScrollingStateScrollingNode::dumpProperties(TextStream& ts, ScrollingStateT
314327 if (m_requestedScrollPositionRepresentsProgrammaticScroll)
315328 ts.dumpProperty("requested scroll position represents programmatic scroll", m_requestedScrollPositionRepresentsProgrammaticScroll);
316329
 330#if PLATFORM(IOS_FAMILY)
 331 if (m_requestedScrollPositionWithAnimation)
 332 ts.dumpProperty("requested scroll position with animation", m_requestedScrollPositionWithAnimation);
 333#endif
 334
317335 if (!m_parentRelativeScrollableRect.isEmpty())
318336 ts.dumpProperty("parent relative scrollable rect", m_parentRelativeScrollableRect);
319337

Source/WebCore/page/scrolling/ScrollingStateScrollingNode.h

@@public:
111111
112112 const FloatPoint& requestedScrollPosition() const { return m_requestedScrollPosition; }
113113 bool requestedScrollPositionRepresentsProgrammaticScroll() const { return m_requestedScrollPositionRepresentsProgrammaticScroll; }
 114#if PLATFORM(IOS_FAMILY)
 115 bool requestedScrollPositionWithAnimation() const { return m_requestedScrollPositionWithAnimation; }
 116 WEBCORE_EXPORT void setRequestedScrollPosition(const FloatPoint&, bool representsProgrammaticScroll, bool requestedWithAnimation = false);
 117#else
114118 WEBCORE_EXPORT void setRequestedScrollPosition(const FloatPoint&, bool representsProgrammaticScroll);
 119#endif
115120
116121 bool isMonitoringWheelEvents() const { return m_isMonitoringWheelEvents; }
117122 WEBCORE_EXPORT void setIsMonitoringWheelEvents(bool);

@@private:
171176 ScrollableAreaParameters m_scrollableAreaParameters;
172177
173178 bool m_requestedScrollPositionRepresentsProgrammaticScroll { false };
 179#if PLATFORM(IOS_FAMILY)
 180 bool m_requestedScrollPositionWithAnimation { false };
 181#endif
174182 bool m_isMonitoringWheelEvents { false };
175183};
176184

Source/WebCore/page/scrolling/ScrollingTree.h

@@public:
8282 // Updates FrameView/RenderLayer scrolling state and GraphicsLayers.
8383 virtual void scrollingTreeNodeDidScroll(ScrollingTreeScrollingNode&, ScrollingLayerPositionAction = ScrollingLayerPositionAction::Sync) = 0;
8484
 85#if PLATFORM(IOS_FAMILY)
 86 // Called for scroll animation status updates.
 87 virtual void scrollingTreeNodeIsScrollAnimationInProgressDidChange(WebCore::ScrollingNodeID, bool /*isScrollAnimationInProgress*/) { }
 88#endif
 89
8590 // Called for requested scroll position updates.
86  virtual void scrollingTreeNodeRequestsScroll(ScrollingNodeID, const FloatPoint& /*scrollPosition*/, bool /*representsProgrammaticScroll*/) { }
 91 virtual void scrollingTreeNodeRequestsScroll(ScrollingNodeID, const FloatPoint& /*scrollPosition*/, bool /*representsProgrammaticScroll*/, bool /*withAnimation*/ = false) { }
8792
8893 // Delegated scrolling/zooming has caused the viewport to change, so update viewport-constrained layers
8994 WEBCORE_EXPORT void mainFrameViewportChangedViaDelegatedScrolling(const FloatPoint& scrollPosition, const WebCore::FloatRect& layoutViewport, double scale);

Source/WebCore/page/scrolling/ScrollingTreeScrollingNode.cpp

@@void ScrollingTreeScrollingNode::commitStateBeforeChildren(const ScrollingStateN
107107void ScrollingTreeScrollingNode::commitStateAfterChildren(const ScrollingStateNode& stateNode)
108108{
109109 const ScrollingStateScrollingNode& scrollingStateNode = downcast<ScrollingStateScrollingNode>(stateNode);
 110 bool withAnimation = false;
 111#if PLATFORM(IOS_FAMILY)
 112 withAnimation = scrollingStateNode.requestedScrollPositionWithAnimation();
 113#endif
110114 if (scrollingStateNode.hasChangedProperty(ScrollingStateScrollingNode::RequestedScrollPosition))
111  scrollingTree().scrollingTreeNodeRequestsScroll(scrollingNodeID(), scrollingStateNode.requestedScrollPosition(), scrollingStateNode.requestedScrollPositionRepresentsProgrammaticScroll());
 115 scrollingTree().scrollingTreeNodeRequestsScroll(scrollingNodeID(), scrollingStateNode.requestedScrollPosition(), scrollingStateNode.requestedScrollPositionRepresentsProgrammaticScroll(), withAnimation);
112116
113117 m_isFirstCommit = false;
114118}

@@void ScrollingTreeScrollingNode::scrollBy(const FloatSize& delta, ScrollPosition
157161 scrollTo(currentScrollPosition() + delta, ScrollType::User, clamp);
158162}
159163
160 void ScrollingTreeScrollingNode::scrollTo(const FloatPoint& position, ScrollType scrollType, ScrollPositionClamp clamp)
 164#if PLATFORM(IOS_FAMILY)
 165void ScrollingTreeScrollingNode::scrollTo(const FloatPoint& position, ScrollType scrollType, ScrollPositionClamp clamp, bool needSyncScrollPosition)
 166#else
 167void ScrollingTreeScrollingNode::scrollTo(const FloatPoint& position, ScrollType scrollType, ScrollPositionClamp clamp, bool /*needSyncScrollPosition*/)
 168#endif
161169{
162  if (position == m_currentScrollPosition)
 170 if (position == m_currentScrollPosition) {
 171#if PLATFORM(IOS_FAMILY)
 172 // Send the scroll position to the Web process.
 173 if (requestAnimatedScroll() && needSyncScrollPosition)
 174 scrollingTree().scrollingTreeNodeDidScroll(*this, ScrollingLayerPositionAction::Sync);
 175 scrollingTree().scrollingTreeNodeIsScrollAnimationInProgressDidChange(scrollingNodeID(), false);
 176 setRequestAnimatedScroll(false);
 177#endif
163178 return;
 179 }
164180
 181#if PLATFORM(IOS_FAMILY)
 182 // If during a scroll animation, need to stop it before starting a new one.
 183 if (scrollAnimationInProgress())
 184 setNeedsStopCurrentScrollAnimation(true);
 185#endif
165186 scrollingTree().setIsHandlingProgrammaticScroll(scrollType == ScrollType::Programmatic);
166 
 187
167188 m_currentScrollPosition = adjustedScrollPosition(position, clamp);
168 
 189
169190 LOG_WITH_STREAM(Scrolling, stream << "ScrollingTreeScrollingNode " << scrollingNodeID() << " scrollTo " << position << " (delta from last committed position " << (m_lastCommittedScrollPosition - m_currentScrollPosition) << ")");
170191
171192 updateViewportForCurrentScrollPosition();
172193 currentScrollPositionChanged();
173194
174195 scrollingTree().setIsHandlingProgrammaticScroll(false);
 196
 197#if PLATFORM(IOS_FAMILY)
 198 setNeedsStopCurrentScrollAnimation(false);
 199 setRequestAnimatedScroll(false);
 200#endif
175201}
176202
177203void ScrollingTreeScrollingNode::currentScrollPositionChanged()

@@void ScrollingTreeScrollingNode::currentScrollPositionChanged()
179205 repositionScrollingLayers();
180206 repositionRelatedLayers();
181207
 208#if PLATFORM(IOS_FAMILY)
 209 if (!requestAnimatedScroll())
 210 return;
 211#endif
182212 scrollingTree().notifyRelatedNodesAfterScrollPositionChange(*this);
183213 scrollingTree().scrollingTreeNodeDidScroll(*this);
184214}

@@void ScrollingTreeScrollingNode::dumpProperties(TextStream& ts, ScrollingStateTr
266296 ts.dumpProperty("scrollable area parameters", m_scrollableAreaParameters);
267297}
268298
 299#if PLATFORM(IOS_FAMILY)
 300void ScrollingTreeScrollingNode::setRequestAnimatedScroll(bool animated)
 301{
 302 m_requestAnimatedScroll = animated;
 303}
 304
 305bool ScrollingTreeScrollingNode::requestAnimatedScroll() const
 306{
 307 return m_requestAnimatedScroll;
 308}
 309
 310void ScrollingTreeScrollingNode::setScrollAnimationInProgress(bool inProgress)
 311{
 312 m_scrollAnimationInProgress = inProgress;
 313}
 314
 315bool ScrollingTreeScrollingNode::scrollAnimationInProgress() const
 316{
 317 return m_scrollAnimationInProgress;
 318}
 319
 320void ScrollingTreeScrollingNode::setNeedsStopCurrentScrollAnimation(bool stop)
 321{
 322 m_needsStopCurrentScrollAnimation = stop;
 323}
 324
 325bool ScrollingTreeScrollingNode::needsStopCurrentScrollAnimation() const
 326{
 327 return m_needsStopCurrentScrollAnimation;
 328}
 329#endif
269330} // namespace WebCore
270331
271332#endif // ENABLE(ASYNC_SCROLLING)

Source/WebCore/page/scrolling/ScrollingTreeScrollingNode.h

@@public:
6060 FloatSize scrollDeltaSinceLastCommit() const { return m_currentScrollPosition - m_lastCommittedScrollPosition; }
6161
6262 // These are imperative; they adjust the scrolling layers.
63  void scrollTo(const FloatPoint&, ScrollType = ScrollType::User, ScrollPositionClamp = ScrollPositionClamp::ToContentEdges);
 63 void scrollTo(const FloatPoint&, ScrollType = ScrollType::User, ScrollPositionClamp = ScrollPositionClamp::ToContentEdges, bool needSyncScrollPosition = false);
6464 void scrollBy(const FloatSize&, ScrollPositionClamp = ScrollPositionClamp::ToContentEdges);
6565
6666 void wasScrolledByDelegatedScrolling(const FloatPoint& position, Optional<FloatRect> overrideLayoutViewport = { }, ScrollingLayerPositionAction = ScrollingLayerPositionAction::Sync);

@@public:
9191 const LayerRepresentation& scrollContainerLayer() const { return m_scrollContainerLayer; }
9292 const LayerRepresentation& scrolledContentsLayer() const { return m_scrolledContentsLayer; }
9393
 94#if PLATFORM(IOS_FAMILY)
 95 void setRequestAnimatedScroll(bool);
 96 bool requestAnimatedScroll() const;
 97 void setScrollAnimationInProgress(bool);
 98 bool scrollAnimationInProgress() const;
 99 void setNeedsStopCurrentScrollAnimation(bool);
 100 bool needsStopCurrentScrollAnimation() const;
 101#endif
 102
94103protected:
95104 ScrollingTreeScrollingNode(ScrollingTree&, ScrollingNodeType, ScrollingNodeID);
96105

@@private:
148157 ScrollableAreaParameters m_scrollableAreaParameters;
149158 bool m_isFirstCommit { true };
150159
 160#if PLATFORM(IOS_FAMILY)
 161 bool m_requestAnimatedScroll { false };
 162 bool m_scrollAnimationInProgress { false };
 163 bool m_needsStopCurrentScrollAnimation { false };
 164#endif
 165
151166 LayerRepresentation m_scrollContainerLayer;
152167 LayerRepresentation m_scrolledContentsLayer;
153168};

Source/WebCore/platform/ScrollTypes.h

@@enum class ScrollPositionClamp : uint8_t {
5454 ToContentEdges,
5555};
5656
57 // FIXME: Add another status InNativeAnimation to indicate native scrolling is in progress.
58 // See: https://bugs.webkit.org/show_bug.cgi?id=204936
 57#if PLATFORM(IOS_FAMILY) && ENABLE(ASYNC_SCROLLING)
 58enum class ScrollBehaviorType : uint8_t {
 59 Instant,
 60 Smooth,
 61};
 62#endif
 63
5964enum class ScrollBehaviorStatus : uint8_t {
6065 NotInAnimation,
6166 InNonNativeAnimation,
 67#if PLATFORM(IOS_FAMILY) && ENABLE(ASYNC_SCROLLING)
 68 InNativeAnimation,
 69#endif
6270};
6371
6472inline ScrollDirection logicalToPhysical(ScrollLogicalDirection direction, bool isVertical, bool isFlipped)

Source/WebCore/platform/ScrollView.cpp

@@void ScrollView::setScrollPosition(const ScrollPosition& scrollPosition, bool/*
465465{
466466 LOG_WITH_STREAM(Scrolling, stream << "ScrollView::setScrollPosition " << scrollPosition);
467467
 468#if PLATFORM(IOS_FAMILY) && ENABLE(ASYNC_SCROLLING)
 469 setCurrentScrollBehaviorType(ScrollBehaviorType::Instant);
 470#endif
 471
468472 if (prohibitsScrolling())
469473 return;
470474

Source/WebCore/platform/ScrollableArea.cpp

@@ScrollableArea::ScrollableArea()
7171 , m_scrollOriginChanged(false)
7272 , m_currentScrollType(static_cast<unsigned>(ScrollType::User))
7373 , m_scrollShouldClearLatchedState(false)
 74#if PLATFORM(IOS_FAMILY) && ENABLE(ASYNC_SCROLLING)
 75 , m_currentScrollBehaviorType(static_cast<unsigned>(ScrollBehaviorType::Instant))
 76#endif
7477{
7578}
7679

Source/WebCore/platform/ScrollableArea.h

@@public:
246246 ScrollType currentScrollType() const { return static_cast<ScrollType>(m_currentScrollType); }
247247 void setCurrentScrollType(ScrollType scrollType) { m_currentScrollType = static_cast<unsigned>(scrollType); }
248248
 249#if PLATFORM(IOS_FAMILY) && ENABLE(ASYNC_SCROLLING)
 250 ScrollBehaviorType currentScrollBehaviorType() const { return static_cast<ScrollBehaviorType>(m_currentScrollBehaviorType); }
 251 void setCurrentScrollBehaviorType(ScrollBehaviorType scrollBehaviorType) { m_currentScrollBehaviorType = static_cast<unsigned>(scrollBehaviorType); }
 252#endif
 253
249254 bool scrollShouldClearLatchedState() const { return m_scrollShouldClearLatchedState; }
250255 void setScrollShouldClearLatchedState(bool shouldClear) { m_scrollShouldClearLatchedState = shouldClear; }
251256

@@private:
409414 unsigned m_scrollOriginChanged : 1;
410415 unsigned m_currentScrollType : 1; // ScrollType
411416 unsigned m_scrollShouldClearLatchedState : 1;
 417#if PLATFORM(IOS_FAMILY) && ENABLE(ASYNC_SCROLLING)
 418 unsigned m_currentScrollBehaviorType : 1;
 419#endif
412420};
413421
414422} // namespace WebCore

Source/WebCore/rendering/RenderLayer.cpp

@@ScrollOffset RenderLayer::clampScrollOffset(const ScrollOffset& scrollOffset) co
26022602
26032603void RenderLayer::scrollToOffset(const ScrollOffset& scrollOffset, ScrollType scrollType, ScrollClamping clamping)
26042604{
 2605#if PLATFORM(IOS_FAMILY) && ENABLE(ASYNC_SCROLLING)
 2606 setCurrentScrollBehaviorType(ScrollBehaviorType::Instant);
 2607#endif
 2608
26052609 if (currentScrollBehaviorStatus() == ScrollBehaviorStatus::InNonNativeAnimation)
26062610 scrollAnimator().cancelAnimations();
26072611
26082612 ScrollOffset clampedScrollOffset = clamping == ScrollClamping::Clamped ? clampScrollOffset(scrollOffset) : scrollOffset;
2609  if (clampedScrollOffset == this->scrollOffset())
 2613 if (clampedScrollOffset == this->scrollOffset()) {
 2614#if PLATFORM(IOS_FAMILY) && ENABLE(ASYNC_SCROLLING)
 2615 // If UIScrollView is performing a scroll animation, the scroll offset of the Web process might be overridden.
 2616 // So we need to call requestScrollPositionUpdate here and let it be checked on the UI process.
 2617 // If the scroll offset on the UI process is different, the correct scroll offset needs to sync back to the Web process.
 2618 if (currentScrollBehaviorStatus() == ScrollBehaviorStatus::InNativeAnimation)
 2619 requestScrollPositionUpdate(scrollPositionFromOffset(clampedScrollOffset));
 2620#endif
26102621 return;
 2622 }
26112623
26122624 auto previousScrollType = currentScrollType();
26132625 setCurrentScrollType(scrollType);

@@void RenderLayer::scrollToOffsetWithAnimation(const ScrollOffset& offset, Scroll
26392651 auto previousScrollType = currentScrollType();
26402652 setCurrentScrollType(scrollType);
26412653
 2654#if PLATFORM(IOS_FAMILY) && ENABLE(ASYNC_SCROLLING)
 2655 setCurrentScrollBehaviorType(ScrollBehaviorType::Smooth);
 2656 if (requestScrollPositionUpdate(scrollPositionFromOffset(offset))) {
 2657 setCurrentScrollType(previousScrollType);
 2658 return;
 2659 }
 2660#endif
 2661
26422662 ScrollOffset newScrollOffset = clamping == ScrollClamping::Clamped ? clampScrollOffset(offset) : offset;
26432663 if (currentScrollBehaviorStatus() == ScrollBehaviorStatus::InNonNativeAnimation)
26442664 scrollAnimator().cancelAnimations();

Source/WebKit/ChangeLog

 12019-12-11 Cathie Chen <cathiechen@igalia.com>
 2
 3 Add support for scroll behavior relies on native scroll interfaces for iOS platform
 4 https://bugs.webkit.org/show_bug.cgi?id=204936
 5
 6 Reviewed by NOBODY (OOPS!).
 7
 8 Based on the patch by Frédéric Wang.
 9
 10 Add CSSOM smooth scrolling as an experimental feature. On ios platform, use native animated scrolling
 11 interfaces to performance smooth scroll and send the scroll position to the Web process.
 12
 13 (ArgumentCoder<ScrollingStateScrollingNode>::encode):
 14 (ArgumentCoder<ScrollingStateScrollingNode>::decode):
 15 (WebKit::dump):
 16 * UIProcess/API/Cocoa/WKWebView.mm:
 17 (pointsEqualInRoundToDevicePixel): Help function to check if two float points are not equal but in the same device pixel.
 18 (-[WKWebView _scrollToContentScrollPosition:scrollOrigin:animated:]): Add animated flag to start a animated scroll if needed.
 19 (-[WKWebView scrollViewDidEndScrollingAnimation:]): Send sroll end message to the Web process.
 20 (-[WKWebView _scrollToContentScrollPosition:scrollOrigin:]): Deleted.
 21 * UIProcess/API/Cocoa/WKWebViewInternal.h:
 22 * UIProcess/PageClient.h:
 23 (WebKit::PageClient::requestScrollWithAnimation): Provide interface for animated scrolling.
 24 * UIProcess/RemoteLayerTree/RemoteLayerTreeDrawingAreaProxy.mm:
 25 (WebKit::RemoteLayerTreeDrawingAreaProxy::commitLayerTree): Add animated flag.
 26 * UIProcess/RemoteLayerTree/RemoteScrollingCoordinatorProxy.cpp:
 27 (WebKit::RemoteScrollingCoordinatorProxy::scrollingTreeNodeDidScroll): Sync the scroll position to the Web process.
 28 (WebKit::RemoteScrollingCoordinatorProxy::scrollingTreeNodeRequestsScroll): Add animated scrolling info to m_requestedScrollInfo.
 29 (WebKit::RemoteScrollingCoordinatorProxy::scrollingTreeNodeIsScrollAnimationInProgressDidChange): Sync scrollAnimationInProgress to the Web process.
 30 (WebKit::RemoteScrollingCoordinatorProxy::scrollingTreeRootNodeIsScrollAnimationInProgressDidChange): Ditto. It's specific to the root node.
 31 * UIProcess/RemoteLayerTree/RemoteScrollingCoordinatorProxy.h:
 32 * UIProcess/RemoteLayerTree/RemoteScrollingTree.cpp:
 33 (WebKit::RemoteScrollingTree::scrollingTreeNodeDidScroll): Add animated info.
 34 (WebKit::RemoteScrollingTree::scrollingTreeNodeRequestsScroll): Ditto.
 35 (WebKit::RemoteScrollingTree::scrollingTreeNodeIsScrollAnimationInProgressDidChange): Ditto.
 36 * UIProcess/RemoteLayerTree/RemoteScrollingTree.h:
 37 * UIProcess/RemoteLayerTree/ios/ScrollingTreeScrollingNodeDelegateIOS.h:
 38 * UIProcess/RemoteLayerTree/ios/ScrollingTreeScrollingNodeDelegateIOS.mm:
 39 (-[WKScrollingNodeScrollViewDelegate scrollViewDidEndScrollingAnimation:]): Send scoll end info to the Web process.
 40 (WebKit::ScrollingTreeScrollingNodeDelegateIOS::commitStateAfterChildren): If the scroll position of the Web process isn't equal to the UI process,
 41 the scroll position should be synchronized, even there's no scrolling performed in the UI process.
 42 (WebKit::ScrollingTreeScrollingNodeDelegateIOS::repositionScrollingLayers): Calling the native animated scrolling interface for smooth scroll.
 43 If there's a scroll animation performing, it should be stopped first, then start a new scrolling.
 44 (WebKit::ScrollingTreeScrollingNodeDelegateIOS::scrollViewDidEndScrollingAnimation): Sync scroll end info to the Web process.
 45 * UIProcess/WebPageProxy.cpp:
 46 (WebKit::WebPageProxy::requestScroll): To call different functions for smooth and instant scroll.
 47 * UIProcess/WebPageProxy.h:
 48 * UIProcess/ios/PageClientImplIOS.h:
 49 * UIProcess/ios/PageClientImplIOS.mm:
 50 (WebKit::PageClientImpl::requestScroll):
 51 (WebKit::PageClientImpl::requestScrollWithAnimation):
 52 * WebProcess/WebPage/RemoteLayerTree/RemoteScrollingCoordinator.h:
 53 * WebProcess/WebPage/RemoteLayerTree/RemoteScrollingCoordinator.messages.in:
 54 * WebProcess/WebPage/RemoteLayerTree/RemoteScrollingCoordinator.mm:
 55 (WebKit::RemoteScrollingCoordinator::scrollAnimationInProgressChangedForNode):
 56
1572019-12-10 Cathie Chen <cathiechen@igalia.com>
258
359 Add support for scroll behavior parsing

Source/WebKit/Shared/RemoteLayerTree/RemoteScrollingCoordinatorTransaction.cpp

@@void ArgumentCoder<ScrollingStateScrollingNode>::encode(Encoder& encoder, const
152152 SCROLLING_NODE_ENCODE(ScrollingStateScrollingNode::ScrollableAreaParams, scrollableAreaParameters)
153153 SCROLLING_NODE_ENCODE(ScrollingStateScrollingNode::RequestedScrollPosition, requestedScrollPosition)
154154 SCROLLING_NODE_ENCODE(ScrollingStateScrollingNode::RequestedScrollPosition, requestedScrollPositionRepresentsProgrammaticScroll)
 155#if PLATFORM(IOS_FAMILY)
 156 SCROLLING_NODE_ENCODE(ScrollingStateScrollingNode::RequestedScrollPosition, requestedScrollPositionWithAnimation)
 157#endif
155158
156159 if (node.hasChangedProperty(ScrollingStateScrollingNode::ScrollContainerLayer))
157160 encoder << static_cast<GraphicsLayer::PlatformLayerID>(node.scrollContainerLayer());

@@bool ArgumentCoder<ScrollingStateScrollingNode>::decode(Decoder& decoder, Scroll
260263 if (!decoder.decode(representsProgrammaticScroll))
261264 return false;
262265
 266#if PLATFORM(IOS_FAMILY)
 267 bool scrollWithAnimation;
 268 if (!decoder.decode(scrollWithAnimation))
 269 return false;
 270 node.setRequestedScrollPosition(scrollPosition, representsProgrammaticScroll, scrollWithAnimation);
 271#else
263272 node.setRequestedScrollPosition(scrollPosition, representsProgrammaticScroll);
 273#endif
264274 }
265275
266276 if (node.hasChangedProperty(ScrollingStateScrollingNode::ScrollContainerLayer)) {

@@static void dump(TextStream& ts, const ScrollingStateScrollingNode& node, bool c
608618 if (!changedPropertiesOnly || node.hasChangedProperty(ScrollingStateScrollingNode::RequestedScrollPosition)) {
609619 ts.dumpProperty("requested-scroll-position", node.requestedScrollPosition());
610620 ts.dumpProperty("requested-scroll-position-is-programatic", node.requestedScrollPositionRepresentsProgrammaticScroll());
 621#if PLATFORM(IOS_FAMILY)
 622 ts.dumpProperty("requested-scroll-position-with-animation", node.requestedScrollPositionWithAnimation());
 623#endif
611624 }
612625
613626 if (!changedPropertiesOnly || node.hasChangedProperty(ScrollingStateScrollingNode::ScrollContainerLayer))

Source/WebKit/UIProcess/API/Cocoa/WKWebView.mm

@@static inline bool pointsEqualInDevicePixels(CGPoint a, CGPoint b, float deviceS
16171617 && fabs(a.y * deviceScaleFactor - b.y * deviceScaleFactor) < std::numeric_limits<float>::epsilon();
16181618}
16191619
 1620static inline bool pointsEqualInRoundToDevicePixel(CGPoint a, CGPoint b, float deviceScaleFactor)
 1621{
 1622 return CGRound(a.x * deviceScaleFactor) == CGRound(b.x * deviceScaleFactor)
 1623 && CGRound(a.y * deviceScaleFactor) == CGRound(b.y * deviceScaleFactor);
 1624}
16201625static CGSize roundScrollViewContentSize(const WebKit::WebPageProxy& page, CGSize contentSize)
16211626{
16221627 float deviceScaleFactor = page.deviceScaleFactor();

@@static WebCore::FloatPoint constrainContentOffset(WebCore::FloatPoint contentOff
23412346 return contentOffset.constrainedBetween(WebCore::FloatPoint(), WebCore::FloatPoint(maximumContentOffset));
23422347}
23432348
2344 - (void)_scrollToContentScrollPosition:(WebCore::FloatPoint)scrollPosition scrollOrigin:(WebCore::IntPoint)scrollOrigin
 2349- (void)_scrollToContentScrollPosition:(WebCore::FloatPoint)scrollPosition scrollOrigin:(WebCore::IntPoint)scrollOrigin animated:(BOOL)animated
23452350{
2346  if (_commitDidRestoreScrollPosition || _dynamicViewportUpdateMode != WebKit::DynamicViewportUpdateMode::NotResizing)
 2351 // Animated scrolling shouldn't be skipped.
 2352 if (!animated && (_commitDidRestoreScrollPosition || _dynamicViewportUpdateMode != WebKit::DynamicViewportUpdateMode::NotResizing))
23472353 return;
23482354
23492355 WebCore::FloatPoint contentOffset = WebCore::ScrollableArea::scrollOffsetFromPosition(scrollPosition, toFloatSize(scrollOrigin));

@@static WebCore::FloatPoint constrainContentOffset(WebCore::FloatPoint contentOff
23572363
23582364 [_scrollView _stopScrollingAndZoomingAnimations];
23592365
2360  if (!CGPointEqualToPoint(contentOffsetInScrollViewCoordinates, [_scrollView contentOffset]))
2361  [_scrollView setContentOffset:contentOffsetInScrollViewCoordinates];
 2366 // It's possible that they are not equal, but in the same device pixel, so _scrollView won't change.
 2367 // We need to calculate the round to device pixel here.
 2368 if (!pointsEqualInRoundToDevicePixel(contentOffsetInScrollViewCoordinates, [_scrollView contentOffset], _page->deviceScaleFactor()))
 2369 [_scrollView setContentOffset:contentOffsetInScrollViewCoordinates animated:animated];
23622370 else {
23632371 // If we haven't changed anything, there would not be any VisibleContentRect update sent to the content.
23642372 // The WebProcess would keep the invalid contentOffset as its scroll position.
23652373 // To synchronize the WebProcess with what is on screen, we send the VisibleContentRect again.
23662374 _page->resendLastVisibleContentRects();
 2375 // If _scrollView won't change, we still need to tell the Web process that the animation stopped.
 2376 if (animated) {
 2377 WebKit::RemoteScrollingCoordinatorProxy* coordinator = _page->scrollingCoordinatorProxy();
 2378 if (coordinator)
 2379 coordinator->scrollingTreeRootNodeIsScrollAnimationInProgressDidChange(false);
 2380 }
23672381 }
23682382}
23692383

@@static WebCore::FloatPoint constrainContentOffset(WebCore::FloatPoint contentOff
28792893- (void)scrollViewDidEndScrollingAnimation:(UIScrollView *)scrollView
28802894{
28812895 [self _didFinishScrolling];
 2896
 2897 WebKit::RemoteScrollingCoordinatorProxy* coordinator = _page->scrollingCoordinatorProxy();
 2898 if (coordinator)
 2899 coordinator->scrollingTreeRootNodeIsScrollAnimationInProgressDidChange(false);
28822900}
28832901
28842902- (void)_scrollViewDidInterruptDecelerating:(UIScrollView *)scrollView

Source/WebKit/UIProcess/API/Cocoa/WKWebViewInternal.h

@@struct PrintInfo;
9797
9898- (RefPtr<WebKit::ViewSnapshot>)_takeViewSnapshot;
9999
100 - (void)_scrollToContentScrollPosition:(WebCore::FloatPoint)scrollPosition scrollOrigin:(WebCore::IntPoint)scrollOrigin;
 100- (void)_scrollToContentScrollPosition:(WebCore::FloatPoint)scrollPosition scrollOrigin:(WebCore::IntPoint)scrollOrigin animated:(BOOL)animated;
101101- (BOOL)_scrollToRect:(WebCore::FloatRect)targetRect origin:(WebCore::FloatPoint)origin minimumScrollDistance:(float)minimumScrollDistance;
102102- (double)_initialScaleFactor;
103103- (double)_contentZoomScale;

Source/WebKit/UIProcess/PageClient.h

@@public:
181181 // Tell the view to scroll to the given position, and whether this was a programmatic scroll.
182182 virtual void requestScroll(const WebCore::FloatPoint& scrollPosition, const WebCore::IntPoint& scrollOrigin) = 0;
183183
 184 virtual void requestScrollWithAnimation(const WebCore::FloatPoint& scrollPosition, const WebCore::IntPoint& scrollOrigin) { }
 185
184186 // Return the current scroll position (not necessarily the same as the WebCore scroll position, because of scaling, insets etc.)
185187 virtual WebCore::FloatPoint viewScrollPosition() = 0;
186188

Source/WebKit/UIProcess/RemoteLayerTree/RemoteLayerTreeDrawingAreaProxy.mm

@@void RemoteLayerTreeDrawingAreaProxy::commitLayerTree(const RemoteLayerTreeTrans
224224
225225 // Handle requested scroll position updates from the scrolling tree transaction after didCommitLayerTree()
226226 // has updated the view size based on the content size.
227  if (requestedScrollInfo.requestsScrollPositionUpdate)
228  m_webPageProxy.requestScroll(requestedScrollInfo.requestedScrollPosition, layerTreeTransaction.scrollOrigin());
 227 if (requestedScrollInfo.requestsScrollPositionUpdate) {
 228 m_webPageProxy.requestScroll(requestedScrollInfo.requestedScrollPosition
 229 , layerTreeTransaction.scrollOrigin()
 230#if PLATFORM(IOS_FAMILY)
 231 , requestedScrollInfo.requestWithAnimation
 232#endif
 233 );
 234 }
229235#endif // ENABLE(ASYNC_SCROLLING)
230236
231237 if (m_debugIndicatorLayerTreeHost) {

Source/WebKit/UIProcess/RemoteLayerTree/RemoteScrollingCoordinatorProxy.cpp

@@void RemoteScrollingCoordinatorProxy::currentSnapPointIndicesDidChange(WebCore::
208208}
209209
210210// This comes from the scrolling tree.
211 void RemoteScrollingCoordinatorProxy::scrollingTreeNodeDidScroll(ScrollingNodeID scrolledNodeID, const FloatPoint& newScrollPosition, const Optional<FloatPoint>& layoutViewportOrigin, ScrollingLayerPositionAction scrollingLayerPositionAction)
 211void RemoteScrollingCoordinatorProxy::scrollingTreeNodeDidScroll(ScrollingNodeID scrolledNodeID, const FloatPoint& newScrollPosition, const Optional<FloatPoint>& layoutViewportOrigin, ScrollingLayerPositionAction scrollingLayerPositionAction, bool instantScrollDidStopAnimation)
212212{
213213 // Scroll updates for the main frame are sent via WebPageProxy::updateVisibleContentRects()
214214 // so don't send them here.

@@void RemoteScrollingCoordinatorProxy::scrollingTreeNodeDidScroll(ScrollingNodeID
222222 m_webPageProxy.scrollingNodeScrollViewDidScroll();
223223#endif
224224
 225#if PLATFORM(IOS_FAMILY)
 226 if (m_scrollingTree->isHandlingProgrammaticScroll() && !instantScrollDidStopAnimation)
 227 return;
 228#else
225229 if (m_scrollingTree->isHandlingProgrammaticScroll())
226230 return;
 231#endif
227232
228233 m_webPageProxy.send(Messages::RemoteScrollingCoordinator::ScrollPositionChangedForNode(scrolledNodeID, newScrollPosition, scrollingLayerPositionAction == ScrollingLayerPositionAction::Sync));
229234}
230235
231 void RemoteScrollingCoordinatorProxy::scrollingTreeNodeRequestsScroll(ScrollingNodeID scrolledNodeID, const FloatPoint& scrollPosition, bool representsProgrammaticScroll)
 236void RemoteScrollingCoordinatorProxy::scrollingTreeNodeRequestsScroll(ScrollingNodeID scrolledNodeID, const FloatPoint& scrollPosition, bool representsProgrammaticScroll, bool withAnimation)
232237{
233238 if (scrolledNodeID == rootScrollingNodeID() && m_requestedScrollInfo) {
234239 m_requestedScrollInfo->requestsScrollPositionUpdate = true;
235240 m_requestedScrollInfo->requestIsProgrammaticScroll = representsProgrammaticScroll;
 241#if PLATFORM(IOS_FAMILY)
 242 m_requestedScrollInfo->requestWithAnimation = withAnimation;
 243#endif
236244 m_requestedScrollInfo->requestedScrollPosition = scrollPosition;
237245 }
238246}
239247
 248#if PLATFORM(IOS_FAMILY)
 249void RemoteScrollingCoordinatorProxy::scrollingTreeNodeIsScrollAnimationInProgressDidChange(WebCore::ScrollingNodeID scrolledNodeID, bool isScrollAnimationInProgress)
 250{
 251 m_webPageProxy.send(Messages::RemoteScrollingCoordinator::scrollAnimationInProgressChangedForNode(scrolledNodeID, isScrollAnimationInProgress));
 252}
 253
 254void RemoteScrollingCoordinatorProxy::scrollingTreeRootNodeIsScrollAnimationInProgressDidChange(bool isScrollAnimationInProgress)
 255{
 256 m_webPageProxy.send(Messages::RemoteScrollingCoordinator::scrollAnimationInProgressChangedForNode(rootScrollingNodeID(), isScrollAnimationInProgress));
 257}
 258#endif
 259
240260String RemoteScrollingCoordinatorProxy::scrollingTreeAsText() const
241261{
242262 if (m_scrollingTree)

Source/WebKit/UIProcess/RemoteLayerTree/RemoteScrollingCoordinatorProxy.h

@@public:
5555 explicit RemoteScrollingCoordinatorProxy(WebPageProxy&);
5656 virtual ~RemoteScrollingCoordinatorProxy();
5757
 58#if PLATFORM(IOS_FAMILY)
 59 void scrollingTreeNodeIsScrollAnimationInProgressDidChange(WebCore::ScrollingNodeID, bool isScrollAnimationInProgress);
 60 void scrollingTreeRootNodeIsScrollAnimationInProgressDidChange(bool isScrollAnimationInProgress);
 61#endif
 62
5863 // Inform the web process that the scroll position changed (called from the scrolling tree)
59  void scrollingTreeNodeDidScroll(WebCore::ScrollingNodeID, const WebCore::FloatPoint& newScrollPosition, const Optional<WebCore::FloatPoint>& layoutViewportOrigin, WebCore::ScrollingLayerPositionAction);
60  void scrollingTreeNodeRequestsScroll(WebCore::ScrollingNodeID, const WebCore::FloatPoint& scrollPosition, bool representsProgrammaticScroll);
 64 void scrollingTreeNodeDidScroll(WebCore::ScrollingNodeID, const WebCore::FloatPoint& newScrollPosition, const Optional<WebCore::FloatPoint>& layoutViewportOrigin, WebCore::ScrollingLayerPositionAction, bool instantScrollDidStopAnimation = false);
 65 void scrollingTreeNodeRequestsScroll(WebCore::ScrollingNodeID, const WebCore::FloatPoint& scrollPosition, bool representsProgrammaticScroll, bool withAnimation = false);
6166
6267 WebCore::TrackingType eventTrackingTypeForPoint(const AtomString& eventName, WebCore::IntPoint) const;
6368

@@public:
8085 struct RequestedScrollInfo {
8186 bool requestsScrollPositionUpdate { };
8287 bool requestIsProgrammaticScroll { };
 88#if PLATFORM(IOS_FAMILY)
 89 bool requestWithAnimation { };
 90#endif
8391 WebCore::FloatPoint requestedScrollPosition;
8492 };
8593 void commitScrollingTreeState(const RemoteScrollingCoordinatorTransaction&, RequestedScrollInfo&);

Source/WebKit/UIProcess/RemoteLayerTree/RemoteScrollingTree.cpp

@@void RemoteScrollingTree::scrollingTreeNodeDidScroll(ScrollingTreeScrollingNode&
104104 if (is<ScrollingTreeFrameScrollingNode>(node))
105105 layoutViewportOrigin = downcast<ScrollingTreeFrameScrollingNode>(node).layoutViewport().location();
106106
 107#if PLATFORM(IOS_FAMILY)
 108 m_scrollingCoordinatorProxy.scrollingTreeNodeDidScroll(node.scrollingNodeID(), node.currentScrollPosition(), layoutViewportOrigin, scrollingLayerPositionAction, node.needsStopCurrentScrollAnimation() && !node.requestAnimatedScroll());
 109#else
107110 m_scrollingCoordinatorProxy.scrollingTreeNodeDidScroll(node.scrollingNodeID(), node.currentScrollPosition(), layoutViewportOrigin, scrollingLayerPositionAction);
 111#endif
108112}
109113
110 void RemoteScrollingTree::scrollingTreeNodeRequestsScroll(ScrollingNodeID nodeID, const FloatPoint& scrollPosition, bool representsProgrammaticScroll)
 114void RemoteScrollingTree::scrollingTreeNodeRequestsScroll(ScrollingNodeID nodeID, const FloatPoint& scrollPosition, bool representsProgrammaticScroll, bool withAnimation)
111115{
112  m_scrollingCoordinatorProxy.scrollingTreeNodeRequestsScroll(nodeID, scrollPosition, representsProgrammaticScroll);
 116 m_scrollingCoordinatorProxy.scrollingTreeNodeRequestsScroll(nodeID, scrollPosition, representsProgrammaticScroll, withAnimation);
113117}
114118
115119Ref<ScrollingTreeNode> RemoteScrollingTree::createScrollingTreeNode(ScrollingNodeType nodeType, ScrollingNodeID nodeID)

@@Ref<ScrollingTreeNode> RemoteScrollingTree::createScrollingTreeNode(ScrollingNod
143147 return ScrollingTreeFixedNode::create(*this, nodeID);
144148}
145149
 150#if PLATFORM(IOS_FAMILY)
 151void RemoteScrollingTree::scrollingTreeNodeIsScrollAnimationInProgressDidChange(WebCore::ScrollingNodeID nodeID, bool isScrollAnimationInProgress)
 152{
 153 m_scrollingCoordinatorProxy.scrollingTreeNodeIsScrollAnimationInProgressDidChange(nodeID, isScrollAnimationInProgress);
 154}
 155#endif
 156
146157void RemoteScrollingTree::currentSnapPointIndicesDidChange(ScrollingNodeID nodeID, unsigned horizontal, unsigned vertical)
147158{
148159 m_scrollingCoordinatorProxy.currentSnapPointIndicesDidChange(nodeID, horizontal, vertical);

Source/WebKit/UIProcess/RemoteLayerTree/RemoteScrollingTree.h

@@public:
5252 const RemoteScrollingCoordinatorProxy& scrollingCoordinatorProxy() const { return m_scrollingCoordinatorProxy; }
5353
5454 void scrollingTreeNodeDidScroll(WebCore::ScrollingTreeScrollingNode&, WebCore::ScrollingLayerPositionAction = WebCore::ScrollingLayerPositionAction::Sync) override;
55  void scrollingTreeNodeRequestsScroll(WebCore::ScrollingNodeID, const WebCore::FloatPoint& scrollPosition, bool representsProgrammaticScroll) override;
 55 void scrollingTreeNodeRequestsScroll(WebCore::ScrollingNodeID, const WebCore::FloatPoint& scrollPosition, bool representsProgrammaticScroll, bool withAnimation = false) override;
 56
 57#if PLATFORM(IOS_FAMILY)
 58 void scrollingTreeNodeIsScrollAnimationInProgressDidChange(WebCore::ScrollingNodeID, bool isScrollAnimationInProgress) override;
 59#endif
5660
5761 void currentSnapPointIndicesDidChange(WebCore::ScrollingNodeID, unsigned horizontal, unsigned vertical) override;
5862

Source/WebKit/UIProcess/RemoteLayerTree/ios/ScrollingTreeScrollingNodeDelegateIOS.h

@@public:
5757 void scrollDidEnd() const;
5858 void scrollViewWillStartPanGesture() const;
5959 void scrollViewDidScroll(const WebCore::FloatPoint& scrollOffset, bool inUserInteraction);
 60 void scrollViewDidEndScrollingAnimation();
6061
6162 void currentSnapPointIndicesDidChange(unsigned horizontal, unsigned vertical) const;
6263 CALayer *scrollLayer() const { return m_scrollLayer.get(); }

Source/WebKit/UIProcess/RemoteLayerTree/ios/ScrollingTreeScrollingNodeDelegateIOS.mm

152152 }
153153}
154154
 155- (void)scrollViewDidEndScrollingAnimation:(UIScrollView *)scrollView
 156{
 157 _scrollingTreeNodeDelegate->scrollViewDidEndScrollingAnimation();
 158}
 159
155160#if ENABLE(POINTER_EVENTS)
156161- (CGPoint)_scrollView:(UIScrollView *)scrollView adjustedOffsetForOffset:(CGPoint)offset translation:(CGPoint)translation startPoint:(CGPoint)start locationInView:(CGPoint)locationInView horizontalVelocity:(inout double *)hv verticalVelocity:(inout double *)vv
157162{

@@void ScrollingTreeScrollingNodeDelegateIOS::commitStateAfterChildren(const Scrol
300305
301306 if (scrollingStateNode.hasChangedProperty(ScrollingStateScrollingNode::RequestedScrollPosition)) {
302307 auto scrollType = scrollingStateNode.requestedScrollPositionRepresentsProgrammaticScroll() ? ScrollType::Programmatic : ScrollType::User;
303  scrollingNode().scrollTo(scrollingStateNode.requestedScrollPosition(), scrollType);
 308 if (scrollingStateNode.requestedScrollPositionWithAnimation())
 309 scrollingNode().setRequestAnimatedScroll(true);
 310 // If the scroll positions are not the same, there's a possibility that the scroll offset from the Web process has been overridden.
 311 // In this case, the scroll position need to be sent to the Web process.
 312 bool shouldSyncScrollPosition = scrollingStateNode.scrollPosition() != scrollingNode().currentScrollPosition();
 313 scrollingNode().scrollTo(scrollingStateNode.requestedScrollPosition(), scrollType, ScrollPositionClamp::ToContentEdges, shouldSyncScrollPosition);
304314 }
305315}
306316
307317void ScrollingTreeScrollingNodeDelegateIOS::repositionScrollingLayers()
308318{
309  BEGIN_BLOCK_OBJC_EXCEPTIONS
310  [scrollView() setContentOffset:scrollingNode().currentScrollOffset()];
311  END_BLOCK_OBJC_EXCEPTIONS
 319 bool animationInProgress = scrollingNode().scrollAnimationInProgress();
 320 bool needToStopAnimation = scrollingNode().needsStopCurrentScrollAnimation();
 321 if (needToStopAnimation && animationInProgress) {
 322 BEGIN_BLOCK_OBJC_EXCEPTIONS
 323 [scrollView() setContentOffset:scrollView().contentOffset animated:NO];
 324 END_BLOCK_OBJC_EXCEPTIONS
 325 }
 326
 327 if (scrollingNode().requestAnimatedScroll()) {
 328 BEGIN_BLOCK_OBJC_EXCEPTIONS
 329 [scrollView() setContentOffset:scrollingNode().currentScrollOffset() animated:YES];
 330 END_BLOCK_OBJC_EXCEPTIONS
 331
 332 scrollingNode().setScrollAnimationInProgress(true);
 333 } else if (!animationInProgress || needToStopAnimation) {
 334 BEGIN_BLOCK_OBJC_EXCEPTIONS
 335 [scrollView() setContentOffset:scrollingNode().currentScrollOffset()];
 336 END_BLOCK_OBJC_EXCEPTIONS
 337 }
312338}
313339
314340void ScrollingTreeScrollingNodeDelegateIOS::scrollWillStart() const

@@void ScrollingTreeScrollingNodeDelegateIOS::scrollViewDidScroll(const FloatPoint
335361 scrollingNode().wasScrolledByDelegatedScrolling(scrollPosition, { }, inUserInteraction ? ScrollingLayerPositionAction::Sync : ScrollingLayerPositionAction::Set);
336362}
337363
 364void ScrollingTreeScrollingNodeDelegateIOS::scrollViewDidEndScrollingAnimation()
 365{
 366 auto& node = scrollingNode();
 367 if (!(node.requestAnimatedScroll() && node.scrollAnimationInProgress())) {
 368 scrollingTree().scrollingTreeNodeIsScrollAnimationInProgressDidChange(node.scrollingNodeID(), false);
 369 node.setScrollAnimationInProgress(false);
 370 }
 371}
 372
338373void ScrollingTreeScrollingNodeDelegateIOS::currentSnapPointIndicesDidChange(unsigned horizontal, unsigned vertical) const
339374{
340375 if (m_updatingFromStateNode)

Source/WebKit/UIProcess/WebPageProxy.cpp

@@void WebPageProxy::setViewNeedsDisplay(const Region& region)
17671767 pageClient().setViewNeedsDisplay(region);
17681768}
17691769
1770 void WebPageProxy::requestScroll(const FloatPoint& scrollPosition, const IntPoint& scrollOrigin)
 1770void WebPageProxy::requestScroll(const FloatPoint& scrollPosition, const IntPoint& scrollOrigin, const bool withAnimation)
17711771{
1772  pageClient().requestScroll(scrollPosition, scrollOrigin);
 1772 if (withAnimation)
 1773 pageClient().requestScrollWithAnimation(scrollPosition, scrollOrigin);
 1774 else
 1775 pageClient().requestScroll(scrollPosition, scrollOrigin);
17731776}
17741777
17751778WebCore::FloatPoint WebPageProxy::viewScrollPosition() const

Source/WebKit/UIProcess/WebPageProxy.h

@@public:
613613 PageClient& pageClient() const;
614614
615615 void setViewNeedsDisplay(const WebCore::Region&);
616  void requestScroll(const WebCore::FloatPoint& scrollPosition, const WebCore::IntPoint& scrollOrigin);
 616 void requestScroll(const WebCore::FloatPoint& scrollPosition, const WebCore::IntPoint& scrollOrigin, bool withAnimation = false);
617617
618618 WebCore::FloatPoint viewScrollPosition() const;
619619

Source/WebKit/UIProcess/ios/PageClientImplIOS.h

@@private:
5757 std::unique_ptr<DrawingAreaProxy> createDrawingAreaProxy(WebProcessProxy&) override;
5858 void setViewNeedsDisplay(const WebCore::Region&) override;
5959 void requestScroll(const WebCore::FloatPoint& scrollPosition, const WebCore::IntPoint& scrollOrigin) override;
 60 void requestScrollWithAnimation(const WebCore::FloatPoint& scrollPosition, const WebCore::IntPoint& scrollOrigin) override;
6061 WebCore::FloatPoint viewScrollPosition() override;
6162 WebCore::IntSize viewSize() override;
6263 bool isViewWindowActive() override;

Source/WebKit/UIProcess/ios/PageClientImplIOS.mm

@@void PageClientImpl::setViewNeedsDisplay(const Region&)
9595
9696void PageClientImpl::requestScroll(const FloatPoint& scrollPosition, const IntPoint& scrollOrigin)
9797{
98  [m_webView _scrollToContentScrollPosition:scrollPosition scrollOrigin:scrollOrigin];
 98 [m_webView _scrollToContentScrollPosition:scrollPosition scrollOrigin:scrollOrigin animated:NO];
 99}
 100
 101void PageClientImpl::requestScrollWithAnimation(const FloatPoint& scrollPosition, const IntPoint& scrollOrigin)
 102{
 103 [m_webView _scrollToContentScrollPosition:scrollPosition scrollOrigin:scrollOrigin animated:YES];
99104}
100105
101106WebCore::FloatPoint PageClientImpl::viewScrollPosition()

Source/WebKit/WebProcess/WebPage/RemoteLayerTree/RemoteScrollingCoordinator.h

@@private:
7373 void scrollPositionChangedForNode(WebCore::ScrollingNodeID, const WebCore::FloatPoint& scrollPosition, bool syncLayerPosition);
7474 void currentSnapPointIndicesChangedForNode(WebCore::ScrollingNodeID, unsigned horizontal, unsigned vertical);
7575
 76#if PLATFORM(IOS_FAMILY)
 77 void scrollAnimationInProgressChangedForNode(WebCore::ScrollingNodeID, bool isScrollAnimationInProgress);
 78#endif
 79
7680 WebPage* m_webPage;
7781};
7882

Source/WebKit/WebProcess/WebPage/RemoteLayerTree/RemoteScrollingCoordinator.messages.in

2525messages -> RemoteScrollingCoordinator {
2626 ScrollPositionChangedForNode(uint64_t nodeID, WebCore::FloatPoint scrollPosition, bool syncLayerPosition);
2727 CurrentSnapPointIndicesChangedForNode(uint64_t nodeID, unsigned horizontal, unsigned vertical);
 28#if PLATFORM(IOS_FAMILY)
 29 scrollAnimationInProgressChangedForNode(uint64_t nodeID, bool isScrollAnimationInProgress);
 30#endif
2831}
2932
3033#endif // ENABLE(ASYNC_SCROLLING)

Source/WebKit/WebProcess/WebPage/RemoteLayerTree/RemoteScrollingCoordinator.mm

@@void RemoteScrollingCoordinator::currentSnapPointIndicesChangedForNode(Scrolling
104104 setActiveScrollSnapIndices(nodeID, horizontal, vertical);
105105}
106106
 107#if PLATFORM(IOS_FAMILY)
 108void RemoteScrollingCoordinator::scrollAnimationInProgressChangedForNode(WebCore::ScrollingNodeID nodeID, bool isScrollAnimationInProgress)
 109{
 110 setScrollAnimationInProgress(nodeID, isScrollAnimationInProgress);
 111}
 112#endif
 113
107114} // namespace WebKit
108115
109116#endif // ENABLE(ASYNC_SCROLLING)