diff options
Diffstat (limited to 'image/test/browser/browser_bug666317.js')
-rw-r--r-- | image/test/browser/browser_bug666317.js | 140 |
1 files changed, 140 insertions, 0 deletions
diff --git a/image/test/browser/browser_bug666317.js b/image/test/browser/browser_bug666317.js new file mode 100644 index 000000000..2bd2d0615 --- /dev/null +++ b/image/test/browser/browser_bug666317.js @@ -0,0 +1,140 @@ +waitForExplicitFinish(); + +var pageSource = + '<html><body>' + + '<img id="testImg" src="' + TESTROOT + 'big.png">' + + '</body></html>'; + +var oldDiscardingPref, oldTab, newTab; +var prefBranch = Cc["@mozilla.org/preferences-service;1"] + .getService(Ci.nsIPrefService) + .getBranch('image.mem.'); + +var gWaitingForDiscard = false; +var gScriptedObserver; +var gClonedRequest; + +function ImageObserver(decodeCallback, discardCallback) { + this.decodeComplete = function onDecodeComplete(aRequest) { + decodeCallback(); + } + + this.discard = function onDiscard(request) + { + if (!gWaitingForDiscard) { + return; + } + + this.synchronous = false; + discardCallback(); + } + + this.synchronous = true; +} + +function currentRequest() { + let img = gBrowser.getBrowserForTab(newTab).contentWindow + .document.getElementById('testImg'); + img.QueryInterface(Ci.nsIImageLoadingContent); + return img.getRequest(Ci.nsIImageLoadingContent.CURRENT_REQUEST); +} + +function isImgDecoded() { + let request = currentRequest(); + return request.imageStatus & Ci.imgIRequest.STATUS_DECODE_COMPLETE ? true : false; +} + +// Ensure that the image is decoded by drawing it to a canvas. +function forceDecodeImg() { + let doc = gBrowser.getBrowserForTab(newTab).contentWindow.document; + let img = doc.getElementById('testImg'); + let canvas = doc.createElement('canvas'); + let ctx = canvas.getContext('2d'); + ctx.drawImage(img, 0, 0); +} + +function runAfterAsyncEvents(aCallback) { + function handlePostMessage(aEvent) { + if (aEvent.data == 'next') { + window.removeEventListener('message', handlePostMessage, false); + aCallback(); + } + } + + window.addEventListener('message', handlePostMessage, false); + + // We'll receive the 'message' event after everything else that's currently in + // the event queue (which is a stronger guarantee than setTimeout, because + // setTimeout events may be coalesced). This lets us ensure that we run + // aCallback *after* any asynchronous events are delivered. + window.postMessage('next', '*'); +} + +function test() { + // Enable the discarding pref. + oldDiscardingPref = prefBranch.getBoolPref('discardable'); + prefBranch.setBoolPref('discardable', true); + + // Create and focus a new tab. + oldTab = gBrowser.selectedTab; + newTab = gBrowser.addTab('data:text/html,' + pageSource); + gBrowser.selectedTab = newTab; + + // Run step2 after the tab loads. + gBrowser.getBrowserForTab(newTab) + .addEventListener("pageshow", step2); +} + +function step2() { + // Create the image observer. + var observer = + new ImageObserver(() => runAfterAsyncEvents(step3), // DECODE_COMPLETE + () => runAfterAsyncEvents(step5)); // DISCARD + gScriptedObserver = Cc["@mozilla.org/image/tools;1"] + .getService(Ci.imgITools) + .createScriptedObserver(observer); + + // Clone the current imgIRequest with our new observer. + var request = currentRequest(); + gClonedRequest = request.clone(gScriptedObserver); + + // Check that the image is decoded. + forceDecodeImg(); + + // The DECODE_COMPLETE notification is delivered asynchronously. ImageObserver will + // eventually call step3. +} + +function step3() { + ok(isImgDecoded(), 'Image should initially be decoded.'); + + // Focus the old tab, then fire a memory-pressure notification. This should + // cause the decoded image in the new tab to be discarded. + gBrowser.selectedTab = oldTab; + + // Allow time to process the tab change. + runAfterAsyncEvents(step4); +} + +function step4() { + gWaitingForDiscard = true; + + var os = Cc["@mozilla.org/observer-service;1"] + .getService(Ci.nsIObserverService); + os.notifyObservers(null, 'memory-pressure', 'heap-minimize'); + + // The DISCARD notification is delivered asynchronously. ImageObserver will + // eventually call step5. (Or else, sadly, the test will time out.) +} + +function step5() { + ok(true, 'Image should be discarded.'); + + // And we're done. + gBrowser.removeTab(newTab); + prefBranch.setBoolPref('discardable', oldDiscardingPref); + + gClonedRequest.cancelAndForgetObserver(0); + + finish(); +} |