Source code
Revision control
Copy as Markdown
Other Tools
<!DOCTYPE html>
<html>
<meta charset="utf-8">
<script src="/tests/SimpleTest/EventUtils.js"></script>
<script src="/tests/SimpleTest/NativeKeyCodes.js"></script>
<script src="/tests/SimpleTest/paint_listener.js"></script>
<script src="apz_test_utils.js"></script>
<script src="apz_test_native_event_utils.js"></script>
<title>What happens if main thread scrolls?</title>
<style>
html, body { margin: 0; }
html {
background:
repeating-linear-gradient(45deg, transparent 0, transparent 100px, rgba(0,0,0,0.1) 0, rgba(0,0,0,0.1) 200px),
repeating-linear-gradient(-45deg, transparent 0, transparent 100px, rgba(0,0,0,0.1) 0, rgba(0,0,0,0.1) 200px),
repeating-linear-gradient(to bottom, transparent 0, transparent 500px, rgba(0,0,0,0.4) 0, rgba(0,0,0,0.4) 1000px),
repeating-linear-gradient(to bottom, hsl(0, 60%, 80%), hsl(0, 60%, 80%) 200px, hsl(70, 60%, 80%) 0, hsl(70, 60%, 80%) 400px, hsl(140, 60%, 80%) 0, hsl(140, 60%, 80%) 600px, hsl(210, 60%, 80%) 0, hsl(210, 60%, 80%) 800px),
white;
background-size:
283px 283px,
283px 283px,
100px 1000px,
100px 800px;
}
body {
height: 10000px;
}
</style>
<script>
const searchParams = new URLSearchParams(location.search);
let strict = searchParams.get("strict") == "true";
var intervalId;
// Start periodic content expansions after we get a scroll event triggered by
// a key press in test() function below, otherwise we may have same scroll
// offsets caused by this script before we start scrolling.
window.addEventListener("scroll", () => {
var offset = 0;
var initialBodyHeight = 10000;
intervalId = setInterval(() => {
// "Add content" at the top. We do this by making the body longer and adjusting the background position.
offset += 10;
document.documentElement.style.backgroundPosition = `0px ${offset}px`;
document.body.style.height = `${initialBodyHeight + offset}px`;
switch (searchParams.get("scroll-method")) {
case "scrollBy":
window.scrollBy(0, 10);
break;
case "scrollTop":
document.scrollingElement.scrollTop += 10;
break;
case "scrollTo":
window.scrollTo(0, window.scrollY + 10);
break;
default:
ok(false, "Unsupported scroll method: " + searchParams.get("scroll-method"));
break;
}
// Simulate some jank.
var freezeDurationInMilliseconds = 100;
var startTime = Date.now();
while (Date.now() - startTime < freezeDurationInMilliseconds) {} // eslint-disable-line no-empty
}, 300);
}, { once: true });
async function test() {
// Once this content starts scrolling, it triggers a 100ms jank every 300ms so
// sending arrow down keys for 1500ms will cause some jank.
const TEST_DURATION_MS = 1500;
const timeAtStart = performance.now();
while (performance.now() - timeAtStart < TEST_DURATION_MS) {
switch (searchParams.get("input-type")) {
case "key":
synthesizeKey("KEY_ArrowDown");
break;
case "native-key":
const DownArrowKeyCode = nativeArrowDownKey();
ok(synthesizeNativeKey(KEYBOARD_LAYOUT_EN_US,
DownArrowKeyCode, {} /* no modifier */,
"", ""),
"Dispatched an down arrow key event");
break;
case "wheel":
await synthesizeNativeWheel(window, 50, 50, 0, -50);
break;
default:
ok(false, "Unsupported input type: " + searchParams.get("input-type"));
break;
}
await promiseFrame(window);
}
// Stop the periodic expansions.
clearInterval(intervalId);
const records = collectSampledScrollOffsets(document.scrollingElement);
let previousRecord = { scrollOffsetY: 0, sampledTimeStamp: 0 };
let scrollStartTime = null;
for (const record of records) {
// Ignore offsets before scrolling.
if (record.scrollOffsetY == 0) {
continue;
}
// Ignore offsets after TEST_DURATION_MS has elapsed since the
// start of scrolling. Note that the sampled timestamps are
// in microseconds.
if (!scrollStartTime) {
scrollStartTime = record.sampledTimeStamp;
} else if (((record.sampledTimeStamp - scrollStartTime) / 1000) > TEST_DURATION_MS) {
break;
}
ok(
strict
? (record.scrollOffsetY > previousRecord.scrollOffsetY)
: (record.scrollOffsetY >= previousRecord.scrollOffsetY),
"scroll offset should be " +
(strict ? "strictly monotonically increasing " : "nondecreasing ") +
"previous offset: " + previousRecord.scrollOffsetY +
", offset: " + record.scrollOffsetY
);
ok(
record.sampledTimeStamp > previousRecord.sampledTimeStamp,
"sampled time stamp should be strictly monotonically increasing " +
"previous timestamp: " + previousRecord.sampledTimeStamp +
", timestamp: " + record.sampledTimeStamp
);
previousRecord = record;
}
}
function isOnChaosMode() {
return SpecialPowers.Services.env.get("MOZ_CHAOSMODE");
}
function startTest() {
if (searchParams.get("input-type") == "native-key") {
if (getPlatform() != "mac" && getPlatform() != "windows") {
ok(true, "Skipping test because native key events are not supported on " +
getPlatform());
subtestDone();
return;
} else if (getPlatform() == "mac" && isOnChaosMode()) {
ok(true, "Skipping native-key tests on verify runs on Mac");
subtestDone();
return;
} else if (getPlatform() == "windows") {
ok(true, "Skipping native-key tests on Windows due to intermittent failures");
subtestDone();
return;
}
}
waitUntilApzStable()
.then(test)
.then(subtestDone, subtestFailed);
}
startTest();
</script>