Merge mozilla-central to inbound. a=merge CLOSED TREE
authorshindli <shindli@mozilla.com>
Mon, 20 Aug 2018 19:36:01 +0300
changeset 432427 14ef4dec612654a0c3ba398bfcefd9436ea4abf6
parent 432409 56856b94af05f97c1ef66b0bbb71ce8be890a156 (current diff)
parent 432426 1ba33950cff38b7e7baaf5d96431a11814de83df (diff)
child 432428 6129cb421151f9a4f6032a3a2e48a71209850711
push id106731
push usershindli@mozilla.com
push dateMon, 20 Aug 2018 16:36:25 +0000
treeherdermozilla-inbound@14ef4dec6126 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone63.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge mozilla-central to inbound. a=merge CLOSED TREE
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -218,20 +218,24 @@ XPCOMUtils.defineLazyGetter(this, "Win7F
 
   const WINTASKBAR_CONTRACTID = "@mozilla.org/windows-taskbar;1";
   if (WINTASKBAR_CONTRACTID in Cc &&
       Cc[WINTASKBAR_CONTRACTID].getService(Ci.nsIWinTaskbar).available) {
     let AeroPeek = ChromeUtils.import("resource:///modules/WindowsPreviewPerTab.jsm", {}).AeroPeek;
     return {
       onOpenWindow() {
         AeroPeek.onOpenWindow(window);
+        this.handledOpening = true;
       },
       onCloseWindow() {
-        AeroPeek.onCloseWindow(window);
-      }
+        if (this.handledOpening) {
+          AeroPeek.onCloseWindow(window);
+        }
+      },
+      handledOpening: false,
     };
   }
   return null;
 });
 
 var gBrowser;
 var gLastValidURLStr = "";
 var gInPrintPreviewMode = false;
@@ -1502,19 +1506,16 @@ var gBrowserInit = {
       updateEditUIVisibility();
       let placesContext = document.getElementById("placesContext");
       placesContext.addEventListener("popupshowing", updateEditUIVisibility);
       placesContext.addEventListener("popuphiding", updateEditUIVisibility);
     }
 
     LightWeightThemeWebInstaller.init();
 
-    if (Win7Features)
-      Win7Features.onOpenWindow();
-
     FullScreen.init();
     PointerLock.init();
 
     if (AppConstants.isPlatformAndVersionAtLeast("win", "10")) {
       MenuTouchModeObserver.init();
     }
 
     if (AppConstants.MOZ_DATA_REPORTING)
@@ -1765,16 +1766,20 @@ var gBrowserInit = {
         DownloadsCommon.initializeAllDataLinks();
         ChromeUtils.import("resource:///modules/DownloadsTaskbar.jsm", {})
           .DownloadsTaskbar.registerIndicator(window);
       } catch (ex) {
         Cu.reportError(ex);
       }
     }, {timeout: 10000});
 
+    if (Win7Features) {
+      scheduleIdleTask(() => Win7Features.onOpenWindow());
+    }
+
     // This should always go last, since the idle tasks (except for the ones with
     // timeouts) should execute in order. Note that this observer notification is
     // not guaranteed to fire, since the window could close before we get here.
     scheduleIdleTask(() => {
       this.idleTasksFinished = true;
       Services.obs.notifyObservers(window, "browser-idle-startup-tasks-finished");
     });
   },
