зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1617427 - Add a test for the scenario being fixed. r=botond
Differential Revision: https://phabricator.services.mozilla.com/D66428 --HG-- extra : moz-landing-system : lando
This commit is contained in:
Родитель
c4913fea1d
Коммит
67bc5d7367
|
@ -198,6 +198,30 @@ function isLayerized(elementId) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Return a rect (or null) that holds the last known content-side displayport
|
||||||
|
// for a given element. (The element selection works the same way, and with
|
||||||
|
// the same assumptions as the isLayerized function above).
|
||||||
|
function getLastContentDisplayportFor(elementId) {
|
||||||
|
var contentTestData = SpecialPowers.getDOMWindowUtils(
|
||||||
|
window
|
||||||
|
).getContentAPZTestData();
|
||||||
|
var nonEmptyBucket = getLastNonemptyBucket(contentTestData.paints);
|
||||||
|
ok(nonEmptyBucket != null, "expected at least one nonempty paint");
|
||||||
|
var seqno = nonEmptyBucket.sequenceNumber;
|
||||||
|
contentTestData = convertTestData(contentTestData);
|
||||||
|
var paint = contentTestData.paints[seqno];
|
||||||
|
for (var scrollId in paint) {
|
||||||
|
if ("contentDescription" in paint[scrollId]) {
|
||||||
|
if (paint[scrollId].contentDescription.includes(elementId)) {
|
||||||
|
if ("displayport" in paint[scrollId]) {
|
||||||
|
return parseRect(paint[scrollId].displayport);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
// Return a promise that is resolved on the next rAF callback
|
// Return a promise that is resolved on the next rAF callback
|
||||||
function waitForFrame() {
|
function waitForFrame() {
|
||||||
return new Promise(resolve => {
|
return new Promise(resolve => {
|
||||||
|
|
|
@ -0,0 +1,104 @@
|
||||||
|
<!DOCTYPE HTML>
|
||||||
|
<html id="root-element">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width; initial-scale=1.0">
|
||||||
|
<title>Checkerboarding while root scrollframe async-scrolls and a
|
||||||
|
subframe has APZ force disabled</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>
|
||||||
|
<script type="application/javascript">
|
||||||
|
|
||||||
|
function* test(testDriver) {
|
||||||
|
var utils = SpecialPowers.getDOMWindowUtils(window);
|
||||||
|
var subframe = document.getElementById('subframe');
|
||||||
|
|
||||||
|
// layerize subframe
|
||||||
|
yield synthesizeNativeClick(subframe, 10, 10, testDriver);
|
||||||
|
|
||||||
|
// verify layerization
|
||||||
|
yield waitForAllPaints(() => setTimeout(testDriver, 0));
|
||||||
|
ok(isLayerized("subframe"), "subframe should be layerized at this point");
|
||||||
|
var subframeScrollId = utils.getViewId(subframe);
|
||||||
|
ok(subframeScrollId > 0, "subframe should have a scroll id");
|
||||||
|
|
||||||
|
// then disable APZ for it
|
||||||
|
utils.disableApzForElement(subframe);
|
||||||
|
|
||||||
|
// wait for the dust to settle
|
||||||
|
yield waitForAllPaints(() => setTimeout(testDriver, 0));
|
||||||
|
|
||||||
|
// Check that the root element's displayport has at least 500px of vertical
|
||||||
|
// displayport margin on either side. This will ensure that we can scroll
|
||||||
|
// by 500px without causing the displayport to move, which in turn means that
|
||||||
|
// the scroll will not trigger repaints (due to paint-skipping).
|
||||||
|
var rootElem = document.documentElement;
|
||||||
|
var rootDisplayport = getLastContentDisplayportFor(rootElem.id);
|
||||||
|
ok(rootDisplayport != null, "root element should have a displayport");
|
||||||
|
dump("root dp: " + JSON.stringify(rootDisplayport) +
|
||||||
|
", height: " + rootElem.clientHeight);
|
||||||
|
var rootDpVerticalMargin = (rootDisplayport.h - rootElem.clientHeight) / 2;
|
||||||
|
ok(rootDpVerticalMargin > 500,
|
||||||
|
"root element should have at least 500px of vertical displayport margin");
|
||||||
|
|
||||||
|
// Scroll enough that we reveal new parts of the subframe, but not so much
|
||||||
|
// that the root displayport starts moving. If the root displayport moves,
|
||||||
|
// the main-thread will trigger a repaint of the subframe, but if the root
|
||||||
|
// displayport doesn't move, we get a paint-skipped scroll which is where the
|
||||||
|
// bug manifests. (The bug being that the subframe ends in a visual perma-
|
||||||
|
// checkerboarding state). Note that we do an 'auto' behavior scroll so
|
||||||
|
// that it's "instant" rather than an animation. Animations would demonstrate
|
||||||
|
// the bug too but are more complicated to wait for.
|
||||||
|
window.scrollBy({top: 500, left: 0, behavior: 'auto'});
|
||||||
|
is(window.scrollY, 500, "document got scrolled instantly");
|
||||||
|
|
||||||
|
// Note that at this point we must NOT call flushApzRepaints, because
|
||||||
|
// otherwise APZCCallbackHelper::NotifyFlushComplete will trigger a repaint
|
||||||
|
// (for unrelated reasons), and the repaint will clear the checkerboard
|
||||||
|
// state. We do, however, want to wait for a "steady state" here that
|
||||||
|
// includes all pending paints from the main thread and a composite that
|
||||||
|
// samples the APZ state. (The latter is not required if the APZ frame delay
|
||||||
|
// is disabled, but it's enabled by default so it's desirable to handle that
|
||||||
|
// situation as well.) In order to accomplish this we wait for all the main
|
||||||
|
// thread paints, and then force a composite via advanceTimeAndRefresh. The
|
||||||
|
// advanceTimeAndRefresh has the additional advantage of freezing the refresh
|
||||||
|
// driver which avoids any additional externally-triggered repaints from
|
||||||
|
// erasing the symptoms of the bug.
|
||||||
|
yield waitForAllPaints(() => setTimeout(testDriver, 0));
|
||||||
|
utils.advanceTimeAndRefresh(0);
|
||||||
|
|
||||||
|
var data = utils.getCompositorAPZTestData();
|
||||||
|
//dump(JSON.stringify(data, null, 4));
|
||||||
|
|
||||||
|
var found = false;
|
||||||
|
for (apzcData of data.additionalData) {
|
||||||
|
if (apzcData.key == subframeScrollId) {
|
||||||
|
var checkerboarding = apzcData.value.split(',').includes("checkerboarding");
|
||||||
|
ok(!checkerboarding, "subframe is not checkerboarding");
|
||||||
|
found = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ok(found, "Found the checkerboarding subframe");
|
||||||
|
|
||||||
|
utils.restoreNormalRefresh();
|
||||||
|
subtestDone();
|
||||||
|
}
|
||||||
|
|
||||||
|
waitUntilApzStable().then(runContinuation(test));
|
||||||
|
|
||||||
|
</script>
|
||||||
|
<style>
|
||||||
|
#subframe {
|
||||||
|
overflow-x: auto;
|
||||||
|
margin-left: 100px; /* makes APZ minimap easier to see */
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="subframe">
|
||||||
|
<div style="width: 10000px; height: 10000px; background-image: linear-gradient(green, red)">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -68,3 +68,4 @@
|
||||||
[test_group_zoomToFocusedInput.html]
|
[test_group_zoomToFocusedInput.html]
|
||||||
[test_group_scroll_snap.html]
|
[test_group_scroll_snap.html]
|
||||||
skip-if = (os == 'android') # wheel events not supported on mobile
|
skip-if = (os == 'android') # wheel events not supported on mobile
|
||||||
|
[test_group_checkerboarding.html]
|
||||||
|
|
|
@ -0,0 +1,34 @@
|
||||||
|
<!DOCTYPE HTML>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<script src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||||
|
<script type="application/javascript" src="apz_test_utils.js"></script>
|
||||||
|
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||||
|
<script type="application/javascript">
|
||||||
|
if (isApzEnabled()) {
|
||||||
|
SimpleTest.waitForExplicitFinish();
|
||||||
|
|
||||||
|
var prefs = [
|
||||||
|
["apz.test.logging_enabled", true],
|
||||||
|
["apz.paint_skipping.enabled", true],
|
||||||
|
["apz.displayport_expiry_ms", 0],
|
||||||
|
["general.smoothScroll", false],
|
||||||
|
["apz.minimap.enabled", true], // helps to debug these tests
|
||||||
|
];
|
||||||
|
const subtests = [
|
||||||
|
{ file: "helper_checkerboard_apzforcedisabled.html", prefs },
|
||||||
|
];
|
||||||
|
// Run the actual test in its own window, because it requires that the
|
||||||
|
// root APZC be scrollable. Mochitest pages themselves often run
|
||||||
|
// inside an iframe which means we have no control over the root APZC.
|
||||||
|
window.onload = () => {
|
||||||
|
runSubtestsSeriallyInFreshWindows(subtests)
|
||||||
|
.then(SimpleTest.finish, SimpleTest.finish);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
</body>
|
||||||
|
</html>
|
Загрузка…
Ссылка в новой задаче