diff options
Diffstat (limited to 'testing/web-platform/tests/css/css-scroll-snap-2')
57 files changed, 4974 insertions, 0 deletions
diff --git a/testing/web-platform/tests/css/css-scroll-snap-2/parsing/scroll-start-computed.html b/testing/web-platform/tests/css/css-scroll-snap-2/parsing/scroll-start-computed.html new file mode 100644 index 0000000000..dd8a5e280f --- /dev/null +++ b/testing/web-platform/tests/css/css-scroll-snap-2/parsing/scroll-start-computed.html @@ -0,0 +1,140 @@ +<!DOCTYPE html> +<html> + +<head> + <meta charset="utf-8"> + <title> CSS Scroll Snap 2 Test: scroll-start-* computed values</title> + <link rel="help" href="https://drafts.csswg.org/css-scroll-snap-2/#scroll-start"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + <script src="/css/support/computed-testcommon.js"></script> +</head> + +<body> + <div id="target"></div> + <script> + test_computed_value("scroll-start", "start"); + test_computed_value("scroll-start", "start start", "start"); + test_computed_value("scroll-start", "100px"); + test_computed_value("scroll-start", "50%"); + test_computed_value("scroll-start", "center"); + test_computed_value("scroll-start", "100px 200px"); + test_computed_value("scroll-start", "50% 100px"); + test_computed_value("scroll-start", "start 50%"); + test_computed_value("scroll-start", "center start", "center"); + test_computed_value("scroll-start", "end center"); + test_computed_value("scroll-start", "top end"); + test_computed_value("scroll-start", "bottom top"); + test_computed_value("scroll-start", "left bottom"); + test_computed_value("scroll-start", "right left"); + test_computed_value("scroll-start", "auto right"); + test_computed_value("scroll-start", "calc(1px)", "1px") + test_computed_value("scroll-start", "calc(1px) start", "1px") + + test_computed_value("scroll-start-block", "100px"); + test_computed_value("scroll-start-block", "50%"); + test_computed_value("scroll-start-block", "start"); + test_computed_value("scroll-start-block", "center"); + test_computed_value("scroll-start-block", "end"); + test_computed_value("scroll-start-block", "top"); + test_computed_value("scroll-start-block", "bottom"); + test_computed_value("scroll-start-block", "left"); + test_computed_value("scroll-start-block", "right"); + test_computed_value("scroll-start-block", "auto"); + test_computed_value("scroll-start-block", "calc(-1px)", "0px"); + + test_computed_value("scroll-start-inline", "100px"); + test_computed_value("scroll-start-inline", "50%"); + test_computed_value("scroll-start-inline", "start"); + test_computed_value("scroll-start-inline", "center"); + test_computed_value("scroll-start-inline", "end"); + test_computed_value("scroll-start-inline", "top"); + test_computed_value("scroll-start-inline", "bottom"); + test_computed_value("scroll-start-inline", "left"); + test_computed_value("scroll-start-inline", "right"); + test_computed_value("scroll-start-inline", "auto"); + test_computed_value("scroll-start-inline", "calc(-1px)", "0px"); + + test_computed_value("scroll-start-x", "100px"); + test_computed_value("scroll-start-x", "50%"); + test_computed_value("scroll-start-x", "start"); + test_computed_value("scroll-start-x", "center"); + test_computed_value("scroll-start-x", "end"); + test_computed_value("scroll-start-x", "top"); + test_computed_value("scroll-start-x", "bottom"); + test_computed_value("scroll-start-x", "left"); + test_computed_value("scroll-start-x", "right"); + test_computed_value("scroll-start-x", "auto"); + test_computed_value("scroll-start-x", "calc(-1px)", "0px"); + + test_computed_value("scroll-start-y", "100px"); + test_computed_value("scroll-start-y", "50%"); + test_computed_value("scroll-start-y", "start"); + test_computed_value("scroll-start-y", "center"); + test_computed_value("scroll-start-y", "end"); + test_computed_value("scroll-start-y", "top"); + test_computed_value("scroll-start-y", "bottom"); + test_computed_value("scroll-start-y", "left"); + test_computed_value("scroll-start-y", "right"); + test_computed_value("scroll-start-y", "auto"); + test_computed_value("scroll-start-y", "calc(-1px)", "0px"); + + target.style = ""; + + // Test logical-physical mapping. + test((t) => { + t.add_cleanup(() => { target.style = ""; }); + target.style.scrollStartBlock = "100px"; + assert_equals(getComputedStyle(target).scrollStartX, "auto"); + assert_equals(getComputedStyle(target).scrollStartY, "100px"); + }, "scroll-start-block maps to scroll-start-y in horizontal writing mode."); + test((t) => { + t.add_cleanup(() => { target.style = ""; }); + target.style.scrollStartInline = "200px"; + assert_equals(getComputedStyle(target).scrollStartX, "200px"); + assert_equals(getComputedStyle(target).scrollStartY, "auto"); + }, "scroll-start-inline maps to scroll-start-x in horizontal writing mode."); + test((t) => { + t.add_cleanup(() => { target.style = ""; }); + target.style.scrollStartX = "100px"; + assert_equals(getComputedStyle(target).scrollStartBlock, "auto"); + assert_equals(getComputedStyle(target).scrollStartInline, "100px"); + }, "scroll-start-x maps to scroll-start-inline in horizontal writing mode."); + test((t) => { + t.add_cleanup(() => { target.style = ""; }); + target.style.scrollStartY = "200px"; + assert_equals(getComputedStyle(target).scrollStartBlock, "200px"); + assert_equals(getComputedStyle(target).scrollStartInline, "auto"); + }, "scroll-start-y maps to scroll-start-block in horizontal writing mode."); + test((t) => { + t.add_cleanup(() => { target.style = ""; }); + target.style.scrollStartBlock = "100px"; + target.style.writingMode = "vertical-lr"; + assert_equals(getComputedStyle(target).scrollStartX, "100px"); + assert_equals(getComputedStyle(target).scrollStartY, "auto"); + }, "scroll-start-block maps to scroll-start-x in vertical writing mode."); + test((t) => { + t.add_cleanup(() => { target.style = ""; }); + target.style.scrollStartInline = "200px"; + target.style.writingMode = "vertical-lr"; + assert_equals(getComputedStyle(target).scrollStartX, "auto"); + assert_equals(getComputedStyle(target).scrollStartY, "200px"); + }, "scroll-start-inline maps to scroll-start-y in vertical writing mode."); + test((t) => { + t.add_cleanup(() => { target.style = ""; }); + target.style.scrollStartX = "100px"; + target.style.writingMode = "vertical-lr"; + assert_equals(getComputedStyle(target).scrollStartBlock, "100px"); + assert_equals(getComputedStyle(target).scrollStartInline, "auto"); + }, "scroll-start-x maps to scroll-start-block in vertical writing mode."); + test((t) => { + t.add_cleanup(() => { target.style = ""; }); + target.style.scrollStartY = "200px"; + target.style.writingMode = "vertical-lr"; + assert_equals(getComputedStyle(target).scrollStartBlock, "auto"); + assert_equals(getComputedStyle(target).scrollStartInline, "200px"); + }, "scroll-start-y maps to scroll-start-inline in vertical writing mode."); + </script> +</body> + +</html>
\ No newline at end of file diff --git a/testing/web-platform/tests/css/css-scroll-snap-2/parsing/scroll-start-invalid.html b/testing/web-platform/tests/css/css-scroll-snap-2/parsing/scroll-start-invalid.html new file mode 100644 index 0000000000..01dbbc4858 --- /dev/null +++ b/testing/web-platform/tests/css/css-scroll-snap-2/parsing/scroll-start-invalid.html @@ -0,0 +1,48 @@ +<!DOCTYPE html> +<html> +<head> + <meta charset="utf-8"> + <title> CSS Scroll Snap 2 Test: scroll-start-block with invalid values</title> + <link rel="help" href="https://drafts.csswg.org/css-scroll-snap-2/#scroll-start"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + <script src="/css/support/parsing-testcommon.js"></script> +</head> +<body> + <script> + test_invalid_value("scroll-start", "-100px"); + test_invalid_value("scroll-start", "-50%"); + test_invalid_value("scroll-start", "invalid_keyword"); + test_invalid_value("scroll-start", "-100px -50%"); + test_invalid_value("scroll-start", "-50% invalid_keyword"); + test_invalid_value("scroll-start", "invalid_keyword invalid_keyword"); + test_invalid_value("scroll-start", "-100px - 100px"); + test_invalid_value("scroll-start", "-50% -100px"); + test_invalid_value("scroll-start", "invalid_keyword -50%"); + test_invalid_value("scroll-start", "-100px invalid_keyword"); + test_invalid_value("scroll-start", "-50% -50%"); + test_invalid_value("scroll-start", "invalid_keyword -100px"); + test_invalid_value("scroll-start", "100px 200px 300px"); + + test_invalid_value("scroll-start-block", "-100px"); + test_invalid_value("scroll-start-block", "-50%"); + test_invalid_value("scroll-start-block", "invalid_keyword"); + test_invalid_value("scroll-start-block", "100px 200px"); + + test_invalid_value("scroll-start-inline", "-100px"); + test_invalid_value("scroll-start-inline", "-50%"); + test_invalid_value("scroll-start-inline", "invalid_keyword"); + test_invalid_value("scroll-start-inline", "100px 200px"); + + test_invalid_value("scroll-start-x", "-100px"); + test_invalid_value("scroll-start-x", "-50%"); + test_invalid_value("scroll-start-x", "invalid_keyword"); + test_invalid_value("scroll-start-x", "100px 200px"); + + test_invalid_value("scroll-start-y", "-100px"); + test_invalid_value("scroll-start-y", "-50%"); + test_invalid_value("scroll-start-y", "invalid_keyword"); + test_invalid_value("scroll-start-y", "100px 200px"); + </script> +</body> +</html> diff --git a/testing/web-platform/tests/css/css-scroll-snap-2/parsing/scroll-start-shorthand.html b/testing/web-platform/tests/css/css-scroll-snap-2/parsing/scroll-start-shorthand.html new file mode 100644 index 0000000000..22e206ec62 --- /dev/null +++ b/testing/web-platform/tests/css/css-scroll-snap-2/parsing/scroll-start-shorthand.html @@ -0,0 +1,63 @@ +<!DOCTYPE html> +<html> +<head> +<meta charset="utf-8"> +<title>CSS Scroll Snap 2 Test: scroll-start sets longhands</title> +<link rel="help" href="https://drafts.csswg.org/css-scroll-snap-2/#scroll-start"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/css/support/shorthand-testcommon.js"></script> +</head> + +<body> + <script> + test_shorthand_value('scroll-start', '100px', { + 'scroll-start-block': '100px', + 'scroll-start-inline': 'start', + }); + test_shorthand_value('scroll-start', '50%', { + 'scroll-start-block': '50%', + 'scroll-start-inline': 'start', + }); + test_shorthand_value('scroll-start', 'center', { + 'scroll-start-block': 'center', + 'scroll-start-inline': 'start', + }); + test_shorthand_value('scroll-start', '100px 200px', { + 'scroll-start-block': '100px', + 'scroll-start-inline': '200px', + }); + test_shorthand_value('scroll-start', '100px 50%', { + 'scroll-start-block': '100px', + 'scroll-start-inline': '50%', + }); + test_shorthand_value('scroll-start', '100px center', { + 'scroll-start-block': '100px', + 'scroll-start-inline': 'center', + }); + test_shorthand_value('scroll-start', '50% 200px', { + 'scroll-start-block': '50%', + 'scroll-start-inline': '200px', + }); + test_shorthand_value('scroll-start', '50% 25%', { + 'scroll-start-block': '50%', + 'scroll-start-inline': '25%', + }); + test_shorthand_value('scroll-start', '50% center', { + 'scroll-start-block': '50%', + 'scroll-start-inline': 'center', + }); + test_shorthand_value('scroll-start', 'center 200px', { + 'scroll-start-block': 'center', + 'scroll-start-inline': '200px', + }); + test_shorthand_value('scroll-start', 'center 25%', { + 'scroll-start-block': 'center', + 'scroll-start-inline': '25%', + }); + test_shorthand_value('scroll-start', 'center end', { + 'scroll-start-block': 'center', + 'scroll-start-inline': 'end', + }); + </script> +</body>
\ No newline at end of file diff --git a/testing/web-platform/tests/css/css-scroll-snap-2/parsing/scroll-start-target-computed.html b/testing/web-platform/tests/css/css-scroll-snap-2/parsing/scroll-start-target-computed.html new file mode 100644 index 0000000000..bb31f2b244 --- /dev/null +++ b/testing/web-platform/tests/css/css-scroll-snap-2/parsing/scroll-start-target-computed.html @@ -0,0 +1,86 @@ +<!DOCTYPE html> +<html> + +<head> + <meta charset="utf-8"> + <title> CSS Scroll Snap 2 Test: scroll-start-target-* computed values</title> + <link rel="help" href="https://drafts.csswg.org/css-scroll-snap-2/#scroll-start"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + <script src="/css/support/computed-testcommon.js"></script> +</head> + +<body> + <div id="target"></div> + <script> + test_computed_value("scroll-start-target-block", "auto"); + test_computed_value("scroll-start-target-block", "none"); + + test_computed_value("scroll-start-target-inline", "auto"); + test_computed_value("scroll-start-target-inline", "none"); + + test_computed_value("scroll-start-target-x", "auto"); + test_computed_value("scroll-start-target-x", "none"); + + test_computed_value("scroll-start-target-y", "auto"); + test_computed_value("scroll-start-target-y", "none"); + + target.style = ""; + + // Test logical-physical mapping. + test((t) => { + t.add_cleanup(() => { target.style = ""; }); + target.style.scrollStartTargetBlock = "auto"; + assert_equals(getComputedStyle(target).scrollStartTargetX, "none"); + assert_equals(getComputedStyle(target).scrollStartTargetY, "auto"); + }, "scroll-start-block maps to scroll-start-y in horizontal writing mode."); + test((t) => { + t.add_cleanup(() => { target.style = ""; }); + target.style.scrollStartTargetInline = "auto"; + assert_equals(getComputedStyle(target).scrollStartTargetX, "auto"); + assert_equals(getComputedStyle(target).scrollStartTargetY, "none"); + }, "scroll-start-inline maps to scroll-start-x in horizontal writing mode."); + test((t) => { + t.add_cleanup(() => { target.style = ""; }); + target.style.scrollStartTargetX = "auto"; + assert_equals(getComputedStyle(target).scrollStartTargetBlock, "none"); + assert_equals(getComputedStyle(target).scrollStartTargetInline, "auto"); + }, "scroll-start-x maps to scroll-start-inline in horizontal writing mode."); + test((t) => { + t.add_cleanup(() => { target.style = ""; }); + target.style.scrollStartTargetY = "auto"; + assert_equals(getComputedStyle(target).scrollStartTargetBlock, "auto"); + assert_equals(getComputedStyle(target).scrollStartTargetInline, "none"); + }, "scroll-start-y maps to scroll-start-block in horizontal writing mode."); + test((t) => { + t.add_cleanup(() => { target.style = ""; }); + target.style.scrollStartTargetBlock = "auto"; + target.style.writingMode = "vertical-lr"; + assert_equals(getComputedStyle(target).scrollStartTargetX, "auto"); + assert_equals(getComputedStyle(target).scrollStartTargetY, "none"); + }, "scroll-start-block maps to scroll-start-x in vertical writing mode."); + test((t) => { + t.add_cleanup(() => { target.style = ""; }); + target.style.scrollStartTargetInline = "auto"; + target.style.writingMode = "vertical-lr"; + assert_equals(getComputedStyle(target).scrollStartTargetX, "none"); + assert_equals(getComputedStyle(target).scrollStartTargetY, "auto"); + }, "scroll-start-inline maps to scroll-start-y in vertical writing mode."); + test((t) => { + t.add_cleanup(() => { target.style = ""; }); + target.style.scrollStartTargetX = "auto"; + target.style.writingMode = "vertical-lr"; + assert_equals(getComputedStyle(target).scrollStartTargetBlock, "auto"); + assert_equals(getComputedStyle(target).scrollStartTargetInline, "none"); + }, "scroll-start-x maps to scroll-start-block in vertical writing mode."); + test((t) => { + t.add_cleanup(() => { target.style = ""; }); + target.style.scrollStartTargetY = "auto"; + target.style.writingMode = "vertical-lr"; + assert_equals(getComputedStyle(target).scrollStartTargetBlock, "none"); + assert_equals(getComputedStyle(target).scrollStartTargetInline, "auto"); + }, "scroll-start-y maps to scroll-start-inline in vertical writing mode."); + </script> +</body> + +</html>
\ No newline at end of file diff --git a/testing/web-platform/tests/css/css-scroll-snap-2/parsing/scroll-start-target-invalid.html b/testing/web-platform/tests/css/css-scroll-snap-2/parsing/scroll-start-target-invalid.html new file mode 100644 index 0000000000..03ca718629 --- /dev/null +++ b/testing/web-platform/tests/css/css-scroll-snap-2/parsing/scroll-start-target-invalid.html @@ -0,0 +1,36 @@ +<!DOCTYPE html> +<html> +<head> + <meta charset="utf-8"> + <title> CSS Scroll Snap 2 Test: scroll-start-target-* with invalid values</title> + <link rel="help" href="https://drafts.csswg.org/css-scroll-snap-2/#scroll-start"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + <script src="/css/support/parsing-testcommon.js"></script> +</head> +<body> + <script> + test_invalid_value("scroll-start-target", "invalid_keyword"); + test_invalid_value("scroll-start-target", "100px"); + test_invalid_value("scroll-start-target", "none none none"); + test_invalid_value("scroll-start-target", "invalid_keyword1 invalid_keyword2"); + test_invalid_value("scroll-start-target", "100px 100px"); + + test_invalid_value("scroll-start-target-block", "invalid_keyword"); + test_invalid_value("scroll-start-target-block", "100px"); + test_invalid_value("scroll-start-target-block", "none none"); + + test_invalid_value("scroll-start-target-inline", "invalid_keyword"); + test_invalid_value("scroll-start-target-inline", "100px"); + test_invalid_value("scroll-start-target-inline", "none none"); + + test_invalid_value("scroll-start-target-x", "invalid_keyword"); + test_invalid_value("scroll-start-target-x", "100px"); + test_invalid_value("scroll-start-target-x", "none none"); + + test_invalid_value("scroll-start-target-y", "invalid_keyword"); + test_invalid_value("scroll-start-target-y", "100px"); + test_invalid_value("scroll-start-target-y", "none none"); + </script> +</body> +</html> diff --git a/testing/web-platform/tests/css/css-scroll-snap-2/parsing/scroll-start-target-shorthand.html b/testing/web-platform/tests/css/css-scroll-snap-2/parsing/scroll-start-target-shorthand.html new file mode 100644 index 0000000000..6017157842 --- /dev/null +++ b/testing/web-platform/tests/css/css-scroll-snap-2/parsing/scroll-start-target-shorthand.html @@ -0,0 +1,31 @@ +<!DOCTYPE html> +<html> +<head> +<meta charset="utf-8"> +<title>CSS Scroll Snap 2 Test: scroll-none-target sets longhands</title> +<link rel="help" href="https://drafts.csswg.org/css-scroll-snap-2/#scroll-start-target"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/css/support/shorthand-testcommon.js"></script> +</head> + +<body> + <script> + test_shorthand_value("scroll-start-target", "none", { + "scroll-start-target-block": "none", + "scroll-start-target-inline": "none", + }); + test_shorthand_value("scroll-start-target", "auto", { + "scroll-start-target-block": "auto", + "scroll-start-target-inline": "none", + }); + test_shorthand_value("scroll-start-target", "none auto", { + "scroll-start-target-block": "none", + "scroll-start-target-inline": "auto", + }); + test_shorthand_value("scroll-start-target", "auto none", { + "scroll-start-target-block": "auto", + "scroll-start-target-inline": "none", + }); + </script> +</body>
\ No newline at end of file diff --git a/testing/web-platform/tests/css/css-scroll-snap-2/parsing/scroll-start-target-valid.html b/testing/web-platform/tests/css/css-scroll-snap-2/parsing/scroll-start-target-valid.html new file mode 100644 index 0000000000..aed964bdff --- /dev/null +++ b/testing/web-platform/tests/css/css-scroll-snap-2/parsing/scroll-start-target-valid.html @@ -0,0 +1,34 @@ +<!DOCTYPE html> +<html> + +<head> + <meta charset="utf-8"> + <title> CSS Scroll Snap 2 Test: scroll-start-target-* with valid values</title> + <link rel="help" href="https://drafts.csswg.org/css-scroll-snap-2/#scroll-start"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + <script src="/css/support/parsing-testcommon.js"></script> +</head> + +<body> + <script> + test_valid_value("scroll-start-target", "none"); + test_valid_value("scroll-start-target", "auto"); + test_valid_value("scroll-start-target", "none auto"); + test_valid_value("scroll-start-target", "auto none", "auto"); + + test_valid_value("scroll-start-target-block", "none"); + test_valid_value("scroll-start-target-block", "auto"); + + test_valid_value("scroll-start-target-inline", "none"); + test_valid_value("scroll-start-target-inline", "auto"); + + test_valid_value("scroll-start-target-x", "none"); + test_valid_value("scroll-start-target-x", "auto"); + + test_valid_value("scroll-start-target-y", "none"); + test_valid_value("scroll-start-target-y", "auto"); + </script> +</body> + +</html>
\ No newline at end of file diff --git a/testing/web-platform/tests/css/css-scroll-snap-2/parsing/scroll-start-valid.html b/testing/web-platform/tests/css/css-scroll-snap-2/parsing/scroll-start-valid.html new file mode 100644 index 0000000000..c472979543 --- /dev/null +++ b/testing/web-platform/tests/css/css-scroll-snap-2/parsing/scroll-start-valid.html @@ -0,0 +1,81 @@ +<!DOCTYPE html> +<html> + +<head> + <meta charset="utf-8"> + <title> CSS Scroll Snap 2 Test: scroll-start-block with valid values</title> + <link rel="help" href="https://drafts.csswg.org/css-scroll-snap-2/#scroll-start"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + <script src="/css/support/parsing-testcommon.js"></script> +</head> + +<body> + <script> + test_valid_value("scroll-start", "start"); + test_valid_value("scroll-start", "start start", "start"); + test_valid_value("scroll-start", "50%"); + test_valid_value("scroll-start", "center"); + test_valid_value("scroll-start", "100px 200px"); + test_valid_value("scroll-start", "50% 100px"); + test_valid_value("scroll-start", "start 50%"); + test_valid_value("scroll-start", "center start", "center"); + test_valid_value("scroll-start", "end center"); + test_valid_value("scroll-start", "top end"); + test_valid_value("scroll-start", "bottom top"); + test_valid_value("scroll-start", "left bottom"); + test_valid_value("scroll-start", "right left"); + test_valid_value("scroll-start", "auto right"); + test_valid_value("scroll-start", "calc(1px) auto"); + + test_valid_value("scroll-start-block", "100px"); + test_valid_value("scroll-start-block", "50%"); + test_valid_value("scroll-start-block", "start"); + test_valid_value("scroll-start-block", "center"); + test_valid_value("scroll-start-block", "end"); + test_valid_value("scroll-start-block", "top"); + test_valid_value("scroll-start-block", "bottom"); + test_valid_value("scroll-start-block", "left"); + test_valid_value("scroll-start-block", "right"); + test_valid_value("scroll-start-block", "auto"); + test_valid_value("scroll-start-block", "calc(-1px)"); + + test_valid_value("scroll-start-inline", "100px"); + test_valid_value("scroll-start-inline", "50%"); + test_valid_value("scroll-start-inline", "start"); + test_valid_value("scroll-start-inline", "center"); + test_valid_value("scroll-start-inline", "end"); + test_valid_value("scroll-start-inline", "top"); + test_valid_value("scroll-start-inline", "bottom"); + test_valid_value("scroll-start-inline", "left"); + test_valid_value("scroll-start-inline", "right"); + test_valid_value("scroll-start-inline", "auto"); + test_valid_value("scroll-start-inline", "calc(-1px)"); + + test_valid_value("scroll-start-x", "100px"); + test_valid_value("scroll-start-x", "50%"); + test_valid_value("scroll-start-x", "start"); + test_valid_value("scroll-start-x", "center"); + test_valid_value("scroll-start-x", "end"); + test_valid_value("scroll-start-x", "top"); + test_valid_value("scroll-start-x", "bottom"); + test_valid_value("scroll-start-x", "left"); + test_valid_value("scroll-start-x", "right"); + test_valid_value("scroll-start-x", "auto"); + test_valid_value("scroll-start-x", "calc(-1px)"); + + test_valid_value("scroll-start-y", "100px"); + test_valid_value("scroll-start-y", "50%"); + test_valid_value("scroll-start-y", "start"); + test_valid_value("scroll-start-y", "center"); + test_valid_value("scroll-start-y", "end"); + test_valid_value("scroll-start-y", "top"); + test_valid_value("scroll-start-y", "bottom"); + test_valid_value("scroll-start-y", "left"); + test_valid_value("scroll-start-y", "right"); + test_valid_value("scroll-start-y", "auto"); + test_valid_value("scroll-start-y", "calc(-1px)"); + </script> +</body> + +</html>
\ No newline at end of file diff --git a/testing/web-platform/tests/css/css-scroll-snap-2/resources/common.js b/testing/web-platform/tests/css/css-scroll-snap-2/resources/common.js new file mode 100644 index 0000000000..1a2edab90b --- /dev/null +++ b/testing/web-platform/tests/css/css-scroll-snap-2/resources/common.js @@ -0,0 +1,106 @@ +function checkSnapEventSupport(event_type) { + if (event_type == "snapchanged") { + assert_true(window.onsnapchanged !== undefined, "snapchanged not supported"); + } else if (event_type == "snapchanging") { + assert_true(window.onsnapchanging !== undefined, "snapchanging not supported"); + } else { + assert_unreached(`Unknown snap event type selected: ${event_type}`); + } +} + +function assertSnapEvent(evt, expected_ids) { + assert_equals(evt.bubbles, false, "snap events don't bubble"); + assert_false(evt.cancelable, "snap events are not cancelable."); + const actual = Array.from(evt.snapTargets, el => el.id).join(","); + const expected = expected_ids.join(","); + assert_equals(actual, expected, "snap event supplied expected targets"); +} + +// This function holds logic intended to be used by tests for scroll snap +// events. +// |test_data| should contain: +// - |scroller|: the snap container being scrolled (or +// document.scrollingElement) +// - |scrolling_function|: this function should trigger the desired snap event +// when executed. +// - |expected_snap_targets|: a list of element ids which the triggered snap +// event should supply in SnapEvent.snapTargets. +// - |expected_scroll_offsets|: the scroll offsets at which the snap container +// should be after scrolling function has been +// executed. +// |event_type|: should be "snapchanged" or "snapchanging". +async function test_snap_event(test, test_data, event_type) { + checkSnapEventSupport(event_type); + await waitForScrollReset(test, test_data.scroller); + + let listener = test_data.scroller == + document.scrollingElement ? document : test_data.scroller; + + const event_promise = waitForSnapEvent(listener, event_type); + await test_data.scrolling_function(); + let evt = await event_promise; + + assertSnapEvent(evt, test_data.expected_snap_targets); + assert_approx_equals(test_data.scroller.scrollTop, + test_data.expected_scroll_offsets.y, 1, + "vertical scroll offset mismatch."); + assert_approx_equals(test_data.scroller.scrollLeft, + test_data.expected_scroll_offsets.x, 1, + "horizontal scroll offset mismatch."); +} + +async function test_snapchanged(test, test_data) { + await test_snap_event(test, test_data, "snapchanged"); +} + +function waitForEventUntil(event_target, event_type, wait_until) { + return new Promise(resolve => { + let result = null; + const listener = (evt) => { + result = evt; + }; + event_target.addEventListener(event_type, listener); + wait_until.then(() => { + event_target.removeEventListener(event_type, listener); + resolve(result); + }); + }); +} + +function waitForEventsUntil(event_target, event_type, wait_until) { + return new Promise(resolve => { + let result = []; + const listener = (evt) => { + result.push(evt); + }; + event_target.addEventListener(event_type, listener); + wait_until.then(() => { + event_target.removeEventListener(event_type, listener); + resolve(result); + }); + }); +} + +// Proxy a wait for a snap event. We want to avoid having a test +// timeout in the event of an expected snap event not firing in a particular +// test case as that would cause the entire file to fail. +// Snap events should fire before scrollend, so if a scroll should happen, wait +// for a scrollend event. Otherwise, just do a rAF-based wait. +function waitForSnapEvent(event_target, event_type, scroll_happens = true) { + return scroll_happens ? waitForEventUntil(event_target, event_type, + waitForScrollendEventNoTimeout(event_target)) + : waitForEventUntil(event_target, event_type, + waitForAnimationFrames(2)); +} + +function waitForSnapChangedEvent(event_target, scroll_happens = true) { + return waitForSnapEvent(event_target, "snapchanged", scroll_happens); +} + +function getScrollbarToScrollerRatio(scroller) { + // Ideally we'd subtract the length of the scrollbar thumb from + // the dividend but there isn't currently a way to get the + // scrollbar thumb length. + return scroller.clientHeight / + (scroller.scrollHeight - scroller.clientHeight); +} diff --git a/testing/web-platform/tests/css/css-scroll-snap-2/resources/user-scroll-common.js b/testing/web-platform/tests/css/css-scroll-snap-2/resources/user-scroll-common.js new file mode 100644 index 0000000000..6587aebd92 --- /dev/null +++ b/testing/web-platform/tests/css/css-scroll-snap-2/resources/user-scroll-common.js @@ -0,0 +1,71 @@ +// Helper functions for snapchanged-on-user-* tests. + +// This performs a touch scroll on |scroller| using the coordinates provided +// in |start_pos| and |end_pos|. +// It is meant for use in snapchanged & snapchanging tests for triggering snap +// events when touch scrolling from |start_pos| to |end_pos|. +function snap_event_touch_scroll_helper(start_pos, end_pos) { + return new test_driver.Actions() + .addPointer("TestPointer", "touch") + .pointerMove(Math.round(start_pos.x), Math.round(start_pos.y)) + .pointerDown() + .addTick() + .pause(200) + .pointerMove(Math.round(end_pos.x), Math.round(end_pos.y)) + .addTick() + .pointerUp() + .send(); +} + +// This drags the provided |scroller|'s scrollbar vertically by |drag_amt|. +// Snap event tests should provide a |drag_amt| that would result in a +// the desired snap event being triggered. +const vertical_offset_into_scrollbar = 30; +function snap_event_scrollbar_drag_helper(scroller, scrollbar_width, drag_amt) { + let x, y, bounds; + if (scroller == document.scrollingElement) { + bounds = document.documentElement.getBoundingClientRect(); + x = Math.round(window.innerWidth - scrollbar_width / 2); + } else { + bounds = scroller.getBoundingClientRect(); + x = Math.round(bounds.right - Math.round(scrollbar_width / 2)); + } + y = Math.round(bounds.top + vertical_offset_into_scrollbar); + return new test_driver.Actions() + .addPointer('TestPointer', 'mouse') + .pointerMove(x, y) + .pointerDown() + .pointerMove(x, Math.round(y + drag_amt)) + .addTick() + .pointerUp() + .send(); +} + +// This tests that snap event of type |event_type| don't fire for a user (wheel) +// scroll that snaps back to the same element. Snap events tests should provide +// a |delta| small enough that no change in |scroller|'s snap targets occurs at +// the end of the scroll. +async function test_no_snap_event(test, scroller, delta, event_type) { + const listening_element = scroller == document.scrollingElement + ? document : scroller; + checkSnapEventSupport(event_type); + await waitForScrollReset(test, scroller); + await waitForCompositorCommit(); + let snap_event_promise = waitForSnapEvent(listening_element, event_type); + // Set the scroll destination to just a little off (0, 0) top so we snap + // back to the top box. + await new test_driver.Actions().scroll(0, 0, delta, delta, + { origin: scroller }).send(); + let evt = await snap_event_promise; + assert_equals(evt, null, "no snap event since scroller is back to top"); + assert_equals(scroller.scrollTop, 0, "scroller snaps back to the top"); + assert_equals(scroller.scrollLeft, 0, "scroller snaps back to the left"); +} + +async function test_no_snapchanged(t, scroller, delta) { + await test_no_snap_event(t, scroller, delta, "snapchanged"); +} + +async function test_no_snapchanging(t, scroller, delta) { + await test_no_snap_event(t, scroller, delta, "snapchanging"); +}
\ No newline at end of file diff --git a/testing/web-platform/tests/css/css-scroll-snap-2/scroll-start-target/scroll-start-target-aligns-with-snap-align.tentative.html b/testing/web-platform/tests/css/css-scroll-snap-2/scroll-start-target/scroll-start-target-aligns-with-snap-align.tentative.html new file mode 100644 index 0000000000..6b133dea7d --- /dev/null +++ b/testing/web-platform/tests/css/css-scroll-snap-2/scroll-start-target/scroll-start-target-aligns-with-snap-align.tentative.html @@ -0,0 +1,74 @@ +<!DOCTYPE html> +<html> + <head> + <meta charset="utf-8"> + <title> CSS Scroll Snap 2 Test: scroll-start-target*</title> + <link rel="help" href="https://drafts.csswg.org/css-scroll-snap-2/#scroll-start-target"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + <script src="/dom/events/scrolling/scroll_support.js"></script> + </head> + <body> + <style> + #space { + width: 1000px; + height: 1000px; + border: solid 1px red; + } + #scroller { + width: 400px; + height: 400px; + overflow: hidden; + border: solid 1px blue; + position: absolute; + } + #target { + width: 100px; + height: 100px; + background-color: pink; + scroll-start-target: auto auto; + position: absolute; + top: 400px; + left: 400px; + } + </style> + <div id="scroller"> + <div id="space"></div> + <div id="target"></div> + </div> + <script> + promise_test(async (t) => { + await waitForCompositorCommit(); + + assert_equals(scroller.scrollTop, 400, + "scroller is vertically scrolled to target"); + assert_equals(scroller.scrollLeft, 400, + "scroller is horizontally scrolled to target"); + + target.style.scrollSnapAlign = "center"; + await waitForCompositorCommit(); + + assert_equals(scroller.scrollTop, 250, + "scroller is vertically aligned to target's center"); + assert_equals(scroller.scrollLeft, 250, + "scroller is horizontally aligned to target's center"); + + target.style.scrollSnapAlign = "end"; + await waitForCompositorCommit(); + + assert_equals(scroller.scrollTop, 100, + "scroller is vertically aligned to target's bottom"); + assert_equals(scroller.scrollLeft, 100, + "scroller is horizontally aligned to target's right"); + + target.style.scrollSnapAlign = "start"; + await waitForCompositorCommit(); + + assert_equals(scroller.scrollTop, 400, + "scroller is vertically aligned to target's top"); + assert_equals(scroller.scrollLeft, 400, + "scroller is horizontally aligned to target's left"); + }, "scroll-start-target aligns with scroll-snap-align"); + </script> + </body> +</html> diff --git a/testing/web-platform/tests/css/css-scroll-snap-2/scroll-start-target/scroll-start-target-display-toggled.tentative.html b/testing/web-platform/tests/css/css-scroll-snap-2/scroll-start-target/scroll-start-target-display-toggled.tentative.html new file mode 100644 index 0000000000..527d750267 --- /dev/null +++ b/testing/web-platform/tests/css/css-scroll-snap-2/scroll-start-target/scroll-start-target-display-toggled.tentative.html @@ -0,0 +1,125 @@ +<!DOCTYPE html> +<html> + <head> + <meta charset="utf-8"> + <title> CSS Scroll Snap 2 Test: scroll-start-target*</title> + <link rel="help" href="https://drafts.csswg.org/css-scroll-snap-2/#scroll-start-target"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body> + <style> + #space-filler { + width: 500px; + height: 500px; + border: solid 1px red; + } + #outer-container { + width: 400px; + height: 400px; + overflow: scroll; + border: solid 2px blue; + } + #inner-container { + top: 20px; + left: 20px; + width: 300px; + height: 300px; + overflow: scroll; + position: relative; + border: solid 2px black; + } + #target { + width: 100px; + height: 100px; + background-color: pink; + scroll-start-target: auto auto; + } + </style> + <div id="outer-container"> + <div id="inner-container"> + <div id="space-filler"></div> + <div id="target"> + </div> + </div> + </div> + <script> + let outer_scroller = document.getElementById("outer-container"); + let inner_scroller = document.getElementById("inner-container"); + let space_filler = document.getElementById("space-filler"); + let target = document.getElementById("target"); + + const target_height = target.getBoundingClientRect().height; + const space_filler_height = space_filler.getBoundingClientRect().height; + const total_content_height = target_height + space_filler_height; + + async function resetDisplay() { + return new Promise((resolve) => { + if (getComputedStyle(outer_scroller).display == "block" && + getComputedStyle(inner_scroller).display == "block" && + getComputedStyle(target).display == "block") { + resolve(); + } else { + outer_scroller.style.display = "block"; + inner_scroller.style.display = "block"; + target.style.display = "block"; + requestAnimationFrame(async () => { + await resetDisplay(); + resolve(); + }); + } + }); + } + + async function waitForDisplay(element, display) { + return new Promise((resolve) => { + if (getComputedStyle(element).display == display) { + resolve(); + } else { + requestAnimationFrame(async () => { + await waitForDisplay(element, display); + resolve(); + }) + } + }); + } + + promise_test(async (t) => { + await resetDisplay(); + let initial_expected_scroll_top = + total_content_height - inner_scroller.clientHeight; + assert_equals(inner_scroller.scrollTop, initial_expected_scroll_top, + "inner-scroller is scrolled to scroll-start-target"); + + let display_promise = waitForDisplay(target, "none"); + target.style.display = "none"; + await display_promise; + + let final_expected_scroll_top = initial_expected_scroll_top - target_height; + assert_equals(inner_scroller.scrollTop, final_expected_scroll_top, + "inner scroller is clamped to updated scroll range"); + }, "display:block scroll-start-target becomes display: none"); + + promise_test(async (t) => { + await resetDisplay(); + let initial_expected_scroll_top = + total_content_height - inner_scroller.clientHeight; + assert_equals(inner_scroller.scrollTop, initial_expected_scroll_top, + "inner-scroller is scrolled to scroll-start-target"); + + let display_promise = waitForDisplay(target, "none"); + target.style.display = "none"; + await display_promise; + assert_equals(inner_scroller.scrollTop, + initial_expected_scroll_top - target_height, + "inner scroller is clamped to updated scroll range"); + + display_promise = waitForDisplay(target, "block"); + target.style.display = "block"; + await display_promise; + assert_equals(inner_scroller.scrollTop, initial_expected_scroll_top, + "inner scroller is updated as scroll-start-target reappears"); + }, "display:none scroll-start-target becomes display: block"); + </script> + </body> +</html> diff --git a/testing/web-platform/tests/css/css-scroll-snap-2/scroll-start-target/scroll-start-target-nested-container.tentative.html b/testing/web-platform/tests/css/css-scroll-snap-2/scroll-start-target/scroll-start-target-nested-container.tentative.html new file mode 100644 index 0000000000..b84803c941 --- /dev/null +++ b/testing/web-platform/tests/css/css-scroll-snap-2/scroll-start-target/scroll-start-target-nested-container.tentative.html @@ -0,0 +1,230 @@ +<!DOCTYPE html> +<html> + <head> + <meta charset="utf-8"> + <title> CSS Scroll Snap 2 Test: scroll-start-target*</title> + <link rel="help" href="https://drafts.csswg.org/css-scroll-snap-2/#scroll-start-target"> + <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="/dom/events/scrolling/scroll_support.js"></script> + </head> + <body> + <style> + #space-filler { + width: 500px; + height: 500px; + background-color: green; + } + #outer-container { + width: 400px; + height: 400px; + overflow: scroll; + background-color: yellow; + } + #inner-container { + top: 20px; + left: 20px; + width: 300px; + height: 300px; + overflow: visible; + position: relative; + background-color: blue; + } + #target { + width: 100px; + height: 100px; + background-color: pink; + scroll-start-target: auto auto; + } + </style> + <div id="outer-container"> + <div id="space-filler"></div> + <div id="inner-container"> + <div id="space-filler"></div> + <div id="target"> + </div> + </div> + </div> + <script> + let outer_container = document.getElementById("outer-container"); + let inner_container = document.getElementById("inner-container"); + let space_filler = document.getElementById("space-filler"); + let target = document.getElementById("target"); + + const inner_scroller_top_offset = 20; + const target_height = target.getBoundingClientRect().height; + const space_filler_height = space_filler.getBoundingClientRect().height; + const inner_content_height = target_height + space_filler_height; + const inner_container_height = inner_container.getBoundingClientRect().height; + + async function resetDisplay() { + return new Promise((resolve) => { + if (getComputedStyle(outer_container).display == "block" && + getComputedStyle(inner_container).display == "block" && + getComputedStyle(target).display == "block") { + resolve(); + } else { + outer_container.style.display = "block"; + inner_container.style.display = "block"; + target.style.display = "block"; + requestAnimationFrame(async () => { + await resetDisplay(); + resolve(); + }); + } + }); + } + + async function waitForCSSProperty(element, property, value) { + return new Promise((resolve) => { + if (getComputedStyle(element)[property] == value) { + resolve(); + } else { + requestAnimationFrame(async () => { + await waitForCSSProperty(element, property, value); + resolve(); + }) + } + }); + } + + async function waitForDisplay(element, value) { + return waitForCSSProperty(element, "display", value); + } + + async function waitForOverflow(element, value) { + return waitForCSSProperty(element, "overflow", value); + } + + let initial_expected_scroll_top = space_filler_height + + inner_scroller_top_offset + inner_content_height - + outer_container.clientHeight; + promise_test(async (t) => { + await resetDisplay(); + assert_equals(outer_container.scrollTop, initial_expected_scroll_top, + "outer-container is scrolled to scroll-start-target"); + + inner_container.style.display = "none"; + await waitForDisplay(inner_container, "none"); + + assert_equals(outer_container.scrollTop, + space_filler_height - outer_container.clientHeight, + "outer-container has no content to scroll"); + + inner_container.style.display = "block"; + await waitForDisplay(inner_container, "block"); + + assert_equals(outer_container.scrollTop, initial_expected_scroll_top, + "outer-scroller is updated as scroll-start-target reappears"); + }, "display:none scroll-start-target becomes display:block"); + + promise_test(async (t) => { + await waitForCompositorCommit(); + await resetDisplay(); + assert_equals(outer_container.scrollTop, initial_expected_scroll_top, + "outer-container is scrolled to scroll-start-target"); + + inner_container.style.overflow = "scroll"; + await waitForOverflow(inner_container, "scroll"); + + // inner-container has become a scroller and should be scrolled to + // scroll-start-target. + assert_equals(inner_container.scrollTop, + inner_content_height - inner_container.clientHeight, + "inner-container is fully scrolled to target"); + // outer-container should be adjusted to its new max scroll offset. + const scrollbar_width = outer_container.offsetHeight - + outer_container.clientHeight; + assert_equals(outer_container.scrollTop, + space_filler_height + inner_scroller_top_offset + + inner_container_height - outer_container.clientHeight, + "outer-container's overflowing content is only its direct " + + "children"); + + inner_container.style.overflow = "visible"; + await waitForOverflow(inner_container, "visible"); + + assert_equals(inner_container.scrollTop, 0, + "inner-container is no longer a scroll container"); + assert_equals(outer_container.scrollTop, initial_expected_scroll_top, + "outer-scroller is the scroll container for target once again"); + }, "intermediate overflow:visible container becomes overflow:scroll"); + + promise_test(async (t) => { + // This test verifies that: + // 1. when both the child and grandchild are scroll-start-targets, the + // grandchild wins/is scrolled to. + // 2. if/when the grandchild stops being a scroll-start-target, the + // child (inner container) is scrolled to. + await waitForCompositorCommit(); + await resetDisplay(); + t.add_cleanup(async () => { + target.style.scrollStartTarget = "auto auto"; + await waitForCSSProperty(target, "scroll-start-target", "auto"); + }); + + assert_equals(outer_container.scrollTop, initial_expected_scroll_top, + "outer-container is scrolled to scroll-start-target"); + // Make the inner container a scroll-start-target. + inner_container.style.scrollStartTarget = "auto auto"; + await waitForCSSProperty(inner_container, "scroll-start-target", "auto"); + + // The inner container has overflow: visible, so it's not the scroll + // container of target. + assert_equals(outer_container.scrollTop, initial_expected_scroll_top, + "outer-container is still scrolled to inner scroll-start-target"); + + // Make target no longer a scroll-start-target. The outer container's + // scroll-start-target should now be the inner container. + target.style.scrollStartTarget = "none none"; + await waitForCSSProperty(target, "scroll-start-target", "none"); + assert_equals(outer_container.scrollTop, + space_filler_height + inner_scroller_top_offset, + "outer-container is scrolled to inner-container"); + }, "inner scroll-start-target takes precedence over outer"); + + promise_test(async (t) => { + // This test verifies that a child which is a scroller, is a + // scroll-start-target, and has a scroll-start-target is scrolled to by + // its scrolling container, and also scrolls to its own + // scroll-start-target. + await waitForCompositorCommit(); + await resetDisplay(); + t.add_cleanup(async () => { + inner_container.style.overflow = "visible"; + inner_container.style.scrollStartTarget = "none none"; + await waitForCSSProperty(inner_container, "overflow", + "visible"); + await waitForCSSProperty(inner_container, "scroll-start-target", + "none"); + }); + + assert_equals(outer_container.scrollTop, initial_expected_scroll_top, + "outer-container is scrolled to scroll-start-target"); + + // Make the inner container a scroll-start-target. + inner_container.style.scrollStartTarget = "auto auto"; + await waitForCSSProperty(inner_container, "scroll-start-target", "auto"); + + assert_equals(outer_container.scrollTop, initial_expected_scroll_top, + "outer-container is still scrolled to inner scroll-start-target"); + + // Make the inner container a scroller. + inner_container.style.overflow = "scroll"; + await waitForOverflow(inner_container, "scroll"); + + assert_equals(outer_container.scrollTop, + space_filler_height + inner_scroller_top_offset + + inner_container.offsetHeight - outer_container.clientHeight, + "outer-container is scrolled to the inner container"); + assert_equals(inner_container.scrollTop, + space_filler_height + target.offsetHeight - + inner_container.clientHeight, + "inner-container is scrolled to target"); + }, "scroll containers can also be scroll-start-targets"); + </script> + </body> +</html> diff --git a/testing/web-platform/tests/css/css-scroll-snap-2/scroll-start-target/scroll-start-target-root.tentative.html b/testing/web-platform/tests/css/css-scroll-snap-2/scroll-start-target/scroll-start-target-root.tentative.html new file mode 100644 index 0000000000..f2af38bbab --- /dev/null +++ b/testing/web-platform/tests/css/css-scroll-snap-2/scroll-start-target/scroll-start-target-root.tentative.html @@ -0,0 +1,63 @@ +<!DOCTYPE html> +<html> + +<head> + <meta charset="utf-8"> + <title> CSS Scroll Snap 2 Test: scroll-start-target*</title> + <link rel="help" href="https://drafts.csswg.org/css-scroll-snap-2/#scroll-start-target"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> +</head> + +<body> + <style> + .spacer { + width: 200vw; + height: 200vh; + } + + .box { + position: absolute; + width: 60vw; + height: 60vh; + } + + .top_left { + top: 0px; + left: 0px; + background-color: red; + } + + .center { + top: 60vh; + left: 60vw; + background-color: purple; + scroll-start-target: auto auto; + } + + .bottom_right { + top: 120vh; + left: 120vw; + background-color: yellow; + } + </style> + <div class="spacer"></div> + <div class="top_left box" id="top_left_box"></div> + <div class="center box" id="centerbox"></div> + <div class="bottom_right box"></div> + <script> + test((t) => { + let scroller = document.scrollingElement; + let top_left_box = document.getElementById("top_left_box"); + + const expected_scroll_top = top_left_box.getBoundingClientRect().height; + const expected_scroll_left = top_left_box.getBoundingClientRect().width; + + assert_approx_equals(scroller.scrollTop, expected_scroll_top, 1, + "scroll-start-target sets initial vertical scroll position"); + assert_approx_equals(scroller.scrollLeft, expected_scroll_left, 1, + "scroll-start-target sets initial horizontal scroll position"); + }); + </script> +</body> + diff --git a/testing/web-platform/tests/css/css-scroll-snap-2/scroll-start-target/scroll-start-target-rtl.tentative.html b/testing/web-platform/tests/css/css-scroll-snap-2/scroll-start-target/scroll-start-target-rtl.tentative.html new file mode 100644 index 0000000000..5a2fa0a93c --- /dev/null +++ b/testing/web-platform/tests/css/css-scroll-snap-2/scroll-start-target/scroll-start-target-rtl.tentative.html @@ -0,0 +1,63 @@ +<!DOCTYPE html> +<html> + +<head> + <meta charset="utf-8"> + <title> CSS Scroll Snap 2 Test: scroll-start-target*</title> + <link rel="help" href="https://drafts.csswg.org/css-scroll-snap-2/#scroll-start-target"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> +</head> + +<body> + <style> + #scroller { + height: 500px; + width: 500px; + display: block; + overflow: scroll; + writing-mode: vertical-rl; + } + + .box { + position: relative; + width: 60%; + height: 60%; + } + + .top_right { + top: 0px; + left: 0px; + background-color: red; + } + + .center { + top: 60%; + background-color: purple; + scroll-start-target: auto auto; + } + + .bottom_left { + top: 120%; + background-color: yellow; + } + </style> + <div id="scroller"> + <div class="top_right box" id="box1"></div> + <div class="center box" id="box2"></div> + <div class="bottom_left box" id="box3"></div> + </div> + <script> + let initial_expected_scroll_top = box1.getBoundingClientRect().height; + let initial_expected_scroll_left = -box1.getBoundingClientRect().width; + + test((t) => { + assert_equals(scroller.scrollTop, initial_expected_scroll_top, + "scroller is vertically scrolled to scroll-start-target"); + assert_equals(scroller.scrollLeft, initial_expected_scroll_left, + "scroller is horizontally scrolled to scroll-start-target"); + }, "scroll-start-target reflects vertical rtl writing mode."); + </script> +</body> + +</html>
\ No newline at end of file diff --git a/testing/web-platform/tests/css/css-scroll-snap-2/scroll-start-target/scroll-start-target-with-anchor-navigation-inner-frame.html b/testing/web-platform/tests/css/css-scroll-snap-2/scroll-start-target/scroll-start-target-with-anchor-navigation-inner-frame.html new file mode 100644 index 0000000000..bea0525ecd --- /dev/null +++ b/testing/web-platform/tests/css/css-scroll-snap-2/scroll-start-target/scroll-start-target-with-anchor-navigation-inner-frame.html @@ -0,0 +1,42 @@ +<!DOCTYPE html> +<html> + +<head> +</head> + +<body> + <style> + :root, body { + margin: 0px; + } + + #spacer { + height: 100vh; + width: 100px; + } + + #top_box { + width: 100px; + height: 60vh; + background-color: red; + } + #middle_box { + width: 100px; + height: 60vh; + scroll-start-target: auto auto; + background-color: purple; + } + #bottom_box { + width: 100px; + height: 60vh; + background-color: yellow; + } + </style> + <div id="top_box"><a id="anchor_target_link" href="#anchor_target">Anchor Link</a></div> + <div id="middle_box"></div> + <div id="bottom_box"></div> + <div id="spacer"></div> + <div id="anchor_target">Anchor Target</div> +</body> + +</html> diff --git a/testing/web-platform/tests/css/css-scroll-snap-2/scroll-start-target/scroll-start-target-with-anchor-navigation.tentative.html b/testing/web-platform/tests/css/css-scroll-snap-2/scroll-start-target/scroll-start-target-with-anchor-navigation.tentative.html new file mode 100644 index 0000000000..bc5b75f75f --- /dev/null +++ b/testing/web-platform/tests/css/css-scroll-snap-2/scroll-start-target/scroll-start-target-with-anchor-navigation.tentative.html @@ -0,0 +1,60 @@ +<!DOCTYPE html> +<html> + +<head> + <meta charset="utf-8"> + <title> CSS Scroll Snap 2 Test: scroll-start-target interaction with anchor navigation</title> + <link rel="help" href="https://drafts.csswg.org/css-scroll-snap-2/#scroll-start-target"> + <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="/html/browsers/browsing-the-web/resources/helpers.js"></script> + <script src="/dom/events/scrolling/scroll_support.js"></script> +</head> + +<body> + <iframe id="frame" src="scroll-start-target-with-anchor-navigation-inner-frame.html" onload="runTest()"></iframe> + <script> + function runTest() { + promise_test(async (t) => { + await waitForCompositorCommit(); + let scroller = frame.contentDocument.scrollingElement; + // anchor_target is at the bottom of the frame so the frame should be + // fully scrolled down to bring it into view. + let anchor_target_scrolltop = scroller.scrollHeight - scroller.clientHeight; + let anchor_target_link = frame.contentDocument.getElementById("anchor_target_link"); + + // Expect scroll offset of 100px per scroll-start. + const scroll_start_target_top = 0.6 * frame.contentWindow.innerHeight; + assert_equals(scroller.scrollTop, scroll_start_target_top, + "scroll-start-target sets initial scroll offset"); + + // Scroll away from start position. + scroller.scrollTop = 200; + assert_equals(scroller.scrollTop, 200, + "scrolled away from scroll-start-target"); + + anchor_target_link.click(); + await waitForHashchange(frame.contentWindow); + assert_equals(frame.contentWindow.location.hash, "#anchor_target", + "clicking anchor link navigates to target"); + + // Expect page to be fully scrolled as anchor_target is at the bottom of + // the document. + assert_equals(scroller.scrollTop, anchor_target_scrolltop, + "anchor navigation sets scroll offset"); + + frame.contentWindow.history.back(); + await waitForHashchange(frame.contentWindow); + assert_equals(frame.contentWindow.location.hash, ""); + + assert_equals(scroller.scrollTop, 200, + "scroller returns to previous scroll position, not " + + "scroll-start-target"); + }, "scroll-start-target does not override anchor navigation."); + } + </script> +</body> + diff --git a/testing/web-platform/tests/css/css-scroll-snap-2/scroll-start-target/scroll-start-target-with-hash-fragment-navigation-inner-frame.html b/testing/web-platform/tests/css/css-scroll-snap-2/scroll-start-target/scroll-start-target-with-hash-fragment-navigation-inner-frame.html new file mode 100644 index 0000000000..9bf77363d3 --- /dev/null +++ b/testing/web-platform/tests/css/css-scroll-snap-2/scroll-start-target/scroll-start-target-with-hash-fragment-navigation-inner-frame.html @@ -0,0 +1,48 @@ +<!DOCTYPE html> +<html> + +<head> +</head> + +<body> + <style> + :root { + margin: 0px; + } + + #spacer { + height: 100vh; + width: 100px; + } + + #top_box { + width: 100px; + height: 60vh; + background-color: blue; + } + #middle_box { + width: 100px; + height: 60vh; + scroll-start-target: auto auto; + background-color: purple; + } + #bottom_box { + width: 100px; + height: 60vh; + background-color: yellow; + } + + #fragment_target { + width: 100px; + height: 100px; + background-color: red; + } + </style> + <div id="top_box"></div> + <div id="middle_box"></div> + <div id="bottom_box"></div> + <div id="spacer"></div> + <div id="fragment_target">Fragment Target</div> +</body> + +</html> diff --git a/testing/web-platform/tests/css/css-scroll-snap-2/scroll-start-target/scroll-start-target-with-hash-fragment-navigation.tentative.html b/testing/web-platform/tests/css/css-scroll-snap-2/scroll-start-target/scroll-start-target-with-hash-fragment-navigation.tentative.html new file mode 100644 index 0000000000..2d291c2ef9 --- /dev/null +++ b/testing/web-platform/tests/css/css-scroll-snap-2/scroll-start-target/scroll-start-target-with-hash-fragment-navigation.tentative.html @@ -0,0 +1,34 @@ +<!DOCTYPE html> +<html> + +<head> + <meta charset="utf-8"> + <title> CSS Scroll Snap 2 Test: scroll-start-target interaction with fragment-navigation</title> + <link rel="help" href="https://drafts.csswg.org/css-scroll-snap-2/#scroll-start-target"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> +</head> + +<body> + <iframe id="frame" src="scroll-start-target-with-fragment-navigation-inner-frame.html#fragment_target" + onload="runTest()"></iframe> + <script> + function runTest() { + test((t) => { + let scroller = frame.contentDocument.scrollingElement; + // fragment_target is at the bottom of the frame so the frame should be + // fully scrolled down to bring it into view (despite middle_box being + // the scroll-start-target). + let expected_scroll_top = scroller.scrollHeight - scroller.clientHeight; + // The scroll-start-target is just below top_box which has a height of + // 60vh. + const scroll_start_target_top = 0.6 * frame.contentWindow.innerHeight; + + assert_equals(frame.contentWindow.location.hash, "#fragment_target"); + assert_not_equals(scroll_start_target_top, expected_scroll_top); + assert_equals(frame.contentDocument.scrollingElement.scrollTop, + expected_scroll_top); + }, "scroll-start-target does not override hash fragment navigation"); + } + </script> +</body>
\ No newline at end of file diff --git a/testing/web-platform/tests/css/css-scroll-snap-2/scroll-start-target/scroll-start-target-with-scroll-snap.tentative.html b/testing/web-platform/tests/css/css-scroll-snap-2/scroll-start-target/scroll-start-target-with-scroll-snap.tentative.html new file mode 100644 index 0000000000..9cb66c01fc --- /dev/null +++ b/testing/web-platform/tests/css/css-scroll-snap-2/scroll-start-target/scroll-start-target-with-scroll-snap.tentative.html @@ -0,0 +1,79 @@ +<!DOCTYPE html> +<html> + +<head> + <meta charset="utf-8"> + <title> CSS Scroll Snap 2 Test: scroll-start-target*</title> + <link rel="help" href="https://drafts.csswg.org/css-scroll-snap-2/#scroll-start-target"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> +</head> + +<body> + <style> + .spacer { + width: 1000px; + height: 1000px; + } + + .scroller { + width: 300px; + height: 300px; + border: solid 1px black; + overflow: scroll; + margin: 0px; + position: absolute; + scroll-snap-type: y mandatory; + } + + .box { + position: absolute; + width: 200px; + height: 200px; + } + + .top_left { + top: 0px; + left: 0px; + background-color: red; + } + + .center { + top: 200px; + left: 200px; + background-color: purple; + scroll-start-target: auto auto; + } + + .bottom_right { + top: 400px; + left: 400px; + background-color: yellow; + /* Expect scroller to snap to the top and left border of the bottom right div. */ + scroll-snap-align: start start; + } + </style> + <div class="scroller" id="scroller"> + <div class="spacer"></div> + <div class="top_left box" id="top_left_box"></div> + <div class="center box" id="centerbox"></div> + <div class="bottom_right box"></div> + </div> + <script> + test((t) => { + let scroller = document.getElementById("scroller"); + let top_left_box = document.getElementById("top_left_box"); + let center_box = document.getElementById("center_box"); + + const expected_scroll_top = top_left_box.getBoundingClientRect().height + + centerbox.getBoundingClientRect().height; + const expected_scroll_left = top_left_box.getBoundingClientRect().width; + centerbox.getBoundingClientRect().width; + + assert_approx_equals(scroller.scrollTop, expected_scroll_top, 1, + "scroll-start-target sets initial vertical scroll position"); + assert_approx_equals(scroller.scrollLeft, expected_scroll_left, 1, + "scroll-start-target sets initial horizontal scroll position"); + }); + </script> +</body>
\ No newline at end of file diff --git a/testing/web-platform/tests/css/css-scroll-snap-2/scroll-start-target/scroll-start-target-with-scroll-start-root.tentative.html b/testing/web-platform/tests/css/css-scroll-snap-2/scroll-start-target/scroll-start-target-with-scroll-start-root.tentative.html new file mode 100644 index 0000000000..af99595f25 --- /dev/null +++ b/testing/web-platform/tests/css/css-scroll-snap-2/scroll-start-target/scroll-start-target-with-scroll-start-root.tentative.html @@ -0,0 +1,66 @@ +<!DOCTYPE html> +<html> + +<head> + <meta charset="utf-8"> + <title> CSS Scroll Snap 2 Test: scroll-start-target*</title> + <link rel="help" href="https://drafts.csswg.org/css-scroll-snap-2/#scroll-start-target"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> +</head> + +<body> + <style> + :root { + scroll-start: end end; + } + + .spacer { + width: 200vw; + height: 200vh; + } + + .box { + position: absolute; + width: 60vw; + height: 60vh; + } + + .top_left { + top: 0px; + left: 0px; + background-color: red; + } + + .center { + top: 60vh; + left: 60vw; + background-color: purple; + scroll-start-target: auto auto; + } + + .bottom_right { + top: 120vh; + left: 120vw; + background-color: yellow; + } + </style> + <div class="spacer"></div> + <div class="top_left box" id="top_left_box"></div> + <div class="center box" id="centerbox"></div> + <div class="bottom_right box"></div> + <script> + test((t) => { + let scroller = document.scrollingElement; + let top_left_box = document.getElementById("top_left_box"); + + const expected_scroll_top = top_left_box.getBoundingClientRect().height; + const expected_scroll_left = top_left_box.getBoundingClientRect().width; + + assert_approx_equals(scroller.scrollTop, expected_scroll_top, 1, + "scroll-start-target sets initial vertical scroll position"); + assert_approx_equals(scroller.scrollLeft, expected_scroll_left, 1, + "scroll-start-target sets initial horizontal scroll position"); + }); + </script> +</body>
\ No newline at end of file diff --git a/testing/web-platform/tests/css/css-scroll-snap-2/scroll-start-target/scroll-start-target-with-scroll-start.tentative.html b/testing/web-platform/tests/css/css-scroll-snap-2/scroll-start-target/scroll-start-target-with-scroll-start.tentative.html new file mode 100644 index 0000000000..a37c831288 --- /dev/null +++ b/testing/web-platform/tests/css/css-scroll-snap-2/scroll-start-target/scroll-start-target-with-scroll-start.tentative.html @@ -0,0 +1,75 @@ +<!DOCTYPE html> +<html> + +<head> + <meta charset="utf-8"> + <title> CSS Scroll Snap 2 Test: scroll-start-target*</title> + <link rel="help" href="https://drafts.csswg.org/css-scroll-snap-2/#scroll-start-target"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> +</head> + +<body> + <style> + .spacer { + width: 1000px; + height: 1000px; + } + + .scroller { + width: 300px; + height: 300px; + border: solid 1px black; + overflow: scroll; + margin: 0px; + position: absolute; + scroll-start: end end; + /* This should be overriden by scroll-start-target. */ + } + + .box { + position: absolute; + width: 200px; + height: 200px; + } + + .top_left { + top: 0px; + left: 0px; + background-color: red; + } + + .center { + top: 200px; + left: 200px; + background-color: purple; + scroll-start-target: auto auto; + } + + .bottom_right { + top: 400px; + left: 400px; + background-color: yellow; + } + </style> + <div class="scroller" id="scroller"> + <div class="spacer"></div> + <div class="top_left box" id="top_left_box"></div> + <div class="center box" id="centerbox"></div> + <div class="bottom_right box"></div> + </div> + <script> + test((t) => { + let scroller = document.getElementById("scroller"); + let top_left_box = document.getElementById("top_left_box"); + + const expected_scroll_top = top_left_box.getBoundingClientRect().height; + const expected_scroll_left = top_left_box.getBoundingClientRect().width; + + assert_approx_equals(scroller.scrollTop, expected_scroll_top, 1, + "scroll-start-target sets initial vertical scroll position"); + assert_approx_equals(scroller.scrollLeft, expected_scroll_left, 1, + "scroll-start-target sets initial horizontal scroll position"); + }); + </script> +</body>
\ No newline at end of file diff --git a/testing/web-platform/tests/css/css-scroll-snap-2/scroll-start-target/scroll-start-target-with-text-fragment-navigation-target.html b/testing/web-platform/tests/css/css-scroll-snap-2/scroll-start-target/scroll-start-target-with-text-fragment-navigation-target.html new file mode 100644 index 0000000000..da53e7a566 --- /dev/null +++ b/testing/web-platform/tests/css/css-scroll-snap-2/scroll-start-target/scroll-start-target-with-text-fragment-navigation-target.html @@ -0,0 +1,83 @@ +<!DOCTYPE html> +<html> + +<body> + <style> + :root { + margin: 0px; + } + + #spacer { + height: 100vh; + width: 100px; + } + + #top_box { + width: 100px; + height: 60vh; + background-color: blue; + } + #middle_box { + width: 100px; + height: 60vh; + scroll-start-target: auto auto; + background-color: purple; + } + #bottom_box { + width: 100px; + height: 60vh; + background-color: yellow; + } + + #fragment_target { + width: 100px; + height: 100px; + background-color: red; + } + </style> + <div id="top_box"></div> + <div id="middle_box"></div> + <div id="bottom_box"></div> + <div id="spacer"></div> + <div id="fragment_target">Target</div> + <script> + function stashResult(key, results) { + fetch(`/css/css-scroll-snap-2/scroll-start-target/stash.py?key=${key}`, { + method: "POST", + body: JSON.stringify(results) + }).then(() => { + window.close(); + }); + } + function record() { + let scroll_position = "UNKNOWN"; + // Expect page is scrolled all the way down as the text is at the bottom of + // the page. + const expected_scroll_top = document.scrollingElement.scrollHeight - + document.scrollingElement.clientHeight; + + const scroll_start_target_top = top_box.getBoundingClientRect().height; + + if (document.scrollingElement.scrollTop == scroll_start_target_top) { + scroll_position = "AT_SCROLL_START_TARGET"; + } else if (document.scrollingElement.scrollTop == expected_scroll_top) { + scroll_position = "AT_TEXT_FRAGMENT"; + } + + const result = { + scroll_position: scroll_position + }; + + let key = (new URL(document.location)).searchParams.get("key"); + stashResult(key, result); + } + + window.onload = () => { + window.requestAnimationFrame(function () { + window.requestAnimationFrame(record); + }) + } + </script> +</body> + +</html>
\ No newline at end of file diff --git a/testing/web-platform/tests/css/css-scroll-snap-2/scroll-start-target/scroll-start-target-with-text-fragment-navigation.tentative.html b/testing/web-platform/tests/css/css-scroll-snap-2/scroll-start-target/scroll-start-target-with-text-fragment-navigation.tentative.html new file mode 100644 index 0000000000..f83ea1a036 --- /dev/null +++ b/testing/web-platform/tests/css/css-scroll-snap-2/scroll-start-target/scroll-start-target-with-text-fragment-navigation.tentative.html @@ -0,0 +1,49 @@ +<!DOCTYPE html> +<html> + +<head> + <meta charset="utf-8"> + <title> CSS Scroll Snap 2 Test: scroll-start-target interaction with text-fragment navigation</title> + <link rel="help" href="https://drafts.csswg.org/css-scroll-snap-2/#scroll-start-target"> + <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> + function fetchResult(key, resolve, reject) { + fetch(`/css/css-scroll-snap-2/scroll-start-target/stash.py?key=${key}`).then(response => { + return response.text(); + }).then(text => { + if (text) { + try { + let result = JSON.parse(text); + resolve(result); + } catch (e) { + reject(); + } + } else { + fetchResult(key, resolve, reject); + } + }); + } + + function runTest() { + promise_test(t => new Promise(async (resolve, reject) => { + let key = token(); + + test_driver.bless("Open a URL with a text fragment directive", () => { + window.open(`scroll-start-target-with-text-fragment-navigation-target.html?key=${key}#:~:text=Target`, "_blank", "noopener"); + }); + + fetchResult(key, resolve, reject); + }).then(result => { + assert_equals(result.scroll_position, "AT_TEXT_FRAGMENT"); + }), "scroll-start doesn't override text fragment navigation"); + } + </script> +</body> diff --git a/testing/web-platform/tests/css/css-scroll-snap-2/scroll-start-target/scroll-start-target-with-user-programmatic-scroll.tentative.html b/testing/web-platform/tests/css/css-scroll-snap-2/scroll-start-target/scroll-start-target-with-user-programmatic-scroll.tentative.html new file mode 100644 index 0000000000..2d487e9b85 --- /dev/null +++ b/testing/web-platform/tests/css/css-scroll-snap-2/scroll-start-target/scroll-start-target-with-user-programmatic-scroll.tentative.html @@ -0,0 +1,125 @@ +<!DOCTYPE html> +<html> + +<head> + <meta charset="utf-8"> + <title> CSS Scroll Snap 2 Test: scroll-start-target*</title> + <link rel="help" href="https://drafts.csswg.org/css-scroll-snap-2/#scroll-start-target"> + <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="/dom/events/scrolling/scroll_support.js"></script> +</head> + +<body> + <style> + .spacer { + width: 1000px; + height: 1000px; + } + + .scroller { + width: 300px; + height: 300px; + border: solid 1px black; + overflow: scroll; + margin: 0px; + position: absolute; + } + + .box { + position: absolute; + width: 200px; + height: 200px; + } + + .top_left { + top: 0px; + left: 0px; + background-color: red; + } + + .center { + top: 200px; + left: 200px; + background-color: purple; + scroll-start-target: auto auto; + } + + .bottom_right { + top: 400px; + left: 400px; + background-color: yellow; + } + </style> + <div class="scroller" id="user_scroller"> + <div class="spacer"></div> + <div class="top_left box" id="user_top_left_box"></div> + <div class="center box"></div> + <div class="bottom_right box"></div> + </div> + <div class="scroller" id="programmatic_scroller" style="left: 500px"> + <div class="spacer"></div> + <div class="top_left box" id="programmatic_top_left_box"></div> + <div class="center box"></div> + <div class="bottom_right box"></div> + </div> + <script> + async function user_scroll(scroller, current_offset, target_offset) { + return new test_driver.Actions().scroll(0, 0, + target_offset.x - current_offset.x, + target_offset.y - current_offset.y, { origin: scroller }) + .send(); + } + + function programmatic_scroll(scroller, current_offset, target_offset) { + scroller.scrollTo(target_offset.x, target_offset.y); + } + + async function test_scroll_start_target(test, scroller, msg, scrolling_function) { + await waitForCompositorCommit(); + let top_left_box = document.getElementById("user_top_left_box"); + + let expected_scroll_top = top_left_box.getBoundingClientRect().height; + let expected_scroll_left = top_left_box.getBoundingClientRect().width; + + assert_approx_equals(scroller.scrollTop, expected_scroll_top, 1, + "scroll-start-target sets initial vertical scroll position"); + assert_approx_equals(scroller.scrollLeft, expected_scroll_left, 1, + "scroll-start-target sets initial horizontal scroll position"); + + let scrollend_promise = new Promise((resolve) => { + scroller.addEventListener("scrollend", resolve); + }); + const current_offset = { x: scroller.scrollLeft, y: scroller.scrollTop }; + const target_offset = { + x: current_offset.x + 100, + y: current_offset.y + 100 + }; + await scrolling_function(scroller, current_offset, target_offset); + + // Only wait for scrollend if it is supported. + if (window.onscrollend == null || window.onscrollend != undefined) { + await scrollend_promise; + } + assert_approx_equals(scroller.scrollTop, target_offset.y, 1, + `${msg} (vertical)`); + assert_approx_equals(scroller.scrollLeft, target_offset.x, 1, + `${msg} (horizontal)`); + } + + promise_test(async (t) => { + let scroller = document.getElementById("user_scroller"); + const msg = "user scroll is not overriden in by scroll-start-target"; + await test_scroll_start_target(t, scroller, msg, user_scroll); + }, "scroll-start-target does not override user scroll"); + + promise_test(async (t) => { + let scroller = document.getElementById("programmatic_scroller"); + const msg = "programmatic scroll is not overriden in by scroll-start-target"; + await test_scroll_start_target(t, scroller, msg, programmatic_scroll); + }, "scroll-start-target does not override programmatic scroll"); + </script> +</body>
\ No newline at end of file diff --git a/testing/web-platform/tests/css/css-scroll-snap-2/scroll-start-target/scroll-start-target.tentative.html b/testing/web-platform/tests/css/css-scroll-snap-2/scroll-start-target/scroll-start-target.tentative.html new file mode 100644 index 0000000000..2e679c3739 --- /dev/null +++ b/testing/web-platform/tests/css/css-scroll-snap-2/scroll-start-target/scroll-start-target.tentative.html @@ -0,0 +1,98 @@ +<!DOCTYPE html> +<html> + +<head> + <meta charset="utf-8"> + <title> CSS Scroll Snap 2 Test: scroll-start-target*</title> + <link rel="help" href="https://drafts.csswg.org/css-scroll-snap-2/#scroll-start-target"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> +</head> + +<body> + <style> + .spacer { + width: 1000px; + height: 1000px; + } + + .scroller { + width: 300px; + height: 300px; + border: solid 1px black; + overflow: scroll; + margin: 0px; + position: absolute; + } + + .box { + position: absolute; + width: 200px; + height: 200px; + } + + .top_left { + top: 0px; + left: 0px; + background-color: red; + } + + .target_for_x_and_y { + scroll-start-target: auto auto; + } + + .target_for_x { + scroll-start-target: none auto; + } + + .center { + top: 200px; + left: 200px; + background-color: purple; + } + + .bottom_right { + top: 400px; + left: 400px; + background-color: yellow; + } + </style> + <div class="scroller" id="scroller1"> + <div class="spacer"></div> + <div class="top_left box" id="top_left_box1"></div> + <div class="center box target_for_x_and_y" id="centerbox"></div> + <div class="bottom_right box"></div> + </div> + <div class="scroller" id="scroller2"> + <div class="spacer"></div> + <div class="top_left box" id="top_left_box2"></div> + <div class="center box target_for_x" id="centerbox2"></div> + <div class="bottom_right box"></div> + </div> + <script> + test((t) => { + let scroller = document.getElementById("scroller1"); + let top_left_box = document.getElementById("top_left_box1"); + + const expected_scroll_top = top_left_box.getBoundingClientRect().height; + const expected_scroll_left = top_left_box.getBoundingClientRect().width; + + assert_approx_equals(scroller.scrollTop, expected_scroll_top, 1, + "scroll-start-target sets initial vertical scroll position"); + assert_approx_equals(scroller.scrollLeft, expected_scroll_left, 1, + "scroll-start-target sets initial horizontal scroll position"); + }); + test((t) => { + let scroller = document.getElementById("scroller2"); + let top_left_box = document.getElementById("top_left_box2"); + + const expected_scroll_top = 0; + const expected_scroll_left = top_left_box.getBoundingClientRect().width; + + assert_approx_equals(scroller.scrollTop, expected_scroll_top, 1, + "scroll-start-target sets initial vertical scroll position"); + assert_approx_equals(scroller.scrollLeft, expected_scroll_left, 1, + "scroll-start-target sets initial horizontal scroll position"); + }); + </script> +</body>
\ No newline at end of file diff --git a/testing/web-platform/tests/css/css-scroll-snap-2/scroll-start-target/stash.py b/testing/web-platform/tests/css/css-scroll-snap-2/scroll-start-target/stash.py new file mode 100644 index 0000000000..3c65e2b59b --- /dev/null +++ b/testing/web-platform/tests/css/css-scroll-snap-2/scroll-start-target/stash.py @@ -0,0 +1,27 @@ +# Copyright 2023 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-2/scroll-start-target-with-text-fragment-navigation.html +to store and retrieve data. + +scroll-start-target-with-text-fragment-navigation.html (test file) opens a window to +scroll-start-target-with-text-fragment-navigation-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-2/scroll-start-target/') + return u"ok" + else: + # Request for result data from test page + value = request.server.stash.take(key, u'/css/css-scroll-snap-2/scroll-start-target/') + return value diff --git a/testing/web-platform/tests/css/css-scroll-snap-2/scroll-start/scroll-start-display-toggled.tentative.html b/testing/web-platform/tests/css/css-scroll-snap-2/scroll-start/scroll-start-display-toggled.tentative.html new file mode 100644 index 0000000000..088c14128e --- /dev/null +++ b/testing/web-platform/tests/css/css-scroll-snap-2/scroll-start/scroll-start-display-toggled.tentative.html @@ -0,0 +1,78 @@ +<!DOCTYPE html> +<html> + +<head> + <meta charset="utf-8"> + <title> CSS Scroll Snap 2 Test: scroll-start-*</title> + <link rel="help" href="https://drafts.csswg.org/css-scroll-snap-2/#scroll-start"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> +</head> + +<body> + <style> + #scroller { + height: 100px; + width: 100px; + scroll-start: 100px 200px; + border: solid 1px black; + overflow: scroll; + } + + .spacer { + width: 200vw; + height: 200vh; + border: solid 1px green; + } + </style> + <div id="scroller"> + <div class="spacer"></div> + </div> + <script> + async function assertScrollPositionResetOnDisplayNone(scroller) { + return new Promise((resolve) => { + if (getComputedStyle(scroller)["display"] == "none") { + assert_equals(scroller.scrollTop, 0, "scrollTop is reset"); + assert_equals(scroller.scrollLeft, 0, "scrollLeft is reset"); + resolve(); + } else { + requestAnimationFrame(async () => { + await assertScrollPositionResetOnDisplayNone(scroller); + resove(); + }); + } + }); + } + promise_test(async (t) => { + // This tests that toggling the display of a scroller from none to block + // scroll-start does not reset the scroller's scroll position. + assert_equals(scroller.scrollTop, 100, + "scroll-start: <length> sets initial vertical scroll position"); + assert_equals(scroller.scrollLeft, 200, + "scroll-start: <length> sets initial horizontal scroll position"); + + // Scroll to somewhere other than scroll-start position. + scroller.scrollTop = 200; + scroller.scrollLeft = 100; + assert_equals(scroller.scrollTop, 200, + "vertical scroll position is programmatically adjusted"); + assert_equals(scroller.scrollLeft, 100, + "horizontal scroll position is programmatically adjusted"); + + scroller.style.display = "none"; + assert_equals(getComputedStyle(scroller)["display"], "none"); + + await assertScrollPositionResetOnDisplayNone(scroller); + + scroller.style.display = "block"; + assert_equals(getComputedStyle(scroller)["display"], "block"); + + // Verify that we are again scrolled to the position specified by scroll-start. + assert_equals(scroller.scrollTop, 200, + "scroll-start is not applied vertically after display toggle"); + assert_equals(scroller.scrollLeft, 100, + "scroll-start is not applied horizontally after display toggle"); + }, "scroll-start does not interfer with recovering saved scroll position " + + "after display toggle"); + </script> +</body>
\ No newline at end of file diff --git a/testing/web-platform/tests/css/css-scroll-snap-2/scroll-start/scroll-start-fieldset.tentative.html b/testing/web-platform/tests/css/css-scroll-snap-2/scroll-start/scroll-start-fieldset.tentative.html new file mode 100644 index 0000000000..9a0190506e --- /dev/null +++ b/testing/web-platform/tests/css/css-scroll-snap-2/scroll-start/scroll-start-fieldset.tentative.html @@ -0,0 +1,149 @@ +<!DOCTYPE html> +<html> + +<head> + <meta charset="utf-8"> + <title> CSS Scroll Snap 2 Test: scroll-start-*</title> + <link rel="help" href="https://drafts.csswg.org/css-scroll-snap-2/#scroll-start"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> +</head> + +<body> + <style> + .spacer { + width: 500px; + height: 500px; + border: solid 1px green; + } + + legend { + background-color: #000; + color: #fff; + padding: 0px 0px; + } + + input { + margin: 0rem; + } + + .scroller { + width: 100px; + height: 100px; + border: solid 1px black; + overflow: scroll; + padding-block-start: 0px; + padding-block-end: 0px; + } + </style> + <fieldset id="scroller" class="scroller"> + <div class="spacer"></div> + </fieldset> + <script> + let scroller = document.getElementById("scroller"); + // fieldsets' clientHeight and scrollHeight can be affected by the presence of + // a scrollbar which has been anecdotally measured to be 15 on several + // platforms. + const scrollbar_width = 15; + const max_vertical_scroll_offset = scroller.scrollHeight - + scroller.clientHeight; + // The fieldset's width is set based on the size of its contents: + // https://html.spec.whatwg.org/multipage/form-elements.html#the-fieldset-element + // "For the purpose of calculating the min-content inline size, use the + // greater of the min-content inline size of the rendered legend and the + // min-content inline size of the anonymous fieldset content box." + // So only bother checking vertical scrolling as the adjusted width might + // not permit horizontal scrolling. + let test_cases = [ + { + scroll_start: "100px 200px", + expectation: { + scrollTop: 100, + msg: "scroll-start: <length> sets initial scroll position", + } + }, + { + scroll_start: "25% 75%", + expectation: { + scrollTop: 0.25 * max_vertical_scroll_offset, + msg: "scroll-start: <percent> sets initial scroll position", + } + }, + { + scroll_start: "calc(50px) calc(75px)", + expectation: { + scrollTop: 50, + msg: "scroll-start: <calc> sets initial scroll position", + } + }, + { + scroll_start: "start", + expectation: { + scrollTop: 0, + msg: "scroll-start: start sets initial scroll position", + } + }, + { + scroll_start: "center center", + expectation: { + scrollTop: 0.5 * max_vertical_scroll_offset, + msg: "scroll-start: center sets initial scroll position", + } + }, + { + scroll_start: "end end", + expectation: { + scrollTop: max_vertical_scroll_offset, + msg: "scroll-start: end sets initial scroll position", + } + }, + { + scroll_start: "top top", + expectation: { + scrollTop: 0, + msg: "scroll-start: top sets initial scroll position", + } + }, + { + scroll_start: "bottom bottom", + expectation: { + scrollTop: max_vertical_scroll_offset, + msg: "scroll-start: bottom sets initial scroll position", + } + }, + { + scroll_start: "1000px 2000px", + expectation: { + scrollTop: max_vertical_scroll_offset, + msg: "scroll-start is clamped", + } + } + ]; + + async function resetScroller(scroll_start) { + scroller.style.display = "none"; + assert_equals(getComputedStyle(scroller)["display"], "none"); + + scroller.style["scroll-start"] = scroll_start; + + scroller.style.display = "block"; + assert_equals(getComputedStyle(scroller)["display"], "block"); + assert_equals(scroller.style.scrollStart, scroll_start); + } + + async function test_scroll_start(scroll_start, expectation) { + await resetScroller(scroll_start); + + assert_approx_equals(scroller.scrollTop, expectation.scrollTop, + scrollbar_width, expectation.msg); + } + + + promise_test(async () => { + for (let test_case of test_cases) { + await test_scroll_start(test_case.scroll_start, + test_case.expectation); + } + }, "scroll-start sets default position of fieldset element"); + </script> +</body>
\ No newline at end of file diff --git a/testing/web-platform/tests/css/css-scroll-snap-2/scroll-start/scroll-start-overflow-toggled.tentative.html b/testing/web-platform/tests/css/css-scroll-snap-2/scroll-start/scroll-start-overflow-toggled.tentative.html new file mode 100644 index 0000000000..8829519024 --- /dev/null +++ b/testing/web-platform/tests/css/css-scroll-snap-2/scroll-start/scroll-start-overflow-toggled.tentative.html @@ -0,0 +1,67 @@ +<!DOCTYPE html> +<html> + +<head> + <meta charset="utf-8"> + <title> CSS Scroll Snap 2 Test: scroll-start-*</title> + <link rel="help" href="https://drafts.csswg.org/css-scroll-snap-2/#scroll-start"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> +</head> + +<body> + <style> + #scroller { + height: 100px; + width: 100px; + scroll-start: 100px 200px; + border: solid 1px black; + overflow: scroll; + } + + .spacer { + width: 200vw; + height: 200vh; + border: solid 1px green; + } + </style> + <div id="scroller"> + <div class="spacer"></div> + </div> + <script> + promise_test(async (t) => { + // This tests that toggling the overflow of a scroller from visible to + // scroll doesn't change the scroll position to scroll-start (since + // overflow:visible to overflow:scroll doesn't cause the scroller to be laid + // out again.) + assert_equals(scroller.scrollTop, 100, + "scroll-start: <length> sets initial vertical scroll position"); + assert_equals(scroller.scrollLeft, 200, + "scroll-start: <length> sets initial horizontal scroll position"); + + // Scroll to somewhere other than scroll-start position. + scroller.scrollTop = 200; + scroller.scrollLeft = 100; + // Allow for an animation frame that might be needed for the update to take + // place. + await requestAnimationFrame(() => { }); + assert_equals(scroller.scrollTop, 200, + "vertical scroll position is programmatically adjusted"); + assert_equals(scroller.scrollLeft, 100, + "horizontal scroll position is programmatically adjusted"); + + scroller.style.overflow = "visible"; + assert_equals(getComputedStyle(scroller)["overflow"], "visible"); + scroller.style.overflow = "scroll"; + assert_equals(getComputedStyle(scroller)["overflow"], "scroll"); + + // Verify that the scroll position is not changed. + assert_equals(scroller.scrollTop, 200, + "scroll-start does not reset vertical scroll position on overflow " + + "toggle."); + assert_equals(scroller.scrollLeft, 100, + "scroll-start does not reset vertical scroll position on overflow " + + "toggle."); + }, "scroll-start sets scroller position if overflow is not visible"); + </script> +</body>
\ No newline at end of file diff --git a/testing/web-platform/tests/css/css-scroll-snap-2/scroll-start/scroll-start-root.tentative.html b/testing/web-platform/tests/css/css-scroll-snap-2/scroll-start/scroll-start-root.tentative.html new file mode 100644 index 0000000000..a74a1131e3 --- /dev/null +++ b/testing/web-platform/tests/css/css-scroll-snap-2/scroll-start/scroll-start-root.tentative.html @@ -0,0 +1,33 @@ +<!DOCTYPE html> +<html> + +<head> + <meta charset="utf-8"> + <title> CSS Scroll Snap 2 Test: scroll-start-*</title> + <link rel="help" href="https://drafts.csswg.org/css-scroll-snap-2/#scroll-start"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> +</head> + +<body> + <style> + :root { + scroll-start: 10vh 200px; + } + + .spacer { + width: 200vw; + height: 200vh; + border: solid 1px green; + } + </style> + <div class="spacer"></div> + <script> + promise_test(async (t) => { + assert_equals(window.scrollX, 200, + "scroll-start: <length> sets initial scroll position"); + assert_equals(window.scrollY, 0.1 * window.innerHeight, + "scroll-start: <length> sets initial scroll position"); + }, "scroll-start sets the initial scroll position of the document"); + </script> +</body>
\ No newline at end of file diff --git a/testing/web-platform/tests/css/css-scroll-snap-2/scroll-start/scroll-start-vertical-lr.tentative.html b/testing/web-platform/tests/css/css-scroll-snap-2/scroll-start/scroll-start-vertical-lr.tentative.html new file mode 100644 index 0000000000..7ed152fd9a --- /dev/null +++ b/testing/web-platform/tests/css/css-scroll-snap-2/scroll-start/scroll-start-vertical-lr.tentative.html @@ -0,0 +1,133 @@ +<!DOCTYPE html> +<html> + +<head> + <meta charset="utf-8"> + <title> CSS Scroll Snap 2 Test: scroll-start-*</title> + <link rel="help" href="https://drafts.csswg.org/css-scroll-snap-2/#scroll-start"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> +</head> + +<body> + <style> + .spacer { + width: 500px; + height: 500px; + border: solid 1px green; + } + + .scroller { + width: 100px; + height: 100px; + border: solid 1px black; + overflow: scroll; + writing-mode: vertical-lr; + } + </style> + <div id="lengthscroller" class="scroller" style="scroll-start: 100px"> + <div class="spacer"></div> + </div> + <div id="percentscroller" class="scroller" style="scroll-start: 25%"> + <div class="spacer"></div> + </div> + <div id="calcscroller" class="scroller" style="scroll-start: calc(50px)"> + <div class="spacer"></div> + </div> + <div id="startscroller" class="scroller" style="scroll-start: start"> + <div class="spacer"></div> + </div> + <div id="centerscroller" class="scroller" style="scroll-start: center"> + <div class="spacer"></div> + </div> + <div id="endscroller" class="scroller" style="scroll-start: end"> + <div class="spacer"></div> + </div> + <div id="topscroller" class="scroller" style="scroll-start: 100px top"> + <div class="spacer"></div> + </div> + <div id="bottomscroller" class="scroller" style="scroll-start: 100px bottom"> + <div class="spacer"></div> + </div> + <div id="leftscroller" class="scroller" style="scroll-start: left 100px"> + <div class="spacer"></div> + </div> + <div id="rightscroller" class="scroller" style="scroll-start: right 100px"> + <div class="spacer"></div> + </div> + <div id="clampedscroller" class="scroller" style="scroll-start: 1000px 1000px"> + <div class="spacer"></div> + </div> + <script> + promise_test(async (t) => { + let length_scroller = document.getElementById("lengthscroller"); + assert_equals(length_scroller.scrollLeft, 100, + "scroll-start: <length> sets initial scroll position"); + + let percent_scroller = document.getElementById("percentscroller"); + const percent_scroll_left = 0.25 * (percent_scroller.scrollWidth - + percent_scroller.clientWidth); + assert_approx_equals(percent_scroller.scrollLeft, percent_scroll_left, 1, + "scroll-start: <percent> sets initial scroll position"); + + let calc_scroller = document.getElementById("calcscroller"); + assert_equals(calc_scroller.scrollLeft, 50, + "scroll-start: <calc> sets initial scroll position"); + + let start_scroller = document.getElementById("startscroller"); + assert_equals(start_scroller.scrollLeft, 0, + "scroll-start: start sets initial scroll position"); + + let center_scroller = document.getElementById("centerscroller"); + const center_scroll_top = 0.5 * (center_scroller.scrollHeight - + center_scroller.clientHeight); + assert_approx_equals(center_scroller.scrollLeft, center_scroll_top, 1, + "scroll-start: center sets initial scroll position"); + + let end_scroller = document.getElementById("endscroller"); + const end_scroll_top = end_scroller.scrollWidth - + end_scroller.clientWidth; + assert_equals(end_scroller.scrollLeft, end_scroll_top, + "scroll-start: end sets initial scroll position"); + + let top_scroller = document.getElementById("topscroller"); + assert_equals(top_scroller.scrollLeft, 100, + "scroll-start: top sets initial scroll position"); + assert_equals(top_scroller.scrollTop, 0, + "scroll-start: top sets initial scroll position"); + + let bottom_scroller = document.getElementById("bottomscroller"); + const bottom_scroll_top = bottom_scroller.scrollHeight - + bottom_scroller.clientHeight; + assert_equals(bottom_scroller.scrollLeft, 100, + "scroll-start: bottom sets initial scroll position"); + assert_equals(bottom_scroller.scrollTop, bottom_scroll_top, + "scroll-start: top sets initial scroll position"); + + let left_scroller = document.getElementById("leftscroller"); + assert_equals(left_scroller.scrollTop, 100, + "scroll-start: left sets initial scroll position"); + assert_equals(left_scroller.scrollLeft, 0, + "scroll-start: left sets initial scroll position"); + + let right_scroller = document.getElementById("rightscroller"); + const right_scroll_top = right_scroller.scrollWidth - + right_scroller.clientWidth; + assert_equals(right_scroller.scrollTop, 100, + "scroll-start: right sets initial scroll position"); + assert_equals(right_scroller.scrollLeft, right_scroll_top, + "scroll-start: right sets initial scroll position"); + + let clamped_scroller = document.getElementById("clampedscroller"); + const clamped_scroll_top = clamped_scroller.scrollWidth - + clamped_scroller.clientWidth; + const clamped_scroll_left = clamped_scroller.scrollHeight - + clamped_scroller.clientHeight; + assert_equals(clamped_scroller.scrollTop, clamped_scroll_top, + "scroll-start is clamped to max vertical scroll offset"); + assert_equals(clamped_scroller.scrollLeft, clamped_scroll_left, + "scroll-start is clamped to max horizontal scroll offset"); + }, "scroll-start sets initial scroll offset correctly in vertical " + + "writing modes"); + </script> +</body>
\ No newline at end of file diff --git a/testing/web-platform/tests/css/css-scroll-snap-2/scroll-start/scroll-start-with-anchor-navigation-inner-frame.html b/testing/web-platform/tests/css/css-scroll-snap-2/scroll-start/scroll-start-with-anchor-navigation-inner-frame.html new file mode 100644 index 0000000000..c32bac913d --- /dev/null +++ b/testing/web-platform/tests/css/css-scroll-snap-2/scroll-start/scroll-start-with-anchor-navigation-inner-frame.html @@ -0,0 +1,38 @@ +<!DOCTYPE html> +<html> + +<head> +</head> + +<body> + <style> + :root { + margin: 0px; + scroll-start: 100px; + } + + #spacer { + height: 100vh; + width: 100vw; + } + + #scroll_start_target { + width: 100px; + height: 100px; + background-color: blue; + } + + #anchor_target { + width: 100px; + height: 100px; + background-color: red; + } + </style> + <a id="anchor_target_link" href="#anchor_target"></a> + <div id="spacer"></div> + <div id="scroll_start_target"></div> + <div id="anchor_target"> + </div> +</body> + +</html>
\ No newline at end of file diff --git a/testing/web-platform/tests/css/css-scroll-snap-2/scroll-start/scroll-start-with-anchor-navigation.tentative.html b/testing/web-platform/tests/css/css-scroll-snap-2/scroll-start/scroll-start-with-anchor-navigation.tentative.html new file mode 100644 index 0000000000..ff5c979391 --- /dev/null +++ b/testing/web-platform/tests/css/css-scroll-snap-2/scroll-start/scroll-start-with-anchor-navigation.tentative.html @@ -0,0 +1,56 @@ +<!DOCTYPE html> +<html> + +<head> + <meta charset="utf-8"> + <title> CSS Scroll Snap 2 Test: scroll-start interaction with anchor navigation</title> + <link rel="help" href="https://drafts.csswg.org/css-scroll-snap-2/#scroll-start"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + <script src="/html/browsers/browsing-the-web/resources/helpers.js"></script> + <script src="/dom/events/scrolling/scroll_support.js"></script> +</head> + +<body> + <iframe id="frame" src="scroll-start-with-anchor-navigation-inner-frame.html" onload="runTest()"></iframe> + <script> + function runTest() { + promise_test(async (t) => { + let scroller = frame.contentDocument.scrollingElement; + // anchor_target is at the bottom of the frame so the frame should be + // fully scrolled down to bring it into view. + let anchor_target_scrolltop = scroller.scrollHeight - scroller.clientHeight; + let anchor_target_link = frame.contentDocument.getElementById("anchor_target_link"); + + // Expect scroll offset of 100px per scroll-start. + assert_equals(scroller.scrollTop, 100, + "scroll-start sets initial scroll offset"); + + // Scroll away from start position. + scroller.scrollTop = 200; + await waitForCompositorCommit(); + assert_equals(scroller.scrollTop, 200, + "scroll-start sets initial scroll offset"); + + anchor_target_link.click(); + await waitForHashchange(frame.contentWindow); + assert_equals(frame.contentWindow.location.hash, "#anchor_target", + "clicking anchor link navigates to target"); + + // Expect page to be fully scrolled as anchor_target is at the bottom of + // the document. + assert_equals(scroller.scrollTop, anchor_target_scrolltop, + "anchor navigation sets scroll offset"); + + frame.contentWindow.history.back(); + await waitForHashchange(frame.contentWindow); + assert_equals(frame.contentWindow.location.hash, ""); + + scroller = frame.contentDocument.scrollingElement; + assert_equals(scroller.scrollTop, 200, + "scroller returns to previous scroll position, not " + + "scroll-start"); + }, "scroll-start does not override anchor navigation."); + } + </script> +</body>
\ No newline at end of file diff --git a/testing/web-platform/tests/css/css-scroll-snap-2/scroll-start/scroll-start-with-fragment-navigation-inner-frame.html b/testing/web-platform/tests/css/css-scroll-snap-2/scroll-start/scroll-start-with-fragment-navigation-inner-frame.html new file mode 100644 index 0000000000..736a26a5f0 --- /dev/null +++ b/testing/web-platform/tests/css/css-scroll-snap-2/scroll-start/scroll-start-with-fragment-navigation-inner-frame.html @@ -0,0 +1,36 @@ +<!DOCTYPE html> +<html> + +<head> +</head> + +<body> + <style> + :root { + margin: 0px; + scroll-start: 100px; + } + + #spacer { + height: 100vh; + width: 100vw; + } + + #box { + width: 100px; + height: 100px; + background-color: blue; + } + + #fragment_target { + width: 100px; + height: 100px; + background-color: red; + } + </style> + <div id="spacer"></div> + <div id="box"></div> + <div id="fragment_target"></div> +</body> + +</html>
\ No newline at end of file diff --git a/testing/web-platform/tests/css/css-scroll-snap-2/scroll-start/scroll-start-with-fragment-navigation.tentative.html b/testing/web-platform/tests/css/css-scroll-snap-2/scroll-start/scroll-start-with-fragment-navigation.tentative.html new file mode 100644 index 0000000000..6e7730b0dc --- /dev/null +++ b/testing/web-platform/tests/css/css-scroll-snap-2/scroll-start/scroll-start-with-fragment-navigation.tentative.html @@ -0,0 +1,30 @@ +<!DOCTYPE html> +<html> + +<head> + <meta charset="utf-8"> + <title> CSS Scroll Snap 2 Test: scroll-start interaction with fragment-navigation</title> + <link rel="help" href="https://drafts.csswg.org/css-scroll-snap-2/#scroll-start"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> +</head> + +<body> + <iframe id="frame" src="scroll-start-with-fragment-navigation-inner-frame.html#fragment_target" + onload="runTest()"></iframe> + <script> + function runTest() { + test((t) => { + let scroller = frame.contentDocument.scrollingElement; + // fragment_target is at the bottom of the frame so the frame should be + // fully scrolled down to bring it into view. + let expected_scroll_top = scroller.scrollHeight - scroller.clientHeight; + + assert_equals(frame.contentWindow.location.hash, "#fragment_target"); + assert_not_equals(100, expected_scroll_top); + assert_equals(frame.contentDocument.scrollingElement.scrollTop, + expected_scroll_top); + }, "scroll-start does not override hash fragment navigation"); + } + </script> +</body>
\ No newline at end of file diff --git a/testing/web-platform/tests/css/css-scroll-snap-2/scroll-start/scroll-start-with-programmatic-scroll.tentative.html b/testing/web-platform/tests/css/css-scroll-snap-2/scroll-start/scroll-start-with-programmatic-scroll.tentative.html new file mode 100644 index 0000000000..c10746f854 --- /dev/null +++ b/testing/web-platform/tests/css/css-scroll-snap-2/scroll-start/scroll-start-with-programmatic-scroll.tentative.html @@ -0,0 +1,82 @@ +<!DOCTYPE html> +<html> + +<head> + <meta charset="utf-8"> + <title> CSS Scroll Snap 2 Test: scroll-start-*</title> + <link rel="help" href="https://drafts.csswg.org/css-scroll-snap-2/#scroll-start"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> +</head> + +<body onload="runTest()"> + <style> + #scroller { + height: 100px; + width: 100px; + overflow: scroll; + scroll-start: 10vh 200px; + } + + .spacer { + width: 200vw; + height: 200vh; + border: solid 1px green; + } + </style> + <div id="scroller"> + <div class="spacer" id="spacer"></div> + </div> + <script> + function runTest() { + // scroll position declared by scroll-start. + const scroll_start_top = 0.1 * window.innerHeight; + const scroll_start_left = 200; + + // target position of the programmatic scroll. + const target_scroll_top = 100; + const target_scroll_left = 100; + + promise_test(async (t) => { + // verify that we are starting from the offsets indicated by scroll start. + assert_equals(scroller.scrollTop, scroll_start_top, + "scroll-start: <length> sets initial scroll position vertically"); + assert_equals(scroller.scrollLeft, scroll_start_left, + "scroll-start: <length> sets initial scroll position horizontally"); + + // verify that the programmatic scroll should result in an actual scroll. + assert_not_equals(target_scroll_top, scroll_start_top, + "programmatic scroll should not be a nop vertically"); + assert_not_equals(target_scroll_left, scroll_start_left, + "programmatic scroll should not be a nop horizontally"); + + scroller.scrollTop = target_scroll_top; + scroller.scrollLeft = target_scroll_left; + // verify that programmtic scroll succeeded. + assert_equals(scroller.scrollTop, target_scroll_top, + "programmatic scroll succeeds vertically"); + assert_equals(scroller.scrollLeft, target_scroll_left, + "programmatic scroll succeeds horizontally"); + + // Trigger a layout change. + scroller.style.height = "200px"; + scroller.style.width = "200px"; + let spacer = document.getElementById("spacer"); + spacer.style.height = "300vh"; + spacer.style.width = "300vw"; + assert_equals(getComputedStyle(spacer)["height"], + `${3 * window.innerHeight}px`); + assert_equals(getComputedStyle(spacer)["width"], + `${3 * window.innerWidth}px`); + + // Verify that the layout change did not affect the scroll position. + assert_equals(scroller.scrollTop, target_scroll_top, + "layout change after programmatic scroll doesn't apply scroll-start " + + "vertically"); + assert_equals(scroller.scrollLeft, target_scroll_left, + "layout change after programmatic scroll doesn't apply scroll-start " + + "horizontally"); + }, "scroll-start is not applied after a programmatic scroll"); + } + </script> +</body>
\ No newline at end of file diff --git a/testing/web-platform/tests/css/css-scroll-snap-2/scroll-start/scroll-start-with-scroll-snap.tentative.html b/testing/web-platform/tests/css/css-scroll-snap-2/scroll-start/scroll-start-with-scroll-snap.tentative.html new file mode 100644 index 0000000000..8bdac300ba --- /dev/null +++ b/testing/web-platform/tests/css/css-scroll-snap-2/scroll-start/scroll-start-with-scroll-snap.tentative.html @@ -0,0 +1,70 @@ +<!DOCTYPE html> +<html> + +<head> + <meta charset="utf-8"> + <title> CSS Scroll Snap 2 Test: scroll-start interaction with scroll-snap</title> + <link rel="help" href="https://drafts.csswg.org/css-scroll-snap-2/#scroll-start"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> +</head> + + +<body> + <style> + body { + margin: 0px; + } + + .spacer { + height: 200px; + width: 100px; + } + + .scroller { + height: 220px; + width: 100px; + overflow: scroll; + scroll-snap-type: both mandatory; + } + + #single_snap_scroller { + scroll-start: 100%; + } + #multi_snap_scroller { + scroll-start: 350px; + } + + .snap_point { + width: 100px; + height: 200px; + scroll-snap-align: start; + } + </style> + <div id="single_snap_scroller" class="scroller"> + <div id="top_spacer" class="spacer"></div> + <div id="lone_snap_point" class="snap_point"></div> + <div id="bottom_spacer" class="spacer"></div> + </div> + <div id="multi_snap_scroller" class="scroller"> + <div id="snap_point_1" class="snap_point"></div> + <div id="snap_point_2" class="snap_point"></div> + <div id="snap_point_3" class="snap_point"></div> + </div> + <script> + test((t) => { + assert_equals(single_snap_scroller.scrollTop, + top_spacer.getBoundingClientRect().height, + "scroller snaps to top of snap point"); + }, "snap overrides scroll-start position"); + + test((t) => { + // scroll-start sets the initial scroll offset to 350px which is closer to + // the third snap point than the second, so the scroller should snap to + // the third snap_point. + assert_equals(multi_snap_scroller.scrollTop, + multi_snap_scroller.scrollHeight - multi_snap_scroller.clientHeight, + "scroller snaps to snap point closer to start position."); + }, "scroller snaps based on scroll-start position"); + </script> +</body> diff --git a/testing/web-platform/tests/css/css-scroll-snap-2/scroll-start/scroll-start-with-text-fragment-navigation-target.html b/testing/web-platform/tests/css/css-scroll-snap-2/scroll-start/scroll-start-with-text-fragment-navigation-target.html new file mode 100644 index 0000000000..5537d47fb5 --- /dev/null +++ b/testing/web-platform/tests/css/css-scroll-snap-2/scroll-start/scroll-start-with-text-fragment-navigation-target.html @@ -0,0 +1,74 @@ +<!DOCTYPE html> +<html> + +<head> +</head> + +<body> + <div id="spacer"></div> + <div id="box"></div> + <div id="text_fragment_target"> + <p>Target</p> + </div> + <style> + :root { + margin: 0px; + scroll-start: 100px; + } + + #spacer { + height: 100vh; + width: 100vw; + } + + #box { + width: 100px; + height: 100px; + background-color: blue; + } + + #fragment_target { + width: 100px; + height: 100px; + background-color: red; + } + </style> + <script> + function stashResult(key, results) { + fetch(`/css/css-scroll-snap-2/scroll-start/stash.py?key=${key}`, { + method: "POST", + body: JSON.stringify(results) + }).then(() => { + window.close(); + }); + } + function record() { + let scroll_position = "UNKNOWN"; + // Expect page is scrolled all the way down as the text is at the bottom of + // the page. + const expected_scroll_top = document.scrollingElement.scrollHeight - + document.scrollingElement.clientHeight; + + if (document.scrollingElement.scrollTop == 100) { + scroll_position = "AT_SCROLL_START"; + } else if (document.scrollingElement.scrollTop == expected_scroll_top) { + scroll_position = "AT_TEXT_FRAGMENT"; + } + + const result = { + scroll_position: scroll_position + }; + + let key = (new URL(document.location)).searchParams.get("key"); + stashResult(key, result); + } + + window.onload = () => { + window.requestAnimationFrame(function () { + window.requestAnimationFrame(record); + }) + } + </script> +</body> + +</html>
\ No newline at end of file diff --git a/testing/web-platform/tests/css/css-scroll-snap-2/scroll-start/scroll-start-with-text-fragment-navigation.tentative.html b/testing/web-platform/tests/css/css-scroll-snap-2/scroll-start/scroll-start-with-text-fragment-navigation.tentative.html new file mode 100644 index 0000000000..7348c39501 --- /dev/null +++ b/testing/web-platform/tests/css/css-scroll-snap-2/scroll-start/scroll-start-with-text-fragment-navigation.tentative.html @@ -0,0 +1,49 @@ +<!DOCTYPE html> +<html> + +<head> + <meta charset="utf-8"> + <title> CSS Scroll Snap 2 Test: scroll-start interaction with text-fragment navigation</title> + <link rel="help" href="https://drafts.csswg.org/css-scroll-snap-2/#scroll-start"> + <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> + function fetchResult(key, resolve, reject) { + fetch(`/css/css-scroll-snap-2/scroll-start/stash.py?key=${key}`).then(response => { + return response.text(); + }).then(text => { + if (text) { + try { + let result = JSON.parse(text); + resolve(result); + } catch (e) { + reject(); + } + } else { + fetchResult(key, resolve, reject); + } + }); + } + + function runTest() { + promise_test(t => new Promise(async (resolve, reject) => { + let key = token(); + + test_driver.bless("Open a URL with a text fragment directive", () => { + window.open(`scroll-start-with-text-fragment-navigation-target.html?key=${key}#:~:text=Target`, "_blank", "noopener"); + }); + + fetchResult(key, resolve, reject); + }).then(result => { + assert_equals(result.scroll_position, "AT_TEXT_FRAGMENT"); + }), "scroll-start doesn't override text fragment navigation"); + } + </script> +</body> diff --git a/testing/web-platform/tests/css/css-scroll-snap-2/scroll-start/scroll-start-with-user-scroll.tentative.html b/testing/web-platform/tests/css/css-scroll-snap-2/scroll-start/scroll-start-with-user-scroll.tentative.html new file mode 100644 index 0000000000..c122a6ef09 --- /dev/null +++ b/testing/web-platform/tests/css/css-scroll-snap-2/scroll-start/scroll-start-with-user-scroll.tentative.html @@ -0,0 +1,91 @@ +<!DOCTYPE html> +<html> + +<head> + <meta charset="utf-8"> + <title> CSS Scroll Snap 2 Test: scroll-start-*</title> + <link rel="help" href="https://drafts.csswg.org/css-scroll-snap-2/#scroll-start"> + <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> +</head> + +<body onload="runTest()"> + <style> + #scroller { + height: 100px; + width: 100px; + overflow: scroll; + scroll-start: 10vh 200px; + } + + .spacer { + width: 200vw; + height: 200vh; + border: solid 1px green; + } + </style> + <script> + function runTest() { + // scroll position declared by scroll-start. + const scroll_start_top = 0.1 * window.innerHeight; + const scroll_start_left = 200; + + // target position of the user scroll. + const target_scroll_delta = 100; + const target_scroll_top = scroll_start_top + target_scroll_delta; + const target_scroll_left = scroll_start_left + target_scroll_delta; + + promise_test(async (t) => { + // verify that we are starting from the offsets indicated by scroll start. + assert_equals(scroller.scrollTop, scroll_start_top, + "scroll-start: <length> sets initial scroll position vertically"); + assert_equals(scroller.scrollLeft, scroll_start_left, + "scroll-start: <length> sets initial scroll position horizontally"); + + // verify that the user scroll should result in an actual scroll. + assert_not_equals(target_scroll_top, scroll_start_top, + "user scroll should not be nop vertically"); + assert_not_equals(target_scroll_left, scroll_start_left, + "user scroll should not be nop horizontally"); + + let scrollend_promise = new Promise((resolve) => { + scroller.onscrollend = () => { resolve(); } + }); + await new test_driver.Actions().scroll(0, 0, + target_scroll_delta, + target_scroll_delta, + { origin: scroller }).send(); + + await scrollend_promise; + assert_equals(scroller.scrollTop, target_scroll_top, + "user scroll succeeds vertically"); + assert_equals(scroller.scrollLeft, target_scroll_left, + "user scroll succeeds horizontally"); + + // Trigger a layout change. + scroller.style.height = "200px"; + scroller.style.width = "200px"; + let spacer = document.getElementById("spacer"); + spacer.style.height = "300vh"; + spacer.style.width = "300vw"; + assert_equals(getComputedStyle(spacer)["height"], + `${3 * window.innerHeight}px`); + assert_equals(getComputedStyle(spacer)["width"], + `${3 * window.innerWidth}px`); + // Verify that the layout change did not affect the scroll position. + assert_equals(scroller.scrollTop, target_scroll_top, + "layout change after user scroll does not apply scroll-start " + + "vertically"); + assert_equals(scroller.scrollLeft, target_scroll_left, + "layout change after user scroll does not apply scroll-start " + + "horizontally"); + }, "scroll-start is not applied after user a scroll"); + } + </script> + <div id="scroller"> + <div class="spacer" id="spacer"></div> + </div> +</body>
\ No newline at end of file diff --git a/testing/web-platform/tests/css/css-scroll-snap-2/scroll-start/scroll-start.tentative.html b/testing/web-platform/tests/css/css-scroll-snap-2/scroll-start/scroll-start.tentative.html new file mode 100644 index 0000000000..a35c612d7f --- /dev/null +++ b/testing/web-platform/tests/css/css-scroll-snap-2/scroll-start/scroll-start.tentative.html @@ -0,0 +1,122 @@ +<!DOCTYPE html> +<html> + +<head> + <meta charset="utf-8"> + <title> CSS Scroll Snap 2 Test: scroll-start-*</title> + <link rel="help" href="https://drafts.csswg.org/css-scroll-snap-2/#scroll-start"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> +</head> + +<body> + <style> + .spacer { + width: 500px; + height: 500px; + border: solid 1px green; + } + + .scroller { + width: 100px; + height: 100px; + border: solid 1px black; + overflow: scroll; + } + </style> + <div id="lengthscroller" class="scroller" style="scroll-start: 100px"> + <div class="spacer"></div> + </div> + <div id="percentscroller" class="scroller" style="scroll-start: 25%"> + <div class="spacer"></div> + </div> + <div id="calcscroller" class="scroller" style="scroll-start: calc(50px)"> + <div class="spacer"></div> + </div> + <div id="startscroller" class="scroller" style="scroll-start: start"> + <div class="spacer"></div> + </div> + <div id="centerscroller" class="scroller" style="scroll-start: center"> + <div class="spacer"></div> + </div> + <div id="endscroller" class="scroller" style="scroll-start: end"> + <div class="spacer"></div> + </div> + <div id="topscroller" class="scroller" style="scroll-start: top"> + <div class="spacer"></div> + </div> + <div id="bottomscroller" class="scroller" style="scroll-start: bottom"> + <div class="spacer"></div> + </div> + <div id="leftscroller" class="scroller" style="scroll-start: auto left"> + <div class="spacer"></div> + </div> + <div id="rightscroller" class="scroller" style="scroll-start: auto right"> + <div class="spacer"></div> + </div> + <div id="clampedscroller" class="scroller" style="scroll-start: 1000px 1000px"> + <div class="spacer"></div> + </div> + <script>promise_test(async (t) => { + let length_scroller = document.getElementById("lengthscroller"); + assert_equals(length_scroller.scrollTop, 100, + "scroll-start: <length> sets initial scroll position"); + + let percent_scroller = document.getElementById("percentscroller"); + const percent_scroll_top = 0.25 * (percent_scroller.scrollHeight - + percent_scroller.clientHeight); + assert_approx_equals(percent_scroller.scrollTop, percent_scroll_top, 1, + "scroll-start: <percent> sets initial scroll position"); + + let calc_scroller = document.getElementById("calcscroller"); + assert_equals(calc_scroller.scrollTop, 50, + "scroll-start: <calc> sets initial scroll position"); + + let start_scroller = document.getElementById("startscroller"); + assert_equals(start_scroller.scrollTop, 0, + "scroll-start: start sets initial scroll position"); + + let center_scroller = document.getElementById("centerscroller"); + const center_scroll_top = 0.5 * (center_scroller.scrollHeight - + center_scroller.clientHeight); + assert_approx_equals(center_scroller.scrollTop, center_scroll_top, 1, + "scroll-start: center sets initial scroll position"); + + let end_scroller = document.getElementById("endscroller"); + const end_scroll_top = end_scroller.scrollHeight - + end_scroller.clientHeight; + assert_equals(end_scroller.scrollTop, end_scroll_top, + "scroll-start: end sets initial scroll position"); + + let top_scroller = document.getElementById("topscroller"); + assert_equals(top_scroller.scrollTop, 0, + "scroll-start: top sets initial scroll position"); + + let bottom_scroller = document.getElementById("bottomscroller"); + const bottom_scroll_top = bottom_scroller.scrollHeight - + bottom_scroller.clientHeight; + assert_equals(bottom_scroller.scrollTop, bottom_scroll_top, + "scroll-start: bottom sets initial scroll position"); + + let left_scroller = document.getElementById("leftscroller"); + assert_equals(left_scroller.scrollLeft, 0, + "scroll-start: left sets initial scroll position"); + + let right_scroller = document.getElementById("rightscroller"); + const right_scroll_top = right_scroller.scrollWidth - + right_scroller.clientWidth; + assert_equals(right_scroller.scrollLeft, right_scroll_top, + "scroll-start: right sets initial scroll position"); + + let clamped_scroller = document.getElementById("clampedscroller"); + const clamped_scroll_top = clamped_scroller.scrollHeight - + clamped_scroller.clientHeight; + const clamped_scroll_left = clamped_scroller.scrollWidth - + clamped_scroller.clientWidth; + assert_equals(clamped_scroller.scrollTop, clamped_scroll_top, + "scroll-start is clamped to max vertical scroll offset"); + assert_equals(clamped_scroller.scrollLeft, clamped_scroll_left, + "scroll-start is clamped to max horizontal scroll offset"); + }); + </script> +</body>
\ No newline at end of file diff --git a/testing/web-platform/tests/css/css-scroll-snap-2/scroll-start/stash.py b/testing/web-platform/tests/css/css-scroll-snap-2/scroll-start/stash.py new file mode 100644 index 0000000000..13bb0e91ba --- /dev/null +++ b/testing/web-platform/tests/css/css-scroll-snap-2/scroll-start/stash.py @@ -0,0 +1,27 @@ +# Copyright 2023 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-2/scroll-start/scroll-start-with-text-fragment-navigation.html +to store and retrieve data. + +scroll-start-with-text-fragment-navigation.html (test file) opens a window to +scroll-start-with-text-fragment-navigation-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-2/scroll-start') + return u"ok" + else: + # Request for result data from test page + value = request.server.stash.take(key, u'/css/css-scroll-snap-2/scroll-start') + return value diff --git a/testing/web-platform/tests/css/css-scroll-snap-2/snapchanged/snapchanged-after-layout-change.tentative.html b/testing/web-platform/tests/css/css-scroll-snap-2/snapchanged/snapchanged-after-layout-change.tentative.html new file mode 100644 index 0000000000..293400edda --- /dev/null +++ b/testing/web-platform/tests/css/css-scroll-snap-2/snapchanged/snapchanged-after-layout-change.tentative.html @@ -0,0 +1,145 @@ +<!DOCTYPE html> +<html> + +<head> + <link rel="help" href="https://drafts.csswg.org/css-scroll-snap-2/#snap-events" /> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + <script src="/dom/events/scrolling/scroll_support.js"></script> + <script src="/css/css-scroll-snap-2/resources/common.js"></script> + <script src="/web-animations/testcommon.js"></script> +</head> + +<body> + <style> + #scroller { + overflow: scroll; + scroll-snap-type: y mandatory; + height: 200px; + width: 200px; + border: solid 1px; + position: absolute; + } + + .snap_area { + position: absolute; + width: 100px; + left: calc(50% - 50px); + } + + #outer_snap_area { + scroll-snap-align: start none; + height: 1000px; + background-color: blue; + } + + #inner_snap_area { + scroll-snap-align: start none; + height: 100px; + top: 100px; + background-color: yellow; + } + </style> + <div id="scroller"> + <div id="outer_snap_area" class="snap_area"></div> + <div id="inner_snap_area" class="snap_area"></div> + </div> + <script> + let scroller = document.getElementById("scroller"); + + async function reset(t) { + inner_snap_area.style.height = "100px"; + inner_snap_area.style.scrollSnapAlign = "start none"; + outer_snap_area.style.scrollSnapAlign = "start none"; + scroller.style.scrollSnapType = "y mandatory"; + await resetTargetScrollState(t, scroller); + } + + async function setup(t) { + checkSnapEventSupport("snapchanged"); + await reset(t); + await waitForCompositorCommit(); + assert_equals(scroller.scrollTop, 0, "test precondition: scroller " + + "is not scrolled."); + } + + promise_test(async (t) => { + await setup(t); + let target_snap_position = inner_snap_area.offsetTop + + inner_snap_area.offsetHeight; + // Scroll to an offset close to the bottom of the inner snap area and + // expect to snap to an offset just below this snap area. + let scrollend_promise = waitForScrollendEventNoTimeout(scroller); + scroller.scrollTo(0, target_snap_position - 10); + await scrollend_promise; + assert_equals(scroller.scrollTop, target_snap_position, + "scroller snaps to just below the inner snap area."); + // We are just below the inner snap area. Increase its height so that it + // is larger than the snapport and straddled by the snapport. Verify + // that we snap to its bottom. + let snapchanged_promise = waitForSnapChangedEvent(scroller); + inner_snap_area.style.height = + `${scroller.clientHeight + inner_snap_area.clientHeight - 10}px`; + const evt = await snapchanged_promise; + assertSnapEvent(evt, [outer_snap_area.id, inner_snap_area.id]); + target_snap_position = inner_snap_area.offsetTop + + inner_snap_area.offsetHeight - scroller.clientHeight; + assert_equals(scroller.scrollTop, target_snap_position, + "scroller snaps to the bottom of the smaller snap area (which is " + + "now covering)."); + }, "snapchanged fires after snap area is snapped to upon layout change."); + + promise_test(async (t) => { + await setup(t); + let target_snap_position = inner_snap_area.offsetTop + + inner_snap_area.offsetHeight; + // Scroll to an offset close to the bottom of the inner snap area and + // expect to snap to an offset just below this snap area. + let scrollend_promise = waitForScrollendEventNoTimeout(scroller); + scroller.scrollTo(0, target_snap_position - 10); + await scrollend_promise; + assert_equals(scroller.scrollTop, target_snap_position, + "scroller snaps to just below the inner snap area."); + // We are just below the inner snap area. Increase its height so that it + // is larger than the snapport making the current scroll position + // a valid covering position within the inner snap area. + let snapchanged_promise = waitForSnapChangedEvent(scroller, false); + inner_snap_area.style.height = + `${scroller.clientHeight + inner_snap_area.clientHeight + 10}px`; + const evt = await snapchanged_promise; + assertSnapEvent(evt, [outer_snap_area.id, inner_snap_area.id]); + assert_equals(scroller.scrollTop, target_snap_position, + "scroller maintains offset which is now covering within inner area"); + }, "snapchanged fires after snap area is snapped to upon layout change " + + "without scroll."); + + promise_test(async(t) => { + await setup(t); + await waitForCompositorCommit(); + let snapchanged_promise = waitForSnapChangedEvent(scroller, false); + scroller.style.scrollSnapType = "none"; + let evt = await snapchanged_promise; + assertSnapEvent(evt, []); + snapchanged_promise = waitForSnapChangedEvent(scroller, false); + scroller.style.scrollSnapType = "y mandatory"; + evt = await snapchanged_promise; + assertSnapEvent(evt, [outer_snap_area.id]); + }, "snapchanged fires when container stops snapping"); + + promise_test(async(t) => { + await setup(t); + await waitForCompositorCommit(); + let snapchanged_promise = waitForSnapChangedEvent(scroller, false); + inner_snap_area.style.scrollSnapAlign = "none"; + outer_snap_area.style.scrollSnapAlign = "none"; + let evt = await snapchanged_promise; + assertSnapEvent(evt, []); + snapchanged_promise = waitForSnapChangedEvent(scroller, false); + inner_snap_area.style.scrollSnapAlign = "start"; + outer_snap_area.style.scrollSnapAlign = "start"; + evt = await snapchanged_promise; + assertSnapEvent(evt, [outer_snap_area.id]); + }, "snapchanged fires when snap container no longer has snap areas"); + </script> +</body> +</html> diff --git a/testing/web-platform/tests/css/css-scroll-snap-2/snapchanged/snapchanged-ensures-dom-order.html b/testing/web-platform/tests/css/css-scroll-snap-2/snapchanged/snapchanged-ensures-dom-order.html new file mode 100644 index 0000000000..10bc73b622 --- /dev/null +++ b/testing/web-platform/tests/css/css-scroll-snap-2/snapchanged/snapchanged-ensures-dom-order.html @@ -0,0 +1,95 @@ +<!DOCTYPE html> +<html> + +<head> + <link rel="help" href="https://drafts.csswg.org/css-scroll-snap-2/#snap-events" /> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + <script src="/dom/events/scrolling/scroll_support.js"></script> + <script src="/css/css-scroll-snap-2/resources/common.js"></script> + <script src="/web-animations/testcommon.js"></script> + <style> + #scroller { + overflow-y: scroll; + scroll-snap-type: y mandatory; + width: 500px; + height: 500px; + background-color: white; + position: relative; + } + .space_filler { + display: inline-block; + width: 40%; + height: 30%; + background-color: green; + } + .snap_area { + scroll-snap-align: start; + background-color: yellow; + position: absolute; + width: 40%; + height: 30%; + } + + #snap_point_1 { + left: 1px; + } + #snap_point_2 { + left: 80%; + } + #snap_point_3 { + left: 40%; + scroll-snap-align: start; + background-color: yellow; + position: absolute; + width: 40%; + height: 30%; + } + </style> +</head> +<body> + <div id="scroller"> + <div class="space_filler"></div> + <div class="space_filler"></div> + <div class="space_filler"></div> + <div class="space_filler"></div> + <div class="space_filler"></div> + <div class="space_filler"></div> + <div class="space_filler"></div> + <div class="space_filler"></div> + <div id="snap_point_1" class="snap_area"><h1>1</h1></div> + <div id="snap_point_2" class="snap_area"><h1>2</h1></div> + </div> + <script> + promise_test(async (t) => { + checkSnapEventSupport("snapchanged"); + await waitForCompositorCommit(); + const snapchanged_promise = waitForSnapChangedEvent(scroller, false); + const snap_point_3 = document.createElement("div"); + snap_point_3.id = "snap_point_3"; + t.add_cleanup(() => { + snap_point_3.remove(); + }); + scroller.insertBefore(snap_point_3, snap_point_2); + const evt_seen = await snapchanged_promise; + assertSnapEvent(evt_seen, + [snap_point_1.id, snap_point_3.id, snap_point_2.id]); + }, "snapchanged lists snapTargets in DOM order."); + + promise_test(async (t) => { + checkSnapEventSupport("snapchanged"); + await waitForCompositorCommit(); + const unreached_func = t.unreached_func("snapchanged shouldn't fire " + + "since the scroller is snapped to the same elements despite the " + + "dom order change."); + t.add_cleanup(() => { + scroller.removeEventListener("snapchanged", unreached_func); + }) + scroller.addEventListener("snapchanged", unreached_func); + scroller.insertBefore(snap_point_2, snap_point_1); + await waitForCompositorCommit(); + }, "DOM order change doesn't trigger snapchanged if snapped targets " + + "don't change."); + </script> +</body> +</html> diff --git a/testing/web-platform/tests/css/css-scroll-snap-2/snapchanged/snapchanged-on-interrupted-scroll.tentative.html b/testing/web-platform/tests/css/css-scroll-snap-2/snapchanged/snapchanged-on-interrupted-scroll.tentative.html new file mode 100644 index 0000000000..a1d5259451 --- /dev/null +++ b/testing/web-platform/tests/css/css-scroll-snap-2/snapchanged/snapchanged-on-interrupted-scroll.tentative.html @@ -0,0 +1,68 @@ +<!DOCTYPE html> +<html> + <head> + <meta charset="utf-8"> + <title> CSS Scroll Snap 2 Test: snapchanged events</title> + <link rel="help" href="https://drafts.csswg.org/css-scroll-snap-2/#snap-events"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + <script src="/dom/events/scrolling/scroll_support.js"></script> + </head> + <body> + <style> + #container { + overflow-y: scroll; + height: 500px; + width: 300px; + border: solid 1px black; + position: absolute; + scroll-snap-type: y mandatory; + } + .snap_area { + scroll-snap-align: start; + height: 400px; + width: 200px; + left: 50px; + position: absolute; + } + #area1 { + background-color: blue; + } + #area2 { + top: 400px; + background-color: yellow; + } + #area3 { + top: 800px; + background-color: green; + } + </style> + <div id="container"> + <div id="area1" class="snap_area"></div> + <div id="area2" class="snap_area"></div> + <div id="area3" class="snap_area"></div> + </div> + <script> + promise_test(async (t) => { + await waitForCompositorCommit(); + + container.addEventListener("snapchanged", + t.unreached_func("snapchanged should not fire")); + let reset = () => { + container.scrollTo({ top: 0, behavior: "smooth"}); + container.removeEventListener("scroll", reset); + }; + container.addEventListener("scroll", reset); + + let scrollend_promise = waitForScrollendEventNoTimeout(container); + container.scrollTo({ top: 250, behavior: "smooth"}); + await scrollend_promise; + assert_equals(container.scrollTop, 0, "scroll position is reset"); + + // snapchanged should not fire since the scroll ended on the same snap + // target as the one it started on. + await waitForCompositorCommit(); + }, "snapchanged doesn't fire if interrupting scroll cancels snap"); + </script> + </body> +</html> diff --git a/testing/web-platform/tests/css/css-scroll-snap-2/snapchanged/snapchanged-on-programmatic-root-scroll.tentative.html b/testing/web-platform/tests/css/css-scroll-snap-2/snapchanged/snapchanged-on-programmatic-root-scroll.tentative.html new file mode 100644 index 0000000000..2e33c3c970 --- /dev/null +++ b/testing/web-platform/tests/css/css-scroll-snap-2/snapchanged/snapchanged-on-programmatic-root-scroll.tentative.html @@ -0,0 +1,122 @@ +<!DOCTYPE html> +<html> + +<head> + <meta charset="utf-8"> + <title> CSS Scroll Snap 2 Test: snapchanged event on the root/document</title> + <link rel="help" href="https://drafts.csswg.org/css-scroll-snap-2/#snap-events"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + <script src="/css/css-scroll-snap-2/resources/common.js"></script> + <script src="/dom/events/scrolling/scroll_support.js"></script> + <script src="/web-animations/testcommon.js"></script> +</head> + +<body> + <style> + :root { + margin: 0; + padding: 0; + scroll-snap-type: both mandatory; + } + + div { + position: absolute; + margin: 0px; + } + + #spacer { + width: 200vw; + height: 200vh; + } + + .snap_point { + width: 40vw; + height: 40vh; + scroll-snap-align: start; + } + + #snap_point_1 { + left: 0px; + top: 0px; + background-color: red; + } + + #snap_point_2 { + top: 40vh; + left: 40vw; + background-color: orange; + } + + #snap_point_3 { + left: 80vw; + top: 80vh; + background-color: blue; + } + </style> + <div id="spacer"></div> + <div id="snap_point_1" class="snap_point"></div> + <div id="snap_point_2" class="snap_point"></div> + <div id="snap_point_3" class="snap_point"></div> + + <script> + let scroller = document.scrollingElement; + + promise_test(async (t) => { + await waitForCompositorCommit(); + const test_data = { + scroller: scroller, + scrolling_function: () => { + scroller.scrollTo(snap_point_2.offsetLeft, snap_point_2.offsetTop); + }, + expected_snap_targets: [snap_point_2.id], + expected_scroll_offsets: { + x: snap_point_2.offsetLeft, + y: snap_point_2.offsetTop, + } + }; + await test_snapchanged(t, test_data); + }, "snapchanged event fires after snap target changes via scrollTo"); + + promise_test(async (t) => { + checkSnapEventSupport("snapchanged"); + await waitForScrollReset(t, scroller); + await waitForCompositorCommit(); + assert_equals(scroller.scrollTop, 0, + "scroller is initially not scrolled vertically"); + assert_equals(scroller.scrollLeft, 0, + "scroller is initially not scrolled horizontally"); + + let snapchanged_promise = waitForSnapChangedEvent(document, false); + // Set the scroll destination to just a little off (0, 0) so we snap + // back to the top box. + let scroll_top_target = 10; + let scroll_left_target = 10; + + scroller.scrollTo(scroll_left_target, scroll_top_target); + let evt = await snapchanged_promise; + assert_equals(evt, null, "no snapchanges since scroller is back to top"); + // scroller should snap back to (0,0) with no snapchanged event. + assert_equals(scroller.scrollTop, 0, + "scroller snaps back to the top"); + assert_equals(scroller.scrollLeft, 0, + "scroller snaps back to the left"); + + snapchanged_promise = waitForSnapChangedEvent(document); + scroll_top_target = snap_point_2.offsetTop + 10; + scroll_left_target = snap_point_2.offsetLeft + 10; + // This scroll should snap to snap_point_2, so snapchanged should be + // fired. + scroller.scrollTo(scroll_left_target, scroll_top_target); + + evt = await snapchanged_promise; + assertSnapEvent(evt, [snap_point_2.id]); + assert_approx_equals(scroller.scrollTop, snap_point_2.offsetTop, 1, + "scroller snaps to the top of snap_point_2"); + assert_approx_equals(scroller.scrollLeft, snap_point_2.offsetLeft, 1, + "scroller snaps to the left of snap_point_2"); + }, "snapchanged is not fired if snap target doesn't change on " + + "programmatic scroll"); + </script> +</body> +</html> diff --git a/testing/web-platform/tests/css/css-scroll-snap-2/snapchanged/snapchanged-on-programmatic-scroll.tentative.html b/testing/web-platform/tests/css/css-scroll-snap-2/snapchanged/snapchanged-on-programmatic-scroll.tentative.html new file mode 100644 index 0000000000..6082e09013 --- /dev/null +++ b/testing/web-platform/tests/css/css-scroll-snap-2/snapchanged/snapchanged-on-programmatic-scroll.tentative.html @@ -0,0 +1,128 @@ +<!DOCTYPE html> +<html> + +<head> + <meta charset="utf-8"> + <title> CSS Scroll Snap 2 Test: snapchanged events</title> + <link rel="help" href="https://drafts.csswg.org/css-scroll-snap-2/#snap-events"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + <script src="/css/css-scroll-snap-2/resources/common.js"></script> + <script src="/dom/events/scrolling/scroll_support.js"></script> + <script src="/web-animations/testcommon.js"></script> +</head> + +<body onload="runTests()"> + <style> + body { + margin: 0px; + } + + div { + position: absolute; + margin: 0px; + } + + #spacer { + width: 2000px; + height: 2000px; + } + + .scroller { + height: 400px; + width: 400px; + overflow: scroll; + scroll-snap-type: both mandatory; + } + + .snap_point { + width: 300px; + height: 300px; + scroll-snap-align: start; + } + + #snap_point_1 { + left: 0px; + top: 0px; + background-color: red; + } + + #snap_point_2 { + top: 300px; + left: 300px; + background-color: orange; + } + + #snap_point_3 { + left: 600px; + top: 600px; + background-color: blue; + } + </style> + <div id="scroller" class="scroller"> + <div id="spacer"></div> + <div id="snap_point_1" class="snap_point"></div> + <div id="snap_point_2" class="snap_point"></div> + <div id="snap_point_3" class="snap_point"></div> + </div> + <script> + function runTests () { + let scroller = document.getElementById("scroller"); + + promise_test(async (t) => { + await waitForCompositorCommit(); + const test_data = { + scroller: scroller, + scrolling_function: () => { + scroller.scrollTo(snap_point_2.offsetLeft, snap_point_2.offsetTop); + }, + expected_snap_targets: [snap_point_2.id], + expected_scroll_offsets: { + x: snap_point_2.offsetLeft, + y: snap_point_2.offsetTop, + } + }; + await test_snapchanged(t, test_data); + }, "snapchanged event fires after snap target changes via scrollTo"); + + promise_test(async (t) => { + checkSnapEventSupport("snapchanged"); + await waitForScrollReset(t, scroller); + await waitForCompositorCommit(); + assert_equals(scroller.scrollTop, 0, + "scroller is initially not scrolled vertically"); + assert_equals(scroller.scrollLeft, 0, + "scroller is initially not scrolled horizontally"); + + let snapchanged_promise = waitForSnapChangedEvent(scroller, false); + // Set the scroll destination to just a little off (0, 0) so we snap + // back to the top box. + let scroll_top_target = 10; + let scroll_left_target = 10; + + scroller.scrollTo(scroll_left_target, scroll_top_target); + let evt = await snapchanged_promise; + assert_equals(evt, null, "no snapchanges since scroller is back to top"); + // scroller should snap back to (0,0) with no snapchanged event. + assert_equals(scroller.scrollTop, 0, "scroller snaps back to the top"); + assert_equals(scroller.scrollLeft, 0, "scroller snaps back to the left"); + + snapchanged_promise = waitForSnapChangedEvent(scroller); + scroll_top_target = snap_point_2.offsetTop + 10; + scroll_left_target = snap_point_2.offsetLeft + 10; + // This scroll should snap to snap_point_2, so snapchanged should be + // fired. + scroller.scrollTo(scroll_left_target, scroll_top_target); + + evt = await snapchanged_promise; + assertSnapEvent(evt, [snap_point_2.id]); + assert_approx_equals(scroller.scrollTop, snap_point_2.offsetTop, 1, + "scroller snaps to the top of snap_point_2"); + assert_approx_equals(scroller.scrollLeft, snap_point_2.offsetLeft, 1, + "scroller snaps to the left of snap_point_2"); + }, "snapchanged is not fired if snap target doesn't change on " + + "programmatic scroll"); + } + </script> +</body> +</html> diff --git a/testing/web-platform/tests/css/css-scroll-snap-2/snapchanged/snapchanged-on-user-root-scroll.tentative.html b/testing/web-platform/tests/css/css-scroll-snap-2/snapchanged/snapchanged-on-user-root-scroll.tentative.html new file mode 100644 index 0000000000..5405d778bf --- /dev/null +++ b/testing/web-platform/tests/css/css-scroll-snap-2/snapchanged/snapchanged-on-user-root-scroll.tentative.html @@ -0,0 +1,166 @@ +<!DOCTYPE html> +<html> + +<head> + <meta charset="utf-8"> + <title> CSS Scroll Snap 2 Test: snapchanged events</title> + <link rel="help" href="https://drafts.csswg.org/css-scroll-snap-2/#snap-events"> + <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="/css/css-scroll-snap-2/resources/common.js"></script> + <script src="/css/css-scroll-snap-2/resources/user-scroll-common.js"></script> + <script src="/dom/events/scrolling/scroll_support.js"></script> + <script src="/web-animations/testcommon.js"></script> +</head> + +<body> + <style type='text/css'> + :root { + margin: 0px; + padding: 0px; + scroll-snap-type: both mandatory; + } + + div { + position: absolute; + margin: 0px; + } + + #spacer { + width: 200vw; + height: 200vh; + } + + .snap_point { + width: 40vw; + height: 40vh; + scroll-snap-align: start; + } + + #snap_point_1 { + left: 0px; + top: 0px; + background-color: red; + } + + #snap_point_2 { + top: 35vh; + left: 35vw; + background-color: orange; + } + + #snap_point_3 { + left: 70vw; + top: 70vh; + background-color: blue; + } + </style> + <div id="spacer"></div> + <div id="snap_point_1" class="snap_point"></div> + <div id="snap_point_2" class="snap_point"></div> + <div id="snap_point_3" class="snap_point"></div> + <script> + const scroller = document.scrollingElement; + const offset_to_snap_point_2 = { + x: snap_point_2.offsetLeft, + y: snap_point_2.offsetTop + }; + + // Touch scroll test. + promise_test(async (t) => { + await waitForCompositorCommit(); + const start_pos = { + x: scroller.clientWidth / 2, + y: scroller.clientHeight / 2, + }; + const end_pos = { x: 0, y: 0 }; + const test_data = { + scroller: scroller, + scrolling_function: async () => { + await snap_event_touch_scroll_helper(start_pos, end_pos); + }, + expected_snap_targets: [snap_point_2.id], + expected_scroll_offsets: { + x: offset_to_snap_point_2.x, + y: offset_to_snap_point_2.y, + } + }; + await test_snapchanged(t, test_data); + }, "snapchanged event fires after snap target changes on touch scroll"); + + // Wheel scroll test. + promise_test(async (t) => { + await waitForCompositorCommit(); + const test_data = { + scroller: scroller, + scrolling_function: async () => { + await new test_driver.Actions().scroll(0, 0, + offset_to_snap_point_2.x, + offset_to_snap_point_2.y, + { origin: scroller }).send(); + }, + expected_snap_targets: [snap_point_2.id], + expected_scroll_offsets: { + x: offset_to_snap_point_2.x, + y: offset_to_snap_point_2.y, + } + }; + await test_snapchanged(t, test_data); + }, "snapchanged event fires after snap target changes on wheel scroll"); + + // Scrollbar drag test. + promise_test(async (t) => { + await waitForCompositorCommit(); + // Skip test on platforms that do not have a visible scrollbar (e.g. + // overlay scrollbar). + const scrollbar_width = window.innerWidth - + document.documentElement.clientWidth; + if (scrollbar_width == 0) { + return; + } + const test_data = { + scroller: scroller, + scrolling_function: async () => { + const scrollbar_to_scroller_ratio = + getScrollbarToScrollerRatio(document.documentElement); + // Scroll by just over half of the top box's height. + const drag_amt = (offset_to_snap_point_2.y / 2 + 1) * + scrollbar_to_scroller_ratio; + await snap_event_scrollbar_drag_helper(scroller, scrollbar_width, + drag_amt); + }, + expected_snap_targets: [snap_point_1.id, snap_point_2.id], + expected_scroll_offsets: { + x: 0, + y: offset_to_snap_point_2.y, + } + }; + await test_snapchanged(t, test_data); + }, "snapchanged event fires after snap target changes on scrollbar drag"); + + // Keyboard test. + promise_test(async (t) => { + const test_data = { + scroller: scroller, + scrolling_function: async () => { + scroller.focus(); + window.test_driver.send_keys(document.documentElement, + '\ue015'/*ArrowDown*/); + }, + expected_snap_targets: [snap_point_1.id, snap_point_2.id], + expected_scroll_offsets: { + x: 0, + y: offset_to_snap_point_2.y, + } + }; + await test_snapchanged(t, test_data); + }, "snapchanged event fires after snap target changes on keydown press"); + + promise_test(async (t) => { + await test_no_snapchanged(t, scroller, /*delta*/10); + }, "snapchanged is not fired if snap target doesn't change on user scroll"); + </script> +</body> diff --git a/testing/web-platform/tests/css/css-scroll-snap-2/snapchanged/snapchanged-on-user-scroll.tentative.html b/testing/web-platform/tests/css/css-scroll-snap-2/snapchanged/snapchanged-on-user-scroll.tentative.html new file mode 100644 index 0000000000..4f36200722 --- /dev/null +++ b/testing/web-platform/tests/css/css-scroll-snap-2/snapchanged/snapchanged-on-user-scroll.tentative.html @@ -0,0 +1,170 @@ +<!DOCTYPE html> +<html> + +<head> + <meta charset="utf-8"> + <title> CSS Scroll Snap 2 Test: snapchanged events</title> + <link rel="help" href="https://drafts.csswg.org/css-scroll-snap-2/#snap-events"> + <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="/css/css-scroll-snap-2/resources/common.js"></script> + <script src="/css/css-scroll-snap-2/resources/user-scroll-common.js"></script> + <script src="/dom/events/scrolling/scroll_support.js"></script> + <script src="/web-animations/testcommon.js"></script> +</head> + +<body> + <style> + body { + margin: 0px; + } + + div { + position: absolute; + margin: 0px; + } + + #spacer { + width: 200vw; + height: 200vh; + } + + .scroller { + height: 400px; + width: 400px; + overflow: scroll; + scroll-snap-type: both mandatory; + } + + .snap_point { + width: 40%; + height: 40%; + scroll-snap-align: start; + } + + #snap_point_1 { + left: 0px; + top: 0px; + background-color: red; + } + + #snap_point_2 { + top: 35%; + left: 35%; + background-color: orange; + } + + #snap_point_3 { + top: 70%; + left: 70%; + background-color: blue; + } + </style> + <div id="scroller" class="scroller"> + <div id="spacer"></div> + <div id="snap_point_1" class="snap_point"></div> + <div id="snap_point_2" class="snap_point"></div> + <div id="snap_point_3" class="snap_point"></div> + </div> + <script> + const scroller = document.getElementById("scroller"); + const offset_to_snap_point_2 = { + x: snap_point_2.offsetLeft, + y: snap_point_2.offsetTop + }; + + // Touch scroll test. + promise_test(async (t) => { + await waitForCompositorCommit(); + const start_pos = { + x: scroller.clientWidth / 2, + y: scroller.clientHeight / 2, + }; + const end_pos = { x: 0, y: 0 }; + const test_data = { + scroller: scroller, + scrolling_function: async () => { + await snap_event_touch_scroll_helper(start_pos, end_pos); + }, + expected_snap_targets: [snap_point_2.id], + expected_scroll_offsets: { + x: offset_to_snap_point_2.x, + y: offset_to_snap_point_2.y, + } + }; + await test_snapchanged(t, test_data); + }, "snapchanged event fires after snap target changes on touch scroll"); + + // Wheel scroll test. + promise_test(async (t) => { + await waitForCompositorCommit(); + const test_data = { + scroller: scroller, + scrolling_function: async () => { + await new test_driver.Actions().scroll(0, 0, + offset_to_snap_point_2.x, + offset_to_snap_point_2.y, + { origin: scroller }).send(); + }, + expected_snap_targets: [snap_point_2.id], + expected_scroll_offsets: { + x: offset_to_snap_point_2.x, + y: offset_to_snap_point_2.y, + } + }; + await test_snapchanged(t, test_data); + }, "snapchanged event fires after snap target changes on wheel scroll"); + + // Scrollbar drag test. + promise_test(async (t) => { + await waitForCompositorCommit(); + // Skip test on platforms that do not have a visible scrollbar (e.g. + // overlay scrollbar). + const scrollbar_width = scroller.offsetWidth - scroller.clientWidth; + if (scrollbar_width == 0) + return; + const test_data = { + scroller: scroller, + scrolling_function: async () => { + const scrollbar_to_scroller_ratio = + getScrollbarToScrollerRatio(scroller); + // Scroll by just over half of the top box's height. + const drag_amt = (offset_to_snap_point_2.y / 2 + 1) * + scrollbar_to_scroller_ratio; + await snap_event_scrollbar_drag_helper(scroller, scrollbar_width, drag_amt); + }, + expected_snap_targets: [snap_point_1.id, snap_point_2.id], + expected_scroll_offsets: { + x: 0, + y: offset_to_snap_point_2.y, + } + }; + await test_snapchanged(t, test_data); + }, "snapchanged event fires after snap target changes on scrollbar drag"); + + // Keyboard test. + promise_test(async (t) => { + await waitForCompositorCommit(); + const test_data = { + scroller: scroller, + scrolling_function: async () => { + scroller.focus(); + window.test_driver.send_keys(scroller, '\ue015'/*ArrowDown*/); + }, + expected_snap_targets: [snap_point_1.id, snap_point_2.id], + expected_scroll_offsets: { + x: 0, + y: offset_to_snap_point_2.y, + } + }; + await test_snapchanged(t, test_data); + }, "snapchanged event fires after snap target changes on keydown press"); + + promise_test(async (t) => { + await test_no_snapchanged(t, scroller, /*delta*/10); + }, "snapchanged is not fired if snap target doesn't change on user scroll"); + </script> +</body> diff --git a/testing/web-platform/tests/css/css-scroll-snap-2/snapchanged/snapchanged-same-targets-after-layout-changed.html b/testing/web-platform/tests/css/css-scroll-snap-2/snapchanged/snapchanged-same-targets-after-layout-changed.html new file mode 100644 index 0000000000..4d16bd80a3 --- /dev/null +++ b/testing/web-platform/tests/css/css-scroll-snap-2/snapchanged/snapchanged-same-targets-after-layout-changed.html @@ -0,0 +1,106 @@ +<!DOCTYPE html> +<html> + +<head> + <link rel="help" href="https://drafts.csswg.org/css-scroll-snap-2/#snap-events" /> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + <script src="/dom/events/scrolling/scroll_support.js"></script> + <script src="/css/css-scroll-snap-2/resources/common.js"></script> + <style> + #scroller { + overflow-y: scroll; + scroll-snap-type: y mandatory; + width: 500px; + height: 500px; + background-color: white; + position: relative; + } + .large_space { + position: absolute; + height: 100vh; + width: 100vw; + } + .space_filler { + display: inline-block; + width: 40%; + height: 30%; + background-color: green; + } + .snap_area { + scroll-snap-align: start; + background-color: yellow; + position: absolute; + width: 40%; + height: 30%; + top: 500px; + } + + .left { + left: 1px; + } + .right { + left: 41%; + } + </style> +</head> +<body> + <div id="scroller"> + <div class="large_space"></div> + <div class="space_filler"></div> + <div class="space_filler"></div> + <div class="space_filler"></div> + <div class="space_filler"></div> + <div class="space_filler"></div> + <div class="space_filler"></div> + <div class="space_filler"></div> + <div class="space_filler"></div> + <div id="left" class="snap_area left"><h1>1</h1></div> + <div id="right" class="snap_area right"><h1>2</h1></div> + </div> + <script> + let unreached_func = null; + promise_test(async (t) => { + checkSnapEventSupport("snapchanged"); + await waitForCompositorCommit(); + unreached_func = t.unreached_func("snapchanged shouldn't fire " + + "since the scroller is snapped to the same elements."); + scroller.addEventListener("snapchanged", unreached_func); + t.add_cleanup(() => { + scroller.removeEventListener("snapchanged", unreached_func); + }); + assert_greater_than(right.offsetLeft, left.offsetLeft, + "boxes have switched positions."); + // Switch the boxes' horizontal positions. + right.style.left = "1px"; + left.style.left = "41%"; + await waitForCompositorCommit(); + assert_less_than(right.offsetLeft, left.offsetLeft, + "boxes have switched positions."); + await waitForCompositorCommit(); + }, "snapchanged doesn't fire after layout change if snapped to the same " + + "elements"); + + promise_test(async (t) => { + checkSnapEventSupport("snapchanged"); + await waitForCompositorCommit(); + unreached_func = t.unreached_func("snapchanged shouldn't fire " + + "since the scroller is snapped to the same elements."); + scroller.addEventListener("snapchanged", unreached_func); + t.add_cleanup(() => { + scroller.removeEventListener("snapchanged", unreached_func); + }); + const scrollend_promise = waitForScrollendEventNoTimeout(scroller); + // Move the boxes to the same vertical level. Both boxes should still be + // considered snapped to so snapchanged should not be triggerred. + right.style.top = `0px`; + left.style.top = `0px`; + await scrollend_promise; + assert_equals(scroller.scrollTop, 0); + await waitForCompositorCommit(); + }, "snapchanged doesn't fire after snap to the same targets after scroll. " + + "elements"); + + </script> +</body> +</html> diff --git a/testing/web-platform/tests/css/css-scroll-snap-2/snapchanged/snapchanged-with-proximity-strictness.tentative.html b/testing/web-platform/tests/css/css-scroll-snap-2/snapchanged/snapchanged-with-proximity-strictness.tentative.html new file mode 100644 index 0000000000..cb55054e6f --- /dev/null +++ b/testing/web-platform/tests/css/css-scroll-snap-2/snapchanged/snapchanged-with-proximity-strictness.tentative.html @@ -0,0 +1,80 @@ +<!DOCTYPE html> +<html> +<head> +<title> + <title> CSS Scroll Snap 2 Test: snapchanged events on proximity strictness container</title> + <link rel="help" href="https://drafts.csswg.org/css-scroll-snap-2/#snap-events"/> +</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/dom/events/scrolling/scroll_support.js"></script> +<script src="/css/css-scroll-snap-2/resources/common.js"></script> +<style> + div { + position: absolute; + margin: 0; + } + + #scroller { + height: 600px; + width: 600px; + overflow: hidden; + scroll-snap-type: y proximity; + } + + .snap { + width: 300px; + height: 300px; + background-color: green; + scroll-snap-align: start; + } + + .area { + width: 2000px; + height: 2000px; + } + </style> +</head> +<body> +<div id="scroller"> + <div class="area"></div> + <div id="target" class="snap" style="top: 0px;"></div> +</div> + +<script> + const target = document.getElementById("target"); + let resolve_func = null; + + promise_test(async (test) => { + checkSnapEventSupport("snapchanged"); + await waitForCompositorCommit(); + // The initial snap position is at (0, 0). + assert_equals(scroller.scrollTop, 0); + assert_equals(scroller.scrollLeft, 0); + + let snapchanged_promise = waitForSnapChangedEvent(scroller); + // Scroll to a position where it's outside of the scroll-snap proximity + // threshold, so that it won't trigger snapping. + scroller.scrollTo(0, 250); + + // snapchanged should fire as we've moved from within the proximity range + // to outside the proximity range and are no longer snapped. + let evt = await snapchanged_promise; + assert_equals(scroller.scrollTop, 250); + assertSnapEvent(evt, []); + evt = null; + + snapchanged_promise = waitForSnapChangedEvent(scroller); + // Scroll to a position within the scroll-snap proximity + // threshold, so that it triggers snapping. + scroller.scrollTo(0, 190); + + evt = await snapchanged_promise; + assert_equals(scroller.scrollTop, 0); + // snapchanged should fire as we've moved from outside the proximity range + // to inside the proximity range and are once again snapped. + assertSnapEvent(evt, [target.id]); + }, "Snapchanged fires when scrolling outside proximity range."); + </script> +</body> +</html> diff --git a/testing/web-platform/tests/css/css-scroll-snap-2/snapchanging/snapchanging-after-layout-change.tentative.html b/testing/web-platform/tests/css/css-scroll-snap-2/snapchanging/snapchanging-after-layout-change.tentative.html new file mode 100644 index 0000000000..5474b7ddce --- /dev/null +++ b/testing/web-platform/tests/css/css-scroll-snap-2/snapchanging/snapchanging-after-layout-change.tentative.html @@ -0,0 +1,118 @@ +<!DOCTYPE html> +<html> +<head> + <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="/dom/events/scrolling/scroll_support.js"></script> + <script src="/css/css-scroll-snap-2/resources/common.js"></script> + <script src="/css/css-scroll-snap-2/resources/user-scroll-common.js"></script> + <script src="/web-animations/testcommon.js"></script> + <style> + body { + margin: 0px; + } + #space { + height: 200vh; + width: 200vw; + } + .scroller { + scroll-snap-type: x mandatory; + overflow-x: auto; + overflow-y: hidden; + position: relative; + height: 500px; + width: 500px; + } + + .box { + scroll-snap-align: start; + height: 100px; + width: 100px; + position: absolute; + top: 200px; + } + + #box1 { + background-color: red; + } + + #box2 { + background-color: yellow; + left: 200px; + } + + #box3 { + background-color: blue; + left: 400px; + } + </style> +</head> +<body> + <div id="scroller" class="scroller"> + <div id="space"></div> + <div id="box1" class="box"><h1>1</h1></div> + <div id="box2" class="box"><h1>2</h1></div> + <div id="box3" class="box"><h1>3</h1></div> + </div> + <script> + const scroller = document.getElementById("scroller"); + promise_test(async (t) => { + // This tests snapchanging firing after a layout change in the middle of a + // touch scroll. We start a touch scroll far enough that snapchanging + // fires and then, with the pointer still down, we change the layout so + // that snapchanging should fire with a different target. + await waitForScrollReset(t, scroller); + await waitForCompositorCommit(); + + const start_pos_x = Math.round(box2.offsetLeft); + // Drag by enough to ensure box2 is the preferred snap target. + const drag_amt = Math.round(box2.offsetLeft / 2) + 50; + const end_pos_x = start_pos_x - drag_amt; + const pos_y = Math.round(scroller.clientHeight / 2); + let evt_promise; + let snap_evt; + + const save_snapchanging_evt = (evt) => { snap_evt = evt; } + evt_promise = scroller.addEventListener("snapchanging", + save_snapchanging_evt); + // We wait to reach the expected scroll position rather than waiting for a + // snapchanging event to avoid timing out if the snapchanging event does + // not fire. + const scroll_promise = new Promise((resolve) => { + scroller.addEventListener("scroll", async () => { + if (scroller.scrollLeft >= (box2.offsetLeft / 2)) { + await waitForAnimationFrames(2); + resolve(); + } + }); + }); + + await new test_driver.Actions() + .addPointer("TestPointer", "touch") + .pointerMove(start_pos_x, pos_y) + .pointerDown() + .addTick() + .pause(200) + // Drag closer to box2, which should trigger a snapchanging event. + .pointerMove(start_pos_x - drag_amt, pos_y) + .send(); + + // assert snapchanging that should have already happened. + await scroll_promise; + assertSnapEvent(snap_evt, [box2.id]); + + evt_promise = waitForSnapEvent(scroller, "snapchanging", false); + // Change layout while pointer is still down. + let box2_prev_left = getComputedStyle(box2).getPropertyValue("left"); + let box3_prev_left = getComputedStyle(box3).getPropertyValue("left"); + box2.style.left = box3_prev_left; + box3.style.left = box2_prev_left; + snap_evt = await evt_promise; + assertSnapEvent(snap_evt, [box3.id]); + }, "snapchanging fires after layout change"); + </script> +</body> +</html>
\ No newline at end of file diff --git a/testing/web-platform/tests/css/css-scroll-snap-2/snapchanging/snapchanging-on-programmatic-root-scroll.tentative.html b/testing/web-platform/tests/css/css-scroll-snap-2/snapchanging/snapchanging-on-programmatic-root-scroll.tentative.html new file mode 100644 index 0000000000..d031811c17 --- /dev/null +++ b/testing/web-platform/tests/css/css-scroll-snap-2/snapchanging/snapchanging-on-programmatic-root-scroll.tentative.html @@ -0,0 +1,105 @@ +<!DOCTYPE html> +<html> + +<head> + <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="/dom/events/scrolling/scroll_support.js"></script> + <script src="/css/css-scroll-snap-2/resources/common.js"></script> +ß <script src="/web-animations/testcommon.js"></script> +</head> + +<body> + <style> + :root { + scroll-snap-type: y mandatory; + } + + .box { + position: absolute; + left: 150px; + height: 80vh; + width: 100px; + border: solid 1px white; + } + + .snap { + scroll-snap-align: start; + } + + .blue { + background-color: blue; + } + + .green { + background-color: green; + } + + .yellow { + background-color: yellow; + } + + #snap_area_1 { + top: 0px; + } + + #snap_area_2 { + top: calc(80vh + 2px); + } + + #snap_area_3 { + top: calc(160vh + 4px); + } + + .large_space { + height: 400vh; + width: 400vw; + position: absolute; + } + </style> + <div class="large_space"></div> + <div id="snap_area_1" class="blue snap box"></div> + <div id="snap_area_2" class="green snap box"></div> + <div id="snap_area_3" class="yellow snap box"></div> + <script> + const scroller = document.scrollingElement; + + promise_test(async (t) => { + await waitForCompositorCommit(); + const test_data = { + scroller: scroller, + scrolling_function: async () => { + scroller.scrollTo(0, snap_area_2.offsetTop); + }, + expected_snap_targets: [snap_area_2.id], + expected_scroll_offsets: { + x: 0, + y: snap_area_2.offsetTop + } + }; + await test_snap_event(t, test_data, "snapchanging"); + }, "snapchanging fires on programmatic scrolls that changes a scroller's" + + " snap targets."); + + promise_test(async (t) => { + checkSnapEventSupport("snapchanging"); + await waitForScrollReset(t, scroller); + await waitForCompositorCommit(); + let snap_event_promise = waitForSnapEvent(document, "snapchanging", false); + // The snap areas are far apart enough that 10px is not enough to trigger + // a change in snap targets. + const small_scroll_offset = 10; + scroller.scrollTo(0, small_scroll_offset); + let evt = await snap_event_promise; + assert_equals(evt, null, "no snap event since scroller is back to top"); + assert_equals(scroller.scrollTop, 0, "scroller snaps back to the top"); + assert_equals(scroller.scrollLeft, 0, "scroller snaps back to the left"); + }, "snapchanging does not fire on programmatic scrolls that don't " + + "trigger a change in snap targets."); + </script> +</body> + +</html> diff --git a/testing/web-platform/tests/css/css-scroll-snap-2/snapchanging/snapchanging-on-programmatic-scroll.tentative.html b/testing/web-platform/tests/css/css-scroll-snap-2/snapchanging/snapchanging-on-programmatic-scroll.tentative.html new file mode 100644 index 0000000000..5a0de1deb3 --- /dev/null +++ b/testing/web-platform/tests/css/css-scroll-snap-2/snapchanging/snapchanging-on-programmatic-scroll.tentative.html @@ -0,0 +1,113 @@ +<!DOCTYPE html> +<html> + +<head> + <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="/dom/events/scrolling/scroll_support.js"></script> + <script src="/css/css-scroll-snap-2/resources/common.js"></script> + <script src="/web-animations/testcommon.js"></script> +</head> + +<body> + <style> + #scroller { + height: 400px; + width: 400px; + position: relative; + overflow: scroll; + scroll-snap-type: y mandatory; + border: solid 1px black; + } + + .box { + position: absolute; + left: 150px; + height: 350px; + width: 100px; + border: solid 1px white; + } + + .snap { + scroll-snap-align: start; + } + + .blue { + background-color: blue; + } + + .green { + background-color: green; + } + + .yellow { + background-color: yellow; + } + + #snap_area_1 { + top: 0px; + } + + #snap_area_2 { + top: 352px; + } + + #snap_area_3 { + top: 704px; + } + + .large_space { + height: 400vh; + width: 400vw; + position: absolute; + } + </style> + <div id="scroller"> + <div class="large_space"></div> + <div id="snap_area_1" class="blue snap box"></div> + <div id="snap_area_2" class="green snap box"></div> + <div id="snap_area_3" class="yellow snap box"></div> + </div> + <script> + const scroller = document.getElementById("scroller"); + + promise_test(async (t) => { + await waitForCompositorCommit(); + const test_data = { + scroller: scroller, + scrolling_function: async () => { + scroller.scrollTo(0, snap_area_2.offsetTop); + }, + expected_snap_targets: [snap_area_2.id], + expected_scroll_offsets: { + x: 0, + y: snap_area_2.offsetTop + } + }; + await test_snap_event(t, test_data, "snapchanging"); + }, "snapchanging fires on programmatic scrolls that changes a scroller's" + + " snap targets."); + + promise_test(async (t) => { + checkSnapEventSupport("snapchanging"); + await waitForScrollReset(t, scroller); + await waitForCompositorCommit(); + let snap_event_promise = waitForSnapEvent(scroller, "snapchanging", false); + // The snap areas are far apart enough that 10px is not enough to trigger + // a change in snap targets. + const small_scroll_offset = 10; + // Set the scroll destination to just a little off (0, 0) top so we snap + // back to the top box. + scroller.scrollTo(0, small_scroll_offset); + let evt = await snap_event_promise; + assert_equals(evt, null, "no snap event since scroller is back to top"); + assert_equals(scroller.scrollTop, 0, "scroller snaps back to the top"); + assert_equals(scroller.scrollLeft, 0, "scroller snaps back to the left"); + }); + </script> +</body> + +</html> diff --git a/testing/web-platform/tests/css/css-scroll-snap-2/snapchanging/snapchanging-on-user-root-scroll.tentative.html b/testing/web-platform/tests/css/css-scroll-snap-2/snapchanging/snapchanging-on-user-root-scroll.tentative.html new file mode 100644 index 0000000000..29d0239e2d --- /dev/null +++ b/testing/web-platform/tests/css/css-scroll-snap-2/snapchanging/snapchanging-on-user-root-scroll.tentative.html @@ -0,0 +1,198 @@ +<!DOCTYPE html> +<html> + +<head> + <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="/dom/events/scrolling/scroll_support.js"></script> + <script src="/css/css-scroll-snap-2/resources/common.js"></script> + <script src="/css/css-scroll-snap-2/resources/user-scroll-common.js"></script> +</head> + +<body> + <style> + :root { + scroll-snap-type: y mandatory; + } + #scroller { + height: 400px; + width: 400px; + position: relative; + overflow: scroll; + scroll-snap-type: y mandatory; + border: solid 1px black; + } + + .box { + position: absolute; + left: 150px; + height: 80vh; + width: 100px; + border: solid 1px white; + } + + .snap { + scroll-snap-align: start; + } + + .blue { + background-color: blue; + } + + .green { + background-color: green; + } + + .yellow { + background-color: yellow; + } + + #snap_area_1 { + top: 0px; + } + + #snap_area_2 { + top: calc(80vh + 2px); /* height of snap_area_1 + its borders. */ + } + + #snap_area_3 { + top: calc(160vh + 4px); /* heights of snap areas 1 & 2 + their borders */ + } + + .large_space { + height: 400vh; + width: 400vw; + position: absolute; + } + </style> + <div class="large_space"></div> + <div id="snap_area_1" class="blue snap box"></div> + <div id="snap_area_2" class="green snap box"></div> + <div id="snap_area_3" class="yellow snap box"></div> + <script> + const scroller = document.scrollingElement; + + // Touch scroll test. + promise_test(async (t) => { + await waitForCompositorCommit(); + const scroller_middle = Math.round(scroller.clientWidth / 2); + const test_data = { + scroller: scroller, + scrolling_function: async () => { + const start_pos = { x: scroller_middle, y: snap_area_2.offsetTop }; + const end_pos = { x: scroller_middle, y: 0 }; + await snap_event_touch_scroll_helper(start_pos, end_pos); + }, + expected_snap_targets: [snap_area_2.id], + expected_scroll_offsets: { + x: 0, + y: snap_area_2.offsetTop + } + }; + await test_snap_event(t, test_data, "snapchanging"); + }, "touch scrolling fires snapchanging."); + + // Wheel scroll test. + promise_test(async (t) => { + await waitForCompositorCommit(); + const test_data = { + scroller: scroller, + scrolling_function: async () => { + await new test_driver.Actions().scroll(0, 0, 0, + Math.round(snap_area_2.offsetTop / 2) + 1).send(); + }, + expected_snap_targets: [snap_area_2.id], + expected_scroll_offsets: { + x: 0, + y: snap_area_2.offsetTop + } + }; + await test_snap_event(t, test_data, "snapchanging"); + }, "mouse wheel scroll triggers snapchanging."); + + // Scrollbar drag test. + promise_test(async (t) => { + await waitForCompositorCommit(); + // Skip test on platforms that do not have a visible scrollbar (e.g. + // overlay scrollbar). + const scrollbar_width = window.innerWidth - + document.documentElement.clientWidth; + const test_data = { + scroller: scroller, + scrolling_function: async () => { + const scrollbar_to_scroller_ratio = + getScrollbarToScrollerRatio(scroller); + // Scroll by just over half of the top box's height. + const drag_amt = (snap_area_2.offsetTop / 2 + 1) * + scrollbar_to_scroller_ratio; + await snap_event_scrollbar_drag_helper(scroller, scrollbar_width, drag_amt); + }, + expected_snap_targets: [snap_area_2.id], + expected_scroll_offsets: { + x: 0, + y: snap_area_2.offsetTop + } + }; + await test_snap_event(t, test_data, "snapchanging"); + }, "scrollbar dragging fires snapchanging."); + + // Keyboard test. + promise_test(async (t) => { + await waitForCompositorCommit(); + const test_data = { + scroller: scroller, + scrolling_function: async () => { + scroller.focus(); + window.test_driver.send_keys(document.documentElement, '\ue015'/*ArrowDown*/); + }, + expected_snap_targets: [snap_area_2.id], + expected_scroll_offsets: { + x: 0, + y: snap_area_2.offsetTop + } + }; + await test_snap_event(t, test_data, "snapchanging"); + }, "keyboard scroll triggers snapchanging."); + + // Touch scroll test: peek at snap_area_2 and then drag back to + // snap_area_1. + promise_test(async (t) => { + await waitForScrollReset(t, scroller); + await waitForCompositorCommit(); + const pos_x = Math.round(scroller.clientWidth / 2); + const start_pos_y = Math.round(snap_area_2.offsetTop); + let evts_promise = waitForEventsUntil(document, "snapchanging", + waitForScrollendEventNoTimeout(document)); + await new test_driver.Actions() + .addPointer("TestPointer", "touch") + .pointerMove(pos_x, start_pos_y) + .pointerDown() + .addTick() + .pause(200) + // Drag up to y=0, which should trigger a snapchanging event. + .pointerMove(pos_x, 0) + .addTick() + .pause(200) + // Drag down again to start position, which should trigger a + // snapchanging event. + .pointerMove(pos_x, start_pos_y) + .pointerUp() + .send(); + let evts = await evts_promise; + assert_equals(evts.length, 2, "2 snapchanging events are seens"); + assertSnapEvent(evts[0], [snap_area_2.id]); + assertSnapEvent(evts[1], [snap_area_1.id]); + }, "snapchanging fires as scroll moves through different snap targets."); + + // snapchanging doesn't fire test. + promise_test(async (t) => { + test_no_snapchanging(t, scroller, 10); + }, "snapchanging doesn't fire if scroll doesn't reach different snap " + + "targets."); + </script> +</body> + +</html>
\ No newline at end of file diff --git a/testing/web-platform/tests/css/css-scroll-snap-2/snapchanging/snapchanging-on-user-scroll.tentative.html b/testing/web-platform/tests/css/css-scroll-snap-2/snapchanging/snapchanging-on-user-scroll.tentative.html new file mode 100644 index 0000000000..2c1f9742b6 --- /dev/null +++ b/testing/web-platform/tests/css/css-scroll-snap-2/snapchanging/snapchanging-on-user-scroll.tentative.html @@ -0,0 +1,188 @@ +<!DOCTYPE html> +<html> +<head> + <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="/dom/events/scrolling/scroll_support.js"></script> + <script src="/css/css-scroll-snap-2/resources/common.js"></script> + <script src="/css/css-scroll-snap-2/resources/user-scroll-common.js"></script> +</head> + +<body> + <style> + #scroller { + height: 400px; + width: 400px; + position: relative; + overflow: scroll; + scroll-snap-type: y mandatory; + border: solid 1px black; + } + .box { + position: absolute; + left: 150px; + height: 350px; + width: 100px; + border: solid 1px white; + } + .snap { + scroll-snap-align: start; + } + .blue { + background-color: blue; + } + .green { + background-color: green; + } + .yellow { + background-color: yellow; + } + #snap_area_1 { + top: 0px; + } + #snap_area_2 { + top: 352px; + } + #snap_area_3 { + top: 704px; + } + .large_space { + height: 400vh; + width: 400vw; + position: absolute; + } + </style> + <div id="scroller"> + <div class="large_space"></div> + <div id="snap_area_1" class="blue snap box"></div> + <div id="snap_area_2" class="green snap box"></div> + <div id="snap_area_3" class="yellow snap box"></div> + </div> + <script> + const scroller = document.getElementById("scroller"); + + // Touch scroll test. + promise_test(async (t) => { + await waitForCompositorCommit(); + const scroller_middle = Math.round(scroller.clientWidth / 2); + const test_data = { + scroller: scroller, + scrolling_function: async () => { + const start_pos = { x: scroller_middle, y: snap_area_2.offsetTop }; + const end_pos = { x: scroller_middle, y: 0 }; + await snap_event_touch_scroll_helper(start_pos, end_pos); + }, + expected_snap_targets: [snap_area_2.id], + expected_scroll_offsets: { + x: 0, + y: snap_area_2.offsetTop + } + }; + await test_snap_event(t, test_data, "snapchanging"); + }, "touch scrolling fires snapchanging."); + + // Wheel scroll test. + promise_test(async (t) => { + await waitForCompositorCommit(); + const test_data = { + scroller: scroller, + scrolling_function: async () => { + await new test_driver.Actions().scroll(0, 0, 0, + Math.round(snap_area_2.offsetTop / 2) + 1, + { origin: scroller }).send(); + }, + expected_snap_targets: [snap_area_2.id], + expected_scroll_offsets: { + x: 0, + y: snap_area_2.offsetTop + } + }; + await test_snap_event(t, test_data, "snapchanging"); + }, "mouse wheel scroll triggers snapchanging."); + + // Scrollbar drag test. + promise_test(async (t) => { + await waitForCompositorCommit(); + // Skip test on platforms that do not have a visible scrollbar (e.g. + // overlay scrollbar). + const scrollbar_width = scroller.offsetWidth - scroller.clientWidth; + if (scrollbar_width == 0) + return; + const test_data = { + scroller: scroller, + scrolling_function: async () => { + const scrollbar_to_scroller_ratio = + getScrollbarToScrollerRatio(scroller); + // Scroll by just over half of the top box's height. + const drag_amt = (snap_area_2.offsetTop / 2 + 1) * + scrollbar_to_scroller_ratio; + await snap_event_scrollbar_drag_helper(scroller, scrollbar_width, drag_amt); + }, + expected_snap_targets: [snap_area_2.id], + expected_scroll_offsets: { + x: 0, + y: snap_area_2.offsetTop + } + }; + await test_snap_event(t, test_data, "snapchanging"); + }, "scrollbar dragging fires snapchanging."); + + // Keyboard test. + promise_test(async (t) => { + await waitForCompositorCommit(); + const test_data = { + scroller: scroller, + scrolling_function: async () => { + scroller.focus(); + window.test_driver.send_keys(scroller, '\ue015'/*ArrowDown*/); + }, + expected_snap_targets: [snap_area_2.id], + expected_scroll_offsets: { + x: 0, + y: snap_area_2.offsetTop + } + }; + await test_snap_event(t, test_data, "snapchanging"); + }, "keyboard scroll triggers snapchanging."); + + // Touch scroll test: peek at snap_area_2 and then drag back to + // snap_area_1. + promise_test(async (t) => { + await waitForScrollReset(t, scroller); + await waitForCompositorCommit(); + const pos_x = Math.round(scroller.clientWidth / 2); + const start_pos_y = Math.round(snap_area_2.offsetTop); + let evts_promise = waitForEventsUntil(scroller, "snapchanging", + waitForScrollendEventNoTimeout(scroller)); + await new test_driver.Actions() + .addPointer("TestPointer", "touch") + .pointerMove(pos_x, start_pos_y) + .pointerDown() + .addTick() + .pause(200) + // Drag up to y=0, which should trigger a snapchanging event. + .pointerMove(pos_x, 0) + .addTick() + .pause(200) + // Drag down again to start position, which should trigger a + // snapchanging event. + .pointerMove(pos_x, start_pos_y) + .pointerUp() + .send(); + let evts = await evts_promise; + assert_equals(evts.length, 2, "2 snapchanging events are seens"); + assertSnapEvent(evts[0], [snap_area_2.id]); + assertSnapEvent(evts[1], [snap_area_1.id]); + }, "snapchanging fires as scroll moves through different snap targets."); + + // snapchanging doesn't fire test. + promise_test(async (t) => { + test_no_snapchanging(t, scroller, 10); + }, "snapchanging doesn't fire if scroll doesn't reach different snap " + + "targets."); + </script> + </body> +</html> |