Bug 1426494: Share more code among Document / ShadowRoot. r=smaug
authorEmilio Cobos Álvarez <emilio@crisal.io>
Wed, 20 Dec 2017 06:46:01 +0100
changeset 451553 abba86fa9a5b02a3a058f767efca7c90b3db4c0b
parent 451552 f28babf65d7277182a3ab72825e1a16641c0fee5
child 451554 d00cfb672a3ff1dd33895fa2f80f81cf715e7a82
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)
reviewerssmaug
bugs1426494
milestone59.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
Bug 1426494: Share more code among Document / ShadowRoot. r=smaug MozReview-Commit-ID: C4cJrSFPnIb
dom/base/Element.h
dom/base/ShadowRoot.cpp
dom/base/ShadowRoot.h
dom/base/StyleScope.cpp
dom/base/StyleScope.h
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
--- a/dom/base/Element.h
+++ b/dom/base/Element.h
@@ -178,16 +178,17 @@ 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
@@ -281,47 +281,16 @@ ShadowRoot::RemoveSheet(StyleSheet* aShe
   mProtoBinding->RemoveStyleSheet(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);
   }
 }
@@ -333,22 +302,16 @@ 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
@@ -52,18 +52,16 @@ public:
     return mMode;
   }
   bool IsClosed() const
   {
     return mMode == ShadowRootMode::Closed;
   }
 
   // [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 &StyleScope::EnsureDOMStyleSheets();
   }
@@ -112,25 +110,21 @@ 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.
-  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);
+  using mozilla::dom::StyleScope::GetElementById;
   void GetInnerHTML(nsAString& aInnerHTML);
   void SetInnerHTML(const nsAString& aInnerHTML, ErrorResult& aError);
   void StyleSheetChanged();
 
   bool IsComposedDocParticipant() { return mIsComposedDocParticipant; }
   void SetIsComposedDocParticipant(bool aIsComposedDocParticipant)
   {
     mIsComposedDocParticipant = aIsComposedDocParticipant;
@@ -142,18 +136,16 @@ 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
--- a/dom/base/StyleScope.cpp
+++ b/dom/base/StyleScope.cpp
@@ -1,16 +1,17 @@
 /* -*- 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"
+#include "XULDocument.h"
 
 namespace mozilla {
 namespace dom {
 
 StyleScope::StyleScope(mozilla::dom::ShadowRoot& aShadowRoot)
   : mAsNode(aShadowRoot)
   , mKind(Kind::ShadowRoot)
 {}
@@ -28,10 +29,71 @@ StyleSheetList&
 StyleScope::EnsureDOMStyleSheets()
 {
   if (!mDOMStyleSheets) {
     mDOMStyleSheets = new StyleSheetList(*this);
   }
   return *mDOMStyleSheets;
 }
 
+Element*
+StyleScope::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>
+StyleScope::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>
+StyleScope::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>
+StyleScope::GetElementsByClassName(const nsAString& aClasses)
+{
+  return nsContentUtils::GetElementsByClassName(&AsNode(), aClasses);
+}
+
 }
 }
--- a/dom/base/StyleScope.h
+++ b/dom/base/StyleScope.h
@@ -3,25 +3,28 @@
 /* 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"
+#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.
  */
@@ -73,23 +76,73 @@ public:
 
   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);
+
   ~StyleScope();
 
 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*>*
+StyleScope::GetAllElementsForId(const nsAString& aElementId) const
+{
+  if (aElementId.IsEmpty()) {
+    return nullptr;
+  }
+
+  nsIdentifierMapEntry* entry = mIdentifierMap.GetEntry(aElementId);
+  return entry ? &entry->GetIdElements() : nullptr;
+}
+
 }
 
 }
 
 #endif
--- a/dom/base/nsContentUtils.cpp
+++ b/dom/base/nsContentUtils.cpp
@@ -4103,16 +4103,24 @@ 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,16 +1085,18 @@ 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,19 +380,34 @@ 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));
 
