mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-19 00:05:36 +00:00
05aceb8d0a
The previous patch wasn't good enough because it only prevented dispatching more setTimeouts after finish. It did nothing to stop already dispatched setTimeouts from calling ok(true,...).
213 lines
6.8 KiB
HTML
213 lines
6.8 KiB
HTML
<!DOCTYPE HTML>
|
|
<html>
|
|
<!--
|
|
https://bugzilla.mozilla.org/show_bug.cgi?id=686905
|
|
-->
|
|
<head>
|
|
<title>Test that animated images can be discarded</title>
|
|
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
|
<script type="text/javascript" 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=686905">Mozilla Bug 686905</a>
|
|
<p id="display"></p>
|
|
<div id="content">
|
|
<div id="container">
|
|
<canvas id="canvas" width="100" height="100"></canvas>
|
|
<img id="infinitepng" src="infinite-apng.png">
|
|
<img id="infinitegif" src="animated1.gif">
|
|
<img id="finitepng" src="restore-previous.png">
|
|
<img id="finitegif" src="animated-gif.gif">
|
|
</div>
|
|
</div>
|
|
<pre id="test">
|
|
<script class="testbody" type="text/javascript">
|
|
|
|
/** Test for Bug 686905. **/
|
|
SimpleTest.waitForExplicitFinish();
|
|
|
|
var gFinished = false;
|
|
|
|
var gNumDiscards = 0;
|
|
|
|
window.onload = function() {
|
|
// Enable discarding for the test.
|
|
SpecialPowers.pushPrefEnv({
|
|
'set':[['image.mem.discardable',true]]
|
|
}, runTest);
|
|
}
|
|
|
|
var gImgs = ['infinitepng', 'infinitegif', 'finitepng', 'finitegif'];
|
|
// If we are currently counting frame updates.
|
|
var gCountingFrameUpdates = false;
|
|
// The number of frame update notifications for the images in gImgs that happen
|
|
// after discarding. (The last two images are finite looping so we don't expect
|
|
// them to get incremented but it's possible if they don't finish their
|
|
// animation before we discard them.)
|
|
var gNumFrameUpdates = [0, 0, 0, 0];
|
|
// The last snapshot of the image. Used to check that the image actually changes.
|
|
var gLastSnapShot = [null, null, null, null];
|
|
// Number of observed changes in the snapshot.
|
|
var gNumSnapShotChanges = [0, 0, 0, 0];
|
|
// If we've removed the observer.
|
|
var gRemovedObserver = [false, false, false, false];
|
|
|
|
// 2 would probably be a good enough test, we arbitrarily choose 4.
|
|
var kNumFrameUpdatesToExpect = 4;
|
|
|
|
function runTest() {
|
|
var animatedDiscardable =
|
|
SpecialPowers.getBoolPref('image.mem.animated.discardable');
|
|
if (!animatedDiscardable) {
|
|
ok(true, "discarding of animated images is disabled, nothing to test");
|
|
SimpleTest.finish();
|
|
return;
|
|
}
|
|
|
|
setTimeout(step2, 0);
|
|
}
|
|
|
|
function step2() {
|
|
// Draw the images to canvas to force them to be decoded.
|
|
for (var i = 0; i < gImgs.length; i++) {
|
|
drawCanvas(document.getElementById(gImgs[i]));
|
|
}
|
|
|
|
for (var i = 0; i < gImgs.length; i++) {
|
|
addCallbacks(document.getElementById(gImgs[i]), i);
|
|
}
|
|
|
|
setTimeout(step3, 0);
|
|
}
|
|
|
|
function step3() {
|
|
document.getElementById("container").style.display = "none";
|
|
document.documentElement.offsetLeft; // force that style to take effect
|
|
|
|
for (var i = 0; i < gImgs.length; i++) {
|
|
requestDiscard(document.getElementById(gImgs[i]));
|
|
}
|
|
|
|
// the discard observers will call step4
|
|
}
|
|
|
|
function step4() {
|
|
gCountingFrameUpdates = true;
|
|
document.getElementById("container").style.display = "";
|
|
|
|
// Draw the images to canvas to force them to be decoded again.
|
|
for (var i = 0; i < gImgs.length; i++) {
|
|
drawCanvas(document.getElementById(gImgs[i]));
|
|
}
|
|
}
|
|
|
|
function checkIfFinished() {
|
|
if (gFinished) {
|
|
return;
|
|
}
|
|
|
|
if ((gNumFrameUpdates[0] >= kNumFrameUpdatesToExpect) &&
|
|
(gNumFrameUpdates[1] >= kNumFrameUpdatesToExpect) &&
|
|
(gNumSnapShotChanges[0] >= kNumFrameUpdatesToExpect) &&
|
|
(gNumSnapShotChanges[1] >= kNumFrameUpdatesToExpect)) {
|
|
ok(true, "got expected frame updates");
|
|
gFinished = true;
|
|
SimpleTest.finish();
|
|
}
|
|
}
|
|
|
|
// arrayIndex is the index into the arrays gNumFrameUpdates and gNumDecodes
|
|
// to increment when a frame update notification is received.
|
|
function addCallbacks(anImage, arrayIndex) {
|
|
var observer = new ImageDecoderObserverStub();
|
|
observer.discard = function () {
|
|
gNumDiscards++;
|
|
ok(true, "got image discard");
|
|
if (arrayIndex >= 2) {
|
|
// The last two images are finite, so we don't expect any frame updates,
|
|
// this image is done the test, so remove the observer.
|
|
if (!gRemovedObserver[arrayIndex]) {
|
|
gRemovedObserver[arrayIndex] = true;
|
|
imgLoadingContent.removeObserver(scriptedObserver);
|
|
}
|
|
}
|
|
if (gNumDiscards == gImgs.length) {
|
|
step4();
|
|
}
|
|
};
|
|
observer.frameUpdate = function () {
|
|
if (!gCountingFrameUpdates) {
|
|
return;
|
|
}
|
|
|
|
// Do this off a setTimeout since nsImageLoadingContent uses a scriptblocker
|
|
// when it notifies us and calling drawWindow can call will paint observers
|
|
// which can dispatch a scrollport event, and events assert if dispatched
|
|
// when there is a scriptblocker.
|
|
setTimeout(function () {
|
|
gNumFrameUpdates[arrayIndex]++;
|
|
|
|
var r = document.getElementById(gImgs[arrayIndex]).getBoundingClientRect();
|
|
var snapshot = snapshotRect(window, r, "rgba(0,0,0,0)");
|
|
if (gLastSnapShot[arrayIndex] != null) {
|
|
if (snapshot.toDataURL() != gLastSnapShot[arrayIndex].toDataURL()) {
|
|
gNumSnapShotChanges[arrayIndex]++;
|
|
}
|
|
}
|
|
gLastSnapShot[arrayIndex] = snapshot;
|
|
|
|
if (gNumFrameUpdates[arrayIndex] >= kNumFrameUpdatesToExpect &&
|
|
gNumSnapShotChanges[arrayIndex] >= kNumFrameUpdatesToExpect) {
|
|
if (!gRemovedObserver[arrayIndex]) {
|
|
gRemovedObserver[arrayIndex] = true;
|
|
imgLoadingContent.removeObserver(scriptedObserver);
|
|
}
|
|
}
|
|
if (!gFinished) {
|
|
// because we do this in a setTimeout we can have several in flight
|
|
// so don't call ok if we've already finished.
|
|
ok(true, "got frame update");
|
|
}
|
|
checkIfFinished();
|
|
}, 0);
|
|
};
|
|
observer = SpecialPowers.wrapCallbackObject(observer);
|
|
|
|
var scriptedObserver = SpecialPowers.Cc["@mozilla.org/image/tools;1"]
|
|
.getService(SpecialPowers.Ci.imgITools)
|
|
.createScriptedObserver(observer);
|
|
|
|
var imgLoadingContent =
|
|
SpecialPowers.wrap(anImage)
|
|
.QueryInterface(SpecialPowers.Ci.nsIImageLoadingContent);
|
|
imgLoadingContent.addObserver(scriptedObserver);
|
|
}
|
|
|
|
function requestDiscard(anImage) {
|
|
var request = SpecialPowers.wrap(anImage)
|
|
.QueryInterface(SpecialPowers.Ci.nsIImageLoadingContent)
|
|
.getRequest(SpecialPowers.Ci.nsIImageLoadingContent.CURRENT_REQUEST);
|
|
setTimeout(() => request.requestDiscard(), 0);
|
|
}
|
|
|
|
function drawCanvas(anImage) {
|
|
var canvas = document.getElementById('canvas');
|
|
var context = canvas.getContext('2d');
|
|
|
|
context.clearRect(0,0,100,100);
|
|
var cleared = canvas.toDataURL();
|
|
|
|
context.drawImage(anImage, 0, 0);
|
|
ok(true, "we got through the drawImage call without an exception being thrown");
|
|
|
|
ok(cleared != canvas.toDataURL(), "drawImage drew something");
|
|
}
|
|
|
|
</script>
|
|
</pre>
|
|
</body>
|
|
</html>
|
|
|