Backed out changeset 638eb8a41245 (bug 1453751) for frequent linux debug e-10s failures on test_ext_webrequest_filter.html
--HG-- rename : browser/base/content/test/favicons/browser_bug408415.js => browser/base/content/test/general/browser_bug408415.js rename : browser/base/content/test/favicons/browser_bug550565.js => browser/base/content/test/general/browser_bug550565.js rename : browser/base/content/test/favicons/browser_favicon_change.js => browser/base/content/test/general/browser_favicon_change.js rename : browser/base/content/test/favicons/browser_favicon_change_not_in_document.js => browser/base/content/test/general/browser_favicon_change_not_in_document.js rename : browser/base/content/test/favicons/browser_subframe_favicons_not_used.js => browser/base/content/test/general/browser_subframe_favicons_not_used.js rename : browser/base/content/test/favicons/file_generic_favicon.ico => browser/base/content/test/general/file_bug970276_favicon1.ico rename : browser/base/content/test/favicons/file_bug970276_popup1.html => browser/base/content/test/general/file_bug970276_popup1.html rename : browser/base/content/test/favicons/file_bug970276_popup2.html => browser/base/content/test/general/file_bug970276_popup2.html rename : browser/base/content/test/favicons/file_favicon_change.html => browser/base/content/test/general/file_favicon_change.html rename : browser/base/content/test/favicons/file_favicon_change_not_in_document.html => browser/base/content/test/general/file_favicon_change_not_in_document.html rename : browser/base/content/test/favicons/file_with_favicon.html => browser/base/content/test/general/file_with_favicon.html extra : rebase_source : 77bf32209022e0351c2a3b69affaac4cf33aa9a6
@ -268,6 +268,7 @@ pref("browser.aboutHomeSnippets.updateUrl", "https://snippets.cdn.mozilla.net/%S
|
||||
|
||||
pref("browser.enable_automatic_image_resizing", true);
|
||||
pref("browser.chrome.site_icons", true);
|
||||
pref("browser.chrome.favicons", true);
|
||||
// browser.warnOnQuit == false will override all other possible prompts when quitting or restarting
|
||||
pref("browser.warnOnQuit", true);
|
||||
// browser.showQuitWarning specifically controls the quit warning dialog. We
|
||||
|
@ -3756,8 +3756,8 @@ const DOMEventHandler = {
|
||||
break;
|
||||
|
||||
case "Link:SetIcon":
|
||||
this.setIconFromLink(aMsg.target, aMsg.data.originalURL, aMsg.data.loadingPrincipal,
|
||||
aMsg.data.canUseForTab, aMsg.data.expiration, aMsg.data.iconURL);
|
||||
this.setIcon(aMsg.target, aMsg.data.url, aMsg.data.loadingPrincipal,
|
||||
aMsg.data.requestContextID, aMsg.data.canUseForTab);
|
||||
break;
|
||||
|
||||
case "Link:AddSearch":
|
||||
@ -3776,16 +3776,21 @@ const DOMEventHandler = {
|
||||
return true;
|
||||
},
|
||||
|
||||
setIconFromLink(aBrowser, aOriginalURL, aLoadingPrincipal, aCanUseForTab, aExpiration, aIconURL = aOriginalURL) {
|
||||
setIcon(aBrowser, aURL, aLoadingPrincipal, aRequestContextID = 0, aCanUseForTab = true) {
|
||||
if (gBrowser.isFailedIcon(aURL))
|
||||
return false;
|
||||
|
||||
let tab = gBrowser.getTabForBrowser(aBrowser);
|
||||
if (!tab)
|
||||
return false;
|
||||
|
||||
let loadingPrincipal = aLoadingPrincipal ||
|
||||
Services.scriptSecurityManager.getSystemPrincipal();
|
||||
gBrowser.storeIcon(aBrowser, aOriginalURL, loadingPrincipal, aExpiration, aOriginalURL);
|
||||
if (aURL) {
|
||||
gBrowser.storeIcon(aBrowser, aURL, loadingPrincipal, aRequestContextID);
|
||||
}
|
||||
if (aCanUseForTab) {
|
||||
gBrowser.setIcon(tab, aIconURL, aOriginalURL);
|
||||
gBrowser.setIcon(tab, aURL, loadingPrincipal, aRequestContextID);
|
||||
}
|
||||
return true;
|
||||
},
|
||||
|
@ -321,7 +321,7 @@ var ClickEventHandler = {
|
||||
};
|
||||
ClickEventHandler.init();
|
||||
|
||||
new ContentLinkHandler(this);
|
||||
ContentLinkHandler.init(this);
|
||||
ContentMetaHandler.init(this);
|
||||
|
||||
// TODO: Load this lazily so the JSM is run only if a relevant event/message fires.
|
||||
|
@ -762,52 +762,43 @@ window._gBrowser = {
|
||||
}
|
||||
},
|
||||
|
||||
storeIcon(aBrowser, aOriginalURL, aLoadingPrincipal, aExpiration, aIconURL = aOriginalURL) {
|
||||
storeIcon(aBrowser, aURI, aLoadingPrincipal, aRequestContextID) {
|
||||
try {
|
||||
if (!(aOriginalURL instanceof Ci.nsIURI)) {
|
||||
aOriginalURL = makeURI(aOriginalURL);
|
||||
if (!(aURI instanceof Ci.nsIURI)) {
|
||||
aURI = makeURI(aURI);
|
||||
}
|
||||
if (!(aIconURL instanceof Ci.nsIURI)) {
|
||||
aIconURL = makeURI(aIconURL);
|
||||
}
|
||||
PlacesUIUtils.loadFavicon(aBrowser, aLoadingPrincipal, aOriginalURL, aExpiration, aIconURL);
|
||||
PlacesUIUtils.loadFavicon(aBrowser, aLoadingPrincipal, aURI, aRequestContextID);
|
||||
} catch (ex) {
|
||||
Cu.reportError(ex);
|
||||
}
|
||||
},
|
||||
|
||||
setIcon(aTab, aIconURL = "", aOriginalURL = aIconURL) {
|
||||
let makeString = (url) => url instanceof Ci.nsIURI ? url.spec : url;
|
||||
|
||||
aIconURL = makeString(aIconURL);
|
||||
aOriginalURL = makeString(aOriginalURL);
|
||||
|
||||
let LOCAL_PROTOCOLS = [
|
||||
"chrome:",
|
||||
"about:",
|
||||
"resource:",
|
||||
"data:",
|
||||
];
|
||||
|
||||
if (aIconURL && !LOCAL_PROTOCOLS.some(protocol => aIconURL.startsWith(protocol))) {
|
||||
console.error(`Attempt to set a remote URL ${aIconURL} as a tab icon.`);
|
||||
return;
|
||||
}
|
||||
|
||||
setIcon(aTab, aURI, aLoadingPrincipal, aRequestContextID) {
|
||||
let browser = this.getBrowserForTab(aTab);
|
||||
browser.mIconURL = aIconURL;
|
||||
|
||||
if (aIconURL != aTab.getAttribute("image")) {
|
||||
if (aIconURL) {
|
||||
aTab.setAttribute("image", aIconURL);
|
||||
browser.mIconURL = aURI instanceof Ci.nsIURI ? aURI.spec : aURI;
|
||||
let loadingPrincipal = aLoadingPrincipal ||
|
||||
Services.scriptSecurityManager.getSystemPrincipal();
|
||||
let requestContextID = aRequestContextID || 0;
|
||||
let sizedIconUrl = browser.mIconURL || "";
|
||||
if (sizedIconUrl != aTab.getAttribute("image")) {
|
||||
if (sizedIconUrl) {
|
||||
if (!browser.mIconLoadingPrincipal ||
|
||||
!browser.mIconLoadingPrincipal.equals(loadingPrincipal)) {
|
||||
aTab.setAttribute("iconloadingprincipal",
|
||||
this.serializationHelper.serializeToString(loadingPrincipal));
|
||||
aTab.setAttribute("requestcontextid", requestContextID);
|
||||
browser.mIconLoadingPrincipal = loadingPrincipal;
|
||||
}
|
||||
aTab.setAttribute("image", sizedIconUrl);
|
||||
} else {
|
||||
aTab.removeAttribute("iconloadingprincipal");
|
||||
delete browser.mIconLoadingPrincipal;
|
||||
aTab.removeAttribute("image");
|
||||
}
|
||||
this._tabAttrModified(aTab, ["image"]);
|
||||
}
|
||||
|
||||
// The aOriginalURL argument is currently only used by tests.
|
||||
this._callProgressListeners(browser, "onLinkIconAvailable", [aIconURL, aOriginalURL]);
|
||||
this._callProgressListeners(browser, "onLinkIconAvailable", [browser.mIconURL]);
|
||||
},
|
||||
|
||||
getIcon(aTab) {
|
||||
@ -822,6 +813,51 @@ window._gBrowser = {
|
||||
}
|
||||
},
|
||||
|
||||
shouldLoadFavIcon(aURI) {
|
||||
return (aURI &&
|
||||
Services.prefs.getBoolPref("browser.chrome.site_icons") &&
|
||||
Services.prefs.getBoolPref("browser.chrome.favicons") &&
|
||||
("schemeIs" in aURI) && (aURI.schemeIs("http") || aURI.schemeIs("https")));
|
||||
},
|
||||
|
||||
useDefaultIcon(aTab) {
|
||||
let browser = this.getBrowserForTab(aTab);
|
||||
let documentURI = browser.documentURI;
|
||||
let requestContextID = browser.contentRequestContextID;
|
||||
let loadingPrincipal = browser.contentPrincipal;
|
||||
let icon = null;
|
||||
|
||||
if (browser.imageDocument) {
|
||||
if (Services.prefs.getBoolPref("browser.chrome.site_icons")) {
|
||||
let sz = Services.prefs.getIntPref("browser.chrome.image_icons.max_size");
|
||||
if (browser.imageDocument.width <= sz &&
|
||||
browser.imageDocument.height <= sz) {
|
||||
// Don't try to store the icon in Places, regardless it would
|
||||
// be skipped (see Bug 403651).
|
||||
icon = browser.currentURI;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Use documentURIObject in the check for shouldLoadFavIcon so that we
|
||||
// do the right thing with about:-style error pages. Bug 453442
|
||||
if (!icon && this.shouldLoadFavIcon(documentURI)) {
|
||||
let url = documentURI.prePath + "/favicon.ico";
|
||||
if (!this.isFailedIcon(url)) {
|
||||
icon = url;
|
||||
this.storeIcon(browser, icon, loadingPrincipal, requestContextID);
|
||||
}
|
||||
}
|
||||
|
||||
this.setIcon(aTab, icon, loadingPrincipal, requestContextID);
|
||||
},
|
||||
|
||||
isFailedIcon(aURI) {
|
||||
if (!(aURI instanceof Ci.nsIURI))
|
||||
aURI = makeURI(aURI);
|
||||
return PlacesUtils.favicons.isFailedFavicon(aURI);
|
||||
},
|
||||
|
||||
getWindowTitleForBrowser(aBrowser) {
|
||||
var newTitle = "";
|
||||
var docElement = document.documentElement;
|
||||
@ -3113,7 +3149,7 @@ window._gBrowser = {
|
||||
// Workarounds for bug 458697
|
||||
// Icon might have been set on DOMLinkAdded, don't override that.
|
||||
if (!ourBrowser.mIconURL && otherBrowser.mIconURL)
|
||||
this.setIcon(aOurTab, otherBrowser.mIconURL);
|
||||
this.setIcon(aOurTab, otherBrowser.mIconURL, otherBrowser.contentPrincipal, otherBrowser.contentRequestContextID);
|
||||
var isBusy = aOtherTab.hasAttribute("busy");
|
||||
if (isBusy) {
|
||||
aOurTab.setAttribute("busy", "true");
|
||||
@ -4208,7 +4244,7 @@ window._gBrowser = {
|
||||
}
|
||||
|
||||
tab.removeAttribute("soundplaying");
|
||||
this.setIcon(tab, icon);
|
||||
this.setIcon(tab, icon, browser.contentPrincipal, browser.contentRequestContextID);
|
||||
});
|
||||
|
||||
this.addEventListener("oop-browser-buildid-mismatch", (event) => {
|
||||
@ -4547,6 +4583,21 @@ class TabProgressListener {
|
||||
} else if (isSuccessful) {
|
||||
this.mBrowser.urlbarChangeTracker.finishedLoad();
|
||||
}
|
||||
|
||||
// Ignore initial about:blank to prevent flickering.
|
||||
if (!this.mBrowser.mIconURL && !ignoreBlank) {
|
||||
// Don't switch to the default icon on about:home, about:newtab,
|
||||
// about:privatebrowsing, or about:welcome since these pages get
|
||||
// their favicon set in browser code to improve perceived performance.
|
||||
let isNewTab = originalLocation &&
|
||||
(originalLocation.spec == "about:newtab" ||
|
||||
originalLocation.spec == "about:privatebrowsing" ||
|
||||
originalLocation.spec == "about:home" ||
|
||||
originalLocation.spec == "about:welcome");
|
||||
if (!isNewTab) {
|
||||
gBrowser.useDefaultIcon(this.mTab);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// For keyword URIs clear the user typed value since they will be changed into real URIs
|
||||
|
@ -2,41 +2,21 @@
|
||||
support-files =
|
||||
head.js
|
||||
discovery.html
|
||||
file_rich_icon.html
|
||||
file_mask_icon.html
|
||||
moz.png
|
||||
rich_moz_1.png
|
||||
rich_moz_2.png
|
||||
file_bug970276_favicon1.ico
|
||||
file_generic_favicon.ico
|
||||
file_with_favicon.html
|
||||
prefs =
|
||||
browser.chrome.guess_favicon=true
|
||||
|
||||
[browser_bug408415.js]
|
||||
[browser_bug550565.js]
|
||||
[browser_favicon_change.js]
|
||||
support-files =
|
||||
file_favicon_change.html
|
||||
[browser_favicon_change_not_in_document.js]
|
||||
support-files =
|
||||
file_favicon_change_not_in_document.html
|
||||
[browser_multiple_icons_in_short_timeframe.js]
|
||||
skip-if = verify
|
||||
[browser_rich_icons.js]
|
||||
support-files =
|
||||
file_rich_icon.html
|
||||
file_mask_icon.html
|
||||
[browser_icon_discovery.js]
|
||||
[browser_preferred_icons.js]
|
||||
support-files =
|
||||
icon.svg
|
||||
[browser_favicon_load.js]
|
||||
support-files =
|
||||
file_favicon.html
|
||||
file_favicon.png
|
||||
file_favicon.png^headers^
|
||||
file_favicon_thirdParty.html
|
||||
[browser_subframe_favicons_not_used.js]
|
||||
support-files =
|
||||
file_bug970276_popup1.html
|
||||
file_bug970276_popup2.html
|
||||
file_bug970276_favicon2.ico
|
||||
|
||||
[browser_multiple_icons_in_short_timeframe.js]
|
||||
skip-if = verify
|
||||
[browser_rich_icons.js]
|
||||
skip-if = (verify && debug)
|
||||
[browser_icon_discovery.js]
|
||||
skip-if = verify
|
||||
[browser_preferred_icons.js]
|
||||
[browser_favicon_load.js]
|
||||
|
@ -1,33 +0,0 @@
|
||||
add_task(async function test() {
|
||||
let testPath = getRootDirectory(gTestPath);
|
||||
|
||||
await BrowserTestUtils.withNewTab({ gBrowser, url: "about:blank" },
|
||||
async function(tabBrowser) {
|
||||
const URI = testPath + "file_with_favicon.html";
|
||||
const expectedIcon = testPath + "file_generic_favicon.ico";
|
||||
let faviconPromise = waitForLinkAvailable(tabBrowser);
|
||||
|
||||
BrowserTestUtils.loadURI(tabBrowser, URI);
|
||||
|
||||
let iconURI = await faviconPromise;
|
||||
is(iconURI, expectedIcon, "Correct icon before pushState.");
|
||||
|
||||
faviconPromise = waitForLinkAvailable(tabBrowser);
|
||||
|
||||
await ContentTask.spawn(tabBrowser, null, function() {
|
||||
content.location.href += "#foo";
|
||||
});
|
||||
|
||||
TestUtils.executeSoon(() => {
|
||||
faviconPromise.cancel();
|
||||
});
|
||||
|
||||
try {
|
||||
await faviconPromise;
|
||||
ok(false, "Should not have seen a new icon load.");
|
||||
} catch (e) {
|
||||
ok(true, "Should have been able to cancel the promise.");
|
||||
}
|
||||
});
|
||||
});
|
||||
|
@ -1,33 +0,0 @@
|
||||
add_task(async function test() {
|
||||
let testPath = getRootDirectory(gTestPath);
|
||||
|
||||
await BrowserTestUtils.withNewTab({ gBrowser, url: "about:blank" },
|
||||
async function(tabBrowser) {
|
||||
const URI = testPath + "file_with_favicon.html";
|
||||
const expectedIcon = testPath + "file_generic_favicon.ico";
|
||||
let faviconPromise = waitForLinkAvailable(tabBrowser);
|
||||
|
||||
BrowserTestUtils.loadURI(tabBrowser, URI);
|
||||
|
||||
let iconURI = await faviconPromise;
|
||||
is(iconURI, expectedIcon, "Correct icon before pushState.");
|
||||
|
||||
faviconPromise = waitForLinkAvailable(tabBrowser);
|
||||
|
||||
await ContentTask.spawn(tabBrowser, null, function() {
|
||||
content.history.pushState("page2", "page2", "page2");
|
||||
});
|
||||
|
||||
// We've navigated and shouldn't get a call to onLinkIconAvailable.
|
||||
TestUtils.executeSoon(() => {
|
||||
faviconPromise.cancel();
|
||||
});
|
||||
|
||||
try {
|
||||
await faviconPromise;
|
||||
ok(false, "Should not have seen a new icon load.");
|
||||
} catch (e) {
|
||||
ok(true, "Should have been able to cancel the promise.");
|
||||
}
|
||||
});
|
||||
});
|
@ -1,30 +0,0 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
const TEST_ROOT = "http://mochi.test:8888/browser/browser/base/content/test/favicons/";
|
||||
const TEST_URL = TEST_ROOT + "file_favicon_change.html";
|
||||
|
||||
add_task(async function() {
|
||||
let extraTab = gBrowser.selectedTab = BrowserTestUtils.addTab(gBrowser);
|
||||
let haveChanged = waitForFavicon(extraTab.linkedBrowser, TEST_ROOT + "file_bug970276_favicon1.ico");
|
||||
|
||||
extraTab.linkedBrowser.loadURI(TEST_URL);
|
||||
await BrowserTestUtils.browserLoaded(extraTab.linkedBrowser);
|
||||
await haveChanged;
|
||||
|
||||
haveChanged = waitForFavicon(extraTab.linkedBrowser, TEST_ROOT + "moz.png");
|
||||
|
||||
ContentTask.spawn(extraTab.linkedBrowser, null, function() {
|
||||
let ev = new content.CustomEvent("PleaseChangeFavicon", {});
|
||||
content.dispatchEvent(ev);
|
||||
});
|
||||
|
||||
await haveChanged;
|
||||
|
||||
ok(true, "Saw all the icons we expected.");
|
||||
|
||||
gBrowser.removeTab(extraTab);
|
||||
});
|
||||
|
@ -70,6 +70,14 @@ FaviconObserver.prototype = {
|
||||
return;
|
||||
}
|
||||
|
||||
let loadingPrincipal = reqLoadInfo.loadingPrincipal;
|
||||
|
||||
if (loadingPrincipal.equals(systemPrincipal)) {
|
||||
this._faviconReqXUL = true;
|
||||
} else {
|
||||
this._faviconReqPlaces = true;
|
||||
}
|
||||
|
||||
let haveTailFlag = !!(cos.classFlags & Ci.nsIClassOfService.Tail);
|
||||
info("classFlags=" + cos.classFlags);
|
||||
is(haveTailFlag, this._tailingEnabled, "Should have correct cos flag.");
|
||||
@ -77,10 +85,14 @@ FaviconObserver.prototype = {
|
||||
ok(false, "Received unexpected topic: ", aTopic);
|
||||
}
|
||||
|
||||
this._faviconLoaded.resolve();
|
||||
if (this._faviconReqXUL && this._faviconReqPlaces) {
|
||||
this._faviconLoaded.resolve();
|
||||
}
|
||||
},
|
||||
|
||||
reset(aPageURI, aFaviconURL, aTailingEnabled) {
|
||||
this._faviconReqXUL = false;
|
||||
this._faviconReqPlaces = false;
|
||||
this._faviconURL = aFaviconURL;
|
||||
this._faviconLoaded = PromiseUtils.defer();
|
||||
this._tailingEnabled = aTailingEnabled;
|
||||
|
@ -3,114 +3,94 @@
|
||||
|
||||
/* eslint-disable mozilla/no-arbitrary-setTimeout */
|
||||
|
||||
const ROOTURI = "http://mochi.test:8888/browser/browser/base/content/test/favicons/";
|
||||
const ICON = "moz.png";
|
||||
const DATAURL = "data:image/x-icon;base64,AAABAAEAEBAAAAAAAABoBQAAFgAAACgAAAAQAAAAIAAAAAEACAAAAAAAAAEAAAAAAAAAAAAAAAEAAAABAAAAAAAAAACAAACAAAAAgIAAgAAAAIAAgACAgAAAwMDAAMDcwADwyqYABAQEAAgICAAMDAwAERERABYWFgAcHBwAIiIiACkpKQBVVVUATU1NAEJCQgA5OTkAgHz/AFBQ/wCTANYA/+zMAMbW7wDW5+cAkKmtAAAAMwAAAGYAAACZAAAAzAAAMwAAADMzAAAzZgAAM5kAADPMAAAz/wAAZgAAAGYzAABmZgAAZpkAAGbMAABm/wAAmQAAAJkzAACZZgAAmZkAAJnMAACZ/wAAzAAAAMwzAADMZgAAzJkAAMzMAADM/wAA/2YAAP+ZAAD/zAAzAAAAMwAzADMAZgAzAJkAMwDMADMA/wAzMwAAMzMzADMzZgAzM5kAMzPMADMz/wAzZgAAM2YzADNmZgAzZpkAM2bMADNm/wAzmQAAM5kzADOZZgAzmZkAM5nMADOZ/wAzzAAAM8wzADPMZgAzzJkAM8zMADPM/wAz/zMAM/9mADP/mQAz/8wAM///AGYAAABmADMAZgBmAGYAmQBmAMwAZgD/AGYzAABmMzMAZjNmAGYzmQBmM8wAZjP/AGZmAABmZjMAZmZmAGZmmQBmZswAZpkAAGaZMwBmmWYAZpmZAGaZzABmmf8AZswAAGbMMwBmzJkAZszMAGbM/wBm/wAAZv8zAGb/mQBm/8wAzAD/AP8AzACZmQAAmTOZAJkAmQCZAMwAmQAAAJkzMwCZAGYAmTPMAJkA/wCZZgAAmWYzAJkzZgCZZpkAmWbMAJkz/wCZmTMAmZlmAJmZmQCZmcwAmZn/AJnMAACZzDMAZsxmAJnMmQCZzMwAmcz/AJn/AACZ/zMAmcxmAJn/mQCZ/8wAmf//AMwAAACZADMAzABmAMwAmQDMAMwAmTMAAMwzMwDMM2YAzDOZAMwzzADMM/8AzGYAAMxmMwCZZmYAzGaZAMxmzACZZv8AzJkAAMyZMwDMmWYAzJmZAMyZzADMmf8AzMwAAMzMMwDMzGYAzMyZAMzMzADMzP8AzP8AAMz/MwCZ/2YAzP+ZAMz/zADM//8AzAAzAP8AZgD/AJkAzDMAAP8zMwD/M2YA/zOZAP8zzAD/M/8A/2YAAP9mMwDMZmYA/2aZAP9mzADMZv8A/5kAAP+ZMwD/mWYA/5mZAP+ZzAD/mf8A/8wAAP/MMwD/zGYA/8yZAP/MzAD/zP8A//8zAMz/ZgD//5kA///MAGZm/wBm/2YAZv//AP9mZgD/Zv8A//9mACEApQBfX18Ad3d3AIaGhgCWlpYAy8vLALKysgDX19cA3d3dAOPj4wDq6uoA8fHxAPj4+ADw+/8ApKCgAICAgAAAAP8AAP8AAAD//wD/AAAA/wD/AP//AAD///8ACgoKCgoKCgoKCgoKCgoKCgoKCgoHAQEMbQoKCgoKCgoAAAdDH/kgHRIAAAAAAAAAAADrHfn5ASQQAAAAAAAAAArsBx0B+fkgHesAAAAAAAD/Cgwf+fn5IA4dEus/IvcACgcMAfkg+QEB+SABHushbf8QHR/5HQH5+QEdHetEHx4K7B/5+QH5+fkdDBL5+SBE/wwdJfkf+fn5AR8g+fkfEArsCh/5+QEeJR/5+SAeBwAACgoe+SAlHwFAEhAfAAAAAPcKHh8eASYBHhAMAAAAAAAA9EMdIB8gHh0dBwAAAAAAAAAA7BAdQ+wHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP//AADwfwAAwH8AAMB/AAAAPwAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAQAAgAcAAIAPAADADwAA8D8AAP//AAA=";
|
||||
add_task(async function() {
|
||||
let url = "http://mochi.test:8888/browser/browser/base/content/test/favicons/discovery.html";
|
||||
info("Test icons discovery");
|
||||
// First we need to clear the failed favicons cache, since previous tests
|
||||
// likely added this non-existing icon, and useDefaultIcon would skip it.
|
||||
PlacesUtils.favicons.removeFailedFavicon(makeURI("http://mochi.test:8888/favicon.ico"));
|
||||
await BrowserTestUtils.withNewTab(url, iconDiscovery);
|
||||
});
|
||||
|
||||
let iconDiscoveryTests = [
|
||||
{
|
||||
text: "rel icon discovered",
|
||||
icons: [{}]
|
||||
}, {
|
||||
text: "rel may contain additional rels separated by spaces",
|
||||
icons: [{ rel: "abcdefg icon qwerty" }],
|
||||
}, {
|
||||
text: "rel is case insensitive",
|
||||
icons: [{ rel: "ICON" }],
|
||||
}, {
|
||||
text: "rel shortcut-icon not discovered",
|
||||
expectedIcon: ROOTURI + ICON,
|
||||
icons: [ // We will prefer the later icon if detected
|
||||
{ },
|
||||
{ rel: "shortcut-icon", href: "nothere.png" },
|
||||
],
|
||||
}, {
|
||||
text: "relative href works",
|
||||
icons: [{ href: "moz.png" }],
|
||||
}, {
|
||||
text: "404'd icon is removed properly",
|
||||
pass: false,
|
||||
icons: [{ href: "notthere.png" }],
|
||||
}, {
|
||||
text: "data: URIs work",
|
||||
icons: [{ href: DATAURL, type: "image/x-icon" }],
|
||||
}, {
|
||||
text: "type may have optional parameters (RFC2046)",
|
||||
icons: [{ type: "image/png; charset=utf-8" }],
|
||||
}, {
|
||||
text: "apple-touch-icon discovered",
|
||||
richIcon: true,
|
||||
icons: [{ rel: "apple-touch-icon" }],
|
||||
}, {
|
||||
text: "apple-touch-icon-precomposed discovered",
|
||||
richIcon: true,
|
||||
icons: [{ rel: "apple-touch-icon-precomposed" }],
|
||||
}, {
|
||||
text: "fluid-icon discovered",
|
||||
richIcon: true,
|
||||
icons: [{ rel: "fluid-icon" }],
|
||||
}, {
|
||||
text: "unknown icon not discovered",
|
||||
expectedIcon: ROOTURI + ICON,
|
||||
richIcon: true,
|
||||
icons: [ // We will prefer the larger icon if detected
|
||||
{ rel: "apple-touch-icon", sizes: "32x32" },
|
||||
{ rel: "unknown-icon", sizes: "128x128", href: "notthere.png" },
|
||||
],
|
||||
},
|
||||
{ text: "rel icon discovered" },
|
||||
{ rel: "abcdefg icon qwerty", text: "rel may contain additional rels separated by spaces" },
|
||||
{ rel: "ICON", text: "rel is case insensitive" },
|
||||
{ rel: "shortcut-icon", pass: false, text: "rel shortcut-icon not discovered" },
|
||||
{ href: "moz.png", text: "relative href works" },
|
||||
{ href: "notthere.png", text: "404'd icon is removed properly" },
|
||||
{ href: "data:image/x-icon,%00", type: "image/x-icon", text: "data: URIs work" },
|
||||
{ type: "image/png; charset=utf-8", text: "type may have optional parameters (RFC2046)" },
|
||||
{ richIcon: true, rel: "apple-touch-icon", text: "apple-touch-icon discovered" },
|
||||
{ richIcon: true, rel: "apple-touch-icon-precomposed", text: "apple-touch-icon-precomposed discovered" },
|
||||
{ richIcon: true, rel: "fluid-icon", text: "fluid-icon discovered" },
|
||||
{ richIcon: true, rel: "unknown-icon", pass: false, text: "unknown icon not discovered" }
|
||||
];
|
||||
|
||||
add_task(async function() {
|
||||
let url = ROOTURI + "discovery.html";
|
||||
let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, url);
|
||||
async function iconDiscovery() {
|
||||
// Since the page doesn't have an icon, we should try using the root domain
|
||||
// icon.
|
||||
await BrowserTestUtils.waitForCondition(() => {
|
||||
return gBrowser.getIcon() == "http://mochi.test:8888/favicon.ico";
|
||||
}, "wait for default icon load to finish");
|
||||
|
||||
for (let testCase of iconDiscoveryTests) {
|
||||
info(`Running test "${testCase.text}"`);
|
||||
|
||||
if (testCase.pass === undefined)
|
||||
if (testCase.pass == undefined)
|
||||
testCase.pass = true;
|
||||
|
||||
if (testCase.icons.length > 1 && !testCase.expectedIcon) {
|
||||
ok(false, "Invalid test data, missing expectedIcon");
|
||||
continue;
|
||||
}
|
||||
// Clear the current icon.
|
||||
gBrowser.setIcon(gBrowser.selectedTab, null);
|
||||
|
||||
let expectedIcon = testCase.expectedIcon || testCase.icons[0].href || ICON;
|
||||
expectedIcon = (new URL(expectedIcon, ROOTURI)).href;
|
||||
|
||||
let iconPromise = waitForFaviconMessage(!testCase.richIcon, expectedIcon);
|
||||
|
||||
await ContentTask.spawn(gBrowser.selectedBrowser, [testCase.icons, ROOTURI + ICON], ([icons, defaultIcon]) => {
|
||||
let doc = content.document;
|
||||
let head = doc.head;
|
||||
|
||||
for (let icon of icons) {
|
||||
let link = doc.createElement("link");
|
||||
link.rel = icon.rel || "icon";
|
||||
link.href = icon.href || defaultIcon;
|
||||
link.type = icon.type || "image/png";
|
||||
if (icon.sizes) {
|
||||
link.sizes = icon.sizes;
|
||||
}
|
||||
head.appendChild(link);
|
||||
}
|
||||
let promiseLinkAdded =
|
||||
BrowserTestUtils.waitForContentEvent(gBrowser.selectedBrowser, "DOMLinkAdded",
|
||||
false, null, true);
|
||||
let promiseMessage = new Promise(resolve => {
|
||||
let mm = window.messageManager;
|
||||
mm.addMessageListener("Link:SetIcon", function listenForIcon(msg) {
|
||||
mm.removeMessageListener("Link:SetIcon", listenForIcon);
|
||||
resolve(msg.data);
|
||||
});
|
||||
});
|
||||
|
||||
try {
|
||||
let { iconURL } = await iconPromise;
|
||||
ok(testCase.pass, testCase.text);
|
||||
is(iconURL, expectedIcon, "Should have seen the expected icon.");
|
||||
} catch (e) {
|
||||
ok(!testCase.pass, testCase.text);
|
||||
await ContentTask.spawn(gBrowser.selectedBrowser, testCase, test => {
|
||||
let doc = content.document;
|
||||
let head = doc.getElementById("linkparent");
|
||||
let link = doc.createElement("link");
|
||||
link.rel = test.rel || "icon";
|
||||
link.href = test.href || "http://mochi.test:8888/browser/browser/base/content/test/favicons/moz.png";
|
||||
link.type = test.type || "image/png";
|
||||
head.appendChild(link);
|
||||
});
|
||||
|
||||
await promiseLinkAdded;
|
||||
|
||||
if (!testCase.richIcon) {
|
||||
// Because there is debounce logic in ContentLinkHandler.jsm to reduce the
|
||||
// favicon loads, we have to wait some time before checking that icon was
|
||||
// stored properly.
|
||||
try {
|
||||
await BrowserTestUtils.waitForCondition(() => {
|
||||
return gBrowser.getIcon() != null;
|
||||
}, "wait for icon load to finish", 100, 20);
|
||||
ok(testCase.pass, testCase.text);
|
||||
} catch (ex) {
|
||||
ok(!testCase.pass, testCase.text);
|
||||
}
|
||||
} else {
|
||||
// Rich icons are not set as tab icons, so just check for the SetIcon message.
|
||||
try {
|
||||
let data = await Promise.race([promiseMessage,
|
||||
new Promise((resolve, reject) => setTimeout(reject, 2000))]);
|
||||
is(data.canUseForTab, false, "Rich icons cannot be used for tabs");
|
||||
ok(testCase.pass, testCase.text);
|
||||
} catch (ex) {
|
||||
ok(!testCase.pass, testCase.text);
|
||||
}
|
||||
}
|
||||
|
||||
await ContentTask.spawn(gBrowser.selectedBrowser, null, () => {
|
||||
let links = content.document.querySelectorAll("link");
|
||||
for (let link of links) {
|
||||
link.remove();
|
||||
}
|
||||
let head = content.document.getElementById("linkparent");
|
||||
head.removeChild(head.getElementsByTagName("link")[0]);
|
||||
});
|
||||
}
|
||||
|
||||
BrowserTestUtils.removeTab(tab);
|
||||
});
|
||||
}
|
||||
|
@ -5,25 +5,36 @@ add_task(async function() {
|
||||
const ROOT = "http://mochi.test:8888/browser/browser/base/content/test/favicons/";
|
||||
const URL = ROOT + "discovery.html";
|
||||
|
||||
let iconPromise = waitForFaviconMessage(true, "http://mochi.test:8888/favicon.ico");
|
||||
let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, URL);
|
||||
let icon = await iconPromise;
|
||||
|
||||
// Because there is debounce logic in ContentLinkHandler.jsm to reduce the
|
||||
// favicon loads, we have to wait some time before checking that icon was
|
||||
// stored properly.
|
||||
let promiseIcon = BrowserTestUtils.waitForCondition(
|
||||
() => {
|
||||
let tabIcon = gBrowser.getIcon();
|
||||
info("Found icon " + tabIcon);
|
||||
return tabIcon == ROOT + "two.png";
|
||||
},
|
||||
"wait for icon load to finish", 200, 25);
|
||||
|
||||
await ContentTask.spawn(gBrowser.selectedBrowser, ROOT, root => {
|
||||
let doc = content.document;
|
||||
let head = doc.head;
|
||||
let head = doc.getElementById("linkparent");
|
||||
let link = doc.createElement("link");
|
||||
link.rel = "icon";
|
||||
link.href = root + "rich_moz_1.png";
|
||||
link.href = root + "one.png";
|
||||
link.type = "image/png";
|
||||
head.appendChild(link);
|
||||
let link2 = link.cloneNode(false);
|
||||
link2.href = root + "rich_moz_2.png";
|
||||
link2.href = root + "two.png";
|
||||
head.appendChild(link2);
|
||||
});
|
||||
|
||||
icon = await waitForFaviconMessage();
|
||||
Assert.equal(icon.iconURL, ROOT + "rich_moz_2.png", "The expected icon has been set");
|
||||
await promiseIcon;
|
||||
// The test must have at least one pass.
|
||||
Assert.equal(gBrowser.getIcon(), ROOT + "two.png",
|
||||
"The expected icon has been set");
|
||||
|
||||
BrowserTestUtils.removeTab(tab);
|
||||
});
|
||||
|
@ -3,15 +3,26 @@
|
||||
|
||||
const ROOT = "http://mochi.test:8888/browser/browser/base/content/test/favicons/";
|
||||
|
||||
async function waitIcon(url) {
|
||||
let icon = await waitForFaviconMessage(true, url);
|
||||
is(icon.iconURL, url, "Should have seen the right icon.");
|
||||
function waitIcon(url) {
|
||||
// Make sure we don't miss out on an icon if it was previously used in a test
|
||||
PlacesUtils.favicons.removeFailedFavicon(makeURI(url));
|
||||
|
||||
// Because there is debounce logic in ContentLinkHandler.jsm to reduce the
|
||||
// favicon loads, we have to wait some time before checking that icon was
|
||||
// stored properly.
|
||||
return BrowserTestUtils.waitForCondition(
|
||||
() => {
|
||||
let tabIcon = gBrowser.getIcon();
|
||||
info("Found icon " + tabIcon);
|
||||
return tabIcon == url;
|
||||
},
|
||||
"wait for icon load to finish", 200, 25);
|
||||
}
|
||||
|
||||
function createLinks(linkInfos) {
|
||||
return ContentTask.spawn(gBrowser.selectedBrowser, linkInfos, links => {
|
||||
let doc = content.document;
|
||||
let head = doc.head;
|
||||
let head = doc.getElementById("linkparent");
|
||||
for (let l of links) {
|
||||
let link = doc.createElement("link");
|
||||
link.rel = "icon";
|
||||
@ -27,9 +38,7 @@ function createLinks(linkInfos) {
|
||||
|
||||
add_task(async function setup() {
|
||||
const URL = ROOT + "discovery.html";
|
||||
let iconPromise = waitIcon("http://mochi.test:8888/favicon.ico");
|
||||
let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, URL);
|
||||
await iconPromise;
|
||||
registerCleanupFunction(async function() {
|
||||
BrowserTestUtils.removeTab(tab);
|
||||
});
|
||||
@ -50,15 +59,17 @@ add_task(async function prefer_svg() {
|
||||
},
|
||||
]);
|
||||
await promise;
|
||||
// Must have at least one test.
|
||||
Assert.ok(true, "The expected icon has been set");
|
||||
});
|
||||
|
||||
add_task(async function prefer_sized() {
|
||||
let promise = waitIcon(ROOT + "moz.png");
|
||||
let promise = waitIcon(ROOT + "icon.png");
|
||||
await createLinks([
|
||||
{ href: ROOT + "icon.ico",
|
||||
type: "image/x-icon"
|
||||
},
|
||||
{ href: ROOT + "moz.png",
|
||||
{ href: ROOT + "icon.png",
|
||||
type: "image/png",
|
||||
size: 16 * Math.ceil(window.devicePixelRatio)
|
||||
},
|
||||
@ -67,10 +78,12 @@ add_task(async function prefer_sized() {
|
||||
},
|
||||
]);
|
||||
await promise;
|
||||
// Must have at least one test.
|
||||
Assert.ok(true, "The expected icon has been set");
|
||||
});
|
||||
|
||||
add_task(async function prefer_last_ico() {
|
||||
let promise = waitIcon(ROOT + "file_generic_favicon.ico");
|
||||
let promise = waitIcon(ROOT + "icon2.ico");
|
||||
await createLinks([
|
||||
{ href: ROOT + "icon.ico",
|
||||
type: "image/x-icon"
|
||||
@ -78,15 +91,17 @@ add_task(async function prefer_last_ico() {
|
||||
{ href: ROOT + "icon.png",
|
||||
type: "image/png",
|
||||
},
|
||||
{ href: ROOT + "file_generic_favicon.ico",
|
||||
{ href: ROOT + "icon2.ico",
|
||||
type: "image/x-icon"
|
||||
},
|
||||
]);
|
||||
await promise;
|
||||
// Must have at least one test.
|
||||
Assert.ok(true, "The expected icon has been set");
|
||||
});
|
||||
|
||||
add_task(async function fuzzy_ico() {
|
||||
let promise = waitIcon(ROOT + "file_generic_favicon.ico");
|
||||
let promise = waitIcon(ROOT + "microsoft.ico");
|
||||
await createLinks([
|
||||
{ href: ROOT + "icon.ico",
|
||||
type: "image/x-icon"
|
||||
@ -94,11 +109,13 @@ add_task(async function fuzzy_ico() {
|
||||
{ href: ROOT + "icon.png",
|
||||
type: "image/png",
|
||||
},
|
||||
{ href: ROOT + "file_generic_favicon.ico",
|
||||
{ href: ROOT + "microsoft.ico",
|
||||
type: "image/vnd.microsoft.icon"
|
||||
},
|
||||
]);
|
||||
await promise;
|
||||
// Must have at least one test.
|
||||
Assert.ok(true, "The expected icon has been set");
|
||||
});
|
||||
|
||||
add_task(async function guess_svg() {
|
||||
@ -114,17 +131,21 @@ add_task(async function guess_svg() {
|
||||
},
|
||||
]);
|
||||
await promise;
|
||||
// Must have at least one test.
|
||||
Assert.ok(true, "The expected icon has been set");
|
||||
});
|
||||
|
||||
add_task(async function guess_ico() {
|
||||
let promise = waitIcon(ROOT + "file_generic_favicon.ico");
|
||||
let promise = waitIcon(ROOT + "icon.ico");
|
||||
await createLinks([
|
||||
{ href: ROOT + "file_generic_favicon.ico" },
|
||||
{ href: ROOT + "icon.ico" },
|
||||
{ href: ROOT + "icon.png",
|
||||
type: "image/png",
|
||||
},
|
||||
]);
|
||||
await promise;
|
||||
// Must have at least one test.
|
||||
Assert.ok(true, "The expected icon has been set");
|
||||
});
|
||||
|
||||
add_task(async function guess_invalid() {
|
||||
@ -140,11 +161,13 @@ add_task(async function guess_invalid() {
|
||||
{ href: "about:icon" },
|
||||
]);
|
||||
await promise;
|
||||
// Must have at least one test.
|
||||
Assert.ok(true, "The expected icon has been set");
|
||||
});
|
||||
|
||||
add_task(async function guess_bestSized() {
|
||||
let preferredWidth = 16 * Math.ceil(window.devicePixelRatio);
|
||||
let promise = waitIcon(ROOT + "moz.png");
|
||||
let promise = waitIcon(ROOT + "icon3.png");
|
||||
await createLinks([
|
||||
{ href: ROOT + "icon.png",
|
||||
type: "image/png",
|
||||
@ -153,7 +176,7 @@ add_task(async function guess_bestSized() {
|
||||
{ href: ROOT + "icon2.png",
|
||||
type: "image/png",
|
||||
},
|
||||
{ href: ROOT + "moz.png",
|
||||
{ href: ROOT + "icon3.png",
|
||||
type: "image/png",
|
||||
size: preferredWidth + 1
|
||||
},
|
||||
@ -163,4 +186,6 @@ add_task(async function guess_bestSized() {
|
||||
},
|
||||
]);
|
||||
await promise;
|
||||
// Must have at least one test.
|
||||
Assert.ok(true, "The expected icon has been set");
|
||||
});
|
||||
|
@ -9,29 +9,61 @@ add_task(async function test_richIcons() {
|
||||
const URL = ROOT + "file_rich_icon.html";
|
||||
const EXPECTED_ICON = ROOT + "moz.png";
|
||||
const EXPECTED_RICH_ICON = ROOT + "rich_moz_2.png";
|
||||
// One regular icon and one rich icon. Note that ContentLinkHandler will
|
||||
// choose the best rich icon if there are multiple candidates available
|
||||
// in the page.
|
||||
const EXPECTED_ICON_LOADS = 2;
|
||||
let loadCount = 0;
|
||||
let tabIconUri;
|
||||
let richIconUri;
|
||||
|
||||
let tabPromises = Promise.all([
|
||||
waitForFaviconMessage(true, EXPECTED_ICON),
|
||||
waitForFaviconMessage(false, EXPECTED_RICH_ICON),
|
||||
]);
|
||||
const promiseMessage = new Promise(resolve => {
|
||||
const mm = window.messageManager;
|
||||
mm.addMessageListener("Link:SetIcon", function listenForSetIcon(msg) {
|
||||
// Ignore the chrome favicon sets on the tab before the actual page load.
|
||||
if (msg.data.url === "chrome://branding/content/icon32.png")
|
||||
return;
|
||||
|
||||
if (!msg.data.canUseForTab)
|
||||
richIconUri = msg.data.url;
|
||||
|
||||
if (++loadCount === EXPECTED_ICON_LOADS) {
|
||||
mm.removeMessageListener("Link:SetIcon", listenForSetIcon);
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
const tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, URL);
|
||||
let [tabIcon, richIcon] = await tabPromises;
|
||||
await promiseMessage;
|
||||
|
||||
is(richIcon.iconURL, EXPECTED_RICH_ICON, "should choose the largest rich icon");
|
||||
is(tabIcon.iconURL, EXPECTED_ICON, "should use the non-rich icon for the tab");
|
||||
is(richIconUri, EXPECTED_RICH_ICON, "should choose the largest rich icon");
|
||||
|
||||
// Because there is debounce logic in ContentLinkHandler.jsm to reduce the
|
||||
// favicon loads, we have to wait some time before checking that icon was
|
||||
// stored properly.
|
||||
await BrowserTestUtils.waitForCondition(() => {
|
||||
tabIconUri = gBrowser.getIcon();
|
||||
return tabIconUri != null;
|
||||
}, "wait for icon load to finish", 100, 20);
|
||||
is(tabIconUri, EXPECTED_ICON, "should use the non-rich icon for the tab");
|
||||
BrowserTestUtils.removeTab(tab);
|
||||
});
|
||||
|
||||
add_task(async function test_maskIcons() {
|
||||
const URL = ROOT + "file_mask_icon.html";
|
||||
// First we need to clear the failed favicons cache, since previous tests
|
||||
// likely added this non-existing icon, and useDefaultIcon would skip it.
|
||||
PlacesUtils.favicons.removeFailedFavicon(makeURI("http://mochi.test:8888/favicon.ico"));
|
||||
const EXPECTED_ICON = "http://mochi.test:8888/favicon.ico";
|
||||
let tabIconUri;
|
||||
|
||||
let promise = waitForFaviconMessage(true, EXPECTED_ICON);
|
||||
const tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, URL);
|
||||
let tabIcon = await promise;
|
||||
is(tabIcon.iconURL, EXPECTED_ICON, "should ignore the mask icons and load the root favicon");
|
||||
|
||||
await BrowserTestUtils.waitForCondition(() => {
|
||||
tabIconUri = gBrowser.getIcon();
|
||||
return tabIconUri != null;
|
||||
}, "wait for icon load to finish", 100, 20);
|
||||
is(tabIconUri, EXPECTED_ICON, "should ignore the mask icons and load the root favicon");
|
||||
BrowserTestUtils.removeTab(tab);
|
||||
});
|
||||
|
@ -1,14 +0,0 @@
|
||||
/* Make sure <link rel="..."> isn't respected in sub-frames. */
|
||||
|
||||
add_task(async function() {
|
||||
const ROOT = "http://mochi.test:8888/browser/browser/base/content/test/favicons/";
|
||||
const URL = ROOT + "file_bug970276_popup1.html";
|
||||
|
||||
let promiseIcon = waitForFaviconMessage(true, ROOT + "file_bug970276_favicon1.ico");
|
||||
let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, URL);
|
||||
let icon = await promiseIcon;
|
||||
|
||||
Assert.equal(icon.iconURL, ROOT + "file_bug970276_favicon1.ico", "The expected icon has been set");
|
||||
|
||||
BrowserTestUtils.removeTab(tab);
|
||||
});
|
@ -1,6 +1,6 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<head id="linkparent">
|
||||
<title>Autodiscovery Test</title>
|
||||
</head>
|
||||
<body>
|
||||
|
@ -3,90 +3,9 @@
|
||||
|
||||
ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
ChromeUtils.defineModuleGetter(this, "BrowserTestUtils",
|
||||
"resource://testing-common/BrowserTestUtils.jsm");
|
||||
ChromeUtils.defineModuleGetter(this, "ContentTask",
|
||||
"resource://testing-common/ContentTask.jsm");
|
||||
ChromeUtils.defineModuleGetter(this, "PlacesUtils",
|
||||
"resource://gre/modules/PlacesUtils.jsm");
|
||||
|
||||
// Clear the network cache between every test to make sure we get a stable state
|
||||
Services.cache2.clear();
|
||||
|
||||
function waitForFaviconMessage(isTabIcon = undefined, expectedURL = undefined) {
|
||||
return new Promise((resolve, reject) => {
|
||||
let listener = msg => {
|
||||
// If requested filter out loads of the wrong kind of icon.
|
||||
if (isTabIcon != undefined && isTabIcon != msg.data.canUseForTab) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (expectedURL && msg.data.originalURL != expectedURL) {
|
||||
return;
|
||||
}
|
||||
|
||||
window.messageManager.removeMessageListener("Link:SetIcon", listener);
|
||||
window.messageManager.removeMessageListener("Link:SetFailedIcon", listener);
|
||||
|
||||
if (msg.name == "Link:SetIcon") {
|
||||
resolve({
|
||||
iconURL: msg.data.originalURL,
|
||||
dataURL: msg.data.iconURL,
|
||||
canUseForTab: msg.data.canUseForTab,
|
||||
});
|
||||
} else {
|
||||
reject({
|
||||
iconURL: msg.data.originalURL,
|
||||
canUseForTab: msg.data.canUseForTab,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
window.messageManager.addMessageListener("Link:SetIcon", listener);
|
||||
window.messageManager.addMessageListener("Link:SetFailedIcon", listener);
|
||||
});
|
||||
}
|
||||
|
||||
function waitForFavicon(browser, url) {
|
||||
return new Promise(resolve => {
|
||||
let listener = {
|
||||
onLinkIconAvailable(b, dataURI, iconURI) {
|
||||
if (b !== browser || iconURI != url) {
|
||||
return;
|
||||
}
|
||||
|
||||
gBrowser.removeTabsProgressListener(listener);
|
||||
resolve();
|
||||
}
|
||||
};
|
||||
|
||||
gBrowser.addTabsProgressListener(listener);
|
||||
});
|
||||
}
|
||||
|
||||
function waitForLinkAvailable(browser) {
|
||||
let resolve, reject;
|
||||
|
||||
let listener = {
|
||||
onLinkIconAvailable(b, dataURI, iconURI) {
|
||||
// Ignore icons for other browsers or empty icons.
|
||||
if (browser !== b || !iconURI) {
|
||||
return;
|
||||
}
|
||||
|
||||
gBrowser.removeTabsProgressListener(listener);
|
||||
resolve(iconURI);
|
||||
}
|
||||
};
|
||||
|
||||
let promise = new Promise((res, rej) => {
|
||||
resolve = res;
|
||||
reject = rej;
|
||||
|
||||
gBrowser.addTabsProgressListener(listener);
|
||||
});
|
||||
|
||||
promise.cancel = () => {
|
||||
gBrowser.removeTabsProgressListener(listener);
|
||||
|
||||
reject();
|
||||
};
|
||||
|
||||
return promise;
|
||||
}
|
||||
|
@ -1,11 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- This Source Code Form is subject to the terms of the Mozilla Public
|
||||
- License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
||||
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
|
||||
<circle cx="8" cy="8" r="8" fill="#8d20ae" />
|
||||
<circle cx="8" cy="8" r="7.5" stroke="#7b149a" stroke-width="1" fill="none" />
|
||||
<path d="M11.309,10.995C10.061,10.995,9.2,9.5,8,9.5s-2.135,1.5-3.309,1.5c-1.541,0-2.678-1.455-2.7-3.948C1.983,5.5,2.446,5.005,4.446,5.005S7.031,5.822,8,5.822s1.555-.817,3.555-0.817S14.017,5.5,14.006,7.047C13.987,9.54,12.85,10.995,11.309,10.995ZM5.426,6.911a1.739,1.739,0,0,0-1.716.953A2.049,2.049,0,0,0,5.3,8.544c0.788,0,1.716-.288,1.716-0.544A1.428,1.428,0,0,0,5.426,6.911Zm5.148,0A1.429,1.429,0,0,0,8.981,8c0,0.257.928,0.544,1.716,0.544a2.049,2.049,0,0,0,1.593-.681A1.739,1.739,0,0,0,10.574,6.911Z" stroke="#670c83" stroke-width="2" fill="none" />
|
||||
<path d="M11.309,10.995C10.061,10.995,9.2,9.5,8,9.5s-2.135,1.5-3.309,1.5c-1.541,0-2.678-1.455-2.7-3.948C1.983,5.5,2.446,5.005,4.446,5.005S7.031,5.822,8,5.822s1.555-.817,3.555-0.817S14.017,5.5,14.006,7.047C13.987,9.54,12.85,10.995,11.309,10.995ZM5.426,6.911a1.739,1.739,0,0,0-1.716.953A2.049,2.049,0,0,0,5.3,8.544c0.788,0,1.716-.288,1.716-0.544A1.428,1.428,0,0,0,5.426,6.911Zm5.148,0A1.429,1.429,0,0,0,8.981,8c0,0.257.928,0.544,1.716,0.544a2.049,2.049,0,0,0,1.593-.681A1.739,1.739,0,0,0,10.574,6.911Z" fill="#fff" />
|
||||
</svg>
|
Before Width: | Height: | Size: 1.5 KiB |
@ -35,9 +35,17 @@ support-files =
|
||||
download_page_2.txt
|
||||
dummy_page.html
|
||||
feed_tab.html
|
||||
file_generic_favicon.ico
|
||||
file_with_favicon.html
|
||||
file_mediaPlayback.html
|
||||
file_bug970276_popup1.html
|
||||
file_bug970276_popup2.html
|
||||
file_bug970276_favicon1.ico
|
||||
file_bug970276_favicon2.ico
|
||||
file_documentnavigation_frameset.html
|
||||
file_double_close_tab.html
|
||||
file_favicon_change.html
|
||||
file_favicon_change_not_in_document.html
|
||||
file_fullscreen-window-open.html
|
||||
file_with_link_to_http.html
|
||||
head.js
|
||||
@ -101,6 +109,8 @@ skip-if = (verify && !debug && (os == 'win'))
|
||||
# DO NOT ADD MORE TESTS HERE. USE A TOPICAL DIRECTORY INSTEAD.
|
||||
[browser_bug406216.js]
|
||||
# DO NOT ADD MORE TESTS HERE. USE A TOPICAL DIRECTORY INSTEAD.
|
||||
[browser_bug408415.js]
|
||||
# DO NOT ADD MORE TESTS HERE. USE A TOPICAL DIRECTORY INSTEAD.
|
||||
[browser_bug413915.js]
|
||||
# DO NOT ADD MORE TESTS HERE. USE A TOPICAL DIRECTORY INSTEAD.
|
||||
[browser_bug416661.js]
|
||||
@ -161,6 +171,8 @@ skip-if = true # bug 1393813
|
||||
# DO NOT ADD MORE TESTS HERE. USE A TOPICAL DIRECTORY INSTEAD.
|
||||
[browser_bug537474.js]
|
||||
# DO NOT ADD MORE TESTS HERE. USE A TOPICAL DIRECTORY INSTEAD.
|
||||
[browser_bug550565.js]
|
||||
# DO NOT ADD MORE TESTS HERE. USE A TOPICAL DIRECTORY INSTEAD.
|
||||
[browser_bug555224.js]
|
||||
# DO NOT ADD MORE TESTS HERE. USE A TOPICAL DIRECTORY INSTEAD.
|
||||
[browser_bug555767.js]
|
||||
@ -298,6 +310,12 @@ skip-if = (verify && !debug && (os == 'linux'))
|
||||
[browser_drag.js]
|
||||
skip-if = true # browser_drag.js is disabled, as it needs to be updated for the new behavior from bug 320638.
|
||||
# DO NOT ADD MORE TESTS HERE. USE A TOPICAL DIRECTORY INSTEAD.
|
||||
[browser_favicon_change.js]
|
||||
skip-if = verify
|
||||
# DO NOT ADD MORE TESTS HERE. USE A TOPICAL DIRECTORY INSTEAD.
|
||||
[browser_favicon_change_not_in_document.js]
|
||||
skip-if = verify
|
||||
# DO NOT ADD MORE TESTS HERE. USE A TOPICAL DIRECTORY INSTEAD.
|
||||
[browser_findbarClose.js]
|
||||
# DO NOT ADD MORE TESTS HERE. USE A TOPICAL DIRECTORY INSTEAD.
|
||||
[browser_focusonkeydown.js]
|
||||
@ -411,6 +429,8 @@ support-files =
|
||||
[browser_storagePressure_notification.js]
|
||||
skip-if = verify
|
||||
# DO NOT ADD MORE TESTS HERE. USE A TOPICAL DIRECTORY INSTEAD.
|
||||
[browser_subframe_favicons_not_used.js]
|
||||
# DO NOT ADD MORE TESTS HERE. USE A TOPICAL DIRECTORY INSTEAD.
|
||||
[browser_tab_close_dependent_window.js]
|
||||
# DO NOT ADD MORE TESTS HERE. USE A TOPICAL DIRECTORY INSTEAD.
|
||||
[browser_tabDrop.js]
|
||||
|
45
browser/base/content/test/general/browser_bug408415.js
Normal file
@ -0,0 +1,45 @@
|
||||
add_task(async function test() {
|
||||
let testPath = getRootDirectory(gTestPath);
|
||||
|
||||
await BrowserTestUtils.withNewTab({ gBrowser, url: "about:blank" },
|
||||
async function(tabBrowser) {
|
||||
const URI = testPath + "file_with_favicon.html";
|
||||
const expectedIcon = testPath + "file_generic_favicon.ico";
|
||||
|
||||
let got_favicon = PromiseUtils.defer();
|
||||
let listener = {
|
||||
onLinkIconAvailable(browser, iconURI) {
|
||||
if (got_favicon && iconURI && browser === tabBrowser) {
|
||||
got_favicon.resolve(iconURI);
|
||||
got_favicon = null;
|
||||
}
|
||||
}
|
||||
};
|
||||
gBrowser.addTabsProgressListener(listener);
|
||||
|
||||
BrowserTestUtils.loadURI(tabBrowser, URI);
|
||||
|
||||
let iconURI = await got_favicon.promise;
|
||||
is(iconURI, expectedIcon, "Correct icon before pushState.");
|
||||
|
||||
got_favicon = PromiseUtils.defer();
|
||||
got_favicon.promise.then(() => { ok(false, "shouldn't be called"); }, (e) => e);
|
||||
await ContentTask.spawn(tabBrowser, null, function() {
|
||||
content.location.href += "#foo";
|
||||
});
|
||||
|
||||
// We've navigated and shouldn't get a call to onLinkIconAvailable.
|
||||
TestUtils.executeSoon(() => {
|
||||
got_favicon.reject(gBrowser.getIcon(gBrowser.getTabForBrowser(tabBrowser)));
|
||||
});
|
||||
try {
|
||||
await got_favicon.promise;
|
||||
} catch (e) {
|
||||
iconURI = e;
|
||||
}
|
||||
is(iconURI, expectedIcon, "Correct icon after pushState.");
|
||||
|
||||
gBrowser.removeTabsProgressListener(listener);
|
||||
});
|
||||
});
|
||||
|
@ -43,8 +43,9 @@ var progressListener = {
|
||||
if (aBrowser == tab.linkedBrowser)
|
||||
record("onStateChange");
|
||||
},
|
||||
onLinkIconAvailable: function onLinkIconAvailable(aBrowser) {
|
||||
if (aBrowser == tab.linkedBrowser)
|
||||
onLinkIconAvailable: function onLinkIconAvailable(aBrowser, aIconURL) {
|
||||
if (aBrowser == tab.linkedBrowser &&
|
||||
aIconURL == "about:logo")
|
||||
record("onLinkIconAvailable");
|
||||
}
|
||||
};
|
||||
|
44
browser/base/content/test/general/browser_bug550565.js
Normal file
@ -0,0 +1,44 @@
|
||||
add_task(async function test() {
|
||||
let testPath = getRootDirectory(gTestPath);
|
||||
|
||||
await BrowserTestUtils.withNewTab({ gBrowser, url: "about:blank" },
|
||||
async function(tabBrowser) {
|
||||
const URI = testPath + "file_with_favicon.html";
|
||||
const expectedIcon = testPath + "file_generic_favicon.ico";
|
||||
|
||||
let got_favicon = PromiseUtils.defer();
|
||||
let listener = {
|
||||
onLinkIconAvailable(browser, iconURI) {
|
||||
if (got_favicon && iconURI && browser === tabBrowser) {
|
||||
got_favicon.resolve(iconURI);
|
||||
got_favicon = null;
|
||||
}
|
||||
}
|
||||
};
|
||||
gBrowser.addTabsProgressListener(listener);
|
||||
|
||||
BrowserTestUtils.loadURI(tabBrowser, URI);
|
||||
|
||||
let iconURI = await got_favicon.promise;
|
||||
is(iconURI, expectedIcon, "Correct icon before pushState.");
|
||||
|
||||
got_favicon = PromiseUtils.defer();
|
||||
got_favicon.promise.then(() => { ok(false, "shouldn't be called"); }, (e) => e);
|
||||
await ContentTask.spawn(tabBrowser, null, function() {
|
||||
content.history.pushState("page2", "page2", "page2");
|
||||
});
|
||||
|
||||
// We've navigated and shouldn't get a call to onLinkIconAvailable.
|
||||
TestUtils.executeSoon(() => {
|
||||
got_favicon.reject(gBrowser.getIcon(gBrowser.getTabForBrowser(tabBrowser)));
|
||||
});
|
||||
try {
|
||||
await got_favicon.promise;
|
||||
} catch (e) {
|
||||
iconURI = e;
|
||||
}
|
||||
is(iconURI, expectedIcon, "Correct icon after pushState.");
|
||||
|
||||
gBrowser.removeTabsProgressListener(listener);
|
||||
});
|
||||
});
|
42
browser/base/content/test/general/browser_favicon_change.js
Normal file
@ -0,0 +1,42 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
const TEST_URL = "http://mochi.test:8888/browser/browser/base/content/test/general/file_favicon_change.html";
|
||||
|
||||
add_task(async function() {
|
||||
let extraTab = gBrowser.selectedTab = BrowserTestUtils.addTab(gBrowser);
|
||||
extraTab.linkedBrowser.loadURI(TEST_URL);
|
||||
let tabLoaded = BrowserTestUtils.browserLoaded(extraTab.linkedBrowser);
|
||||
let expectedFavicon = "http://example.org/one-icon";
|
||||
let haveChanged = PromiseUtils.defer();
|
||||
let observer = new MutationObserver(function(mutations) {
|
||||
for (let mut of mutations) {
|
||||
if (mut.attributeName != "image") {
|
||||
continue;
|
||||
}
|
||||
let imageVal = extraTab.getAttribute("image").replace(/#.*$/, "");
|
||||
// Ignore chrome favicons set on the tab before the actual page load.
|
||||
if (!imageVal || !imageVal.startsWith("http://example.org/")) {
|
||||
// The value gets removed because it doesn't load.
|
||||
continue;
|
||||
}
|
||||
is(imageVal, expectedFavicon, "Favicon image should correspond to expected image.");
|
||||
haveChanged.resolve();
|
||||
}
|
||||
});
|
||||
observer.observe(extraTab, {attributes: true});
|
||||
await tabLoaded;
|
||||
await haveChanged.promise;
|
||||
haveChanged = PromiseUtils.defer();
|
||||
expectedFavicon = "http://example.org/other-icon";
|
||||
ContentTask.spawn(extraTab.linkedBrowser, null, function() {
|
||||
let ev = new content.CustomEvent("PleaseChangeFavicon", {});
|
||||
content.dispatchEvent(ev);
|
||||
});
|
||||
await haveChanged.promise;
|
||||
observer.disconnect();
|
||||
gBrowser.removeTab(extraTab);
|
||||
});
|
||||
|
@ -1,7 +1,6 @@
|
||||
"use strict";
|
||||
|
||||
const TEST_ROOT = "http://mochi.test:8888/browser/browser/base/content/test/favicons/";
|
||||
const TEST_URL = TEST_ROOT + "file_favicon_change_not_in_document.html";
|
||||
const TEST_URL = "http://mochi.test:8888/browser/browser/base/content/test/general/file_favicon_change_not_in_document.html";
|
||||
|
||||
/*
|
||||
* This test tests a link element won't fire DOMLinkChanged/DOMLinkAdded unless
|
||||
@ -23,14 +22,19 @@ add_task(async function() {
|
||||
const linkChangedhandler = event => domLinkChangedFired++;
|
||||
BrowserTestUtils.addContentEventListener(gBrowser.selectedBrowser, "DOMLinkAdded", linkAddedHandler);
|
||||
BrowserTestUtils.addContentEventListener(gBrowser.selectedBrowser, "DOMLinkChanged", linkChangedhandler);
|
||||
|
||||
let expectedFavicon = TEST_ROOT + "file_generic_favicon.ico";
|
||||
let faviconPromise = waitForFavicon(extraTab.linkedBrowser, expectedFavicon);
|
||||
|
||||
extraTab.linkedBrowser.loadURI(TEST_URL);
|
||||
await BrowserTestUtils.browserLoaded(extraTab.linkedBrowser);
|
||||
let expectedFavicon = "http://example.org/yet-another-icon";
|
||||
await promiseTabLoaded(extraTab);
|
||||
|
||||
await faviconPromise;
|
||||
// Make sure the new added favicon link gets loaded.
|
||||
try {
|
||||
await BrowserTestUtils.waitForCondition(() => {
|
||||
return gBrowser.getIcon(extraTab) === expectedFavicon;
|
||||
}, "wait for favicon load to finish", 1000, 5);
|
||||
ok(true, "Should load the added favicon");
|
||||
} catch (e) {
|
||||
ok(false, "Should've loaded the new added favicon.");
|
||||
}
|
||||
|
||||
is(domLinkAddedFired, 2, "Should fire the correct number of DOMLinkAdded event.");
|
||||
is(domLinkChangedFired, 0, "Should not fire any DOMLinkChanged event.");
|
@ -0,0 +1,32 @@
|
||||
/* Make sure <link rel="..."> isn't respected in sub-frames. */
|
||||
|
||||
function test() {
|
||||
waitForExplicitFinish();
|
||||
|
||||
let testPath = getRootDirectory(gTestPath);
|
||||
|
||||
let tab = BrowserTestUtils.addTab(gBrowser, testPath + "file_bug970276_popup1.html");
|
||||
|
||||
tab.linkedBrowser.addEventListener("load", function() {
|
||||
let expectedIcon = testPath + "file_bug970276_favicon1.ico";
|
||||
let icon;
|
||||
|
||||
// Because there is debounce logic in ContentLinkHandler.jsm to reduce the
|
||||
// favicon loads, we have to wait some time before checking that icon was
|
||||
// stored properly.
|
||||
BrowserTestUtils.waitForCondition(() => {
|
||||
icon = gBrowser.getIcon(tab);
|
||||
return icon != null;
|
||||
}, "wait for favicon load to finish", 100, 5)
|
||||
.then(() => {
|
||||
is(icon, expectedIcon, "Correct icon.");
|
||||
})
|
||||
.catch(() => {
|
||||
ok(false, "Can't get the correct icon.");
|
||||
})
|
||||
.then(() => {
|
||||
gBrowser.removeTab(tab);
|
||||
finish();
|
||||
});
|
||||
}, {capture: true, once: true});
|
||||
}
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.4 KiB |
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.4 KiB |
@ -1,13 +1,13 @@
|
||||
<!DOCTYPE html>
|
||||
<html><head>
|
||||
<meta http-equiv="content-type" content="text/html; charset=utf-8">
|
||||
<link rel="icon" href="file_bug970276_favicon1.ico" type="image/ico" id="i">
|
||||
<link rel="icon" href="http://example.org/one-icon" type="image/ico" id="i">
|
||||
</head>
|
||||
<body>
|
||||
<script>
|
||||
window.addEventListener("PleaseChangeFavicon", function() {
|
||||
var ico = document.getElementById("i");
|
||||
ico.setAttribute("href", "moz.png");
|
||||
ico.setAttribute("href", "http://example.org/other-icon");
|
||||
});
|
||||
</script>
|
||||
</body></html>
|
@ -1,7 +1,7 @@
|
||||
<!DOCTYPE html>
|
||||
<html><head>
|
||||
<meta http-equiv="content-type" content="text/html; charset=utf-8">
|
||||
<link rel="icon" href="file_bug970276_favicon1.ico" type="image/ico" id="i">
|
||||
<link rel="icon" href="http://example.org/one-icon" type="image/ico" id="i">
|
||||
</head>
|
||||
<body onload="onload()">
|
||||
<script>
|
||||
@ -9,9 +9,9 @@
|
||||
var ico = document.createElement("link");
|
||||
ico.setAttribute("rel", "icon");
|
||||
ico.setAttribute("type", "image/ico");
|
||||
ico.setAttribute("href", "file_bug970276_favicon1.ico");
|
||||
ico.setAttribute("href", "http://example.org/other-icon");
|
||||
setTimeout(function() {
|
||||
ico.setAttribute("href", "file_generic_favicon.ico");
|
||||
ico.setAttribute("href", "http://example.org/yet-another-icon");
|
||||
document.getElementById("i").remove();
|
||||
document.head.appendChild(ico);
|
||||
}, 1000);
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.4 KiB |
@ -186,6 +186,14 @@ add_task(async function navigate_around() {
|
||||
min: 50,
|
||||
max: 55,
|
||||
},
|
||||
"browser.chrome.favicons": {
|
||||
min: 50,
|
||||
max: 55,
|
||||
},
|
||||
"browser.chrome.site_icons": {
|
||||
min: 50,
|
||||
max: 55,
|
||||
},
|
||||
"toolkit.cosmeticAnimations.enabled": {
|
||||
min: 45,
|
||||
max: 55,
|
||||
|
@ -26,8 +26,6 @@ const TEST_CACHE_PAGE = TEST_DIRECTORY + "file_favicon_cache.html";
|
||||
const FAVICON_URI = TEST_DIRECTORY + "file_favicon.png";
|
||||
const TEST_FAVICON_CACHE_URI = TEST_DIRECTORY + "file_favicon_cache.png";
|
||||
|
||||
const ICON_DATA = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAABH0lEQVRYw2P8////f4YBBEwMAwxGHcBCUMX/91DGOSj/BpT/DkpzQChGBSjfBErLQsVZhmoI/L8LpRdD6X1QietQGhYy7FB5aAgwmkLpBKi4BZTPMThDgBGjHIDF+f9mKD0fKvGBRKNdoF7sgPL1saaJwZgGDkJ9vpZMn8PAHqg5G9FyifBgD4H/W9HyOWrU/f+DIzHhkoeZxxgzZEIAVtJ9RxX+Q6DAxCmP3byhXxkxshAs5odqbcioAY3UC1CBLyTGOTqAmsfAOWRCwBvqxV0oIUB2OQAzDy3/D+a6wB7q8mCU2vD/nw94GziYIQOtDRn9oXz+IZMGBKGMbCjNh9Ii+v8HR4uIAUeLiEEbb9twELaIRlqrmHG0bzjiHQAA1LVfww8jwM4AAAAASUVORK5CYII=";
|
||||
|
||||
let systemPrincipal = Services.scriptSecurityManager.getSystemPrincipal();
|
||||
let makeURI = ChromeUtils.import("resource://gre/modules/BrowserUtils.jsm", {}).BrowserUtils.makeURI;
|
||||
|
||||
@ -58,7 +56,10 @@ function clearAllPlacesFavicons() {
|
||||
});
|
||||
}
|
||||
|
||||
function observeFavicon(aFirstPartyDomain, aExpectedCookie, aPageURI) {
|
||||
function observeFavicon(aFirstPartyDomain, aExpectedCookie, aPageURI, aOnlyXUL) {
|
||||
let faviconReqXUL = false;
|
||||
// If aOnlyXUL is true, we only care about the favicon request from XUL.
|
||||
let faviconReqPlaces = aOnlyXUL === true;
|
||||
let expectedPrincipal = Services.scriptSecurityManager
|
||||
.createCodebasePrincipal(aPageURI, { firstPartyDomain: aFirstPartyDomain });
|
||||
|
||||
@ -88,10 +89,15 @@ function observeFavicon(aFirstPartyDomain, aExpectedCookie, aPageURI) {
|
||||
is(reqLoadInfo.originAttributes.firstPartyDomain, aFirstPartyDomain,
|
||||
"The loadInfo has correct first party domain");
|
||||
|
||||
ok(loadingPrincipal.equals(expectedPrincipal),
|
||||
"The loadingPrincipal of favicon loads should be the content prinicpal");
|
||||
ok(triggeringPrincipal.equals(expectedPrincipal),
|
||||
"The triggeringPrincipal of favicon loads should be the content prinicpal");
|
||||
if (loadingPrincipal.equals(systemPrincipal)) {
|
||||
faviconReqXUL = true;
|
||||
ok(triggeringPrincipal.equals(expectedPrincipal),
|
||||
"The triggeringPrincipal of favicon loading from XUL should be the content principal.");
|
||||
} else {
|
||||
faviconReqPlaces = true;
|
||||
ok(loadingPrincipal.equals(expectedPrincipal),
|
||||
"The loadingPrincipal of favicon loading from Places should be the content prinicpal");
|
||||
}
|
||||
|
||||
let faviconCookie = httpChannel.getRequestHeader("cookie");
|
||||
|
||||
@ -100,8 +106,10 @@ function observeFavicon(aFirstPartyDomain, aExpectedCookie, aPageURI) {
|
||||
ok(false, "Received unexpected topic: ", aTopic);
|
||||
}
|
||||
|
||||
Services.obs.removeObserver(observer, "http-on-modify-request");
|
||||
resolve();
|
||||
if (faviconReqXUL && faviconReqPlaces) {
|
||||
Services.obs.removeObserver(observer, "http-on-modify-request");
|
||||
resolve();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@ -207,12 +215,6 @@ async function generateCookies(aThirdParty) {
|
||||
return cookies;
|
||||
}
|
||||
|
||||
function assertIconIsData(item) {
|
||||
let icon = item.getAttribute("image");
|
||||
is(icon.substring(0, 5), "data:", "Expected the image element to be a data URI");
|
||||
is(icon, ICON_DATA, "Expected to see the correct data.");
|
||||
}
|
||||
|
||||
async function doTest(aTestPage, aExpectedCookies, aFaviconURL) {
|
||||
let firstPageURI = makeURI(TEST_SITE_ONE + aTestPage);
|
||||
let secondPageURI = makeURI(TEST_SITE_TWO + aTestPage);
|
||||
@ -232,8 +234,6 @@ async function doTest(aTestPage, aExpectedCookies, aFaviconURL) {
|
||||
// Waiting until favicon loaded.
|
||||
await promiseFaviconLoaded;
|
||||
|
||||
assertIconIsData(tabInfo.tab);
|
||||
|
||||
BrowserTestUtils.removeTab(tabInfo.tab);
|
||||
// FIXME: We need to wait for the next event tick here to avoid observing
|
||||
// the previous tab info in the next step (bug 1446725).
|
||||
@ -252,6 +252,8 @@ async function doTest(aTestPage, aExpectedCookies, aFaviconURL) {
|
||||
}
|
||||
|
||||
async function doTestForAllTabsFavicon(aTestPage, aExpectedCookies, aIsThirdParty) {
|
||||
let firstPageURI = makeURI(TEST_SITE_ONE + aTestPage);
|
||||
let secondPageURI = makeURI(TEST_SITE_TWO + aTestPage);
|
||||
let faviconURI = aIsThirdParty ? THIRD_PARTY_SITE + FAVICON_URI :
|
||||
TEST_SITE_ONE + FAVICON_URI;
|
||||
|
||||
@ -268,16 +270,21 @@ async function doTestForAllTabsFavicon(aTestPage, aExpectedCookies, aIsThirdPart
|
||||
// Waiting until the favicon loaded.
|
||||
await promiseFaviconLoaded;
|
||||
|
||||
assertIconIsData(tabInfo.tab);
|
||||
// We need to clear the image cache here for making sure the network request will
|
||||
// be made for the favicon of allTabs menuitem.
|
||||
clearAllImageCaches();
|
||||
|
||||
// Start to observe the allTabs favicon requests earlier in case we miss it.
|
||||
let promiseObserveFavicon = observeFavicon(FIRST_PARTY_ONE, aExpectedCookies[0],
|
||||
firstPageURI, true);
|
||||
|
||||
// Make the popup of allTabs showing up and trigger the loading of the favicon.
|
||||
let allTabsView = document.getElementById("allTabsMenu-allTabsView");
|
||||
let allTabsPopupShownPromise = BrowserTestUtils.waitForEvent(allTabsView, "ViewShown");
|
||||
gTabsPanel.showAllTabsPanel();
|
||||
await promiseObserveFavicon;
|
||||
await allTabsPopupShownPromise;
|
||||
|
||||
assertIconIsData(gTabsPanel.allTabsViewTabs.lastChild.firstChild);
|
||||
|
||||
// Close the popup of allTabs and wait until it's done.
|
||||
let allTabsPopupHiddenPromise = BrowserTestUtils.waitForEvent(allTabsView.panelMultiView, "PanelMultiViewHidden");
|
||||
gTabsPanel.hideAllTabsPanel();
|
||||
@ -298,15 +305,19 @@ async function doTestForAllTabsFavicon(aTestPage, aExpectedCookies, aIsThirdPart
|
||||
// Wait until the favicon is fully loaded.
|
||||
await promiseFaviconLoaded;
|
||||
|
||||
assertIconIsData(tabInfo.tab);
|
||||
// Clear the image cache for the favicon of the second site.
|
||||
clearAllImageCaches();
|
||||
|
||||
// Start to observe the allTabs favicon requests earlier in case we miss it.
|
||||
promiseObserveFavicon = observeFavicon(FIRST_PARTY_TWO, aExpectedCookies[1],
|
||||
secondPageURI, true);
|
||||
|
||||
// Make the popup of allTabs showing up again.
|
||||
allTabsPopupShownPromise = BrowserTestUtils.waitForEvent(allTabsView, "ViewShown");
|
||||
gTabsPanel.showAllTabsPanel();
|
||||
await promiseObserveFavicon;
|
||||
await allTabsPopupShownPromise;
|
||||
|
||||
assertIconIsData(gTabsPanel.allTabsViewTabs.lastChild.firstChild);
|
||||
|
||||
// Close the popup of allTabs and wait until it's done.
|
||||
allTabsPopupHiddenPromise = BrowserTestUtils.waitForEvent(allTabsView.panelMultiView, "PanelMultiViewHidden");
|
||||
gTabsPanel.hideAllTabsPanel();
|
||||
@ -402,12 +413,17 @@ add_task(async function test_favicon_cache_firstParty() {
|
||||
// Waiting until the favicon has been loaded and cached.
|
||||
await promiseForFaviconLoaded;
|
||||
|
||||
// Here, we are going to observe the favicon response for the third tab which
|
||||
// opens with the second first party.
|
||||
// Open the tab again for checking the image cache is working correctly.
|
||||
let tabInfoB = await openTab(TEST_SITE_ONE + TEST_CACHE_PAGE);
|
||||
|
||||
// Start to observe the favicon response, the second tab actually will not
|
||||
// make any network request since the favicon will be loaded by the cache for
|
||||
// both Places and XUL image. So here, we are going to observe the favicon
|
||||
// response for the third tab which opens with the second first party.
|
||||
let promiseForFaviconResponse = waitOnFaviconResponse(THIRD_PARTY_SITE + TEST_FAVICON_CACHE_URI);
|
||||
|
||||
// Open the tab for the second site.
|
||||
let tabInfoB = await openTab(TEST_SITE_TWO + TEST_CACHE_PAGE);
|
||||
let tabInfoC = await openTab(TEST_SITE_TWO + TEST_CACHE_PAGE);
|
||||
|
||||
// Wait for the favicon response. In this case, we suppose to catch the
|
||||
// response for the third tab but not the second tab since it will not
|
||||
@ -421,4 +437,5 @@ add_task(async function test_favicon_cache_firstParty() {
|
||||
|
||||
BrowserTestUtils.removeTab(tabInfoA.tab);
|
||||
BrowserTestUtils.removeTab(tabInfoB.tab);
|
||||
BrowserTestUtils.removeTab(tabInfoC.tab);
|
||||
});
|
||||
|
@ -56,8 +56,8 @@ function clearAllPlacesFavicons() {
|
||||
});
|
||||
}
|
||||
|
||||
function FaviconObserver(aUserContextId, aExpectedCookie, aPageURI, aFaviconURL) {
|
||||
this.reset(aUserContextId, aExpectedCookie, aPageURI, aFaviconURL);
|
||||
function FaviconObserver(aUserContextId, aExpectedCookie, aPageURI, aFaviconURL, aOnlyXUL) {
|
||||
this.reset(aUserContextId, aExpectedCookie, aPageURI, aFaviconURL, aOnlyXUL);
|
||||
}
|
||||
|
||||
FaviconObserver.prototype = {
|
||||
@ -73,7 +73,8 @@ FaviconObserver.prototype = {
|
||||
|
||||
let httpChannel = aSubject.QueryInterface(Ci.nsIHttpChannel);
|
||||
let reqLoadInfo = httpChannel.loadInfo;
|
||||
let loadingPrincipal, triggeringPrincipal;
|
||||
let loadingPrincipal;
|
||||
let triggeringPrincipal;
|
||||
|
||||
// Make sure this is a favicon request.
|
||||
if (httpChannel.URI.spec !== this._faviconURL) {
|
||||
@ -89,10 +90,15 @@ FaviconObserver.prototype = {
|
||||
is(reqLoadInfo.originAttributes.userContextId, this._curUserContextId,
|
||||
"The loadInfo has correct userContextId");
|
||||
|
||||
ok(loadingPrincipal.equals(this._expectedPrincipal),
|
||||
"The loadingPrincipal of favicon loading from content should be the content prinicpal");
|
||||
ok(triggeringPrincipal.equals(this._expectedPrincipal),
|
||||
"The triggeringPrincipal of favicon loading from content should be the content prinicpal");
|
||||
if (loadingPrincipal.equals(systemPrincipal)) {
|
||||
this._faviconReqXUL = true;
|
||||
ok(triggeringPrincipal.equals(this._expectedPrincipal),
|
||||
"The triggeringPrincipal of favicon loading from XUL should be the content principal.");
|
||||
} else {
|
||||
this._faviconReqPlaces = true;
|
||||
ok(loadingPrincipal.equals(this._expectedPrincipal),
|
||||
"The loadingPrincipal of favicon loading from Places should be the content prinicpal");
|
||||
}
|
||||
|
||||
let faviconCookie = httpChannel.getRequestHeader("cookie");
|
||||
|
||||
@ -101,7 +107,9 @@ FaviconObserver.prototype = {
|
||||
ok(false, "Received unexpected topic: ", aTopic);
|
||||
}
|
||||
|
||||
this._faviconLoaded.resolve();
|
||||
if (this._faviconReqXUL && this._faviconReqPlaces) {
|
||||
this._faviconLoaded.resolve();
|
||||
}
|
||||
},
|
||||
|
||||
reset(aUserContextId, aExpectedCookie, aPageURI, aFaviconURL, aOnlyXUL) {
|
||||
@ -109,6 +117,9 @@ FaviconObserver.prototype = {
|
||||
this._expectedCookie = aExpectedCookie;
|
||||
this._expectedPrincipal = Services.scriptSecurityManager
|
||||
.createCodebasePrincipal(aPageURI, { userContextId: aUserContextId });
|
||||
this._faviconReqXUL = false;
|
||||
// If aOnlyXUL is true, we only care about the favicon request from XUL.
|
||||
this._faviconReqPlaces = aOnlyXUL === true;
|
||||
this._faviconURL = aFaviconURL;
|
||||
this._faviconLoaded = new Promise.defer();
|
||||
},
|
||||
@ -198,17 +209,18 @@ async function doTest(aTestPage, aFaviconHost, aFaviconURL) {
|
||||
BrowserTestUtils.removeTab(tabInfo.tab);
|
||||
}
|
||||
|
||||
function assertIconIsData(item) {
|
||||
is(item.getAttribute("image").substring(0, 5), "data:", "Expected the image element to be a data URI");
|
||||
}
|
||||
|
||||
async function doTestForAllTabsFavicon(aTestPage, aFaviconHost, aFaviconURL) {
|
||||
await generateCookies(aFaviconHost);
|
||||
let cookies = await generateCookies(aFaviconHost);
|
||||
let pageURI = makeURI(aTestPage);
|
||||
|
||||
// Set the 'overflow' attribute to make allTabs button available.
|
||||
let tabBrowser = document.getElementById("tabbrowser-tabs");
|
||||
tabBrowser.setAttribute("overflow", true);
|
||||
|
||||
// Create the observer object for observing request channels of the personal
|
||||
// container.
|
||||
let observer = new FaviconObserver(USER_CONTEXT_ID_PERSONAL, cookies[0], pageURI, aFaviconURL, true);
|
||||
|
||||
// Add the observer earlier in case we miss it.
|
||||
let promiseWaitOnFaviconLoaded = waitOnFaviconLoaded(aFaviconURL);
|
||||
|
||||
@ -222,19 +234,25 @@ async function doTestForAllTabsFavicon(aTestPage, aFaviconHost, aFaviconURL) {
|
||||
// be made for the favicon of allTabs menuitem.
|
||||
clearAllImageCaches();
|
||||
|
||||
// Add the observer for listening favicon requests.
|
||||
Services.obs.addObserver(observer, "http-on-modify-request");
|
||||
|
||||
// Make the popup of allTabs showing up and trigger the loading of the favicon.
|
||||
let allTabsView = document.getElementById("allTabsMenu-allTabsView");
|
||||
let allTabsPopupShownPromise = BrowserTestUtils.waitForEvent(allTabsView, "ViewShown");
|
||||
gTabsPanel.showAllTabsPanel();
|
||||
await observer.promise;
|
||||
await allTabsPopupShownPromise;
|
||||
|
||||
assertIconIsData(gTabsPanel.allTabsViewTabs.lastChild.firstChild);
|
||||
|
||||
// Close the popup of allTabs and wait until it's done.
|
||||
let allTabsPopupHiddenPromise = BrowserTestUtils.waitForEvent(allTabsView.panelMultiView, "PanelMultiViewHidden");
|
||||
gTabsPanel.hideAllTabsPanel();
|
||||
await allTabsPopupHiddenPromise;
|
||||
|
||||
// Remove the observer for not receiving the favicon requests for opening a tab
|
||||
// since we want to focus on the favicon of allTabs menu here.
|
||||
Services.obs.removeObserver(observer, "http-on-modify-request");
|
||||
|
||||
// Close the tab.
|
||||
BrowserTestUtils.removeTab(tabInfo.tab);
|
||||
// FIXME: We need to wait for the next event tick here to avoid observing
|
||||
@ -249,18 +267,25 @@ async function doTestForAllTabsFavicon(aTestPage, aFaviconHost, aFaviconURL) {
|
||||
// Clear the image cache again.
|
||||
clearAllImageCaches();
|
||||
|
||||
// Reset the observer for observing requests for the work container.
|
||||
observer.reset(USER_CONTEXT_ID_WORK, cookies[1], pageURI, aFaviconURL, true);
|
||||
|
||||
// Add the observer back for listening the favicon requests for allTabs menuitem.
|
||||
Services.obs.addObserver(observer, "http-on-modify-request");
|
||||
|
||||
// Make the popup of allTabs showing up again.
|
||||
allTabsPopupShownPromise = BrowserTestUtils.waitForEvent(allTabsView, "ViewShown");
|
||||
gTabsPanel.showAllTabsPanel();
|
||||
await observer.promise;
|
||||
await allTabsPopupShownPromise;
|
||||
|
||||
assertIconIsData(gTabsPanel.allTabsViewTabs.lastChild.firstChild);
|
||||
|
||||
// Close the popup of allTabs and wait until it's done.
|
||||
allTabsPopupHiddenPromise = BrowserTestUtils.waitForEvent(allTabsView.panelMultiView, "PanelMultiViewHidden");
|
||||
gTabsPanel.hideAllTabsPanel();
|
||||
await allTabsPopupHiddenPromise;
|
||||
|
||||
Services.obs.removeObserver(observer, "http-on-modify-request");
|
||||
|
||||
// Close the tab.
|
||||
BrowserTestUtils.removeTab(tabInfo.tab);
|
||||
|
||||
|
@ -163,7 +163,7 @@ let InternalFaviconLoader = {
|
||||
});
|
||||
},
|
||||
|
||||
loadFavicon(browser, principal, uri, expiration = null, iconURI = null) {
|
||||
loadFavicon(browser, principal, uri, requestContextID) {
|
||||
this.ensureInitialized();
|
||||
let win = browser.ownerGlobal;
|
||||
if (!gFaviconLoadDataMap.has(win)) {
|
||||
@ -186,15 +186,9 @@ let InternalFaviconLoader = {
|
||||
? PlacesUtils.favicons.FAVICON_LOAD_PRIVATE
|
||||
: PlacesUtils.favicons.FAVICON_LOAD_NON_PRIVATE;
|
||||
let callback = this._makeCompletionCallback(win, innerWindowID);
|
||||
|
||||
if (iconURI && iconURI.schemeIs("data")) {
|
||||
expiration = PlacesUtils.toPRTime(expiration || 0);
|
||||
PlacesUtils.favicons.replaceFaviconDataFromDataURL(uri, iconURI.spec,
|
||||
expiration, principal);
|
||||
}
|
||||
|
||||
let request = PlacesUtils.favicons.setAndFetchFaviconForPage(currentURI, uri, false,
|
||||
loadType, callback, principal);
|
||||
loadType, callback, principal,
|
||||
requestContextID);
|
||||
|
||||
// Now register the result so we can cancel it if/when necessary.
|
||||
if (!request) {
|
||||
|
@ -2108,7 +2108,7 @@ var gMainPane = {
|
||||
// they'll only visit URLs derived from that template (i.e. with %s
|
||||
// in the template replaced by the URL of the content being handled).
|
||||
|
||||
if (/^https?$/.test(uri.scheme) && Services.prefs.getBoolPref("browser.chrome.site_icons"))
|
||||
if (/^https?$/.test(uri.scheme) && Services.prefs.getBoolPref("browser.chrome.favicons"))
|
||||
return uri.prePath + "/favicon.ico";
|
||||
|
||||
return "";
|
||||
|
@ -44,6 +44,8 @@ function clearAllPlacesFavicons() {
|
||||
}
|
||||
|
||||
function observeFavicon(aIsPrivate, aExpectedCookie, aPageURI) {
|
||||
let faviconReqXUL = false;
|
||||
let faviconReqPlaces = false;
|
||||
let attr = {};
|
||||
|
||||
if (aIsPrivate) {
|
||||
@ -68,6 +70,7 @@ function observeFavicon(aIsPrivate, aExpectedCookie, aPageURI) {
|
||||
let httpChannel = aSubject.QueryInterface(Ci.nsIHttpChannel);
|
||||
let reqLoadInfo = httpChannel.loadInfo;
|
||||
let loadingPrincipal = reqLoadInfo.loadingPrincipal;
|
||||
let triggeringPrincipal = reqLoadInfo.triggeringPrincipal;
|
||||
|
||||
// Make sure this is a favicon request.
|
||||
if (httpChannel.URI.spec !== FAVICON_URI) {
|
||||
@ -81,8 +84,15 @@ function observeFavicon(aIsPrivate, aExpectedCookie, aPageURI) {
|
||||
is(reqLoadInfo.originAttributes.privateBrowsingId, 0, "The loadInfo has correct privateBrowsingId");
|
||||
}
|
||||
|
||||
ok(loadingPrincipal.equals(expectedPrincipal),
|
||||
"The loadingPrincipal of favicon loading from Places should be the content prinicpal");
|
||||
if (loadingPrincipal.equals(systemPrincipal)) {
|
||||
faviconReqXUL = true;
|
||||
ok(triggeringPrincipal.equals(expectedPrincipal),
|
||||
"The triggeringPrincipal of favicon loading from XUL should be the content principal.");
|
||||
} else {
|
||||
faviconReqPlaces = true;
|
||||
ok(loadingPrincipal.equals(expectedPrincipal),
|
||||
"The loadingPrincipal of favicon loading from Places should be the content prinicpal");
|
||||
}
|
||||
|
||||
let faviconCookie = httpChannel.getRequestHeader("cookie");
|
||||
|
||||
@ -91,8 +101,10 @@ function observeFavicon(aIsPrivate, aExpectedCookie, aPageURI) {
|
||||
ok(false, "Received unexpected topic: ", aTopic);
|
||||
}
|
||||
|
||||
resolve();
|
||||
Services.obs.removeObserver(observer, "http-on-modify-request");
|
||||
if (faviconReqXUL && faviconReqPlaces) {
|
||||
resolve();
|
||||
Services.obs.removeObserver(observer, "http-on-modify-request");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -25,8 +25,9 @@ add_task(async function test() {
|
||||
return gBrowser.getIcon(tab) != null;
|
||||
}, "wait for favicon load to finish", 100, 5);
|
||||
|
||||
// Check that the tab has an 'image' attribute.
|
||||
// Check that the tab has 'image' and 'iconloadingprincipal' attributes.
|
||||
ok(tab.hasAttribute("image"), "tab.image exists");
|
||||
ok(tab.hasAttribute("iconloadingprincipal"), "tab.iconloadingprincipal exists");
|
||||
|
||||
tab.toggleMuteAudio();
|
||||
// Check that the tab has a 'muted' attribute.
|
||||
@ -35,8 +36,10 @@ add_task(async function test() {
|
||||
// Make sure we do not persist 'image' and 'muted' attributes.
|
||||
ss.persistTabAttribute("image");
|
||||
ss.persistTabAttribute("muted");
|
||||
ss.persistTabAttribute("iconloadingprincipal");
|
||||
let {attributes} = JSON.parse(ss.getTabState(tab));
|
||||
ok(!("image" in attributes), "'image' attribute not saved");
|
||||
ok(!("iconloadingprincipal" in attributes), "'iconloadingprincipal' attribute not saved");
|
||||
ok(!("muted" in attributes), "'muted' attribute not saved");
|
||||
ok(!("custom" in attributes), "'custom' attribute not saved");
|
||||
|
||||
|
@ -39,6 +39,13 @@ add_task(async function test_label_and_icon() {
|
||||
is(gBrowser.getIcon(tab), "chrome://browser/content/robot.ico", "icon is set");
|
||||
is(tab.label, "Gort! Klaatu barada nikto!", "label is set");
|
||||
|
||||
let serhelper = Cc["@mozilla.org/network/serialization-helper;1"]
|
||||
.getService(Ci.nsISerializationHelper);
|
||||
let serializedPrincipal = tab.getAttribute("iconloadingprincipal");
|
||||
let iconLoadingPrincipal = serhelper.deserializeObject(serializedPrincipal)
|
||||
.QueryInterface(Ci.nsIPrincipal);
|
||||
is(iconLoadingPrincipal.origin, "about:robots", "correct loadingPrincipal used");
|
||||
|
||||
// Cleanup.
|
||||
BrowserTestUtils.removeTab(tab);
|
||||
});
|
||||
|
@ -4,21 +4,13 @@
|
||||
|
||||
"use strict";
|
||||
|
||||
const EXPORTED_SYMBOLS = ["ContentLinkHandler"];
|
||||
var EXPORTED_SYMBOLS = [ "ContentLinkHandler" ];
|
||||
|
||||
ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyGlobalGetters(this, ["Blob", "FileReader"]);
|
||||
|
||||
ChromeUtils.defineModuleGetter(this, "Feeds",
|
||||
"resource:///modules/Feeds.jsm");
|
||||
ChromeUtils.defineModuleGetter(this, "NetUtil",
|
||||
"resource://gre/modules/NetUtil.jsm");
|
||||
ChromeUtils.defineModuleGetter(this, "DeferredTask",
|
||||
"resource://gre/modules/DeferredTask.jsm");
|
||||
ChromeUtils.defineModuleGetter(this, "PromiseUtils",
|
||||
"resource://gre/modules/PromiseUtils.jsm");
|
||||
|
||||
const SIZES_TELEMETRY_ENUM = {
|
||||
NO_SIZES: 0,
|
||||
@ -29,148 +21,21 @@ const SIZES_TELEMETRY_ENUM = {
|
||||
|
||||
const FAVICON_PARSING_TIMEOUT = 100;
|
||||
const FAVICON_RICH_ICON_MIN_WIDTH = 96;
|
||||
const PREFERRED_WIDTH = 16;
|
||||
|
||||
// URL schemes that we don't want to load and convert to data URLs.
|
||||
const LOCAL_FAVICON_SCHEMES = [
|
||||
"chrome",
|
||||
"about",
|
||||
"resource",
|
||||
"data",
|
||||
];
|
||||
|
||||
const MAX_FAVICON_EXPIRATION = 7 * 24 * 60 * 60 * 1000;
|
||||
|
||||
const TYPE_ICO = "image/x-icon";
|
||||
const TYPE_SVG = "image/svg+xml";
|
||||
|
||||
function promiseBlobAsDataURL(blob) {
|
||||
return new Promise((resolve, reject) => {
|
||||
let reader = new FileReader();
|
||||
reader.addEventListener("load", () => resolve(reader.result));
|
||||
reader.addEventListener("error", reject);
|
||||
reader.readAsDataURL(blob);
|
||||
});
|
||||
}
|
||||
|
||||
function promiseBlobAsOctets(blob) {
|
||||
return new Promise((resolve, reject) => {
|
||||
let reader = new FileReader();
|
||||
reader.addEventListener("load", () => {
|
||||
resolve(Array.from(reader.result).map(c => c.charCodeAt(0)));
|
||||
});
|
||||
reader.addEventListener("error", reject);
|
||||
reader.readAsBinaryString(blob);
|
||||
});
|
||||
}
|
||||
|
||||
class FaviconLoad {
|
||||
constructor(iconInfo) {
|
||||
this.buffers = [];
|
||||
this.icon = iconInfo;
|
||||
|
||||
this.channel = NetUtil.newChannel({
|
||||
uri: iconInfo.iconUri,
|
||||
loadingNode: iconInfo.node,
|
||||
loadingPrincipal: iconInfo.node.nodePrincipal,
|
||||
triggeringPrincipal: iconInfo.node.nodePrincipal,
|
||||
contentPolicyType: Ci.nsIContentPolicy.TYPE_INTERNAL_IMAGE_FAVICON,
|
||||
securityFlags: Ci.nsILoadInfo.SEC_ALLOW_CROSS_ORIGIN_DATA_INHERITS |
|
||||
Ci.nsILoadInfo.SEC_ALLOW_CHROME |
|
||||
Ci.nsILoadInfo.SEC_DISALLOW_SCRIPT,
|
||||
});
|
||||
|
||||
this.channel.loadFlags |= Ci.nsIRequest.LOAD_BACKGROUND;
|
||||
// Sometimes node is a document and sometimes it is an element. This is
|
||||
// the easiest single way to get to the load group in both those cases.
|
||||
this.channel.loadGroup = iconInfo.node.ownerGlobal.document.documentLoadGroup;
|
||||
|
||||
if (Services.prefs.getBoolPref("network.http.tailing.enabled", true) &&
|
||||
this.channel instanceof Ci.nsIClassOfService) {
|
||||
this.channel.addClassFlags(Ci.nsIClassOfService.Tail | Ci.nsIClassOfService.Throttleable);
|
||||
}
|
||||
}
|
||||
|
||||
load() {
|
||||
this._deferred = PromiseUtils.defer();
|
||||
|
||||
try {
|
||||
this.channel.asyncOpen2(this);
|
||||
} catch (e) {
|
||||
this._deferred.reject(e);
|
||||
}
|
||||
|
||||
return this._deferred.promise;
|
||||
}
|
||||
|
||||
cancel() {
|
||||
this._deferred.reject(Components.Exception(`Favicon load from ${this.icon.iconUri.spec} was cancelled.`, Cr.NS_BINDING_ABORTED));
|
||||
this.channel.cancel(Cr.NS_BINDING_ABORTED);
|
||||
}
|
||||
|
||||
onStartRequest(request, context) {
|
||||
}
|
||||
|
||||
onDataAvailable(request, context, inputStream, offset, count) {
|
||||
let data = NetUtil.readInputStreamToString(inputStream, count);
|
||||
this.buffers.push(Uint8Array.from(data, c => c.charCodeAt(0)));
|
||||
}
|
||||
|
||||
async onStopRequest(request, context, statusCode) {
|
||||
if (!Components.isSuccessCode(statusCode)) {
|
||||
// If the load was cancelled the promise will have been rejected then.
|
||||
if (statusCode != Cr.NS_BINDING_ABORTED) {
|
||||
this._deferred.reject(Components.Exception(`Favicon at "${this.icon.iconUri.spec}" failed to load.`, statusCode));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.channel instanceof Ci.nsIHttpChannel) {
|
||||
if (!this.channel.requestSucceeded) {
|
||||
this._deferred.reject(Components.Exception(`Favicon at "${this.icon.iconUri.spec}" failed to load: ${this.channel.responseStatusText}.`, Cr.NS_ERROR_FAILURE));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Attempt to get an expiration time from the cache. If this fails, we'll
|
||||
// use this default.
|
||||
let expiration = Date.now() + MAX_FAVICON_EXPIRATION;
|
||||
|
||||
// This stuff isn't available after onStopRequest returns (so don't start
|
||||
// any async operations before this!).
|
||||
if (this.channel instanceof Ci.nsICacheInfoChannel) {
|
||||
expiration = Math.min(this.channel.cacheTokenExpirationTime * 1000, expiration);
|
||||
}
|
||||
|
||||
let type = this.channel.contentType;
|
||||
let blob = new Blob(this.buffers, { type });
|
||||
|
||||
if (type != "image/svg+xml") {
|
||||
let octets = await promiseBlobAsOctets(blob);
|
||||
let sniffer = Cc["@mozilla.org/image/loader;1"].
|
||||
createInstance(Ci.nsIContentSniffer);
|
||||
try {
|
||||
type = sniffer.getMIMETypeFromContent(this.channel, octets, octets.length);
|
||||
} catch (e) {
|
||||
this._deferred.reject(e);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!type) {
|
||||
this._deferred.reject(Components.Exception(`Favicon at "${this.icon.iconUri.spec}" did not match a known mimetype.`, Cr.NS_ERROR_FAILURE));
|
||||
return;
|
||||
}
|
||||
|
||||
blob = blob.slice(0, blob.size, type);
|
||||
}
|
||||
|
||||
let dataURL = await promiseBlobAsDataURL(blob);
|
||||
|
||||
this._deferred.resolve({
|
||||
expiration,
|
||||
dataURL,
|
||||
});
|
||||
}
|
||||
/*
|
||||
* Create a nsITimer.
|
||||
*
|
||||
* @param {function} aCallback A timeout callback function.
|
||||
* @param {Number} aDelay A timeout interval in millisecond.
|
||||
* @return {nsITimer} A nsITimer object.
|
||||
*/
|
||||
function setTimeout(aCallback, aDelay) {
|
||||
let timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
|
||||
timer.initWithCallback(aCallback, aDelay, Ci.nsITimer.TYPE_ONE_SHOT);
|
||||
return timer;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -232,6 +97,25 @@ function getLinkIconURI(aLink) {
|
||||
return uri;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the icon via sending the "Link:Seticon" message.
|
||||
*
|
||||
* @param {Object} aIconInfo The IconInfo object looks like {
|
||||
* iconUri: icon URI,
|
||||
* loadingPrincipal: icon loading principal
|
||||
* }.
|
||||
* @param {Object} aChromeGlobal A global chrome object.
|
||||
*/
|
||||
function setIconForLink(aIconInfo, aChromeGlobal) {
|
||||
aChromeGlobal.sendAsyncMessage(
|
||||
"Link:SetIcon",
|
||||
{ url: aIconInfo.iconUri.spec,
|
||||
loadingPrincipal: aIconInfo.loadingPrincipal,
|
||||
requestContextID: aIconInfo.requestContextID,
|
||||
canUseForTab: !aIconInfo.isRichIcon,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Guess a type for an icon based on its declared type or file extension.
|
||||
*/
|
||||
@ -257,21 +141,23 @@ function guessType(icon) {
|
||||
}
|
||||
|
||||
/*
|
||||
* Selects the best rich icon and tab icon from a list of IconInfo objects.
|
||||
* Timeout callback function for loading favicon.
|
||||
*
|
||||
* @param {Document} document The document to select icons for.
|
||||
* @param {Array} iconInfos A list of IconInfo objects.
|
||||
* @param {integer} preferredWidth The preferred width for tab icons.
|
||||
* @param {Map} aFaviconLoads A map of page URL and FaviconLoad object pairs,
|
||||
* where the FaviconLoad object looks like {
|
||||
* timer: a nsITimer object,
|
||||
* iconInfos: an array of IconInfo objects
|
||||
* }
|
||||
* @param {String} aPageUrl A page URL string for this callback.
|
||||
* @param {Object} aChromeGlobal A global chrome object.
|
||||
*/
|
||||
function selectIcons(document, iconInfos, preferredWidth) {
|
||||
if (iconInfos.length == 0) {
|
||||
return {
|
||||
richIcon: null,
|
||||
tabIcon: null,
|
||||
};
|
||||
}
|
||||
function faviconTimeoutCallback(aFaviconLoads, aPageUrl, aChromeGlobal) {
|
||||
let load = aFaviconLoads.get(aPageUrl);
|
||||
if (!load)
|
||||
return;
|
||||
|
||||
let preferredIcon;
|
||||
let preferredWidth = 16 * Math.ceil(aChromeGlobal.content.devicePixelRatio);
|
||||
let bestSizedIcon;
|
||||
// Other links with the "icon" tag are the default icons
|
||||
let defaultIcon;
|
||||
@ -279,7 +165,7 @@ function selectIcons(document, iconInfos, preferredWidth) {
|
||||
// dimension 96x96 or greater
|
||||
let largestRichIcon;
|
||||
|
||||
for (let icon of iconInfos) {
|
||||
for (let icon of load.iconInfos) {
|
||||
if (!icon.isRichIcon) {
|
||||
// First check for svg. If it's not available check for an icon with a
|
||||
// size adapt to the current resolution. If both are not available, prefer
|
||||
@ -317,203 +203,111 @@ function selectIcons(document, iconInfos, preferredWidth) {
|
||||
// sized fit.
|
||||
// This order allows smaller icon frames to eventually override rich icon
|
||||
// frames.
|
||||
|
||||
let tabIcon = null;
|
||||
if (largestRichIcon) {
|
||||
setIconForLink(largestRichIcon, aChromeGlobal);
|
||||
}
|
||||
if (preferredIcon) {
|
||||
tabIcon = preferredIcon;
|
||||
setIconForLink(preferredIcon, aChromeGlobal);
|
||||
} else if (bestSizedIcon) {
|
||||
tabIcon = bestSizedIcon;
|
||||
setIconForLink(bestSizedIcon, aChromeGlobal);
|
||||
} else if (defaultIcon) {
|
||||
tabIcon = defaultIcon;
|
||||
setIconForLink(defaultIcon, aChromeGlobal);
|
||||
}
|
||||
|
||||
return {
|
||||
richIcon: largestRichIcon,
|
||||
tabIcon
|
||||
};
|
||||
load.timer = null;
|
||||
aFaviconLoads.delete(aPageUrl);
|
||||
}
|
||||
|
||||
function makeFaviconFromLink(aLink, aIsRichIcon) {
|
||||
/*
|
||||
* Get request context ID of the link dom node's document.
|
||||
*
|
||||
* @param {DOMNode} aLink A link dom node.
|
||||
* @return {Number} The request context ID.
|
||||
* Return null when document's load group is not available.
|
||||
*/
|
||||
function getLinkRequestContextID(aLink) {
|
||||
try {
|
||||
return aLink.ownerDocument.documentLoadGroup.requestContextID;
|
||||
} catch (e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Favicon link handler.
|
||||
*
|
||||
* @param {DOMNode} aLink A link dom node.
|
||||
* @param {bool} aIsRichIcon A bool to indicate if the link is rich icon.
|
||||
* @param {Object} aChromeGlobal A global chrome object.
|
||||
* @param {Map} aFaviconLoads A map of page URL and FaviconLoad object pairs.
|
||||
* @return {bool} Returns true if the link is successfully handled.
|
||||
*/
|
||||
function handleFaviconLink(aLink, aIsRichIcon, aChromeGlobal, aFaviconLoads) {
|
||||
let pageUrl = aLink.ownerDocument.documentURI;
|
||||
let iconUri = getLinkIconURI(aLink);
|
||||
if (!iconUri)
|
||||
return null;
|
||||
return false;
|
||||
|
||||
// Extract the size type and width.
|
||||
let width = extractIconSize(aLink.sizes);
|
||||
|
||||
return {
|
||||
let iconInfo = {
|
||||
iconUri,
|
||||
width,
|
||||
isRichIcon: aIsRichIcon,
|
||||
type: aLink.type,
|
||||
node: aLink,
|
||||
loadingPrincipal: aLink.ownerDocument.nodePrincipal,
|
||||
requestContextID: getLinkRequestContextID(aLink)
|
||||
};
|
||||
|
||||
if (aFaviconLoads.has(pageUrl)) {
|
||||
let load = aFaviconLoads.get(pageUrl);
|
||||
load.iconInfos.push(iconInfo);
|
||||
// Re-initialize the timer
|
||||
load.timer.delay = FAVICON_PARSING_TIMEOUT;
|
||||
} else {
|
||||
let timer = setTimeout(() => faviconTimeoutCallback(aFaviconLoads, pageUrl, aChromeGlobal),
|
||||
FAVICON_PARSING_TIMEOUT);
|
||||
let load = { timer, iconInfos: [iconInfo] };
|
||||
aFaviconLoads.set(pageUrl, load);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
class IconLoader {
|
||||
constructor(chromeGlobal) {
|
||||
this.chromeGlobal = chromeGlobal;
|
||||
}
|
||||
|
||||
async load(iconInfo) {
|
||||
if (this._loader) {
|
||||
this._loader.cancel();
|
||||
}
|
||||
|
||||
if (LOCAL_FAVICON_SCHEMES.includes(iconInfo.iconUri.scheme)) {
|
||||
this.chromeGlobal.sendAsyncMessage("Link:SetIcon", {
|
||||
originalURL: iconInfo.iconUri.spec,
|
||||
loadingPrincipal: iconInfo.node.nodePrincipal,
|
||||
canUseForTab: !iconInfo.isRichIcon,
|
||||
expiration: null,
|
||||
iconURL: iconInfo.iconUri.spec,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
this._loader = new FaviconLoad(iconInfo);
|
||||
let { dataURL, expiration } = await this._loader.load();
|
||||
this._loader = null;
|
||||
|
||||
this.chromeGlobal.sendAsyncMessage("Link:SetIcon", {
|
||||
originalURL: iconInfo.iconUri.spec,
|
||||
loadingPrincipal: iconInfo.node.nodePrincipal,
|
||||
canUseForTab: !iconInfo.isRichIcon,
|
||||
expiration,
|
||||
iconURL: dataURL,
|
||||
});
|
||||
} catch (e) {
|
||||
if (e.resultCode != Cr.NS_BINDING_ABORTED) {
|
||||
Cu.reportError(e);
|
||||
|
||||
// Used mainly for tests currently.
|
||||
this.chromeGlobal.sendAsyncMessage("Link:SetFailedIcon", {
|
||||
originalURL: iconInfo.iconUri.spec,
|
||||
loadingPrincipal: iconInfo.node.nodePrincipal,
|
||||
canUseForTab: !iconInfo.isRichIcon,
|
||||
});
|
||||
var ContentLinkHandler = {
|
||||
init(chromeGlobal) {
|
||||
const faviconLoads = new Map();
|
||||
chromeGlobal.addEventListener("DOMLinkAdded", event => {
|
||||
this.onLinkEvent(event, chromeGlobal, faviconLoads);
|
||||
});
|
||||
chromeGlobal.addEventListener("DOMLinkChanged", event => {
|
||||
this.onLinkEvent(event, chromeGlobal, faviconLoads);
|
||||
});
|
||||
chromeGlobal.addEventListener("unload", event => {
|
||||
for (const [pageUrl, load] of faviconLoads) {
|
||||
load.timer.cancel();
|
||||
load.timer = null;
|
||||
faviconLoads.delete(pageUrl);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
cancel() {
|
||||
if (!this._loader) {
|
||||
onLinkEvent(event, chromeGlobal, faviconLoads) {
|
||||
var link = event.originalTarget;
|
||||
var rel = link.rel && link.rel.toLowerCase();
|
||||
if (!link || !link.ownerDocument || !rel || !link.href)
|
||||
return;
|
||||
}
|
||||
|
||||
this._loader.cancel();
|
||||
this._loader = null;
|
||||
}
|
||||
}
|
||||
|
||||
class ContentLinkHandler {
|
||||
constructor(chromeGlobal) {
|
||||
this.chromeGlobal = chromeGlobal;
|
||||
this.iconInfos = [];
|
||||
this.seenTabIcon = false;
|
||||
|
||||
chromeGlobal.addEventListener("DOMLinkAdded", this);
|
||||
chromeGlobal.addEventListener("DOMLinkChanged", this);
|
||||
chromeGlobal.addEventListener("pageshow", this);
|
||||
chromeGlobal.addEventListener("pagehide", this);
|
||||
|
||||
// For every page we attempt to find a rich icon and a tab icon. These
|
||||
// objects take care of the load process for each.
|
||||
this.richIconLoader = new IconLoader(chromeGlobal);
|
||||
this.tabIconLoader = new IconLoader(chromeGlobal);
|
||||
|
||||
this.iconTask = new DeferredTask(() => this.loadIcons(), FAVICON_PARSING_TIMEOUT);
|
||||
}
|
||||
|
||||
loadIcons() {
|
||||
let preferredWidth = PREFERRED_WIDTH * Math.ceil(this.chromeGlobal.content.devicePixelRatio);
|
||||
let { richIcon, tabIcon } = selectIcons(this.chromeGlobal.content.document,
|
||||
this.iconInfos, preferredWidth);
|
||||
this.iconInfos = [];
|
||||
|
||||
if (richIcon) {
|
||||
this.richIconLoader.load(richIcon);
|
||||
}
|
||||
|
||||
if (tabIcon) {
|
||||
this.tabIconLoader.load(tabIcon);
|
||||
}
|
||||
}
|
||||
|
||||
addIcon(iconInfo) {
|
||||
if (!Services.prefs.getBoolPref("browser.chrome.site_icons", true)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!iconInfo.isRichIcon) {
|
||||
this.seenTabIcon = true;
|
||||
}
|
||||
this.iconInfos.push(iconInfo);
|
||||
this.iconTask.arm();
|
||||
}
|
||||
|
||||
onPageShow(event) {
|
||||
if (event.target != this.chromeGlobal.content.document) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.seenTabIcon && Services.prefs.getBoolPref("browser.chrome.guess_favicon", true)) {
|
||||
// Currently ImageDocuments will just load the default favicon, see bug
|
||||
// 403651 for discussion.
|
||||
|
||||
// Inject the default icon. Use documentURIObject so that we do the right
|
||||
// thing with about:-style error pages. See bug 453442
|
||||
let baseURI = this.chromeGlobal.content.document.documentURIObject;
|
||||
if (baseURI.schemeIs("http") || baseURI.schemeIs("https")) {
|
||||
let iconUri = baseURI.mutate().setPathQueryRef("/favicon.ico").finalize();
|
||||
this.addIcon({
|
||||
iconUri,
|
||||
width: -1,
|
||||
isRichIcon: false,
|
||||
type: TYPE_ICO,
|
||||
node: this.chromeGlobal.content.document,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// We're likely done with icon parsing so load the pending icons now.
|
||||
if (this.iconTask.isArmed) {
|
||||
this.iconTask.disarm();
|
||||
this.loadIcons();
|
||||
}
|
||||
}
|
||||
|
||||
onPageHide(event) {
|
||||
if (event.target != this.chromeGlobal.content.document) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.richIconLoader.cancel();
|
||||
this.tabIconLoader.cancel();
|
||||
|
||||
this.iconTask.disarm();
|
||||
this.iconInfos = [];
|
||||
this.seenTabIcon = false;
|
||||
}
|
||||
|
||||
onLinkEvent(event) {
|
||||
let link = event.target;
|
||||
// Ignore sub-frames (bugs 305472, 479408).
|
||||
if (link.ownerGlobal != this.chromeGlobal.content) {
|
||||
return;
|
||||
}
|
||||
|
||||
let rel = link.rel && link.rel.toLowerCase();
|
||||
if (!rel || !link.href)
|
||||
let window = link.ownerGlobal;
|
||||
if (window != window.top)
|
||||
return;
|
||||
|
||||
// Note: following booleans only work for the current link, not for the
|
||||
// whole content
|
||||
let feedAdded = false;
|
||||
let iconAdded = false;
|
||||
let searchAdded = false;
|
||||
let rels = {};
|
||||
var feedAdded = false;
|
||||
var iconAdded = false;
|
||||
var searchAdded = false;
|
||||
var rels = {};
|
||||
for (let relString of rel.split(/\s+/))
|
||||
rels[relString] = true;
|
||||
|
||||
@ -528,11 +322,10 @@ class ContentLinkHandler {
|
||||
break;
|
||||
|
||||
if (Feeds.isValidFeed(link, link.ownerDocument.nodePrincipal, "feed" in rels)) {
|
||||
this.chromeGlobal.sendAsyncMessage("Link:AddFeed", {
|
||||
type: link.type,
|
||||
href: link.href,
|
||||
title: link.title,
|
||||
});
|
||||
chromeGlobal.sendAsyncMessage("Link:AddFeed",
|
||||
{type: link.type,
|
||||
href: link.href,
|
||||
title: link.title});
|
||||
feedAdded = true;
|
||||
}
|
||||
}
|
||||
@ -543,50 +336,35 @@ class ContentLinkHandler {
|
||||
case "apple-touch-icon":
|
||||
case "apple-touch-icon-precomposed":
|
||||
case "fluid-icon":
|
||||
if (iconAdded || link.hasAttribute("mask")) { // Masked icons are not supported yet.
|
||||
if (link.hasAttribute("mask") || // Masked icons are not supported yet.
|
||||
iconAdded ||
|
||||
!Services.prefs.getBoolPref("browser.chrome.site_icons")) {
|
||||
break;
|
||||
}
|
||||
|
||||
let iconInfo = makeFaviconFromLink(link, isRichIcon);
|
||||
if (iconInfo) {
|
||||
iconAdded = this.addIcon(iconInfo);
|
||||
}
|
||||
iconAdded = handleFaviconLink(link, isRichIcon, chromeGlobal, faviconLoads);
|
||||
break;
|
||||
case "search":
|
||||
if (Services.policies && !Services.policies.isAllowed("installSearchEngine")) {
|
||||
if (Services.policies &&
|
||||
!Services.policies.isAllowed("installSearchEngine")) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (!searchAdded && event.type == "DOMLinkAdded") {
|
||||
let type = link.type && link.type.toLowerCase();
|
||||
var type = link.type && link.type.toLowerCase();
|
||||
type = type.replace(/^\s+|\s*(?:;.*)?$/g, "");
|
||||
|
||||
let re = /^(?:https?|ftp):/i;
|
||||
if (type == "application/opensearchdescription+xml" && link.title &&
|
||||
re.test(link.href)) {
|
||||
let engine = { title: link.title, href: link.href };
|
||||
this.chromeGlobal.sendAsyncMessage("Link:AddSearch", {
|
||||
engine,
|
||||
url: link.ownerDocument.documentURI,
|
||||
});
|
||||
chromeGlobal.sendAsyncMessage("Link:AddSearch",
|
||||
{engine,
|
||||
url: link.ownerDocument.documentURI});
|
||||
searchAdded = true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
handleEvent(event) {
|
||||
switch (event.type) {
|
||||
case "pageshow":
|
||||
this.onPageShow(event);
|
||||
break;
|
||||
case "pagehide":
|
||||
this.onPageHide(event);
|
||||
break;
|
||||
default:
|
||||
this.onLinkEvent(event);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
|
@ -7944,17 +7944,6 @@ nsIDocument::CanSavePresentation(nsIRequest *aNewRequest)
|
||||
|
||||
nsCOMPtr<nsIRequest> request = do_QueryInterface(elem);
|
||||
if (request && request != aNewRequest && request != baseChannel) {
|
||||
// Favicon loads don't need to block caching.
|
||||
nsCOMPtr<nsIChannel> channel = do_QueryInterface(request);
|
||||
if (channel) {
|
||||
nsCOMPtr<nsILoadInfo> li;
|
||||
channel->GetLoadInfo(getter_AddRefs(li));
|
||||
if (li) {
|
||||
if (li->InternalContentPolicyType() == nsIContentPolicy::TYPE_INTERNAL_IMAGE_FAVICON) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
#ifdef DEBUG_PAGE_CACHE
|
||||
nsAutoCString requestName, docSpec;
|
||||
request->GetName(requestName);
|
||||
|
@ -28,6 +28,11 @@
|
||||
let expectedPrincipal = securityManager.createCodebasePrincipal(makeURI(LOADING_URI), {});
|
||||
let systemPrincipal = Cc["@mozilla.org/systemprincipal;1"].createInstance();
|
||||
|
||||
// We expect 2 favicon loads, one from PlacesUIUtils.loadFavicon and one
|
||||
// from XUL:image loads.
|
||||
let requestXUL = false;
|
||||
let requestPlaces = false;
|
||||
|
||||
function runTest() {
|
||||
// Register our observer to intercept favicon requests.
|
||||
let os = Cc["@mozilla.org/observer-service;1"].
|
||||
@ -48,11 +53,29 @@
|
||||
let triggeringPrincipal = httpChannel.loadInfo.triggeringPrincipal;
|
||||
let loadingPrincipal = httpChannel.loadInfo.loadingPrincipal;
|
||||
|
||||
ok(loadingPrincipal.equals(expectedPrincipal), "Should be loading with the expected principal.");
|
||||
ok(triggeringPrincipal.equals(expectedPrincipal), "Should be triggered with the expected principal.");
|
||||
if (loadingPrincipal.equals(systemPrincipal)) {
|
||||
// This is the favicon loading from XUL, which will have the system
|
||||
// principal as its loading principal and have a content principal
|
||||
// as its triggering principal.
|
||||
ok(triggeringPrincipal.equals(expectedPrincipal),
|
||||
"Correct triggeringPrincipal for favicon from XUL.");
|
||||
requestXUL = true;
|
||||
} else if (loadingPrincipal.equals(expectedPrincipal)) {
|
||||
// This is the favicon loading from Places, which will have a
|
||||
// content principal as its loading principal and triggering
|
||||
// principal.
|
||||
ok(triggeringPrincipal.equals(expectedPrincipal),
|
||||
"Correct triggeringPrincipal for favicon from Places.");
|
||||
requestPlaces = true;
|
||||
} else {
|
||||
ok(false, "An unexpected favicon request.")
|
||||
}
|
||||
|
||||
os.removeObserver(this, "http-on-modify-request");
|
||||
SimpleTest.finish();
|
||||
// Cleanup after ourselves...
|
||||
if (requestXUL && requestPlaces) {
|
||||
os.removeObserver(this, "http-on-modify-request");
|
||||
SimpleTest.finish();
|
||||
}
|
||||
}
|
||||
}
|
||||
os.addObserver(observer, "http-on-modify-request");
|
||||
|
@ -5,7 +5,6 @@ skip-if = (verify && (os == 'linux' || os == 'mac'))
|
||||
support-files =
|
||||
damonbowling.jpg
|
||||
damonbowling.jpg^headers^
|
||||
file_favicon.html
|
||||
[browser_permmgr_sync.js]
|
||||
# The browser_permmgr_sync test tests e10s specific behavior, and runs code
|
||||
# paths which would hit the debug only assertion in
|
||||
|
@ -1,9 +1,9 @@
|
||||
// Tests third party cookie blocking using a favicon loaded from a different
|
||||
// domain. The cookie should be considered third party.
|
||||
// tests third party cookie blocking using a favicon load directly from chrome.
|
||||
// in this case, the docshell of the channel is chrome, not content; thus
|
||||
// the cookie should be considered third party.
|
||||
|
||||
add_task(async function() {
|
||||
const iconUrl = "http://example.org/browser/extensions/cookie/test/damonbowling.jpg";
|
||||
const pageUrl = "http://example.com/browser/extensions/cookie/test/file_favicon.html";
|
||||
await SpecialPowers.pushPrefEnv({"set": [["network.cookie.cookieBehavior", 1]]});
|
||||
|
||||
let promise = TestUtils.topicObserved("cookie-rejected", subject => {
|
||||
@ -11,12 +11,13 @@ add_task(async function() {
|
||||
return uri.spec == iconUrl;
|
||||
});
|
||||
|
||||
// Kick off a page load that will load the favicon.
|
||||
let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, pageUrl);
|
||||
let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, "http://example.com/");
|
||||
registerCleanupFunction(async function() {
|
||||
BrowserTestUtils.removeTab(tab);
|
||||
});
|
||||
|
||||
// Kick off a favicon load.
|
||||
gBrowser.setIcon(tab, iconUrl);
|
||||
await promise;
|
||||
ok(true, "foreign favicon cookie was blocked");
|
||||
});
|
||||
|
@ -1,7 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<link rel="shortcut icon" href="http://example.org/browser/extensions/cookie/test/damonbowling.jpg">
|
||||
</head>
|
||||
</html>
|
Before Width: | Height: | Size: 1.4 KiB |
@ -49,7 +49,6 @@ TEST_HARNESS_FILES.testing.mochitest += [
|
||||
'browser-test.js',
|
||||
'chrome-harness.js',
|
||||
'chunkifyTests.js',
|
||||
'favicon.ico',
|
||||
'gen_template.pl',
|
||||
'harness.xul',
|
||||
'leaks.py',
|
||||
|
@ -15,7 +15,6 @@ user_pref("app.update.url.android", "");
|
||||
// bug 1210465.
|
||||
user_pref("apz.content_response_timeout", 60000);
|
||||
user_pref("browser.EULA.override", true);
|
||||
user_pref("browser.chrome.guess_favicon", false);
|
||||
// Make sure we don't try to load snippets from the network.
|
||||
user_pref("browser.aboutHomeSnippets.updateUrl", "nonexistent://test");
|
||||
// Disable Bookmark backups by default.
|
||||
|
@ -0,0 +1,5 @@
|
||||
[icon-blocked.sub.html]
|
||||
expected: TIMEOUT
|
||||
[Test that spv event is fired]
|
||||
expected: NOTRUN
|
||||
|
@ -257,6 +257,10 @@ function background(events) {
|
||||
browser.test.assertTrue(expectedEvent, `received ${name}`);
|
||||
browser.test.assertEq(expected.type, details.type, "resource type is correct");
|
||||
browser.test.assertEq(expected.origin || defaultOrigin, details.originUrl, "origin is correct");
|
||||
// ignore origin test for generated background page
|
||||
if (!details.originUrl || !details.originUrl.endsWith("_generated_background_page.html")) {
|
||||
browser.test.assertEq(expected.origin || defaultOrigin, details.originUrl, "origin is correct");
|
||||
}
|
||||
|
||||
if (name != "onBeforeRequest") {
|
||||
// On events after onBeforeRequest, check the previous values.
|
||||
|
@ -53,7 +53,6 @@ support-files =
|
||||
file_redirect_data_uri.html
|
||||
prefs =
|
||||
security.mixed_content.upgrade_display_content=false
|
||||
browser.chrome.guess_favicon=true
|
||||
|
||||
[test_ext_background_canvas.html]
|
||||
[test_ext_background_page.html]
|
||||
|
@ -30,10 +30,6 @@ add_task(async function setup() {
|
||||
let imgTools = SpecialPowers.Cc["@mozilla.org/image/tools;1"].getService(SpecialPowers.Ci.imgITools);
|
||||
let cache = imgTools.getImgCacheForDocument(document);
|
||||
cache.clearCache(false);
|
||||
function clearCache() {
|
||||
ChromeUtils.import("resource://gre/modules/Services.jsm", {}).Services.cache2.clear();
|
||||
}
|
||||
SpecialPowers.loadChromeScript(clearCache);
|
||||
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [["network.http.rcwn.enabled", false]],
|
||||
@ -54,7 +50,6 @@ add_task(async function setup() {
|
||||
// cancel: event in which we return cancel=true. cancelled message is sent.
|
||||
// cached: expected fromCache value, default is false, checked in onCompletion
|
||||
// headers: request or response headers to modify
|
||||
// origin: The expected originUrl, a default origin can be passed for all files
|
||||
|
||||
add_task(async function test_webRequest_links() {
|
||||
let expect = {
|
||||
@ -273,24 +268,14 @@ add_task(async function test_webRequest_tabId() {
|
||||
});
|
||||
await tabExt.startup();
|
||||
|
||||
let linkUrl = `file_WebRequest_page3.html?trigger=a&nocache=${Math.random()}`;
|
||||
let expect = {
|
||||
"file_WebRequest_page3.html": {
|
||||
type: "main_frame",
|
||||
},
|
||||
};
|
||||
|
||||
if (AppConstants.platform != "android") {
|
||||
expect["favicon.ico"] = {
|
||||
type: "image",
|
||||
origin: SimpleTest.getTestFileURL(linkUrl),
|
||||
cached: false,
|
||||
};
|
||||
}
|
||||
|
||||
extension.sendMessage("set-expected", {expect, origin: location.href});
|
||||
await extension.awaitMessage("continue");
|
||||
let a = addLink(linkUrl);
|
||||
let a = addLink(`file_WebRequest_page3.html?trigger=a&nocache=${Math.random()}`);
|
||||
a.click();
|
||||
await extension.awaitMessage("done");
|
||||
|
||||
@ -313,14 +298,13 @@ add_task(async function test_webRequest_tabId_browser() {
|
||||
tabId = tab.id;
|
||||
}
|
||||
|
||||
let pageUrl = `${SimpleTest.getTestFileURL("file_sample.html")}?nocache=${Math.random()}`;
|
||||
let tabExt = ExtensionTestUtils.loadExtension({
|
||||
manifest: {
|
||||
permissions: [
|
||||
"tabs",
|
||||
],
|
||||
},
|
||||
background: `(${background})('${pageUrl}')`,
|
||||
background: `(${background})('${SimpleTest.getTestFileURL("file_sample.html")}?nocache=${Math.random()}')`,
|
||||
});
|
||||
|
||||
let expect = {
|
||||
@ -328,15 +312,6 @@ add_task(async function test_webRequest_tabId_browser() {
|
||||
type: "main_frame",
|
||||
},
|
||||
};
|
||||
|
||||
if (AppConstants.platform != "android") {
|
||||
expect["favicon.ico"] = {
|
||||
type: "image",
|
||||
origin: pageUrl,
|
||||
cached: true,
|
||||
};
|
||||
}
|
||||
|
||||
// expecting origin == undefined
|
||||
extension.sendMessage("set-expected", {expect});
|
||||
await extension.awaitMessage("continue");
|
||||
|
@ -124,15 +124,6 @@ let expected = {
|
||||
},
|
||||
};
|
||||
|
||||
if (AppConstants.platform != "android") {
|
||||
expected["favicon.ico"] = {
|
||||
type: "image",
|
||||
toplevel: true,
|
||||
origin: "file_simple_xhr.html",
|
||||
cached: false,
|
||||
};
|
||||
}
|
||||
|
||||
function checkDetails(details) {
|
||||
let url = new URL(details.url);
|
||||
let filename = url.pathname.split(url.protocol == "data:" ? "," : "/").pop();
|
||||
@ -186,10 +177,6 @@ add_task(async function test_webRequest_main_frame() {
|
||||
let imgTools = SpecialPowers.Cc["@mozilla.org/image/tools;1"].getService(SpecialPowers.Ci.imgITools);
|
||||
let cache = imgTools.getImgCacheForDocument(document);
|
||||
cache.clearCache(false);
|
||||
function clearCache() {
|
||||
ChromeUtils.import("resource://gre/modules/Services.jsm", {}).Services.cache2.clear();
|
||||
}
|
||||
SpecialPowers.loadChromeScript(clearCache);
|
||||
|
||||
let extension = ExtensionTestUtils.loadExtension(extensionData);
|
||||
await extension.startup();
|
||||
|
@ -98,9 +98,6 @@ function background() {
|
||||
browser.webRequest.onCompleted.addListener(
|
||||
details => {
|
||||
browser.test.log(`onCompleted ${details.requestId} ${details.url}`);
|
||||
if (details.url.endsWith("/favicon.ico")) {
|
||||
return;
|
||||
}
|
||||
|
||||
browser.test.sendMessage("done");
|
||||
},
|
||||
@ -108,9 +105,6 @@ function background() {
|
||||
|
||||
let onBeforeRequest = details => {
|
||||
browser.test.log(`${name} ${details.requestId} ${details.url}`);
|
||||
if (details.url.endsWith("/favicon.ico")) {
|
||||
return;
|
||||
}
|
||||
|
||||
onUpload(details);
|
||||
};
|
||||
|
@ -2,7 +2,7 @@
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta http-equiv="Content-Security-Policy" content="default-src chrome:; img-src data: *; media-src *" />
|
||||
<meta http-equiv="Content-Security-Policy" content="default-src chrome:; img-src *; media-src *" />
|
||||
<meta content="text/html; charset=UTF-8" http-equiv="content-type" />
|
||||
<meta name="viewport" content="width=device-width; user-scalable=0" />
|
||||
<link rel="stylesheet" href="chrome://global/skin/aboutReader.css" type="text/css"/>
|
||||
|