Bug 1561435 - Format image/, a=automatic-formatting

# ignore-this-changeset

Differential Revision: https://phabricator.services.mozilla.com/D35906

--HG--
extra : source : a224e9d645e49dd7a343f88bd95c0da61aff0f6a
This commit is contained in:
Victor Porof 2019-07-05 10:47:38 +02:00
Родитель 054a393a76
Коммит 06e7696b74
18 изменённых файлов: 2739 добавлений и 1694 удалений

Просмотреть файл

@ -45,7 +45,6 @@ module.exports = {
"overrides": [{ "overrides": [{
"files": [ "files": [
"devtools/**", "devtools/**",
"image/**",
"intl/**", "intl/**",
"ipc/**", "ipc/**",
"js/**", "js/**",

Просмотреть файл

@ -40,7 +40,6 @@ toolkit/components/telemetry/datareporting-prefs.js
toolkit/components/telemetry/healthreport-prefs.js toolkit/components/telemetry/healthreport-prefs.js
# Ignore all top-level directories for now. # Ignore all top-level directories for now.
image/**
intl/** intl/**
ipc/** ipc/**
js/** js/**

Просмотреть файл

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

Просмотреть файл

@ -1,4 +1,3 @@
"use strict"; "use strict";
const SIMPLE_HTML = "data:text/html,<html><head></head><body></body></html>"; const SIMPLE_HTML = "data:text/html,<html><head></head><body></body></html>";
@ -10,8 +9,7 @@ const SIMPLE_HTML = "data:text/html,<html><head></head><body></body></html>";
*/ */
function getManifestDir() { function getManifestDir() {
let path = getTestFilePath("browser_docshell_type_editor"); let path = getTestFilePath("browser_docshell_type_editor");
let file = Cc["@mozilla.org/file/local;1"] let file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile);
.createInstance(Ci.nsIFile);
file.initWithPath(path); file.initWithPath(path);
return file; return file;
} }
@ -28,92 +26,111 @@ add_task(async function() {
let manifestDir = getManifestDir(); let manifestDir = getManifestDir();
Components.manager.addBootstrappedManifestLocation(manifestDir); Components.manager.addBootstrappedManifestLocation(manifestDir);
await BrowserTestUtils.withNewTab({ await BrowserTestUtils.withNewTab(
gBrowser, {
url: SIMPLE_HTML gBrowser,
}, async function(browser) { url: SIMPLE_HTML,
await ContentTask.spawn(browser, null, async function() { },
let rootDocShell = docShell.QueryInterface(Ci.nsIDocShellTreeItem) async function(browser) {
.rootTreeItem await ContentTask.spawn(browser, null, async function() {
.QueryInterface(Ci.nsIInterfaceRequestor) let rootDocShell = docShell
.getInterface(Ci.nsIDocShell); .QueryInterface(Ci.nsIDocShellTreeItem)
let defaultAppType = rootDocShell.appType; .rootTreeItem.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDocShell);
let defaultAppType = rootDocShell.appType;
rootDocShell.appType = Ci.nsIDocShell.APP_TYPE_EDITOR; rootDocShell.appType = Ci.nsIDocShell.APP_TYPE_EDITOR;
is(rootDocShell.appType, Ci.nsIDocShell.APP_TYPE_EDITOR, is(
"sanity check: appType after update should be type editor"); rootDocShell.appType,
Ci.nsIDocShell.APP_TYPE_EDITOR,
"sanity check: appType after update should be type editor"
);
return new Promise(resolve => {
return new Promise(resolve => { let doc = content.document;
let doc = content.document; let image = doc.createElement("img");
let image = doc.createElement("img"); image.onload = function() {
image.onload = function() { ok(true, "APP_TYPE_EDITOR is allowed to load privileged image");
ok(true, "APP_TYPE_EDITOR is allowed to load privileged image"); // restore appType of rootDocShell before moving on to the next test
// restore appType of rootDocShell before moving on to the next test rootDocShell.appType = defaultAppType;
rootDocShell.appType = defaultAppType; resolve();
resolve(); };
} image.onerror = function() {
image.onerror = function() { ok(false, "APP_TYPE_EDITOR is allowed to load privileged image");
ok(false, "APP_TYPE_EDITOR is allowed to load privileged image"); // restore appType of rootDocShell before moving on to the next test
// restore appType of rootDocShell before moving on to the next test rootDocShell.appType = defaultAppType;
rootDocShell.appType = defaultAppType; resolve();
resolve(); };
} doc.body.appendChild(image);
doc.body.appendChild(image); image.src = "chrome://test1/skin/privileged.png";
image.src = "chrome://test1/skin/privileged.png"; });
}); });
}); }
}); );
Components.manager.removeBootstrappedManifestLocation(manifestDir); Components.manager.removeBootstrappedManifestLocation(manifestDir);
}); });
add_task(async function() { add_task(async function() {
info("docshell of appType APP_TYPE_UNKNOWN can *not* access privileged images."); info(
"docshell of appType APP_TYPE_UNKNOWN can *not* access privileged images."
);
// Load a temporary manifest adding a route to a privileged image // Load a temporary manifest adding a route to a privileged image
let manifestDir = getManifestDir(); let manifestDir = getManifestDir();
Components.manager.addBootstrappedManifestLocation(manifestDir); Components.manager.addBootstrappedManifestLocation(manifestDir);
await BrowserTestUtils.withNewTab({ await BrowserTestUtils.withNewTab(
gBrowser, {
url: SIMPLE_HTML gBrowser,
}, async function(browser) { url: SIMPLE_HTML,
await ContentTask.spawn(browser, null, async function() { },
let rootDocShell = docShell.QueryInterface(Ci.nsIDocShellTreeItem) async function(browser) {
.rootTreeItem await ContentTask.spawn(browser, null, async function() {
.QueryInterface(Ci.nsIInterfaceRequestor) let rootDocShell = docShell
.getInterface(Ci.nsIDocShell); .QueryInterface(Ci.nsIDocShellTreeItem)
let defaultAppType = rootDocShell.appType; .rootTreeItem.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDocShell);
let defaultAppType = rootDocShell.appType;
rootDocShell.appType = Ci.nsIDocShell.APP_TYPE_UNKNOWN; rootDocShell.appType = Ci.nsIDocShell.APP_TYPE_UNKNOWN;
is(rootDocShell.appType, Ci.nsIDocShell.APP_TYPE_UNKNOWN, is(
"sanity check: appType of docshell should be unknown"); rootDocShell.appType,
Ci.nsIDocShell.APP_TYPE_UNKNOWN,
"sanity check: appType of docshell should be unknown"
);
return new Promise(resolve => { return new Promise(resolve => {
let doc = content.document; let doc = content.document;
let image = doc.createElement("img"); let image = doc.createElement("img");
image.onload = function() { image.onload = function() {
ok(false, "APP_TYPE_UNKNOWN is *not* allowed to acces privileged image"); ok(
// restore appType of rootDocShell before moving on to the next test false,
rootDocShell.appType = defaultAppType; "APP_TYPE_UNKNOWN is *not* allowed to acces privileged image"
resolve(); );
} // restore appType of rootDocShell before moving on to the next test
image.onerror = function() { rootDocShell.appType = defaultAppType;
ok(true, "APP_TYPE_UNKNOWN is *not* allowed to acces privileged image"); resolve();
// restore appType of rootDocShell before moving on to the next test };
rootDocShell.appType = defaultAppType; image.onerror = function() {
resolve(); ok(
} true,
doc.body.appendChild(image); "APP_TYPE_UNKNOWN is *not* allowed to acces privileged image"
// Set the src via wrappedJSObject so the load is triggered with );
// the content page's principal rather than ours. // restore appType of rootDocShell before moving on to the next test
image.wrappedJSObject.src = "chrome://test1/skin/privileged.png"; rootDocShell.appType = defaultAppType;
resolve();
};
doc.body.appendChild(image);
// Set the src via wrappedJSObject so the load is triggered with
// the content page's principal rather than ours.
image.wrappedJSObject.src = "chrome://test1/skin/privileged.png";
});
}); });
}); }
}); );
Components.manager.removeBootstrappedManifestLocation(manifestDir); Components.manager.removeBootstrappedManifestLocation(manifestDir);
}); });

Просмотреть файл

@ -11,20 +11,29 @@ function testBFCache() {
function theTest() { function theTest() {
var abort = false; var abort = false;
var chances, gImage, gFrames; var chances, gImage, gFrames;
gBrowser.selectedTab = BrowserTestUtils.addTab(gBrowser, TESTROOT + "image.html"); gBrowser.selectedTab = BrowserTestUtils.addTab(
gBrowser.selectedBrowser.addEventListener("pageshow", function () { gBrowser,
var window = gBrowser.contentWindow; TESTROOT + "image.html"
// If false, we are in an optimized build, and we abort this and );
// all further tests gBrowser.selectedBrowser.addEventListener(
if (!actOnMozImage(window.document, "img1", function(image) { "pageshow",
gImage = image; function() {
gFrames = gImage.framesNotified; var window = gBrowser.contentWindow;
})) { // If false, we are in an optimized build, and we abort this and
gBrowser.removeCurrentTab(); // all further tests
abort = true; if (
} !actOnMozImage(window.document, "img1", function(image) {
goer.next(); gImage = image;
}, {capture: true, once: true}); gFrames = gImage.framesNotified;
})
) {
gBrowser.removeCurrentTab();
abort = true;
}
goer.next();
},
{ capture: true, once: true }
);
yield; yield;
if (abort) { if (abort) {
finish(); finish();
@ -35,15 +44,19 @@ function testBFCache() {
chances = 120; chances = 120;
do { do {
gTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer); gTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
gTimer.initWithCallback(function() { gTimer.initWithCallback(
if (gImage.framesNotified >= 20) { function() {
goer.send(true); if (gImage.framesNotified >= 20) {
} else { goer.send(true);
chances--; } else {
goer.send(chances == 0); // maybe if we wait a bit, it will happen chances--;
} goer.send(chances == 0); // maybe if we wait a bit, it will happen
}, 500, Ci.nsITimer.TYPE_ONE_SHOT); }
} while (!(yield)); },
500,
Ci.nsITimer.TYPE_ONE_SHOT
);
} while (!yield);
is(chances > 0, true, "Must have animated a few frames so far"); is(chances > 0, true, "Must have animated a few frames so far");
// Browse elsewhere; push our animating page into the bfcache // Browse elsewhere; push our animating page into the bfcache
@ -52,16 +65,30 @@ function testBFCache() {
// Wait a bit for page to fully load, then wait a while and // Wait a bit for page to fully load, then wait a while and
// see that no animation occurs. // see that no animation occurs.
gTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer); gTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
gTimer.initWithCallback(function() { gTimer.initWithCallback(
gFrames = gImage.framesNotified; function() {
gTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer); gFrames = gImage.framesNotified;
gTimer.initWithCallback(function() { gTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
// Might have a few stray frames, until other page totally loads gTimer.initWithCallback(
var additionalFrames = gImage.framesNotified - gFrames; function() {
is(additionalFrames == 0, true, "Must have not animated in bfcache! Got " + additionalFrames + " additional frames"); // Might have a few stray frames, until other page totally loads
goer.next(); var additionalFrames = gImage.framesNotified - gFrames;
}, 4000, Ci.nsITimer.TYPE_ONE_SHOT); // 4 seconds - expect 40 frames is(
}, 0, Ci.nsITimer.TYPE_ONE_SHOT); // delay of 0 - wait for next event loop 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; yield;
// Go back // Go back
@ -70,15 +97,19 @@ function testBFCache() {
chances = 120; chances = 120;
do { do {
gTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer); gTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
gTimer.initWithCallback(function() { gTimer.initWithCallback(
if (gImage.framesNotified - gFrames >= 20) { function() {
goer.send(true); if (gImage.framesNotified - gFrames >= 20) {
} else { goer.send(true);
chances--; } else {
goer.send(chances == 0); // maybe if we wait a bit, it will happen chances--;
} goer.send(chances == 0); // maybe if we wait a bit, it will happen
}, 500, Ci.nsITimer.TYPE_ONE_SHOT); }
} while (!(yield)); },
500,
Ci.nsITimer.TYPE_ONE_SHOT
);
} while (!yield);
is(chances > 0, true, "Must have animated once out of bfcache!"); is(chances > 0, true, "Must have animated once out of bfcache!");
// Finally, check that the css background image has essentially the same // Finally, check that the css background image has essentially the same
@ -90,9 +121,17 @@ function testBFCache() {
var div = doc.getElementById("background_div"); var div = doc.getElementById("background_div");
div.innerHTML += '<img src="animated2.gif" id="img3">'; div.innerHTML += '<img src="animated2.gif" id="img3">';
actOnMozImage(doc, "img3", function(image) { actOnMozImage(doc, "img3", function(image) {
is(Math.abs(image.framesNotified - gImage.framesNotified)/gImage.framesNotified < 0.5, true, is(
"Must have also animated the background image, and essentially the same # of frames. " + Math.abs(image.framesNotified - gImage.framesNotified) /
"Regular image got " + gImage.framesNotified + " frames but background image got " + image.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(); gBrowser.removeCurrentTab();
@ -111,57 +150,87 @@ function testSharedContainers() {
var gImages = []; var gImages = [];
var gFrames; var gFrames;
gBrowser.selectedTab = BrowserTestUtils.addTab(gBrowser, TESTROOT + "image.html"); gBrowser.selectedTab = BrowserTestUtils.addTab(
gBrowser.selectedBrowser.addEventListener("pageshow", function () { gBrowser,
actOnMozImage(gBrowser.contentDocument, "img1", function(image) { TESTROOT + "image.html"
gImages[0] = image; );
gFrames = image.framesNotified; // May in theory have frames from last test gBrowser.selectedBrowser.addEventListener(
// in this counter - so subtract them out "pageshow",
}); function() {
goer.next(); actOnMozImage(gBrowser.contentDocument, "img1", function(image) {
}, {capture: true, once: true}); gImages[0] = image;
gFrames = image.framesNotified; // May in theory have frames from last test
// in this counter - so subtract them out
});
goer.next();
},
{ capture: true, once: true }
);
yield; yield;
// Load next tab somewhat later // Load next tab somewhat later
gTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer); gTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
gTimer.initWithCallback(function() { gTimer.initWithCallback(
goer.next(); function() {
}, 1500, Ci.nsITimer.TYPE_ONE_SHOT); goer.next();
},
1500,
Ci.nsITimer.TYPE_ONE_SHOT
);
yield; yield;
gBrowser.selectedTab = BrowserTestUtils.addTab(gBrowser, TESTROOT + "imageX2.html"); gBrowser.selectedTab = BrowserTestUtils.addTab(
gBrowser.selectedBrowser.addEventListener("pageshow", function () { gBrowser,
[1,2].forEach(function(i) { TESTROOT + "imageX2.html"
actOnMozImage(gBrowser.contentDocument, "img"+i, function(image) { );
gImages[i] = image; gBrowser.selectedBrowser.addEventListener(
"pageshow",
function() {
[1, 2].forEach(function(i) {
actOnMozImage(gBrowser.contentDocument, "img" + i, function(image) {
gImages[i] = image;
});
}); });
}); goer.next();
goer.next(); },
}, {capture: true, once: true}); { capture: true, once: true }
);
yield; yield;
var chances = 120; var chances = 120;
do { do {
gTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer); gTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
gTimer.initWithCallback(function() { gTimer.initWithCallback(
if (gImages[0].framesNotified - gFrames >= 10) { function() {
goer.send(true); if (gImages[0].framesNotified - gFrames >= 10) {
} else { goer.send(true);
chances--; } else {
goer.send(chances == 0); // maybe if we wait a bit, it will happen 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"); 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 // Check they all have the same frame counts
var theFrames = null; var theFrames = null;
[0,1,2].forEach(function(i) { [0, 1, 2].forEach(function(i) {
var frames = gImages[i].framesNotified; var frames = gImages[i].framesNotified;
if (theFrames == null) { if (theFrames == null) {
theFrames = frames; theFrames = frames;
} else { } else {
is(theFrames, frames, "Sharing the same imgContainer means *exactly* the same frame counts!"); is(
theFrames,
frames,
"Sharing the same imgContainer means *exactly* the same frame counts!"
);
} }
}); });
@ -189,4 +258,3 @@ function test() {
ignoreAllUncaughtExceptions(); ignoreAllUncaughtExceptions();
nextTest(); nextTest();
} }

Просмотреть файл

@ -12,12 +12,13 @@ function getImageLoading(doc, id) {
// Tries to get the Moz debug image, imgIContainerDebug. Only works // Tries to get the Moz debug image, imgIContainerDebug. Only works
// in a debug build. If we succeed, we call func(). // in a debug build. If we succeed, we call func().
function actOnMozImage(doc, id, func) { function actOnMozImage(doc, id, func) {
var imgContainer = getImageLoading(doc, id).getRequest(Ci.nsIImageLoadingContent.CURRENT_REQUEST).image; var imgContainer = getImageLoading(doc, id).getRequest(
Ci.nsIImageLoadingContent.CURRENT_REQUEST
).image;
var mozImage; var mozImage;
try { try {
mozImage = imgContainer.QueryInterface(Ci.imgIContainerDebug); mozImage = imgContainer.QueryInterface(Ci.imgIContainerDebug);
} } catch (e) {
catch (e) {
return false; return false;
} }
func(mozImage); func(mozImage);

Просмотреть файл

@ -3,49 +3,56 @@ var currentTest;
var gIsRefImageLoaded = false; var gIsRefImageLoaded = false;
const gShouldOutputDebugInfo = false; const gShouldOutputDebugInfo = false;
function pollForSuccess() function pollForSuccess() {
{
if (!currentTest.isTestFinished) { if (!currentTest.isTestFinished) {
if (!currentTest.reusingReferenceImage || (currentTest.reusingReferenceImage if (
&& gRefImageLoaded)) { !currentTest.reusingReferenceImage ||
(currentTest.reusingReferenceImage && gRefImageLoaded)
) {
currentTest.checkImage(); currentTest.checkImage();
} }
setTimeout(pollForSuccess, currentTest.pollFreq); setTimeout(pollForSuccess, currentTest.pollFreq);
} }
}; }
function referencePoller() function referencePoller() {
{
currentTest.takeReferenceSnapshot(); currentTest.takeReferenceSnapshot();
} }
function reuseImageCallback() function reuseImageCallback() {
{
gIsRefImageLoaded = true; gIsRefImageLoaded = true;
} }
function failTest() function failTest() {
{
if (currentTest.isTestFinished || currentTest.closeFunc) { if (currentTest.isTestFinished || currentTest.closeFunc) {
return; return;
} }
ok(false, "timing out after " + currentTest.timeout + "ms. " ok(
+ "Animated image still doesn't look correct, after poll #" false,
+ currentTest.pollCounter); "timing out after " +
currentTest.timeout +
"ms. " +
"Animated image still doesn't look correct, after poll #" +
currentTest.pollCounter
);
currentTest.wereFailures = true; currentTest.wereFailures = true;
if (currentTest.currentSnapshotDataURI) { if (currentTest.currentSnapshotDataURI) {
currentTest.outputDebugInfo("Snapshot #" + currentTest.pollCounter, currentTest.outputDebugInfo(
"snapNum" + currentTest.pollCounter, "Snapshot #" + currentTest.pollCounter,
currentTest.currentSnapshotDataURI); "snapNum" + currentTest.pollCounter,
currentTest.currentSnapshotDataURI
);
} }
currentTest.enableDisplay(document.getElementById(currentTest.debugElementId)); currentTest.enableDisplay(
document.getElementById(currentTest.debugElementId)
);
currentTest.cleanUpAndFinish(); currentTest.cleanUpAndFinish();
}; }
/** /**
* Create a new AnimationTest object. * Create a new AnimationTest object.
@ -75,9 +82,17 @@ function failTest()
* chain tests together, so they are all finished exactly once. * chain tests together, so they are all finished exactly once.
* @returns {AnimationTest} * @returns {AnimationTest}
*/ */
function AnimationTest(pollFreq, timeout, referenceElementId, imageElementId, function AnimationTest(
debugElementId, cleanId, srcAttr, xulTest, closeFunc) pollFreq,
{ timeout,
referenceElementId,
imageElementId,
debugElementId,
cleanId,
srcAttr,
xulTest,
closeFunc
) {
// We want to test the cold loading behavior, so clear cache in case an // We want to test the cold loading behavior, so clear cache in case an
// earlier test got our image in there already. // earlier test got our image in there already.
clearAllImageCaches(); clearAllImageCaches();
@ -103,24 +118,24 @@ function AnimationTest(pollFreq, timeout, referenceElementId, imageElementId,
this.numRefsTaken = 0; this.numRefsTaken = 0;
this.blankWaitTime = 0; this.blankWaitTime = 0;
this.cleanId = cleanId ? cleanId : ''; this.cleanId = cleanId ? cleanId : "";
this.xulTest = xulTest ? xulTest : ''; this.xulTest = xulTest ? xulTest : "";
this.closeFunc = closeFunc ? closeFunc : ''; this.closeFunc = closeFunc ? closeFunc : "";
}; }
AnimationTest.prototype.preloadImage = function() AnimationTest.prototype.preloadImage = function() {
{
if (this.srcAttr) { if (this.srcAttr) {
this.myImage = new Image(); this.myImage = new Image();
this.myImage.onload = function() { currentTest.continueTest(); }; this.myImage.onload = function() {
currentTest.continueTest();
};
this.myImage.src = this.srcAttr; this.myImage.src = this.srcAttr;
} else { } else {
this.continueTest(); this.continueTest();
} }
}; };
AnimationTest.prototype.outputDebugInfo = function(message, id, dataUri) AnimationTest.prototype.outputDebugInfo = function(message, id, dataUri) {
{
if (!gShouldOutputDebugInfo) { if (!gShouldOutputDebugInfo) {
return; return;
} }
@ -135,13 +150,11 @@ AnimationTest.prototype.outputDebugInfo = function(message, id, dataUri)
todo(false, "Debug (" + id + "): " + message + " " + dataUri); todo(false, "Debug (" + id + "): " + message + " " + dataUri);
}; };
AnimationTest.prototype.isFinished = function() AnimationTest.prototype.isFinished = function() {
{
return this.isTestFinished; return this.isTestFinished;
}; };
AnimationTest.prototype.takeCleanSnapshot = function() AnimationTest.prototype.takeCleanSnapshot = function() {
{
var cleanElement; var cleanElement;
if (this.cleanId) { if (this.cleanId) {
cleanElement = document.getElementById(this.cleanId); cleanElement = document.getElementById(this.cleanId);
@ -161,18 +174,23 @@ AnimationTest.prototype.takeCleanSnapshot = function()
} }
var dataString1 = "Clean Snapshot"; var dataString1 = "Clean Snapshot";
this.outputDebugInfo(dataString1, 'cleanSnap', this.outputDebugInfo(
this.cleanSnapshot.toDataURL()); dataString1,
"cleanSnap",
this.cleanSnapshot.toDataURL()
);
}; };
AnimationTest.prototype.takeBlankSnapshot = function() AnimationTest.prototype.takeBlankSnapshot = function() {
{
// Take a snapshot of the initial (essentially blank) page // Take a snapshot of the initial (essentially blank) page
this.blankSnapshot = snapshotWindow(window, false); this.blankSnapshot = snapshotWindow(window, false);
var dataString1 = "Initial Blank Snapshot"; var dataString1 = "Initial Blank Snapshot";
this.outputDebugInfo(dataString1, 'blank1Snap', this.outputDebugInfo(
this.blankSnapshot.toDataURL()); dataString1,
"blank1Snap",
this.blankSnapshot.toDataURL()
);
}; };
/** /**
@ -182,8 +200,7 @@ AnimationTest.prototype.takeBlankSnapshot = function()
* image, if applicable, and then asynchronously call continueTest(), or if not * image, if applicable, and then asynchronously call continueTest(), or if not
* applicable, synchronously trigger a call to continueTest(). * applicable, synchronously trigger a call to continueTest().
*/ */
AnimationTest.prototype.beginTest = function() AnimationTest.prototype.beginTest = function() {
{
SimpleTest.waitForExplicitFinish(); SimpleTest.waitForExplicitFinish();
SimpleTest.requestFlakyTimeout("untriaged"); SimpleTest.requestFlakyTimeout("untriaged");
@ -196,8 +213,7 @@ AnimationTest.prototype.beginTest = function()
* beginTest() either synchronously or asynchronously, as an image load * beginTest() either synchronously or asynchronously, as an image load
* callback. * callback.
*/ */
AnimationTest.prototype.continueTest = function() AnimationTest.prototype.continueTest = function() {
{
// In case something goes wrong, fail earlier than mochitest timeout, // In case something goes wrong, fail earlier than mochitest timeout,
// and with more information. // and with more information.
setTimeout(failTest, this.timeout); setTimeout(failTest, this.timeout);
@ -211,34 +227,35 @@ AnimationTest.prototype.continueTest = function()
SimpleTest.executeSoon(pollForSuccess); SimpleTest.executeSoon(pollForSuccess);
}; };
AnimationTest.prototype.setupPolledImage = function () AnimationTest.prototype.setupPolledImage = function() {
{
// Make sure the image is visible // Make sure the image is visible
if (!this.reusingImageAsReference) { if (!this.reusingImageAsReference) {
this.enableDisplay(document.getElementById(this.imageElementId)); this.enableDisplay(document.getElementById(this.imageElementId));
var currentSnapshot = snapshotWindow(window, false); var currentSnapshot = snapshotWindow(window, false);
var result = compareSnapshots(currentSnapshot, var result = compareSnapshots(
this.referenceSnapshot, true); currentSnapshot,
this.referenceSnapshot,
true
);
this.currentSnapshotDataURI = currentSnapshot.toDataURL(); this.currentSnapshotDataURI = currentSnapshot.toDataURL();
if (result[0]) { if (result[0]) {
// SUCCESS! // SUCCESS!
ok(true, "Animated image looks correct, at poll #" ok(true, "Animated image looks correct, at poll #" + this.pollCounter);
+ this.pollCounter);
this.cleanUpAndFinish(); this.cleanUpAndFinish();
} }
} else if (!gIsRefImageLoaded) { } else if (!gIsRefImageLoaded) {
this.myImage = new Image(); this.myImage = new Image();
this.myImage.onload = reuseImageCallback; this.myImage.onload = reuseImageCallback;
document.getElementById(this.imageElementId).setAttribute('src', document
this.referenceElementId); .getElementById(this.imageElementId)
} .setAttribute("src", this.referenceElementId);
} }
};
AnimationTest.prototype.checkImage = function () AnimationTest.prototype.checkImage = function() {
{
if (this.isTestFinished) { if (this.isTestFinished) {
return; return;
} }
@ -258,15 +275,13 @@ AnimationTest.prototype.checkImage = function ()
if (result[0]) { if (result[0]) {
// SUCCESS! // SUCCESS!
ok(true, "Animated image looks correct, at poll #" ok(true, "Animated image looks correct, at poll #" + this.pollCounter);
+ this.pollCounter);
this.cleanUpAndFinish(); this.cleanUpAndFinish();
} }
}; };
AnimationTest.prototype.takeReferenceSnapshot = function () AnimationTest.prototype.takeReferenceSnapshot = function() {
{
this.numRefsTaken++; this.numRefsTaken++;
// Test to make sure the reference image doesn't match a clean snapshot // Test to make sure the reference image doesn't match a clean snapshot
@ -286,15 +301,20 @@ AnimationTest.prototype.takeReferenceSnapshot = function ()
this.referenceSnapshot = snapshotWindow(window, false); this.referenceSnapshot = snapshotWindow(window, false);
var snapResult = compareSnapshots(this.cleanSnapshot, var snapResult = compareSnapshots(
this.referenceSnapshot, false); this.cleanSnapshot,
this.referenceSnapshot,
false
);
if (!snapResult[0]) { if (!snapResult[0]) {
if (this.blankWaitTime > 2000) { if (this.blankWaitTime > 2000) {
// if it took longer than two seconds to load the image, we probably // if it took longer than two seconds to load the image, we probably
// have a problem. // have a problem.
this.wereFailures = true; this.wereFailures = true;
ok(snapResult[0], ok(
"Reference snapshot shouldn't match clean (non-image) snapshot"); snapResult[0],
"Reference snapshot shouldn't match clean (non-image) snapshot"
);
} else { } else {
this.blankWaitTime += currentTest.pollFreq; this.blankWaitTime += currentTest.pollFreq;
// let's wait a bit and see if it clears up // let's wait a bit and see if it clears up
@ -303,12 +323,17 @@ AnimationTest.prototype.takeReferenceSnapshot = function ()
} }
} }
ok(snapResult[0], ok(
"Reference snapshot shouldn't match clean (non-image) snapshot"); snapResult[0],
"Reference snapshot shouldn't match clean (non-image) snapshot"
);
var dataString = "Reference Snapshot #" + this.numRefsTaken; var dataString = "Reference Snapshot #" + this.numRefsTaken;
this.outputDebugInfo(dataString, 'refSnapId', this.outputDebugInfo(
this.referenceSnapshot.toDataURL()); dataString,
"refSnapId",
this.referenceSnapshot.toDataURL()
);
} else { } else {
// Make sure the animation section is hidden // Make sure the animation section is hidden
this.disableDisplay(document.getElementById(this.imageElementId)); this.disableDisplay(document.getElementById(this.imageElementId));
@ -318,15 +343,20 @@ AnimationTest.prototype.takeReferenceSnapshot = function ()
this.enableDisplay(referenceDiv); this.enableDisplay(referenceDiv);
this.referenceSnapshot = snapshotWindow(window, false); this.referenceSnapshot = snapshotWindow(window, false);
var snapResult = compareSnapshots(this.cleanSnapshot, var snapResult = compareSnapshots(
this.referenceSnapshot, false); this.cleanSnapshot,
this.referenceSnapshot,
false
);
if (!snapResult[0]) { if (!snapResult[0]) {
if (this.blankWaitTime > 2000) { if (this.blankWaitTime > 2000) {
// if it took longer than two seconds to load the image, we probably // if it took longer than two seconds to load the image, we probably
// have a problem. // have a problem.
this.wereFailures = true; this.wereFailures = true;
ok(snapResult[0], ok(
"Reference snapshot shouldn't match clean (non-image) snapshot"); snapResult[0],
"Reference snapshot shouldn't match clean (non-image) snapshot"
);
} else { } else {
this.blankWaitTime += 20; this.blankWaitTime += 20;
// let's wait a bit and see if it clears up // let's wait a bit and see if it clears up
@ -335,12 +365,17 @@ AnimationTest.prototype.takeReferenceSnapshot = function ()
} }
} }
ok(snapResult[0], ok(
"Reference snapshot shouldn't match clean (non-image) snapshot"); snapResult[0],
"Reference snapshot shouldn't match clean (non-image) snapshot"
);
var dataString = "Reference Snapshot #" + this.numRefsTaken; var dataString = "Reference Snapshot #" + this.numRefsTaken;
this.outputDebugInfo(dataString, 'refSnapId', this.outputDebugInfo(
this.referenceSnapshot.toDataURL()); dataString,
"refSnapId",
this.referenceSnapshot.toDataURL()
);
// Re-hide reference div, and take another snapshot to be sure it's gone // Re-hide reference div, and take another snapshot to be sure it's gone
this.disableDisplay(referenceDiv); this.disableDisplay(referenceDiv);
@ -348,47 +383,46 @@ AnimationTest.prototype.takeReferenceSnapshot = function ()
} }
}; };
AnimationTest.prototype.enableDisplay = function(element) AnimationTest.prototype.enableDisplay = function(element) {
{
if (!element) { if (!element) {
return; return;
} }
if (!this.xulTest) { if (!this.xulTest) {
element.style.display = ''; element.style.display = "";
} else { } else {
element.setAttribute('hidden', 'false'); element.setAttribute("hidden", "false");
} }
}; };
AnimationTest.prototype.disableDisplay = function(element) AnimationTest.prototype.disableDisplay = function(element) {
{
if (!element) { if (!element) {
return; return;
} }
if (!this.xulTest) { if (!this.xulTest) {
element.style.display = 'none'; element.style.display = "none";
} else { } else {
element.setAttribute('hidden', 'true'); element.setAttribute("hidden", "true");
} }
}; };
AnimationTest.prototype.testBlankCameBack = function() AnimationTest.prototype.testBlankCameBack = function() {
{
var blankSnapshot2 = snapshotWindow(window, false); var blankSnapshot2 = snapshotWindow(window, false);
var result = compareSnapshots(this.blankSnapshot, blankSnapshot2, true); var result = compareSnapshots(this.blankSnapshot, blankSnapshot2, true);
ok(result[0], "Reference image should disappear when it becomes display:none"); ok(
result[0],
"Reference image should disappear when it becomes display:none"
);
if (!result[0]) { if (!result[0]) {
this.wereFailures = true; this.wereFailures = true;
var dataString = "Second Blank Snapshot"; var dataString = "Second Blank Snapshot";
this.outputDebugInfo(dataString, 'blank2SnapId', result[2]); this.outputDebugInfo(dataString, "blank2SnapId", result[2]);
} }
}; };
AnimationTest.prototype.cleanUpAndFinish = function () AnimationTest.prototype.cleanUpAndFinish = function() {
{
// On the off chance that failTest and checkImage are triggered // On the off chance that failTest and checkImage are triggered
// back-to-back, use a flag to prevent multiple calls to SimpleTest.finish. // back-to-back, use a flag to prevent multiple calls to SimpleTest.finish.
if (this.isTestFinished) { if (this.isTestFinished) {
@ -404,7 +438,7 @@ AnimationTest.prototype.cleanUpAndFinish = function ()
} }
if (this.wereFailures) { if (this.wereFailures) {
document.getElementById(this.debugElementId).style.display = 'block'; document.getElementById(this.debugElementId).style.display = "block";
} }
SimpleTest.finish(); SimpleTest.finish();

Просмотреть файл

@ -1,54 +1,51 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */ /* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
// Helper file for shared image functionality // Helper file for shared image functionality
// //
// Note that this is use by tests elsewhere in the source tree. When in doubt, // Note that this is use by tests elsewhere in the source tree. When in doubt,
// check mxr before removing or changing functionality. // check mxr before removing or changing functionality.
// Helper function to clear both the content and chrome image caches // Helper function to clear both the content and chrome image caches
function clearAllImageCaches() function clearAllImageCaches() {
{ var tools = SpecialPowers.Cc["@mozilla.org/image/tools;1"].getService(
var tools = SpecialPowers.Cc["@mozilla.org/image/tools;1"] SpecialPowers.Ci.imgITools
.getService(SpecialPowers.Ci.imgITools); );
var imageCache = tools.getImgCacheForDocument(window.document); var imageCache = tools.getImgCacheForDocument(window.document);
imageCache.clearCache(true); // true=chrome imageCache.clearCache(true); // true=chrome
imageCache.clearCache(false); // false=content imageCache.clearCache(false); // false=content
} }
// Helper function to clear the image cache of content images // Helper function to clear the image cache of content images
function clearImageCache() function clearImageCache() {
{ var tools = SpecialPowers.Cc["@mozilla.org/image/tools;1"].getService(
var tools = SpecialPowers.Cc["@mozilla.org/image/tools;1"] SpecialPowers.Ci.imgITools
.getService(SpecialPowers.Ci.imgITools); );
var imageCache = tools.getImgCacheForDocument(window.document); var imageCache = tools.getImgCacheForDocument(window.document);
imageCache.clearCache(false); // true=chrome, false=content imageCache.clearCache(false); // true=chrome, false=content
} }
// Helper function to determine if the frame is decoded for a given image id // Helper function to determine if the frame is decoded for a given image id
function isFrameDecoded(id) function isFrameDecoded(id) {
{ return getImageStatus(id) & SpecialPowers.Ci.imgIRequest.STATUS_FRAME_COMPLETE
return (getImageStatus(id) & ? true
SpecialPowers.Ci.imgIRequest.STATUS_FRAME_COMPLETE) : false;
? true : false;
} }
// Helper function to determine if the image is loaded for a given image id // Helper function to determine if the image is loaded for a given image id
function isImageLoaded(id) function isImageLoaded(id) {
{ return getImageStatus(id) & SpecialPowers.Ci.imgIRequest.STATUS_LOAD_COMPLETE
return (getImageStatus(id) & ? true
SpecialPowers.Ci.imgIRequest.STATUS_LOAD_COMPLETE) : false;
? true : false;
} }
// Helper function to get the status flags of an image // Helper function to get the status flags of an image
function getImageStatus(id) function getImageStatus(id) {
{
// Get the image // Get the image
var img = SpecialPowers.wrap(document.getElementById(id)); var img = SpecialPowers.wrap(document.getElementById(id));
// Get the request // Get the request
var request = img.getRequest(SpecialPowers.Ci var request = img.getRequest(
.nsIImageLoadingContent SpecialPowers.Ci.nsIImageLoadingContent.CURRENT_REQUEST
.CURRENT_REQUEST); );
// Return the status // Return the status
return request.imageStatus; return request.imageStatus;
@ -56,8 +53,7 @@ function getImageStatus(id)
// Forces a synchronous decode of an image by drawing it to a canvas. Only // Forces a synchronous decode of an image by drawing it to a canvas. Only
// really meaningful if the image is fully loaded first // really meaningful if the image is fully loaded first
function forceDecode(id) function forceDecode(id) {
{
// Get the image // Get the image
var img = document.getElementById(id); var img = document.getElementById(id);
@ -69,25 +65,36 @@ function forceDecode(id)
ctx.drawImage(img, 0, 0); ctx.drawImage(img, 0, 0);
} }
// Functions to facilitate getting/setting various image-related prefs // Functions to facilitate getting/setting various image-related prefs
// //
// If you change a pref in a mochitest, Don't forget to reset it to its // If you change a pref in a mochitest, Don't forget to reset it to its
// original value! // original value!
// //
// Null indicates no pref set // Null indicates no pref set
const DISCARD_ENABLED_PREF = {name: "discardable", branch: "image.mem.", type: "bool"}; const DISCARD_ENABLED_PREF = {
const DECODEONDRAW_ENABLED_PREF = {name: "decodeondraw", branch: "image.mem.", type: "bool"}; name: "discardable",
const DISCARD_TIMEOUT_PREF = {name: "min_discard_timeout_ms", branch: "image.mem.", type: "int"}; branch: "image.mem.",
type: "bool",
};
const DECODEONDRAW_ENABLED_PREF = {
name: "decodeondraw",
branch: "image.mem.",
type: "bool",
};
const DISCARD_TIMEOUT_PREF = {
name: "min_discard_timeout_ms",
branch: "image.mem.",
type: "int",
};
function setImagePref(pref, val) function setImagePref(pref, val) {
{ var prefService = SpecialPowers.Cc[
var prefService = SpecialPowers.Cc["@mozilla.org/preferences-service;1"] "@mozilla.org/preferences-service;1"
.getService(SpecialPowers.Ci.nsIPrefService); ].getService(SpecialPowers.Ci.nsIPrefService);
var branch = prefService.getBranch(pref.branch); var branch = prefService.getBranch(pref.branch);
if (val != null) { if (val != null) {
switch(pref.type) { switch (pref.type) {
case "bool": case "bool":
branch.setBoolPref(pref.name, val); branch.setBoolPref(pref.name, val);
break; break;
@ -97,15 +104,15 @@ function setImagePref(pref, val)
default: default:
throw new Error("Unknown pref type"); throw new Error("Unknown pref type");
} }
} } else if (branch.prefHasUserValue(pref.name)) {
else if (branch.prefHasUserValue(pref.name))
branch.clearUserPref(pref.name); branch.clearUserPref(pref.name);
}
} }
function getImagePref(pref) function getImagePref(pref) {
{ var prefService = SpecialPowers.Cc[
var prefService = SpecialPowers.Cc["@mozilla.org/preferences-service;1"] "@mozilla.org/preferences-service;1"
.getService(SpecialPowers.Ci.nsIPrefService); ].getService(SpecialPowers.Ci.nsIPrefService);
var branch = prefService.getBranch(pref.branch); var branch = prefService.getBranch(pref.branch);
if (branch.prefHasUserValue(pref.name)) { if (branch.prefHasUserValue(pref.name)) {
switch (pref.type) { switch (pref.type) {
@ -116,20 +123,19 @@ function getImagePref(pref)
default: default:
throw new Error("Unknown pref type"); throw new Error("Unknown pref type");
} }
} } else {
else
return null; return null;
}
} }
// JS implementation of imgIScriptedNotificationObserver with stubs for all of its methods. // JS implementation of imgIScriptedNotificationObserver with stubs for all of its methods.
function ImageDecoderObserverStub() function ImageDecoderObserverStub() {
{ this.sizeAvailable = function sizeAvailable(aRequest) {};
this.sizeAvailable = function sizeAvailable(aRequest) {} this.frameComplete = function frameComplete(aRequest) {};
this.frameComplete = function frameComplete(aRequest) {} this.decodeComplete = function decodeComplete(aRequest) {};
this.decodeComplete = function decodeComplete(aRequest) {} this.loadComplete = function loadComplete(aRequest) {};
this.loadComplete = function loadComplete(aRequest) {} this.frameUpdate = function frameUpdate(aRequest) {};
this.frameUpdate = function frameUpdate(aRequest) {} this.discard = function discard(aRequest) {};
this.discard = function discard(aRequest) {} this.isAnimated = function isAnimated(aRequest) {};
this.isAnimated = function isAnimated(aRequest) {} this.hasTransparency = function hasTransparency(aRequest) {};
this.hasTransparency = function hasTransparency(aRequest) {}
} }

Просмотреть файл

@ -6,23 +6,21 @@
* var uri. * var uri.
*/ */
const {HttpServer} = ChromeUtils.import("resource://testing-common/httpd.js"); const { HttpServer } = ChromeUtils.import("resource://testing-common/httpd.js");
const {NetUtil} = ChromeUtils.import("resource://gre/modules/NetUtil.jsm"); const { NetUtil } = ChromeUtils.import("resource://gre/modules/NetUtil.jsm");
var server = new HttpServer(); var server = new HttpServer();
server.registerDirectory("/", do_get_file('')); server.registerDirectory("/", do_get_file(""));
server.registerContentType("sjs", "sjs"); server.registerContentType("sjs", "sjs");
server.start(-1); server.start(-1);
load("image_load_helpers.js");
load('image_load_helpers.js');
var requests = []; var requests = [];
// Return a closure that holds on to the listener from the original // Return a closure that holds on to the listener from the original
// imgIRequest, and compares its results to the cloned one. // imgIRequest, and compares its results to the cloned one.
function getCloneStopCallback(original_listener) function getCloneStopCallback(original_listener) {
{
return function cloneStop(listener) { return function cloneStop(listener) {
Assert.equal(original_listener.state, listener.state); Assert.equal(original_listener.state, listener.state);
@ -30,35 +28,38 @@ function getCloneStopCallback(original_listener)
// twice. // twice.
Assert.notEqual(original_listener, listener); Assert.notEqual(original_listener, listener);
do_test_finished(); do_test_finished();
} };
} }
// Make sure that cloned requests get all the same callbacks as the original, // Make sure that cloned requests get all the same callbacks as the original,
// but they aren't synchronous right now. // but they aren't synchronous right now.
function checkClone(other_listener, aRequest) function checkClone(other_listener, aRequest) {
{
do_test_pending(); do_test_pending();
// For as long as clone notification is synchronous, we can't test the clone state reliably. // For as long as clone notification is synchronous, we can't test the clone state reliably.
var listener = new ImageListener(null, function(foo, bar) { do_test_finished(); } /* getCloneStopCallback(other_listener)*/); var listener = new ImageListener(
null,
function(foo, bar) {
do_test_finished();
} /* getCloneStopCallback(other_listener)*/
);
listener.synchronous = false; listener.synchronous = false;
var outer = Cc["@mozilla.org/image/tools;1"].getService(Ci.imgITools) var outer = Cc["@mozilla.org/image/tools;1"]
.createScriptedObserver(listener); .getService(Ci.imgITools)
.createScriptedObserver(listener);
var clone = aRequest.clone(outer); var clone = aRequest.clone(outer);
requests.push({ request: clone, locked: false }); requests.push({ request: clone, locked: false });
} }
// Ensure that all the callbacks were called on aRequest. // Ensure that all the callbacks were called on aRequest.
function checkSizeAndLoad(listener, aRequest) function checkSizeAndLoad(listener, aRequest) {
{
Assert.notEqual(listener.state & SIZE_AVAILABLE, 0); Assert.notEqual(listener.state & SIZE_AVAILABLE, 0);
Assert.notEqual(listener.state & LOAD_COMPLETE, 0); Assert.notEqual(listener.state & LOAD_COMPLETE, 0);
do_test_finished(); do_test_finished();
} }
function secondLoadDone(oldlistener, aRequest) function secondLoadDone(oldlistener, aRequest) {
{
do_test_pending(); do_test_pending();
try { try {
@ -68,11 +69,12 @@ function secondLoadDone(oldlistener, aRequest)
// clone state reliably. // clone state reliably.
var listener = new ImageListener(null, checkSizeAndLoad); var listener = new ImageListener(null, checkSizeAndLoad);
listener.synchronous = false; listener.synchronous = false;
var outer = Cc["@mozilla.org/image/tools;1"].getService(Ci.imgITools) var outer = Cc["@mozilla.org/image/tools;1"]
.createScriptedObserver(listener); .getService(Ci.imgITools)
.createScriptedObserver(listener);
var staticrequestclone = staticrequest.clone(outer); var staticrequestclone = staticrequest.clone(outer);
requests.push({ request: staticrequestclone, locked: false }); requests.push({ request: staticrequestclone, locked: false });
} catch(e) { } catch (e) {
// We can't create a static request. Most likely the request we started // We can't create a static request. Most likely the request we started
// with didn't load successfully. // with didn't load successfully.
do_test_finished(); do_test_finished();
@ -85,22 +87,32 @@ function secondLoadDone(oldlistener, aRequest)
// Load the request a second time. This should come from the image cache, and // Load the request a second time. This should come from the image cache, and
// therefore would be at most risk of being served synchronously. // therefore would be at most risk of being served synchronously.
function checkSecondLoad() function checkSecondLoad() {
{
do_test_pending(); do_test_pending();
var listener = new ImageListener(checkClone, secondLoadDone); var listener = new ImageListener(checkClone, secondLoadDone);
var outer = Cc["@mozilla.org/image/tools;1"].getService(Ci.imgITools) var outer = Cc["@mozilla.org/image/tools;1"]
.createScriptedObserver(listener); .getService(Ci.imgITools)
.createScriptedObserver(listener);
requests.push({ requests.push({
request: gCurrentLoader.loadImageXPCOM(uri, null, null, "default", null, null, outer, null, 0, null), request: gCurrentLoader.loadImageXPCOM(
uri,
null,
null,
"default",
null,
null,
outer,
null,
0,
null
),
locked: false, locked: false,
}); });
listener.synchronous = false; listener.synchronous = false;
} }
function firstLoadDone(oldlistener, aRequest) function firstLoadDone(oldlistener, aRequest) {
{
checkSecondLoad(uri); checkSecondLoad(uri);
do_test_finished(); do_test_finished();
@ -108,33 +120,37 @@ function firstLoadDone(oldlistener, aRequest)
// Return a closure that allows us to check the stream listener's status when the // Return a closure that allows us to check the stream listener's status when the
// image finishes loading. // image finishes loading.
function getChannelLoadImageStopCallback(streamlistener, next) function getChannelLoadImageStopCallback(streamlistener, next) {
{
return function channelLoadStop(imglistener, aRequest) { return function channelLoadStop(imglistener, aRequest) {
next(); next();
do_test_finished(); do_test_finished();
} };
} }
// Load the request a second time. This should come from the image cache, and // Load the request a second time. This should come from the image cache, and
// therefore would be at most risk of being served synchronously. // therefore would be at most risk of being served synchronously.
function checkSecondChannelLoad() function checkSecondChannelLoad() {
{
do_test_pending(); do_test_pending();
var channel = NetUtil.newChannel({uri, loadUsingSystemPrincipal: true}); var channel = NetUtil.newChannel({ uri, loadUsingSystemPrincipal: true });
var channellistener = new ChannelListener(); var channellistener = new ChannelListener();
channel.asyncOpen(channellistener); channel.asyncOpen(channellistener);
var listener = new ImageListener(null, var listener = new ImageListener(
getChannelLoadImageStopCallback(channellistener, null,
all_done_callback)); getChannelLoadImageStopCallback(channellistener, all_done_callback)
var outer = Cc["@mozilla.org/image/tools;1"].getService(Ci.imgITools) );
.createScriptedObserver(listener); var outer = Cc["@mozilla.org/image/tools;1"]
.getService(Ci.imgITools)
.createScriptedObserver(listener);
var outlistener = {}; var outlistener = {};
requests.push({ requests.push({
request: gCurrentLoader.loadImageWithChannelXPCOM(channel, outer, null, outlistener), request: gCurrentLoader.loadImageWithChannelXPCOM(
channel,
outer,
null,
outlistener
),
locked: false, locked: false,
}); });
channellistener.outputListener = outlistener.value; channellistener.outputListener = outlistener.value;
@ -142,24 +158,32 @@ function checkSecondChannelLoad()
listener.synchronous = false; listener.synchronous = false;
} }
function run_loadImageWithChannel_tests() function run_loadImageWithChannel_tests() {
{
// To ensure we're testing what we expect to, create a new loader and cache. // To ensure we're testing what we expect to, create a new loader and cache.
gCurrentLoader = Cc["@mozilla.org/image/loader;1"].createInstance(Ci.imgILoader); gCurrentLoader = Cc["@mozilla.org/image/loader;1"].createInstance(
Ci.imgILoader
);
do_test_pending(); do_test_pending();
var channel = NetUtil.newChannel({uri, loadUsingSystemPrincipal: true}); var channel = NetUtil.newChannel({ uri, loadUsingSystemPrincipal: true });
var channellistener = new ChannelListener(); var channellistener = new ChannelListener();
channel.asyncOpen(channellistener); channel.asyncOpen(channellistener);
var listener = new ImageListener(null, var listener = new ImageListener(
getChannelLoadImageStopCallback(channellistener, null,
checkSecondChannelLoad)); getChannelLoadImageStopCallback(channellistener, checkSecondChannelLoad)
var outer = Cc["@mozilla.org/image/tools;1"].getService(Ci.imgITools) );
.createScriptedObserver(listener); var outer = Cc["@mozilla.org/image/tools;1"]
.getService(Ci.imgITools)
.createScriptedObserver(listener);
var outlistener = {}; var outlistener = {};
requests.push({ requests.push({
request: gCurrentLoader.loadImageWithChannelXPCOM(channel, outer, null, outlistener), request: gCurrentLoader.loadImageWithChannelXPCOM(
channel,
outer,
null,
outlistener
),
locked: false, locked: false,
}); });
channellistener.outputListener = outlistener.value; channellistener.outputListener = outlistener.value;
@ -167,54 +191,84 @@ function run_loadImageWithChannel_tests()
listener.synchronous = false; listener.synchronous = false;
} }
function all_done_callback() function all_done_callback() {
{ server.stop(function() {
server.stop(function() { do_test_finished(); }); do_test_finished();
});
} }
function startImageCallback(otherCb) function startImageCallback(otherCb) {
{ return function(listener, request) {
return function(listener, request)
{
// Make sure we can load the same image immediately out of the cache. // Make sure we can load the same image immediately out of the cache.
do_test_pending(); do_test_pending();
var listener2 = new ImageListener(null, function(foo, bar) { do_test_finished(); }); var listener2 = new ImageListener(null, function(foo, bar) {
var outer = Cc["@mozilla.org/image/tools;1"].getService(Ci.imgITools) do_test_finished();
.createScriptedObserver(listener2); });
var outer = Cc["@mozilla.org/image/tools;1"]
.getService(Ci.imgITools)
.createScriptedObserver(listener2);
requests.push({ requests.push({
request: gCurrentLoader.loadImageXPCOM(uri, null, null, "default", null, null, outer, null, 0, null), request: gCurrentLoader.loadImageXPCOM(
uri,
null,
null,
"default",
null,
null,
outer,
null,
0,
null
),
locked: false, locked: false,
}); });
listener2.synchronous = false; listener2.synchronous = false;
// Now that we've started another load, chain to the callback. // Now that we've started another load, chain to the callback.
otherCb(listener, request); otherCb(listener, request);
} };
} }
var gCurrentLoader; var gCurrentLoader;
function cleanup() function cleanup() {
{ for (let { request, locked } of requests) {
for (let {request, locked} of requests) {
if (locked) { if (locked) {
try { request.unlockImage() } catch (e) {} try {
request.unlockImage();
} catch (e) {}
} }
request.cancelAndForgetObserver(0); request.cancelAndForgetObserver(0);
} }
} }
function run_test() function run_test() {
{
registerCleanupFunction(cleanup); registerCleanupFunction(cleanup);
gCurrentLoader = Cc["@mozilla.org/image/loader;1"].createInstance(Ci.imgILoader); gCurrentLoader = Cc["@mozilla.org/image/loader;1"].createInstance(
Ci.imgILoader
);
do_test_pending(); do_test_pending();
var listener = new ImageListener(startImageCallback(checkClone), firstLoadDone); var listener = new ImageListener(
var outer = Cc["@mozilla.org/image/tools;1"].getService(Ci.imgITools) startImageCallback(checkClone),
.createScriptedObserver(listener); firstLoadDone
var req = gCurrentLoader.loadImageXPCOM(uri, null, null, "default", null, null, outer, null, 0, null); );
var outer = Cc["@mozilla.org/image/tools;1"]
.getService(Ci.imgITools)
.createScriptedObserver(listener);
var req = gCurrentLoader.loadImageXPCOM(
uri,
null,
null,
"default",
null,
null,
outer,
null,
0,
null
);
// Ensure that we don't cause any mayhem when we lock an image. // Ensure that we don't cause any mayhem when we lock an image.
req.lockImage(); req.lockImage();

Просмотреть файл

@ -21,44 +21,37 @@ do_get_profile();
// An implementation of imgIScriptedNotificationObserver with the ability to // An implementation of imgIScriptedNotificationObserver with the ability to
// call specified functions on onStartRequest and onStopRequest. // call specified functions on onStartRequest and onStopRequest.
function ImageListener(start_callback, stop_callback) function ImageListener(start_callback, stop_callback) {
{ this.sizeAvailable = function onSizeAvailable(aRequest) {
this.sizeAvailable = function onSizeAvailable(aRequest)
{
Assert.ok(!this.synchronous); Assert.ok(!this.synchronous);
this.state |= SIZE_AVAILABLE; this.state |= SIZE_AVAILABLE;
if (this.start_callback) if (this.start_callback) {
this.start_callback(this, aRequest); this.start_callback(this, aRequest);
} }
this.frameComplete = function onFrameComplete(aRequest) };
{ this.frameComplete = function onFrameComplete(aRequest) {
Assert.ok(!this.synchronous); Assert.ok(!this.synchronous);
this.state |= FRAME_COMPLETE; this.state |= FRAME_COMPLETE;
} };
this.decodeComplete = function onDecodeComplete(aRequest) this.decodeComplete = function onDecodeComplete(aRequest) {
{
Assert.ok(!this.synchronous); Assert.ok(!this.synchronous);
this.state |= DECODE_COMPLETE; this.state |= DECODE_COMPLETE;
} };
this.loadComplete = function onLoadcomplete(aRequest) this.loadComplete = function onLoadcomplete(aRequest) {
{
Assert.ok(!this.synchronous); Assert.ok(!this.synchronous);
this.state |= LOAD_COMPLETE; this.state |= LOAD_COMPLETE;
if (this.stop_callback) if (this.stop_callback) {
this.stop_callback(this, aRequest); this.stop_callback(this, aRequest);
} }
this.frameUpdate = function onFrameUpdate(aRequest) };
{ this.frameUpdate = function onFrameUpdate(aRequest) {};
} this.isAnimated = function onIsAnimated() {};
this.isAnimated = function onIsAnimated()
{
}
// Initialize the synchronous flag to true to start. This must be set to // Initialize the synchronous flag to true to start. This must be set to
// false before exiting to the event loop! // false before exiting to the event loop!
@ -76,41 +69,50 @@ function ImageListener(start_callback, stop_callback)
this.state = 0; this.state = 0;
} }
function NS_FAILED(val) function NS_FAILED(val) {
{
return !!(val & 0x80000000); return !!(val & 0x80000000);
} }
function ChannelListener() function ChannelListener() {
{ this.onStartRequest = function onStartRequest(aRequest) {
this.onStartRequest = function onStartRequest(aRequest) if (this.outputListener) {
{
if (this.outputListener)
this.outputListener.onStartRequest(aRequest); this.outputListener.onStartRequest(aRequest);
}
this.requestStatus |= START_REQUEST; this.requestStatus |= START_REQUEST;
} };
this.onDataAvailable = function onDataAvailable(aRequest, aInputStream, aOffset, aCount) this.onDataAvailable = function onDataAvailable(
{ aRequest,
if (this.outputListener) aInputStream,
this.outputListener.onDataAvailable(aRequest, aInputStream, aOffset, aCount); aOffset,
aCount
) {
if (this.outputListener) {
this.outputListener.onDataAvailable(
aRequest,
aInputStream,
aOffset,
aCount
);
}
this.requestStatus |= DATA_AVAILABLE; this.requestStatus |= DATA_AVAILABLE;
} };
this.onStopRequest = function onStopRequest(aRequest, aStatusCode) this.onStopRequest = function onStopRequest(aRequest, aStatusCode) {
{ if (this.outputListener) {
if (this.outputListener)
this.outputListener.onStopRequest(aRequest, aStatusCode); this.outputListener.onStopRequest(aRequest, aStatusCode);
}
// If we failed (or were canceled - failure is implied if canceled), // If we failed (or were canceled - failure is implied if canceled),
// there's no use tracking our state, since it's meaningless. // there's no use tracking our state, since it's meaningless.
if (NS_FAILED(aStatusCode)) if (NS_FAILED(aStatusCode)) {
this.requestStatus = 0; this.requestStatus = 0;
else } else {
this.requestStatus |= STOP_REQUEST; this.requestStatus |= STOP_REQUEST;
} }
};
// A listener to pass the notifications we get to. // A listener to pass the notifications we get to.
this.outputListener = null; this.outputListener = null;

Просмотреть файл

@ -3,8 +3,11 @@
*/ */
// A simple 3x3 png; rows go red, green, blue. Stolen from the PNG encoder test. // A simple 3x3 png; rows go red, green, blue. Stolen from the PNG encoder test.
var pngspec = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAADCAIAAADZSiLoAAAAEUlEQVQImWP4z8AAQTAamQkAhpcI+DeMzFcAAAAASUVORK5CYII="; var pngspec =
var ioService = Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService); "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAADCAIAAADZSiLoAAAAEUlEQVQImWP4z8AAQTAamQkAhpcI+DeMzFcAAAAASUVORK5CYII=";
var ioService = Cc["@mozilla.org/network/io-service;1"].getService(
Ci.nsIIOService
);
var uri = ioService.newURI(pngspec); var uri = ioService.newURI(pngspec);
load('async_load_tests.js'); load("async_load_tests.js");

Просмотреть файл

@ -2,15 +2,20 @@
* Test to ensure that load/decode notifications are delivered completely and * Test to ensure that load/decode notifications are delivered completely and
* asynchronously when dealing with a file that's a 404. * asynchronously when dealing with a file that's a 404.
*/ */
const {XPCOMUtils} = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm"); const { XPCOMUtils } = ChromeUtils.import(
"resource://gre/modules/XPCOMUtils.jsm"
);
var ioService = Cc["@mozilla.org/network/io-service;1"] var ioService = Cc["@mozilla.org/network/io-service;1"].getService(
.getService(Ci.nsIIOService); Ci.nsIIOService
);
XPCOMUtils.defineLazyGetter(this, "uri", function() { XPCOMUtils.defineLazyGetter(this, "uri", function() {
return ioService.newURI("http://localhost:" + return ioService.newURI(
server.identity.primaryPort + "http://localhost:" +
"/async-notification-never-here.jpg"); server.identity.primaryPort +
"/async-notification-never-here.jpg"
);
}); });
load('async_load_tests.js'); load("async_load_tests.js");

Просмотреть файл

@ -7,8 +7,11 @@
*/ */
// transparent-animation.gif from the gif reftests. // transparent-animation.gif from the gif reftests.
var spec = "data:image/gif;base64,R0lGODlhZABkAIABAP8AAP///yH5BAkBAAEALAAAAABLAGQAAAK8jI+py+0Po5y02ouz3rz7D4biSJbmiabqyrbuC8fyTNf2jef6zvf+DwwKh8Si8YhMKpchgPMJjUqnVOipis1ir9qul+sNV8HistVkTj/JajG7/UXDy+95tm4fy/NdPF/q93dWIqgVWAhwWKgoyPjnyAeZJ2lHOWcJh9mmqcaZ5mkGSreHOCXqRloadRrGGkeoapoa6+TaN0tra4gbq3vHq+q7BVwqrMeEnKy8zNzs/AwdLT1NXW19jZ1tUgAAIfkECQEAAQAsAAAAADQAZAAAArCMj6nL7Q+jnLTai7PevPsPhuJIluaJpurKtu4Lx/JM1/aN5/rO9/7vAAiHxKLxiCRCkswmc+mMSqHSapJqzSof2u4Q67WCw1MuOTs+N9Pqq7kdZcON8vk2aF+/88g6358HaCc4Rwhn2IaopnjGSOYYBukl2UWpZYm2x0enuXnX4NnXGQqAKTYaalqlWoZH+snwWsQah+pJ64Sr5ypbCvQLHCw8TFxsfIycrLzM3PxQAAAh+QQJAQABACwAAAAAGwBkAAACUIyPqcvtD6OctNqLs968+w+G4kiW5omm6sq27gTE8kzX9o3n+s73/g8MCofEovGITCqXzKbzCY1Kp9Sq9YrNarfcrvdrfYnH5LL5jE6r16sCADs="; var spec =
var ioService = Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService); "data:image/gif;base64,R0lGODlhZABkAIABAP8AAP///yH5BAkBAAEALAAAAABLAGQAAAK8jI+py+0Po5y02ouz3rz7D4biSJbmiabqyrbuC8fyTNf2jef6zvf+DwwKh8Si8YhMKpchgPMJjUqnVOipis1ir9qul+sNV8HistVkTj/JajG7/UXDy+95tm4fy/NdPF/q93dWIqgVWAhwWKgoyPjnyAeZJ2lHOWcJh9mmqcaZ5mkGSreHOCXqRloadRrGGkeoapoa6+TaN0tra4gbq3vHq+q7BVwqrMeEnKy8zNzs/AwdLT1NXW19jZ1tUgAAIfkECQEAAQAsAAAAADQAZAAAArCMj6nL7Q+jnLTai7PevPsPhuJIluaJpurKtu4Lx/JM1/aN5/rO9/7vAAiHxKLxiCRCkswmc+mMSqHSapJqzSof2u4Q67WCw1MuOTs+N9Pqq7kdZcON8vk2aF+/88g6358HaCc4Rwhn2IaopnjGSOYYBukl2UWpZYm2x0enuXnX4NnXGQqAKTYaalqlWoZH+snwWsQah+pJ64Sr5ypbCvQLHCw8TFxsfIycrLzM3PxQAAAh+QQJAQABACwAAAAAGwBkAAACUIyPqcvtD6OctNqLs968+w+G4kiW5omm6sq27gTE8kzX9o3n+s73/g8MCofEovGITCqXzKbzCY1Kp9Sq9YrNarfcrvdrfYnH5LL5jE6r16sCADs=";
var ioService = Cc["@mozilla.org/network/io-service;1"].getService(
Ci.nsIIOService
);
var uri = ioService.newURI(spec); var uri = ioService.newURI(spec);
load('async_load_tests.js'); load("async_load_tests.js");

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -4,250 +4,379 @@
*/ */
var png1A = { var png1A = {
// A 3x3 image, rows are red, green, blue. // A 3x3 image, rows are red, green, blue.
// RGB format, transparency defaults. // RGB format, transparency defaults.
transparency : null, transparency: null,
frames : [ frames: [
{ {
width : 3, height : 3, width: 3,
height: 3,
format : Ci.imgIEncoder.INPUT_FORMAT_RGB, stride : 9, format: Ci.imgIEncoder.INPUT_FORMAT_RGB,
stride: 9,
pixels : [ pixels: [
255,0,0, 255,0,0, 255,0,0, 255,
0,255,0, 0,255,0, 0,255,0, 0,
0,0,255, 0,0,255, 0,0,255, 0,
] 255,
} 0,
0,
], 255,
expected : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAADCAIAAADZSiLoAAAAEUlEQVQImWP4z8AAQTAamQkAhpcI+DeMzFcAAAAASUVORK5CYII=" 0,
0,
0,
255,
0,
0,
255,
0,
0,
255,
0,
0,
0,
255,
0,
0,
255,
0,
0,
255,
],
},
],
expected:
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAADCAIAAADZSiLoAAAAEUlEQVQImWP4z8AAQTAamQkAhpcI+DeMzFcAAAAASUVORK5CYII=",
}; };
var png1B = { var png1B = {
// A 3x3 image, rows are red, green, blue. // A 3x3 image, rows are red, green, blue.
// RGB format, transparency=none. // RGB format, transparency=none.
transparency : "none", transparency: "none",
frames : [ frames: [
{ {
width : 3, height : 3, width: 3,
height: 3,
format : Ci.imgIEncoder.INPUT_FORMAT_RGB, stride : 9, format: Ci.imgIEncoder.INPUT_FORMAT_RGB,
stride: 9,
pixels : [ pixels: [
255,0,0, 255,0,0, 255,0,0, 255,
0,255,0, 0,255,0, 0,255,0, 0,
0,0,255, 0,0,255, 0,0,255, 0,
] 255,
} 0,
0,
], 255,
expected : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAADCAIAAADZSiLoAAAAEUlEQVQImWP4z8AAQTAamQkAhpcI+DeMzFcAAAAASUVORK5CYII=" 0,
0,
0,
255,
0,
0,
255,
0,
0,
255,
0,
0,
0,
255,
0,
0,
255,
0,
0,
255,
],
},
],
expected:
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAADCAIAAADZSiLoAAAAEUlEQVQImWP4z8AAQTAamQkAhpcI+DeMzFcAAAAASUVORK5CYII=",
}; };
var png2A = { var png2A = {
// A 3x3 image, rows are: red, green, blue. Columns are: 0%, 33%, 66% transparent. // A 3x3 image, rows are: red, green, blue. Columns are: 0%, 33%, 66% transparent.
transparency : null, transparency: null,
frames : [ frames: [
{ {
width : 3, height : 3, width: 3,
height: 3,
format : Ci.imgIEncoder.INPUT_FORMAT_RGBA, stride : 12, format: Ci.imgIEncoder.INPUT_FORMAT_RGBA,
stride: 12,
pixels : [ pixels: [
255,0,0,255, 255,0,0,170, 255,0,0,85, 255,
0,255,0,255, 0,255,0,170, 0,255,0,85, 0,
0,0,255,255, 0,0,255,170, 0,0,255,85 0,
] 255,
} 255,
0,
], 0,
expected : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAADCAYAAABWKLW/AAAAIElEQVQImSXJMQEAMAwEIUy+yZi8DmVFFBcjycn86GgPJw4O8v9DkkEAAAAASUVORK5CYII=" 170,
255,
0,
0,
85,
0,
255,
0,
255,
0,
255,
0,
170,
0,
255,
0,
85,
0,
0,
255,
255,
0,
0,
255,
170,
0,
0,
255,
85,
],
},
],
expected:
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAADCAYAAABWKLW/AAAAIElEQVQImSXJMQEAMAwEIUy+yZi8DmVFFBcjycn86GgPJw4O8v9DkkEAAAAASUVORK5CYII=",
}; };
var png2B = { var png2B = {
// A 3x3 image, rows are: red, green, blue. Columns are: 0%, 33%, 66% transparent, // A 3x3 image, rows are: red, green, blue. Columns are: 0%, 33%, 66% transparent,
// but transparency will be ignored. // but transparency will be ignored.
transparency : "none", transparency: "none",
frames : [ frames: [
{ {
width : 3, height : 3, width: 3,
height: 3,
format : Ci.imgIEncoder.INPUT_FORMAT_RGBA, stride : 12, format: Ci.imgIEncoder.INPUT_FORMAT_RGBA,
stride: 12,
pixels : [ pixels: [
255,0,0,255, 255,0,0,170, 255,0,0,85, 255,
0,255,0,255, 0,255,0,170, 0,255,0,85, 0,
0,0,255,255, 0,0,255,170, 0,0,255,85 0,
] 255,
} 255,
0,
], 0,
expected : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAADCAIAAADZSiLoAAAAEUlEQVQImWP4z8AAQTAamQkAhpcI+DeMzFcAAAAASUVORK5CYII=" 170,
255,
0,
0,
85,
0,
255,
0,
255,
0,
255,
0,
170,
0,
255,
0,
85,
0,
0,
255,
255,
0,
0,
255,
170,
0,
0,
255,
85,
],
},
],
expected:
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAADCAIAAADZSiLoAAAAEUlEQVQImWP4z8AAQTAamQkAhpcI+DeMzFcAAAAASUVORK5CYII=",
}; };
// Main test entry point. // Main test entry point.
function run_test() { function run_test() {
dump("Checking png1A...\n") dump("Checking png1A...\n");
run_test_for(png1A); run_test_for(png1A);
dump("Checking png1B...\n") dump("Checking png1B...\n");
run_test_for(png1B); run_test_for(png1B);
dump("Checking png2A...\n") dump("Checking png2A...\n");
run_test_for(png2A); run_test_for(png2A);
dump("Checking png2B...\n") dump("Checking png2B...\n");
run_test_for(png2B); run_test_for(png2B);
}; }
function run_test_for(input) { function run_test_for(input) {
var encoder, dataURL; var encoder, dataURL;
encoder = encodeImage(input); encoder = encodeImage(input);
dataURL = makeDataURL(encoder, "image/png"); dataURL = makeDataURL(encoder, "image/png");
Assert.equal(dataURL, input.expected); Assert.equal(dataURL, input.expected);
encoder = encodeImageAsync(input);
dataURL = makeDataURLFromAsync(encoder, "image/png", input.expected);
};
encoder = encodeImageAsync(input);
dataURL = makeDataURLFromAsync(encoder, "image/png", input.expected);
}
function encodeImage(input) { function encodeImage(input) {
var encoder = Cc["@mozilla.org/image/encoder;2?type=image/png"].createInstance(); var encoder = Cc[
encoder.QueryInterface(Ci.imgIEncoder); "@mozilla.org/image/encoder;2?type=image/png"
].createInstance();
encoder.QueryInterface(Ci.imgIEncoder);
var options = ""; var options = "";
if (input.transparency) { if (input.transparency) {
options += "transparency=" + input.transparency; options += "transparency=" + input.transparency;
} }
var frame = input.frames[0]; var frame = input.frames[0];
encoder.initFromData(frame.pixels, frame.pixels.length, encoder.initFromData(
frame.width, frame.height, frame.stride, frame.pixels,
frame.format, options); frame.pixels.length,
return encoder; frame.width,
frame.height,
frame.stride,
frame.format,
options
);
return encoder;
} }
function _encodeImageAsyncFactory(frame, options, encoder) function _encodeImageAsyncFactory(frame, options, encoder) {
{ function finishEncode() {
function finishEncode() { encoder.addImageFrame(
encoder.addImageFrame(frame.pixels, frame.pixels.length, frame.pixels,
frame.width, frame.height, frame.stride, frame.pixels.length,
frame.format, options); frame.width,
encoder.endImageEncode(); frame.height,
} frame.stride,
return finishEncode; frame.format,
options
);
encoder.endImageEncode();
}
return finishEncode;
} }
function encodeImageAsync(input) function encodeImageAsync(input) {
{ var encoder = Cc[
var encoder = Cc["@mozilla.org/image/encoder;2?type=image/png"].createInstance(); "@mozilla.org/image/encoder;2?type=image/png"
encoder.QueryInterface(Ci.imgIEncoder); ].createInstance();
encoder.QueryInterface(Ci.imgIEncoder);
var options = ""; var options = "";
if (input.transparency) { if (input.transparency) {
options += "transparency=" + input.transparency; options += "transparency=" + input.transparency;
} }
var frame = input.frames[0]; var frame = input.frames[0];
encoder.startImageEncode(frame.width, frame.height, encoder.startImageEncode(frame.width, frame.height, frame.format, options);
frame.format, options);
do_timeout(50, _encodeImageAsyncFactory(frame, options, encoder)); do_timeout(50, _encodeImageAsyncFactory(frame, options, encoder));
return encoder; return encoder;
} }
function makeDataURL(encoder, mimetype) { function makeDataURL(encoder, mimetype) {
var rawStream = encoder.QueryInterface(Ci.nsIInputStream); var rawStream = encoder.QueryInterface(Ci.nsIInputStream);
var stream = Cc["@mozilla.org/binaryinputstream;1"].createInstance(); var stream = Cc["@mozilla.org/binaryinputstream;1"].createInstance();
stream.QueryInterface(Ci.nsIBinaryInputStream); stream.QueryInterface(Ci.nsIBinaryInputStream);
stream.setInputStream(rawStream); stream.setInputStream(rawStream);
var bytes = stream.readByteArray(stream.available()); // returns int[] var bytes = stream.readByteArray(stream.available()); // returns int[]
var base64String = toBase64(bytes); var base64String = toBase64(bytes);
return "data:" + mimetype + ";base64," + base64String; return "data:" + mimetype + ";base64," + base64String;
} }
function makeDataURLFromAsync(encoder, mimetype, expected) { function makeDataURLFromAsync(encoder, mimetype, expected) {
do_test_pending(); do_test_pending();
var rawStream = encoder.QueryInterface(Ci.nsIAsyncInputStream); var rawStream = encoder.QueryInterface(Ci.nsIAsyncInputStream);
var currentThread = Cc["@mozilla.org/thread-manager;1"].getService().currentThread; var currentThread = Cc["@mozilla.org/thread-manager;1"].getService()
.currentThread;
var bytes = []; var bytes = [];
var binarystream = Cc["@mozilla.org/binaryinputstream;1"].createInstance(); var binarystream = Cc["@mozilla.org/binaryinputstream;1"].createInstance();
binarystream.QueryInterface(Ci.nsIBinaryInputStream); binarystream.QueryInterface(Ci.nsIBinaryInputStream);
var asyncReader = var asyncReader = {
{ onInputStreamReady(stream) {
onInputStreamReady(stream) binarystream.setInputStream(stream);
{ var available = 0;
binarystream.setInputStream(stream); try {
var available = 0; available = stream.available();
try { } catch (e) {}
available = stream.available();
} catch(e) { }
if (available > 0) if (available > 0) {
{ bytes = bytes.concat(binarystream.readByteArray(available));
bytes = bytes.concat(binarystream.readByteArray(available)); stream.asyncWait(this, 0, 0, currentThread);
stream.asyncWait(this, 0, 0, currentThread); } else {
} else { var base64String = toBase64(bytes);
var base64String = toBase64(bytes); var dataURL = "data:" + mimetype + ";base64," + base64String;
var dataURL = "data:" + mimetype + ";base64," + base64String; Assert.equal(dataURL, expected);
Assert.equal(dataURL, expected); do_test_finished();
do_test_finished(); }
} },
};
} rawStream.asyncWait(asyncReader, 0, 0, currentThread);
};
rawStream.asyncWait(asyncReader, 0, 0, currentThread);
} }
/* toBase64 copied from extensions/xml-rpc/src/nsXmlRpcClient.js */ /* toBase64 copied from extensions/xml-rpc/src/nsXmlRpcClient.js */
/* Convert data (an array of integers) to a Base64 string. */ /* Convert data (an array of integers) to a Base64 string. */
const toBase64Table = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz' + const toBase64Table =
'0123456789+/'; "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" + "0123456789+/";
const base64Pad = '='; const base64Pad = "=";
function toBase64(data) { function toBase64(data) {
var result = ''; var result = "";
var length = data.length; var length = data.length;
var i; var i;
// Convert every three bytes to 4 ascii characters. // Convert every three bytes to 4 ascii characters.
for (i = 0; i < (length - 2); i += 3) { for (i = 0; i < length - 2; i += 3) {
result += toBase64Table[data[i] >> 2]; result += toBase64Table[data[i] >> 2];
result += toBase64Table[((data[i] & 0x03) << 4) + (data[i+1] >> 4)]; result += toBase64Table[((data[i] & 0x03) << 4) + (data[i + 1] >> 4)];
result += toBase64Table[((data[i+1] & 0x0f) << 2) + (data[i+2] >> 6)]; result += toBase64Table[((data[i + 1] & 0x0f) << 2) + (data[i + 2] >> 6)];
result += toBase64Table[data[i+2] & 0x3f]; result += toBase64Table[data[i + 2] & 0x3f];
} }
// Convert the remaining 1 or 2 bytes, pad out to 4 characters. // Convert the remaining 1 or 2 bytes, pad out to 4 characters.
if (length%3) { if (length % 3) {
i = length - (length%3); i = length - (length % 3);
result += toBase64Table[data[i] >> 2]; result += toBase64Table[data[i] >> 2];
if ((length%3) == 2) { if (length % 3 == 2) {
result += toBase64Table[((data[i] & 0x03) << 4) + (data[i+1] >> 4)]; result += toBase64Table[((data[i] & 0x03) << 4) + (data[i + 1] >> 4)];
result += toBase64Table[(data[i+1] & 0x0f) << 2]; result += toBase64Table[(data[i + 1] & 0x0f) << 2];
result += base64Pad; result += base64Pad;
} else { } else {
result += toBase64Table[(data[i] & 0x03) << 4]; result += toBase64Table[(data[i] & 0x03) << 4];
result += base64Pad + base64Pad; result += base64Pad + base64Pad;
}
} }
}
return result; return result;
} }

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Различия файлов скрыты, потому что одна или несколько строк слишком длинны

Просмотреть файл

@ -1,18 +1,24 @@
const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm"); const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
const {NetUtil} = ChromeUtils.import("resource://gre/modules/NetUtil.jsm"); const { NetUtil } = ChromeUtils.import("resource://gre/modules/NetUtil.jsm");
const {HttpServer} = ChromeUtils.import("resource://testing-common/httpd.js"); const { HttpServer } = ChromeUtils.import("resource://testing-common/httpd.js");
var server = new HttpServer(); var server = new HttpServer();
server.registerPathHandler('/image.png', imageHandler); server.registerPathHandler("/image.png", imageHandler);
server.start(-1); server.start(-1);
load('image_load_helpers.js'); load("image_load_helpers.js");
var gHits = 0; var gHits = 0;
var gIoService = Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService); var gIoService = Cc["@mozilla.org/network/io-service;1"].getService(
var gPublicLoader = Cc["@mozilla.org/image/loader;1"].createInstance(Ci.imgILoader); Ci.nsIIOService
var gPrivateLoader = Cc["@mozilla.org/image/loader;1"].createInstance(Ci.imgILoader); );
var gPublicLoader = Cc["@mozilla.org/image/loader;1"].createInstance(
Ci.imgILoader
);
var gPrivateLoader = Cc["@mozilla.org/image/loader;1"].createInstance(
Ci.imgILoader
);
gPrivateLoader.QueryInterface(Ci.imgICache).respectPrivacyNotifications(); gPrivateLoader.QueryInterface(Ci.imgICache).respectPrivacyNotifications();
var nonPrivateLoadContext = Cu.createLoadContext(); var nonPrivateLoadContext = Cu.createLoadContext();
@ -23,49 +29,75 @@ function imageHandler(metadata, response) {
response.setHeader("Cache-Control", "max-age=10000", false); response.setHeader("Cache-Control", "max-age=10000", false);
response.setStatusLine(metadata.httpVersion, 200, "OK"); response.setStatusLine(metadata.httpVersion, 200, "OK");
response.setHeader("Content-Type", "image/png", false); response.setHeader("Content-Type", "image/png", false);
var body = "iVBORw0KGgoAAAANSUhEUgAAAAMAAAADCAIAAADZSiLoAAAAEUlEQVQImWP4z8AAQTAamQkAhpcI+DeMzFcAAAAASUVORK5CYII="; var body =
"iVBORw0KGgoAAAANSUhEUgAAAAMAAAADCAIAAADZSiLoAAAAEUlEQVQImWP4z8AAQTAamQkAhpcI+DeMzFcAAAAASUVORK5CYII=";
response.bodyOutputStream.write(body, body.length); response.bodyOutputStream.write(body, body.length);
} }
var requests = []; var requests = [];
var listeners = []; var listeners = [];
var gImgPath = 'http://localhost:' + server.identity.primaryPort + '/image.png'; var gImgPath = "http://localhost:" + server.identity.primaryPort + "/image.png";
function setup_chan(path, isPrivate, callback) { function setup_chan(path, isPrivate, callback) {
var uri = NetUtil.newURI(gImgPath); var uri = NetUtil.newURI(gImgPath);
var securityFlags = Ci.nsILoadInfo.SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL; var securityFlags = Ci.nsILoadInfo.SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL;
var principal = Services.scriptSecurityManager var principal = Services.scriptSecurityManager.createCodebasePrincipal(uri, {
.createCodebasePrincipal(uri, {privateBrowsingId: isPrivate ? 1 : 0}); privateBrowsingId: isPrivate ? 1 : 0,
var chan = NetUtil.newChannel({uri, loadingPrincipal: principal, });
securityFlags, var chan = NetUtil.newChannel({
contentPolicyType: Ci.nsIContentPolicy.TYPE_INTERNAL_IMAGE}); uri,
chan.notificationCallbacks = isPrivate ? privateLoadContext loadingPrincipal: principal,
: nonPrivateLoadContext; securityFlags,
contentPolicyType: Ci.nsIContentPolicy.TYPE_INTERNAL_IMAGE,
});
chan.notificationCallbacks = isPrivate
? privateLoadContext
: nonPrivateLoadContext;
var channelListener = new ChannelListener(); var channelListener = new ChannelListener();
chan.asyncOpen(channelListener); chan.asyncOpen(channelListener);
var listener = new ImageListener(null, callback); var listener = new ImageListener(null, callback);
var outlistener = {}; var outlistener = {};
var loader = isPrivate ? gPrivateLoader : gPublicLoader; var loader = isPrivate ? gPrivateLoader : gPublicLoader;
var outer = Cc["@mozilla.org/image/tools;1"].getService(Ci.imgITools) var outer = Cc["@mozilla.org/image/tools;1"]
.createScriptedObserver(listener); .getService(Ci.imgITools)
.createScriptedObserver(listener);
listeners.push(outer); listeners.push(outer);
requests.push(loader.loadImageWithChannelXPCOM(chan, outer, null, outlistener)); requests.push(
loader.loadImageWithChannelXPCOM(chan, outer, null, outlistener)
);
channelListener.outputListener = outlistener.value; channelListener.outputListener = outlistener.value;
listener.synchronous = false; listener.synchronous = false;
} }
function loadImage(isPrivate, callback) { function loadImage(isPrivate, callback) {
var listener = new ImageListener(null, callback); var listener = new ImageListener(null, callback);
var outer = Cc["@mozilla.org/image/tools;1"].getService(Ci.imgITools) var outer = Cc["@mozilla.org/image/tools;1"]
.createScriptedObserver(listener); .getService(Ci.imgITools)
.createScriptedObserver(listener);
var uri = gIoService.newURI(gImgPath); var uri = gIoService.newURI(gImgPath);
var loadGroup = Cc["@mozilla.org/network/load-group;1"].createInstance(Ci.nsILoadGroup); var loadGroup = Cc["@mozilla.org/network/load-group;1"].createInstance(
loadGroup.notificationCallbacks = isPrivate ? privateLoadContext Ci.nsILoadGroup
: nonPrivateLoadContext; );
loadGroup.notificationCallbacks = isPrivate
? privateLoadContext
: nonPrivateLoadContext;
var loader = isPrivate ? gPrivateLoader : gPublicLoader; var loader = isPrivate ? gPrivateLoader : gPublicLoader;
requests.push(loader.loadImageXPCOM(uri, null, null, "default", null, loadGroup, outer, null, 0, null)); requests.push(
loader.loadImageXPCOM(
uri,
null,
null,
"default",
null,
loadGroup,
outer,
null,
0,
null
)
);
listener.synchronous = false; listener.synchronous = false;
} }
@ -86,13 +118,13 @@ function run_loadImage_tests() {
} }
Services.obs.addObserver(observer, "cacheservice:empty-cache"); Services.obs.addObserver(observer, "cacheservice:empty-cache");
let cs = Cc["@mozilla.org/netwerk/cache-storage-service;1"] let cs = Cc["@mozilla.org/netwerk/cache-storage-service;1"].getService(
.getService(Ci.nsICacheStorageService); Ci.nsICacheStorageService
);
cs.clear(); cs.clear();
} }
function cleanup() function cleanup() {
{
for (var i = 0; i < requests.length; ++i) { for (var i = 0; i < requests.length; ++i) {
requests[i].cancelAndForgetObserver(0); requests[i].cancelAndForgetObserver(0);
} }
@ -110,10 +142,10 @@ function run_test() {
// and load the same image, and do that a second time to ensure a cache // and load the same image, and do that a second time to ensure a cache
// read. In total, we should cause two separate http responses to occur, // read. In total, we should cause two separate http responses to occur,
// since the private channels shouldn't be able to use the public cache. // since the private channels shouldn't be able to use the public cache.
setup_chan('/image.png', false, function() { setup_chan("/image.png", false, function() {
setup_chan('/image.png', false, function() { setup_chan("/image.png", false, function() {
setup_chan('/image.png', true, function() { setup_chan("/image.png", true, function() {
setup_chan('/image.png', true, function() { setup_chan("/image.png", true, function() {
Assert.equal(gHits, 2); Assert.equal(gHits, 2);
run_loadImage_tests(); run_loadImage_tests();
}); });