Backed out 3 changesets (bug 1426494) for build bustages on dom/base/FuzzingFunctions.h:25:44 r=backout on a CLOSED TREE
authorCosmin Sabou <csabou@mozilla.com>
Thu, 21 Dec 2017 03:09:22 +0200
changeset 451332 a8fc361b0f24025fa0db2fb838d074317b6b55c2
parent 451331 d1d69957a5b393ec0e55fdda57d5128f6629630e
child 451333 41168df03ca6d90b175c86aabd899535d075ab22
push id1648
push usermtabara@mozilla.com
push dateThu, 01 Mar 2018 12:45:47 +0000
treeherdermozilla-release@cbb9688c2eeb [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbackout
bugs1426494
milestone59.0a1
backs out8d07cb1ef2323f3033e10f4eeb0c4e6a69b8a9ae
74a8ebb0f5d3e1e4c98989c483765bd8a1f76e84
07c4aa18a0b6ce4df6626c9a4fb9d4a37fe4c5d4
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
Backed out 3 changesets (bug 1426494) for build bustages on dom/base/FuzzingFunctions.h:25:44 r=backout on a CLOSED TREE Backed out changeset 8d07cb1ef232 (bug 1426494) Backed out changeset 74a8ebb0f5d3 (bug 1426494) Backed out changeset 07c4aa18a0b6 (bug 1426494)
dom/base/DocumentOrShadowRoot.cpp
dom/base/DocumentOrShadowRoot.h
dom/base/Element.h
dom/base/ShadowRoot.cpp
dom/base/ShadowRoot.h
dom/base/StyleScope.cpp
dom/base/StyleScope.h
dom/base/StyleSheetList.cpp
dom/base/StyleSheetList.h
dom/base/moz.build
dom/base/nsContentUtils.cpp
dom/base/nsContentUtils.h
dom/base/nsDocument.cpp
dom/base/nsDocument.h
dom/base/nsIDocument.h
dom/base/nsIdentifierMapEntry.h
dom/html/nsHTMLDocument.h
dom/xul/XULDocument.cpp
dom/xul/XULDocument.h
editor/libeditor/TextEditor.cpp
deleted file mode 100644
--- a/dom/base/DocumentOrShadowRoot.cpp
+++ /dev/null
@@ -1,95 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set ts=8 sts=2 et sw=2 tw=80: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "DocumentOrShadowRoot.h"
-#include "mozilla/dom/StyleSheetList.h"
-#include "XULDocument.h"
-
-namespace mozilla {
-namespace dom {
-
-DocumentOrShadowRoot::DocumentOrShadowRoot(mozilla::dom::ShadowRoot& aShadowRoot)
-  : mAsNode(aShadowRoot)
-  , mKind(Kind::ShadowRoot)
-{}
-
-DocumentOrShadowRoot::DocumentOrShadowRoot(nsIDocument& aDoc)
-  : mAsNode(aDoc)
-  , mKind(Kind::Document)
-{}
-
-StyleSheetList&
-DocumentOrShadowRoot::EnsureDOMStyleSheets()
-{
-  if (!mDOMStyleSheets) {
-    mDOMStyleSheets = new StyleSheetList(*this);
-  }
-  return *mDOMStyleSheets;
-}
-
-Element*
-DocumentOrShadowRoot::GetElementById(const nsAString& aElementId)
-{
-  if (MOZ_UNLIKELY(aElementId.IsEmpty())) {
-    nsContentUtils::ReportEmptyGetElementByIdArg(AsNode().OwnerDoc());
-    return nullptr;
-  }
-
-  if (nsIdentifierMapEntry* entry = mIdentifierMap.GetEntry(aElementId)) {
-    if (Element* el = entry->GetIdElement()) {
-      return el;
-    }
-  }
-
-  if (MOZ_UNLIKELY(mKind == Kind::Document &&
-      static_cast<nsIDocument&>(AsNode()).IsXULDocument())) {
-    return static_cast<XULDocument&>(AsNode()).GetRefById(aElementId);
-  }
-
-  return nullptr;
-}
-
-already_AddRefed<nsContentList>
-DocumentOrShadowRoot::GetElementsByTagNameNS(const nsAString& aNamespaceURI,
-                                   const nsAString& aLocalName)
-{
-  ErrorResult rv;
-  RefPtr<nsContentList> list =
-    GetElementsByTagNameNS(aNamespaceURI, aLocalName, rv);
-  if (rv.Failed()) {
-    return nullptr;
-  }
-  return list.forget();
-}
-
-already_AddRefed<nsContentList>
-DocumentOrShadowRoot::GetElementsByTagNameNS(const nsAString& aNamespaceURI,
-                                   const nsAString& aLocalName,
-                                   mozilla::ErrorResult& aResult)
-{
-  int32_t nameSpaceId = kNameSpaceID_Wildcard;
-
-  if (!aNamespaceURI.EqualsLiteral("*")) {
-    aResult =
-      nsContentUtils::NameSpaceManager()->RegisterNameSpace(aNamespaceURI,
-                                                            nameSpaceId);
-    if (aResult.Failed()) {
-      return nullptr;
-    }
-  }
-
-  NS_ASSERTION(nameSpaceId != kNameSpaceID_Unknown, "Unexpected namespace ID!");
-  return NS_GetContentList(&AsNode(), nameSpaceId, aLocalName);
-}
-
-already_AddRefed<nsContentList>
-DocumentOrShadowRoot::GetElementsByClassName(const nsAString& aClasses)
-{
-  return nsContentUtils::GetElementsByClassName(&AsNode(), aClasses);
-}
-
-}
-}
deleted file mode 100644
--- a/dom/base/DocumentOrShadowRoot.h
+++ /dev/null
@@ -1,149 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set ts=8 sts=2 et sw=2 tw=80: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#ifndef mozilla_dom_DocumentOrShadowRoot_h__
-#define mozilla_dom_DocumentOrShadowRoot_h__
-
-#include "nsTArray.h"
-#include "nsIdentifierMapEntry.h"
-
-class nsContentList;
-class nsINode;
-
-namespace mozilla {
-class StyleSheet;
-
-namespace dom {
-
-class StyleSheetList;
-class ShadowRoot;
-
-/**
- * A class meant to be shared by ShadowRoot and Document, that holds a list of
- * stylesheets.
- *
- * TODO(emilio, bug 1418159): In the future this should hold most of the
- * relevant style state, this should allow us to fix bug 548397.
- */
-class DocumentOrShadowRoot
-{
-  enum class Kind
-  {
-    Document,
-    ShadowRoot,
-  };
-
-public:
-  explicit DocumentOrShadowRoot(nsIDocument&);
-  explicit DocumentOrShadowRoot(mozilla::dom::ShadowRoot&);
-
-  nsINode& AsNode()
-  {
-    return mAsNode;
-  }
-
-  const nsINode& AsNode() const
-  {
-    return mAsNode;
-  }
-
-  StyleSheet* SheetAt(size_t aIndex) const
-  {
-    return mStyleSheets.SafeElementAt(aIndex);
-  }
-
-  size_t SheetCount() const
-  {
-    return mStyleSheets.Length();
-  }
-
-  int32_t IndexOfSheet(const StyleSheet& aSheet) const
-  {
-    return mStyleSheets.IndexOf(&aSheet);
-  }
-
-  void InsertSheetAt(size_t aIndex, StyleSheet& aSheet)
-  {
-    mStyleSheets.InsertElementAt(aIndex, &aSheet);
-  }
-
-  void RemoveSheet(StyleSheet& aSheet)
-  {
-    mStyleSheets.RemoveElement(&aSheet);
-  }
-
-  void AppendStyleSheet(StyleSheet& aSheet)
-  {
-    mStyleSheets.AppendElement(&aSheet);
-  }
-
-  StyleSheetList& EnsureDOMStyleSheets();
-
-  Element* GetElementById(const nsAString& aElementId);
-
-  /**
-   * This method returns _all_ the elements in this scope which have id
-   * aElementId, if there are any.  Otherwise it returns null.
-   *
-   * This is useful for stuff like QuerySelector optimization and such.
-   */
-  inline const nsTArray<Element*>*
-  GetAllElementsForId(const nsAString& aElementId) const;
-
-  already_AddRefed<nsContentList>
-  GetElementsByTagName(const nsAString& aTagName)
-  {
-    return NS_GetContentList(&AsNode(), kNameSpaceID_Unknown, aTagName);
-  }
-
-  already_AddRefed<nsContentList>
-  GetElementsByTagNameNS(const nsAString& aNamespaceURI,
-                         const nsAString& aLocalName);
-
-  already_AddRefed<nsContentList>
-  GetElementsByTagNameNS(const nsAString& aNamespaceURI,
-                         const nsAString& aLocalName,
-                         mozilla::ErrorResult&);
-
-  already_AddRefed<nsContentList>
-  GetElementsByClassName(const nsAString& aClasses);
-
-  ~DocumentOrShadowRoot() = default;
-
-protected:
-  nsTArray<RefPtr<mozilla::StyleSheet>> mStyleSheets;
-  RefPtr<mozilla::dom::StyleSheetList> mDOMStyleSheets;
-
-  /*
-   * mIdentifierMap works as follows for IDs:
-   * 1) Attribute changes affect the table immediately (removing and adding
-   *    entries as needed).
-   * 2) Removals from the DOM affect the table immediately
-   * 3) Additions to the DOM always update existing entries for names, and add
-   *    new ones for IDs.
-   */
-  nsTHashtable<nsIdentifierMapEntry> mIdentifierMap;
-
-  nsINode& mAsNode;
-  const Kind mKind;
-};
-
-inline const nsTArray<Element*>*
-DocumentOrShadowRoot::GetAllElementsForId(const nsAString& aElementId) const
-{
-  if (aElementId.IsEmpty()) {
-    return nullptr;
-  }
-
-  nsIdentifierMapEntry* entry = mIdentifierMap.GetEntry(aElementId);
-  return entry ? &entry->GetIdElements() : nullptr;
-}
-
-}
-
-}
-
-#endif
--- a/dom/base/Element.h
+++ b/dom/base/Element.h
@@ -178,17 +178,16 @@ enum class CSSPseudoElementType : uint8_
 class EventChainPostVisitor;
 class EventChainPreVisitor;
 class EventChainVisitor;
 class EventListenerManager;
 class EventStateManager;
 
 namespace dom {
 
-struct CustomElementDefinition;
 class Animation;
 class CustomElementRegistry;
 class Link;
 class DOMRect;
 class DOMRectList;
 class Flex;
 class Grid;
 
--- a/dom/base/ShadowRoot.cpp
+++ b/dom/base/ShadowRoot.cpp
@@ -51,17 +51,16 @@ NS_INTERFACE_MAP_END_INHERITING(Document
 
 NS_IMPL_ADDREF_INHERITED(ShadowRoot, DocumentFragment)
 NS_IMPL_RELEASE_INHERITED(ShadowRoot, DocumentFragment)
 
 ShadowRoot::ShadowRoot(Element* aElement, bool aClosed,
                        already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo,
                        nsXBLPrototypeBinding* aProtoBinding)
   : DocumentFragment(aNodeInfo)
-  , DocumentOrShadowRoot(*this)
   , mProtoBinding(aProtoBinding)
   , mInsertionPointChanged(false)
   , mIsComposedDocParticipant(false)
 {
   SetHost(aElement);
   mMode = aClosed ? ShadowRootMode::Closed : ShadowRootMode::Open;
 
   // Nodes in a shadow tree should never store a value
@@ -213,17 +212,17 @@ ShadowRoot::InsertSheet(StyleSheet* aShe
     linkingElement = do_QueryInterface(aLinkingContent);
 
   // FIXME(emilio, bug 1410578): <link> should probably also be allowed here.
   MOZ_ASSERT(linkingElement, "The only styles in a ShadowRoot should come "
                              "from <style>.");
 
   linkingElement->SetStyleSheet(aSheet); // This sets the ownerNode on the sheet
 
-  MOZ_DIAGNOSTIC_ASSERT(mProtoBinding->SheetCount() == DocumentOrShadowRoot::SheetCount());
+  MOZ_DIAGNOSTIC_ASSERT(mProtoBinding->SheetCount() == StyleScope::SheetCount());
 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
   // FIXME(emilio, bug 1425759): For now we keep them duplicated, the proto
   // binding will disappear soon (tm).
   {
     size_t i = 0;
     for (RefPtr<StyleSheet>& sheet : mStyleSheets) {
       MOZ_DIAGNOSTIC_ASSERT(sheet.get() == mProtoBinding->StyleSheetAt(i++));
     }
@@ -251,23 +250,54 @@ ShadowRoot::InsertSheet(StyleSheet* aShe
     StyleSheetChanged();
   }
 }
 
 void
 ShadowRoot::RemoveSheet(StyleSheet* aSheet)
 {
   mProtoBinding->RemoveStyleSheet(aSheet);
-  DocumentOrShadowRoot::RemoveSheet(*aSheet);
+  StyleScope::RemoveSheet(*aSheet);
 
   if (aSheet->IsApplicable()) {
     StyleSheetChanged();
   }
 }
 
+Element*
+ShadowRoot::GetElementById(const nsAString& aElementId)
+{
+  nsIdentifierMapEntry *entry = mIdentifierMap.GetEntry(aElementId);
+  return entry ? entry->GetIdElement() : nullptr;
+}
+
+already_AddRefed<nsContentList>
+ShadowRoot::GetElementsByTagName(const nsAString& aTagName)
+{
+  return NS_GetContentList(this, kNameSpaceID_Unknown, aTagName);
+}
+
+already_AddRefed<nsContentList>
+ShadowRoot::GetElementsByTagNameNS(const nsAString& aNamespaceURI,
+                                   const nsAString& aLocalName)
+{
+  int32_t nameSpaceId = kNameSpaceID_Wildcard;
+
+  if (!aNamespaceURI.EqualsLiteral("*")) {
+    nsresult rv =
+      nsContentUtils::NameSpaceManager()->RegisterNameSpace(aNamespaceURI,
+                                                            nameSpaceId);
+    NS_ENSURE_SUCCESS(rv, nullptr);
+  }
+
+  NS_ASSERTION(nameSpaceId != kNameSpaceID_Unknown, "Unexpected namespace ID!");
+
+  return NS_GetContentList(this, nameSpaceId, aLocalName);
+}
+
 void
 ShadowRoot::AddToIdTable(Element* aElement, nsAtom* aId)
 {
   nsIdentifierMapEntry* entry = mIdentifierMap.PutEntry(aId);
   if (entry) {
     entry->AddIdElement(aElement);
   }
 }
@@ -279,16 +309,22 @@ ShadowRoot::RemoveFromIdTable(Element* a
   if (entry) {
     entry->RemoveIdElement(aElement);
     if (entry->IsEmpty()) {
       mIdentifierMap.RemoveEntry(entry);
     }
   }
 }
 
+already_AddRefed<nsContentList>
+ShadowRoot::GetElementsByClassName(const nsAString& aClasses)
+{
+  return nsContentUtils::GetElementsByClassName(this, aClasses);
+}
+
 nsresult
 ShadowRoot::GetEventTargetParent(EventChainPreVisitor& aVisitor)
 {
   aVisitor.mCanHandle = true;
   aVisitor.mRootOfClosedTree = IsClosed();
 
   // https://dom.spec.whatwg.org/#ref-for-get-the-parent%E2%91%A6
   if (!aVisitor.mEvent->mFlags.mComposed) {
--- a/dom/base/ShadowRoot.h
+++ b/dom/base/ShadowRoot.h
@@ -3,17 +3,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_dom_shadowroot_h__
 #define mozilla_dom_shadowroot_h__
 
 #include "mozilla/dom/DocumentFragment.h"
-#include "mozilla/dom/DocumentOrShadowRoot.h"
+#include "mozilla/dom/StyleScope.h"
 #include "nsCOMPtr.h"
 #include "nsCycleCollectionParticipant.h"
 #include "nsIContentInlines.h"
 #include "nsIdentifierMapEntry.h"
 #include "nsTHashtable.h"
 
 class nsAtom;
 class nsIContent;
@@ -23,17 +23,17 @@ namespace mozilla {
 
 class EventChainPreVisitor;
 
 namespace dom {
 
 class Element;
 
 class ShadowRoot final : public DocumentFragment,
-                         public DocumentOrShadowRoot,
+                         public StyleScope,
                          public nsStubMutationObserver
 {
 public:
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(ShadowRoot,
                                            DocumentFragment)
   NS_DECL_ISUPPORTS_INHERITED
 
   NS_DECL_NSIMUTATIONOBSERVER_ATTRIBUTECHANGED
@@ -51,24 +51,32 @@ public:
   {
     return mMode;
   }
   bool IsClosed() const
   {
     return mMode == ShadowRootMode::Closed;
   }
 
+  // StyleScope.
+  nsINode& AsNode() final
+  {
+    return *this;
+  }
+
   // [deprecated] Shadow DOM v0
+  void AddToIdTable(Element* aElement, nsAtom* aId);
+  void RemoveFromIdTable(Element* aElement, nsAtom* aId);
   void InsertSheet(StyleSheet* aSheet, nsIContent* aLinkingContent);
   void RemoveSheet(StyleSheet* aSheet);
   bool ApplyAuthorStyles();
   void SetApplyAuthorStyles(bool aApplyAuthorStyles);
   StyleSheetList* StyleSheets()
   {
-    return &DocumentOrShadowRoot::EnsureDOMStyleSheets();
+    return &StyleScope::EnsureDOMStyleSheets();
   }
 
   /**
    * Distributes all the explicit children of the pool host to the content
    * insertion points in this ShadowRoot.
    */
   void DistributeAllNodes();
 
@@ -110,21 +118,25 @@ public:
   void SetInsertionPointChanged() { mInsertionPointChanged = true; }
 
   void SetAssociatedBinding(nsXBLBinding* aBinding) { mAssociatedBinding = aBinding; }
 
   JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
 
   static ShadowRoot* FromNode(nsINode* aNode);
 
-  void AddToIdTable(Element* aElement, nsAtom* aId);
-  void RemoveFromIdTable(Element* aElement, nsAtom* aId);
-
   // WebIDL methods.
-  using mozilla::dom::DocumentOrShadowRoot::GetElementById;
+  Element* GetElementById(const nsAString& aElementId);
+  already_AddRefed<nsContentList>
+    GetElementsByTagName(const nsAString& aNamespaceURI);
+  already_AddRefed<nsContentList>
+    GetElementsByTagNameNS(const nsAString& aNamespaceURI,
+                           const nsAString& aLocalName);
+  already_AddRefed<nsContentList>
+    GetElementsByClassName(const nsAString& aClasses);
   void GetInnerHTML(nsAString& aInnerHTML);
   void SetInnerHTML(const nsAString& aInnerHTML, ErrorResult& aError);
   void StyleSheetChanged();
 
   bool IsComposedDocParticipant() { return mIsComposedDocParticipant; }
   void SetIsComposedDocParticipant(bool aIsComposedDocParticipant)
   {
     mIsComposedDocParticipant = aIsComposedDocParticipant;
@@ -136,16 +148,18 @@ protected:
   virtual ~ShadowRoot();
 
   ShadowRootMode mMode;
 
   // 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, nsTArray<mozilla::dom::HTMLSlotElement*>> mSlotMap;
+
+  nsTHashtable<nsIdentifierMapEntry> mIdentifierMap;
   nsXBLPrototypeBinding* mProtoBinding;
 
   // It is necessary to hold a reference to the associated nsXBLBinding
   // because the binding holds a reference on the nsXBLDocumentInfo that
   // owns |mProtoBinding|.
   RefPtr<nsXBLBinding> mAssociatedBinding;
 
   // A boolean that indicates that an insertion point was added or removed
new file mode 100644
--- /dev/null
+++ b/dom/base/StyleScope.cpp
@@ -0,0 +1,27 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "StyleScope.h"
+#include "mozilla/dom/StyleSheetList.h"
+
+namespace mozilla {
+namespace dom {
+
+StyleScope::~StyleScope()
+{
+}
+
+StyleSheetList&
+StyleScope::EnsureDOMStyleSheets()
+{
+  if (!mDOMStyleSheets) {
+    mDOMStyleSheets = new StyleSheetList(*this);
+  }
+  return *mDOMStyleSheets;
+}
+
+}
+}
new file mode 100644
--- /dev/null
+++ b/dom/base/StyleScope.h
@@ -0,0 +1,81 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_dom_StyleScope_h__
+#define mozilla_dom_StyleScope_h__
+
+#include "nsTArray.h"
+
+class nsINode;
+
+namespace mozilla {
+class StyleSheet;
+
+namespace dom {
+
+class StyleSheetList;
+
+/**
+ * A class meant to be shared by ShadowRoot and Document, that holds a list of
+ * stylesheets.
+ *
+ * TODO(emilio, bug 1418159): In the future this should hold most of the
+ * relevant style state, this should allow us to fix bug 548397.
+ */
+class StyleScope
+{
+public:
+  virtual nsINode& AsNode() = 0;
+
+  const nsINode& AsNode() const
+  {
+    return const_cast<StyleScope&>(*this).AsNode();
+  }
+
+  StyleSheet* SheetAt(size_t aIndex) const
+  {
+    return mStyleSheets.SafeElementAt(aIndex);
+  }
+
+  size_t SheetCount() const
+  {
+    return mStyleSheets.Length();
+  }
+
+  int32_t IndexOfSheet(const StyleSheet& aSheet) const
+  {
+    return mStyleSheets.IndexOf(&aSheet);
+  }
+
+  void InsertSheetAt(size_t aIndex, StyleSheet& aSheet)
+  {
+    mStyleSheets.InsertElementAt(aIndex, &aSheet);
+  }
+
+  void RemoveSheet(StyleSheet& aSheet)
+  {
+    mStyleSheets.RemoveElement(&aSheet);
+  }
+
+  void AppendStyleSheet(StyleSheet& aSheet)
+  {
+    mStyleSheets.AppendElement(&aSheet);
+  }
+
+  StyleSheetList& EnsureDOMStyleSheets();
+
+  ~StyleScope();
+
+protected:
+  nsTArray<RefPtr<mozilla::StyleSheet>> mStyleSheets;
+  RefPtr<mozilla::dom::StyleSheetList> mDOMStyleSheets;
+};
+
+}
+
+}
+
+#endif
--- a/dom/base/StyleSheetList.cpp
+++ b/dom/base/StyleSheetList.cpp
@@ -43,26 +43,26 @@ StyleSheetList::SlowItem(uint32_t aIndex
 {
   NS_IF_ADDREF(*aItem = Item(aIndex));
   return NS_OK;
 }
 
 void
 StyleSheetList::NodeWillBeDestroyed(const nsINode* aNode)
 {
-  mDocumentOrShadowRoot = nullptr;
+  mStyleScope = nullptr;
 }
 
-StyleSheetList::StyleSheetList(DocumentOrShadowRoot& aScope)
-  : mDocumentOrShadowRoot(&aScope)
+StyleSheetList::StyleSheetList(StyleScope& aScope)
+  : mStyleScope(&aScope)
 {
-  mDocumentOrShadowRoot->AsNode().AddMutationObserver(this);
+  mStyleScope->AsNode().AddMutationObserver(this);
 }
 
 StyleSheetList::~StyleSheetList()
 {
-  if (mDocumentOrShadowRoot) {
-    mDocumentOrShadowRoot->AsNode().RemoveMutationObserver(this);
+  if (mStyleScope) {
+    mStyleScope->AsNode().RemoveMutationObserver(this);
   }
 }
 
 } // namespace dom
 } // namespace mozilla
--- a/dom/base/StyleSheetList.h
+++ b/dom/base/StyleSheetList.h
@@ -2,17 +2,17 @@
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_dom_StyleSheetList_h
 #define mozilla_dom_StyleSheetList_h
 
-#include "mozilla/dom/DocumentOrShadowRoot.h"
+#include "mozilla/dom/StyleScope.h"
 #include "nsIDOMStyleSheetList.h"
 #include "nsWrapperCache.h"
 #include "nsStubDocumentObserver.h"
 
 class nsINode;
 
 namespace mozilla {
 class StyleSheet;
@@ -26,50 +26,50 @@ class StyleSheetList final : public nsID
 public:
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_AMBIGUOUS(StyleSheetList, nsIDOMStyleSheetList)
 
   NS_DECL_NSIDOMSTYLESHEETLIST
 
   NS_DECL_NSIMUTATIONOBSERVER_NODEWILLBEDESTROYED
 
-  explicit StyleSheetList(DocumentOrShadowRoot& aScope);
+  explicit StyleSheetList(StyleScope& aScope);
 
   virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override final;
 
   nsINode* GetParentObject() const
   {
-    return mDocumentOrShadowRoot ? &mDocumentOrShadowRoot->AsNode() : nullptr;
+    return mStyleScope ? &mStyleScope->AsNode() : nullptr;
   }
 
   uint32_t Length() const
   {
-    return mDocumentOrShadowRoot ? mDocumentOrShadowRoot->SheetCount() : 0;
+    return mStyleScope ? mStyleScope->SheetCount() : 0;
   }
 
   StyleSheet* IndexedGetter(uint32_t aIndex, bool& aFound) const
   {
-    if (!mDocumentOrShadowRoot) {
+    if (!mStyleScope) {
       aFound = false;
       return nullptr;
     }
 
-    StyleSheet* sheet = mDocumentOrShadowRoot->SheetAt(aIndex);
+    StyleSheet* sheet = mStyleScope->SheetAt(aIndex);
     aFound = !!sheet;
     return sheet;
   }
 
   StyleSheet* Item(uint32_t aIndex) const
   {
     bool dummy = false;
     return IndexedGetter(aIndex, dummy);
   }
 
 protected:
   virtual ~StyleSheetList();
 
-  DocumentOrShadowRoot* mDocumentOrShadowRoot; // Weak, cleared on "NodeWillBeDestroyed".
+  StyleScope* mStyleScope; // Weak, cleared on "NodeWillBeDestroyed".
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_StyleSheetList_h
--- a/dom/base/moz.build
+++ b/dom/base/moz.build
@@ -157,17 +157,16 @@ EXPORTS.mozilla.dom += [
     'ChromeNodeList.h',
     'ChromeUtils.h',
     'Comment.h',
     'CustomElementRegistry.h',
     'DirectionalityUtils.h',
     'DispatcherTrait.h',
     'DocGroup.h',
     'DocumentFragment.h',
-    'DocumentOrShadowRoot.h',
     'DocumentType.h',
     'DOMCursor.h',
     'DOMError.h',
     'DOMException.h',
     'DOMImplementation.h',
     'DOMIntersectionObserver.h',
     'DOMMatrix.h',
     'DOMParser.h',
@@ -203,16 +202,17 @@ EXPORTS.mozilla.dom += [
     'ResponsiveImageSelector.h',
     'SameProcessMessageQueue.h',
     'ScreenOrientation.h',
     'Selection.h',
     'ShadowRoot.h',
     'StructuredCloneBlob.h',
     'StructuredCloneHolder.h',
     'StructuredCloneTags.h',
+    'StyleScope.h',
     'StyleSheetList.h',
     'SubtleCrypto.h',
     'TabGroup.h',
     'Text.h',
     'Timeout.h',
     'TimeoutHandler.h',
     'TimeoutManager.h',
     'TreeWalker.h',
@@ -236,17 +236,16 @@ UNIFIED_SOURCES += [
     'ChromeUtils.cpp',
     'Comment.cpp',
     'Crypto.cpp',
     'CustomElementRegistry.cpp',
     'DirectionalityUtils.cpp',
     'DispatcherTrait.cpp',
     'DocGroup.cpp',
     'DocumentFragment.cpp',
-    'DocumentOrShadowRoot.cpp',
     'DocumentType.cpp',
     'DOMCursor.cpp',
     'DOMError.cpp',
     'DOMException.cpp',
     'DOMImplementation.cpp',
     'DOMMatrix.cpp',
     'DOMParser.cpp',
     'DOMPoint.cpp',
@@ -347,16 +346,17 @@ UNIFIED_SOURCES += [
     'ResponsiveImageSelector.cpp',
     'SameProcessMessageQueue.cpp',
     'ScreenOrientation.cpp',
     'Selection.cpp',
     'SelectionChangeListener.cpp',
     'ShadowRoot.cpp',
     'StructuredCloneBlob.cpp',
     'StructuredCloneHolder.cpp',
+    'StyleScope.cpp',
     'StyleSheetList.cpp',
     'SubtleCrypto.cpp',
     'TabGroup.cpp',
     'Text.cpp',
     'TextInputProcessor.cpp',
     'ThirdPartyUtil.cpp',
     'Timeout.cpp',
     'TimeoutBudgetManager.cpp',
--- a/dom/base/nsContentUtils.cpp
+++ b/dom/base/nsContentUtils.cpp
@@ -4103,24 +4103,16 @@ nsContentUtils::ReportToConsole(uint32_t
   }
   NS_ENSURE_SUCCESS(rv, rv);
 
   return ReportToConsoleNonLocalized(errorText, aErrorFlags, aCategory,
                                      aDocument, aURI, aSourceLine,
                                      aLineNumber, aColumnNumber);
 }
 
-/* static */ void
-nsContentUtils::ReportEmptyGetElementByIdArg(const nsIDocument* aDoc)
-{
-  ReportToConsole(nsIScriptError::warningFlag,
-                  NS_LITERAL_CSTRING("DOM"), aDoc,
-                  nsContentUtils::eDOM_PROPERTIES,
-                  "EmptyGetElementByIdParam");
-}
 
 /* static */ nsresult
 nsContentUtils::ReportToConsoleNonLocalized(const nsAString& aErrorText,
                                             uint32_t aErrorFlags,
                                             const nsACString& aCategory,
                                             const nsIDocument* aDocument,
                                             nsIURI* aURI,
                                             const nsString& aSourceLine,
--- a/dom/base/nsContentUtils.h
+++ b/dom/base/nsContentUtils.h
@@ -1085,18 +1085,16 @@ public:
                                   const char16_t **aParams = nullptr,
                                   uint32_t aParamsLength = 0,
                                   nsIURI* aURI = nullptr,
                                   const nsString& aSourceLine
                                     = EmptyString(),
                                   uint32_t aLineNumber = 0,
                                   uint32_t aColumnNumber = 0);
 
-  static void ReportEmptyGetElementByIdArg(const nsIDocument* aDoc);
-
   static void LogMessageToConsole(const char* aMsg);
 
   /**
    * Get the localized string named |aKey| in properties file |aFile|.
    */
   static nsresult GetLocalizedString(PropertiesFile aFile,
                                      const char* aKey,
                                      nsAString& aResult);
--- a/dom/base/nsDocument.cpp
+++ b/dom/base/nsDocument.cpp
@@ -380,34 +380,19 @@ private:
   bool mAsyncClassified;
   nsTArray<nsCString> mMatchedTables;
   mozilla::dom::FlashClassification mResult;
 };
 
 
 #define NAME_NOT_VALID ((nsSimpleContentList*)1)
 
-nsIdentifierMapEntry::nsIdentifierMapEntry(const nsIdentifierMapEntry::AtomOrString& aKey)
-  : mKey(aKey)
-{}
-
-nsIdentifierMapEntry::nsIdentifierMapEntry(const nsIdentifierMapEntry::AtomOrString* aKey)
-  : mKey(aKey ? *aKey : nullptr)
-{}
-
 nsIdentifierMapEntry::~nsIdentifierMapEntry()
-{}
-
-nsIdentifierMapEntry::nsIdentifierMapEntry(nsIdentifierMapEntry&& aOther)
-  : mKey(mozilla::Move(aOther.mKey))
-  , mIdContentList(mozilla::Move(aOther.mIdContentList))
-  , mNameContentList(mozilla::Move(aOther.mNameContentList))
-  , mChangeCallbacks(mozilla::Move(aOther.mChangeCallbacks))
-  , mImageElement(mozilla::Move(aOther.mImageElement))
-{}
+{
+}
 
 void
 nsIdentifierMapEntry::Traverse(nsCycleCollectionTraversalCallback* aCallback)
 {
   NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*aCallback,
                                      "mIdentifierMap mNameContentList");
   aCallback->NoteXPCOMChild(static_cast<nsIDOMNodeList*>(mNameContentList));
 
@@ -421,22 +406,16 @@ nsIdentifierMapEntry::Traverse(nsCycleCo
 
 bool
 nsIdentifierMapEntry::IsEmpty()
 {
   return mIdContentList.IsEmpty() && !mNameContentList &&
          !mChangeCallbacks && !mImageElement;
 }
 
-bool
-nsIdentifierMapEntry::HasNameElement() const
-{
-  return mNameContentList && mNameContentList->Length() != 0;
-}
-
 Element*
 nsIdentifierMapEntry::GetIdElement()
 {
   return mIdContentList.SafeElementAt(0);
 }
 
 Element*
 nsIdentifierMapEntry::GetImageIdElement()
@@ -1420,17 +1399,16 @@ struct nsIDocument::FrameRequest
 
 static already_AddRefed<mozilla::dom::NodeInfo> nullNodeInfo;
 
 // ==================================================================
 // =
 // ==================================================================
 nsIDocument::nsIDocument()
   : nsINode(nullNodeInfo),
-    DocumentOrShadowRoot(*this),
     mReferrerPolicySet(false),
     mReferrerPolicy(mozilla::net::RP_Unset),
     mBlockAllMixedContent(false),
     mBlockAllMixedContentPreloads(false),
     mUpgradeInsecureRequests(false),
     mUpgradeInsecurePreloads(false),
     mCharacterSet(WINDOWS_1252_ENCODING),
     mCharacterSetSource(0),
@@ -3848,16 +3826,22 @@ nsDocument::NodesFromRectHelper(float aX
 NS_IMETHODIMP
 nsDocument::GetElementsByClassName(const nsAString& aClasses,
                                    nsIDOMNodeList** aReturn)
 {
   *aReturn = nsIDocument::GetElementsByClassName(aClasses).take();
   return NS_OK;
 }
 
+already_AddRefed<nsContentList>
+nsIDocument::GetElementsByClassName(const nsAString& aClasses)
+{
+  return nsContentUtils::GetElementsByClassName(this, aClasses);
+}
+
 void
 nsIDocument::ReleaseCapture() const
 {
   // only release the capture if the caller can access it. This prevents a
   // page from stopping a scrollbar grab for example.
   nsCOMPtr<nsINode> node = nsIPresShell::GetCapturingContent();
   if (node && nsContentUtils::CanCallerAccess(node)) {
     nsIPresShell::SetCapturingContent(nullptr, 0);
@@ -4672,17 +4656,17 @@ nsDocument::UpdateStyleSheets(nsTArray<R
 }
 
 void
 nsDocument::InsertStyleSheetAt(StyleSheet* aSheet, size_t aIndex)
 {
   MOZ_ASSERT(aSheet);
   MOZ_DIAGNOSTIC_ASSERT(aSheet->IsServo() == IsStyledByServo());
 
-  // FIXME(emilio): Stop touching DocumentOrShadowRoot's members directly, and use an
+  // FIXME(emilio): Stop touching StyleScope's members directly, and use an
   // accessor.
   mStyleSheets.InsertElementAt(aIndex, aSheet);
 
   aSheet->SetAssociatedDocument(this, StyleSheet::OwnedByDocument);
 
   if (aSheet->IsApplicable()) {
     AddStyleSheetToStyleSets(aSheet);
   }
@@ -5387,17 +5371,42 @@ nsDocument::BeginLoad()
   }
 
   NS_DOCUMENT_NOTIFY_OBSERVERS(BeginLoad, (this));
 }
 
 void
 nsDocument::ReportEmptyGetElementByIdArg()
 {
-  nsContentUtils::ReportEmptyGetElementByIdArg(this);
+  nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
+                                  NS_LITERAL_CSTRING("DOM"), this,
+                                  nsContentUtils::eDOM_PROPERTIES,
+                                  "EmptyGetElementByIdParam");
+}
+
+Element*
+nsDocument::GetElementById(const nsAString& aElementId)
+{
+  if (!CheckGetElementByIdArg(aElementId)) {
+    return nullptr;
+  }
+
+  nsIdentifierMapEntry *entry = mIdentifierMap.GetEntry(aElementId);
+  return entry ? entry->GetIdElement() : nullptr;
+}
+
+const nsTArray<Element*>*
+nsDocument::GetAllElementsForId(const nsAString& aElementId) const
+{
+  if (aElementId.IsEmpty()) {
+    return nullptr;
+  }
+
+  nsIdentifierMapEntry *entry = mIdentifierMap.GetEntry(aElementId);
+  return entry ? &entry->GetIdElements() : nullptr;
 }
 
 NS_IMETHODIMP
 nsDocument::GetElementById(const nsAString& aId, nsIDOMElement** aReturn)
 {
   Element *content = GetElementById(aId);
   if (content) {
     return CallQueryInterface(content, aReturn);
@@ -6344,24 +6353,45 @@ nsDocument::BlockedTrackingNodes() const
     if (node) {
       list->AppendElement(node);
     }
   }
 
   return list.forget();
 }
 
+already_AddRefed<nsContentList>
+nsIDocument::GetElementsByTagNameNS(const nsAString& aNamespaceURI,
+                                    const nsAString& aLocalName,
+                                    ErrorResult& aResult)
+{
+  int32_t nameSpaceId = kNameSpaceID_Wildcard;
+
+  if (!aNamespaceURI.EqualsLiteral("*")) {
+    aResult =
+      nsContentUtils::NameSpaceManager()->RegisterNameSpace(aNamespaceURI,
+                                                            nameSpaceId);
+    if (aResult.Failed()) {
+      return nullptr;
+    }
+  }
+
+  NS_ASSERTION(nameSpaceId != kNameSpaceID_Unknown, "Unexpected namespace ID!");
+
+  return NS_GetContentList(this, nameSpaceId, aLocalName);
+}
+
 NS_IMETHODIMP
 nsDocument::GetElementsByTagNameNS(const nsAString& aNamespaceURI,
                                    const nsAString& aLocalName,
                                    nsIDOMNodeList** aReturn)
 {
   ErrorResult rv;
   RefPtr<nsContentList> list =
-    GetElementsByTagNameNS(aNamespaceURI, aLocalName, rv);
+    nsIDocument::GetElementsByTagNameNS(aNamespaceURI, aLocalName, rv);
   if (rv.Failed()) {
     return rv.StealNSResult();
   }
 
   // transfer ref to aReturn
   list.forget(aReturn);
   return NS_OK;
 }
--- a/dom/base/nsDocument.h
+++ b/dom/base/nsDocument.h
@@ -330,16 +330,17 @@ class nsDocument : public nsIDocument,
                    public nsIApplicationCacheContainer,
                    public nsStubMutationObserver,
                    public nsIDOMXPathEvaluator
 {
   friend class nsIDocument;
 
 public:
   typedef mozilla::dom::Element Element;
+  using nsIDocument::GetElementsByTagName;
   typedef mozilla::net::ReferrerPolicy ReferrerPolicy;
 
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
 
   NS_DECL_ADDSIZEOFEXCLUDINGTHIS
 
   virtual void Reset(nsIChannel *aChannel, nsILoadGroup *aLoadGroup) override;
   virtual void ResetToURI(nsIURI *aURI, nsILoadGroup *aLoadGroup,
@@ -639,21 +640,16 @@ public:
   NS_FORWARD_NSIDOMNODE_TO_NSINODE_OVERRIDABLE
 
   // nsIDOMDocument
   NS_DECL_NSIDOMDOCUMENT
 
   // nsIDOMDocumentXBL
   NS_DECL_NSIDOMDOCUMENTXBL
 
-  using mozilla::dom::DocumentOrShadowRoot::GetElementById;
-  using mozilla::dom::DocumentOrShadowRoot::GetElementsByTagName;
-  using mozilla::dom::DocumentOrShadowRoot::GetElementsByTagNameNS;
-  using mozilla::dom::DocumentOrShadowRoot::GetElementsByClassName;
-
   // nsIDOMEventTarget
   virtual nsresult GetEventTargetParent(
                      mozilla::EventChainPreVisitor& aVisitor) override;
   virtual mozilla::EventListenerManager*
     GetOrCreateListenerManager() override;
   virtual mozilla::EventListenerManager*
     GetExistingListenerManager() const override;
 
@@ -813,17 +809,20 @@ public:
   // Only BlockOnload should call this!
   void AsyncBlockOnload();
 
   virtual void SetScrollToRef(nsIURI *aDocumentURI) override;
   virtual void ScrollToRef() override;
   virtual void ResetScrolledToRefAlready() override;
   virtual void SetChangeScrollPosWhenScrollingToRef(bool aValue) override;
 
-  virtual Element* LookupImageElement(const nsAString& aElementId) override;
+  virtual Element *GetElementById(const nsAString& aElementId) override;
+  virtual const nsTArray<Element*>* GetAllElementsForId(const nsAString& aElementId) const override;
+
+  virtual Element *LookupImageElement(const nsAString& aElementId) override;
   virtual void MozSetImageElement(const nsAString& aImageElementId,
                                   Element* aElement) override;
 
   // AddPlugin adds a plugin-related element to mPlugins when the element is
   // added to the tree.
   virtual nsresult AddPlugin(nsIObjectLoadingContent* aPlugin) override;
   // RemovePlugin removes a plugin-related element to mPlugins when the
   // element is removed from the tree.
@@ -1139,16 +1138,24 @@ protected:
   // caches its result here.
   mozilla::Maybe<bool> mIsThirdParty;
 
 public:
   RefPtr<mozilla::EventListenerManager> mListenerManager;
   RefPtr<nsDOMStyleSheetSetList> mStyleSheetSetList;
   RefPtr<mozilla::dom::ScriptLoader> mScriptLoader;
   nsDocHeaderData* mHeaderData;
+  /* mIdentifierMap works as follows for IDs:
+   * 1) Attribute changes affect the table immediately (removing and adding
+   *    entries as needed).
+   * 2) Removals from the DOM affect the table immediately
+   * 3) Additions to the DOM always update existing entries for names, and add
+   *    new ones for IDs.
+   */
+  nsTHashtable<nsIdentifierMapEntry> mIdentifierMap;
 
   nsClassHashtable<nsStringHashKey, nsRadioGroupStruct> mRadioGroups;
 
   // Recorded time of change to 'loading' state.
   mozilla::TimeStamp mLoadingTimeStamp;
 
   // True if the document has been detached from its content viewer.
   bool mIsGoingAway:1;
--- a/dom/base/nsIDocument.h
+++ b/dom/base/nsIDocument.h
@@ -29,17 +29,17 @@
 #include "mozilla/UseCounter.h"
 #include "mozilla/WeakPtr.h"
 #include "Units.h"
 #include "nsContentListDeclarations.h"
 #include "nsExpirationTracker.h"
 #include "nsClassHashtable.h"
 #include "mozilla/CORSMode.h"
 #include "mozilla/dom/DispatcherTrait.h"
-#include "mozilla/dom/DocumentOrShadowRoot.h"
+#include "mozilla/dom/StyleScope.h"
 #include "mozilla/LinkedList.h"
 #include "mozilla/NotNull.h"
 #include "mozilla/SegmentedVector.h"
 #include "mozilla/ServoBindingTypes.h"
 #include "mozilla/StyleBackendType.h"
 #include "mozilla/StyleSheet.h"
 #include "mozilla/TimeStamp.h"
 #include "mozilla/UniquePtr.h"
@@ -211,17 +211,17 @@ enum class HSTSPrimingState {
 // Some function forward-declarations
 class nsContentList;
 
 //----------------------------------------------------------------------
 
 // Document interface.  This is implemented by all document objects in
 // Gecko.
 class nsIDocument : public nsINode,
-                    public mozilla::dom::DocumentOrShadowRoot,
+                    public mozilla::dom::StyleScope,
                     public mozilla::dom::DispatcherTrait
 {
   typedef mozilla::dom::GlobalObject GlobalObject;
 
 protected:
   using Encoding = mozilla::Encoding;
   template <typename T> using NotNull = mozilla::NotNull<T>;
 
@@ -567,17 +567,17 @@ public:
    * This gets fired when the element that an id refers to changes.
    * This fires at difficult times. It is generally not safe to do anything
    * which could modify the DOM in any way. Use
    * nsContentUtils::AddScriptRunner.
    * @return true to keep the callback in the callback set, false
    * to remove it.
    */
   typedef bool (* IDTargetObserver)(Element* aOldElement,
-                                    Element* aNewelement, void* aData);
+                                      Element* aNewelement, void* aData);
 
   /**
    * Add an IDTargetObserver for a specific ID. The IDTargetObserver
    * will be fired whenever the content associated with the ID changes
    * in the future. If aForImage is true, mozSetImageElement can override
    * what content is associated with the ID. In that case the IDTargetObserver
    * will be notified at those times when the result of LookupImageElement
    * changes.
@@ -1326,19 +1326,24 @@ public:
    * supplied by add-ons or by the app (Firefox OS or Firefox Mobile, for
    * example), since their sheets should override built-in sheets.
    *
    * TODO We can get rid of the whole concept of delayed loading if we fix
    * bug 77999.
    */
   virtual void EnsureOnDemandBuiltInUASheet(mozilla::StyleSheet* aSheet) = 0;
 
+  nsINode& AsNode() final
+  {
+    return *this;
+  }
+
   mozilla::dom::StyleSheetList* StyleSheets()
   {
-    return &DocumentOrShadowRoot::EnsureDOMStyleSheets();
+    return &StyleScope::EnsureDOMStyleSheets();
   }
 
   /**
    * Insert a sheet at a particular spot in the stylesheet list (zero-based)
    * @param aSheet the sheet to insert
    * @param aIndex the index to insert at.
    * @throws no exceptions
    */
@@ -2635,20 +2640,29 @@ public:
 
   virtual nsISupports* GetCurrentContentSink() = 0;
 
   virtual void SetScrollToRef(nsIURI *aDocumentURI) = 0;
   virtual void ScrollToRef() = 0;
   virtual void ResetScrolledToRefAlready() = 0;
   virtual void SetChangeScrollPosWhenScrollingToRef(bool aValue) = 0;
 
-  using mozilla::dom::DocumentOrShadowRoot::GetElementById;
-  using mozilla::dom::DocumentOrShadowRoot::GetElementsByTagName;
-  using mozilla::dom::DocumentOrShadowRoot::GetElementsByTagNameNS;
-  using mozilla::dom::DocumentOrShadowRoot::GetElementsByClassName;
+  /**
+   * This method is similar to GetElementById() from nsIDOMDocument but it
+   * returns a mozilla::dom::Element instead of a nsIDOMElement.
+   * It prevents converting nsIDOMElement to mozilla::dom::Element which is
+   * already converted from mozilla::dom::Element.
+   */
+  virtual Element* GetElementById(const nsAString& aElementId) = 0;
+
+  /**
+   * This method returns _all_ the elements in this document which
+   * have id aElementId, if there are any.  Otherwise it returns null.
+   */
+  virtual const nsTArray<Element*>* GetAllElementsForId(const nsAString& aElementId) const = 0;
 
   /**
    * Lookup an image element using its associated ID, which is usually provided
    * by |-moz-element()|. Similar to GetElementById, with the difference that
    * elements set using mozSetImageElement have higher priority.
    * @param aId the ID associated the element we want to lookup
    * @return the element associated with |aId|
    */
@@ -2835,16 +2849,28 @@ public:
     eConnected,
     eDisconnected,
     eAdopted,
     eAttributeChanged
   };
 
   nsIDocument* GetTopLevelContentDocument();
 
+  already_AddRefed<nsContentList>
+  GetElementsByTagName(const nsAString& aTagName)
+  {
+    return NS_GetContentList(this, kNameSpaceID_Unknown, aTagName);
+  }
+  already_AddRefed<nsContentList>
+    GetElementsByTagNameNS(const nsAString& aNamespaceURI,
+                           const nsAString& aLocalName,
+                           mozilla::ErrorResult& aResult);
+  already_AddRefed<nsContentList>
+    GetElementsByClassName(const nsAString& aClasses);
+  // GetElementById defined above
   virtual already_AddRefed<Element>
     CreateElement(const nsAString& aTagName,
                   const mozilla::dom::ElementCreationOptionsOrString& aOptions,
                   mozilla::ErrorResult& rv) = 0;
   virtual already_AddRefed<Element>
     CreateElementNS(const nsAString& aNamespaceURI,
                     const nsAString& aQualifiedName,
                     const mozilla::dom::ElementCreationOptionsOrString& aOptions,
--- a/dom/base/nsIdentifierMapEntry.h
+++ b/dom/base/nsIdentifierMapEntry.h
@@ -10,51 +10,43 @@
 
 #ifndef nsIdentifierMapEntry_h
 #define nsIdentifierMapEntry_h
 
 #include "PLDHashTable.h"
 
 #include "mozilla/MemoryReporting.h"
 #include "mozilla/Move.h"
+#include "mozilla/dom/Element.h"
 #include "mozilla/net/ReferrerPolicy.h"
 
 #include "nsCOMArray.h"
 #include "nsCOMPtr.h"
+#include "nsContentList.h"
 #include "nsAtom.h"
+#include "nsIDocument.h"
 #include "nsTArray.h"
 #include "nsTHashtable.h"
 
 class nsIContent;
-class nsContentList;
-class nsBaseContentList;
 
 /**
  * Right now our identifier map entries contain information for 'name'
  * and 'id' mappings of a given string. This is so that
  * nsHTMLDocument::ResolveName only has to do one hash lookup instead
  * of two. It's not clear whether this still matters for performance.
  *
  * We also store the document.all result list here. This is mainly so that
  * when all elements with the given ID are removed and we remove
  * the ID's nsIdentifierMapEntry, the document.all result is released too.
  * Perhaps the document.all results should have their own hashtable
  * in nsHTMLDocument.
  */
 class nsIdentifierMapEntry : public PLDHashEntryHdr
 {
-  typedef mozilla::dom::Element Element;
-  typedef mozilla::net::ReferrerPolicy ReferrerPolicy;
-
-  /**
-   * @see nsIDocument::IDTargetObserver, this is just here to avoid include
-   * hell.
-   */
-  typedef bool (* IDTargetObserver)(Element* aOldElement,
-                                    Element* aNewelement, void* aData);
 public:
   struct AtomOrString
   {
     MOZ_IMPLICIT AtomOrString(nsAtom* aAtom) : mAtom(aAtom) {}
     MOZ_IMPLICIT AtomOrString(const nsAString& aString) : mString(aString) {}
     AtomOrString(const AtomOrString& aOther)
       : mAtom(aOther.mAtom)
       , mString(aOther.mString)
@@ -69,19 +61,35 @@ public:
 
     RefPtr<nsAtom> mAtom;
     const nsString mString;
   };
 
   typedef const AtomOrString& KeyType;
   typedef const AtomOrString* KeyTypePointer;
 
-  explicit nsIdentifierMapEntry(const AtomOrString& aKey);
-  explicit nsIdentifierMapEntry(const AtomOrString* aKey);
-  nsIdentifierMapEntry(nsIdentifierMapEntry&& aOther);
+  typedef mozilla::dom::Element Element;
+  typedef mozilla::net::ReferrerPolicy ReferrerPolicy;
+
+  explicit nsIdentifierMapEntry(const AtomOrString& aKey)
+    : mKey(aKey)
+  {
+  }
+  explicit nsIdentifierMapEntry(const AtomOrString* aKey)
+    : mKey(aKey ? *aKey : nullptr)
+  {
+  }
+  nsIdentifierMapEntry(nsIdentifierMapEntry&& aOther) :
+    mKey(mozilla::Move(aOther.mKey)),
+    mIdContentList(mozilla::Move(aOther.mIdContentList)),
+    mNameContentList(aOther.mNameContentList.forget()),
+    mChangeCallbacks(aOther.mChangeCallbacks.forget()),
+    mImageElement(aOther.mImageElement.forget())
+  {
+  }
   ~nsIdentifierMapEntry();
 
   nsString GetKeyAsString() const
   {
     if (mKey.mAtom) {
       return nsAtomString(mKey.mAtom);
     }
 
@@ -116,17 +124,19 @@ public:
   enum { ALLOW_MEMMOVE = false };
 
   void AddNameElement(nsINode* aDocument, Element* aElement);
   void RemoveNameElement(Element* aElement);
   bool IsEmpty();
   nsBaseContentList* GetNameContentList() {
     return mNameContentList;
   }
-  bool HasNameElement() const;
+  bool HasNameElement() const {
+    return mNameContentList && mNameContentList->Length() != 0;
+  }
 
   /**
    * Returns the element if we know the element associated with this
    * id. Otherwise returns null.
    */
   Element* GetIdElement();
   /**
    * Returns the list of all elements associated with this id.
@@ -156,25 +166,25 @@ public:
   /**
    * Set the image element override for this ID. This will be returned by
    * GetIdElement(true) if non-null.
    */
   void SetImageElement(Element* aElement);
   bool HasIdElementExposedAsHTMLDocumentProperty();
 
   bool HasContentChangeCallback() { return mChangeCallbacks != nullptr; }
-  void AddContentChangeCallback(IDTargetObserver aCallback,
+  void AddContentChangeCallback(nsIDocument::IDTargetObserver aCallback,
                                 void* aData, bool aForImage);
-  void RemoveContentChangeCallback(IDTargetObserver aCallback,
+  void RemoveContentChangeCallback(nsIDocument::IDTargetObserver aCallback,
                                 void* aData, bool aForImage);
 
   void Traverse(nsCycleCollectionTraversalCallback* aCallback);
 
   struct ChangeCallback {
-    IDTargetObserver mCallback;
+    nsIDocument::IDTargetObserver mCallback;
     void* mData;
     bool mForImage;
   };
 
   struct ChangeCallbackEntry : public PLDHashEntryHdr {
     typedef const ChangeCallback KeyType;
     typedef const ChangeCallback* KeyTypePointer;
 
--- a/dom/html/nsHTMLDocument.h
+++ b/dom/html/nsHTMLDocument.h
@@ -151,17 +151,21 @@ public:
   virtual void SetMayStartLayout(bool aMayStartLayout) override;
 
   virtual nsresult SetEditingState(EditingState aState) override;
 
   virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
                          bool aPreallocateChildren) const override;
 
   virtual void RemovedFromDocShell() override;
-  using mozilla::dom::DocumentOrShadowRoot::GetElementById;
+
+  virtual mozilla::dom::Element *GetElementById(const nsAString& aElementId) override
+  {
+    return nsDocument::GetElementById(aElementId);
+  }
 
   virtual void DocAddSizeOfExcludingThis(nsWindowSizes& aWindowSizes) const override;
   // DocAddSizeOfIncludingThis is inherited from nsIDocument.
 
   virtual bool WillIgnoreCharsetOverride() override;
 
   // WebIDL API
   virtual JSObject* WrapNode(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
--- a/dom/xul/XULDocument.cpp
+++ b/dom/xul/XULDocument.cpp
@@ -1594,23 +1594,34 @@ NS_IMETHODIMP
 XULDocument::GetCommandDispatcher(nsIDOMXULCommandDispatcher** aTracker)
 {
     *aTracker = mCommandDispatcher;
     NS_IF_ADDREF(*aTracker);
     return NS_OK;
 }
 
 Element*
-XULDocument::GetRefById(const nsAString& aID)
+XULDocument::GetElementById(const nsAString& aId)
 {
-    if (nsRefMapEntry* refEntry = mRefMap.GetEntry(aID)) {
-        MOZ_ASSERT(refEntry->GetFirstElement());
+    if (!CheckGetElementByIdArg(aId))
+        return nullptr;
+
+    nsIdentifierMapEntry *entry = mIdentifierMap.GetEntry(aId);
+    if (entry) {
+        Element* element = entry->GetIdElement();
+        if (element)
+            return element;
+    }
+
+    nsRefMapEntry* refEntry = mRefMap.GetEntry(aId);
+    if (refEntry) {
+        NS_ASSERTION(refEntry->GetFirstElement(),
+                     "nsRefMapEntries should have nonempty content lists");
         return refEntry->GetFirstElement();
     }
-
     return nullptr;
 }
 
 nsresult
 XULDocument::AddElementToDocumentPre(Element* aElement)
 {
     // Do a bunch of work that's necessary when an element gets added
     // to the XUL Document.
--- a/dom/xul/XULDocument.h
+++ b/dom/xul/XULDocument.h
@@ -144,26 +144,25 @@ public:
     // nsIDOMNode interface
     NS_FORWARD_NSIDOMNODE_TO_NSINODE
 
     // nsIDOMDocument interface
     using nsDocument::CreateElement;
     using nsDocument::CreateElementNS;
     NS_FORWARD_NSIDOMDOCUMENT(XMLDocument::)
     // And explicitly import the things from nsDocument that we just shadowed
-    using mozilla::dom::DocumentOrShadowRoot::GetElementById;
     using nsDocument::GetImplementation;
     using nsDocument::GetTitle;
     using nsDocument::SetTitle;
     using nsDocument::GetLastStyleSheetSet;
     using nsDocument::MozSetImageElement;
     using nsIDocument::GetLocation;
 
-    // Helper for StyleScope::GetElementById.
-    Element* GetRefById(const nsAString & elementId);
+    // nsDocument interface overrides
+    virtual Element* GetElementById(const nsAString & elementId) override;
 
     // nsIDOMXULDocument interface
     NS_DECL_NSIDOMXULDOCUMENT
 
     // nsICSSLoaderObserver
     NS_IMETHOD StyleSheetLoaded(mozilla::StyleSheet* aSheet,
                                 bool aWasAlternate,
                                 nsresult aStatus) override;
--- a/editor/libeditor/TextEditor.cpp
+++ b/editor/libeditor/TextEditor.cpp
@@ -21,17 +21,16 @@
 #include "mozilla/dom/Event.h"
 #include "mozilla/dom/Element.h"
 #include "nsAString.h"
 #include "nsCRT.h"
 #include "nsCaret.h"
 #include "nsCharTraits.h"
 #include "nsComponentManagerUtils.h"
 #include "nsContentCID.h"
-#include "nsContentList.h"
 #include "nsCopySupport.h"
 #include "nsDebug.h"
 #include "nsDependentSubstring.h"
 #include "nsError.h"
 #include "nsGkAtoms.h"
 #include "nsIClipboard.h"
 #include "nsIContent.h"
 #include "nsIContentIterator.h"