Source code
Revision control
Copy as Markdown
Other Tools
<!DOCTYPE HTML>
<html>
<head>
<title>Test doing lots of hit-testing on a rapidly changing page</title>
<script type="application/javascript" src="apz_test_utils.js"></script>
<script type="application/javascript" src="apz_test_native_event_utils.js"></script>
<script src="/tests/SimpleTest/paint_listener.js"></script>
<meta name="viewport" content="width=device-width"/>
</head>
<style>
#spamdiv {
overflow: scroll;
width: 400px;
height: 400px;
}
#spamdiv div {
width: 1000px;
height: 1000px;
}
</style>
<body>
<script type="application/javascript">
var SPAM_LIMIT = 200; // bigger numbers make the test run longer
// This function adds and removes a scrollable div very rapidly (via
// setTimeout(0) self-scheduling). This causes very frequent layer
// transactions with a new APZ hit-testing tree from the main thread to APZ.
// The div is created afresh every time so that the scroll identifier in
// Gecko is continually increasing, and hit results from a stale tree will
// not be valid on the new tree.
var spamCount = 0;
var spamPoint = null;
function divSpammer() {
spamCount++;
if (spamCount >= SPAM_LIMIT) {
return;
}
setTimeout(divSpammer, 0);
// Remove the div if it exists...
var spamdiv = document.getElementById('spamdiv');
if (spamdiv) {
spamdiv.remove();
return;
}
// ... and add it if it doesn't exist.
spamdiv = document.createElement('div');
spamdiv.id = 'spamdiv';
spamdiv.appendChild(document.createElement('div'));
document.body.appendChild(spamdiv);
if (spamPoint == null) {
spamPoint = centerOf(spamdiv);
}
}
// This function does continuous hit-testing by scheduling itself over and
// over with setTimeout(0). It hit-tests the same spot and expects to hit
// either the root scrollframe (if the spamdiv is not present in that
// instant) or the spamdiv (if it is present). If the spamdiv is hit, it
// expects the scrollid to be non-decreasing.
var rootScrollId = null;
var lastScrollId = -1;
function hitTestSpammer() {
if (spamCount >= SPAM_LIMIT) {
subtestDone();
return;
}
setTimeout(hitTestSpammer, 0);
if (spamPoint == null) {
// The very first invocation of this function will have spamPoint as null,
// and we use that to pick up the rootScrollId.
ok(rootScrollId == null, "This codepath shouldn't get hit twice");
rootScrollId = hitTest(centerOf(document.body)).scrollId;
ok(true, "Root scroll id detected as " + rootScrollId);
return;
}
var scrollId = hitTest(spamPoint).scrollId;
if (scrollId == rootScrollId) {
ok(true, "Hit test hit the root scroller, spamdiv is not in compositor");
} else {
is(scrollId >= lastScrollId, true, "spamdiv's scroll id is now " + scrollId);
lastScrollId = scrollId;
}
}
function startTest() {
// Make sure to run hitTestSpammer first so the first iteration is while
// spamPoint is still null.
setTimeout(hitTestSpammer, 0);
setTimeout(divSpammer, 0);
}
waitUntilApzStable().then(startTest);
</script>
</body>
</html>