// Scroll the mouse wheel over |element|.
async function scrollWheelOver(element) {
await promiseMoveMouseAndScrollWheelOver(element, 10, 10, /* waitForScroll = */ false);
}
const DISPLAYPORT_EXPIRY = 100;
let config = getHitTestConfig();
let activateAllScrollFrames = config.activateAllScrollFrames;
let heightMultiplier = SpecialPowers.getCharPref("apz.y_stationary_size_multiplier");
// The effective height multiplier can be reduced for alignment reasons.
// The reduction should be no more than a factor of two.
heightMultiplier /= 2;
info("effective displayport height multipler is " + heightMultiplier);
function checkDirectActivation(elementId, containingDoc = null) {
if (activateAllScrollFrames) {
return hasNonZeroMarginDisplayPort(elementId, containingDoc);
}
return isLayerized(elementId);
}
function checkAncestorActivation(elementId, containingDoc = null) {
if (activateAllScrollFrames) {
return hasMinimalDisplayPort(elementId, containingDoc);
}
return isLayerized(elementId);
}
function checkInactive(elementId, containingDoc = null) {
if (activateAllScrollFrames) {
return hasMinimalDisplayPort(elementId, containingDoc);
}
return !isLayerized(elementId);
}
async function test() {
await SpecialPowers.pushPrefEnv({ "set": [
// Causes the test to intermittently fail on ASAN opt linux.
["mousewheel.system_scroll_override.enabled", false],
]
});
let outer3Doc = document.getElementById("outer3").contentDocument;
let outer4Doc = document.getElementById("outer4").contentDocument;
// Initially, everything should be inactive.
ok(checkInactive("outer1"), "initially 'outer1' should not be active");
ok(checkInactive("inner1"), "initially 'inner1' should not be active");
ok(checkInactive("outer2"), "initially 'outer2' should not be active");
ok(checkInactive("inner2"), "initially 'inner2' should not be active");
ok(checkInactive("outer3"), "initially 'outer3' should not be active");
ok(checkInactive("inner3", outer3Doc), "initially 'inner3' should not be active");
ok(checkInactive("outer4"), "initially 'outer4' should not be active");
ok(checkInactive("inner4", outer4Doc), "initially 'inner4' should not be active");
// Scrolling over outer1 should activate outer1 directly, but not inner1.
await scrollWheelOver(document.getElementById("outer1"));
await promiseAllPaintsDone();
await promiseOnlyApzControllerFlushed();
ok(checkDirectActivation("outer1"), "scrolling 'outer1' should activate it directly");
ok(checkInactive("inner1"), "scrolling 'outer1' should not cause 'inner1' to get activated");
// Scrolling over inner2 should activate inner2 directly, but outer2 only ancestrally.
await scrollWheelOver(document.getElementById("inner2"));
await promiseAllPaintsDone();
await promiseOnlyApzControllerFlushed();
ok(checkDirectActivation("inner2"), "scrolling 'inner2' should cause it to be directly activated");
ok(checkAncestorActivation("outer2"), "scrolling 'inner2' should cause 'outer2' to be activated as an ancestor");
// The second half of the test repeats the same checks as the first half,
// but with an iframe as the outer scrollable frame.
// Scrolling over outer3 should activate outer3 directly, but not inner3.
await scrollWheelOver(outer3Doc.documentElement);
await promiseAllPaintsDone();
await promiseOnlyApzControllerFlushed();
ok(checkDirectActivation("outer3"), "scrolling 'outer3' should cause it to be directly activated");
ok(checkInactive("inner3", outer3Doc), "scrolling 'outer3' should not cause 'inner3' to be activated");
// Scrolling over inner4 should activate inner4 directly, but outer4 only ancestrally.
await scrollWheelOver(outer4Doc.getElementById("inner4"));
await promiseAllPaintsDone();
await promiseOnlyApzControllerFlushed();
ok(checkDirectActivation("inner4", outer4Doc), "scrolling 'inner4' should cause it to be directly activated");
ok(checkAncestorActivation("outer4"), "scrolling 'inner4' should cause 'outer4' to be activated");
// Now we enable displayport expiry, and verify that things are still
// activated as they were before.
await SpecialPowers.pushPrefEnv({"set": [["apz.displayport_expiry_ms", DISPLAYPORT_EXPIRY]]});
ok(checkDirectActivation("outer1"), "outer1 still has non zero display port after enabling expiry");
ok(checkInactive("inner1"), "inner1 is still has zero margin display port after enabling expiry");
ok(checkAncestorActivation("outer2"), "outer2 still has zero margin display port after enabling expiry");
ok(checkDirectActivation("inner2"), "inner2 still has non zero display port after enabling expiry");
ok(checkDirectActivation("outer3"), "outer3 still has non zero display port after enabling expiry");
ok(checkInactive("inner3", outer3Doc), "inner3 still has zero margin display port after enabling expiry");
ok(checkDirectActivation("inner4", outer4Doc), "inner4 still has non zero display port after enabling expiry");
ok(checkAncestorActivation("outer4"), "outer4 still has zero margin display port after enabling expiry");
// Now we trigger a scroll on some of the things still layerized, so that
// the displayport expiry gets triggered.
// Expire displayport with scrolling on outer1
await scrollWheelOver(document.getElementById("outer1"));
await promiseAllPaintsDone();
await promiseOnlyApzControllerFlushed();
await SpecialPowers.promiseTimeout(DISPLAYPORT_EXPIRY);
await promiseAllPaintsDone();
ok(checkInactive("outer1"), "outer1 is inactive after displayport expiry");
ok(checkInactive("inner1"), "inner1 is inactive after displayport expiry");
// Expire displayport with scrolling on inner2
await scrollWheelOver(document.getElementById("inner2"));
await promiseAllPaintsDone();
await promiseOnlyApzControllerFlushed();
// Once the expiry elapses, it will trigger expiry on outer2, so we check
// both, one at a time.
await SpecialPowers.promiseTimeout(DISPLAYPORT_EXPIRY);
await promiseAllPaintsDone();
ok(checkInactive("inner2"), "inner2 is inactive after displayport expiry");
await SpecialPowers.promiseTimeout(DISPLAYPORT_EXPIRY);
await promiseAllPaintsDone();
ok(checkInactive("outer2"), "outer2 is inactive with inner2");
// We need to wrap the next bit in a loop and keep retrying until it
// succeeds. Let me explain why this is the best option at this time. Below
// we scroll over inner3, this triggers a 100 ms timer to expire it's display
// port. Then when it expires it schedules a paint and triggers another
// 100 ms timer on it's parent, outer3, to expire. The paint needs to happen
// before the timer fires because the paint is what updates
// mIsParentToActiveScrollFrames on outer3, and mIsParentToActiveScrollFrames
// being true blocks a display port from expiring. It was true because it
// contained inner3, but no longer. In real life the timer is 15000 ms so a
// paint will happen, but here in a test the timer is 100 ms so that paint
// can not happen in time. We could add some more complication to this code
// just for this test, or we could just loop here.
let itWorked = false;
while (!itWorked) {
// Scroll on inner3. inner3 isn't layerized, and this will cause it to
// get layerized, but it will also trigger displayport expiration for inner3
// which will eventually trigger displayport expiration on inner3 and outer3.
// Note that the displayport expiration might actually happen before the wheel
// input is processed in the compositor (see bug 1246480 comment 3), and so
// we make sure not to wait for a scroll event here, since it may never fire.
// However, if we do get a scroll event while waiting for the expiry, we need
// to restart the expiry timer because the displayport expiry got reset. There's
// no good way that I can think of to deterministically avoid doing this.
let inner3 = outer3Doc.getElementById("inner3");
await scrollWheelOver(inner3);
await promiseAllPaintsDone();
await promiseOnlyApzControllerFlushed();
let timerPromise = new Promise(resolve => { var timeoutTarget = function() {
inner3.removeEventListener("scroll", timeoutResetter);
resolve();
}; var timerId = setTimeout(timeoutTarget, DISPLAYPORT_EXPIRY); var timeoutResetter = function() {
ok(true, "Got a scroll event; resetting timer...");
clearTimeout(timerId);
setTimeout(timeoutTarget, DISPLAYPORT_EXPIRY);
// by not updating timerId we ensure that this listener resets the timeout
// at most once.
};
inner3.addEventListener("scroll", timeoutResetter);
});
await timerPromise; // wait for the setTimeout to elapse
await promiseAllPaintsDone();
ok(checkInactive("inner3", outer3Doc), "inner3 is inactive after expiry");
await SpecialPowers.promiseTimeout(DISPLAYPORT_EXPIRY);
await promiseAllPaintsDone();
if (checkInactive("outer3")) {
ok(true, "outer3 is inactive after inner3 triggered expiry");
itWorked = true;
}
}
// Scroll outer4 and wait for the expiry. It should NOT get expired because
// inner4 is still layerized
await scrollWheelOver(outer4Doc.documentElement);
await promiseAllPaintsDone();
await promiseOnlyApzControllerFlushed();
// Wait for the expiry to elapse
await SpecialPowers.promiseTimeout(DISPLAYPORT_EXPIRY);
await promiseAllPaintsDone();
ok(checkDirectActivation("inner4", outer4Doc), "inner4 still is directly activated because it never expired");
ok(checkDirectActivation("outer4"), "outer4 still still is directly activated because inner4 is still layerized");
}
if (isApzEnabled()) {
SimpleTest.waitForExplicitFinish();
SimpleTest.requestFlakyTimeout("we are testing code that measures an actual timeout");
SimpleTest.expectAssertions(0, 8); // we get a bunch of "ASSERTION: Bounds computation mismatch" sometimes (bug 1232856)
// Disable smooth scrolling, because it results in long-running scroll
// animations that can result in a 'scroll' event triggered by an earlier
// wheel event as corresponding to a later wheel event.
// Also enable APZ test logging, since we use that data to determine whether
// a scroll frame was layerized.
pushPrefs([["general.smoothScroll", false],
["apz.displayport_expiry_ms", 0],
["apz.test.logging_enabled", true]])
.then(waitUntilApzStable)
.then(test)
.then(SimpleTest.finish, SimpleTest.finishWithFailure);
}
</script>
</pre>
</body>
</html>
Messung V0.5
¤ Dauer der Verarbeitung: 0.0 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.