summaryrefslogtreecommitdiffstats
path: root/image/test/browser/browser_bug666317.js
diff options
context:
space:
mode:
Diffstat (limited to 'image/test/browser/browser_bug666317.js')
-rw-r--r--image/test/browser/browser_bug666317.js140
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();
+}