summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/css/css-scroll-snap/snap-after-relayout
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 01:14:29 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 01:14:29 +0000
commitfbaf0bb26397aa498eb9156f06d5a6fe34dd7dd8 (patch)
tree4c1ccaf5486d4f2009f9a338a98a83e886e29c97 /testing/web-platform/tests/css/css-scroll-snap/snap-after-relayout
parentReleasing progress-linux version 124.0.1-1~progress7.99u1. (diff)
downloadfirefox-fbaf0bb26397aa498eb9156f06d5a6fe34dd7dd8.tar.xz
firefox-fbaf0bb26397aa498eb9156f06d5a6fe34dd7dd8.zip
Merging upstream version 125.0.1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'testing/web-platform/tests/css/css-scroll-snap/snap-after-relayout')
-rw-r--r--testing/web-platform/tests/css/css-scroll-snap/snap-after-relayout/multiple-aligned-targets/common-to-both-axes-supercedes-first-in-tree-order.html174
-rw-r--r--testing/web-platform/tests/css/css-scroll-snap/snap-after-relayout/multiple-aligned-targets/nested-supercedes-common-to-both-axes.html91
-rw-r--r--testing/web-platform/tests/css/css-scroll-snap/snap-after-relayout/multiple-aligned-targets/positioned-target-iframe.html73
-rw-r--r--testing/web-platform/tests/css/css-scroll-snap/snap-after-relayout/multiple-aligned-targets/prefer-common-to-both-axes.html151
-rw-r--r--testing/web-platform/tests/css/css-scroll-snap/snap-after-relayout/multiple-aligned-targets/prefer-first-in-tree-order.html164
-rw-r--r--testing/web-platform/tests/css/css-scroll-snap/snap-after-relayout/multiple-aligned-targets/prefer-focused-element.html24
-rw-r--r--testing/web-platform/tests/css/css-scroll-snap/snap-after-relayout/multiple-aligned-targets/prefer-focused-nested-containers.html12
-rw-r--r--testing/web-platform/tests/css/css-scroll-snap/snap-after-relayout/multiple-aligned-targets/prefer-inner-target.html158
-rw-r--r--testing/web-platform/tests/css/css-scroll-snap/snap-after-relayout/multiple-aligned-targets/prefer-targeted-element-iframe.html53
-rw-r--r--testing/web-platform/tests/css/css-scroll-snap/snap-after-relayout/multiple-aligned-targets/prefer-targeted-element-main-frame-target.html137
-rw-r--r--testing/web-platform/tests/css/css-scroll-snap/snap-after-relayout/multiple-aligned-targets/prefer-targeted-element-main-frame.html62
-rw-r--r--testing/web-platform/tests/css/css-scroll-snap/snap-after-relayout/multiple-aligned-targets/prefer-targeted-element-positioned.html76
-rw-r--r--testing/web-platform/tests/css/css-scroll-snap/snap-after-relayout/multiple-aligned-targets/prefer-targeted-element.html109
-rw-r--r--testing/web-platform/tests/css/css-scroll-snap/snap-after-relayout/multiple-aligned-targets/resources/common.js119
-rw-r--r--testing/web-platform/tests/css/css-scroll-snap/snap-after-relayout/multiple-aligned-targets/stash.py27
15 files changed, 1366 insertions, 64 deletions
diff --git a/testing/web-platform/tests/css/css-scroll-snap/snap-after-relayout/multiple-aligned-targets/common-to-both-axes-supercedes-first-in-tree-order.html b/testing/web-platform/tests/css/css-scroll-snap/snap-after-relayout/multiple-aligned-targets/common-to-both-axes-supercedes-first-in-tree-order.html
new file mode 100644
index 0000000000..d9989316e4
--- /dev/null
+++ b/testing/web-platform/tests/css/css-scroll-snap/snap-after-relayout/multiple-aligned-targets/common-to-both-axes-supercedes-first-in-tree-order.html
@@ -0,0 +1,174 @@
+<!DOCTYPE html>
+<html>
+
+<head>
+ <link rel="help" href="https://drafts.csswg.org/css-scroll-snap" />
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ <script src="/dom/events/scrolling/scroll_support.js"></script>
+ <script src="/resources/testdriver.js"></script>
+ <script src="/resources/testdriver-actions.js"></script>
+ <script src="/resources/testdriver-vendor.js"></script>
+ <script src="resources/common.js"></script>
+</head>
+
+<body>
+ <style>
+ .placeholder {
+ top: 0px;
+ left: 0px;
+ position: absolute;
+ width: 10px;
+ height: 10px;
+ background-color: black;
+ scroll-snap-align: start;
+ }
+ .space {
+ position: absolute;
+ height: 300vh;
+ width: 300vw;
+ top: 100px;
+ left: 100px;
+ }
+ .scroller {
+ overflow: scroll;
+ scroll-snap-type: both mandatory;
+ width: 550px;
+ height: 550px;
+ border: solid 1px black;
+ position: relative;
+ resize: both;
+ }
+ .box {
+ background-color: green;
+ height: 200px;
+ width: 200px;
+ scroll-snap-align: start;
+ position: absolute;
+ border: solid 1px white;
+ }
+ .row {
+ top: 100px;
+ }
+ .col {
+ left: 100px;
+ }
+ /* Place boxes 0 through 4 on a horizontal row. */
+ #box0 {
+ left: 300px;
+ }
+ #box1 {
+ left: 500px;
+ }
+ #box2 {
+ left: 700px;
+ }
+ #box3 {
+ left: 900px;
+ }
+ #box4 {
+ left: 1100px;
+ }
+ /* Place boxes 5 through 9 in a vertical column. */
+ #box5 {
+ top: 300px;
+ }
+ #box6 {
+ top: 500px;
+ }
+ #box7 {
+ top: 700px;
+ }
+ #box8 {
+ top: 900px;
+ }
+ #box9 {
+ top: 1100px;
+ }
+ </style>
+ <div id="scroller" class="scroller">
+ <!-- This placeholder is a snap target at the top-left of the
+ scroller. It gives the scroller an opportunity to scroll to the
+ snap targets, forcing the UA to run the snap point selection
+ algorithm. Each test case ensures the snap point selection algorithm is
+ invoked by:
+ - first resetting the scroller's scroll position to snap to the
+ placeholder,
+ - then configuring the tree-order and layout of the snap
+ targets as necessary,
+ - then scrolling to the snap areas and,
+ - finally, verifying that the correct snap area was selected.
+ Without the scroll from the placeholder to the snap targets, the UA would
+ be correct to simply make the scroller follow the previously selected snap
+ target (i.e. when there was no snap area aligned in both axes) even after
+ the layout changes made by the test. -->
+ <div class="placeholder"></div>
+ <div id="box0" class="row box">Box 0</div>
+ <div id="box1" class="row box">Box 1</div>
+ <div id="box2" class="row box">Box 2</div>
+ <div id="box3" class="row box">Box 3</div>
+ <div id="box4" class="row box">Box 4</div>
+ <div id="box5" class="col box">Box 5</div>
+ <div id="box6" class="col box">Box 6</div>
+ <div id="box7" class="col box">Box 7</div>
+ <div id="box8" class="col box">Box 8</div>
+ <div id="box9" class="col box">Box 9</div>
+ <div class="space" id="space">
+ </div>
+ <script>
+ window.onload = async () => {
+ const scroller = document.getElementById("scroller");
+ const boxes = document.querySelectorAll(".box");
+ const box = (n) => {
+ return boxes[n];
+ }
+
+ async function test(n) {
+ return promise_test(async (t) => {
+ await waitForScrollReset(t, scroller);
+ await waitForCompositorCommit();
+ const target = document.getElementById(`box${n}`);
+
+ assert_equals(scroller.scrollLeft, 0, "scrollLeft is reset");
+ assert_equals(scroller.scrollTop, 0, "scrollTop is reset");
+
+ // Make target the last in tree-order.
+ scroller.removeChild(target);
+ scroller.appendChild(target);
+
+ const old_style = getComputedStyle(target);
+ const old_top = old_style.top;
+ const old_left = old_style.left;
+
+ // Make target snap-aligned in both axes.
+ t.add_cleanup(async () => {
+ target.style.top = old_top;
+ target.style.left = old_left;
+ });
+ target.style.left = "100px";
+ target.style.top = "100px";
+
+ await runScrollSnapSelectionVerificationTest(t, scroller,
+ /*aligned_elements_x=*/[box(5), box(6), box(7), box(8), box(9)],
+ /*aligned_elements_y=*/[box(0), box(1), box(2), box(3), box(4)],
+ /*axis=*/"both",
+ /*expected_target_x*/target,
+ /*expected_target_y*/target);
+ }, `box${n} is common to both axes and is the snap target despite ` +
+ `being last in tree order.`);
+ }
+
+ await test(0);
+ await test(1);
+ await test(2);
+ await test(3);
+ await test(4);
+ await test(5);
+ await test(6);
+ await test(7);
+ await test(8);
+ await test(9);
+ }
+ </script>
+</body>
+<html>
diff --git a/testing/web-platform/tests/css/css-scroll-snap/snap-after-relayout/multiple-aligned-targets/nested-supercedes-common-to-both-axes.html b/testing/web-platform/tests/css/css-scroll-snap/snap-after-relayout/multiple-aligned-targets/nested-supercedes-common-to-both-axes.html
new file mode 100644
index 0000000000..15743026bc
--- /dev/null
+++ b/testing/web-platform/tests/css/css-scroll-snap/snap-after-relayout/multiple-aligned-targets/nested-supercedes-common-to-both-axes.html
@@ -0,0 +1,91 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <link rel="help" href="https://drafts.csswg.org/css-scroll-snap"/>
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ <script src="/dom/events/scrolling/scroll_support.js"></script>
+ <script src="/resources/testdriver.js"></script>
+ <script src="/resources/testdriver-actions.js"></script>
+ <script src="/resources/testdriver-vendor.js"></script>
+ <script src="resources/common.js" ></script>
+ </head>
+ <body>
+ <style>
+ .scroller {
+ overflow: scroll;
+ width: 450px;
+ height: 450px;
+ border: solid 1px black;
+ scroll-snap-type: both mandatory;
+ position: relative;
+ resize: both;
+ }
+ .large-space {
+ height: 300vh;
+ width: 300vw;
+ position: absolute;
+ }
+ .snap {
+ scroll-snap-align: start;
+ }
+ .box {
+ width: 200px;
+ height: 200px;
+ background-color: green;
+ position: absolute;
+ }
+ .inner {
+ width: 50px;
+ height: 50px;
+ background-color: yellow;
+ }
+ #box2 {
+ top: 0px;
+ left: 100px;
+ }
+ #box3 {
+ top: 100px;
+ left: 0px;
+ }
+ </style>
+ <div class="scroller" id="scroller">
+ <div class="large-space"><div>
+ <div id="box1" class="snap box">Box 1</div>
+ <div id="box2" class="inner snap box">Box 2</div>
+ <div id="box3" class="inner snap box">Box 3</div>
+ </div>
+ <script>
+ window.onload = () => {
+ const scroller = document.getElementById("scroller");
+ const boxes = document.querySelectorAll(".snap.box");
+ function box(n) {
+ return boxes[n - 1];
+ }
+
+ promise_test(async (t) => {
+ await waitForCompositorCommit();
+
+ // Box 2 should be selected as the target in the y axis despite Box 1's
+ // being a common target in both axes because Box 2 is nested within
+ // Box 1.
+ await runScrollSnapSelectionVerificationTest(t, scroller,
+ /*aligned_elements_x=*/[],
+ /*aligned_elements_y=*/[box(1), box(2)],
+ /*axis=*/ "y",
+ /*expected_target_x=*/null,
+ /*expected_target_y=*/box(2));
+
+ // Box 3 should be selected as the target in the x axis despite Box 1's
+ // being a common target in both axes because Box 3 is nested within
+ // Box 1.
+ await runScrollSnapSelectionVerificationTest(t, scroller,
+ /*aligned_elements_x=*/[box(1), box(3)],
+ /*aligned_elements_y=*/[],
+ /*axis=*/"x",
+ /*expected_target_x=*/box(3));
+ }, "scroller prefers nested area over area aligned in both axes.");
+ }
+ </script>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/css/css-scroll-snap/snap-after-relayout/multiple-aligned-targets/positioned-target-iframe.html b/testing/web-platform/tests/css/css-scroll-snap/snap-after-relayout/multiple-aligned-targets/positioned-target-iframe.html
new file mode 100644
index 0000000000..65195af621
--- /dev/null
+++ b/testing/web-platform/tests/css/css-scroll-snap/snap-after-relayout/multiple-aligned-targets/positioned-target-iframe.html
@@ -0,0 +1,73 @@
+<!DOCTYPE html>
+<html>
+<body>
+ <style>
+ .target {
+ width: 100px;
+ height: 100px;
+ background-color: green;
+ scroll-snap-align: start;
+ }
+ .placeholder {
+ background-color: purple;
+ }
+ .snapcontainer {
+ border:solid 1px black;
+ overflow: scroll;
+ scroll-snap-type: y mandatory;
+ }
+ .big {
+ height: 315px;
+ width: 600px;
+ position: relative;
+ }
+ .small {
+ height: 115px;
+ width: 120px;
+ }
+ .positioned {
+ position: absolute;
+ }
+ #target1, #target2, #target3, #target4, #target5 {
+ top: 400px;
+ }
+ #target1 {
+ left: 0px;
+ }
+ #target2 {
+ left: 110px;
+ }
+ #target3 {
+ left: 220px;
+ }
+ #target4 {
+ left: 330px;
+ }
+ #target5 {
+ left: 440px;
+ }
+ :target {
+ background-color: yellow;
+ }
+ .large-space {
+ position: absolute;
+ height: 300vh;
+ width: 300vw;
+ }
+ </style>
+ <div id="outer" class="big snapcontainer">
+ <div id="outerplaceholder1" class="placeholder target"></div>
+ <div id="outerplaceholder2" class="placeholder target"></div>
+ <div id="inner" class="small snapcontainer">
+ <div id="innerplaceholder1" class="placeholder target"></div>
+ <div id="innerplaceholder2" class="placeholder target"></div>
+ <div id="target1" class="positioned target"><h1>Box 1</h1></div>
+ <div id="target2" class="positioned target"><h1>Box 2</h1></div>
+ <div id="target3" class="positioned target"><h1>Box 3</h1></div>
+ <div id="target4" class="positioned target"><h1>Box 4</h1></div>
+ <div id="target5" class="positioned target"><h1>Box 5</h1></div>
+ </div>
+ <div class="large-space"></div>
+ </div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-scroll-snap/snap-after-relayout/multiple-aligned-targets/prefer-common-to-both-axes.html b/testing/web-platform/tests/css/css-scroll-snap/snap-after-relayout/multiple-aligned-targets/prefer-common-to-both-axes.html
new file mode 100644
index 0000000000..09b81e7c0d
--- /dev/null
+++ b/testing/web-platform/tests/css/css-scroll-snap/snap-after-relayout/multiple-aligned-targets/prefer-common-to-both-axes.html
@@ -0,0 +1,151 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <link rel="help" href="https://drafts.csswg.org/css-scroll-snap"/>
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ <script src="/dom/events/scrolling/scroll_support.js"></script>
+ <script src="/resources/testdriver.js"></script>
+ <script src="/resources/testdriver-actions.js"></script>
+ <script src="/resources/testdriver-vendor.js"></script>
+ <script src="resources/common.js" ></script>
+ </head>
+ <body>
+ <style>
+ .scroller {
+ overflow: scroll;
+ width: 350px;
+ height: 350px;
+ border: solid 1px black;
+ scroll-snap-type: both mandatory;
+ position: relative;
+ resize: both;
+ }
+ .large-space {
+ height: 300vh;
+ width: 300vw;
+ position: absolute;
+ }
+ .snap {
+ scroll-snap-align: start;
+ }
+ .box {
+ width: 100px;
+ height: 100px;
+ background-color: green;
+ display: inline-block;
+ position: relative;
+ }
+ .grid {
+ position: absolute;
+ width: 350px;
+ height: 350px;
+ }
+ .snap:focus {
+ background-color: blue;
+ }
+ </style>
+ <div class="scroller" id="scroller">
+ <div class="large-space"><div>
+ <div class="grid" id="grid">
+ <div id="box1" tabindex="1" class="snap box">Box 1</div>
+ <div id="box2" tabindex="1" class="snap box">Box 2</div>
+ <div id="box3" tabindex="1" class="snap box">Box 3</div>
+ <div id="box4" tabindex="1" class="snap box">Box 4</div>
+ <div id="box5" tabindex="1" class="snap box">Box 5</div>
+ <div id="box6" tabindex="1" class="snap box">Box 6</div>
+ <div id="box7" tabindex="1" class="snap box">Box 7</div>
+ <div id="box8" tabindex="1" class="snap box">Box 8</div>
+ <div id="box9" tabindex="1" class="snap box">Box 9</div>
+ </div>
+ </div>
+ <script>
+ window.onload = () => {
+ // This test sets up a 3x3 grid within scroller:
+ // -------------------------
+ // | Box 1 | Box 2 | Box 3 |
+ // ------------------------
+ // | Box 4 | Box 5 | Box 6 |
+ // -------------------------
+ // | Box 7 | Box 8 | Box 9 |
+ // -------------------------
+ const scroller = document.getElementById("scroller");
+ const boxes = document.querySelectorAll(".snap.box");
+ function box(n) {
+ return boxes[n - 1];
+ }
+
+ promise_test(async (t) => {
+ await waitForCompositorCommit();
+
+ await runScrollSnapSelectionVerificationTest(t, scroller,
+ /*aligned_elements_x=*/[],
+ /*aligned_elements_y=*/[box(1), box(2), box(3)],
+ /*axis=*/ "y",
+ /*expected_target_x=*/null,
+ /*expected_target_y=*/box(1));
+
+ await runScrollSnapSelectionVerificationTest(t, scroller,
+ /*aligned_elements_x=*/[],
+ /*aligned_elements_y=*/[box(4), box(5), box(6)],
+ /*axis=*/ "y",
+ /*expected_target_x=*/null,
+ /*expected_target_y=*/box(4));
+
+ await runScrollSnapSelectionVerificationTest(t, scroller,
+ /*aligned_elements_x=*/[],
+ /*aligned_elements_y=*/[box(7), box(8), box(9)],
+ /*axis=*/"y",
+ /*expected_target_x=*/null,
+ /*expected_target_y=*/box(7));
+
+ await runScrollSnapSelectionVerificationTest(t, scroller,
+ /*aligned_elements_x=*/[box(1), box(4), box(7)],
+ /*aligned_elements_y=*/[],
+ /*axis=*/"x",
+ /*expected_target_x=*/box(1));
+
+ await runScrollSnapSelectionVerificationTest(t, scroller,
+ /*aligned_elements_x=*/[box(2), box(5), box(8)],
+ /*aligned_elements_y=*/[],
+ /*axis=*/"x",
+ /*expected_target_x=*/box(2));
+
+ await runScrollSnapSelectionVerificationTest(t, scroller,
+ /*aligned_elements_x=*/[box(3), box(6), box(9)],
+ /*aligned_elements_y=*/[],
+ /*axis=*/"x",
+ /*expected_target_x=*/box(3));
+
+ await runScrollSnapSelectionVerificationTest(t, scroller,
+ /*aligned_elements_x=*/[box(2), box(5), box(8)],
+ /*aligned_elements_y=*/[box(4), box(5), box(6)],
+ /*axis=*/"both",
+ /*expected_target_x=*/box(5),
+ /*expected_target_y=*/box(5));
+ }, "scroller prefers target aligned in both axes.");
+
+ promise_test(async (t) => {
+ const box7 = box(7), box8 = box(8), box9 = box(9);
+ const initial_box8_top = box8.offsetTop;
+ t.add_cleanup(() => {
+ box8.style.top = `${initial_box8_top}px`;
+ });
+
+ // Move box 8 below box7 and box9.
+ box8.style.top = `${2 * box8.offsetTop}px`;
+
+ // Snap to box8.
+ scroller.scrollTop = box8.offsetTop;
+
+ // Test that if box7 and box9 are also shifted to align with box7,
+ // box8 is still treated as the selected snap target despite box7 being
+ // aligned on both axes.
+ runLayoutSnapSeletionVerificationTest(t, scroller, [box7, box9],
+ box8, "y");
+ }, "scroller follows selected snap target after layout shift, " +
+ "regardless of common snap area.");
+ }
+ </script>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/css/css-scroll-snap/snap-after-relayout/multiple-aligned-targets/prefer-first-in-tree-order.html b/testing/web-platform/tests/css/css-scroll-snap/snap-after-relayout/multiple-aligned-targets/prefer-first-in-tree-order.html
new file mode 100644
index 0000000000..f4b32e10c7
--- /dev/null
+++ b/testing/web-platform/tests/css/css-scroll-snap/snap-after-relayout/multiple-aligned-targets/prefer-first-in-tree-order.html
@@ -0,0 +1,164 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <link rel="help" href="https://drafts.csswg.org/css-scroll-snap"/>
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ <script src="/dom/events/scrolling/scroll_support.js"></script>
+ <script src="/resources/testdriver.js"></script>
+ <script src="/resources/testdriver-actions.js"></script>
+ <script src="/resources/testdriver-vendor.js"></script>
+ <script src="resources/common.js"></script>
+ </head>
+<body>
+ <style>
+ .large-space {
+ position: absolute;
+ height: 300vh;
+ width: 300vw;
+ z-index: -1;
+ }
+ .target {
+ width: 100px;
+ height: 100px;
+ background-color: green;
+ scroll-snap-align: start;
+ }
+ .snapcontainer {
+ border:solid 1px black;
+ overflow: scroll;
+ scroll-snap-type: y mandatory;
+ }
+ .outer {
+ height: 315px;
+ width: 1200px;
+ position: relative;
+ }
+ .inner {
+ height: 115px;
+ width: 120px;
+ }
+ .positioned {
+ position: absolute;
+ top: 150px;
+ }
+ .outer .target1 {
+ left: 0px;
+ }
+ .outer .target2 {
+ left: 110px;
+ }
+ .outer .target3 {
+ left: 220px;
+ }
+ .outer .target4 {
+ left: 330px;
+ }
+ .outer .target5 {
+ left: 440px;
+ }
+ .inner .target1 {
+ left: 550px;
+ }
+ .inner .target2 {
+ left: 660px;
+ }
+ .inner .target3 {
+ left: 770px;
+ }
+ .inner .target4 {
+ left: 880px;
+ }
+ .inner .target5 {
+ left: 990px;
+ }
+ .placeholder {
+ background-color: purple;
+ top: 0px;
+ }
+ .outer > .placeholder {
+ position: absolute;
+ top: 0px;
+ left: 200px;
+ }
+ </style>
+ <!--
+ Placeholder snap areas are used to make it necessary for the scroller to
+ scroll in order to reach its snap targets. This forces the scroller to
+ invoke the snap point selection algorithm. Otherwise (i.e. if no scroll
+ happens) a layout change (inserting and removing children) may not be enough
+ to cause the scroller to select the intended snap targets.
+ -->
+ <div id="outerscroller" class="outer snapcontainer">
+ <div id="outerplaceholder1" class="placeholder target">Outer placeholder
+ </div>
+ <div id="outertarget1" class="positioned target target1">Outer 1</div>
+ <div id="outertarget2" class="positioned target target2">Outer 2</div>
+ <div id="outertarget3" class="positioned target target3">Outer 3</div>
+ <div id="outertarget4" class="positioned target target4">Outer 4</div>
+ <div id="outertarget5" class="positioned target target5">Outer 5</div>
+ <div id="innerscroller" class="inner snapcontainer">
+ <div id="innerplaceholder1" class="placeholder target">Inner Placeholder
+ </div>
+ <div id="innertarget1" class="positioned target target1">Inner 1</div>
+ <div id="innertarget2" class="positioned target target2">Inner 2</div>
+ <div id="innertarget3" class="positioned target target3">Inner 3</div>
+ <div id="innertarget4" class="positioned target target4">Inner 4</div>
+ <div id="innertarget5" class="positioned target target5">Inner 5</div>
+ </div>
+ <div class="large-space"></div>
+ </div>
+ <script>
+ window.onload = async () => {
+ const outerscroller = document.getElementById("outerscroller");
+ const innerscroller = document.getElementById("innerscroller");
+ const outertargets = Array.from(
+ document.querySelectorAll(".outer > .positioned.target"));
+ const innertargets = Array.from(
+ document.querySelectorAll(".inner > .positioned.target"));
+
+ promise_test(async (t) => {
+ for (const target of outertargets) {
+ await waitForScrollReset(t, outerscroller);
+ await waitForCompositorCommit();
+
+ // Make target first in tree order.
+ outerscroller.removeChild(target);
+ outerscroller.prepend(target);
+
+ await runScrollSnapSelectionVerificationTest(t, outerscroller,
+ /*aligned_elements_x=*/[],
+ /*aligned_elements_y=*/outertargets,
+ /*axis=*/"y",
+ /*expected_target_x*/null,
+ /*expected_target_y*/target);
+ }
+
+ // The next for-loop tests outerscroller's selection of
+ // out-of-positioned targets that are children of innerscroller. For
+ // outerscroller to consider them first in tree order relative to its
+ // own children, innerscroller must be the first child of outer
+ // scroller.
+ outerscroller.removeChild(innerscroller);
+ outerscroller.prepend(innerscroller);
+
+ for (const target of innertargets) {
+ await waitForScrollReset(t, outerscroller);
+ await waitForCompositorCommit();
+
+ // Make target first in tree order.
+ innerscroller.removeChild(target);
+ innerscroller.prepend(target);
+
+ await runScrollSnapSelectionVerificationTest(t, outerscroller,
+ /*aligned_elements_x=*/[],
+ /*aligned_elements_y=*/innertargets,
+ /*axis=*/"y",
+ /*expected_target_x*/null,
+ /*expected_target_y*/target);
+ }
+ }, "first in tree-order is selected as snap target.");
+ }
+ </script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-scroll-snap/snap-after-relayout/multiple-aligned-targets/prefer-focused-element.html b/testing/web-platform/tests/css/css-scroll-snap/snap-after-relayout/multiple-aligned-targets/prefer-focused-element.html
index f15a291f08..9acf0e905c 100644
--- a/testing/web-platform/tests/css/css-scroll-snap/snap-after-relayout/multiple-aligned-targets/prefer-focused-element.html
+++ b/testing/web-platform/tests/css/css-scroll-snap/snap-after-relayout/multiple-aligned-targets/prefer-focused-element.html
@@ -71,15 +71,19 @@
focusAndAssert(bottomright);
await runScrollSnapSelectionVerificationTest(t, scroller,
- [bottomright,
- bottomleft],
- /*expected_target=*/bottomright, "y");
+ /*aligned_elements_x=*/[],
+ /*aligned_elements_y=*/[bottomright, bottomleft],
+ /*axis=*/"y",
+ /*expected_target_x=*/null,
+ /*expected_target_y=*/bottomright);
focusAndAssert(bottomleft);
await runScrollSnapSelectionVerificationTest(t, scroller,
- [bottomright,
- bottomleft],
- /*expected_target=*/bottomleft, "y");
+ /*aligned_elements_x=*/[],
+ /*aligned_elements_y=*/[bottomright, bottomleft],
+ /*axis=*/"y",
+ /*expected_target_x=*/null,
+ /*expected_target_y=*/bottomleft);
}, "scroller selects focused target from aligned choices on snap");
promise_test(async (t) => {
@@ -94,9 +98,11 @@
// Set focus on bottomright without scrolling to it.
focusAndAssert(bottomright, true);
await runScrollSnapSelectionVerificationTest(t, scroller,
- [bottomright,
- bottomleft],
- /*expected_target=*/bottomleft, "y");
+ /*aligned_elements_x=*/[],
+ /*aligned_elements_y=*/[bottomright, bottomleft],
+ /*axis=*/"y",
+ /*expected_target_x=*/null,
+ /*expected_target_y=*/bottomleft);
}, "out-of-viewport focused element is not the selected snap target.");
promise_test(async(t) => {
diff --git a/testing/web-platform/tests/css/css-scroll-snap/snap-after-relayout/multiple-aligned-targets/prefer-focused-nested-containers.html b/testing/web-platform/tests/css/css-scroll-snap/snap-after-relayout/multiple-aligned-targets/prefer-focused-nested-containers.html
index a6a087316f..4330022b27 100644
--- a/testing/web-platform/tests/css/css-scroll-snap/snap-after-relayout/multiple-aligned-targets/prefer-focused-nested-containers.html
+++ b/testing/web-platform/tests/css/css-scroll-snap/snap-after-relayout/multiple-aligned-targets/prefer-focused-nested-containers.html
@@ -97,11 +97,19 @@
focusAndAssert(lefttarget1, /*preventScroll=*/true);
await runScrollSnapSelectionVerificationTest(t, outercontainer,
- [leftcontainer, rightcontainer], leftcontainer, "y");
+ /*aligned_elements_x=*/[],
+ /*aligned_elements_y=*/[leftcontainer, rightcontainer],
+ /*axis=*/"y",
+ /*expected_target_x=*/null,
+ /*expected_target_x=*/leftcontainer);
focusAndAssert(righttarget1, /*preventScroll=*/true);
await runScrollSnapSelectionVerificationTest(t, outercontainer,
- [leftcontainer, rightcontainer], rightcontainer, "y");
+ /*aligned_elements_x=*/[],
+ /*aligned_elements_y=*/[leftcontainer, rightcontainer],
+ /*axis=*/"y",
+ /*expected_target_x=*/null,
+ /*expected_target_x=*/rightcontainer);
}, "Snap container prefers focused nested snap target.");
}
</script>
diff --git a/testing/web-platform/tests/css/css-scroll-snap/snap-after-relayout/multiple-aligned-targets/prefer-inner-target.html b/testing/web-platform/tests/css/css-scroll-snap/snap-after-relayout/multiple-aligned-targets/prefer-inner-target.html
new file mode 100644
index 0000000000..3cabbc7945
--- /dev/null
+++ b/testing/web-platform/tests/css/css-scroll-snap/snap-after-relayout/multiple-aligned-targets/prefer-inner-target.html
@@ -0,0 +1,158 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <link rel="help" href="https://drafts.csswg.org/css-scroll-snap" />
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ <script src="/dom/events/scrolling/scroll_support.js"></script>
+ <script src="/resources/testdriver.js"></script>
+ <script src="/resources/testdriver-actions.js"></script>
+ <script src="/resources/testdriver-vendor.js"></script>
+ <script src="resources/common.js" ></script>
+ </head>
+ <body>
+ <style>
+ .scroller {
+ overflow: scroll;
+ position: relative;
+ height: 400px;
+ width: 400px;
+ border:solid 1px black;
+ scroll-snap-type: y mandatory;
+ }
+ .no-snap { scroll-snap-align: none }
+ .scroller div:focus {
+ border: solid 1px red;
+ }
+ .large-space {
+ height: 300vh;
+ width: 300vw;
+ position: absolute;
+ }
+ .target {
+ scroll-snap-align: start;
+ position: absolute;
+ width: 100px;
+ height: 100px;
+ border: solid 1px black;
+ }
+ .top {
+ top: 0px;
+ }
+ .left {
+ left: 0px;
+ }
+ .right {
+ left: 200px;
+ }
+ .bottom {
+ top: 200px;
+ }
+ .inner {
+ text-align: right;
+ }
+ .inner1 {
+ height: 150px;
+ width: 150px;
+ top: 150px;
+ left: 100px;
+ background-color: blue;
+ }
+ .inner2 {
+ height: 100px;
+ width: 100px;
+ top: 150px;
+ left: 100px;
+ background-color: pink;
+ }
+ .inner3 {
+ height: 75px;
+ width: 75px;
+ top: 150px;
+ left: 100px;
+ background-color: green;
+ }
+ .inner4 {
+ height: 50px;
+ width: 50px;
+ top: 150px;
+ left: 100px;
+ background-color: grey;
+ }
+ .outer {
+ height: 200px;
+ width: 200px;
+ top: 150px;
+ left: 50px;
+ left: 50px;
+ background-color: yellow;
+ }
+ </style>
+ <div id="scroller" class="scroller">
+ <div class="large-space"></div>
+ <div class="top left target">Top Left</div>
+ <div class="top right target">Top Right</div>
+ <div class="outer target" id="outer">Outer</div>
+ <div class="inner inner1 target" id="inner1">I1</div>
+ <div class="inner inner2 target" id="inner2">I2</div>
+ <div class="inner inner3 target" id="inner3">I3</div>
+ <div class="inner inner4 target" id="inner4">I4</div>
+ </div>
+ <script>
+ function cleanup() {
+ inner.style.top = 100;
+ outer.style.top = 100;
+ }
+ window.onload = (async () => {
+ const inner1 = document.getElementById("inner1");
+ const inner2 = document.getElementById("inner2");
+ const inner3 = document.getElementById("inner3");
+ const inner4 = document.getElementById("inner4");
+ const outer = document.getElementById("outer");
+ const scroller = document.getElementById("scroller");
+
+ promise_test(async (t) => {
+ await waitForCompositorCommit();
+
+ await runScrollSnapSelectionVerificationTest(t, scroller,
+ /*aligned_elements_x=*/[],
+ /*aligned_elements_y=*/[inner1, inner2, inner3, inner4, outer],
+ /*axis=*/"y",
+ /*expected_target_x*/null,
+ /*expected_target_y*/inner4);
+
+ // Push inner4 outside the snapport. It should no longer be considered
+ // the snap target; inner3 is next in line.
+ inner4.style.left = "500px";
+ await runScrollSnapSelectionVerificationTest(t, scroller,
+ /*aligned_elements_x=*/[],
+ /*aligned_elements_y=*/[inner1, inner2, inner3, inner4, outer],
+ /*axis=*/"y",
+ /*expected_target_x*/null,
+ /*expected_target_y*/inner3);
+
+ // Reset inner4's style.
+ inner4.style.left = "100px";
+ }, "snap container selects innermost area as snap target");
+
+ promise_test(async (t) => {
+ t.add_cleanup(() => {
+ outer.style.top = "150px";
+ });
+ await waitForCompositorCommit();
+
+ // Move outer target below inner targets.
+ outer.style.top = "400px";
+
+ // Snap to now-below outer target.
+ scroller.scrollTop = outer.offsetTop;
+
+ runLayoutSnapSeletionVerificationTest(t, scroller,
+ [inner1, inner2, inner3, inner4], outer, "y");
+ }, "snap container follows selected snap target after layout change " +
+ "(the pre-existing snap target should not be overriden because of " +
+ "the innermost area)");
+ });
+ </script>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/css/css-scroll-snap/snap-after-relayout/multiple-aligned-targets/prefer-targeted-element-iframe.html b/testing/web-platform/tests/css/css-scroll-snap/snap-after-relayout/multiple-aligned-targets/prefer-targeted-element-iframe.html
new file mode 100644
index 0000000000..35b0684b26
--- /dev/null
+++ b/testing/web-platform/tests/css/css-scroll-snap/snap-after-relayout/multiple-aligned-targets/prefer-targeted-element-iframe.html
@@ -0,0 +1,53 @@
+<!DOCTYPE html>
+<html>
+ <body>
+ <style>
+ .scroller {
+ overflow: scroll;
+ width: 350px;
+ height: 350px;
+ border: solid 1px black;
+ scroll-snap-type: y mandatory;
+ position: relative;
+ resize: both;
+ }
+ .large-space {
+ height: 300vh;
+ width: 300vw;
+ position: absolute;
+ }
+ .snap {
+ scroll-snap-align: start;
+ }
+ .box {
+ width: 100px;
+ height: 100px;
+ background-color: green;
+ display: inline-block;
+ position: relative;
+ }
+ .grid {
+ position: absolute;
+ width: 350px;
+ height: 350px;
+ }
+ .snap:target {
+ background-color: blue;
+ }
+ </style>
+ <div class="scroller" id="scroller">
+ <div class="large-space"></div>
+ <div class="grid" id="grid">
+ <div id="box1" class="snap box">Box 1</div>
+ <div id="box2" class="snap box">Box 2</div>
+ <div id="box3" class="snap box">Box 3</div>
+ <div id="box4" class="snap box">Box 4</div>
+ <div id="box5" class="snap box">Box 5</div>
+ <div id="box6" class="snap box">Box 6</div>
+ <div id="box7" class="snap box">Box 7</div>
+ <div id="box8" class="snap box">Box 8</div>
+ <div id="box9" class="snap box">Box 9</div>
+ </div>
+ </div>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/css/css-scroll-snap/snap-after-relayout/multiple-aligned-targets/prefer-targeted-element-main-frame-target.html b/testing/web-platform/tests/css/css-scroll-snap/snap-after-relayout/multiple-aligned-targets/prefer-targeted-element-main-frame-target.html
new file mode 100644
index 0000000000..6bc47d15ef
--- /dev/null
+++ b/testing/web-platform/tests/css/css-scroll-snap/snap-after-relayout/multiple-aligned-targets/prefer-targeted-element-main-frame-target.html
@@ -0,0 +1,137 @@
+<!DOCTYPE html>
+<html>
+<body>
+ <style>
+ #space {
+ height: 300vh;
+ width: 300vw;
+ position: absolute;
+ }
+ #scroller {
+ overflow-y: scroll;
+ scroll-snap-type: y mandatory;
+ width: 450px;
+ height: 450px;
+ border: solid 1px black;
+ position: relative;
+ }
+ .box {
+ height: 200px;
+ width: 200px;
+ position: absolute;
+ background-color: green;
+ scroll-snap-align: start;
+ }
+ .box:target {
+ background-color: red;
+ }
+ .toprow { top: 0px; }
+ .midrow { top: 210px; }
+ .bottomrow { top: 420px; }
+ .leftcol { left: 0px; }
+ .midcol { left: 210px; }
+ .rightcol { left: 420px; }
+ </style>
+ <div id="scroller">
+ <div id="space"></div>
+ <div class="leftcol toprow box" id="box1"></div>
+ <div class="midcol toprow box" id="box2"></div>
+ <div class="rightcol toprow box" id="box3"></div>
+ <div class="leftcol midrow box" id="box4"></div>
+ <div class="midcol midrow box" id="box5"></div>
+ <div class="rightcol midrow box" id="box6"></div>
+ <div class="leftcol bottomrow box" id="box7"></div>
+ <div class="midcol bottomrow box" id="box8"></div>
+ <div class="rightcol bottomrow box" id="box9"></div>
+ </div>
+ <script>
+ // This test sets up a 3x3 grid within scroller:
+ // -------------------------
+ // | Box 1 | Box 2 | Box 3 |
+ // ------------------------
+ // | Box 4 | Box 5 | Box 6 |
+ // -------------------------
+ // | Box 7 | Box 8 | Box 9 |
+ // -------------------------
+ // This function just gets the numbers beside |box_number| on each row.
+ // E.g. 4: 4%3 = 1; so the numbers we want are 5 (4+1) and 6 (4+2).
+ function getAlignedNumbers(n) {
+ n = parseInt(n);
+ const mod_3 = n % 3;
+ if (mod_3 == 1) {
+ return [n + 1, n + 2];
+ } else if (mod_3 == 2) {
+ return [n - 1, n + 1];
+ }
+ return [n - 1, n - 2];
+ }
+ function stashResult(key, result) {
+ fetch(`/css/css-scroll-snap/snap-after-relayout` +
+ `/multiple-aligned-targets/stash.py?key=${key}`, {
+ method: "POST",
+ body: result
+ }).then(() => {
+ window.close();
+ });
+ }
+ function assert_equals(v1, v2) {
+ if (v1 != v2) {
+ throw new Error(`Expected equality of v1(${v1}) and v2(${v2}).`);
+ }
+ }
+ async function record() {
+ let key = (new URL(document.location)).searchParams.get("key");
+ try {
+ // Get the id of that targeted element.
+ const target_id = location.hash.substring(1);
+ const box_number = target_id.substring(3);
+
+ // Get the elements aligned with the targeted element.
+ const target = document.getElementById(target_id);
+ if (target == null) {
+ throw new Error("Null hash fragment target.");
+ }
+ let [aligned_number_1, aligned_number_2] =
+ getAlignedNumbers(box_number);
+ const aligned_box_1 = document.getElementById(`box${aligned_number_1}`);
+ const aligned_box_2 = document.getElementById(`box${aligned_number_2}`);
+
+ // Make sure all the boxes are equally aligned.
+ assert_equals(aligned_box_1.offsetTop, target.offsetTop);
+ assert_equals(aligned_box_1.offsetTop, aligned_box_2.offsetTop);
+
+ // Scroll to the aligned boxes if necessary.
+ if (scroller.scrollTop != target.offsetTop) {
+ const scrollend_promise = new Promise((res) => {
+ scroller.addEventListener(res);
+ });
+ scroller.scrollTop = target.offsetTop;
+ await scrollend_promise;
+ }
+
+ // Save target's original top and move it down by 100px;
+ const original_top = getComputedStyle(target).top;
+ target.style.top = `${target.offsetTop + 100}px`;
+
+ // Assert that scroller followed target as it moved down.
+ assert_equals(scroller.scrollTop, target.offsetTop);
+
+ // Cleanup: undo style change.
+ target.style.top = `${original_top}px`;
+
+ // Stash result.
+ stashResult(key, "PASS");
+ } catch (error) {
+ stashResult(key, error.message);
+ }
+ }
+
+ window.onload = () => {
+ window.requestAnimationFrame(function () {
+ window.requestAnimationFrame(record);
+ })
+ }
+ </script>
+</body>
+
+</html>
diff --git a/testing/web-platform/tests/css/css-scroll-snap/snap-after-relayout/multiple-aligned-targets/prefer-targeted-element-main-frame.html b/testing/web-platform/tests/css/css-scroll-snap/snap-after-relayout/multiple-aligned-targets/prefer-targeted-element-main-frame.html
new file mode 100644
index 0000000000..6221b0e4b5
--- /dev/null
+++ b/testing/web-platform/tests/css/css-scroll-snap/snap-after-relayout/multiple-aligned-targets/prefer-targeted-element-main-frame.html
@@ -0,0 +1,62 @@
+<!DOCTYPE html>
+<html>
+
+<head>
+ <meta charset="utf-8">
+ <title> CSS Scroll Snap Test: snap selection with targeted element</title>
+ <link rel="help" href="https://drafts.csswg.org/css-scroll-snap">
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ <script src="/resources/testdriver.js"></script>
+ <script src="/resources/testdriver-actions.js"></script>
+ <script src="/resources/testdriver-vendor.js"></script>
+ <script src="/common/utils.js"></script>
+</head>
+
+<body onload="runTest()">
+ <script>
+ async function fetchResult(key) {
+ const url = `/css/css-scroll-snap/snap-after-relayout/` +
+ `multiple-aligned-targets/stash.py?key=${key}`;
+ // We may need multiple requests. Return a promise that will be resolved
+ // when an actual response is received.
+ return new Promise(async (resolve) => {
+ async function fetchResultInternal(url) {
+ const response = await fetch(url);
+ const text = await response.text();
+ if (text) {
+ resolve(text);
+ } else {
+ requestAnimationFrame(fetchResultInternal.bind(this, url));
+ }
+ }
+ fetchResultInternal(url);
+ });
+ }
+
+ function runTest() {
+ function test(n) {
+ return promise_test(async (t) => {
+ let key = token();
+
+ test_driver.bless("Open a URL with a text fragment directive", () => {
+ window.open(`prefer-targeted-element-main-frame-target.html` +
+ `?key=${key}#box${n}`, "_blank", "noopener");
+ });
+
+ assert_equals(await fetchResult(key), "PASS");
+ }, `targeted box${n} is selected snap target.`);
+ }
+
+ test(1);
+ test(2);
+ test(3);
+ test(4);
+ test(5);
+ test(6);
+ test(7);
+ test(8);
+ test(9);
+ }
+ </script>
+</body>
diff --git a/testing/web-platform/tests/css/css-scroll-snap/snap-after-relayout/multiple-aligned-targets/prefer-targeted-element-positioned.html b/testing/web-platform/tests/css/css-scroll-snap/snap-after-relayout/multiple-aligned-targets/prefer-targeted-element-positioned.html
new file mode 100644
index 0000000000..3a2b1a9089
--- /dev/null
+++ b/testing/web-platform/tests/css/css-scroll-snap/snap-after-relayout/multiple-aligned-targets/prefer-targeted-element-positioned.html
@@ -0,0 +1,76 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <link rel="help" href="https://drafts.csswg.org/css-scroll-snap"/>
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ <script src="/dom/events/scrolling/scroll_support.js"></script>
+ <script src="/resources/testdriver.js"></script>
+ <script src="/resources/testdriver-actions.js"></script>
+ <script src="/resources/testdriver-vendor.js"></script>
+ <script src="resources/common.js"></script>
+ </head>
+<body>
+ <style>
+ .iframe {
+ height: 1000px;
+ width: 1000px;
+ }
+ </style>
+ <script>
+ window.onload = async () => {
+ await waitForCompositorCommit();
+ async function test(target_number) {
+ return promise_test(async (t) => {
+ let finish = null;
+ const finished = new Promise((res) => { finish = res; });
+ var iframe = document.createElement("iframe");
+ iframe.classList.add("iframe");
+ iframe.onload = async () => {
+ let boxes =
+ iframe.contentDocument.getElementsByClassName("positioned");
+ const box = (i) => {
+ return boxes[i - 1];
+ }
+ let scroller = iframe.contentDocument.getElementById("outer");
+ // There are 5 aligned boxes in positioned-target-iframe.html.
+ assert_equals(boxes.length, 5);
+ await runScrollSnapSelectionVerificationTest(t, scroller,
+ /*aligned_elements_x=*/[],
+ /*aligned_elements_y=*/[box(1), box(2), box(3), box(4), box(5)],
+ /*axis=*/"y",
+ /*expected_target_x*/null,
+ /*expected_target_x*/box(target_number));
+
+ // Let scroller no longer be a scroll container.
+ scroller.style.overflow = "visible";
+ assert_equals(scroller.scrollTop, 0);
+
+ // Let scroller be a scroll container once again.
+ scroller.style.overflow = "scroll";
+
+ // Run the test again.
+ await runScrollSnapSelectionVerificationTest(t, scroller,
+ /*aligned_elements_x=*/[],
+ /*aligned_elements_y=*/[box(1), box(2), box(3), box(4), box(5)],
+ /*axis=*/"y",
+ /*expected_target_x*/null,
+ /*expected_target_x*/box(target_number));
+ finish();
+ };
+ iframe.src = `positioned-target-iframe.html#target${target_number}`;
+ document.body.appendChild(iframe);
+ await finished;
+ document.body.removeChild(iframe);
+ }, "");
+ }
+
+ await test(1);
+ await test(2);
+ await test(3);
+ await test(4);
+ await test(5);
+ }
+ </script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-scroll-snap/snap-after-relayout/multiple-aligned-targets/prefer-targeted-element.html b/testing/web-platform/tests/css/css-scroll-snap/snap-after-relayout/multiple-aligned-targets/prefer-targeted-element.html
new file mode 100644
index 0000000000..ceb9bd2ee0
--- /dev/null
+++ b/testing/web-platform/tests/css/css-scroll-snap/snap-after-relayout/multiple-aligned-targets/prefer-targeted-element.html
@@ -0,0 +1,109 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <link rel="help" href="https://drafts.csswg.org/css-scroll-snap"/>
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ <script src="/dom/events/scrolling/scroll_support.js"></script>
+ <script src="/resources/testdriver.js"></script>
+ <script src="/resources/testdriver-actions.js"></script>
+ <script src="/resources/testdriver-vendor.js"></script>
+ <script src="resources/common.js"></script>
+</head>
+
+<body>
+ <style>
+ .iframe {
+ width: 1000px;
+ height: 1000px;
+ }
+ </style>
+ <script>
+ window.onload = async () => {
+ await waitForCompositorCommit();
+ // This test sets up a 3x3 grid within scroller:
+ // -------------------------
+ // | Box 1 | Box 2 | Box 3 |
+ // ------------------------
+ // | Box 4 | Box 5 | Box 6 |
+ // -------------------------
+ // | Box 7 | Box 8 | Box 9 |
+ // -------------------------
+ // within an iframe.
+ // This function just gets the numbers beside |box_number| on each row.
+ // E.g. 4: 4%3 = 1; so the numbers we want are 5 (4+1) and 6 (4+2).
+ function getAlignedNumbers(n) {
+ const mod_3 = n % 3;
+ if (mod_3 == 1) {
+ return [n + 1, n + 2];
+ } else if (mod_3 == 2) {
+ return [n - 1, n + 1];
+ }
+ return [n - 1, n - 2];
+ }
+
+ async function test(box_number) {
+ return promise_test(async (t) => {
+ let [other_box_1, other_box_2] = getAlignedNumbers(box_number);
+ let finish = null;
+ const finished = new Promise((res) => {
+ finish = res;
+ });
+ var iframe = document.createElement("iframe");
+ iframe.classList.add("iframe");
+ iframe.onload = async () => {
+ let boxes = iframe.contentDocument.getElementsByClassName("box");
+ const box = (i) => {
+ return boxes[i - 1];
+ }
+ let scroller = iframe.contentDocument.getElementById("scroller");
+ assert_equals(boxes.length, 9);
+ await runScrollSnapSelectionVerificationTest(t, scroller,
+ /*aligned_elements_x=*/[],
+ /*aligned_elements_y=*/[box(box_number),
+ box(other_box_1),
+ box(other_box_2)],
+ /*axis=*/"y",
+ /*expected_target_x*/null,
+ /*expected_target_y*/box(box_number));
+
+ // Let scroller no longer be a scroll container.
+ scroller.style.overflow = "visible";
+ assert_equals(scroller.scrollTop, 0);
+
+ // Let scroller be a scroll container once again.
+ scroller.style.overflow = "scroll";
+
+ // Run the test again.
+ await runScrollSnapSelectionVerificationTest(t, scroller,
+ /*aligned_elements_x=*/[],
+ /*aligned_elements_y=*/[box(box_number),
+ box(other_box_1),
+ box(other_box_2)],
+ /*axis=*/"y",
+ /*expected_target_x*/null,
+ /*expected_target_y*/box(box_number));
+
+ finish();
+ };
+ iframe.src = `prefer-targeted-element-iframe.html#box${box_number}`;
+ document.body.appendChild(iframe);
+ await finished;
+ document.body.removeChild(iframe);
+ }, `scroller selects targeted area box${box_number} among multiple` +
+ ` aligned areas.`);
+ }
+
+ await test(1);
+ await test(2);
+ await test(3);
+ await test(4);
+ await test(5);
+ await test(6);
+ await test(7);
+ await test(8);
+ await test(9);
+ }
+ </script>
+</body>
+</html> \ No newline at end of file
diff --git a/testing/web-platform/tests/css/css-scroll-snap/snap-after-relayout/multiple-aligned-targets/resources/common.js b/testing/web-platform/tests/css/css-scroll-snap/snap-after-relayout/multiple-aligned-targets/resources/common.js
index 6ceec9118c..1fd88949b3 100644
--- a/testing/web-platform/tests/css/css-scroll-snap/snap-after-relayout/multiple-aligned-targets/resources/common.js
+++ b/testing/web-platform/tests/css/css-scroll-snap/snap-after-relayout/multiple-aligned-targets/resources/common.js
@@ -6,54 +6,55 @@
// This function should be used by scroll snap WPTs wanting to test snap target
// selection when scrolling to multiple aligned targets.
-// It assumes scroll-snap-align: start alignment and tries to align to the list
-// of snap targets provided, |elements|, which are all expected to be at the
-// same offset.
-async function scrollToAlignedElementsInAxis(scroller, elements, axis) {
+// It assumes scroll-snap-align: start alignment and tries to align to the lists
+// of snap targets provided, |elements_x| and |elements_y|, which are all
+// expected to be at the same offset in the relevant axis.
+async function scrollToAlignedElements(scroller, elements_x, elements_y) {
let target_offset_y = null;
let target_offset_x = null;
- if (axis == "y") {
- for (const e of elements) {
- if (target_offset_y) {
- assert_equals(e.offsetTop, target_offset_y,
- `${e.id} is at y offset ${target_offset_y}`);
- } else {
- target_offset_y = e.offsetTop;
- }
+ for (const e of elements_y) {
+ if (target_offset_y != null) {
+ assert_equals(e.offsetTop, target_offset_y,
+ `${e.id} is at y offset ${target_offset_y}`);
+ } else {
+ target_offset_y = e.offsetTop;
}
- assert_equals();
- } else {
- for (const e of elements) {
- if (target_offset_x) {
- assert_equals(e.offsetLeft, target_offset_x,
- `${e.id} is at x offset ${target_offset_x}`);
- } else {
- target_offset_x = e.offsetLeft;
- }
+ }
+ for (const e of elements_x) {
+ if (target_offset_x != null) {
+ assert_equals(e.offsetLeft, target_offset_x,
+ `${e.id} is at x offset ${target_offset_x}`);
+ } else {
+ target_offset_x = e.offsetLeft;
}
}
- assert_not_equals(target_offset_x || target_offset_y, null);
+ assert_true((target_offset_x != null) || (target_offset_y != null),
+ "scrolls in at least 1 axis");
- const scrollend_promise = waitForScrollendEventNoTimeout(scroller);
- await new test_driver.Actions().scroll(0, 0,
- (target_offset_x || 0) - scroller.scrollLeft,
- (target_offset_y || 0) - scroller.scrollTop,
- { origin: scroller })
- .send();
- await scrollend_promise;
- if (axis == "y") {
+ if ((target_offset_x != null && scroller.scrollLeft != target_offset_x) ||
+ (target_offset_y != null && scroller.scrollTop != target_offset_y)) {
+ const scrollend_promise = waitForScrollendEventNoTimeout(scroller);
+ await new test_driver.Actions().scroll(0, 0,
+ (target_offset_x || scroller.scrollLeft) - scroller.scrollLeft,
+ (target_offset_y || scroller.scrollTop) - scroller.scrollTop,
+ { origin: scroller })
+ .send();
+ await scrollend_promise;
+ }
+ if (target_offset_y) {
assert_equals(scroller.scrollTop, target_offset_y, "vertical scroll done");
- } else {
- assert_equals(scroller.scrollLeft,target_offset_x, "horizontal scroll done");
+ }
+ if (target_offset_x) {
+ assert_equals(scroller.scrollLeft, target_offset_x, "horizontal scroll done");
}
}
-// This function verifies the snap target that a scroller picked by triggerring
+// This function verifies the snap target that a scroller picked by triggering
// a layout change and observing which target is followed. Tests using this
// method should ensure that there is at least 100px of room to scroll in the
// desired axis.
// It assumes scroll-snap-align: start alignment.
-function verifySelectedSnapTarget(scroller, expected_snap_target, axis) {
+function verifySelectedSnapTarget(t, scroller, expected_snap_target, axis) {
// Save initial style.
const initial_left = getComputedStyle(expected_snap_target).left;
const initial_top = getComputedStyle(expected_snap_target).top;
@@ -62,19 +63,26 @@ function verifySelectedSnapTarget(scroller, expected_snap_target, axis) {
const initial_scroll_top = scroller.scrollTop;
const target_top = expected_snap_target.offsetTop + 100;
expected_snap_target.style.top = `${target_top}px`;
- assert_equals(scroller.scrollTop, expected_snap_target.offsetTop,
- `scroller followed ${expected_snap_target.id} after layout change`);
- assert_not_equals(scroller.scrollTop, initial_scroll_top,
- "scroller actually scrolled in y axis");
+ // Wrap these asserts in t.step (which catches exceptions) so that even if
+ // they fail, we'll get to undo the style changes we made, allowing
+ // subsequent tests to run with the expected style/layout.
+ t.step(() => {
+ assert_equals(scroller.scrollTop, expected_snap_target.offsetTop,
+ `scroller followed ${expected_snap_target.id} in y axis after layout change`);
+ assert_not_equals(scroller.scrollTop, initial_scroll_top,
+ "scroller actually scrolled in y axis");
+ });
} else {
- // Move the expected snap target along the y axis.
+ // Move the expected snap target along the x axis.
const initial_scroll_left = scroller.scrollLeft;
const target_left = expected_snap_target.offsetLeft + 100;
expected_snap_target.style.left = `${target_left}px`;
- assert_equals(scroller.scrollLeft, expected_snap_target.offsetLeft,
- `scroller followed ${expected_snap_target.id} after layout change`);
- assert_not_equals(scroller.scrollLeft, initial_scroll_left,
- "scroller actually scrolled in x axis");
+ t.step(() => {
+ assert_equals(scroller.scrollLeft, expected_snap_target.offsetLeft,
+ `scroller followed ${expected_snap_target.id} in x axis after layout change`);
+ assert_not_equals(scroller.scrollLeft, initial_scroll_left,
+ "scroller actually scrolled in x axis");
+ });
}
// Undo style changes.
expected_snap_target.style.top = initial_top;
@@ -83,19 +91,24 @@ function verifySelectedSnapTarget(scroller, expected_snap_target, axis) {
// This is a utility function for tests which verify that the correct element
// is snapped to when snapping at the end of a scroll.
-async function runScrollSnapSelectionVerificationTest(t, scroller, aligned_elements,
- expected_target, axis) {
+async function runScrollSnapSelectionVerificationTest(t, scroller,
+ aligned_elements_x=[], aligned_elements_y=[], axis="",
+ expected_target_x=null, expected_target_y=null) {
// Save initial scroll offset.
const initial_scroll_left = scroller.scrollLeft;
const initial_scroll_top = scroller.scrollTop;
- await scrollToAlignedElementsInAxis(scroller, aligned_elements, axis);
- verifySelectedSnapTarget(scroller, expected_target, axis);
- // Restore initial scroll offsets.
- const scrollend_promise = new Promise((resolve) => {
- scroller.addEventListener("scrollend", resolve);
+ await scrollToAlignedElements(scroller, aligned_elements_x,
+ aligned_elements_y);
+ t.step(() => {
+ if (axis == "y" || axis == "both") {
+ verifySelectedSnapTarget(t, scroller, expected_target_y, axis);
+ }
+ if (axis == "x" || axis == "both") {
+ verifySelectedSnapTarget(t, scroller, expected_target_x, axis);
+ }
});
- scroller.scrollTo(initial_scroll_left, initial_scroll_top);
- await scrollend_promise;
+ // Restore initial scroll offsets.
+ await waitForScrollReset(t, scroller, initial_scroll_left, initial_scroll_top);
}
// This is a utility function for tests verifying that a layout shift does not
@@ -127,7 +140,7 @@ async function runLayoutSnapSeletionVerificationTest(t, scroller, elements_to_al
}
shiftLayoutToAlignElements(elements_to_align, expected_target, axis);
- verifySelectedSnapTarget(scroller, expected_target, axis);
+ verifySelectedSnapTarget(t, scroller, expected_target, axis);
// Restore initial scroll offset and position states.
let num_elements = initial_tops.length;
diff --git a/testing/web-platform/tests/css/css-scroll-snap/snap-after-relayout/multiple-aligned-targets/stash.py b/testing/web-platform/tests/css/css-scroll-snap/snap-after-relayout/multiple-aligned-targets/stash.py
new file mode 100644
index 0000000000..a70672ecf0
--- /dev/null
+++ b/testing/web-platform/tests/css/css-scroll-snap/snap-after-relayout/multiple-aligned-targets/stash.py
@@ -0,0 +1,27 @@
+# Copyright 2024 The Chromium Authors
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+"""
+This file allows the different windows created by
+css/css-scroll-snap/snap-after-relayout/prefer-targeted-element-main-frame.html
+to store and retrieve data.
+
+prefer-targeted-element-main-frame.html (test file) opens a window to
+prefer-targeted-element-main-frame.html-target.html which writes some data
+which the test file will eventually read. This file handles the requests from
+both windows.
+"""
+
+import time
+
+def main(request, response):
+ key = request.GET.first(b"key")
+
+ if request.method == u"POST":
+ # Received result data from target page
+ request.server.stash.put(key, request.body, u'/css/css-scroll-snap/snap-after-relayout/multiple-aligned-targets')
+ return u"ok"
+ else:
+ # Request for result data from test page
+ value = request.server.stash.take(key, u'/css/css-scroll-snap/snap-after-relayout/multiple-aligned-targets')
+ return value