Bug 1083895 - favicon should not change if link element isn't in DOM, r=bz
--- a/browser/base/content/test/general/browser.ini
+++ b/browser/base/content/test/general/browser.ini
@@ -52,16 +52,17 @@ support-files =
file_bug906190.sjs
file_bug970276_popup1.html
file_bug970276_popup2.html
file_bug970276_favicon1.ico
file_bug970276_favicon2.ico
file_dom_notifications.html
file_double_close_tab.html
file_favicon_change.html
+ file_favicon_change_not_in_document.html
file_fullscreen-window-open.html
get_user_media.html
head.js
healthreport_testRemoteCommands.html
moz.png
offlineQuotaNotification.cacheManifest
offlineQuotaNotification.html
page_style_sample.html
@@ -319,16 +320,18 @@ skip-if = e10s # Bug 973001 - appears us
skip-if = e10s # Bug 918663 - DOMLinkAdded events don't make their way to chrome
[browser_double_close_tab.js]
skip-if = e10s
[browser_duplicateIDs.js]
[browser_drag.js]
skip-if = true # browser_drag.js is disabled, as it needs to be updated for the new behavior from bug 320638.
[browser_favicon_change.js]
skip-if = e10s
+[browser_favicon_change_not_in_document.js]
+skip-if = e10s
[browser_findbarClose.js]
skip-if = e10s # Bug ?????? - test directly manipulates content (tries to grab an iframe directly from content)
[browser_fullscreen-window-open.js]
skip-if = buildapp == 'mulet' || e10s || os == "linux" # Bug 933103 - mochitest's EventUtils.synthesizeMouse functions not e10s friendly. Linux: Intermittent failures - bug 941575.
[browser_fxa_oauth.js]
[browser_gestureSupport.js]
skip-if = e10s # Bug 863514 - no gesture support.
[browser_getshortcutoruri.js]
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/general/browser_favicon_change_not_in_document.js
@@ -0,0 +1,34 @@
+"use strict";
+
+const TEST_URL = "http://mochi.test:8888/browser/browser/base/content/test/general/file_favicon_change_not_in_document.html"
+
+add_task(function*() {
+ let extraTab = gBrowser.selectedTab = gBrowser.addTab();
+ let tabLoaded = promiseTabLoaded(extraTab);
+ extraTab.linkedBrowser.loadURI(TEST_URL);
+ let expectedFavicon = "http://example.org/one-icon";
+ let haveChanged = new Promise.defer();
+ let observer = new MutationObserver(function(mutations) {
+ for (let mut of mutations) {
+ if (mut.attributeName != "image") {
+ continue;
+ }
+ let imageVal = extraTab.getAttribute("image").replace(/#.*$/, "");
+ if (!imageVal) {
+ // 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});
+ yield tabLoaded;
+ expectedFavicon = "http://example.org/yet-another-icon";
+ haveChanged = new Promise.defer();
+ yield haveChanged.promise;
+ observer.disconnect();
+ gBrowser.removeTab(extraTab);
+});
+
+
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/general/file_favicon_change_not_in_document.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<html><head>
+ <meta http-equiv="content-type" content="text/html; charset=utf-8">
+ <link rel="icon" href="http://example.org/one-icon" type="image/ico" id="i">
+</head>
+<body onload="onload()">
+ <script>
+ function onload() {
+ var ico = document.createElement("link");
+ ico.setAttribute("rel", "icon");
+ ico.setAttribute("type", "image/ico");
+ ico.setAttribute("href", "http://example.org/other-icon");
+ setTimeout(function() {
+ ico.setAttribute("href", "http://example.org/yet-another-icon");
+ document.getElementById("i").remove();
+ document.head.appendChild(ico);
+ }, 1000);
+ }
+ </script>
+</body></html>
+
--- a/content/html/content/src/HTMLLinkElement.cpp
+++ b/content/html/content/src/HTMLLinkElement.cpp
@@ -302,17 +302,19 @@ HTMLLinkElement::SetAttr(int32_t aNameSp
// The ordering of the parent class's SetAttr call and Link::ResetLinkState
// is important here! The attribute is not set until SetAttr returns, and
// we will need the updated attribute value because notifying the document
// that content states have changed will call IntrinsicState, which will try
// to get updated information about the visitedness from Link.
if (aName == nsGkAtoms::href && kNameSpaceID_None == aNameSpaceID) {
Link::ResetLinkState(!!aNotify, true);
- CreateAndDispatchEvent(OwnerDoc(), NS_LITERAL_STRING("DOMLinkChanged"));
+ if (IsInUncomposedDoc()) {
+ CreateAndDispatchEvent(OwnerDoc(), NS_LITERAL_STRING("DOMLinkChanged"));
+ }
}
if (NS_SUCCEEDED(rv) && aNameSpaceID == kNameSpaceID_None &&
(aName == nsGkAtoms::href ||
aName == nsGkAtoms::rel ||
aName == nsGkAtoms::title ||
aName == nsGkAtoms::media ||
aName == nsGkAtoms::type)) {
@@ -365,17 +367,19 @@ HTMLLinkElement::UnsetAttr(int32_t aName
// The ordering of the parent class's UnsetAttr call and Link::ResetLinkState
// is important here! The attribute is not unset until UnsetAttr returns, and
// we will need the updated attribute value because notifying the document
// that content states have changed will call IntrinsicState, which will try
// to get updated information about the visitedness from Link.
if (aAttribute == nsGkAtoms::href && kNameSpaceID_None == aNameSpaceID) {
Link::ResetLinkState(!!aNotify, false);
- CreateAndDispatchEvent(OwnerDoc(), NS_LITERAL_STRING("DOMLinkChanged"));
+ if (IsInUncomposedDoc()) {
+ CreateAndDispatchEvent(OwnerDoc(), NS_LITERAL_STRING("DOMLinkChanged"));
+ }
}
return rv;
}
nsresult
HTMLLinkElement::PreHandleEvent(EventChainPreVisitor& aVisitor)
{