@@ -1890,19 +1895,16 @@ var gBrowserInit = {
 
     BrowserSearch.uninit();
 
     // Now either cancel delayedStartup, or clean up the services initialized from
     // it.
     if (this._boundDelayedStartup) {
       this._cancelDelayedStartup();
     } else {
-      if (Win7Features)
-        Win7Features.onCloseWindow();
-
       Services.prefs.removeObserver(ctrlTab.prefName, ctrlTab);
       ctrlTab.uninit();
       gBrowserThumbnails.uninit();
       FullZoom.destroy();
 
       Services.obs.removeObserver(gIdentityHandler, "perm-changed");
       Services.obs.removeObserver(gRemoteControl, "remote-active");
       Services.obs.removeObserver(gSessionHistoryObserver, "browser:purge-session-history");
--- a/browser/modules/WindowsPreviewPerTab.jsm
+++ b/browser/modules/WindowsPreviewPerTab.jsm
@@ -427,19 +427,19 @@ TabWindow.prototype = {
     // Now that we've updated this.previews, it will resolve successfully.
     controller.updateTitleAndTooltip();
   },
 
   createTabPreview(controller) {
     let docShell = this.win.docShell;
     let preview = AeroPeek.taskbar.createTaskbarTabPreview(docShell, controller);
     preview.visible = AeroPeek.enabled;
-    preview.active = this.tabbrowser.selectedTab == controller.tab;
-    this.onLinkIconAvailable(controller.tab.linkedBrowser,
-                             controller.tab.getAttribute("image"));
+    let {tab} = controller;
+    preview.active = this.tabbrowser.selectedTab == tab;
+    this.updateFavicon(tab, tab.getAttribute("image"));
     return preview;
   },
 
   // Invoked when the given tab is closed
   removeTab(tab) {
     let preview = this.previewFromTab(tab);
     preview.active = false;
     preview.visible = false;
@@ -580,16 +580,20 @@ TabWindow.prototype = {
       this.invalidateTabPreview(aBrowser);
     }
   },
 
   directRequestProtocols: new Set([
     "file", "chrome", "resource", "about"
   ]),
   onLinkIconAvailable(aBrowser, aIconURL) {
+    let tab = this.win.gBrowser.getTabForBrowser(aBrowser);
+    this.updateFavicon(tab, aIconURL);
+  },
+  updateFavicon(aTab, aIconURL) {
     let requestURL = null;
     if (aIconURL) {
       let shouldRequestFaviconURL = true;
       try {
         let urlObject = NetUtil.newURI(aIconURL);
         shouldRequestFaviconURL =
           !this.directRequestProtocols.has(urlObject.scheme);
       } catch (ex) {}
@@ -598,27 +602,32 @@ TabWindow.prototype = {
         "moz-anno:favicon:" + aIconURL :
         aIconURL;
     }
     let isDefaultFavicon = !requestURL;
     getFaviconAsImage(
       requestURL,
       PrivateBrowsingUtils.isWindowPrivate(this.win),
       img => {
-        let index = this.tabbrowser.browsers.indexOf(aBrowser);
-        // Only add it if we've found the index and the URI is still the same.
         // The tab could have closed, and there's no guarantee the icons
         // will have finished fetching 'in order'.
-        if (index != -1) {
-          let tab = this.tabbrowser.tabs[index];
-          let preview = this.previews.get(tab);
-          if (tab.getAttribute("image") == aIconURL ||
-              (!preview.icon && isDefaultFavicon)) {
-            preview.icon = img;
-          }
+        if (this.win.closed || aTab.closing || !aTab.linkedBrowser) {
+          return;
+        }
+        // Note that bizarrely, we can get to updateFavicon via a sync codepath
+        // where the new preview controller hasn't yet been added to the
+        // window's map of previews. So `preview` would be null here - except
+        // getFaviconAsImage is async so that should never happen, as we add
+        // the controller to the preview collection straight after creating it.
+        // However, if any of this code ever tries to access this
+        // synchronously, that won't work.
+        let preview = this.previews.get(aTab);
+        if (aTab.getAttribute("image") == aIconURL ||
+            (!preview.icon && isDefaultFavicon)) {
+          preview.icon = img;
         }
       }
     );
   }
 };
 
 // AeroPeek
 
@@ -819,17 +828,17 @@ var AeroPeek = {
   onDeleteURI() {},
   onClearHistory() {},
   onDeleteVisits() {},
   onPageChanged(uri, changedConst, newValue) {
     if (this.enabled && changedConst == Ci.nsINavHistoryObserver.ATTRIBUTE_FAVICON) {
       for (let win of this.windows) {
         for (let [tab, ] of win.previews) {
           if (tab.getAttribute("image") == newValue) {
-            win.onLinkIconAvailable(tab.linkedBrowser, newValue);
+            win.updateFavicon(tab, newValue);
           }
         }
       }
     }
   },
 
   QueryInterface: ChromeUtils.generateQI([
     Ci.nsISupportsWeakReference,
--- a/browser/themes/shared/identity-block/identity-block.inc.css
+++ b/browser/themes/shared/identity-block/identity-block.inc.css
@@ -224,51 +224,57 @@
   --tracking-protection-shield-color: #c069ff;
 }
 
 @keyframes tp-icon-animation {
   from {
     transform: translateX(0);
     fill-opacity: 0.3;
   }
-  38% {
+  30% {
     fill: inherit;
     fill-opacity: 0.3;
   }
-  39% {
+  31% {
     fill: var(--tracking-protection-shield-color);
     fill-opacity: 1;
   }
-  75% {
+  50% {
     transform: translateX(-1232px);
     fill: var(--tracking-protection-shield-color);
+  }
+  65% {
+    fill: var(--tracking-protection-shield-color);
     fill-opacity: 1;
   }
   to {
     fill: inherit;
     fill-opacity: inherit;
   }
 }
 
 @keyframes tp-icon-animation-rtl {
   from {
     transform: scaleX(-1) translateX(0);
     fill-opacity: 0.3;
   }
-  38% {
+  30% {
     fill: inherit;
     fill-opacity: 0.3;
   }
-  39% {
+  31% {
     fill: var(--tracking-protection-shield-color);
     fill-opacity: 1;
   }
-  75% {
+  50% {
     transform: scaleX(-1) translateX(-1232px);
     fill: var(--tracking-protection-shield-color);
+  }
+  65% {
+    fill: var(--tracking-protection-shield-color);
     fill-opacity: 1;
   }
   to {
     fill: inherit;
     fill-opacity: inherit;
   }
 }
 
--- a/devtools/client/shared/components/menu/MenuButton.js
+++ b/devtools/client/shared/components/menu/MenuButton.js
@@ -121,18 +121,18 @@ class MenuButton extends PureComponent {
   async resetTooltip() {
     if (!this.tooltip) {
       return;
     }
 
     // Mark the menu as closed since the onHidden callback may not be called in
     // this case.
     this.setState({ expanded: false });
+    this.tooltip.off("hidden", this.onHidden);
     this.tooltip.destroy();
-    this.tooltip.off("hidden", this.onHidden);
     this.tooltip = null;
   }
 
   async showMenu(anchor) {
     this.setState({
       expanded: true
     });
 
--- a/devtools/client/webconsole/test/mochitest/browser_webconsole_trackingprotection_errors.js
+++ b/devtools/client/webconsole/test/mochitest/browser_webconsole_trackingprotection_errors.js
@@ -23,17 +23,17 @@ registerCleanupFunction(function() {
 add_task(async function testMessagesAppear() {
   await UrlClassifierTestUtils.addTestTrackers();
   await pushPref("privacy.trackingprotection.enabled", true);
 
   const hud = await openNewTabAndConsole(TEST_URI);
 
   const message = await waitFor(() => findMessage(hud,
     "The resource at \u201chttp://tracking.example.com/\u201d was " +
-    "blocked because tracking protection is enabled"));
+    "blocked because content blocking is enabled"));
 
   await testClickOpenNewTab(hud, message);
 });
 
 async function testClickOpenNewTab(hud, message) {
   info("Clicking on the Learn More link");
 
   const learnMoreLink = message.querySelector(".learn-more-link");
--- a/dom/base/CharacterData.cpp
+++ b/dom/base/CharacterData.cpp
@@ -447,16 +447,18 @@ CharacterData::BindToTree(nsIDocument* a
 {
   MOZ_ASSERT(aParent || aDocument, "Must have document if no parent!");
   MOZ_ASSERT(NODE_FROM(aParent, aDocument)->OwnerDoc() == OwnerDoc(),
              "Must have the same owner document");
   MOZ_ASSERT(!aParent || aDocument == aParent->GetUncomposedDoc(),
              "aDocument must be current doc of aParent");
   MOZ_ASSERT(!GetUncomposedDoc() && !IsInUncomposedDoc(),
              "Already have a document.  Unbind first!");
+  MOZ_ASSERT(!IsInComposedDoc(),
+             "Already have a document.  Unbind first!");
   // Note that as we recurse into the kids, they'll have a non-null parent.  So
   // only assert if our parent is _changing_ while we have a parent.
   MOZ_ASSERT(!GetParent() || aParent == GetParent(),
              "Already have a parent.  Unbind first!");
   MOZ_ASSERT(!GetBindingParent() ||
              aBindingParent == GetBindingParent() ||
              (!aBindingParent && aParent &&
               aParent->GetBindingParent() == GetBindingParent()),
@@ -484,50 +486,50 @@ CharacterData::BindToTree(nsIDocument* a
       SetFlags(NODE_IS_IN_NATIVE_ANONYMOUS_SUBTREE);
     }
     if (aParent->HasFlag(NODE_CHROME_ONLY_ACCESS)) {
       SetFlags(NODE_CHROME_ONLY_ACCESS);
     }
     if (HasFlag(NODE_IS_ANONYMOUS_ROOT)) {
       aParent->SetMayHaveAnonymousChildren();
     }
-    if (aParent->IsInShadowTree()) {
-      ClearSubtreeRootPointer();
-      SetFlags(NODE_IS_IN_SHADOW_TREE);
-    }
-    ShadowRoot* parentContainingShadow = aParent->GetContainingShadow();
-    if (parentContainingShadow) {
-      ExtendedContentSlots()->mContainingShadow = parentContainingShadow;
-    }
+  }
+
+  if (aParent && aParent->IsInShadowTree()) {
+    ClearSubtreeRootPointer();
+    SetFlags(NODE_IS_IN_SHADOW_TREE);
+    SetIsConnected(aParent->IsInComposedDoc());
+    MOZ_ASSERT(aParent->GetContainingShadow());
+    ExtendedContentSlots()->mContainingShadow = aParent->GetContainingShadow();
   }
 
   bool hadParent = !!GetParentNode();
 
   // Set parent
   if (aParent) {
     if (!GetParent()) {
       NS_ADDREF(aParent);
     }
     mParent = aParent;
-  }
-  else {
+  } else {
     mParent = aDocument;
   }
   SetParentIsContent(aParent);
 
   // XXXbz sXBL/XBL2 issue!
 
   // Set document
   if (aDocument) {
     // We no longer need to track the subtree pointer (and in fact we'll assert
     // if we do this any later).
     ClearSubtreeRootPointer();
 
     // XXX See the comment in Element::BindToTree
     SetIsInDocument();
+    SetIsConnected(true);
     if (mText.IsBidi()) {
       aDocument->SetBidiEnabled();
     }
     // Clear the lazy frame construction bits.
     UnsetFlags(NODE_NEEDS_FRAME | NODE_DESCENDANTS_NEED_FRAMES);
   } else if (!IsInShadowTree()) {
     // If we're not in the doc and not in a shadow tree,
     // update our subtree pointer.
@@ -548,33 +550,33 @@ CharacterData::BindToTree(nsIDocument* a
 
   return NS_OK;
 }
 
 void
 CharacterData::UnbindFromTree(bool aDeep, bool aNullParent)
 {
   // Unset frame flags; if we need them again later, they'll get set again.
-  UnsetFlags(NS_CREATE_FRAME_IF_NON_WHITESPACE |
-             NS_REFRAME_IF_WHITESPACE);
+  UnsetFlags(NS_CREATE_FRAME_IF_NON_WHITESPACE | NS_REFRAME_IF_WHITESPACE);
 
   nsIDocument* document = GetComposedDoc();
 
   if (aNullParent) {
     if (this->IsRootOfNativeAnonymousSubtree()) {
       nsNodeUtils::NativeAnonymousChildListChange(this, true);
     }
     if (GetParent()) {
       NS_RELEASE(mParent);
     } else {
       mParent = nullptr;
     }
     SetParentIsContent(false);
   }
   ClearInDocument();
+  SetIsConnected(false);
 
   if (aNullParent || !mParent->IsInShadowTree()) {
     UnsetFlags(NODE_IS_IN_SHADOW_TREE);
 
     // Begin keeping track of our subtree root.
     SetSubtreeRootPointer(aNullParent ? this : mParent->SubtreeRoot());
   }
 
--- a/dom/base/Element.cpp
+++ b/dom/base/Element.cpp
@@ -1253,18 +1253,16 @@ Element::AttachShadowWithoutNameChecks(S
   /**
    * 4. Let shadow be a new shadow root whose node document is
    *    context object’s node document, host is context object,
    *    and mode is init’s mode.
    */
   RefPtr<ShadowRoot> shadowRoot =
     new ShadowRoot(this, aMode, nodeInfo.forget());
 
-  shadowRoot->SetIsComposedDocParticipant(IsInComposedDoc());
-
   if (NodeOrAncestorHasDirAuto()) {
     shadowRoot->SetAncestorHasDirAuto();
   }
 
   /**
    * 5. Set context object’s shadow root to shadow.
    */
   SetShadowRoot(shadowRoot);
@@ -1291,31 +1289,27 @@ Element::UnattachShadow()
 {
   RefPtr<ShadowRoot> shadowRoot = GetShadowRoot();
   if (!shadowRoot) {
     return;
   }
 
   nsAutoScriptBlocker scriptBlocker;
 
-  if (nsIDocument* doc = GetComposedDoc()) {
+  nsIDocument* doc = GetComposedDoc();
+  if (doc) {
     if (nsIPresShell* shell = doc->GetShell()) {
       shell->DestroyFramesForAndRestyle(this);
     }
   }
   MOZ_ASSERT(!GetPrimaryFrame());
 
   // Simply unhook the shadow root from the element.
-  MOZ_ASSERT(!GetShadowRoot()->HasSlots(), "Won't work when shadow root has slots!");
-  for (nsIContent* child = shadowRoot->GetFirstChild(); child;
-       child = child->GetNextSibling()) {
-    child->UnbindFromTree(true, false);
-  }
-
-  shadowRoot->SetIsComposedDocParticipant(false);
+  MOZ_ASSERT(!shadowRoot->HasSlots(), "Won't work when shadow root has slots!");
+  shadowRoot->Unbind();
   SetShadowRoot(nullptr);
 }
 
 void
 Element::GetAttribute(const nsAString& aName, DOMString& aReturn)
 {
   const nsAttrValue* val =
     mAttrs.GetAttr(aName,
@@ -1620,17 +1614,18 @@ nsresult
 Element::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
                     nsIContent* aBindingParent)
 {
   MOZ_ASSERT(aParent || aDocument, "Must have document if no parent!");
   MOZ_ASSERT((NODE_FROM(aParent, aDocument)->OwnerDoc() == OwnerDoc()),
              "Must have the same owner document");
   MOZ_ASSERT(!aParent || aDocument == aParent->GetUncomposedDoc(),
              "aDocument must be current doc of aParent");
-  MOZ_ASSERT(!GetUncomposedDoc(), "Already have a document.  Unbind first!");
+  MOZ_ASSERT(!IsInComposedDoc(), "Already have a document.  Unbind first!");
+  MOZ_ASSERT(!IsInUncomposedDoc(), "Already have a document.  Unbind first!");
   // Note that as we recurse into the kids, they'll have a non-null parent.  So
   // only assert if our parent is _changing_ while we have a parent.
   MOZ_ASSERT(!GetParent() || aParent == GetParent(),
              "Already have a parent.  Unbind first!");
   MOZ_ASSERT(!GetBindingParent() ||
              aBindingParent == GetBindingParent() ||
              (!aBindingParent && aParent &&
               aParent->GetBindingParent() == GetBindingParent()),
@@ -1673,33 +1668,30 @@ Element::BindToTree(nsIDocument* aDocume
       SetFlags(NODE_CHROME_ONLY_ACCESS);
     }
     if (HasFlag(NODE_IS_ANONYMOUS_ROOT)) {
       aParent->SetMayHaveAnonymousChildren();
     }
     if (aParent->IsInShadowTree()) {
       ClearSubtreeRootPointer();
       SetFlags(NODE_IS_IN_SHADOW_TREE);
-    }
-    ShadowRoot* parentContainingShadow = aParent->GetContainingShadow();
-    if (parentContainingShadow) {
-      ExtendedDOMSlots()->mContainingShadow = parentContainingShadow;
+      MOZ_ASSERT(aParent->GetContainingShadow());
+      ExtendedDOMSlots()->mContainingShadow = aParent->GetContainingShadow();
     }
   }
 
   bool hadParent = !!GetParentNode();
 
   // Now set the parent.
   if (aParent) {
     if (!GetParent()) {
       NS_ADDREF(aParent);
     }
     mParent = aParent;
-  }
-  else {
+  } else {
     mParent = aDocument;
   }
   SetParentIsContent(aParent);
 
   // XXXbz sXBL/XBL2 issue!
 
   MOZ_ASSERT(!HasAnyOfFlags(Element::kAllServoDescendantBits));
 
@@ -1715,20 +1707,22 @@ Element::BindToTree(nsIDocument* aDocume
     //                                                   aDocument);
 
     // We no longer need to track the subtree pointer (and in fact we'll assert
     // if we do this any later).
     ClearSubtreeRootPointer();
 
     // Being added to a document.
     SetIsInDocument();
+    SetIsConnected(true);
 
     // Clear the lazy frame construction bits.
     UnsetFlags(NODE_NEEDS_FRAME | NODE_DESCENDANTS_NEED_FRAMES);
   } else if (IsInShadowTree()) {
+    SetIsConnected(aParent->IsInComposedDoc());
     // We're not in a document, but we did get inserted into a shadow tree.
     // Since we won't have any restyle data in the document's restyle trackers,
     // don't let us get inserted with restyle bits set incorrectly.
     //
     // Also clear all the other flags that are cleared above when we do get
     // inserted into a document.
     //
     // See the comment about the restyle bits above, it also applies.
@@ -1823,23 +1817,18 @@ Element::BindToTree(nsIDocument* aDocume
     // XXXbz if we already have a style attr parsed, this won't do
     // anything... need to fix that.
     // If MayHaveStyle() is true, we must be an nsStyledElement
     static_cast<nsStyledElement*>(this)->ReparseStyleAttribute(false, false);
   }
 
   // Call BindToTree on shadow root children.
   if (ShadowRoot* shadowRoot = GetShadowRoot()) {
-    shadowRoot->SetIsComposedDocParticipant(IsInComposedDoc());
-    MOZ_ASSERT(shadowRoot->GetBindingParent() == this);
-    for (nsIContent* child = shadowRoot->GetFirstChild(); child;
-         child = child->GetNextSibling()) {
-      rv = child->BindToTree(nullptr, shadowRoot, this);
-      NS_ENSURE_SUCCESS(rv, rv);
-    }
+    rv = shadowRoot->Bind();
+    NS_ENSURE_SUCCESS(rv, rv);
   }
 
   // FIXME(emilio): Why is this needed? The element shouldn't even be styled in
   // the first place, we should style it properly eventually.
   //
   // Also, if this _is_ needed, then it's wrong and should use GetComposedDoc()
   // to account for Shadow DOM.
   if (aDocument && MayHaveAnimations()) {
@@ -1989,16 +1978,17 @@ Element::UnbindFromTree(bool aDeep, bool
                  presContext->GetViewportScrollStylesOverrideElement(),
                  "Leaving behind a raw pointer to this element (as having "
                  "propagated scrollbar styles) - that's dangerous...");
     }
   }
 #endif
 
   ClearInDocument();
+  SetIsConnected(false);
 
   // Ensure that CSS transitions don't continue on an element at a
   // different place in the tree (even if reinserted before next
   // animation refresh).
   // We need to delete the properties while we're still in document
   // (if we were in document).
   // FIXME (Bug 522599): Need a test for this.
   if (MayHaveAnimations()) {
@@ -2099,22 +2089,17 @@ Element::UnbindFromTree(bool aDeep, bool
       child->UnbindFromTree(true, false);
     }
   }
 
   nsNodeUtils::ParentChainChanged(this);
 
   // Unbind children of shadow root.
   if (ShadowRoot* shadowRoot = GetShadowRoot()) {
-    for (nsIContent* child = shadowRoot->GetFirstChild(); child;
-         child = child->GetNextSibling()) {
-      child->UnbindFromTree(true, false);
-    }
-
-    shadowRoot->SetIsComposedDocParticipant(false);
+    shadowRoot->Unbind();
   }
 
   MOZ_ASSERT(!HasAnyOfFlags(kAllServoDescendantBits));
   MOZ_ASSERT(!document || document->GetServoRestyleRoot() != this);
 }
 
 nsDOMCSSAttributeDeclaration*
 Element::SMILOverrideStyle()
--- a/dom/base/FragmentOrElement.cpp
+++ b/dom/base/FragmentOrElement.cpp
@@ -1460,23 +1460,17 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(Fr
   } else if (!tmp->GetParent() && tmp->HasChildren()) {
     ContentUnbinder::Append(tmp);
   } /* else {
     The subtree root will end up to a ContentUnbinder, and that will
     unbind the child nodes.
   } */
 
   if (ShadowRoot* shadowRoot = tmp->GetShadowRoot()) {
-    for (nsIContent* child = shadowRoot->GetFirstChild();
-         child;
-         child = child->GetNextSibling()) {
-      child->UnbindFromTree(true, false);
-    }
-
-    shadowRoot->SetIsComposedDocParticipant(false);
+    shadowRoot->Unbind();
     tmp->ExtendedDOMSlots()->mShadowRoot = nullptr;
   }
 
   nsIDocument* doc = tmp->OwnerDoc();
   doc->BindingManager()->RemovedFromDocument(tmp, doc,
                                              nsBindingManager::eDoNotRunDtor);
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
--- a/dom/base/ShadowRoot.cpp
+++ b/dom/base/ShadowRoot.cpp
@@ -58,27 +58,27 @@ NS_IMPL_ADDREF_INHERITED(ShadowRoot, Doc
 NS_IMPL_RELEASE_INHERITED(ShadowRoot, DocumentFragment)
 
 ShadowRoot::ShadowRoot(Element* aElement, ShadowRootMode aMode,
                        already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo)
   : DocumentFragment(aNodeInfo)
   , DocumentOrShadowRoot(*this)
   , mMode(aMode)
   , mServoStyles(Servo_AuthorStyles_Create())
-  , mIsComposedDocParticipant(false)
   , mIsUAWidget(false)
 {
   SetHost(aElement);
 
   // Nodes in a shadow tree should never store a value
   // in the subtree root pointer, nodes in the shadow tree
   // track the subtree root using GetContainingShadow().
   ClearSubtreeRootPointer();
 
   SetFlags(NODE_IS_IN_SHADOW_TREE);
+  Bind();
 
   ExtendedDOMSlots()->mBindingParent = aElement;
   ExtendedDOMSlots()->mContainingShadow = this;
 
   // Add the ShadowRoot as a mutation observer on the host to watch
   // for mutations because the insertion points in this ShadowRoot
   // may need to be updated when the host children are modified.
   GetHost()->AddMutationObserver(this);
@@ -86,51 +86,28 @@ ShadowRoot::ShadowRoot(Element* aElement
 
 ShadowRoot::~ShadowRoot()
 {
   if (auto* host = GetHost()) {
     // mHost may have been unlinked.
     host->RemoveMutationObserver(this);
   }
 
-  if (IsComposedDocParticipant()) {
+  if (IsInComposedDoc()) {
     OwnerDoc()->RemoveComposedDocShadowRoot(*this);
   }
 
   MOZ_DIAGNOSTIC_ASSERT(!OwnerDoc()->IsComposedDocShadowRoot(*this));
 
   UnsetFlags(NODE_IS_IN_SHADOW_TREE);
 
   // nsINode destructor expects mSubtreeRoot == this.
   SetSubtreeRootPointer(this);
 }
 
-void
-ShadowRoot::SetIsComposedDocParticipant(bool aIsComposedDocParticipant)
-{
-  bool changed = mIsComposedDocParticipant != aIsComposedDocParticipant;
-  mIsComposedDocParticipant = aIsComposedDocParticipant;
-  if (!changed) {
-    return;
-  }
-
-  nsIDocument* doc = OwnerDoc();
-  if (IsComposedDocParticipant()) {
-    doc->AddComposedDocShadowRoot(*this);
-  } else {
-    doc->RemoveComposedDocShadowRoot(*this);
-  }
-}
-
-void
-ShadowRoot::SetIsUAWidget(bool aIsUAWidget)
-{
-  mIsUAWidget = aIsUAWidget;
-}
-
 JSObject*
 ShadowRoot::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
 {
   return mozilla::dom::ShadowRoot_Binding::Wrap(aCx, this, aGivenProto);
 }
 
 void
 ShadowRoot::CloneInternalDataFrom(ShadowRoot* aOther)
@@ -143,28 +120,60 @@ ShadowRoot::CloneInternalDataFrom(Shadow
         sheet->Clone(nullptr, nullptr, this, nullptr);
       if (clonedSheet) {
         AppendStyleSheet(*clonedSheet.get());
       }
     }
   }
 }
 
+nsresult
+ShadowRoot::Bind()
+{
+  MOZ_ASSERT(!IsInComposedDoc(), "Forgot to unbind?");
+  if (Host()->IsInComposedDoc()) {
+    SetIsConnected(true);
+    OwnerDoc()->AddComposedDocShadowRoot(*this);
+  }
+
+  for (nsIContent* child = GetFirstChild();
+       child;
+       child = child->GetNextSibling()) {
+    nsresult rv = child->BindToTree(nullptr, this, Host());
+    NS_ENSURE_SUCCESS(rv, rv);
+  }
+
+  return NS_OK;
+}
+
+void
+ShadowRoot::Unbind()
+{
+  if (IsInComposedDoc()) {
+    SetIsConnected(false);
+    OwnerDoc()->RemoveComposedDocShadowRoot(*this);
+  }
+
+  for (nsIContent* child = GetFirstChild();
+       child;
+       child = child->GetNextSibling()) {
+    child->UnbindFromTree(true, false);
+  }
+}
+
 void
 ShadowRoot::InvalidateStyleAndLayoutOnSubtree(Element* aElement)
 {
   MOZ_ASSERT(aElement);
-
-  if (!IsComposedDocParticipant()) {
+  nsIDocument* doc = GetComposedDoc();
+  if (!doc) {
     return;
   }
 
-  MOZ_ASSERT(GetComposedDoc() == OwnerDoc());
-
-  nsIPresShell* shell = OwnerDoc()->GetShell();
+  nsIPresShell* shell = doc->GetShell();
   if (!shell) {
     return;
   }
 
   shell->DestroyFramesForAndRestyle(aElement);
 }
 
 void
@@ -311,21 +320,21 @@ void
 ShadowRoot::RuleChanged(StyleSheet&, css::Rule*) {
   Servo_AuthorStyles_ForceDirty(mServoStyles.get());
   ApplicableRulesChanged();
 }
 
 void
 ShadowRoot::ApplicableRulesChanged()
 {
-  if (!IsComposedDocParticipant()) {
+  nsIDocument* doc = GetComposedDoc();
+  if (!doc) {
     return;
   }
 
-  nsIDocument* doc = OwnerDoc();
   if (nsIPresShell* shell = doc->GetShell()) {
     shell->RecordShadowStyleChange(*this);
   }
 }
 
 void
 ShadowRoot::InsertSheetAt(size_t aIndex, StyleSheet& aSheet)
 {
@@ -509,18 +518,18 @@ ShadowRoot::MaybeReassignElement(Element
   HTMLSlotElement* oldSlot = aElement->GetAssignedSlot();
   SlotAssignment assignment = SlotAssignmentFor(aElement);
 
   if (assignment.mSlot == oldSlot) {
     // Nothing to do here.
     return;
   }
 
-  if (IsComposedDocParticipant()) {
-    if (nsIPresShell* shell = OwnerDoc()->GetShell()) {
+  if (nsIDocument* doc = GetComposedDoc()) {
+    if (nsIPresShell* shell = doc->GetShell()) {
       shell->SlotAssignmentWillChange(*aElement, oldSlot, assignment.mSlot);
     }
   }
 
   if (oldSlot) {
     oldSlot->RemoveAssignedNode(aElement);
     oldSlot->EnqueueSlotChangeEvent();
   }
@@ -558,17 +567,16 @@ ShadowRoot::SetInnerHTML(const nsAString
 
 nsINode*
 ShadowRoot::ImportNodeAndAppendChildAt(nsINode& aParentNode,
                                        nsINode& aNode,
                                        bool aDeep,
                                        mozilla::ErrorResult& rv)
 {
   MOZ_ASSERT(mIsUAWidget);
-  MOZ_ASSERT(OwnerDoc());
 
   if (!aParentNode.IsInUAWidget()) {
     rv.Throw(NS_ERROR_INVALID_ARG);
     return nullptr;
   }
 
   RefPtr<nsINode> node = OwnerDoc()->ImportNode(aNode, aDeep, rv);
   if (rv.Failed()) {
--- a/dom/base/ShadowRoot.h
+++ b/dom/base/ShadowRoot.h
@@ -84,16 +84,24 @@ public:
   }
 
   /**
    * Clones internal state, for example stylesheets, of aOther to 'this'.
    */
   void CloneInternalDataFrom(ShadowRoot* aOther);
   void InsertSheetAt(size_t aIndex, StyleSheet&);
 
+  // Calls UnbindFromTree for each of our kids, and also flags us as no longer
+  // being connected.
+  void Unbind();
+
+  // Calls BindToTree on each of our kids, and also maybe flags us as being
+  // connected.
+  nsresult Bind();
+
 private:
   void InsertSheetIntoAuthorData(size_t aIndex, StyleSheet&);
 
   void AppendStyleSheet(StyleSheet& aSheet)
   {
     InsertSheetAt(SheetCount(), aSheet);
   }
 
@@ -180,29 +188,25 @@ public:
   nsINode* ImportNodeAndAppendChildAt(nsINode& aParentNode,
                                       nsINode& aNode,
                                       bool aDeep, mozilla::ErrorResult& rv);
 
   nsINode* CreateElementAndAppendChildAt(nsINode& aParentNode,
                                          const nsAString& aTagName,
                                          mozilla::ErrorResult& rv);
 
-  bool IsComposedDocParticipant() const
-  {
-    return mIsComposedDocParticipant;
-  }
-
-  void SetIsComposedDocParticipant(bool aIsComposedDocParticipant);
-
   bool IsUAWidget() const
   {
     return mIsUAWidget;
   }
 
-  void SetIsUAWidget(bool aIsUAWidget);
+  void SetIsUAWidget()
+  {
+    mIsUAWidget = true;
+  }
 
   void GetEventTargetParent(EventChainPreVisitor& aVisitor) override;
 
 protected:
   // FIXME(emilio): This will need to become more fine-grained.
   void ApplicableRulesChanged();
 
   virtual ~ShadowRoot();
@@ -214,22 +218,16 @@ protected:
   UniquePtr<mozilla::ServoStyleRuleMap> mStyleRuleMap;
 
   using SlotArray = AutoTArray<HTMLSlotElement*, 1>;
   // Map from name of slot to an array of all slots in the shadow DOM with with
   // the given name. The slots are stored as a weak pointer because the elements
   // are in the shadow tree and should be kept alive by its parent.
   nsClassHashtable<nsStringHashKey, SlotArray> mSlotMap;
 
-  // Flag to indicate whether the descendants of this shadow root are part of the
-  // composed document. Ideally, we would use a node flag on nodes to
-  // mark whether it is in the composed document, but we have run out of flags
-  // so instead we track it here.
-  bool mIsComposedDocParticipant;
-
   bool mIsUAWidget;
 
   nsresult Clone(dom::NodeInfo*, nsINode** aResult) const override;
 };
 
 } // namespace dom
 } // namespace mozilla
 
--- a/dom/base/nsDocument.cpp
+++ b/dom/base/nsDocument.cpp
@@ -1514,16 +1514,17 @@ nsIDocument::nsIDocument()
     mCurrentOrientationType(OrientationType::Portrait_primary),
     mServoRestyleRootDirtyBits(0),
     mThrowOnDynamicMarkupInsertionCounter(0),
     mIgnoreOpensDuringUnloadCounter(0),
     mNumTrackersFound(0),
     mNumTrackersBlocked(0)
 {
   SetIsInDocument();
+  SetIsConnected(true);
 }
 
 nsDocument::nsDocument(const char* aContentType)
   : nsIDocument()
 {
   SetContentTypeInternal(nsDependentCString(aContentType));
 
   MOZ_LOG(gDocumentLeakPRLog, LogLevel::Debug, ("DOCUMENT %p created", this));
--- a/dom/base/nsIDocument.h
+++ b/dom/base/nsIDocument.h
@@ -3812,17 +3812,17 @@ protected:
   RefPtr<nsHTMLStyleSheet> mAttrStyleSheet;
   RefPtr<nsHTMLCSSStyleSheet> mStyleAttrStyleSheet;
 
   // Tracking for images in the document.
   RefPtr<mozilla::dom::ImageTracker> mImageTracker;
 
   // A hashtable of ShadowRoots belonging to the composed doc.
   //
-  // See ShadowRoot::SetIsComposedDocParticipant.
+  // See ShadowRoot::Bind and ShadowRoot::Unbind.
   ShadowRootSet mComposedShadowRoots;
 
   using SVGUseElementSet =
     nsTHashtable<nsPtrHashKey<mozilla::dom::SVGUseElement>>;
 
   // The set of <svg:use> elements that need a shadow tree reclone because the
   // tree they map to has changed.
   SVGUseElementSet mSVGUseElementsNeedingShadowTreeUpdate;
--- a/dom/base/nsINode.cpp
+++ b/dom/base/nsINode.cpp
@@ -246,18 +246,18 @@ nsINode::GetTextEditorRootContent(TextEd
     return rootElement;
   }
   return nullptr;
 }
 
 nsINode* nsINode::GetRootNode(const GetRootNodeOptions& aOptions)
 {
   if (aOptions.mComposed) {
-    if (IsInComposedDoc() && GetComposedDoc()) {
-      return OwnerDoc();
+    if (nsIDocument* doc = GetComposedDoc()) {
+      return doc;
     }
 
     nsINode* node = this;
     while(node) {
       node = node->SubtreeRoot();
       ShadowRoot* shadow = ShadowRoot::FromNode(node);
       if (!shadow) {
         break;
@@ -452,35 +452,24 @@ nsINode::InvalidateChildNodes()
 }
 
 void
 nsINode::GetTextContentInternal(nsAString& aTextContent, OOMReporter& aError)
 {
   SetDOMStringToNull(aTextContent);
 }
 
-nsIDocument*
-nsINode::GetComposedDocInternal() const
-{
-  MOZ_ASSERT(HasFlag(NODE_IS_IN_SHADOW_TREE) && IsContent(),
-             "Should only be caled on nodes in the shadow tree.");
-
-  ShadowRoot* containingShadow = AsContent()->GetContainingShadow();
-  return containingShadow && containingShadow->IsComposedDocParticipant() ?
-    OwnerDoc() : nullptr;
-}
-
 DocumentOrShadowRoot*
 nsINode::GetUncomposedDocOrConnectedShadowRoot() const
 {
   if (IsInUncomposedDoc()) {
     return OwnerDoc();
   }
 
-  if (IsInComposedDoc() && HasFlag(NODE_IS_IN_SHADOW_TREE)) {
+  if (IsInComposedDoc() && IsInShadowTree()) {
     return AsContent()->GetContainingShadow();
   }
 
   return nullptr;
 }
 
 #ifdef DEBUG
 void
--- a/dom/base/nsINode.h
+++ b/dom/base/nsINode.h
@@ -638,34 +638,34 @@ public:
    */
 
   nsIDocument* GetUncomposedDoc() const
   {
     return IsInUncomposedDoc() ? OwnerDoc() : nullptr;
   }
 
   /**
+   * Returns true if we're connected, and thus GetComposedDoc() would return a
+   * non-null value.
+   */
+  bool IsInComposedDoc() const
+  {
+    return GetBoolFlag(IsConnected);
+  }
+
+  /**
    * This method returns the owner document if the node is connected to it
    * (as defined in the DOM spec), otherwise it returns null.
    * In other words, returns non-null even in the case the node is in
    * Shadow DOM, if there is a possibly shadow boundary crossing path from
    * the node to its owner document.
    */
   nsIDocument* GetComposedDoc() const
   {
-    return IsInShadowTree() ?
-      GetComposedDocInternal() : GetUncomposedDoc();
-  }
-
-  /**
-   * Returns true if GetComposedDoc() would return a non-null value.
-   */
-  bool IsInComposedDoc() const
-  {
-    return IsInUncomposedDoc() || (IsInShadowTree() && GetComposedDocInternal());
+    return IsInComposedDoc() ? OwnerDoc() : nullptr;
   }
 
   /**
    * Returns OwnerDoc() if the node is in uncomposed document and ShadowRoot if
    * the node is in Shadow DOM and is in composed document.
    */
   mozilla::dom::DocumentOrShadowRoot* GetUncomposedDocOrConnectedShadowRoot() const;
 
@@ -1413,18 +1413,16 @@ public:
   bool Contains(const nsINode* aOther) const;
 
   bool UnoptimizableCCNode() const;
 
 private:
 
   mozilla::dom::SVGUseElement* DoGetContainingSVGUseShadowHost() const;
 
-  nsIDocument* GetComposedDocInternal() const;
-
   nsIContent* GetNextNodeImpl(const nsINode* aRoot,
                               const bool aSkipChildren) const
   {
     // Can't use nsContentUtils::ContentIsDescendantOf here, since we
     // can't include it here.
 #ifdef DEBUG
     if (aRoot) {
       const nsINode* cur = this;
@@ -1496,16 +1494,19 @@ public:
    */
 private:
   enum BooleanFlag {
     // Set if we're being used from -moz-element
     NodeHasRenderingObservers,
     // Set if our parent chain (including this node itself) terminates
     // in a document
     IsInDocument,
+    // Set if we're part of the composed doc.
+    // https://dom.spec.whatwg.org/#connected
+    IsConnected,
     // Set if mParent is an nsIContent
     ParentIsContent,
     // Set if this node is an Element
     NodeIsElement,
     // Set if the element has a non-empty id attribute. This can in rare
     // cases lie for nsXMLElement, such as when the node has been moved between
     // documents with different id mappings.
     ElementHasID,
@@ -1550,18 +1551,16 @@ private:
     // Set if the node is a text node descendant of a node with dir=auto
     // and has a TextNodeDirectionalityMap property listing the elements whose
     // direction it determines.
     NodeHasTextNodeDirectionalityMap,
     // Set if a node in the node's parent chain has dir=auto.
     NodeAncestorHasDirAuto,
     // Set if the node is handling a click.
     NodeHandlingClick,
-    // Set if the node has had :hover selectors matched against it
-    NodeHasRelevantHoverRules,
     // Set if the element has a parser insertion mode other than "in body",
     // per the HTML5 "Parse state" section.
     ElementHasWeirdParserInsertionMode,
     // Parser sets this flag if it has notified about the node.
     ParserHasNotified,
     // Sets if the node is apz aware or we have apz aware listeners.
     MayBeApzAware,
     // Set if the element might have any kind of anonymous content children,
@@ -1675,18 +1674,16 @@ public:
 
   void SetAncestorHasDirAuto() { SetBoolFlag(NodeAncestorHasDirAuto); }
   void ClearAncestorHasDirAuto() { ClearBoolFlag(NodeAncestorHasDirAuto); }
   bool AncestorHasDirAuto() const { return GetBoolFlag(NodeAncestorHasDirAuto); }
 
   // Implemented in nsIContentInlines.h.
   inline bool NodeOrAncestorHasDirAuto() const;
 
-  bool HasRelevantHoverRules() const { return GetBoolFlag(NodeHasRelevantHoverRules); }
-  void SetHasRelevantHoverRules() { SetBoolFlag(NodeHasRelevantHoverRules); }
   void SetParserHasNotified() { SetBoolFlag(ParserHasNotified); };
   bool HasParserNotified() { return GetBoolFlag(ParserHasNotified); }
 
   void SetMayBeApzAware() { SetBoolFlag(MayBeApzAware); }
   bool NodeMayBeApzAware() const
   {
     return GetBoolFlag(MayBeApzAware);
   }
@@ -1695,18 +1692,19 @@ public:
   bool MayHaveAnonymousChildren() const { return GetBoolFlag(ElementMayHaveAnonymousChildren); }
 
   void SetHasCustomElementData() { SetBoolFlag(ElementHasCustomElementData); }
   bool HasCustomElementData() const { return GetBoolFlag(ElementHasCustomElementData); }
 
 protected:
   void SetParentIsContent(bool aValue) { SetBoolFlag(ParentIsContent, aValue); }
   void SetIsInDocument() { SetBoolFlag(IsInDocument); }
+  void ClearInDocument() { ClearBoolFlag(IsInDocument); }
+  void SetIsConnected(bool aConnected) { SetBoolFlag(IsConnected, aConnected); }
   void SetNodeIsContent() { SetBoolFlag(NodeIsContent); }
-  void ClearInDocument() { ClearBoolFlag(IsInDocument); }
   void SetIsElement() { SetBoolFlag(NodeIsElement); }
   void SetHasID() { SetBoolFlag(ElementHasID); }
   void ClearHasID() { ClearBoolFlag(ElementHasID); }
   void SetMayHaveStyle() { SetBoolFlag(ElementMayHaveStyle); }
   void SetHasName() { SetBoolFlag(ElementHasName); }
   void ClearHasName() { ClearBoolFlag(ElementHasName); }
   void SetMayHaveContentEditableAttr()
     { SetBoolFlag(ElementMayHaveContentEditableAttr); }
--- a/dom/html/HTMLMediaElement.cpp
+++ b/dom/html/HTMLMediaElement.cpp
@@ -4945,17 +4945,17 @@ HTMLMediaElement::AttachAndSetUAShadowRo
   if (GetShadowRoot()) {
     MOZ_ASSERT(GetShadowRoot()->IsUAWidget());
     return;
   }
 
   // Add a closed shadow root to host video controls
   RefPtr<ShadowRoot> shadowRoot =
     AttachShadowWithoutNameChecks(ShadowRootMode::Closed);
-  shadowRoot->SetIsUAWidget(true);
+  shadowRoot->SetIsUAWidget();
 }
 
 nsresult
 HTMLMediaElement::InitializeDecoderAsClone(ChannelMediaDecoder* aOriginal)
 {
   NS_ASSERTION(mLoadingSrc, "mLoadingSrc must already be set");
   NS_ASSERTION(mDecoder == nullptr, "Shouldn't have a decoder");
   AssertReadyStateIsNothing();
--- a/dom/webidl/Node.webidl
+++ b/dom/webidl/Node.webidl
@@ -29,17 +29,17 @@ interface Node : EventTarget {
   [Constant]
   readonly attribute unsigned short nodeType;
   [Pure]
   readonly attribute DOMString nodeName;
 
   [Pure, Throws, NeedsCallerType, BinaryName="baseURIFromJS"]
   readonly attribute DOMString? baseURI;
 
-  [Pure, BinaryName=getComposedDoc]
+  [Pure, BinaryName=isInComposedDoc]
   readonly attribute boolean isConnected;
   [Pure]
   readonly attribute Document? ownerDocument;
   [Pure]
   Node getRootNode(optional GetRootNodeOptions options);
   [Pure]
   readonly attribute Node? parentNode;
   [Pure]
--- a/dom/webidl/ShadowRoot.webidl
+++ b/dom/webidl/ShadowRoot.webidl
@@ -42,12 +42,12 @@ interface ShadowRoot : DocumentFragment
   [CEReactions, Throws, Func="IsChromeOrXBLOrUAWidget"]
   Node importNodeAndAppendChildAt(Node parentNode, Node node, optional boolean deep = false);
 
   [CEReactions, Throws, Func="IsChromeOrXBLOrUAWidget"]
   Node createElementAndAppendChildAt(Node parentNode, DOMString localName);
 
   // For triggering UA Widget scope in tests.
   [ChromeOnly]
-  void setIsUAWidget(boolean isUAWidget);
+  void setIsUAWidget();
 };
 
 ShadowRoot implements DocumentOrShadowRoot;
--- a/layout/style/ServoStyleSet.cpp
+++ b/layout/style/ServoStyleSet.cpp
@@ -171,17 +171,17 @@ ServoStyleSet::Init(nsPresContext* aPres
 template<typename Functor>
 void
 EnumerateShadowRoots(const nsIDocument& aDoc, const Functor& aCb)
 {
   const nsIDocument::ShadowRootSet& shadowRoots = aDoc.ComposedShadowRoots();
   for (auto iter = shadowRoots.ConstIter(); !iter.Done(); iter.Next()) {
     ShadowRoot* root = iter.Get()->GetKey();
     MOZ_ASSERT(root);
-    MOZ_DIAGNOSTIC_ASSERT(root->IsComposedDocParticipant());
+    MOZ_DIAGNOSTIC_ASSERT(root->IsInComposedDoc());
     aCb(*root);
   }
 }
 
 void
 ServoStyleSet::Shutdown()
 {
   // Make sure we drop our cached styles before the presshell arena starts going
--- a/netwerk/base/nsChannelClassifier.cpp
+++ b/netwerk/base/nsChannelClassifier.cpp
@@ -884,17 +884,17 @@ nsChannelClassifier::SetBlockedContent(n
   pwin->NotifyContentBlockingState(state, channel);
 
   // Log a warning to the web console.
   nsCOMPtr<nsIURI> uri;
   channel->GetURI(getter_AddRefs(uri));
   NS_ConvertUTF8toUTF16 spec(uri->GetSpecOrDefault());
   const char16_t* params[] = { spec.get() };
   const char* message = (aErrorCode == NS_ERROR_TRACKING_URI) ?
-    "TrackingUriBlocked" : "UnsafeUriBlocked";
+    "TrackerUriBlocked" : "UnsafeUriBlocked";
   nsCString category = (aErrorCode == NS_ERROR_TRACKING_URI) ?
     NS_LITERAL_CSTRING("Tracking Protection") :
     NS_LITERAL_CSTRING("Safe Browsing");
 
   nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
                                   category,
                                   doc,
                                   nsContentUtils::eNECKO_PROPERTIES,
--- a/netwerk/locales/en-US/necko.properties
+++ b/netwerk/locales/en-US/necko.properties
@@ -35,14 +35,14 @@ DirColSize=Size
 DirColMTime=Last Modified
 DirFileLabel=File: 
 
 PhishingAuth=You are about to visit “%1$S”. This site may be attempting to trick you into thinking you are visiting a different site. Use extreme caution.
 PhishingAuthAccept=I understand and will be very careful
 SuperfluousAuth=You are about to log in to the site “%1$S” with the username “%2$S”, but the website does not require authentication. This may be an attempt to trick you.\n\nIs “%1$S” the site you want to visit?
 AutomaticAuth=You are about to log in to the site “%1$S” with the username “%2$S”.
 
-TrackingUriBlocked=The resource at “%1$S” was blocked because tracking protection is enabled.
+TrackerUriBlocked=The resource at “%1$S” was blocked because content blocking is enabled.
 UnsafeUriBlocked=The resource at “%1$S” was blocked by Safe Browsing.
 
 # LOCALIZATION NOTE (nsICookieManagerAPIDeprecated): don't localize originAttributes.
 # %1$S is the deprecated API; %2$S is the interface suffix that the given deprecated API belongs to.
 nsICookieManagerAPIDeprecated=“%1$S” is changed. Update your code and pass the correct originAttributes. Read more on MDN: https://developer.mozilla.org/docs/Mozilla/Tech/XPCOM/Reference/Interface/nsICookieManager%2$S
--- a/python/mozbuild/mozbuild/testing.py
+++ b/python/mozbuild/mozbuild/testing.py
@@ -295,9 +295,15 @@ def read_wpt_manifest(context, paths):
         paths_file = os.path.join(context.config.topsrcdir, "testing",
                                   "web-platform", "tests", "tools", "localpaths.py")
         _globals = {"__file__": paths_file}
         execfile(paths_file, _globals)
         import manifest as wptmanifest
     finally:
         sys.path = old_path
         f = context._finder.get(full_path)
-        return wptmanifest.manifest.load(tests_root, f)
+        try:
+            rv = wptmanifest.manifest.load(tests_root, f)
+        except wptmanifest.manifest.ManifestVersionMismatch:
+            # If we accidentially end up with a committed manifest that's the wrong
+            # version, then return an empty manifest here just to not break the build
+            rv = wptmanifest.manifest.Manifest()
+        return rv
--- a/taskcluster/docker/funsize-update-generator/Pipfile.lock
+++ b/taskcluster/docker/funsize-update-generator/Pipfile.lock
@@ -132,37 +132,37 @@
         "construct": {
             "hashes": [
                 "sha256:2271a0efd0798679dea825ff47e22a4c550456a5db0ba8baa82f7eae0af0118c"
             ],
             "version": "==2.9.45"
         },
         "cryptography": {
             "hashes": [
-                "sha256:21af753934f2f6d1a10fe8f4c0a64315af209ef6adeaee63ca349797d747d687",
-                "sha256:27bb401a20a838d6d0ea380f08c6ead3ccd8c9d8a0232dc9adcc0e4994576a66",
-                "sha256:29720c4253263cff9aea64585adbbe85013ba647f6e98367efff9db2d7193ded",
-                "sha256:2a35b7570d8f247889784010aac8b384fd2e4a47b33e15c4a60b45a7c1944120",
-                "sha256:42c531a6a354407f42ee07fda5c2c0dc822cf6d52744949c182f2b295fbd4183",
-                "sha256:5eb86f03f9c4f0ac2336ac5431271072ddf7ecc76b338e26366732cfac58aa19",
-                "sha256:67f7f57eae8dede577f3f7775957f5bec93edd6bdb6ce597bb5b28e1bdf3d4fb",
-                "sha256:6ec84edcbc966ae460560a51a90046503ff0b5b66157a9efc61515c68059f6c8",
-                "sha256:7ba834564daef87557e7fcd35c3c3183a4147b0b3a57314e53317360b9b201b3",
-                "sha256:7d7f084cbe1fdb82be5a0545062b59b1ad3637bc5a48612ac2eb428ff31b31ea",
-                "sha256:82409f5150e529d699e5c33fa8fd85e965104db03bc564f5f4b6a9199e591f7c",
-                "sha256:87d092a7c2a44e5f7414ab02fb4145723ebba411425e1a99773531dd4c0e9b8d",
-                "sha256:8c56ef989342e42b9fcaba7c74b446f0cc9bed546dd00034fa7ad66fc00307ef",
-                "sha256:9449f5d4d7c516a6118fa9210c4a00f34384cb1d2028672100ee0c6cce49d7f6",
-                "sha256:bc2301170986ad82d9349a91eb8884e0e191209c45f5541b16aa7c0cfb135978",
-                "sha256:c132bab45d4bd0fff1d3fe294d92b0a6eb8404e93337b3127bdec9f21de117e6",
-                "sha256:c3d945b7b577f07a477700f618f46cbc287af3a9222cd73035c6ef527ef2c363",
-                "sha256:cee18beb4c807b5c0b178f4fa2fae03cef9d51821a358c6890f8b23465b7e5d2",
-                "sha256:d01dfc5c2b3495184f683574e03c70022674ca9a7be88589c5aba130d835ea90"
+                "sha256:02602e1672b62e803e08617ec286041cc453e8d43f093a5f4162095506bc0beb",
+                "sha256:10b48e848e1edb93c1d3b797c83c72b4c387ab0eb4330aaa26da8049a6cbede0",
+                "sha256:17db09db9d7c5de130023657be42689d1a5f60502a14f6f745f6f65a6b8195c0",
+                "sha256:227da3a896df1106b1a69b1e319dce218fa04395e8cc78be7e31ca94c21254bc",
+                "sha256:2cbaa03ac677db6c821dac3f4cdfd1461a32d0615847eedbb0df54bb7802e1f7",
+                "sha256:31db8febfc768e4b4bd826750a70c79c99ea423f4697d1dab764eb9f9f849519",
+                "sha256:4a510d268e55e2e067715d728e4ca6cd26a8e9f1f3d174faf88e6f2cb6b6c395",
+                "sha256:6a88d9004310a198c474d8a822ee96a6dd6c01efe66facdf17cb692512ae5bc0",
+                "sha256:76936ec70a9b72eb8c58314c38c55a0336a2b36de0c7ee8fb874a4547cadbd39",
+                "sha256:7e3b4aecc4040928efa8a7cdaf074e868af32c58ffc9bb77e7bf2c1a16783286",
+                "sha256:8168bcb08403ef144ff1fb880d416f49e2728101d02aaadfe9645883222c0aa5",
+                "sha256:8229ceb79a1792823d87779959184a1bf95768e9248c93ae9f97c7a2f60376a1",
+                "sha256:8a19e9f2fe69f6a44a5c156968d9fc8df56d09798d0c6a34ccc373bb186cee86",
+                "sha256:8d10113ca826a4c29d5b85b2c4e045ffa8bad74fb525ee0eceb1d38d4c70dfd6",
+                "sha256:be495b8ec5a939a7605274b6e59fbc35e76f5ad814ae010eb679529671c9e119",
+                "sha256:dc2d3f3b1548f4d11786616cf0f4415e25b0fbecb8a1d2cd8c07568f13fdde38",
+                "sha256:e4aecdd9d5a3d06c337894c9a6e2961898d3f64fe54ca920a72234a3de0f9cb3",
+                "sha256:e79ab4485b99eacb2166f3212218dd858258f374855e1568f728462b0e6ee0d9",
+                "sha256:f995d3667301e1754c57b04e0bae6f0fa9d710697a9f8d6712e8cca02550910f"
             ],
-            "version": "==2.3"
+            "version": "==2.3.1"
         },
         "datadog": {
             "hashes": [
                 "sha256:86cef95acd73543d18c417f1b0313c0a7274ed8f5ae9cceb46314f4e588085b1"
             ],
             "index": "pypi",
             "version": "==0.22.0"
         },
@@ -372,25 +372,25 @@
             ],
             "version": "==4.0.1"
         },
         "urllib3": {
             "hashes": [
                 "sha256:a68ac5e15e76e7e5dd2b8f94007233e01effe3e50e8daddf69acfd81cb686baf",
                 "sha256:b5725a0bd4ba422ab0e66e89e030c806576753ea3ee08554382c14e685d117b5"
             ],
-            "markers": "python_version != '3.3.*' and python_version != '3.1.*' and python_version != '3.2.*' and python_version != '3.0.*' and python_version < '4' and python_version >= '2.6'",
+            "markers": "python_version != '3.0.*' and python_version != '3.2.*' and python_version != '3.3.*' and python_version >= '2.6' and python_version < '4' and python_version != '3.1.*'",
             "version": "==1.23"
         },
         "virtualenv": {
             "hashes": [
                 "sha256:2ce32cd126117ce2c539f0134eb89de91a8413a29baac49cbab3eb50e2026669",
                 "sha256:ca07b4c0b54e14a91af9f34d0919790b016923d157afda5efdde55c96718f752"
             ],
-            "markers": "python_version >= '2.7' and python_version != '3.1.*' and python_version != '3.2.*' and python_version != '3.0.*'",
+            "markers": "python_version >= '2.7' and python_version != '3.1.*' and python_version != '3.0.*' and python_version != '3.2.*'",
             "version": "==16.0.0"
         },
         "yarl": {
             "hashes": [
                 "sha256:2556b779125621b311844a072e0ed367e8409a18fa12cbd68eb1258d187820f9",
                 "sha256:4aec0769f1799a9d4496827292c02a7b1f75c0bab56ab2b60dd94ebb57cbd5ee",
                 "sha256:55369d95afaacf2fa6b49c84d18b51f1704a6560c432a0f9a1aeb23f7b971308",
                 "sha256:6c098b85442c8fe3303e708bbb775afd0f6b29f77612e8892627bcab4b939357",
--- a/testing/web-platform/manifestupdate.py
+++ b/testing/web-platform/manifestupdate.py
@@ -4,21 +4,23 @@ import os
 import sys
 from collections import defaultdict
 
 from mozlog.structured import commandline
 from wptrunner.wptcommandline import get_test_paths, set_from_config
 
 manifest = None
 
+
 def do_delayed_imports(wpt_dir):
     global manifest
     sys.path.insert(0, os.path.join(wpt_dir, "tools", "manifest"))
     import manifest
 
+
 def create_parser():
     p = argparse.ArgumentParser()
     p.add_argument("--check-clean", action="store_true",
                    help="Check that updating the manifest doesn't lead to any changes")
     p.add_argument("--rebuild", action="store_true",
                    help="Rebuild the manifest from scratch")
     commandline.add_logging_group(p)
 
@@ -42,20 +44,24 @@ def update(logger, wpt_dir, check_clean=
         return _check_clean(logger, test_paths)
 
     return _update(logger, test_paths, rebuild)
 
 
 def _update(logger, test_paths, rebuild):
     for url_base, paths in test_paths.iteritems():
         manifest_path = os.path.join(paths["metadata_path"], "MANIFEST.json")
-        if rebuild:
+        m = None
+        if not rebuild:
+            try:
+                m = manifest.manifest.load(paths["tests_path"], manifest_path)
+            except manifest.manifest.ManifestVersionMismatch:
+                logger.info("Manifest format changed, rebuilding")
+        if m is None:
             m = manifest.manifest.Manifest(url_base)
-        else:
-            m = manifest.manifest.load(paths["tests_path"], manifest_path)
         manifest.update.update(paths["tests_path"], m, working_copy=True)
         manifest.manifest.write(m, manifest_path)
     return 0
 
 
 def _check_clean(logger, test_paths):
     manifests_by_path = {}
     rv = 0
--- a/toolkit/components/places/nsITaggingService.idl
+++ b/toolkit/components/places/nsITaggingService.idl
@@ -54,19 +54,15 @@ interface nsITaggingService : nsISupport
    * @param aURI
    *        a URL.
    * @returns array of tags (sorted by name).
    */
   void getTagsForURI(in nsIURI aURI,
                      [optional] out unsigned long length,
                      [retval, array, size_is(length)] out wstring aTags);
 
-  /**
-   * Retrieves all tags used to tag URIs in the data-base (sorted by name).
-   */
-  readonly attribute nsIVariant allTags;
 };
 
 %{C++
 
 #define TAGGING_SERVICE_CID "@mozilla.org/browser/tagging-service;1"
 
 %}
--- a/toolkit/content/tests/widgets/test_ua_widget.html
+++ b/toolkit/content/tests/widgets/test_ua_widget.html
@@ -16,17 +16,17 @@
 
 <pre id="test">
 <script class="testbody" type="text/javascript">
 
 const content = document.getElementById("content");
 
 const div = content.appendChild(document.createElement("div"));
 div.attachShadow({ mode: "open"});
-SpecialPowers.wrap(div.shadowRoot).setIsUAWidget(true);
+SpecialPowers.wrap(div.shadowRoot).setIsUAWidget();
 
 const sandbox = SpecialPowers.Cu.getUAWidgetScope(SpecialPowers.wrap(div).nodePrincipal);
 
 SpecialPowers.setWrapped(sandbox, "info", SpecialPowers.wrap(info));
 SpecialPowers.setWrapped(sandbox, "is", SpecialPowers.wrap(is));
 SpecialPowers.setWrapped(sandbox, "ok", SpecialPowers.wrap(ok));
 
 const sandboxScript = function(shadowRoot) {