@@ -406,16 +421,22 @@ 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()
@@ -3827,22 +3848,16 @@ 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);
@@ -5372,42 +5387,17 @@ nsDocument::BeginLoad()
   }
 
   NS_DOCUMENT_NOTIFY_OBSERVERS(BeginLoad, (this));
 }
 
 void
 nsDocument::ReportEmptyGetElementByIdArg()
 {
-  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;
+  nsContentUtils::ReportEmptyGetElementByIdArg(this);
 }
 
 NS_IMETHODIMP
 nsDocument::GetElementById(const nsAString& aId, nsIDOMElement** aReturn)
 {
   Element *content = GetElementById(aId);
   if (content) {
     return CallQueryInterface(content, aReturn);
@@ -6354,45 +6344,24 @@ 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 =
-    nsIDocument::GetElementsByTagNameNS(aNamespaceURI, aLocalName, rv);
+    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,17 +330,16 @@ 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,
@@ -640,16 +639,21 @@ public:
   NS_FORWARD_NSIDOMNODE_TO_NSINODE_OVERRIDABLE
 
   // nsIDOMDocument
   NS_DECL_NSIDOMDOCUMENT
 
   // nsIDOMDocumentXBL
   NS_DECL_NSIDOMDOCUMENTXBL
 
+  using mozilla::dom::StyleScope::GetElementById;
+  using mozilla::dom::StyleScope::GetElementsByTagName;
+  using mozilla::dom::StyleScope::GetElementsByTagNameNS;
+  using mozilla::dom::StyleScope::GetElementsByClassName;
+
   // nsIDOMEventTarget
   virtual nsresult GetEventTargetParent(
                      mozilla::EventChainPreVisitor& aVisitor) override;
   virtual mozilla::EventListenerManager*
     GetOrCreateListenerManager() override;
   virtual mozilla::EventListenerManager*
     GetExistingListenerManager() const override;
 
@@ -809,20 +813,17 @@ 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 *GetElementById(const nsAString& aElementId) override;
-  virtual const nsTArray<Element*>* GetAllElementsForId(const nsAString& aElementId) const override;
-
-  virtual Element *LookupImageElement(const nsAString& aElementId) 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.
@@ -1144,24 +1145,16 @@ 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
@@ -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.
@@ -2641,29 +2641,20 @@ 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;
 
-  /**
-   * 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;
+  using mozilla::dom::StyleScope::GetElementById;
+  using mozilla::dom::StyleScope::GetElementsByTagName;
+  using mozilla::dom::StyleScope::GetElementsByTagNameNS;
+  using mozilla::dom::StyleScope::GetElementsByClassName;
 
   /**
    * 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|
    */
@@ -2850,28 +2841,16 @@ 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,43 +10,51 @@
 
 #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)
@@ -61,35 +69,19 @@ public:
 
     RefPtr<nsAtom> mAtom;
     const nsString mString;
   };
 
   typedef const AtomOrString& KeyType;
   typedef const AtomOrString* KeyTypePointer;
 
-  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())
-  {
-  }
+  explicit nsIdentifierMapEntry(const AtomOrString& aKey);
+  explicit nsIdentifierMapEntry(const AtomOrString* aKey);
+  nsIdentifierMapEntry(nsIdentifierMapEntry&& aOther);
   ~nsIdentifierMapEntry();
 
   nsString GetKeyAsString() const
   {
     if (mKey.mAtom) {
       return nsAtomString(mKey.mAtom);
     }
 
@@ -124,19 +116,17 @@ public:
   enum { ALLOW_MEMMOVE = false };
 
   void AddNameElement(nsINode* aDocument, Element* aElement);
   void RemoveNameElement(Element* aElement);
   bool IsEmpty();
   nsBaseContentList* GetNameContentList() {
     return mNameContentList;
   }
-  bool HasNameElement() const {
-    return mNameContentList && mNameContentList->Length() != 0;
-  }
+  bool HasNameElement() const;
 
   /**
    * 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.
@@ -166,25 +156,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(nsIDocument::IDTargetObserver aCallback,
+  void AddContentChangeCallback(IDTargetObserver aCallback,
                                 void* aData, bool aForImage);
-  void RemoveContentChangeCallback(nsIDocument::IDTargetObserver aCallback,
+  void RemoveContentChangeCallback(IDTargetObserver aCallback,
                                 void* aData, bool aForImage);
 
   void Traverse(nsCycleCollectionTraversalCallback* aCallback);
 
   struct ChangeCallback {
-    nsIDocument::IDTargetObserver mCallback;
+    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,21 +151,17 @@ 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;
-
-  virtual mozilla::dom::Element *GetElementById(const nsAString& aElementId) override
-  {
-    return nsDocument::GetElementById(aElementId);
-  }
+  using mozilla::dom::StyleScope::GetElementById;
 
   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,34 +1594,23 @@ NS_IMETHODIMP
 XULDocument::GetCommandDispatcher(nsIDOMXULCommandDispatcher** aTracker)
 {
     *aTracker = mCommandDispatcher;
     NS_IF_ADDREF(*aTracker);
     return NS_OK;
 }
 
 Element*
-XULDocument::GetElementById(const nsAString& aId)
+XULDocument::GetRefById(const nsAString& aID)
 {
-    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");
+    if (nsRefMapEntry* refEntry = mRefMap.GetEntry(aID)) {
+        MOZ_ASSERT(refEntry->GetFirstElement());
         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,25 +144,26 @@ 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::StyleScope::GetElementById;
     using nsDocument::GetImplementation;
     using nsDocument::GetTitle;
     using nsDocument::SetTitle;
     using nsDocument::GetLastStyleSheetSet;
     using nsDocument::MozSetImageElement;
     using nsIDocument::GetLocation;
 
-    // nsDocument interface overrides
-    virtual Element* GetElementById(const nsAString & elementId) override;
+    // Helper for StyleScope::GetElementById.
+    Element* GetRefById(const nsAString & elementId);
 
     // 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,16 +21,17 @@
 #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"