test_discardFinishedAnimatedImage.html (4415B)
1 <!DOCTYPE HTML> 2 <html> 3 <head> 4 <title>Test that img.decode works on finished, discarded animated images</title> 5 <script src="/tests/SimpleTest/SimpleTest.js"></script> 6 <script src="/tests/SimpleTest/WindowSnapshot.js"></script> 7 <script type="text/javascript" src="imgutils.js"></script> 8 <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> 9 </head> 10 <body> 11 <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1629490">Mozilla Bug 1629490</a> 12 <div id="container"> 13 <img id="finitepng" src="finite-apng.png"> 14 </div> 15 <script class="testbody" type="text/javascript"> 16 17 SimpleTest.waitForExplicitFinish(); 18 19 window.onload = runTest; 20 21 let discardCallback = undefined; 22 let frameUpdateCallback = undefined; 23 24 async function runTest() { 25 const kUsingWebRender = SpecialPowers.DOMWindowUtils.layerManagerType.startsWith("WebRender"); 26 27 let img = document.getElementById("finitepng"); 28 29 await img.decode(); 30 31 while (!isItGreen(img)) { 32 // We hit an optimized path in WebRender that doesn't cause a repaint on the 33 // main thread and doesn't seem to send MozAfterPaints. 34 // 35 // https://searchfox.org/mozilla-central/rev/b7f3977978922d44c7d92ae01c0d4cc2baca7bc2/layout/style/ImageLoader.cpp#553 36 await new Promise(resolve => { 37 if (kUsingWebRender) { 38 requestAnimationFrame(() => { 39 requestAnimationFrame(resolve); 40 }); 41 } else { 42 window.addEventListener("MozAfterPaint", resolve, { once: true }); 43 } 44 }); 45 } 46 47 addCallbacks(img); 48 49 let iterationsLeft = 26; 50 while (iterationsLeft > 0) { 51 52 let discardPromise = new Promise(resolve => { 53 discardCallback = resolve; 54 }); 55 56 document.getElementById("container").style.display = "none"; 57 document.documentElement.offsetLeft; // force that style to take effect 58 requestDiscard(img); 59 60 await new Promise(resolve => {requestAnimationFrame(() => { requestAnimationFrame(resolve); }); }); 61 62 await discardPromise; 63 await new Promise(resolve => {requestAnimationFrame(() => { requestAnimationFrame(resolve); }); }); 64 65 let waitForFrameUpdate = new Promise(resolve => { 66 frameUpdateCallback = resolve; 67 }); 68 69 document.getElementById("container").style.display = ""; 70 document.documentElement.offsetLeft; // force that style to take effect 71 72 await img.decode(); 73 74 await new Promise(resolve => requestAnimationFrame(resolve)); 75 76 await waitForFrameUpdate; 77 78 ok(isItGreen(img), "should be green"); 79 80 iterationsLeft--; 81 await new Promise(resolve => {requestAnimationFrame(() => { requestAnimationFrame(resolve); }); }); 82 83 } 84 85 removeObserver(img); 86 SimpleTest.finish(); 87 } 88 89 function isItGreen(img) { 90 let rect = img.getBoundingClientRect(); 91 let r = {left: rect.left + 5, top: rect.top + 5, width: 5, height: 5}; 92 let c = SpecialPowers.snapshotWindowWithOptions(window, r); 93 let d = c.getContext('2d').getImageData(0,0,5,5).data; 94 let isGreen = true; 95 for (let i = 0; i < 5*5; i++) { 96 if (d[4*i] != 0 || d[4*i + 1] != 128 || d[4*i + 2] != 0 || d[4*i + 3] != 255) { 97 isGreen = false; 98 } 99 } 100 return isGreen; 101 } 102 103 104 let scriptedObserver = undefined; 105 let imgLoadingContent = undefined; 106 function addCallbacks(anImage) { 107 var observer = new ImageDecoderObserverStub(); 108 observer.discard = function () { 109 if (discardCallback != undefined) { 110 let localDiscardCallback = discardCallback; 111 discardCallback = undefined; 112 setTimeout(localDiscardCallback, 0); 113 } 114 }; 115 observer.frameUpdate = function () { 116 if (frameUpdateCallback != undefined) { 117 let localFrameUpdateCallback = frameUpdateCallback; 118 frameUpdateCallback = undefined; 119 setTimeout(localFrameUpdateCallback, 0); 120 } 121 }; 122 observer = SpecialPowers.wrapCallbackObject(observer); 123 124 scriptedObserver = SpecialPowers.Cc["@mozilla.org/image/tools;1"] 125 .getService(SpecialPowers.Ci.imgITools) 126 .createScriptedObserver(observer); 127 128 imgLoadingContent = SpecialPowers.wrap(anImage); 129 imgLoadingContent.addObserver(scriptedObserver); 130 } 131 132 function removeObserver() { 133 imgLoadingContent.removeObserver(scriptedObserver); 134 } 135 136 function requestDiscard(anImage) { 137 var request = SpecialPowers.wrap(anImage) 138 .getRequest(SpecialPowers.Ci.nsIImageLoadingContent.CURRENT_REQUEST); 139 setTimeout(() => request.requestDiscard(), 0); 140 } 141 142 </script> 143 </body> 144 </html>