Bug 1629490. Add a crashtest and a mochitest. r=aosmond

The mochitest caught the issue of the second patch here so there is value in both it seems.

Differential Revision: https://phabricator.services.mozilla.com/D71484
This commit is contained in:
Timothy Nikkel 2020-04-20 03:38:57 +00:00
Родитель 008ffcf520
Коммит 6fe6b37c32
7 изменённых файлов: 197 добавлений и 0 удалений

Просмотреть файл

@ -0,0 +1 @@
<img id="image1" src="finite-apng.png">

Просмотреть файл

@ -0,0 +1,49 @@
<!DOCTYPE HTML>
<html class="reftest-wait">
<head>
</head>
<body>
<div id="container">
<iframe id='if' src="1629490-1-iframe.html"></iframe>
</div>
<script>
let iterationsLeft = 25;
function runTest() {
// Make sure the image is decoded and advanced to it's final frame.
let img = document.getElementById("if").contentWindow.document.getElementById("image1");
img.decode().then(function() {
setTimeout(forceDiscard, 2000);
});
}
function showIframe() {
document.getElementById("container").style.display = "";
document.documentElement.getBoundingClientRect();
requestAnimationFrame(forceDecode);
}
function forceDecode() {
let img = document.getElementById("if").contentWindow.document.getElementById("image1");
img.decode().then(function() {
setTimeout(forceDiscard, 0);
});
}
function forceDiscard() {
iterationsLeft--;
if (iterationsLeft < 0) {
document.documentElement.className = "";
return;
}
document.getElementById("container").style.display = "none";
document.documentElement.getBoundingClientRect();
requestAnimationFrame(() => { requestAnimationFrame( () => { setTimeout(showIframe, 0); } ) });
}
//window.addEventListener("load", runTest);
window.addEventListener("MozReftestInvalidate", runTest);
</script>
</body>
</html>

Просмотреть файл

@ -60,3 +60,4 @@ load truncated-second-frame.png # Bug 863975
load 1509998.gif
load 1526717-1.html
load 1629490-1.html

Двоичные данные
image/test/crashtests/finite-apng.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 5.7 KiB

Двоичные данные
image/test/mochitest/finite-apng.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 5.7 KiB

Просмотреть файл

@ -54,6 +54,7 @@ support-files =
error-early.png
filter-final.svg
filter.svg
finite-apng.png
first-frame-padding.gif
green.png
green-background.html
@ -139,6 +140,7 @@ skip-if = verify
[test_changeOfSource.html]
[test_changeOfSource2.html]
[test_discardAnimatedImage.html]
[test_discardFinishedAnimatedImage.html]
[test_discardFramesAnimatedImage.html]
[test_drawDiscardedImage.html]
[test_error_events.html]

Просмотреть файл

@ -0,0 +1,144 @@
<!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>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1629490">Mozilla Bug 1629490</a>
<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 === "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.
//
// https://searchfox.org/mozilla-central/rev/b7f3977978922d44c7d92ae01c0d4cc2baca7bc2/layout/style/ImageLoader.cpp#553
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(anImage) {
imgLoadingContent.removeObserver(scriptedObserver);
}
function requestDiscard(anImage) {
var request = SpecialPowers.wrap(anImage)
.getRequest(SpecialPowers.Ci.nsIImageLoadingContent.CURRENT_REQUEST);
setTimeout(() => request.requestDiscard(), 0);
}
</script>
</body>
</html>