diff options
Diffstat (limited to 'image/test/browser')
-rw-r--r-- | image/test/browser/animated.gif | bin | 0 -> 71479 bytes | |||
-rw-r--r-- | image/test/browser/animated2.gif | bin | 0 -> 66647 bytes | |||
-rw-r--r-- | image/test/browser/big.png | bin | 0 -> 129497 bytes | |||
-rw-r--r-- | image/test/browser/browser.ini | 14 | ||||
-rw-r--r-- | image/test/browser/browser_bug666317.js | 140 | ||||
-rw-r--r-- | image/test/browser/browser_docshell_type_editor.js | 92 | ||||
-rw-r--r-- | image/test/browser/browser_image.js | 195 | ||||
-rw-r--r-- | image/test/browser/head.js | 26 | ||||
-rw-r--r-- | image/test/browser/image.html | 24 | ||||
-rw-r--r-- | image/test/browser/imageX2.html | 15 |
10 files changed, 506 insertions, 0 deletions
diff --git a/image/test/browser/animated.gif b/image/test/browser/animated.gif Binary files differnew file mode 100644 index 000000000..eb034e150 --- /dev/null +++ b/image/test/browser/animated.gif diff --git a/image/test/browser/animated2.gif b/image/test/browser/animated2.gif Binary files differnew file mode 100644 index 000000000..053eaae68 --- /dev/null +++ b/image/test/browser/animated2.gif diff --git a/image/test/browser/big.png b/image/test/browser/big.png Binary files differnew file mode 100644 index 000000000..94e7eb6db --- /dev/null +++ b/image/test/browser/big.png diff --git a/image/test/browser/browser.ini b/image/test/browser/browser.ini new file mode 100644 index 000000000..d5e94e575 --- /dev/null +++ b/image/test/browser/browser.ini @@ -0,0 +1,14 @@ +[DEFAULT] +support-files = + animated.gif + animated2.gif + big.png + head.js + image.html + imageX2.html + +[browser_bug666317.js] +skip-if = true || e10s # Bug 1207012 - Permaorange from an uncaught exception that isn't actually turning the suite orange until it hits beta, Bug 948194 - Decoded Images seem to not be discarded on memory-pressure notification with e10s enabled +[browser_image.js] +skip-if = true # Bug 987616 +[browser_docshell_type_editor.js] 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(); +} diff --git a/image/test/browser/browser_docshell_type_editor.js b/image/test/browser/browser_docshell_type_editor.js new file mode 100644 index 000000000..8ac98924f --- /dev/null +++ b/image/test/browser/browser_docshell_type_editor.js @@ -0,0 +1,92 @@ + +"use strict"; + +const Ci = Components.interfaces; +const SIMPLE_HTML = "data:text/html,<html><head></head><body></body></html>"; + +// The following URI is *not* accessible to content, hence loading that URI +// from an unprivileged site should be blocked. If docshell is of appType +// APP_TYPE_EDITOR however the load should be allowed. +// >> chrome://devtools/content/framework/dev-edition-promo/dev-edition-logo.png + +add_task(function* () { + info("docshell of appType APP_TYPE_EDITOR can access privileged images."); + + yield BrowserTestUtils.withNewTab({ + gBrowser, + url: SIMPLE_HTML + }, function* (browser) { + yield ContentTask.spawn(browser, null, function* () { + let rootDocShell = docShell.QueryInterface(Ci.nsIDocShellTreeItem) + .rootTreeItem + .QueryInterface(Ci.nsIInterfaceRequestor) + .getInterface(Ci.nsIDocShell); + let defaultAppType = rootDocShell.appType; + + rootDocShell.appType = Ci.nsIDocShell.APP_TYPE_EDITOR; + + is(rootDocShell.appType, Ci.nsIDocShell.APP_TYPE_EDITOR, + "sanity check: appType after update should be type editor"); + + return new Promise(resolve => { + let doc = content.document; + let image = doc.createElement("img"); + image.onload = function() { + ok(true, "APP_TYPE_EDITOR is allowed to load privileged image"); + // restore appType of rootDocShell before moving on to the next test + rootDocShell.appType = defaultAppType; + resolve(); + } + image.onerror = function() { + ok(false, "APP_TYPE_EDITOR is allowed to load privileged image"); + // restore appType of rootDocShell before moving on to the next test + rootDocShell.appType = defaultAppType; + resolve(); + } + doc.body.appendChild(image); + image.src = "chrome://devtools/content/framework/dev-edition-promo/dev-edition-logo.png"; + }); + }); + }); +}); + +add_task(function* () { + info("docshell of appType APP_TYPE_UNKNOWN can *not* access privileged images."); + + yield BrowserTestUtils.withNewTab({ + gBrowser, + url: SIMPLE_HTML + }, function* (browser) { + yield ContentTask.spawn(browser, null, function* () { + let rootDocShell = docShell.QueryInterface(Ci.nsIDocShellTreeItem) + .rootTreeItem + .QueryInterface(Ci.nsIInterfaceRequestor) + .getInterface(Ci.nsIDocShell); + let defaultAppType = rootDocShell.appType; + + rootDocShell.appType = Ci.nsIDocShell.APP_TYPE_UNKNOWN; + + is(rootDocShell.appType, Ci.nsIDocShell.APP_TYPE_UNKNOWN, + "sanity check: appType of docshell should be unknown"); + + return new Promise(resolve => { + let doc = content.document; + let image = doc.createElement("img"); + image.onload = function() { + ok(false, "APP_TYPE_UNKNOWN is *not* allowed to acces privileged image"); + // restore appType of rootDocShell before moving on to the next test + rootDocShell.appType = defaultAppType; + resolve(); + } + image.onerror = function() { + ok(true, "APP_TYPE_UNKNOWN is *not* allowed to acces privileged image"); + // restore appType of rootDocShell before moving on to the next test + rootDocShell.appType = defaultAppType; + resolve(); + } + doc.body.appendChild(image); + image.src = "chrome://devtools/content/framework/dev-edition-promo/dev-edition-logo.png"; + }); + }); + }); +}); diff --git a/image/test/browser/browser_image.js b/image/test/browser/browser_image.js new file mode 100644 index 000000000..9527726c3 --- /dev/null +++ b/image/test/browser/browser_image.js @@ -0,0 +1,195 @@ +waitForExplicitFinish(); +requestLongerTimeout(2); // see bug 660123 -- this test is slow on Mac. + +// A hold on the current timer, so it doens't get GCed out from +// under us +var gTimer; + +// Browsing to a new URL - pushing us into the bfcache - should cause +// animations to stop, and resume when we return +function testBFCache() { + function theTest() { + var abort = false; + var chances, gImage, gFrames; + gBrowser.selectedTab = gBrowser.addTab(TESTROOT + "image.html"); + gBrowser.selectedBrowser.addEventListener("pageshow", function () { + gBrowser.selectedBrowser.removeEventListener("pageshow", arguments.callee, true); + var window = gBrowser.contentWindow; + // If false, we are in an optimized build, and we abort this and + // all further tests + if (!actOnMozImage(window.document, "img1", function(image) { + gImage = image; + gFrames = gImage.framesNotified; + })) { + gBrowser.removeCurrentTab(); + abort = true; + } + goer.next(); + }, true); + yield; + if (abort) { + finish(); + yield; // optimized build + } + + // Let animation run for a bit + chances = 120; + do { + gTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer); + gTimer.initWithCallback(function() { + if (gImage.framesNotified >= 20) { + goer.send(true); + } else { + chances--; + goer.send(chances == 0); // maybe if we wait a bit, it will happen + } + }, 500, Ci.nsITimer.TYPE_ONE_SHOT); + } while (!(yield)); + is(chances > 0, true, "Must have animated a few frames so far"); + + // Browse elsewhere; push our animating page into the bfcache + gBrowser.loadURI("about:blank"); + + // Wait a bit for page to fully load, then wait a while and + // see that no animation occurs. + gTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer); + gTimer.initWithCallback(function() { + gFrames = gImage.framesNotified; + gTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer); + gTimer.initWithCallback(function() { + // Might have a few stray frames, until other page totally loads + var additionalFrames = gImage.framesNotified - gFrames; + is(additionalFrames == 0, true, "Must have not animated in bfcache! Got " + additionalFrames + " additional frames"); + goer.next(); + }, 4000, Ci.nsITimer.TYPE_ONE_SHOT); // 4 seconds - expect 40 frames + }, 0, Ci.nsITimer.TYPE_ONE_SHOT); // delay of 0 - wait for next event loop + yield; + + // Go back + gBrowser.goBack(); + + chances = 120; + do { + gTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer); + gTimer.initWithCallback(function() { + if (gImage.framesNotified - gFrames >= 20) { + goer.send(true); + } else { + chances--; + goer.send(chances == 0); // maybe if we wait a bit, it will happen + } + }, 500, Ci.nsITimer.TYPE_ONE_SHOT); + } while (!(yield)); + is(chances > 0, true, "Must have animated once out of bfcache!"); + + // Finally, check that the css background image has essentially the same + // # of frames, implying that it animated at the same times as the regular + // image. We can easily retrieve regular images through their HTML image + // elements, which is what we did before. For the background image, we + // create a regular image now, and read the current frame count. + var doc = gBrowser.selectedBrowser.contentWindow.document; + var div = doc.getElementById("background_div"); + div.innerHTML += '<img src="animated2.gif" id="img3">'; + actOnMozImage(doc, "img3", function(image) { + is(Math.abs(image.framesNotified - gImage.framesNotified)/gImage.framesNotified < 0.5, true, + "Must have also animated the background image, and essentially the same # of frames. " + + "Regular image got " + gImage.framesNotified + " frames but background image got " + image.framesNotified); + }); + + gBrowser.removeCurrentTab(); + + nextTest(); + } + + var goer = theTest(); + goer.next(); +} + +// Check that imgContainers are shared on the same page and +// between tabs +function testSharedContainers() { + function theTest() { + var gImages = []; + var gFrames; + + gBrowser.selectedTab = gBrowser.addTab(TESTROOT + "image.html"); + gBrowser.selectedBrowser.addEventListener("pageshow", function () { + gBrowser.selectedBrowser.removeEventListener("pageshow", arguments.callee, true); + actOnMozImage(gBrowser.contentDocument, "img1", function(image) { + gImages[0] = image; + gFrames = image.framesNotified; // May in theory have frames from last test + // in this counter - so subtract them out + }); + goer.next(); + }, true); + yield; + + // Load next tab somewhat later + gTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer); + gTimer.initWithCallback(function() { + goer.next(); + }, 1500, Ci.nsITimer.TYPE_ONE_SHOT); + yield; + + gBrowser.selectedTab = gBrowser.addTab(TESTROOT + "imageX2.html"); + gBrowser.selectedBrowser.addEventListener("pageshow", function () { + gBrowser.selectedBrowser.removeEventListener("pageshow", arguments.callee, true); + [1,2].forEach(function(i) { + actOnMozImage(gBrowser.contentDocument, "img"+i, function(image) { + gImages[i] = image; + }); + }); + goer.next(); + }, true); + yield; + + var chances = 120; + do { + gTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer); + gTimer.initWithCallback(function() { + if (gImages[0].framesNotified - gFrames >= 10) { + goer.send(true); + } else { + chances--; + goer.send(chances == 0); // maybe if we wait a bit, it will happen + } + }, 500, Ci.nsITimer.TYPE_ONE_SHOT); + } while (!(yield)); + is(chances > 0, true, "Must have been animating while showing several images"); + + // Check they all have the same frame counts + var theFrames = null; + [0,1,2].forEach(function(i) { + var frames = gImages[i].framesNotified; + if (theFrames == null) { + theFrames = frames; + } else { + is(theFrames, frames, "Sharing the same imgContainer means *exactly* the same frame counts!"); + } + }); + + gBrowser.removeCurrentTab(); + gBrowser.removeCurrentTab(); + + nextTest(); + } + + var goer = theTest(); + goer.next(); +} + +var tests = [testBFCache, testSharedContainers]; + +function nextTest() { + if (tests.length == 0) { + finish(); + return; + } + tests.shift()(); +} + +function test() { + ignoreAllUncaughtExceptions(); + nextTest(); +} + diff --git a/image/test/browser/head.js b/image/test/browser/head.js new file mode 100644 index 000000000..91a5f5793 --- /dev/null +++ b/image/test/browser/head.js @@ -0,0 +1,26 @@ +const RELATIVE_DIR = "image/test/browser/"; +const TESTROOT = "http://example.com/browser/" + RELATIVE_DIR; +const TESTROOT2 = "http://example.org/browser/" + RELATIVE_DIR; + +var chrome_root = getRootDirectory(gTestPath); +const CHROMEROOT = chrome_root; + +function getImageLoading(doc, id) { + var htmlImg = doc.getElementById(id); + return htmlImg.QueryInterface(Ci.nsIImageLoadingContent); +} + +// Tries to get the Moz debug image, imgIContainerDebug. Only works +// in a debug build. If we succeed, we call func(). +function actOnMozImage(doc, id, func) { + var imgContainer = getImageLoading(doc, id).getRequest(Ci.nsIImageLoadingContent.CURRENT_REQUEST).image; + var mozImage; + try { + mozImage = imgContainer.QueryInterface(Ci.imgIContainerDebug); + } + catch (e) { + return false; + } + func(mozImage); + return true; +} diff --git a/image/test/browser/image.html b/image/test/browser/image.html new file mode 100644 index 000000000..298bf1bdc --- /dev/null +++ b/image/test/browser/image.html @@ -0,0 +1,24 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> + +<html> + <head> + <title>Imagelib2 animation tests</title> + <style type="text/css"> + #background_div { + border: 1px black solid; + height: 200px; + width: 200px; + margin: 10px; + background: url(animated2.gif) center center no-repeat; + } + </style> + </head> + </head> +<body> + <p>Page with image</p> + <img src="animated.gif" id="img1"> + <div id="background_div"></div> +</body> +</html> + diff --git a/image/test/browser/imageX2.html b/image/test/browser/imageX2.html new file mode 100644 index 000000000..bdacd0888 --- /dev/null +++ b/image/test/browser/imageX2.html @@ -0,0 +1,15 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> + +<html> + <head> + <title>Imagelib2 animation tests</title> + </head> +<body> + <p>Page with images</p> + <img src="animated.gif" id="img1"> + <br> + <img src="animated.gif" id="img2"> +</body> +</html> + |