diff --git a/browser/app/profile/firefox.js b/browser/app/profile/firefox.js index 471c57c88fd4..532d82f6aa87 100644 --- a/browser/app/profile/firefox.js +++ b/browser/app/profile/firefox.js @@ -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); pref("browser.fullscreen.autohide", true); diff --git a/browser/base/content/browser.js b/browser/base/content/browser.js index d62ed7fb1b9e..3fc9b56b7dc1 100644 --- a/browser/base/content/browser.js +++ b/browser/base/content/browser.js @@ -3740,8 +3740,8 @@ const DOMEventHandler = { break; case "Link:SetIcon": - this.setIconFromLink(aMsg.target, aMsg.data.originalURL, 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": @@ -3760,20 +3760,21 @@ const DOMEventHandler = { return true; }, - setIconFromLink(aBrowser, aOriginalURL, aCanUseForTab, aExpiration, aIconURL) { + setIcon(aBrowser, aURL, aLoadingPrincipal, aRequestContextID = 0, aCanUseForTab = true) { + if (gBrowser.isFailedIcon(aURL)) + return false; + let tab = gBrowser.getTabForBrowser(aBrowser); if (!tab) return false; - try { - PlacesUIUtils.loadFavicon(aBrowser, Services.scriptSecurityManager.getSystemPrincipal(), - makeURI(aOriginalURL), aExpiration, makeURI(aIconURL)); - } catch (ex) { - Cu.reportError(ex); + let loadingPrincipal = aLoadingPrincipal || + Services.scriptSecurityManager.getSystemPrincipal(); + if (aURL) { + gBrowser.storeIcon(aBrowser, aURL, loadingPrincipal, aRequestContextID); } - if (aCanUseForTab) { - gBrowser.setIcon(tab, aIconURL, aOriginalURL); + gBrowser.setIcon(tab, aURL, loadingPrincipal, aRequestContextID); } return true; }, diff --git a/browser/base/content/content.js b/browser/base/content/content.js index aab0bb25e998..2743eb5ffc25 100644 --- a/browser/base/content/content.js +++ b/browser/base/content/content.js @@ -315,7 +315,7 @@ var ClickEventHandler = { }; ClickEventHandler.init(); -new ContentLinkHandler(this); +ContentLinkHandler.init(this); ContentMetaHandler.init(this); var PluginContentStub = { diff --git a/browser/base/content/tabbrowser.js b/browser/base/content/tabbrowser.js index 29ffe9c1abdf..952b4b85247a 100644 --- a/browser/base/content/tabbrowser.js +++ b/browser/base/content/tabbrowser.js @@ -762,38 +762,43 @@ window._gBrowser = { } }, - 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; + storeIcon(aBrowser, aURI, aLoadingPrincipal, aRequestContextID) { + try { + if (!(aURI instanceof Ci.nsIURI)) { + aURI = makeURI(aURI); + } + PlacesUIUtils.loadFavicon(aBrowser, aLoadingPrincipal, aURI, aRequestContextID); + } catch (ex) { + Cu.reportError(ex); } + }, + 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) { @@ -808,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; @@ -3102,7 +3152,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"); @@ -4201,7 +4251,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) => { @@ -4540,6 +4590,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 diff --git a/browser/base/content/test/favicons/browser.ini b/browser/base/content/test/favicons/browser.ini index 8037678bfead..e2e1c1e5ddfc 100644 --- a/browser/base/content/test/favicons/browser.ini +++ b/browser/base/content/test/favicons/browser.ini @@ -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] diff --git a/browser/base/content/test/favicons/browser_bug408415.js b/browser/base/content/test/favicons/browser_bug408415.js deleted file mode 100644 index 9743761031f6..000000000000 --- a/browser/base/content/test/favicons/browser_bug408415.js +++ /dev/null @@ -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."); - } - }); -}); - diff --git a/browser/base/content/test/favicons/browser_bug550565.js b/browser/base/content/test/favicons/browser_bug550565.js deleted file mode 100644 index c0bbbcbfc54c..000000000000 --- a/browser/base/content/test/favicons/browser_bug550565.js +++ /dev/null @@ -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."); - } - }); -}); diff --git a/browser/base/content/test/favicons/browser_favicon_change.js b/browser/base/content/test/favicons/browser_favicon_change.js deleted file mode 100644 index 082d1278c8c5..000000000000 --- a/browser/base/content/test/favicons/browser_favicon_change.js +++ /dev/null @@ -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); -}); - diff --git a/browser/base/content/test/favicons/browser_favicon_load.js b/browser/base/content/test/favicons/browser_favicon_load.js index 22c0918a81c3..0d6dd2a25319 100644 --- a/browser/base/content/test/favicons/browser_favicon_load.js +++ b/browser/base/content/test/favicons/browser_favicon_load.js @@ -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; diff --git a/browser/base/content/test/favicons/browser_icon_discovery.js b/browser/base/content/test/favicons/browser_icon_discovery.js index 86123d9cd3ed..234eb96ff8a8 100644 --- a/browser/base/content/test/favicons/browser_icon_discovery.js +++ b/browser/base/content/test/favicons/browser_icon_discovery.js @@ -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); -}); +} diff --git a/browser/base/content/test/favicons/browser_multiple_icons_in_short_timeframe.js b/browser/base/content/test/favicons/browser_multiple_icons_in_short_timeframe.js index d266fa6bda94..c856f43e75ca 100644 --- a/browser/base/content/test/favicons/browser_multiple_icons_in_short_timeframe.js +++ b/browser/base/content/test/favicons/browser_multiple_icons_in_short_timeframe.js @@ -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); }); diff --git a/browser/base/content/test/favicons/browser_preferred_icons.js b/browser/base/content/test/favicons/browser_preferred_icons.js index cf554263f8c2..8f3cf02a8fa3 100644 --- a/browser/base/content/test/favicons/browser_preferred_icons.js +++ b/browser/base/content/test/favicons/browser_preferred_icons.js @@ -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"); }); diff --git a/browser/base/content/test/favicons/browser_rich_icons.js b/browser/base/content/test/favicons/browser_rich_icons.js index 0570872ce25a..a2056591ffc5 100644 --- a/browser/base/content/test/favicons/browser_rich_icons.js +++ b/browser/base/content/test/favicons/browser_rich_icons.js @@ -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); }); diff --git a/browser/base/content/test/favicons/browser_subframe_favicons_not_used.js b/browser/base/content/test/favicons/browser_subframe_favicons_not_used.js deleted file mode 100644 index a9d78895a057..000000000000 --- a/browser/base/content/test/favicons/browser_subframe_favicons_not_used.js +++ /dev/null @@ -1,14 +0,0 @@ -/* Make sure 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); -}); diff --git a/browser/base/content/test/favicons/discovery.html b/browser/base/content/test/favicons/discovery.html index 2ff2aaa5f254..1679e6545ec6 100644 --- a/browser/base/content/test/favicons/discovery.html +++ b/browser/base/content/test/favicons/discovery.html @@ -1,6 +1,6 @@ - + Autodiscovery Test diff --git a/browser/base/content/test/favicons/head.js b/browser/base/content/test/favicons/head.js index 95a48d6a7750..07882f9e6531 100644 --- a/browser/base/content/test/favicons/head.js +++ b/browser/base/content/test/favicons/head.js @@ -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; -} diff --git a/browser/base/content/test/favicons/icon.svg b/browser/base/content/test/favicons/icon.svg deleted file mode 100644 index 6de9c64503d9..000000000000 --- a/browser/base/content/test/favicons/icon.svg +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - diff --git a/browser/base/content/test/general/browser.ini b/browser/base/content/test/general/browser.ini index ca72637e3f04..b56c57818f38 100644 --- a/browser/base/content/test/general/browser.ini +++ b/browser/base/content/test/general/browser.ini @@ -35,8 +35,16 @@ support-files = download_page_2.txt dummy_page.html feed_tab.html + file_generic_favicon.ico + file_with_favicon.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 @@ -97,6 +105,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] @@ -157,6 +167,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] @@ -294,6 +306,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] @@ -407,6 +425,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] diff --git a/browser/base/content/test/general/browser_bug408415.js b/browser/base/content/test/general/browser_bug408415.js new file mode 100644 index 000000000000..bce449b8be2d --- /dev/null +++ b/browser/base/content/test/general/browser_bug408415.js @@ -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); + }); +}); + diff --git a/browser/base/content/test/general/browser_bug521216.js b/browser/base/content/test/general/browser_bug521216.js index 29e37becb71c..4f1f7a1b5786 100644 --- a/browser/base/content/test/general/browser_bug521216.js +++ b/browser/base/content/test/general/browser_bug521216.js @@ -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"); } }; diff --git a/browser/base/content/test/general/browser_bug550565.js b/browser/base/content/test/general/browser_bug550565.js new file mode 100644 index 000000000000..3965f6d6e919 --- /dev/null +++ b/browser/base/content/test/general/browser_bug550565.js @@ -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); + }); +}); diff --git a/browser/base/content/test/general/browser_favicon_change.js b/browser/base/content/test/general/browser_favicon_change.js new file mode 100644 index 000000000000..9c198f13d48f --- /dev/null +++ b/browser/base/content/test/general/browser_favicon_change.js @@ -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); +}); + diff --git a/browser/base/content/test/favicons/browser_favicon_change_not_in_document.js b/browser/base/content/test/general/browser_favicon_change_not_in_document.js similarity index 71% rename from browser/base/content/test/favicons/browser_favicon_change_not_in_document.js rename to browser/base/content/test/general/browser_favicon_change_not_in_document.js index bb9ef7080d3e..3ad14277bcd7 100644 --- a/browser/base/content/test/favicons/browser_favicon_change_not_in_document.js +++ b/browser/base/content/test/general/browser_favicon_change_not_in_document.js @@ -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."); diff --git a/browser/base/content/test/general/browser_subframe_favicons_not_used.js b/browser/base/content/test/general/browser_subframe_favicons_not_used.js new file mode 100644 index 000000000000..08e4625bdb9c --- /dev/null +++ b/browser/base/content/test/general/browser_subframe_favicons_not_used.js @@ -0,0 +1,32 @@ +/* Make sure 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}); +} diff --git a/browser/base/content/test/favicons/file_bug970276_favicon1.ico b/browser/base/content/test/general/file_bug970276_favicon1.ico similarity index 100% rename from browser/base/content/test/favicons/file_bug970276_favicon1.ico rename to browser/base/content/test/general/file_bug970276_favicon1.ico diff --git a/browser/base/content/test/favicons/file_bug970276_favicon2.ico b/browser/base/content/test/general/file_bug970276_favicon2.ico similarity index 100% rename from browser/base/content/test/favicons/file_bug970276_favicon2.ico rename to browser/base/content/test/general/file_bug970276_favicon2.ico diff --git a/browser/base/content/test/favicons/file_bug970276_popup1.html b/browser/base/content/test/general/file_bug970276_popup1.html similarity index 100% rename from browser/base/content/test/favicons/file_bug970276_popup1.html rename to browser/base/content/test/general/file_bug970276_popup1.html diff --git a/browser/base/content/test/favicons/file_bug970276_popup2.html b/browser/base/content/test/general/file_bug970276_popup2.html similarity index 100% rename from browser/base/content/test/favicons/file_bug970276_popup2.html rename to browser/base/content/test/general/file_bug970276_popup2.html diff --git a/browser/base/content/test/favicons/file_favicon_change.html b/browser/base/content/test/general/file_favicon_change.html similarity index 68% rename from browser/base/content/test/favicons/file_favicon_change.html rename to browser/base/content/test/general/file_favicon_change.html index 035549c5aaf0..18ac6526b50a 100644 --- a/browser/base/content/test/favicons/file_favicon_change.html +++ b/browser/base/content/test/general/file_favicon_change.html @@ -1,13 +1,13 @@ - + diff --git a/browser/base/content/test/favicons/file_favicon_change_not_in_document.html b/browser/base/content/test/general/file_favicon_change_not_in_document.html similarity index 70% rename from browser/base/content/test/favicons/file_favicon_change_not_in_document.html rename to browser/base/content/test/general/file_favicon_change_not_in_document.html index 10775619d8fc..deebb07dcbaf 100644 --- a/browser/base/content/test/favicons/file_favicon_change_not_in_document.html +++ b/browser/base/content/test/general/file_favicon_change_not_in_document.html @@ -1,7 +1,7 @@ - +