Bug 1869043 remove declaration of missing CreateOrDestroyAudioTracks r=padenot
[gecko.git] / image / test / mochitest / test_discardAnimatedImage.html
blob09bd9372c6a8b4b03094c1c0ad9fa64ae72cf87d
1 <!DOCTYPE HTML>
2 <html>
3 <!--
4 https://bugzilla.mozilla.org/show_bug.cgi?id=686905
5 -->
6 <head>
7 <title>Test that animated images can be discarded</title>
8 <script src="/tests/SimpleTest/SimpleTest.js"></script>
9 <script src="/tests/SimpleTest/WindowSnapshot.js"></script>
10 <script type="text/javascript" src="imgutils.js"></script>
11 <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
12 </head>
13 <body>
14 <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=686905">Mozilla Bug 686905</a>
15 <p id="display"></p>
16 <div id="content">
17 <div id="container">
18 <canvas id="canvas" width="100" height="100"></canvas>
19 <img id="infinitepng" src="infinite-apng.png">
20 <img id="infinitegif" src="animated1.gif">
21 <img id="infinitewebp" src="infinite.webp">
22 <img id="infiniteavif" src="infinite.avif">
23 <img id="finitepng" src="restore-previous.png">
24 <img id="finitegif" src="animated-gif.gif">
25 <img id="finitewebp" src="keep.webp">
26 <img id="finiteavif" src="animated-avif.avif">
27 </div>
28 </div>
29 <pre id="test">
30 <script class="testbody" type="text/javascript">
32 /** Test for Bug 686905. **/
33 SimpleTest.waitForExplicitFinish();
35 var gFinished = false;
37 var gNumDiscards = 0;
39 window.onload = function() {
40 // Enable discarding for the test.
41 SpecialPowers.pushPrefEnv({
42 'set':[['image.mem.discardable',true],
43 ['image.avif.sequence.enabled',true]]
44 }, runTest);
47 var gImgs = ['infinitepng', 'infinitegif', 'infinitewebp', 'infiniteavif',
48 'finitepng', 'finitegif', 'finitewebp', 'finiteavif'];
49 // If we are currently counting frame updates.
50 var gCountingFrameUpdates = false;
51 // The number of frame update notifications for the images in gImgs that happen
52 // after discarding. (The last two images are finite looping so we don't expect
53 // them to get incremented but it's possible if they don't finish their
54 // animation before we discard them.)
55 var gNumFrameUpdates = [0, 0, 0, 0, 0, 0];
56 // The last snapshot of the image. Used to check that the image actually changes.
57 var gLastSnapShot = [null, null, null, null, null, null];
58 // Number of observed changes in the snapshot.
59 var gNumSnapShotChanges = [0, 0, 0, 0, 0, 0];
60 // If we've removed the observer.
61 var gRemovedObserver = [false, false, false, false, false, false];
63 // 2 would probably be a good enough test, we arbitrarily choose 4.
64 var kNumFrameUpdatesToExpect = 4;
66 function runTest() {
67 var animatedDiscardable =
68 SpecialPowers.getBoolPref('image.mem.animated.discardable');
69 if (!animatedDiscardable) {
70 ok(true, "discarding of animated images is disabled, nothing to test");
71 SimpleTest.finish();
72 return;
75 setTimeout(step2, 0);
78 function step2() {
79 // Draw the images to canvas to force them to be decoded.
80 for (let i = 0; i < gImgs.length; i++) {
81 drawCanvas(document.getElementById(gImgs[i]));
84 for (let i = 0; i < gImgs.length; i++) {
85 addCallbacks(document.getElementById(gImgs[i]), i);
88 setTimeout(step3, 0);
91 function step3() {
92 document.getElementById("container").style.display = "none";
93 document.documentElement.offsetLeft; // force that style to take effect
95 for (var i = 0; i < gImgs.length; i++) {
96 requestDiscard(document.getElementById(gImgs[i]));
99 // the discard observers will call step4
102 function step4() {
103 gCountingFrameUpdates = true;
104 document.getElementById("container").style.display = "";
106 // Draw the images to canvas to force them to be decoded again.
107 for (var i = 0; i < gImgs.length; i++) {
108 drawCanvas(document.getElementById(gImgs[i]));
112 function checkIfFinished() {
113 if (gFinished) {
114 return;
117 if ((gNumFrameUpdates[0] >= kNumFrameUpdatesToExpect) &&
118 (gNumFrameUpdates[1] >= kNumFrameUpdatesToExpect) &&
119 (gNumFrameUpdates[2] >= kNumFrameUpdatesToExpect) &&
120 (gNumSnapShotChanges[0] >= kNumFrameUpdatesToExpect) &&
121 (gNumSnapShotChanges[1] >= kNumFrameUpdatesToExpect) &&
122 (gNumSnapShotChanges[2] >= kNumFrameUpdatesToExpect)) {
123 ok(true, "got expected frame updates");
124 gFinished = true;
125 SimpleTest.finish();
129 // arrayIndex is the index into the arrays gNumFrameUpdates and gNumDecodes
130 // to increment when a frame update notification is received.
131 function addCallbacks(anImage, arrayIndex) {
132 var observer = new ImageDecoderObserverStub();
133 observer.discard = function () {
134 gNumDiscards++;
135 ok(true, "got image discard");
136 if (arrayIndex >= 3) {
137 // The last two images are finite, so we don't expect any frame updates,
138 // this image is done the test, so remove the observer.
139 if (!gRemovedObserver[arrayIndex]) {
140 gRemovedObserver[arrayIndex] = true;
141 imgLoadingContent.removeObserver(scriptedObserver);
144 if (gNumDiscards == gImgs.length) {
145 step4();
148 observer.frameUpdate = function () {
149 if (!gCountingFrameUpdates) {
150 return;
153 // Do this off a setTimeout since nsImageLoadingContent uses a scriptblocker
154 // when it notifies us and calling drawWindow can call will paint observers
155 // which can dispatch a scrollport event, and events assert if dispatched
156 // when there is a scriptblocker.
157 setTimeout(function () {
158 gNumFrameUpdates[arrayIndex]++;
160 var r = document.getElementById(gImgs[arrayIndex]).getBoundingClientRect();
161 var snapshot = snapshotRect(window, r, "rgba(0,0,0,0)");
162 if (gLastSnapShot[arrayIndex] != null) {
163 if (snapshot.toDataURL() != gLastSnapShot[arrayIndex].toDataURL()) {
164 gNumSnapShotChanges[arrayIndex]++;
167 gLastSnapShot[arrayIndex] = snapshot;
169 if (gNumFrameUpdates[arrayIndex] >= kNumFrameUpdatesToExpect &&
170 gNumSnapShotChanges[arrayIndex] >= kNumFrameUpdatesToExpect) {
171 if (!gRemovedObserver[arrayIndex]) {
172 gRemovedObserver[arrayIndex] = true;
173 imgLoadingContent.removeObserver(scriptedObserver);
176 if (!gFinished) {
177 // because we do this in a setTimeout we can have several in flight
178 // so don't call ok if we've already finished.
179 ok(true, "got frame update");
181 checkIfFinished();
182 }, 0);
184 observer = SpecialPowers.wrapCallbackObject(observer);
186 var scriptedObserver = SpecialPowers.Cc["@mozilla.org/image/tools;1"]
187 .getService(SpecialPowers.Ci.imgITools)
188 .createScriptedObserver(observer);
190 var imgLoadingContent = SpecialPowers.wrap(anImage);
191 imgLoadingContent.addObserver(scriptedObserver);
194 function requestDiscard(anImage) {
195 var request = SpecialPowers.wrap(anImage)
196 .getRequest(SpecialPowers.Ci.nsIImageLoadingContent.CURRENT_REQUEST);
197 setTimeout(() => request.requestDiscard(), 0);
200 function drawCanvas(anImage) {
201 var canvas = document.getElementById('canvas');
202 var context = canvas.getContext('2d');
204 context.clearRect(0,0,100,100);
205 var cleared = canvas.toDataURL();
207 context.drawImage(anImage, 0, 0);
208 ok(true, "we got through the drawImage call without an exception being thrown");
210 ok(cleared != canvas.toDataURL(), "drawImage drew something");
213 </script>
214 </pre>
215 </body>
216 </html>