Source code

Revision control

Copy as Markdown

Other Tools

Test Info:

<!DOCTYPE HTML>
<html>
<head>
<title>Test that img.decode works on finished, discarded animated images</title>
<script src="/tests/SimpleTest/SimpleTest.js"></script>
<script src="/tests/SimpleTest/WindowSnapshot.js"></script>
<script type="text/javascript" src="imgutils.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<div id="container">
<img id="finitepng" src="finite-apng.png">
</div>
<script class="testbody" type="text/javascript">
SimpleTest.waitForExplicitFinish();
window.onload = runTest;
let discardCallback = undefined;
let frameUpdateCallback = undefined;
async function runTest() {
const kUsingWebRender = SpecialPowers.DOMWindowUtils.layerManagerType.startsWith("WebRender");
let img = document.getElementById("finitepng");
await img.decode();
while (!isItGreen(img)) {
// We hit an optimized path in WebRender that doesn't cause a repaint on the
// main thread and doesn't seem to send MozAfterPaints.
//
await new Promise(resolve => {
if (kUsingWebRender) {
requestAnimationFrame(() => {
requestAnimationFrame(resolve);
});
} else {
window.addEventListener("MozAfterPaint", resolve, { once: true });
}
});
}
addCallbacks(img);
let iterationsLeft = 26;
while (iterationsLeft > 0) {
let discardPromise = new Promise(resolve => {
discardCallback = resolve;
});
document.getElementById("container").style.display = "none";
document.documentElement.offsetLeft; // force that style to take effect
requestDiscard(img);
await new Promise(resolve => {requestAnimationFrame(() => { requestAnimationFrame(resolve); }); });
await discardPromise;
await new Promise(resolve => {requestAnimationFrame(() => { requestAnimationFrame(resolve); }); });
let waitForFrameUpdate = new Promise(resolve => {
frameUpdateCallback = resolve;
});
document.getElementById("container").style.display = "";
document.documentElement.offsetLeft; // force that style to take effect
await img.decode();
await new Promise(resolve => requestAnimationFrame(resolve));
await waitForFrameUpdate;
ok(isItGreen(img), "should be green");
iterationsLeft--;
await new Promise(resolve => {requestAnimationFrame(() => { requestAnimationFrame(resolve); }); });
}
removeObserver(img);
SimpleTest.finish();
}
function isItGreen(img) {
let rect = img.getBoundingClientRect();
let r = {left: rect.left + 5, top: rect.top + 5, width: 5, height: 5};
let c = SpecialPowers.snapshotWindowWithOptions(window, r);
let d = c.getContext('2d').getImageData(0,0,5,5).data;
let isGreen = true;
for (let i = 0; i < 5*5; i++) {
if (d[4*i] != 0 || d[4*i + 1] != 128 || d[4*i + 2] != 0 || d[4*i + 3] != 255) {
isGreen = false;
}
}
return isGreen;
}
let scriptedObserver = undefined;
let imgLoadingContent = undefined;
function addCallbacks(anImage) {
var observer = new ImageDecoderObserverStub();
observer.discard = function () {
if (discardCallback != undefined) {
let localDiscardCallback = discardCallback;
discardCallback = undefined;
setTimeout(localDiscardCallback, 0);
}
};
observer.frameUpdate = function () {
if (frameUpdateCallback != undefined) {
let localFrameUpdateCallback = frameUpdateCallback;
frameUpdateCallback = undefined;
setTimeout(localFrameUpdateCallback, 0);
}
};
observer = SpecialPowers.wrapCallbackObject(observer);
scriptedObserver = SpecialPowers.Cc["@mozilla.org/image/tools;1"]
.getService(SpecialPowers.Ci.imgITools)
.createScriptedObserver(observer);
imgLoadingContent = SpecialPowers.wrap(anImage);
imgLoadingContent.addObserver(scriptedObserver);
}
function removeObserver() {
imgLoadingContent.removeObserver(scriptedObserver);
}
function requestDiscard(anImage) {
var request = SpecialPowers.wrap(anImage)
.getRequest(SpecialPowers.Ci.nsIImageLoadingContent.CURRENT_REQUEST);
setTimeout(() => request.requestDiscard(), 0);
}
</script>
</body>
</html>