mirror of
https://github.com/servo/servo.git
synced 2025-09-27 07:10:19 +01:00
script: Chain up keyboard scrolling to parent <iframe>
s (#39469)
When an `<iframe>` cannot scroll because the size of the frame is greater than or equal to the size of page contents, chain up the keyboard scroll operation to the parent frame. Testing: A new Servo-only WPT tests is added, though needs to be manually run with `--product servodriver`. Signed-off-by: Martin Robinson <mrobinson@igalia.com> Co-authored-by: Delan Azabani <dazabani@igalia.com>
This commit is contained in:
parent
75e32ba5a4
commit
ffdb7d3663
23 changed files with 406 additions and 132 deletions
27
tests/wpt/mozilla/meta/MANIFEST.json
vendored
27
tests/wpt/mozilla/meta/MANIFEST.json
vendored
|
@ -12757,15 +12757,6 @@
|
|||
{}
|
||||
]
|
||||
],
|
||||
"keyboard-scrolling.html": [
|
||||
"2d9a0c40272d8af49f26de8dc49283df68b2d7b0",
|
||||
[
|
||||
null,
|
||||
{
|
||||
"testdriver": true
|
||||
}
|
||||
]
|
||||
],
|
||||
"matchMedia.html": [
|
||||
"45a7ea268b1ebdba69e947b79d675cc9221428d4",
|
||||
[
|
||||
|
@ -13811,6 +13802,24 @@
|
|||
{}
|
||||
]
|
||||
],
|
||||
"keyboard-scrolling-iframe.sub.html": [
|
||||
"e002eb6f2a35ed4f73a079acb05b3d99eb04813b",
|
||||
[
|
||||
null,
|
||||
{
|
||||
"testdriver": true
|
||||
}
|
||||
]
|
||||
],
|
||||
"keyboard-scrolling.html": [
|
||||
"45916c5d11f351f0ca10cde5e52d5ee60c11bd9d",
|
||||
[
|
||||
null,
|
||||
{
|
||||
"testdriver": true
|
||||
}
|
||||
]
|
||||
],
|
||||
"keyframe-infinite-percentage.html": [
|
||||
"36ba83eeac401653356fa38edf30c94d38fd8542",
|
||||
[
|
||||
|
|
165
tests/wpt/mozilla/tests/mozilla/keyboard-scrolling-iframe.sub.html
vendored
Normal file
165
tests/wpt/mozilla/tests/mozilla/keyboard-scrolling-iframe.sub.html
vendored
Normal file
|
@ -0,0 +1,165 @@
|
|||
|
||||
<!doctype html>
|
||||
<meta charset="utf-8">
|
||||
<title>A test to verify that keyboard scrolling works properly in Servo in IFRAMEs.</title>
|
||||
<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>
|
||||
<style>
|
||||
body {
|
||||
margin: 0;
|
||||
}
|
||||
iframe {
|
||||
position: fixed;
|
||||
width: 200px;
|
||||
height: 200px;
|
||||
outline: solid;
|
||||
}
|
||||
</style>
|
||||
|
||||
<!-- This is an IFRAME that should be scrollable via keyboard. -->
|
||||
<iframe id="iframe" style="left: 100px; top: 100px;" srcdoc='
|
||||
<!DOCTYPE html>
|
||||
<body style="margin: 0;">
|
||||
<div style="width: 600px; height: 600px; background: blue;">Lorem ipsum dolor sit amet,</div>
|
||||
'></iframe>
|
||||
|
||||
<!-- This IFRAME does not scroll, so keyboard events should chain to the main frame. -->
|
||||
<iframe id="iframeWithSmallContent" style="left: 300px; top: 100px;" src='iframe_child1.html'></iframe>
|
||||
|
||||
<!-- This IFRAME does not scroll and is also cross origin, so keyboard events should chain to the main frame. -->
|
||||
<iframe id="iframeCrossOriginWithSmallContent" style="left: 100px; top: 300px;" src='//{{hosts[alt][]}}:{{ports[http][0]}}/_mozilla/mozilla/iframe_child1.html'></iframe>
|
||||
|
||||
<!-- This IFRAME does not scroll because the body has overflow: hidden, so keyboard events should chain to the main frame. -->
|
||||
<iframe id="iframeWithOverflowHiddenBody" style="left: 300px; top: 300px;" srcdoc='
|
||||
<!DOCTYPE html>
|
||||
<body style="overflow:hidden;">
|
||||
<div style="width: 600px; height: 600px; background: blue;">Lorem ipsum dolor sit amet,</div>
|
||||
'></iframe>
|
||||
|
||||
|
||||
<div style="width: 300vw; height: 300vh; background: green;">
|
||||
Lorem ipsum dolor sit amet,
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const end = "\uE010";
|
||||
const home = "\uE011";
|
||||
const arrowDown = "\uE015";
|
||||
const arrowUp = "\uE013";
|
||||
const arrowRight = "\uE014";
|
||||
const arrowLeft = "\uE012";
|
||||
const pageDown = "\uE00F";
|
||||
const pageUp = "\uE00E";
|
||||
const lineSize = 76;
|
||||
const pageSize = scrollportHeight => scrollportHeight - 2 * lineSize;
|
||||
|
||||
const pressKeyAndAssert = async (key, element, [expectedX, expectedY], description) => {
|
||||
await test_driver.send_keys(document.body, key);
|
||||
const actualX =
|
||||
element == null ? scrollX
|
||||
: element.nodeName == "IFRAME" ? element.contentWindow.scrollX
|
||||
: element.scrollLeft;
|
||||
const actualY =
|
||||
element == null ? scrollY
|
||||
: element.nodeName == "IFRAME" ? element.contentWindow.scrollY
|
||||
: element.scrollTop;
|
||||
assert_array_equals([actualX, actualY], [expectedX, expectedY], description);
|
||||
};
|
||||
|
||||
promise_test(async () => {
|
||||
await test_driver.click(iframe);
|
||||
|
||||
let bottom = iframe.contentDocument.documentElement.scrollHeight - iframe.contentWindow.innerHeight;
|
||||
await pressKeyAndAssert(end, iframe, [0, bottom], "End key scrolls #iframe to bottom");
|
||||
await pressKeyAndAssert(home, iframe, [0, 0], "Home key scrolls #iframe to top");
|
||||
await pressKeyAndAssert(arrowDown, iframe, [0, lineSize], "ArrowDown key scrolls #iframe down by a line");
|
||||
await pressKeyAndAssert(arrowDown, iframe, [0, lineSize * 2], "ArrowDown key scrolls #iframe down by a line");
|
||||
await pressKeyAndAssert(arrowUp, iframe, [0, lineSize], "ArrowUp key scrolls #iframe up by a line");
|
||||
await pressKeyAndAssert(arrowUp, iframe, [0, 0], "ArrowUp key scrolls #iframe up by a line");
|
||||
await pressKeyAndAssert(arrowRight, iframe, [lineSize, 0], "ArrowRight key scrolls #iframe right by a line");
|
||||
await pressKeyAndAssert(arrowRight, iframe, [lineSize * 2, 0], "ArrowRight key scrolls #iframe right by a line");
|
||||
await pressKeyAndAssert(arrowLeft, iframe, [lineSize, 0], "ArrowLeft key scrolls #iframe left by a line");
|
||||
await pressKeyAndAssert(arrowLeft, iframe, [0, 0], "ArrowLeft key scrolls #iframe left by a line");
|
||||
await pressKeyAndAssert(pageDown, iframe, [0, pageSize(iframe.contentWindow.innerHeight)], "PageDown key scrolls #iframe down by almost a screenful");
|
||||
await pressKeyAndAssert(pageDown, iframe, [0, pageSize(iframe.contentWindow.innerHeight) * 2], "PageDown key scrolls #iframe down by almost a screenful");
|
||||
await pressKeyAndAssert(pageUp, iframe, [0, pageSize(iframe.contentWindow.innerHeight)], "PageUp key scrolls #iframe up by almost a screenful");
|
||||
await pressKeyAndAssert(pageUp, iframe, [0, 0], "PageUp key scrolls #iframe up by almost a screenful");
|
||||
|
||||
// At the bottom of the IFRAME, we should not chain up to scrolling the document.
|
||||
await pressKeyAndAssert(end, iframe, [0, bottom], "End key scrolls #iframe to bottom");
|
||||
await pressKeyAndAssert(arrowDown, iframe, [0, bottom], "ArrowDown should not move the iframe past the max Y position");
|
||||
await pressKeyAndAssert(arrowDown, iframe, [0, bottom], "ArrowDown should not move the iframe past the max Y position");
|
||||
await pressKeyAndAssert(arrowDown, iframe, [0, bottom], "ArrowDown should not move the iframe past the max Y position");
|
||||
assert_array_equals([scrollX, scrollY], [0, 0], "Keyboard scroll on a div should not chain to body");
|
||||
await pressKeyAndAssert(home, iframe, [0, 0], "Home key scrolls #iframe to top");
|
||||
}, "Keyboard scrolling works in #iframe");
|
||||
|
||||
promise_test(async () => {
|
||||
await test_driver.click(iframeWithOverflowHiddenBody);
|
||||
|
||||
await pressKeyAndAssert(arrowDown, iframeWithOverflowHiddenBody, [0, 0], "Arrow down key should not scroll #iframeWithOverflowHiddenBody");
|
||||
assert_array_equals([scrollX, scrollY], [0, lineSize], "The body should scroll instead of #iframeWithOverflowHiddenBody");
|
||||
await pressKeyAndAssert(arrowDown, iframeWithOverflowHiddenBody, [0, 0], "Arrow down key should not scroll #iframeWithOverflowHiddenBody");
|
||||
assert_array_equals([scrollX, scrollY], [0, lineSize * 2], "The body should scroll instead of #iframeWithOverflowHiddenBody");
|
||||
|
||||
await pressKeyAndAssert(arrowUp, iframeWithOverflowHiddenBody, [0, 0], "Arrow up key should not scroll #iframeWithOverflowHiddenBody");
|
||||
assert_array_equals([scrollX, scrollY], [0, lineSize], "The body should scroll instead of #iframeWithOverflowHiddenBody");
|
||||
await pressKeyAndAssert(arrowUp, iframeWithOverflowHiddenBody, [0, 0], "Arrow up key should not scroll #iframeWithOverflowHiddenBody");
|
||||
assert_array_equals([scrollX, scrollY], [0, 0], "The body should scroll instead of #iframeWithOverflowHiddenBody");
|
||||
}, "Keyboard scrolling on iframe with a body that has `overflow:hidden` chains to main document");
|
||||
|
||||
promise_test(async () => {
|
||||
await test_driver.click(iframeCrossOriginWithSmallContent);
|
||||
|
||||
function waitForScrollEvent() {
|
||||
return new Promise((resolve) => {
|
||||
addEventListener("scroll", () => {
|
||||
resolve();
|
||||
}, { "once": true })
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
// We must create the promise before actually triggering the event, as the event might
|
||||
// be fired while we are awaiting the keyboard action.
|
||||
let promise = waitForScrollEvent();
|
||||
await test_driver.send_keys(document.body, arrowDown);
|
||||
await promise;
|
||||
assert_array_equals([scrollX, scrollY], [0, lineSize], "The body should scroll instead of #iframeCrossOriginWithSmallContent");
|
||||
|
||||
promise = waitForScrollEvent();
|
||||
await test_driver.send_keys(document.body, arrowDown);
|
||||
await promise;
|
||||
assert_array_equals([scrollX, scrollY], [0, lineSize * 2], "The body should scroll instead of #iframeCrossOriginWithSmallContent");
|
||||
|
||||
promise = waitForScrollEvent();
|
||||
await test_driver.send_keys(document.body, arrowUp);
|
||||
await promise;
|
||||
assert_array_equals([scrollX, scrollY], [0, lineSize], "The body should scroll instead of #iframeCrossOriginWithSmallContent");
|
||||
|
||||
promise = waitForScrollEvent();
|
||||
await test_driver.send_keys(document.body, arrowUp);
|
||||
await promise;
|
||||
assert_array_equals([scrollX, scrollY], [0, 0], "The body should scroll instead of #iframeCrossOriginWithSmallContent");
|
||||
}, "Keyboard scrolling on cross-origin iframe with small content chains to main document");
|
||||
|
||||
promise_test(async () => {
|
||||
await test_driver.click(iframeWithSmallContent);
|
||||
|
||||
await pressKeyAndAssert(arrowDown, iframeWithSmallContent, [0, 0], "Arrow down key should not scroll #iframeWithSmallContent");
|
||||
assert_array_equals([scrollX, scrollY], [0, lineSize], "The body should scroll instead of #iframeWithSmallContent");
|
||||
await pressKeyAndAssert(arrowDown, iframeWithSmallContent, [0, 0], "Arrow down key should not scroll #iframeWithSmallContent");
|
||||
assert_array_equals([scrollX, scrollY], [0, lineSize * 2], "The body should scroll instead of #iframeWithSmallContent");
|
||||
|
||||
await pressKeyAndAssert(arrowUp, iframeWithSmallContent, [0, 0], "Arrow up key should not scroll #iframeWithSmallContent");
|
||||
assert_array_equals([scrollX, scrollY], [0, lineSize], "The body should scroll instead of #iframeWithSmallContent");
|
||||
await pressKeyAndAssert(arrowUp, iframeWithSmallContent, [0, 0], "Arrow up key should not scroll #iframeWithSmallContent");
|
||||
assert_array_equals([scrollX, scrollY], [0, 0], "The body should scroll instead of #iframeWithSmallContent");
|
||||
}, "Keyboard scrolling on iframe with small content chains to main document");
|
||||
|
||||
|
||||
</script>
|
|
@ -1,6 +1,6 @@
|
|||
<!doctype html>
|
||||
<meta charset="utf-8">
|
||||
<title>CSS test: Calc expressions with numbers should still serialize as calc()</title>
|
||||
<title>A test to verify that keyboard scrolling works properly in Servo.</title>
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="/resources/testdriver.js"></script>
|
||||
|
@ -36,15 +36,8 @@
|
|||
<div style="width: 100px; height: 100px; background: blue;">Lorem ipsum dolor sit amet,</div>
|
||||
</div>
|
||||
|
||||
<!-- This is an IFRAME that should be scrollable via keyboard. -->
|
||||
<iframe id="iframe" style="left: 300px; top: 300px;" srcdoc='
|
||||
<!doctype html><meta charset="utf-8">
|
||||
<body style="margin: 0;">
|
||||
<div style="width: 600px; height: 600px; background: blue;">Lorem ipsum dolor sit amet,</div>
|
||||
'></iframe>
|
||||
|
||||
<!-- This is a DIV with `overflow: hidden` that should not be keyboard scrollable as its content is smaller than the DIV. -->
|
||||
<div id="boxWithOverflowHidden" class="scroller" style="overflow: hidden; left: 500px; top: 300px;">
|
||||
<div id="boxWithOverflowHidden" class="scroller" style="overflow: hidden; left: 300px; top: 300px;">
|
||||
<div style="width: 600px; height: 600px; background: blue;">Lorem ipsum dolor sit amet,</div>
|
||||
</div>
|
||||
|
||||
|
@ -66,13 +59,9 @@ const pageSize = scrollportHeight => scrollportHeight - 2 * lineSize;
|
|||
const pressKeyAndAssert = async (key, element, [expectedX, expectedY], description) => {
|
||||
await test_driver.send_keys(document.body, key);
|
||||
const actualX =
|
||||
element == null ? scrollX
|
||||
: element.nodeName == "IFRAME" ? element.contentWindow.scrollX
|
||||
: element.scrollLeft;
|
||||
element == null ? scrollX : element.scrollLeft;
|
||||
const actualY =
|
||||
element == null ? scrollY
|
||||
: element.nodeName == "IFRAME" ? element.contentWindow.scrollY
|
||||
: element.scrollTop;
|
||||
element == null ? scrollY : element.scrollTop;
|
||||
assert_array_equals([actualX, actualY], [expectedX, expectedY], description);
|
||||
};
|
||||
|
||||
|
@ -156,27 +145,6 @@ promise_test(async () => {
|
|||
await pressKeyAndAssert(home, null, [0, 0], "Home key scrolls viewport to top");
|
||||
}, "Keyboard scrolling chains past inactive overflow:scroll DIVs");
|
||||
|
||||
promise_test(async () => {
|
||||
await test_driver.click(iframe);
|
||||
|
||||
await pressKeyAndAssert(end, iframe, [0, iframe.contentDocument.documentElement.scrollHeight - iframe.contentWindow.innerHeight], "End key scrolls #iframe to bottom");
|
||||
await pressKeyAndAssert(home, iframe, [0, 0], "Home key scrolls #iframe to top");
|
||||
await pressKeyAndAssert(arrowDown, iframe, [0, lineSize], "ArrowDown key scrolls #iframe down by a line");
|
||||
await pressKeyAndAssert(arrowDown, iframe, [0, lineSize * 2], "ArrowDown key scrolls #iframe down by a line");
|
||||
await pressKeyAndAssert(arrowUp, iframe, [0, lineSize], "ArrowUp key scrolls #iframe up by a line");
|
||||
await pressKeyAndAssert(arrowUp, iframe, [0, 0], "ArrowUp key scrolls #iframe up by a line");
|
||||
await pressKeyAndAssert(arrowRight, iframe, [lineSize, 0], "ArrowRight key scrolls #iframe right by a line");
|
||||
await pressKeyAndAssert(arrowRight, iframe, [lineSize * 2, 0], "ArrowRight key scrolls #iframe right by a line");
|
||||
await pressKeyAndAssert(arrowLeft, iframe, [lineSize, 0], "ArrowLeft key scrolls #iframe left by a line");
|
||||
await pressKeyAndAssert(arrowLeft, iframe, [0, 0], "ArrowLeft key scrolls #iframe left by a line");
|
||||
await pressKeyAndAssert(pageDown, iframe, [0, pageSize(iframe.contentWindow.innerHeight)], "PageDown key scrolls #iframe down by almost a screenful");
|
||||
await pressKeyAndAssert(pageDown, iframe, [0, pageSize(iframe.contentWindow.innerHeight) * 2], "PageDown key scrolls #iframe down by almost a screenful");
|
||||
await pressKeyAndAssert(pageUp, iframe, [0, pageSize(iframe.contentWindow.innerHeight)], "PageUp key scrolls #iframe up by almost a screenful");
|
||||
await pressKeyAndAssert(pageUp, iframe, [0, 0], "PageUp key scrolls #iframe up by almost a screenful");
|
||||
|
||||
// TODO: test that scrolls chain up from iframe when they fail.
|
||||
}, "Keyboard scrolling works in #iframe");
|
||||
|
||||
promise_test(async () => {
|
||||
await test_driver.click(boxWithOverflowHidden);
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue