Source code
Revision control
Copy as Markdown
Other Tools
Test Info: Warnings
- This test gets skipped with pattern: verify || (os == 'win' && debug)
- Manifest: dom/canvas/test/mochitest.toml
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>Check for contextlost/restored events after GPU process restart</title>
<script src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" href="/tests/SimpleTest/test.css">
</head>
<body>
<canvas id="c" width="512" height="512"></canvas>
<script type="application/javascript">
function waitRAF() {
return new Promise((resolve, reject) => {
window.requestAnimationFrame(resolve);
});
}
async function restartGPUProcess() {
return await SpecialPowers.spawnChrome([], async () => {
const gfxInfo = Cc["@mozilla.org/gfx/info;1"].getService(Ci.nsIGfxInfo);
if (gfxInfo.usingGPUProcess) {
const { TestUtils } = ChromeUtils.importESModule(
);
let promise = TestUtils.topicObserved("compositor-reinitialized");
const remoteCanvas = gfxInfo.usingRemoteCanvas;
const acceleratedCanvas = gfxInfo.usingAcceleratedCanvas;
ok(true, "Restarting GPU process, remote canvas " + remoteCanvas + ", accelerated canvas " + acceleratedCanvas);
gfxInfo.killGPUProcessForTests();
await promise;
return remoteCanvas || acceleratedCanvas;
}
ok(true, "Not using GPU process");
return false;
});
}
const canvas = document.getElementById("c");
const context = canvas.getContext("2d");
let restoredPromiseResolve;
let restoredPromiseReject;
const restoredPromise = new Promise((resolve, reject) => {
restoredPromiseResolve = resolve;
restoredPromiseReject = reject;
});
let countLostEvents = 0;
let countRestoredEvents = 0;
function onContextLost() {
ok(context.isContextLost(), "Canvas context should be lost during contextlost event");
try {
let transform = context.getTransform();
ok(transform.isIdentity, "Canvas context should return identity transform while context lost");
} catch (e) {}
countLostEvents += 1;
}
function onContextRestored() {
ok(!context.isContextLost(), "Canvas context should not be lost during contextrestored event");
countRestoredEvents += 1;
restoredPromiseResolve(true);
}
function waitContextRestored() {
let timeoutId = window.setTimeout(restoredPromiseReject, 5000);
return restoredPromise.then(() => {
window.clearTimeout(timeoutId);
});
}
async function start() {
try {
canvas.addEventListener("contextlost", onContextLost);
canvas.addEventListener("contextrestored", onContextRestored);
ok(!context.isContextLost(), "Canvas context should not be lost before initial fill");
context.fillStyle = 'red';
context.fill();
await waitRAF();
ok(!context.isContextLost(), "Canvas context should not be lost after initial fill");
let transform = context.getTransform();
ok(transform.isIdentity, "Canvas context should default to identity transform");
context.setTransform(2.0, 3.0, 4.0, 5.0, 6.0, 7.0);
transform = context.getTransform();
ok(!transform.isIdentity, "Canvas context should have non-identity transform");
const restarted = await restartGPUProcess();
const expectedEvents = restarted ? 1 : 0;
if (expectedEvents) {
await waitContextRestored();
}
await waitRAF();
is(countLostEvents, expectedEvents, "Should have fired " + expectedEvents + " contextlost events");
is(countRestoredEvents, expectedEvents, "Should have fired " + expectedEvents + " contextrestored events");
ok(!context.isContextLost(), "Canvas context should not be lost after restoration");
context.fillStyle = 'green';
context.fill();
await waitRAF();
ok(!context.isContextLost(), "Canvas context should not be lost at completion");
} catch (err) {
ok(false, "Caught exception " + err);
} finally {
SimpleTest.finish();
}
}
SimpleTest.waitForExplicitFinish();
SimpleTest.requestFlakyTimeout("Wait for failure condition");
start();
</script>
</body>
</html>