Bug 1083895 - Favicon should not change if link element isn't in DOM. r=bz, a=lmandel
authorGijs Kruitbosch <gijskruitbosch@gmail.com>
Thu, 16 Oct 2014 15:00:12 -0700
changeset 225751 73bc0bc9343b
parent 225750 2235079fe205
child 225752 6d2e5afd8b75
push id4000
push userryanvm@gmail.com
push date2014-10-20 16:31 +0000
treeherdermozilla-beta@6d2e5afd8b75 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbz, lmandel
bugs1083895
milestone34.0
Bug 1083895 - Favicon should not change if link element isn't in DOM. r=bz, a=lmandel
browser/base/content/test/general/browser.ini
browser/base/content/test/general/browser_favicon_change_not_in_document.js
browser/base/content/test/general/file_favicon_change_not_in_document.html
content/html/content/src/HTMLLinkElement.cpp
--- 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
@@ -297,16 +298,18 @@ skip-if = e10s # Bug 973001 - appears us
 [browser_discovery.js]
 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]
+[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
@@ -315,17 +315,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)) {
@@ -378,17 +380,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)
 {