Merge inbound to mozilla-central. a=merge
authorCiure Andrei <aciure@mozilla.com>
Fri, 04 Jan 2019 00:04:46 +0200
changeset 509562 b762378e8c7e
parent 509531 b83cac4f938a (current diff)
parent 509561 4794752b9358 (diff)
child 509583 95d275f757c3
child 509601 35b1ac7c831b
push id10547
push userffxbld-merge
push dateMon, 21 Jan 2019 13:03:58 +0000
treeherdermozilla-beta@24ec1916bffe [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone66.0a1
first release with
nightly linux32
b762378e8c7e / 66.0a1 / 20190103220533 / files
nightly linux64
b762378e8c7e / 66.0a1 / 20190103220533 / files
nightly mac
b762378e8c7e / 66.0a1 / 20190103220533 / files
nightly win32
b762378e8c7e / 66.0a1 / 20190103220533 / files
nightly win64
b762378e8c7e / 66.0a1 / 20190103220533 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge inbound to mozilla-central. a=merge
dom/base/nsDocument.cpp
dom/base/nsIDocument.h
dom/base/nsIDocumentInlines.h
layout/base/nsRefreshDriver.cpp
security/nss/gtests/common/chachapoly-vectors.h
security/nss/gtests/common/gcm-vectors.h
security/nss/gtests/common/wycheproof/header_bases/chachapoly-vectors.h
security/nss/gtests/common/wycheproof/header_bases/gcm-vectors.h
security/nss/gtests/common/wycheproof/testvectors/aes_gcm_test.json
security/nss/gtests/common/wycheproof/testvectors/chacha20_poly1305_test.json
--- a/accessible/android/DocAccessibleWrap.cpp
+++ b/accessible/android/DocAccessibleWrap.cpp
@@ -17,17 +17,17 @@
 using namespace mozilla::a11y;
 
 const uint32_t kCacheRefreshInterval = 500;
 
 ////////////////////////////////////////////////////////////////////////////////
 // DocAccessibleWrap
 ////////////////////////////////////////////////////////////////////////////////
 
-DocAccessibleWrap::DocAccessibleWrap(nsIDocument* aDocument,
+DocAccessibleWrap::DocAccessibleWrap(Document* aDocument,
                                      nsIPresShell* aPresShell)
     : DocAccessible(aDocument, aPresShell) {
   nsCOMPtr<nsIDocShellTreeItem> treeItem(aDocument->GetDocShell());
 
   nsCOMPtr<nsIDocShellTreeItem> parentTreeItem;
   treeItem->GetParent(getter_AddRefs(parentTreeItem));
 
   if (treeItem->ItemType() == nsIDocShellTreeItem::typeContent &&
--- a/accessible/android/DocAccessibleWrap.h
+++ b/accessible/android/DocAccessibleWrap.h
@@ -9,17 +9,17 @@
 #include "DocAccessible.h"
 #include "nsITimer.h"
 
 namespace mozilla {
 namespace a11y {
 
 class DocAccessibleWrap : public DocAccessible {
  public:
-  DocAccessibleWrap(nsIDocument* aDocument, nsIPresShell* aPresShell);
+  DocAccessibleWrap(Document* aDocument, nsIPresShell* aPresShell);
   virtual ~DocAccessibleWrap();
 
   virtual nsresult HandleAccEvent(AccEvent* aEvent) override;
 
   /**
    * Manage the mapping from id to Accessible.
    */
   void AddID(uint32_t aID, AccessibleWrap* aAcc) {
--- a/accessible/android/RootAccessibleWrap.cpp
+++ b/accessible/android/RootAccessibleWrap.cpp
@@ -8,17 +8,17 @@
 #include "Accessible-inl.h"
 #include "AccessibleOrProxy.h"
 #include "DocAccessibleParent.h"
 #include "ProxyAccessibleWrap.h"
 #include "SessionAccessibility.h"
 
 using namespace mozilla::a11y;
 
-RootAccessibleWrap::RootAccessibleWrap(nsIDocument* aDoc,
+RootAccessibleWrap::RootAccessibleWrap(mozilla::dom::Document* aDoc,
                                        nsIPresShell* aPresShell)
     : RootAccessible(aDoc, aPresShell) {}
 
 RootAccessibleWrap::~RootAccessibleWrap() {}
 
 AccessibleWrap* RootAccessibleWrap::GetContentAccessible() {
   if (ProxyAccessible* proxy = GetPrimaryRemoteTopLevelContentDoc()) {
     return WrapperFor(proxy);
--- a/accessible/android/RootAccessibleWrap.h
+++ b/accessible/android/RootAccessibleWrap.h
@@ -10,17 +10,17 @@
 
 namespace mozilla {
 namespace a11y {
 
 class DocProxyAccessibleWrap;
 
 class RootAccessibleWrap : public RootAccessible {
  public:
-  RootAccessibleWrap(nsIDocument* aDocument, nsIPresShell* aPresShell);
+  RootAccessibleWrap(dom::Document* aDocument, nsIPresShell* aPresShell);
   virtual ~RootAccessibleWrap();
 
   AccessibleWrap* GetContentAccessible();
 
   AccessibleWrap* FindAccessibleById(int32_t aID);
 
   // Recursively searches for the accessible ID within the document tree.
   AccessibleWrap* FindAccessibleById(DocAccessibleWrap* aDocument, int32_t aID);
--- a/accessible/atk/DocAccessibleWrap.cpp
+++ b/accessible/atk/DocAccessibleWrap.cpp
@@ -8,13 +8,13 @@
 #include "DocAccessibleWrap.h"
 
 using namespace mozilla::a11y;
 
 ////////////////////////////////////////////////////////////////////////////////
 // DocAccessibleWrap
 ////////////////////////////////////////////////////////////////////////////////
 
-DocAccessibleWrap::DocAccessibleWrap(nsIDocument* aDocument,
+DocAccessibleWrap::DocAccessibleWrap(dom::Document* aDocument,
                                      nsIPresShell* aPresShell)
     : DocAccessible(aDocument, aPresShell), mActivated(false) {}
 
 DocAccessibleWrap::~DocAccessibleWrap() {}
--- a/accessible/atk/DocAccessibleWrap.h
+++ b/accessible/atk/DocAccessibleWrap.h
@@ -13,17 +13,17 @@
 
 #include "DocAccessible.h"
 
 namespace mozilla {
 namespace a11y {
 
 class DocAccessibleWrap : public DocAccessible {
  public:
-  DocAccessibleWrap(nsIDocument* aDocument, nsIPresShell* aPresShell);
+  DocAccessibleWrap(dom::Document* aDocument, nsIPresShell* aPresShell);
   virtual ~DocAccessibleWrap();
 
   bool mActivated;
 };
 
 }  // namespace a11y
 }  // namespace mozilla
 
--- a/accessible/base/DocManager.cpp
+++ b/accessible/base/DocManager.cpp
@@ -47,17 +47,17 @@ nsRefPtrHashtable<nsPtrHashKey<const Doc
 // DocManager
 ////////////////////////////////////////////////////////////////////////////////
 
 DocManager::DocManager() : mDocAccessibleCache(2), mXPCDocumentCache(0) {}
 
 ////////////////////////////////////////////////////////////////////////////////
 // DocManager public
 
-DocAccessible* DocManager::GetDocAccessible(nsIDocument* aDocument) {
+DocAccessible* DocManager::GetDocAccessible(Document* aDocument) {
   if (!aDocument) return nullptr;
 
   DocAccessible* docAcc = GetExistingDocAccessible(aDocument);
   if (docAcc) return docAcc;
 
   return CreateDocOrRootAccessible(aDocument);
 }
 
@@ -85,17 +85,17 @@ void DocManager::RemoveFromXPCDocumentCa
 
     if (!HasXPCDocuments()) {
       MaybeShutdownAccService(nsAccessibilityService::eXPCOM);
     }
   }
 }
 
 void DocManager::NotifyOfDocumentShutdown(DocAccessible* aDocument,
-                                          nsIDocument* aDOMDocument) {
+                                          Document* aDOMDocument) {
   // We need to remove listeners in both cases, when document is being shutdown
   // or when accessibility service is being shut down as well.
   RemoveListeners(aDOMDocument);
 
   // Document will already be removed when accessibility service is shutting
   // down so we do not need to remove it twice.
   if (nsAccessibilityService::IsShutdown()) {
     return;
@@ -213,17 +213,17 @@ DocManager::OnStateChange(nsIWebProgress
 
   nsCOMPtr<mozIDOMWindowProxy> DOMWindow;
   aWebProgress->GetDOMWindow(getter_AddRefs(DOMWindow));
   NS_ENSURE_STATE(DOMWindow);
 
   nsPIDOMWindowOuter* piWindow = nsPIDOMWindowOuter::From(DOMWindow);
   MOZ_ASSERT(piWindow);
 
-  nsCOMPtr<nsIDocument> document = piWindow->GetDoc();
+  nsCOMPtr<Document> document = piWindow->GetDoc();
   NS_ENSURE_STATE(document);
 
   // Document was loaded.
   if (aStateFlags & STATE_STOP) {
 #ifdef A11Y_LOG
     if (logging::IsEnabled(logging::eDocLoad))
       logging::DocLoad("document loaded", aWebProgress, aRequest, aStateFlags);
 #endif
@@ -311,17 +311,17 @@ DocManager::OnSecurityChange(nsIWebProgr
 ////////////////////////////////////////////////////////////////////////////////
 // nsIDOMEventListener
 
 NS_IMETHODIMP
 DocManager::HandleEvent(Event* aEvent) {
   nsAutoString type;
   aEvent->GetType(type);
 
-  nsCOMPtr<nsIDocument> document = do_QueryInterface(aEvent->GetTarget());
+  nsCOMPtr<Document> document = do_QueryInterface(aEvent->GetTarget());
   NS_ASSERTION(document, "pagehide or DOMContentLoaded for non document!");
   if (!document) return NS_OK;
 
   if (type.EqualsLiteral("pagehide")) {
     // 'pagehide' event is registered on every DOM document we create an
     // accessible for, process the event for the target. This document
     // accessible and all its sub document accessible are shutdown as result of
     // processing.
@@ -356,30 +356,30 @@ DocManager::HandleEvent(Event* aEvent) {
   }
 
   return NS_OK;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // DocManager private
 
-void DocManager::HandleDOMDocumentLoad(nsIDocument* aDocument,
+void DocManager::HandleDOMDocumentLoad(Document* aDocument,
                                        uint32_t aLoadEventType) {
   // Document accessible can be created before we were notified the DOM document
   // was loaded completely. However if it's not created yet then create it.
   DocAccessible* docAcc = GetExistingDocAccessible(aDocument);
   if (!docAcc) {
     docAcc = CreateDocOrRootAccessible(aDocument);
     if (!docAcc) return;
   }
 
   docAcc->NotifyOfLoad(aLoadEventType);
 }
 
-void DocManager::AddListeners(nsIDocument* aDocument,
+void DocManager::AddListeners(Document* aDocument,
                               bool aAddDOMContentLoadedListener) {
   nsPIDOMWindowOuter* window = aDocument->GetWindow();
   EventTarget* target = window->GetChromeEventHandler();
   EventListenerManager* elm = target->GetOrCreateListenerManager();
   elm->AddEventListenerByType(this, NS_LITERAL_STRING("pagehide"),
                               TrustedEventsAtCapture());
 
 #ifdef A11Y_LOG
@@ -392,32 +392,32 @@ void DocManager::AddListeners(nsIDocumen
                                 TrustedEventsAtCapture());
 #ifdef A11Y_LOG
     if (logging::IsEnabled(logging::eDocCreate))
       logging::Text("added 'DOMContentLoaded' listener");
 #endif
   }
 }
 
-void DocManager::RemoveListeners(nsIDocument* aDocument) {
+void DocManager::RemoveListeners(Document* aDocument) {
   nsPIDOMWindowOuter* window = aDocument->GetWindow();
   if (!window) return;
 
   EventTarget* target = window->GetChromeEventHandler();
   if (!target) return;
 
   EventListenerManager* elm = target->GetOrCreateListenerManager();
   elm->RemoveEventListenerByType(this, NS_LITERAL_STRING("pagehide"),
                                  TrustedEventsAtCapture());
 
   elm->RemoveEventListenerByType(this, NS_LITERAL_STRING("DOMContentLoaded"),
                                  TrustedEventsAtCapture());
 }
 
-DocAccessible* DocManager::CreateDocOrRootAccessible(nsIDocument* aDocument) {
+DocAccessible* DocManager::CreateDocOrRootAccessible(Document* aDocument) {
   // Ignore hidden documents, resource documents, static clone
   // (printing) documents and documents without a docshell.
   if (!aDocument->IsVisibleConsideringAncestors() ||
       aDocument->IsResourceDoc() || aDocument->IsStaticDocument() ||
       !aDocument->IsActive()) {
     return nullptr;
   }
 
--- a/accessible/base/DocManager.h
+++ b/accessible/base/DocManager.h
@@ -1,17 +1,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_a11_DocManager_h_
 #define mozilla_a11_DocManager_h_
 
 #include "mozilla/ClearOnShutdown.h"
-#include "nsIDocument.h"
+#include "mozilla/dom/Document.h"
 #include "nsIDOMEventListener.h"
 #include "nsRefPtrHashtable.h"
 #include "nsIWebProgressListener.h"
 #include "nsWeakReference.h"
 #include "nsIPresShell.h"
 #include "mozilla/StaticPtr.h"
 
 namespace mozilla {
@@ -31,17 +31,17 @@ class DocManager : public nsIWebProgress
  public:
   NS_DECL_THREADSAFE_ISUPPORTS
   NS_DECL_NSIWEBPROGRESSLISTENER
   NS_DECL_NSIDOMEVENTLISTENER
 
   /**
    * Return document accessible for the given DOM node.
    */
-  DocAccessible* GetDocAccessible(nsIDocument* aDocument);
+  DocAccessible* GetDocAccessible(dom::Document* aDocument);
 
   /**
    * Return document accessible for the given presshell.
    */
   DocAccessible* GetDocAccessible(const nsIPresShell* aPresShell) {
     if (!aPresShell) return nullptr;
 
     DocAccessible* doc = aPresShell->GetDocAccessible();
@@ -55,17 +55,17 @@ class DocManager : public nsIWebProgress
    * unique id.
    */
   Accessible* FindAccessibleInCache(nsINode* aNode) const;
 
   /**
    * Called by document accessible when it gets shutdown.
    */
   void NotifyOfDocumentShutdown(DocAccessible* aDocument,
-                                nsIDocument* aDOMDocument);
+                                dom::Document* aDOMDocument);
 
   void RemoveFromXPCDocumentCache(DocAccessible* aDocument);
 
   /**
    * Return XPCOM accessible document.
    */
   xpcAccessibleDocument* GetXPCDocument(DocAccessible* aDocument);
   xpcAccessibleDocument* GetCachedXPCDocument(DocAccessible* aDocument) const {
@@ -137,35 +137,35 @@ class DocManager : public nsIWebProgress
   /**
    * Create an accessible document if it was't created and fire accessibility
    * events if needed.
    *
    * @param  aDocument       [in] loaded DOM document
    * @param  aLoadEventType  [in] specifies the event type to fire load event,
    *                           if 0 then no event is fired
    */
-  void HandleDOMDocumentLoad(nsIDocument* aDocument, uint32_t aLoadEventType);
+  void HandleDOMDocumentLoad(dom::Document* aDocument, uint32_t aLoadEventType);
 
   /**
    * Add/remove 'pagehide' and 'DOMContentLoaded' event listeners.
    */
-  void AddListeners(nsIDocument* aDocument, bool aAddPageShowListener);
-  void RemoveListeners(nsIDocument* aDocument);
+  void AddListeners(dom::Document* aDocument, bool aAddPageShowListener);
+  void RemoveListeners(dom::Document* aDocument);
 
   /**
    * Create document or root accessible.
    */
-  DocAccessible* CreateDocOrRootAccessible(nsIDocument* aDocument);
+  DocAccessible* CreateDocOrRootAccessible(dom::Document* aDocument);
 
   /**
    * Clear the cache and shutdown the document accessibles.
    */
   void ClearDocCache();
 
-  typedef nsRefPtrHashtable<nsPtrHashKey<const nsIDocument>, DocAccessible>
+  typedef nsRefPtrHashtable<nsPtrHashKey<const dom::Document>, DocAccessible>
       DocAccessibleHashtable;
   DocAccessibleHashtable mDocAccessibleCache;
 
   typedef nsRefPtrHashtable<nsPtrHashKey<const DocAccessible>,
                             xpcAccessibleDocument>
       XPCDocumentHashtable;
   XPCDocumentHashtable mXPCDocumentCache;
   static nsRefPtrHashtable<nsPtrHashKey<const DocAccessibleParent>,
@@ -177,17 +177,17 @@ class DocManager : public nsIWebProgress
   static StaticAutoPtr<nsTArray<DocAccessibleParent*>> sRemoteDocuments;
 };
 
 /**
  * Return the existing document accessible for the document if any.
  * Note this returns the doc accessible for the primary pres shell if there is
  * more than one.
  */
-inline DocAccessible* GetExistingDocAccessible(const nsIDocument* aDocument) {
+inline DocAccessible* GetExistingDocAccessible(const dom::Document* aDocument) {
   nsIPresShell* ps = aDocument->GetShell();
   return ps ? ps->GetDocAccessible() : nullptr;
 }
 
 }  // namespace a11y
 }  // namespace mozilla
 
 #endif  // mozilla_a11_DocManager_h_
--- a/accessible/base/FocusManager.cpp
+++ b/accessible/base/FocusManager.cpp
@@ -129,17 +129,17 @@ void FocusManager::NotifyOfDOMBlur(nsISu
 #endif
 
   mActiveItem = nullptr;
 
   // If DOM document stays focused then fire accessible focus event to process
   // the case when no element within this DOM document will be focused.
   nsCOMPtr<nsINode> targetNode(do_QueryInterface(aTarget));
   if (targetNode && targetNode->OwnerDoc() == FocusedDOMDocument()) {
-    nsIDocument* DOMDoc = targetNode->OwnerDoc();
+    dom::Document* DOMDoc = targetNode->OwnerDoc();
     DocAccessible* document = GetAccService()->GetDocAccessible(DOMDoc);
     if (document) {
       // Clear selection listener for previously focused element.
       if (targetNode->IsElement())
         SelectionMgr()->ClearControlSelectionListener();
 
       document->HandleNotification<FocusManager, nsINode>(
           this, &FocusManager::ProcessDOMFocus, DOMDoc);
@@ -371,15 +371,15 @@ nsINode* FocusManager::FocusedDOMNode() 
     return focusedElm;
   }
 
   // Otherwise the focus can be on DOM document.
   nsPIDOMWindowOuter* focusedWnd = DOMFocusManager->GetFocusedWindow();
   return focusedWnd ? focusedWnd->GetExtantDoc() : nullptr;
 }
 
-nsIDocument* FocusManager::FocusedDOMDocument() const {
+dom::Document* FocusManager::FocusedDOMDocument() const {
   nsINode* focusedNode = FocusedDOMNode();
   return focusedNode ? focusedNode->OwnerDoc() : nullptr;
 }
 
 }  // namespace a11y
 }  // namespace mozilla
--- a/accessible/base/FocusManager.h
+++ b/accessible/base/FocusManager.h
@@ -3,20 +3,23 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_a11y_FocusManager_h_
 #define mozilla_a11y_FocusManager_h_
 
 #include "mozilla/RefPtr.h"
 
 class nsINode;
-class nsIDocument;
 class nsISupports;
 
 namespace mozilla {
+namespace dom {
+class Document;
+}
+
 namespace a11y {
 
 class AccEvent;
 class Accessible;
 class DocAccessible;
 
 /**
  * Manage the accessible focus. Used to fire and process accessible events.
@@ -112,17 +115,17 @@ class FocusManager {
 
  private:
   FocusManager(const FocusManager&);
   FocusManager& operator=(const FocusManager&);
 
   /**
    * Return DOM document having DOM focus.
    */
-  nsIDocument* FocusedDOMDocument() const;
+  dom::Document* FocusedDOMDocument() const;
 
  private:
   RefPtr<Accessible> mActiveItem;
   RefPtr<Accessible> mActiveARIAMenubar;
 };
 
 }  // namespace a11y
 }  // namespace mozilla
--- a/accessible/base/Logging.cpp
+++ b/accessible/base/Logging.cpp
@@ -77,21 +77,21 @@ static void EnableLogging(const char* aM
       }
     }
     token += tokenLen;
 
     if (*token == ',') token++;  // skip ',' char
   }
 }
 
-static void LogDocURI(nsIDocument* aDocumentNode) {
+static void LogDocURI(dom::Document* aDocumentNode) {
   printf("uri: %s", aDocumentNode->GetDocumentURI()->GetSpecOrDefault().get());
 }
 
-static void LogDocShellState(nsIDocument* aDocumentNode) {
+static void LogDocShellState(dom::Document* aDocumentNode) {
   printf("docshell busy: ");
 
   nsAutoCString docShellBusy;
   nsCOMPtr<nsIDocShell> docShell = aDocumentNode->GetDocShell();
   nsIDocShell::BusyFlags busyFlags = nsIDocShell::BUSY_FLAGS_NONE;
   docShell->GetBusyFlags(&busyFlags);
   if (busyFlags == nsIDocShell::BUSY_FLAGS_NONE) {
     printf("'none'");
@@ -102,52 +102,52 @@ static void LogDocShellState(nsIDocument
   if (busyFlags & nsIDocShell::BUSY_FLAGS_BEFORE_PAGE_LOAD) {
     printf(", 'before page load'");
   }
   if (busyFlags & nsIDocShell::BUSY_FLAGS_PAGE_LOADING) {
     printf(", 'page loading'");
   }
 }
 
-static void LogDocType(nsIDocument* aDocumentNode) {
+static void LogDocType(dom::Document* aDocumentNode) {
   if (aDocumentNode->IsActive()) {
     bool isContent = nsCoreUtils::IsContentDocument(aDocumentNode);
     printf("%s document", (isContent ? "content" : "chrome"));
   } else {
     printf("document type: [failed]");
   }
 }
 
-static void LogDocShellTree(nsIDocument* aDocumentNode) {
+static void LogDocShellTree(dom::Document* aDocumentNode) {
   if (aDocumentNode->IsActive()) {
     nsCOMPtr<nsIDocShellTreeItem> treeItem(aDocumentNode->GetDocShell());
     nsCOMPtr<nsIDocShellTreeItem> parentTreeItem;
     treeItem->GetParent(getter_AddRefs(parentTreeItem));
     nsCOMPtr<nsIDocShellTreeItem> rootTreeItem;
     treeItem->GetRootTreeItem(getter_AddRefs(rootTreeItem));
     printf("docshell hierarchy, parent: %p, root: %p, is tab document: %s;",
            static_cast<void*>(parentTreeItem), static_cast<void*>(rootTreeItem),
            (nsCoreUtils::IsTabDocument(aDocumentNode) ? "yes" : "no"));
   }
 }
 
-static void LogDocState(nsIDocument* aDocumentNode) {
+static void LogDocState(dom::Document* aDocumentNode) {
   const char* docState = nullptr;
-  nsIDocument::ReadyState docStateFlag = aDocumentNode->GetReadyStateEnum();
+  dom::Document::ReadyState docStateFlag = aDocumentNode->GetReadyStateEnum();
   switch (docStateFlag) {
-    case nsIDocument::READYSTATE_UNINITIALIZED:
+    case dom::Document::READYSTATE_UNINITIALIZED:
       docState = "uninitialized";
       break;
-    case nsIDocument::READYSTATE_LOADING:
+    case dom::Document::READYSTATE_LOADING:
       docState = "loading";
       break;
-    case nsIDocument::READYSTATE_INTERACTIVE:
+    case dom::Document::READYSTATE_INTERACTIVE:
       docState = "interactive";
       break;
-    case nsIDocument::READYSTATE_COMPLETE:
+    case dom::Document::READYSTATE_COMPLETE:
       docState = "complete";
       break;
   }
 
   printf("doc state: %s", docState);
   printf(", %sinitial", aDocumentNode->IsInitialDocument() ? "" : "not ");
   printf(", %sshowing", aDocumentNode->IsShowing() ? "" : "not ");
   printf(", %svisible", aDocumentNode->IsVisible() ? "" : "not ");
@@ -158,46 +158,46 @@ static void LogDocState(nsIDocument* aDo
 
   dom::Element* rootEl = aDocumentNode->GetBodyElement();
   if (!rootEl) {
     rootEl = aDocumentNode->GetRootElement();
   }
   printf(", has %srole content", rootEl ? "" : "no ");
 }
 
-static void LogPresShell(nsIDocument* aDocumentNode) {
+static void LogPresShell(dom::Document* aDocumentNode) {
   nsIPresShell* ps = aDocumentNode->GetShell();
   printf("presshell: %p", static_cast<void*>(ps));
 
   nsIScrollableFrame* sf = nullptr;
   if (ps) {
     printf(", is %s destroying", (ps->IsDestroying() ? "" : "not"));
     sf = ps->GetRootScrollFrameAsScrollable();
   }
   printf(", root scroll frame: %p", static_cast<void*>(sf));
 }
 
-static void LogDocLoadGroup(nsIDocument* aDocumentNode) {
+static void LogDocLoadGroup(dom::Document* aDocumentNode) {
   nsCOMPtr<nsILoadGroup> loadGroup = aDocumentNode->GetDocumentLoadGroup();
   printf("load group: %p", static_cast<void*>(loadGroup));
 }
 
-static void LogDocParent(nsIDocument* aDocumentNode) {
-  nsIDocument* parentDoc = aDocumentNode->GetParentDocument();
+static void LogDocParent(dom::Document* aDocumentNode) {
+  dom::Document* parentDoc = aDocumentNode->GetParentDocument();
   printf("parent DOM document: %p", static_cast<void*>(parentDoc));
   if (parentDoc) {
     printf(", parent acc document: %p",
            static_cast<void*>(GetExistingDocAccessible(parentDoc)));
     printf("\n    parent ");
     LogDocURI(parentDoc);
     printf("\n");
   }
 }
 
-static void LogDocInfo(nsIDocument* aDocumentNode, DocAccessible* aDocument) {
+static void LogDocInfo(dom::Document* aDocumentNode, DocAccessible* aDocument) {
   printf("    DOM document: %p, acc document: %p\n    ",
          static_cast<void*>(aDocumentNode), static_cast<void*>(aDocument));
 
   // log document info
   if (aDocumentNode) {
     LogDocURI(aDocumentNode);
     printf("\n    ");
     LogDocShellState(aDocumentNode);
@@ -365,17 +365,17 @@ void logging::DocLoad(const char* aMsg, 
   nsCOMPtr<mozIDOMWindowProxy> DOMWindow;
   aWebProgress->GetDOMWindow(getter_AddRefs(DOMWindow));
   nsPIDOMWindowOuter* window = nsPIDOMWindowOuter::From(DOMWindow);
   if (!window) {
     MsgEnd();
     return;
   }
 
-  nsCOMPtr<nsIDocument> documentNode = window->GetDoc();
+  nsCOMPtr<dom::Document> documentNode = window->GetDoc();
   if (!documentNode) {
     MsgEnd();
     return;
   }
 
   DocAccessible* document = GetExistingDocAccessible(documentNode);
 
   LogDocInfo(documentNode, document);
@@ -389,17 +389,17 @@ void logging::DocLoad(const char* aMsg, 
   printf("    state flags: %x", aStateFlags);
   bool isDocLoading;
   aWebProgress->GetIsLoadingDocument(&isDocLoading);
   printf(", document is %sloading\n", (isDocLoading ? "" : "not "));
 
   MsgEnd();
 }
 
-void logging::DocLoad(const char* aMsg, nsIDocument* aDocumentNode) {
+void logging::DocLoad(const char* aMsg, dom::Document* aDocumentNode) {
   MsgBegin(sDocLoadTitle, "%s", aMsg);
 
   DocAccessible* document = GetExistingDocAccessible(aDocumentNode);
   LogDocInfo(aDocumentNode, document);
 
   MsgEnd();
 }
 
@@ -439,27 +439,27 @@ void logging::DocLoadEventHandled(AccEve
   MsgBegin(sDocEventTitle, "handled '%s' event", strEventType.get());
 
   DocAccessible* document = aEvent->GetAccessible()->AsDoc();
   if (document) LogDocInfo(document->DocumentNode(), document);
 
   MsgEnd();
 }
 
-void logging::DocCreate(const char* aMsg, nsIDocument* aDocumentNode,
+void logging::DocCreate(const char* aMsg, dom::Document* aDocumentNode,
                         DocAccessible* aDocument) {
   DocAccessible* document =
       aDocument ? aDocument : GetExistingDocAccessible(aDocumentNode);
 
   MsgBegin(sDocCreateTitle, "%s", aMsg);
   LogDocInfo(aDocumentNode, document);
   MsgEnd();
 }
 
-void logging::DocDestroy(const char* aMsg, nsIDocument* aDocumentNode,
+void logging::DocDestroy(const char* aMsg, dom::Document* aDocumentNode,
                          DocAccessible* aDocument) {
   DocAccessible* document =
       aDocument ? aDocument : GetExistingDocAccessible(aDocumentNode);
 
   MsgBegin(sDocDestroyTitle, "%s", aMsg);
   LogDocInfo(aDocumentNode, document);
   MsgEnd();
 }
@@ -708,17 +708,17 @@ void logging::Text(const char* aText) { 
 
 void logging::Address(const char* aDescr, Accessible* aAcc) {
   if (!aAcc->IsDoc()) {
     printf("    %s accessible: %p, node: %p\n", aDescr,
            static_cast<void*>(aAcc), static_cast<void*>(aAcc->GetNode()));
   }
 
   DocAccessible* doc = aAcc->Document();
-  nsIDocument* docNode = doc->DocumentNode();
+  dom::Document* docNode = doc->DocumentNode();
   printf("    document: %p, node: %p\n", static_cast<void*>(doc),
          static_cast<void*>(docNode));
 
   printf("    ");
   LogDocURI(docNode);
   printf("\n");
 }
 
--- a/accessible/base/Logging.h
+++ b/accessible/base/Logging.h
@@ -6,25 +6,25 @@
 
 #ifndef mozilla_a11y_logs_h__
 #define mozilla_a11y_logs_h__
 
 #include "nscore.h"
 #include "nsStringFwd.h"
 #include "mozilla/Attributes.h"
 
-class nsIDocument;
 class nsINode;
 class nsIRequest;
 class nsISupports;
 class nsIWebProgress;
 
 namespace mozilla {
 
 namespace dom {
+class Document;
 class Selection;
 }  // namespace dom
 
 namespace a11y {
 
 class AccEvent;
 class Accessible;
 class DocAccessible;
@@ -69,39 +69,39 @@ bool IsEnabledAll(uint32_t aModules);
  */
 bool IsEnabled(const nsAString& aModules);
 
 /**
  * Log the document loading progress.
  */
 void DocLoad(const char* aMsg, nsIWebProgress* aWebProgress,
              nsIRequest* aRequest, uint32_t aStateFlags);
-void DocLoad(const char* aMsg, nsIDocument* aDocumentNode);
+void DocLoad(const char* aMsg, dom::Document* aDocumentNode);
 void DocCompleteLoad(DocAccessible* aDocument, bool aIsLoadEventTarget);
 
 /**
  * Log that document load event was fired.
  */
 void DocLoadEventFired(AccEvent* aEvent);
 
 /**
  * Log that document laod event was handled.
  */
 void DocLoadEventHandled(AccEvent* aEvent);
 
 /**
  * Log the document was created.
  */
-void DocCreate(const char* aMsg, nsIDocument* aDocumentNode,
+void DocCreate(const char* aMsg, dom::Document* aDocumentNode,
                DocAccessible* aDocument = nullptr);
 
 /**
  * Log the document was destroyed.
  */
-void DocDestroy(const char* aMsg, nsIDocument* aDocumentNode,
+void DocDestroy(const char* aMsg, dom::Document* aDocumentNode,
                 DocAccessible* aDocument = nullptr);
 
 /**
  * Log the outer document was destroyed.
  */
 void OuterDocDestroy(OuterDocAccessible* OuterDoc);
 
 /**
--- a/accessible/base/SelectionManager.cpp
+++ b/accessible/base/SelectionManager.cpp
@@ -10,17 +10,17 @@
 #include "HyperTextAccessible-inl.h"
 #include "nsAccessibilityService.h"
 #include "nsAccUtils.h"
 #include "nsCoreUtils.h"
 #include "nsEventShell.h"
 #include "nsFrameSelection.h"
 
 #include "nsIAccessibleTypes.h"
-#include "nsIDocument.h"
+#include "mozilla/dom/Document.h"
 #include "nsIPresShell.h"
 #include "mozilla/dom/Selection.h"
 #include "mozilla/dom/Element.h"
 
 using namespace mozilla;
 using namespace mozilla::a11y;
 using mozilla::dom::Selection;
 
@@ -133,17 +133,17 @@ void SelectionManager::ProcessTextSelCha
   if (mCaretOffset != -1) {
     RefPtr<AccCaretMoveEvent> caretMoveEvent =
         new AccCaretMoveEvent(caretCntr, mCaretOffset, aEvent->FromUserInput());
     nsEventShell::FireEvent(caretMoveEvent);
   }
 }
 
 NS_IMETHODIMP
-SelectionManager::NotifySelectionChanged(nsIDocument* aDocument,
+SelectionManager::NotifySelectionChanged(dom::Document* aDocument,
                                          Selection* aSelection,
                                          int16_t aReason) {
   if (NS_WARN_IF(!aDocument) || NS_WARN_IF(!aSelection)) {
     return NS_ERROR_INVALID_ARG;
   }
 
   DocAccessible* document = GetAccService()->GetDocAccessible(aDocument);
 
--- a/accessible/base/nsAccUtils.cpp
+++ b/accessible/base/nsAccUtils.cpp
@@ -444,17 +444,17 @@ bool nsAccUtils::IsARIALive(const Access
   // Get computed aria-live property based on the closest container with the
   // attribute. Inner nodes override outer nodes within the same
   // document, but nodes in outer documents override nodes in inner documents.
   // This should be the same as the container-live attribute, but we don't need
   // the other container-* attributes, so we can't use the same function.
   nsAutoString live;
   nsIContent* startContent = aAccessible->GetContent();
   while (startContent) {
-    nsIDocument* doc = startContent->GetComposedDoc();
+    dom::Document* doc = startContent->GetComposedDoc();
     if (!doc) {
       break;
     }
 
     dom::Element* aTopEl = doc->GetRootElement();
     nsIContent* ancestor = startContent;
     while (ancestor) {
       nsAutoString docLive;
@@ -490,17 +490,17 @@ bool nsAccUtils::IsARIALive(const Access
     }
 
     nsCOMPtr<nsIDocShellTreeItem> sameTypeParent;
     docShellTreeItem->GetSameTypeParent(getter_AddRefs(sameTypeParent));
     if (!sameTypeParent || sameTypeParent == docShellTreeItem) {
       break;
     }
 
-    nsIDocument* parentDoc = doc->GetParentDocument();
+    dom::Document* parentDoc = doc->GetParentDocument();
     if (!parentDoc) {
       break;
     }
 
     startContent = parentDoc->FindContentForSubDocument(doc);
   }
 
   return !live.IsEmpty() && !live.EqualsLiteral("off");
--- a/accessible/base/nsAccessibilityService.cpp
+++ b/accessible/base/nsAccessibilityService.cpp
@@ -277,17 +277,17 @@ nsAccessibilityService::ListenersChanged
       continue;
     }
 
     uint32_t changeCount;
     change->GetCountOfEventListenerChangesAffectingAccessibility(&changeCount);
     NS_ENSURE_SUCCESS(rv, rv);
 
     for (uint32_t i = 0; i < changeCount; i++) {
-      nsIDocument* ownerDoc = node->OwnerDoc();
+      Document* ownerDoc = node->OwnerDoc();
       DocAccessible* document = GetExistingDocAccessible(ownerDoc);
 
       // Create an accessible for a inaccessible element having click event
       // handler.
       if (document && !document->HasAccessible(node) &&
           nsCoreUtils::HasClickListener(node)) {
         document->ContentInserted(node, node->GetNextSibling());
         break;
@@ -313,32 +313,32 @@ nsAccessibilityService::Observe(nsISuppo
   if (!nsCRT::strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID)) {
     Shutdown();
   }
 
   return NS_OK;
 }
 
 void nsAccessibilityService::NotifyOfAnchorJumpTo(nsIContent* aTargetNode) {
-  nsIDocument* documentNode = aTargetNode->GetUncomposedDoc();
+  Document* documentNode = aTargetNode->GetUncomposedDoc();
   if (documentNode) {
     DocAccessible* document = GetDocAccessible(documentNode);
     if (document) document->SetAnchorJump(aTargetNode);
   }
 }
 
 void nsAccessibilityService::FireAccessibleEvent(uint32_t aEvent,
                                                  Accessible* aTarget) {
   nsEventShell::FireEvent(aEvent, aTarget);
 }
 
 Accessible* nsAccessibilityService::GetRootDocumentAccessible(
     nsIPresShell* aPresShell, bool aCanCreate) {
   nsIPresShell* ps = aPresShell;
-  nsIDocument* documentNode = aPresShell->GetDocument();
+  Document* documentNode = aPresShell->GetDocument();
   if (documentNode) {
     nsCOMPtr<nsIDocShellTreeItem> treeItem(documentNode->GetDocShell());
     if (treeItem) {
       nsCOMPtr<nsIDocShellTreeItem> rootTreeItem;
       treeItem->GetRootTreeItem(getter_AddRefs(rootTreeItem));
       if (treeItem != rootTreeItem) {
         nsCOMPtr<nsIDocShell> docShell(do_QueryInterface(rootTreeItem));
         ps = docShell->GetPresShell();
--- a/accessible/base/nsCoreUtils.cpp
+++ b/accessible/base/nsCoreUtils.cpp
@@ -4,17 +4,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsCoreUtils.h"
 
 #include "nsIAccessibleTypes.h"
 
 #include "nsIBaseWindow.h"
 #include "nsIDocShellTreeOwner.h"
-#include "nsIDocument.h"
+#include "mozilla/dom/Document.h"
 #include "nsRange.h"
 #include "nsIBoxObject.h"
 #include "nsXULElement.h"
 #include "mozilla/dom/BoxObject.h"
 #include "nsIDocShell.h"
 #include "nsIObserverService.h"
 #include "nsIPresShell.h"
 #include "nsPresContext.h"
@@ -65,17 +65,17 @@ bool nsCoreUtils::HasClickListener(nsICo
 
 void nsCoreUtils::DispatchClickEvent(nsITreeBoxObject *aTreeBoxObj,
                                      int32_t aRowIndex, nsTreeColumn *aColumn,
                                      const nsAString &aPseudoElt) {
   RefPtr<dom::Element> tcElm;
   aTreeBoxObj->GetTreeBody(getter_AddRefs(tcElm));
   if (!tcElm) return;
 
-  nsIDocument *document = tcElm->GetUncomposedDoc();
+  Document *document = tcElm->GetUncomposedDoc();
   if (!document) return;
 
   nsCOMPtr<nsIPresShell> presShell = document->GetShell();
   if (!presShell) return;
 
   // Ensure row is visible.
   aTreeBoxObj->EnsureRowIsVisible(aRowIndex);
 
@@ -335,50 +335,50 @@ nsIntPoint nsCoreUtils::GetScreenCoordsF
 
 already_AddRefed<nsIDocShell> nsCoreUtils::GetDocShellFor(nsINode *aNode) {
   if (!aNode) return nullptr;
 
   nsCOMPtr<nsIDocShell> docShell = aNode->OwnerDoc()->GetDocShell();
   return docShell.forget();
 }
 
-bool nsCoreUtils::IsRootDocument(nsIDocument *aDocument) {
+bool nsCoreUtils::IsRootDocument(Document *aDocument) {
   nsCOMPtr<nsIDocShellTreeItem> docShellTreeItem = aDocument->GetDocShell();
   NS_ASSERTION(docShellTreeItem, "No document shell for document!");
 
   nsCOMPtr<nsIDocShellTreeItem> parentTreeItem;
   docShellTreeItem->GetParent(getter_AddRefs(parentTreeItem));
 
   return !parentTreeItem;
 }
 
-bool nsCoreUtils::IsContentDocument(nsIDocument *aDocument) {
+bool nsCoreUtils::IsContentDocument(Document *aDocument) {
   nsCOMPtr<nsIDocShellTreeItem> docShellTreeItem = aDocument->GetDocShell();
   NS_ASSERTION(docShellTreeItem, "No document shell tree item for document!");
 
   return (docShellTreeItem->ItemType() == nsIDocShellTreeItem::typeContent);
 }
 
-bool nsCoreUtils::IsTabDocument(nsIDocument *aDocumentNode) {
+bool nsCoreUtils::IsTabDocument(Document *aDocumentNode) {
   nsCOMPtr<nsIDocShellTreeItem> treeItem(aDocumentNode->GetDocShell());
 
   nsCOMPtr<nsIDocShellTreeItem> parentTreeItem;
   treeItem->GetParent(getter_AddRefs(parentTreeItem));
 
   // Tab document running in own process doesn't have parent.
   if (XRE_IsContentProcess()) return !parentTreeItem;
 
   // Parent of docshell for tab document running in chrome process is root.
   nsCOMPtr<nsIDocShellTreeItem> rootTreeItem;
   treeItem->GetRootTreeItem(getter_AddRefs(rootTreeItem));
 
   return parentTreeItem == rootTreeItem;
 }
 
-bool nsCoreUtils::IsErrorPage(nsIDocument *aDocument) {
+bool nsCoreUtils::IsErrorPage(Document *aDocument) {
   nsIURI *uri = aDocument->GetDocumentURI();
   bool isAboutScheme = false;
   uri->SchemeIs("about", &isAboutScheme);
   if (!isAboutScheme) return false;
 
   nsAutoCString path;
   uri->GetPathQueryRef(path);
 
--- a/accessible/base/nsCoreUtils.h
+++ b/accessible/base/nsCoreUtils.h
@@ -5,17 +5,17 @@
 
 #ifndef nsCoreUtils_h_
 #define nsCoreUtils_h_
 
 #include "mozilla/EventForwards.h"
 #include "mozilla/dom/Element.h"
 #include "nsIAccessibleEvent.h"
 #include "nsIContent.h"
-#include "nsIDocument.h"  // for GetShell()
+#include "mozilla/dom/Document.h"  // for GetShell()
 #include "nsIPresShell.h"
 
 #include "nsPoint.h"
 #include "nsTArray.h"
 
 class nsRange;
 class nsTreeColumn;
 class nsIBoxObject;
@@ -24,16 +24,18 @@ class nsIDocShell;
 class nsITreeBoxObject;
 class nsIWidget;
 
 /**
  * Core utils.
  */
 class nsCoreUtils {
  public:
+  typedef mozilla::dom::Document Document;
+
   /**
    * Return true if the given node is a label of a control.
    */
   static bool IsLabelWithControl(nsIContent *aContent);
 
   /**
    * Return true if the given node has registered click, mousedown or mouseup
    * event listeners.
@@ -180,32 +182,32 @@ class nsCoreUtils {
   /**
    * Return document shell for the given DOM node.
    */
   static already_AddRefed<nsIDocShell> GetDocShellFor(nsINode *aNode);
 
   /**
    * Return true if the given document is root document.
    */
-  static bool IsRootDocument(nsIDocument *aDocument);
+  static bool IsRootDocument(Document *aDocument);
 
   /**
    * Return true if the given document is content document (not chrome).
    */
-  static bool IsContentDocument(nsIDocument *aDocument);
+  static bool IsContentDocument(Document *aDocument);
 
   /**
    * Return true if the given document node is for tab document accessible.
    */
-  static bool IsTabDocument(nsIDocument *aDocumentNode);
+  static bool IsTabDocument(Document *aDocumentNode);
 
   /**
    * Return true if the given document is an error page.
    */
-  static bool IsErrorPage(nsIDocument *aDocument);
+  static bool IsErrorPage(Document *aDocument);
 
   /**
    * Return presShell for the document containing the given DOM node.
    */
   static nsIPresShell *GetPresShellFor(nsINode *aNode) {
     return aNode->OwnerDoc()->GetShell();
   }
 
--- a/accessible/generic/Accessible.cpp
+++ b/accessible/generic/Accessible.cpp
@@ -32,17 +32,17 @@
 #include "XULDocument.h"
 
 #include "nsIDOMXULButtonElement.h"
 #include "nsIDOMXULSelectCntrlEl.h"
 #include "nsIDOMXULSelectCntrlItemEl.h"
 #include "nsINodeList.h"
 #include "nsPIDOMWindow.h"
 
-#include "nsIDocument.h"
+#include "mozilla/dom/Document.h"
 #include "nsIContent.h"
 #include "nsIForm.h"
 #include "nsIFormControl.h"
 
 #include "nsDeckFrame.h"
 #include "nsLayoutUtils.h"
 #include "nsIPresShell.h"
 #include "nsIStringBundle.h"
@@ -260,17 +260,17 @@ KeyBinding Accessible::AccessKey() const
       return KeyBinding(key, KeyBinding::kAlt);
     case dom::KeyboardEvent_Binding::DOM_VK_META:
       return KeyBinding(key, KeyBinding::kMeta);
     default:
       return KeyBinding();
   }
 
   // Determine the access modifier used in this context.
-  nsIDocument* document = mContent->GetUncomposedDoc();
+  dom::Document* document = mContent->GetUncomposedDoc();
   if (!document) return KeyBinding();
 
   nsCOMPtr<nsIDocShellTreeItem> treeItem(document->GetDocShell());
   if (!treeItem) return KeyBinding();
 
   nsresult rv = NS_ERROR_FAILURE;
   int32_t modifierMask = 0;
   switch (treeItem->ItemType()) {
@@ -1020,31 +1020,31 @@ already_AddRefed<nsIPersistentProperties
   // Get container-foo computed live region properties based on the closest
   // container with the live region attribute. Inner nodes override outer nodes
   // within the same document. The inner nodes can be used to override live
   // region behavior on more general outer nodes. However, nodes in outer
   // documents override nodes in inner documents: outer doc author may want to
   // override properties on a widget they used in an iframe.
   nsIContent* startContent = mContent;
   while (startContent) {
-    nsIDocument* doc = startContent->GetComposedDoc();
+    dom::Document* doc = startContent->GetComposedDoc();
     if (!doc) break;
 
     nsAccUtils::SetLiveContainerAttributes(attributes, startContent,
                                            doc->GetRootElement());
 
     // Allow ARIA live region markup from outer documents to override
     nsCOMPtr<nsIDocShellTreeItem> docShellTreeItem = doc->GetDocShell();
     if (!docShellTreeItem) break;
 
     nsCOMPtr<nsIDocShellTreeItem> sameTypeParent;
     docShellTreeItem->GetSameTypeParent(getter_AddRefs(sameTypeParent));
     if (!sameTypeParent || sameTypeParent == docShellTreeItem) break;
 
-    nsIDocument* parentDoc = doc->GetParentDocument();
+    dom::Document* parentDoc = doc->GetParentDocument();
     if (!parentDoc) break;
 
     startContent = parentDoc->FindContentForSubDocument(doc);
   }
 
   if (!mContent->IsElement()) return attributes.forget();
 
   nsAutoString id;
@@ -1682,17 +1682,17 @@ Relation Accessible::RelationByType(Rela
           if (form) {
             nsCOMPtr<nsIContent> formContent =
                 do_QueryInterface(form->GetDefaultSubmitElement());
             return Relation(mDoc, formContent);
           }
         }
       } else {
         // In XUL, use first <button default="true" .../> in the document
-        nsIDocument* doc = mContent->OwnerDoc();
+        dom::Document* doc = mContent->OwnerDoc();
         nsIContent* buttonEl = nullptr;
         if (doc->IsXULDocument()) {
           dom::XULDocument* xulDoc = doc->AsXULDocument();
           nsCOMPtr<nsIHTMLCollection> possibleDefaultButtons =
               xulDoc->GetElementsByAttribute(NS_LITERAL_STRING("default"),
                                              NS_LITERAL_STRING("true"));
           if (possibleDefaultButtons) {
             uint32_t length = possibleDefaultButtons->Length();
@@ -2388,17 +2388,17 @@ Accessible* Accessible::CurrentItem() co
   // Check for aria-activedescendant, which changes which element has focus.
   // For activedescendant, the ARIA spec does not require that the user agent
   // checks whether pointed node is actually a DOM descendant of the element
   // with the aria-activedescendant attribute.
   nsAutoString id;
   if (HasOwnContent() && mContent->IsElement() &&
       mContent->AsElement()->GetAttr(kNameSpaceID_None,
                                      nsGkAtoms::aria_activedescendant, id)) {
-    nsIDocument* DOMDoc = mContent->OwnerDoc();
+    dom::Document* DOMDoc = mContent->OwnerDoc();
     dom::Element* activeDescendantElm = DOMDoc->GetElementById(id);
     if (activeDescendantElm) {
       DocAccessible* document = Document();
       if (document) return document->GetAccessible(activeDescendantElm);
     }
   }
   return nullptr;
 }
--- a/accessible/generic/ApplicationAccessible.cpp
+++ b/accessible/generic/ApplicationAccessible.cpp
@@ -120,19 +120,17 @@ void ApplicationAccessible::Init() {
 
   if (!windowsById) {
     return;
   }
 
   for (auto iter = windowsById->Iter(); !iter.Done(); iter.Next()) {
     nsGlobalWindowOuter* window = iter.Data();
     if (window->GetDocShell() && window->IsRootOuterWindow()) {
-      nsCOMPtr<nsIDocument> docNode = window->GetExtantDoc();
-
-      if (docNode) {
+      if (RefPtr<dom::Document> docNode = window->GetExtantDoc()) {
         GetAccService()->GetDocAccessible(docNode);  // ensure creation
       }
     }
   }
 }
 
 Accessible* ApplicationAccessible::GetSiblingAtOffset(int32_t aOffset,
                                                       nsresult* aError) const {
--- a/accessible/generic/DocAccessible-inl.h
+++ b/accessible/generic/DocAccessible-inl.h
@@ -8,17 +8,17 @@
 #define mozilla_a11y_DocAccessible_inl_h_
 
 #include "DocAccessible.h"
 #include "nsAccessibilityService.h"
 #include "nsAccessiblePivot.h"
 #include "NotificationController.h"
 #include "States.h"
 #include "nsIScrollableFrame.h"
-#include "nsIDocumentInlines.h"
+#include "mozilla/dom/DocumentInlines.h"
 
 #ifdef A11Y_LOG
 #include "Logging.h"
 #endif
 
 namespace mozilla {
 namespace a11y {
 
--- a/accessible/generic/DocAccessible.cpp
+++ b/accessible/generic/DocAccessible.cpp
@@ -18,17 +18,17 @@
 #include "RootAccessible.h"
 #include "TreeWalker.h"
 #include "xpcAccessibleDocument.h"
 
 #include "nsContentUtils.h"
 #include "nsIMutableArray.h"
 #include "nsICommandManager.h"
 #include "nsIDocShell.h"
-#include "nsIDocument.h"
+#include "mozilla/dom/Document.h"
 #include "nsPIDOMWindow.h"
 #include "nsIEditingSession.h"
 #include "nsIFrame.h"
 #include "nsIInterfaceRequestorUtils.h"
 #include "nsImageFrame.h"
 #include "nsIPersistentProperties2.h"
 #include "nsIPresShell.h"
 #include "nsIServiceManager.h"
@@ -65,17 +65,17 @@ static nsStaticAtom* const kRelationAttr
                                                nsGkAtoms::_for,
                                                nsGkAtoms::control};
 
 static const uint32_t kRelationAttrsLen = ArrayLength(kRelationAttrs);
 
 ////////////////////////////////////////////////////////////////////////////////
 // Constructor/desctructor
 
-DocAccessible::DocAccessible(nsIDocument* aDocument, nsIPresShell* aPresShell)
+DocAccessible::DocAccessible(dom::Document* aDocument, nsIPresShell* aPresShell)
     :  // XXX don't pass a document to the Accessible constructor so that we
        // don't set mDoc until our vtable is fully setup.  If we set mDoc before
        // setting up the vtable we will call Accessible::AddRef() but not the
        // overrides of it for subclasses.  It is important to call those
        // overrides to avoid confusing leak checking machinary.
       HyperTextAccessibleWrap(nullptr, nullptr),
       // XXX aaronl should we use an algorithm for the initial cache size?
       mAccessibleCache(kDefaultCacheLength),
@@ -367,17 +367,17 @@ void DocAccessible::Init() {
 #endif
 
   // Initialize notification controller.
   mNotificationController = new NotificationController(this, mPresShell);
 
   // Mark the document accessible as loaded if its DOM document was loaded at
   // this point (this can happen because a11y is started late or DOM document
   // having no container was loaded.
-  if (mDocumentNode->GetReadyStateEnum() == nsIDocument::READYSTATE_COMPLETE)
+  if (mDocumentNode->GetReadyStateEnum() == dom::Document::READYSTATE_COMPLETE)
     mLoadState |= eDOMLoaded;
 
   AddEventListeners();
 }
 
 void DocAccessible::Shutdown() {
   if (!mPresShell)  // already shutdown
     return;
@@ -456,18 +456,18 @@ nsIFrame* DocAccessible::GetFrame() cons
 
   return root;
 }
 
 // DocAccessible protected member
 nsRect DocAccessible::RelativeBounds(nsIFrame** aRelativeFrame) const {
   *aRelativeFrame = GetFrame();
 
-  nsIDocument* document = mDocumentNode;
-  nsIDocument* parentDoc = nullptr;
+  dom::Document* document = mDocumentNode;
+  dom::Document* parentDoc = nullptr;
 
   nsRect bounds;
   while (document) {
     nsIPresShell* presShell = document->GetShell();
     if (!presShell) return nsRect();
 
     nsRect scrollPort;
     nsIScrollableFrame* sf = presShell->GetRootScrollFrameAsScrollable();
@@ -1015,17 +1015,17 @@ void DocAccessible::ARIAActiveDescendant
                                         aAccessible);
     }
 #endif
   }
 }
 
 void DocAccessible::ContentAppended(nsIContent* aFirstNewContent) {}
 
-void DocAccessible::ContentStateChanged(nsIDocument* aDocument,
+void DocAccessible::ContentStateChanged(dom::Document* aDocument,
                                         nsIContent* aContent,
                                         EventStates aStateMask) {
   Accessible* accessible = GetAccessible(aContent);
   if (!accessible) return;
 
   if (aStateMask.HasState(NS_EVENT_STATE_CHECKED)) {
     Accessible* widget = accessible->ContainerWidget();
     if (widget && widget->IsSelect()) {
@@ -1053,17 +1053,17 @@ void DocAccessible::ContentStateChanged(
 
   if (aStateMask.HasState(NS_EVENT_STATE_VISITED)) {
     RefPtr<AccEvent> event =
         new AccStateChangeEvent(accessible, states::TRAVERSED, true);
     FireDelayedEvent(event);
   }
 }
 
-void DocAccessible::DocumentStatesChanged(nsIDocument* aDocument,
+void DocAccessible::DocumentStatesChanged(dom::Document* aDocument,
                                           EventStates aStateMask) {}
 
 void DocAccessible::CharacterDataWillChange(nsIContent* aContent,
                                             const CharacterDataChangeInfo&) {}
 
 void DocAccessible::CharacterDataChanged(nsIContent* aContent,
                                          const CharacterDataChangeInfo&) {}
 
--- a/accessible/generic/DocAccessible.h
+++ b/accessible/generic/DocAccessible.h
@@ -9,31 +9,35 @@
 #include "nsIAccessiblePivot.h"
 
 #include "HyperTextAccessibleWrap.h"
 #include "AccEvent.h"
 
 #include "nsAutoPtr.h"
 #include "nsClassHashtable.h"
 #include "nsDataHashtable.h"
-#include "nsIDocument.h"
+#include "mozilla/dom/Document.h"
 #include "nsIDocumentObserver.h"
 #include "nsIObserver.h"
 #include "nsIScrollPositionListener.h"
 #include "nsITimer.h"
 #include "nsIWeakReference.h"
 
 class nsAccessiblePivot;
 
 const uint32_t kDefaultCacheLength = 128;
 
 namespace mozilla {
 
 class TextEditor;
 
+namespace dom {
+class Document;
+}
+
 namespace a11y {
 
 class DocManager;
 class NotificationController;
 class DocAccessibleChild;
 class RelatedAccIterator;
 template <class Class, class... Args>
 class TNotification;
@@ -45,32 +49,35 @@ class DocAccessible : public HyperTextAc
                       public nsSupportsWeakReference,
                       public nsIAccessiblePivotObserver {
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(DocAccessible, Accessible)
 
   NS_DECL_NSIOBSERVER
   NS_DECL_NSIACCESSIBLEPIVOTOBSERVER
 
+ protected:
+  typedef mozilla::dom::Document Document;
+
  public:
-  DocAccessible(nsIDocument* aDocument, nsIPresShell* aPresShell);
+  DocAccessible(Document* aDocument, nsIPresShell* aPresShell);
 
   // nsIScrollPositionListener
   virtual void ScrollPositionWillChange(nscoord aX, nscoord aY) override {}
   virtual void ScrollPositionDidChange(nscoord aX, nscoord aY) override;
 
   // nsIDocumentObserver
   NS_DECL_NSIDOCUMENTOBSERVER
 
   // Accessible
   virtual void Init();
   virtual void Shutdown() override;
   virtual nsIFrame* GetFrame() const override;
   virtual nsINode* GetNode() const override { return mDocumentNode; }
-  nsIDocument* DocumentNode() const { return mDocumentNode; }
+  Document* DocumentNode() const { return mDocumentNode; }
 
   virtual mozilla::a11y::ENameValueFlag Name(nsString& aName) const override;
   virtual void Description(nsString& aDescription) override;
   virtual Accessible* FocusedChild() override;
   virtual mozilla::a11y::role NativeRole() const override;
   virtual uint64_t NativeState() const override;
   virtual uint64_t NativeInteractiveState() const override;
   virtual bool NativelyUnavailable() const override;
@@ -128,17 +135,17 @@ class DocAccessible : public HyperTextAc
   nsPresContext* PresContext() const { return mPresShell->GetPresContext(); }
 
   /**
    * Return true if associated DOM document was loaded and isn't unloading.
    */
   bool IsContentLoaded() const {
     // eDOMLoaded flag check is used for error pages as workaround to make this
     // method return correct result since error pages do not receive 'pageshow'
-    // event and as consequence nsIDocument::IsShowing() returns false.
+    // event and as consequence Document::IsShowing() returns false.
     return mDocumentNode && mDocumentNode->IsVisible() &&
            (mDocumentNode->IsShowing() || HasLoadState(eDOMLoaded));
   }
 
   bool IsHidden() const { return mDocumentNode->Hidden(); }
 
   /**
    * Document load states.
@@ -591,17 +598,17 @@ class DocAccessible : public HyperTextAc
 
   /**
    * Cache of accessibles within this document accessible.
    */
   AccessibleHashtable mAccessibleCache;
   nsDataHashtable<nsPtrHashKey<const nsINode>, Accessible*>
       mNodeToAccessibleMap;
 
-  nsIDocument* mDocumentNode;
+  Document* mDocumentNode;
   nsCOMPtr<nsITimer> mScrollWatchTimer;
   uint16_t mScrollPositionChangedTicks;  // Used for tracking scroll events
   TimeStamp mLastScrollingDispatch;
 
   /**
    * Bit mask of document load states (@see LoadState).
    */
   uint32_t mLoadState : 3;
--- a/accessible/generic/HyperTextAccessible.cpp
+++ b/accessible/generic/HyperTextAccessible.cpp
@@ -1233,17 +1233,17 @@ already_AddRefed<TextEditor> HyperTextAc
     return nullptr;
   }
 
   nsCOMPtr<nsIDocShell> docShell = nsCoreUtils::GetDocShellFor(mContent);
   nsCOMPtr<nsIEditingSession> editingSession;
   docShell->GetEditingSession(getter_AddRefs(editingSession));
   if (!editingSession) return nullptr;  // No editing session interface
 
-  nsIDocument* docNode = mDoc->DocumentNode();
+  dom::Document* docNode = mDoc->DocumentNode();
   RefPtr<HTMLEditor> htmlEditor =
       editingSession->GetHTMLEditorForWindow(docNode->GetWindow());
   return htmlEditor.forget();
 }
 
 /**
  * =================== Caret & Selection ======================
  */
@@ -1283,17 +1283,17 @@ nsresult HyperTextAccessible::SetSelecti
   // When selection is done, move the focus to the selection if accessible is
   // not focusable. That happens when selection is set within hypertext
   // accessible.
   if (isFocusable) return NS_OK;
 
   nsFocusManager* DOMFocusManager = nsFocusManager::GetFocusManager();
   if (DOMFocusManager) {
     NS_ENSURE_TRUE(mDoc, NS_ERROR_FAILURE);
-    nsIDocument* docNode = mDoc->DocumentNode();
+    dom::Document* docNode = mDoc->DocumentNode();
     NS_ENSURE_TRUE(docNode, NS_ERROR_FAILURE);
     nsCOMPtr<nsPIDOMWindowOuter> window = docNode->GetWindow();
     RefPtr<dom::Element> result;
     DOMFocusManager->MoveFocus(
         window, nullptr, nsIFocusManager::MOVEFOCUS_CARET,
         nsIFocusManager::FLAG_BYMOVEFOCUS, getter_AddRefs(result));
   }
 
--- a/accessible/generic/ImageAccessible.cpp
+++ b/accessible/generic/ImageAccessible.cpp
@@ -8,17 +8,17 @@
 #include "nsAccUtils.h"
 #include "Role.h"
 #include "AccIterator.h"
 #include "States.h"
 
 #include "imgIContainer.h"
 #include "imgIRequest.h"
 #include "nsGenericHTMLElement.h"
-#include "nsIDocument.h"
+#include "mozilla/dom/Document.h"
 #include "nsIImageLoadingContent.h"
 #include "nsIPresShell.h"
 #include "nsIServiceManager.h"
 #include "nsIPersistentProperties2.h"
 #include "nsPIDOMWindow.h"
 #include "nsIURI.h"
 
 using namespace mozilla::a11y;
@@ -101,17 +101,17 @@ bool ImageAccessible::DoAction(uint8_t a
 
   nsCOMPtr<nsIURI> uri = GetLongDescURI();
   if (!uri) return false;
 
   nsAutoCString utf8spec;
   uri->GetSpec(utf8spec);
   NS_ConvertUTF8toUTF16 spec(utf8spec);
 
-  nsIDocument* document = mContent->OwnerDoc();
+  dom::Document* document = mContent->OwnerDoc();
   nsCOMPtr<nsPIDOMWindowOuter> piWindow = document->GetWindow();
   if (!piWindow) return false;
 
   nsCOMPtr<nsPIDOMWindowOuter> tmp;
   return NS_SUCCEEDED(piWindow->Open(spec, EmptyString(), EmptyString(),
                                      /* aLoadInfo = */ nullptr,
                                      /* aForceNoOpener = */ false,
                                      getter_AddRefs(tmp)));
--- a/accessible/generic/OuterDocAccessible.cpp
+++ b/accessible/generic/OuterDocAccessible.cpp
@@ -32,19 +32,19 @@ OuterDocAccessible::OuterDocAccessible(n
 #ifdef XP_WIN
   if (DocAccessibleParent* remoteDoc = RemoteChildDoc()) {
     remoteDoc->SendParentCOMProxy();
   }
 #endif
 
   // Request document accessible for the content document to make sure it's
   // created. It will appended to outerdoc accessible children asynchronously.
-  nsIDocument* outerDoc = mContent->GetUncomposedDoc();
+  dom::Document* outerDoc = mContent->GetUncomposedDoc();
   if (outerDoc) {
-    nsIDocument* innerDoc = outerDoc->GetSubDocumentFor(mContent);
+    dom::Document* innerDoc = outerDoc->GetSubDocumentFor(mContent);
     if (innerDoc) GetAccService()->GetDocAccessible(innerDoc);
   }
 }
 
 OuterDocAccessible::~OuterDocAccessible() {}
 
 ////////////////////////////////////////////////////////////////////////////////
 // Accessible public (DON'T add methods here)
--- a/accessible/generic/RootAccessible.cpp
+++ b/accessible/generic/RootAccessible.cpp
@@ -27,17 +27,17 @@
 #include "mozilla/dom/Element.h"
 #include "mozilla/dom/ScriptSettings.h"
 
 #include "nsIDocShellTreeItem.h"
 #include "nsIDocShellTreeOwner.h"
 #include "mozilla/dom/Event.h"
 #include "mozilla/dom/EventTarget.h"
 #include "nsIDOMXULMultSelectCntrlEl.h"
-#include "nsIDocument.h"
+#include "mozilla/dom/Document.h"
 #include "nsIInterfaceRequestorUtils.h"
 #include "nsIPropertyBag2.h"
 #include "nsIServiceManager.h"
 #include "nsPIDOMWindow.h"
 #include "nsIWebBrowserChrome.h"
 #include "nsReadableUtils.h"
 #include "nsFocusManager.h"
 #include "nsGlobalWindow.h"
@@ -53,17 +53,17 @@ using namespace mozilla::dom;
 ////////////////////////////////////////////////////////////////////////////////
 // nsISupports
 
 NS_IMPL_ISUPPORTS_INHERITED(RootAccessible, DocAccessible, nsIDOMEventListener)
 
 ////////////////////////////////////////////////////////////////////////////////
 // Constructor/destructor
 
-RootAccessible::RootAccessible(nsIDocument* aDocument, nsIPresShell* aPresShell)
+RootAccessible::RootAccessible(Document* aDocument, nsIPresShell* aPresShell)
     : DocAccessibleWrap(aDocument, aPresShell) {
   mType = eRootType;
 }
 
 RootAccessible::~RootAccessible() {}
 
 ////////////////////////////////////////////////////////////////////////////////
 // Accessible
@@ -443,17 +443,17 @@ void RootAccessible::Shutdown() {
 Relation RootAccessible::RelationByType(RelationType aType) const {
   if (!mDocumentNode || aType != RelationType::EMBEDS)
     return DocAccessibleWrap::RelationByType(aType);
 
   if (nsPIDOMWindowOuter* rootWindow = mDocumentNode->GetWindow()) {
     nsCOMPtr<nsPIDOMWindowOuter> contentWindow =
         nsGlobalWindowOuter::Cast(rootWindow)->GetContent();
     if (contentWindow) {
-      nsCOMPtr<nsIDocument> contentDocumentNode = contentWindow->GetDoc();
+      RefPtr<Document> contentDocumentNode = contentWindow->GetDoc();
       if (contentDocumentNode) {
         DocAccessible* contentDocument =
             GetAccService()->GetDocAccessible(contentDocumentNode);
         if (contentDocument) return Relation(contentDocument);
       }
     }
   }
 
--- a/accessible/generic/RootAccessible.h
+++ b/accessible/generic/RootAccessible.h
@@ -6,26 +6,24 @@
 #ifndef mozilla_a11y_RootAccessible_h__
 #define mozilla_a11y_RootAccessible_h__
 
 #include "HyperTextAccessible.h"
 #include "DocAccessibleWrap.h"
 
 #include "nsIDOMEventListener.h"
 
-class nsIDocument;
-
 namespace mozilla {
 namespace a11y {
 
 class RootAccessible : public DocAccessibleWrap, public nsIDOMEventListener {
   NS_DECL_ISUPPORTS_INHERITED
 
  public:
-  RootAccessible(nsIDocument* aDocument, nsIPresShell* aPresShell);
+  RootAccessible(dom::Document* aDocument, nsIPresShell* aPresShell);
 
   // nsIDOMEventListener
   NS_DECL_NSIDOMEVENTLISTENER
 
   // Accessible
   virtual void Shutdown() override;
   virtual mozilla::a11y::ENameValueFlag Name(nsString& aName) const override;
   virtual Relation RelationByType(RelationType aType) const override;
--- a/accessible/html/HTMLTableAccessible.cpp
+++ b/accessible/html/HTMLTableAccessible.cpp
@@ -14,17 +14,17 @@
 #include "nsTextEquivUtils.h"
 #include "Relation.h"
 #include "Role.h"
 #include "States.h"
 #include "TreeWalker.h"
 
 #include "mozilla/dom/HTMLTableElement.h"
 #include "nsIHTMLCollection.h"
-#include "nsIDocument.h"
+#include "mozilla/dom/Document.h"
 #include "nsIMutableArray.h"
 #include "nsIPersistentProperties2.h"
 #include "nsIPresShell.h"
 #include "nsITableCellLayout.h"
 #include "nsFrameSelection.h"
 #include "nsError.h"
 #include "nsArrayUtils.h"
 #include "nsComponentManagerUtils.h"
--- a/accessible/mac/DocAccessibleWrap.h
+++ b/accessible/mac/DocAccessibleWrap.h
@@ -8,16 +8,16 @@
 
 #include "DocAccessible.h"
 
 namespace mozilla {
 namespace a11y {
 
 class DocAccessibleWrap : public DocAccessible {
  public:
-  DocAccessibleWrap(nsIDocument* aDocument, nsIPresShell* aPresShell);
+  DocAccessibleWrap(dom::Document* aDocument, nsIPresShell* aPresShell);
   virtual ~DocAccessibleWrap();
 };
 
 }  // namespace a11y
 }  // namespace mozilla
 
 #endif
--- a/accessible/mac/DocAccessibleWrap.mm
+++ b/accessible/mac/DocAccessibleWrap.mm
@@ -5,17 +5,17 @@
 
 #include "DocAccessibleWrap.h"
 
 #import "mozAccessible.h"
 
 using namespace mozilla::a11y;
 
 DocAccessibleWrap::
-  DocAccessibleWrap(nsIDocument* aDocument, nsIPresShell* aPresShell) :
+  DocAccessibleWrap(mozilla::dom::Document* aDocument, nsIPresShell* aPresShell) :
   DocAccessible(aDocument, aPresShell)
 {
 }
 
 DocAccessibleWrap::~DocAccessibleWrap()
 {
 }
 
--- a/accessible/mac/RootAccessibleWrap.h
+++ b/accessible/mac/RootAccessibleWrap.h
@@ -12,17 +12,17 @@
 
 #include "RootAccessible.h"
 
 namespace mozilla {
 namespace a11y {
 
 class RootAccessibleWrap : public RootAccessible {
  public:
-  RootAccessibleWrap(nsIDocument* aDocument, nsIPresShell* aPresShell);
+  RootAccessibleWrap(dom::Document* aDocument, nsIPresShell* aPresShell);
   virtual ~RootAccessibleWrap();
 
   Class GetNativeType();
 
   // let's our native accessible get in touch with the
   // native cocoa view that is our accessible parent.
   void GetNativeWidget(void** aOutView);
 };
--- a/accessible/mac/RootAccessibleWrap.mm
+++ b/accessible/mac/RootAccessibleWrap.mm
@@ -11,17 +11,17 @@
 #include "nsObjCExceptions.h"
 #include "nsIFrame.h"
 #include "nsView.h"
 #include "nsIWidget.h"
 
 using namespace mozilla::a11y;
 
 RootAccessibleWrap::
-  RootAccessibleWrap(nsIDocument* aDocument, nsIPresShell* aPresShell) :
+  RootAccessibleWrap(mozilla::dom::Document* aDocument, nsIPresShell* aPresShell) :
   RootAccessible(aDocument, aPresShell)
 {
 }
 
 RootAccessibleWrap::~RootAccessibleWrap()
 {
 }
 
--- a/accessible/windows/msaa/AccessibleWrap.cpp
+++ b/accessible/windows/msaa/AccessibleWrap.cpp
@@ -476,17 +476,17 @@ AccessibleWrap::get_accRole(
     nsAutoString roleString;
     // Try the role attribute.
     content->AsElement()->GetAttr(kNameSpaceID_None, nsGkAtoms::role,
                                   roleString);
 
     if (roleString.IsEmpty()) {
       // No role attribute (or it is an empty string).
       // Use the tag name.
-      nsIDocument* document = content->GetUncomposedDoc();
+      dom::Document* document = content->GetUncomposedDoc();
       if (!document) return E_FAIL;
 
       dom::NodeInfo* nodeInfo = content->NodeInfo();
       nodeInfo->GetName(roleString);
 
       // Only append name space if different from that of current document.
       if (!nodeInfo->NamespaceEquals(document->GetDefaultNamespaceID())) {
         nsAutoString nameSpaceURI;
--- a/accessible/windows/msaa/DocAccessibleWrap.cpp
+++ b/accessible/windows/msaa/DocAccessibleWrap.cpp
@@ -20,17 +20,17 @@
 
 using namespace mozilla;
 using namespace mozilla::a11y;
 
 ////////////////////////////////////////////////////////////////////////////////
 // DocAccessibleWrap
 ////////////////////////////////////////////////////////////////////////////////
 
-DocAccessibleWrap::DocAccessibleWrap(nsIDocument* aDocument,
+DocAccessibleWrap::DocAccessibleWrap(dom::Document* aDocument,
                                      nsIPresShell* aPresShell)
     : DocAccessible(aDocument, aPresShell), mHWND(nullptr) {}
 
 DocAccessibleWrap::~DocAccessibleWrap() {}
 
 IMPL_IUNKNOWN_QUERY_HEAD(DocAccessibleWrap)
 if (aIID == IID_ISimpleDOMDocument) {
   statistics::ISimpleDOMUsed();
--- a/accessible/windows/msaa/DocAccessibleWrap.h
+++ b/accessible/windows/msaa/DocAccessibleWrap.h
@@ -9,17 +9,17 @@
 
 #include "DocAccessible.h"
 
 namespace mozilla {
 namespace a11y {
 
 class DocAccessibleWrap : public DocAccessible {
  public:
-  DocAccessibleWrap(nsIDocument* aDocument, nsIPresShell* aPresShell);
+  DocAccessibleWrap(dom::Document* aDocument, nsIPresShell* aPresShell);
   virtual ~DocAccessibleWrap();
 
   DECL_IUNKNOWN_INHERITED
 
   // IAccessible
 
   // Override get_accParent for e10s
   virtual /* [id][propget] */ HRESULT STDMETHODCALLTYPE get_accParent(
--- a/accessible/windows/msaa/RootAccessibleWrap.cpp
+++ b/accessible/windows/msaa/RootAccessibleWrap.cpp
@@ -10,17 +10,17 @@
 #include "nsCoreUtils.h"
 #include "nsWinUtils.h"
 
 using namespace mozilla::a11y;
 
 ////////////////////////////////////////////////////////////////////////////////
 // Constructor/destructor
 
-RootAccessibleWrap::RootAccessibleWrap(nsIDocument* aDocument,
+RootAccessibleWrap::RootAccessibleWrap(dom::Document* aDocument,
                                        nsIPresShell* aPresShell)
     : RootAccessible(aDocument, aPresShell), mOuter(&mInternalUnknown) {}
 
 RootAccessibleWrap::~RootAccessibleWrap() {}
 
 ////////////////////////////////////////////////////////////////////////////////
 // Aggregated IUnknown
 HRESULT
--- a/accessible/windows/msaa/RootAccessibleWrap.h
+++ b/accessible/windows/msaa/RootAccessibleWrap.h
@@ -9,17 +9,17 @@
 #include "mozilla/mscom/Aggregation.h"
 #include "RootAccessible.h"
 
 namespace mozilla {
 namespace a11y {
 
 class RootAccessibleWrap : public RootAccessible {
  public:
-  RootAccessibleWrap(nsIDocument* aDocument, nsIPresShell* aPresShell);
+  RootAccessibleWrap(dom::Document* aDocument, nsIPresShell* aPresShell);
   virtual ~RootAccessibleWrap();
 
   // RootAccessible
   virtual void DocumentActivated(DocAccessible* aDocument);
 
   /**
    * This method enables a RootAccessibleWrap to be wrapped by a
    * LazyInstantiator.
--- a/accessible/windows/msaa/nsWinUtils.cpp
+++ b/accessible/windows/msaa/nsWinUtils.cpp
@@ -12,17 +12,17 @@
 #include "nsAccessibilityService.h"
 #include "nsCoreUtils.h"
 
 #include "mozilla/a11y/DocAccessibleParent.h"
 #include "mozilla/Preferences.h"
 #include "nsArrayUtils.h"
 #include "nsIArray.h"
 #include "nsICSSDeclaration.h"
-#include "nsIDocument.h"
+#include "mozilla/dom/Document.h"
 #include "nsIDocShellTreeItem.h"
 #include "mozilla/dom/Element.h"
 #include "nsXULAppAPI.h"
 #include "ProxyWrappers.h"
 
 using namespace mozilla;
 using namespace mozilla::a11y;
 using mozilla::dom::Element;
--- a/accessible/xpcom/xpcAccessibilityService.cpp
+++ b/accessible/xpcom/xpcAccessibilityService.cpp
@@ -187,21 +187,18 @@ xpcAccessibilityService::GetAccessibleFr
 
   // Search for an accessible in each of our per document accessible object
   // caches. If we don't find it, and the given node is itself a document, check
   // our cache of document accessibles (document cache). Note usually shutdown
   // document accessibles are not stored in the document cache, however an
   // "unofficially" shutdown document (i.e. not from DocManager) can still
   // exist in the document cache.
   Accessible* accessible = accService->FindAccessibleInCache(aNode);
-  if (!accessible) {
-    nsCOMPtr<nsIDocument> document(do_QueryInterface(aNode));
-    if (document) {
-      accessible = mozilla::a11y::GetExistingDocAccessible(document);
-    }
+  if (!accessible && aNode->IsDocument()) {
+    accessible = mozilla::a11y::GetExistingDocAccessible(aNode->AsDocument());
   }
 
   NS_IF_ADDREF(*aAccessible = ToXPC(accessible));
   return NS_OK;
 }
 
 NS_IMETHODIMP
 xpcAccessibilityService::CreateAccessiblePivot(nsIAccessible* aRoot,
--- a/accessible/xpcom/xpcAccessibleDocument.cpp
+++ b/accessible/xpcom/xpcAccessibleDocument.cpp
@@ -71,17 +71,17 @@ NS_IMETHODIMP
 xpcAccessibleDocument::GetDocType(nsAString& aType) {
   if (!Intl()) return NS_ERROR_FAILURE;
 
   Intl()->DocType(aType);
   return NS_OK;
 }
 
 NS_IMETHODIMP
-xpcAccessibleDocument::GetDOMDocument(nsIDocument** aDOMDocument) {
+xpcAccessibleDocument::GetDOMDocument(dom::Document** aDOMDocument) {
   NS_ENSURE_ARG_POINTER(aDOMDocument);
   *aDOMDocument = nullptr;
 
   if (!Intl()) return NS_ERROR_FAILURE;
 
   if (Intl()->DocumentNode()) NS_ADDREF(*aDOMDocument = Intl()->DocumentNode());
 
   return NS_OK;
--- a/accessible/xpcom/xpcAccessibleDocument.h
+++ b/accessible/xpcom/xpcAccessibleDocument.h
@@ -35,17 +35,17 @@ class xpcAccessibleDocument : public xpc
 
   NS_DECL_ISUPPORTS_INHERITED
 
   // nsIAccessibleDocument
   NS_IMETHOD GetURL(nsAString& aURL) final;
   NS_IMETHOD GetTitle(nsAString& aTitle) final;
   NS_IMETHOD GetMimeType(nsAString& aType) final;
   NS_IMETHOD GetDocType(nsAString& aType) final;
-  NS_IMETHOD GetDOMDocument(nsIDocument** aDOMDocument) final;
+  NS_IMETHOD GetDOMDocument(dom::Document** aDOMDocument) final;
   NS_IMETHOD GetWindow(mozIDOMWindowProxy** aDOMWindow) final;
   NS_IMETHOD GetParentDocument(nsIAccessibleDocument** aDocument) final;
   NS_IMETHOD GetChildDocumentCount(uint32_t* aCount) final;
   NS_IMETHOD GetChildDocumentAt(uint32_t aIndex,
                                 nsIAccessibleDocument** aDocument) final;
   NS_IMETHOD GetVirtualCursor(nsIAccessiblePivot** aVirtualCursor) final;
 
   /**
--- a/accessible/xul/XULElementAccessibles.cpp
+++ b/accessible/xul/XULElementAccessibles.cpp
@@ -201,16 +201,16 @@ uint32_t XULLinkAccessible::EndOffset() 
 already_AddRefed<nsIURI> XULLinkAccessible::AnchorURIAt(
     uint32_t aAnchorIndex) const {
   if (aAnchorIndex != 0) return nullptr;
 
   nsAutoString href;
   mContent->AsElement()->GetAttr(kNameSpaceID_None, nsGkAtoms::href, href);
 
   nsCOMPtr<nsIURI> baseURI = mContent->GetBaseURI();
-  nsIDocument* document = mContent->OwnerDoc();
+  dom::Document* document = mContent->OwnerDoc();
 
   nsCOMPtr<nsIURI> anchorURI;
   NS_NewURI(getter_AddRefs(anchorURI), href,
             document->GetDocumentCharacterSet(), baseURI);
 
   return anchorURI.forget();
 }
--- a/accessible/xul/XULTabAccessible.cpp
+++ b/accessible/xul/XULTabAccessible.cpp
@@ -7,17 +7,17 @@
 
 #include "ARIAMap.h"
 #include "nsAccUtils.h"
 #include "Relation.h"
 #include "Role.h"
 #include "States.h"
 
 // NOTE: alphabetically ordered
-#include "nsIDocument.h"
+#include "mozilla/dom/Document.h"
 #include "nsIDOMXULSelectCntrlEl.h"
 #include "nsIDOMXULSelectCntrlItemEl.h"
 #include "nsIDOMXULRelatedElement.h"
 #include "nsXULElement.h"
 
 #include "mozilla/dom/BindingDeclarations.h"
 
 using namespace mozilla::a11y;
--- a/browser/components/aboutconfig/content/aboutconfig.js
+++ b/browser/components/aboutconfig/content/aboutconfig.js
@@ -5,16 +5,45 @@
 ChromeUtils.import("resource://gre/modules/Services.jsm");
 ChromeUtils.import("resource://gre/modules/Preferences.jsm");
 
 let gDefaultBranch = Services.prefs.getDefaultBranch("");
 let gPrefArray;
 let gPrefRowInEdit;
 let gPrefInEdit;
 
+class PrefRow {
+  constructor(name) {
+    this.name = name;
+    this.refreshValue();
+  }
+
+  refreshValue() {
+    this.hasUserValue = Services.prefs.prefHasUserValue(this.name);
+    this.hasDefaultValue = this.hasUserValue ? prefHasDefaultValue(this.name)
+                                             : true;
+    this.isLocked = Services.prefs.prefIsLocked(this.name);
+
+    try {
+      // This can throw for locked preferences without a default value.
+      this.value = Preferences.get(this.name);
+      // We don't know which preferences should be read using getComplexValue,
+      // so we use a heuristic to determine if this is a localized preference.
+      if (!this.hasUserValue &&
+          /^chrome:\/\/.+\/locale\/.+\.properties/.test(this.value)) {
+        // This can throw if there is no value in the localized files.
+        this.value = Services.prefs.getComplexValue(this.name,
+          Ci.nsIPrefLocalizedString).data;
+      }
+    } catch (ex) {
+      this.value = "";
+    }
+  }
+}
+
 function getPrefName(prefRow) {
   return prefRow.getAttribute("aria-label");
 }
 
 document.addEventListener("DOMContentLoaded", () => {
   if (!Preferences.get("browser.aboutConfig.showWarning")) {
     loadPrefs();
   }
@@ -33,38 +62,17 @@ function loadPrefs() {
   search.type = "text";
   search.id = "search";
   document.l10n.setAttributes(search, "about-config-search");
   document.body.appendChild(search);
   let prefs = document.createElement("table");
   prefs.id = "prefs";
   document.body.appendChild(prefs);
 
-  gPrefArray = Services.prefs.getChildList("").map(function(name) {
-    let hasUserValue = Services.prefs.prefHasUserValue(name);
-    let pref = {
-      name,
-      hasUserValue,
-      hasDefaultValue: hasUserValue ? prefHasDefaultValue(name) : true,
-      isLocked: Services.prefs.prefIsLocked(name),
-    };
-    // Try in case it's a localized string or locked user added pref
-    // If an execption is thrown the pref value is set to the empty string.
-    try {
-      // Throws an exception in case locked user added pref without default value
-      pref.value = Preferences.get(name);
-      // Throws an exception if there is no equivalent value in the localized files for the pref.
-      if (!pref.hasUserValue && /^chrome:\/\/.+\/locale\/.+\.properties/.test(pref.value)) {
-        pref.value = Services.prefs.getComplexValue(name, Ci.nsIPrefLocalizedString).data;
-      }
-    } catch (ex) {
-      pref.value = "";
-    }
-    return pref;
-  });
+  gPrefArray = Services.prefs.getChildList("").map(name => new PrefRow(name));
 
   gPrefArray.sort((a, b) => a.name > b.name);
 
   search.addEventListener("keypress", e => {
     if (e.key == "Enter") {
       filterPrefs();
     }
   });
@@ -75,18 +83,17 @@ function loadPrefs() {
     }
     let prefRow = event.target.closest("tr");
     let prefName = getPrefName(prefRow);
     let pref = gPrefArray.find(p => p.name == prefName);
     let button = event.target.closest("button");
     if (button.classList.contains("button-reset")) {
       // Reset pref and update gPrefArray.
       Services.prefs.clearUserPref(prefName);
-      pref.value = Preferences.get(prefName);
-      pref.hasUserValue = false;
+      pref.refreshValue();
       // Update UI.
       prefRow.textContent = "";
       prefRow.classList.remove("has-user-value");
       prefRow.appendChild(getPrefRow(pref));
       prefRow.querySelector("td.cell-edit").firstChild.focus();
     } else if (button.classList.contains("add-true")) {
       addNewPref(prefRow.firstChild.innerHTML, true);
     } else if (button.classList.contains("add-false")) {
@@ -97,18 +104,17 @@ function loadPrefs() {
         button.classList.contains("add-Number") ? 0 : "");
       prefRow = [...prefs.getElementsByTagName("tr")]
         .find(row => row.querySelector("td").textContent == prefName);
       startEditingPref(prefRow, gPrefArray.find(p => p.name == prefName));
       prefRow.querySelector("td.cell-value").firstChild.firstChild.focus();
     } else if (button.classList.contains("button-toggle")) {
       // Toggle the pref and update gPrefArray.
       Services.prefs.setBoolPref(prefName, !pref.value);
-      pref.value = !pref.value;
-      pref.hasUserValue = Services.prefs.prefHasUserValue(pref.name);
+      pref.refreshValue();
       // Update UI.
       prefRow.textContent = "";
       if (pref.hasUserValue) {
         prefRow.classList.add("has-user-value");
       } else {
         prefRow.classList.remove("has-user-value");
       }
       prefRow.appendChild(getPrefRow(pref));
@@ -291,18 +297,17 @@ function endEditingPref(row) {
     }
     newValue = numberValue;
     Services.prefs.setIntPref(name, newValue);
   } else {
     Services.prefs.setStringPref(name, newValue);
   }
 
   // Update gPrefArray.
-  gPrefInEdit.value = newValue;
-  gPrefInEdit.hasUserValue = Services.prefs.prefHasUserValue(name);
+  gPrefInEdit.refreshValue();
   // Update UI.
   row.textContent = "";
   if (gPrefInEdit.hasUserValue) {
     row.classList.add("has-user-value");
   } else {
     row.classList.remove("has-user-value");
   }
   row.appendChild(getPrefRow(gPrefInEdit));
@@ -322,17 +327,12 @@ function prefHasDefaultValue(name) {
         return true;
     }
   } catch (ex) {}
   return false;
 }
 
 function addNewPref(name, value) {
   Preferences.set(name, value);
-  gPrefArray.push({
-    name,
-    value,
-    hasUserValue: true,
-    hasDefaultValue: false,
-  });
+  gPrefArray.push(new PrefRow(name));
   gPrefArray.sort((a, b) => a.name > b.name);
   filterPrefs();
 }
--- a/browser/components/aboutconfig/test/browser/browser_basic.js
+++ b/browser/components/aboutconfig/test/browser/browser_basic.js
@@ -1,51 +1,49 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 add_task(async function setup() {
   await SpecialPowers.pushPrefEnv({
     set: [
-      ["random.user.pref", "chrome://test/locale/testing.properties"],
+      ["test.aboutconfig.userValueLikeLocalized",
+       "chrome://test/locale/testing.properties"],
     ],
   });
 });
 
 add_task(async function test_load_title() {
   await AboutConfigTest.withNewTab(async function() {
     Assert.equal(this.document.title, "about:config");
   });
 });
 
 add_task(async function test_load_settings() {
   await AboutConfigTest.withNewTab(async function() {
     // Test if page contains elements.
-    Assert.ok(this.getRow("plugins.testmode"));
-    Assert.ok(this.getRow("dom.vr.enabled"));
-    Assert.ok(this.getRow("accessibility.AOM.enabled"));
+    Assert.equal(this.getRow(PREF_NUMBER_DEFAULT_ZERO).value, 0);
+    Assert.equal(this.getRow(PREF_STRING_DEFAULT_EMPTY).value, "");
 
     // Test if the modified state is displayed for the right prefs.
-    let prefArray = Services.prefs.getChildList("");
-    let nameOfEdited = prefArray.find(
-      name => Services.prefs.prefHasUserValue(name));
-    let nameOfDefault = prefArray.find(
-      name => !Services.prefs.prefHasUserValue(name));
-    Assert.ok(!this.getRow(nameOfDefault).hasClass("has-user-value"));
-    Assert.ok(this.getRow(nameOfEdited).hasClass("has-user-value"));
+    Assert.ok(!this.getRow(PREF_BOOLEAN_DEFAULT_TRUE)
+                   .hasClass("has-user-value"));
+    Assert.ok(this.getRow(PREF_BOOLEAN_USERVALUE_TRUE)
+                  .hasClass("has-user-value"));
 
-    // Test to see if values are localized.
+    // Test to see if values are localized, sampling from different files. If
+    // any of these are removed or their value changes, just update the value
+    // here or point to a different preference in the same file.
     Assert.equal(this.getRow("font.language.group").value, "x-western");
     Assert.equal(this.getRow("intl.ellipsis").value, "\u2026");
     Assert.equal(
       this.getRow("gecko.handlerService.schemes.mailto.1.uriTemplate").value,
       "https://mail.google.com/mail/?extsrc=mailto&url=%s");
 
     // Test to see if user created value is not empty string when it matches
     // /^chrome:\/\/.+\/locale\/.+\.properties/.
-    Assert.equal(this.getRow("random.user.pref").value,
+    Assert.equal(this.getRow("test.aboutconfig.userValueLikeLocalized").value,
       "chrome://test/locale/testing.properties");
 
     // Test to see if empty string when value matches
     // /^chrome:\/\/.+\/locale\/.+\.properties/ and an exception is thrown.
-    Assert.equal(this.getRow("gecko.handlerService.schemes.irc.1.name").value,
-      "");
+    Assert.equal(this.getRow(PREF_STRING_LOCALIZED_MISSING).value, "");
   });
 });
--- a/browser/components/aboutconfig/test/browser/browser_edit.js
+++ b/browser/components/aboutconfig/test/browser/browser_edit.js
@@ -6,19 +6,19 @@ add_task(async function setup() {
     set: [
       ["test.aboutconfig.modify.boolean", true],
       ["test.aboutconfig.modify.number", 1337],
       ["test.aboutconfig.modify.string", "the answer to the life the universe and everything"],
     ],
   });
 
   registerCleanupFunction(() => {
-    Services.prefs.clearUserPref("accessibility.typeaheadfind.autostart");
-    Services.prefs.clearUserPref("accessibility.typeaheadfind.soundURL");
-    Services.prefs.clearUserPref("accessibility.typeaheadfind.casesensitive");
+    Services.prefs.clearUserPref(PREF_BOOLEAN_DEFAULT_TRUE);
+    Services.prefs.clearUserPref(PREF_NUMBER_DEFAULT_ZERO);
+    Services.prefs.clearUserPref(PREF_STRING_DEFAULT_EMPTY);
   });
 });
 
 add_task(async function test_add_user_pref() {
   await AboutConfigTest.withNewTab(async function() {
     Assert.ok(!Services.prefs.getChildList("").find(pref => pref == "testPref"));
 
     for (let [buttonSelector, expectedValue] of [
@@ -35,101 +35,112 @@ add_task(async function test_add_user_pr
     }
   });
 });
 
 add_task(async function test_delete_user_pref() {
   Services.prefs.setBoolPref("userAddedPref", true);
   await AboutConfigTest.withNewTab(async function() {
     let row = this.getRow("userAddedPref");
-    row.element.lastChild.lastChild.click();
+    row.resetColumnButton.click();
     Assert.ok(!this.getRow("userAddedPref"));
     Assert.ok(!Services.prefs.getChildList("").includes("userAddedPref"));
 
     // Search for nothing to test gPrefArray
     this.search();
     Assert.ok(!this.getRow("userAddedPref"));
   });
 });
 
 add_task(async function test_reset_user_pref() {
-  await SpecialPowers.pushPrefEnv({"set": [["browser.autofocus", false]]});
+  await SpecialPowers.pushPrefEnv({
+    "set": [
+      [PREF_BOOLEAN_DEFAULT_TRUE, false],
+      [PREF_STRING_LOCALIZED_MISSING, "user-value"],
+    ],
+  });
 
   await AboutConfigTest.withNewTab(async function() {
-    let testPref = "browser.autofocus";
     // Click reset.
-    let row = this.getRow(testPref);
-    row.element.lastChild.lastChild.click();
+    let row = this.getRow(PREF_BOOLEAN_DEFAULT_TRUE);
+    row.resetColumnButton.click();
     // Check new layout and reset.
     Assert.ok(!row.hasClass("has-user-value"));
-    Assert.equal(row.element.lastChild.childNodes.length, 0);
-    Assert.ok(!Services.prefs.prefHasUserValue(testPref));
-    Assert.equal(this.getRow(testPref).value, "" + Preferences.get(testPref));
+    Assert.ok(!row.resetColumnButton);
+    Assert.ok(!Services.prefs.prefHasUserValue(PREF_BOOLEAN_DEFAULT_TRUE));
+    Assert.equal(this.getRow(PREF_BOOLEAN_DEFAULT_TRUE).value, "true");
 
     // Search for nothing to test gPrefArray
     this.search();
-    row = this.getRow(testPref);
+    row = this.getRow(PREF_BOOLEAN_DEFAULT_TRUE);
     Assert.ok(!row.hasClass("has-user-value"));
-    Assert.equal(row.element.lastChild.childNodes.length, 0);
-    Assert.equal(this.getRow(testPref).value, "" + Preferences.get(testPref));
+    Assert.ok(!row.resetColumnButton);
+    Assert.equal(this.getRow(PREF_BOOLEAN_DEFAULT_TRUE).value, "true");
+
+    // Clicking reset on a localized preference without a corresponding value.
+    row = this.getRow(PREF_STRING_LOCALIZED_MISSING);
+    Assert.equal(row.value, "user-value");
+    row.resetColumnButton.click();
+    // Check new layout and reset.
+    Assert.ok(!row.hasClass("has-user-value"));
+    Assert.ok(!row.resetColumnButton);
+    Assert.ok(!Services.prefs.prefHasUserValue(PREF_STRING_LOCALIZED_MISSING));
+    Assert.equal(this.getRow(PREF_STRING_LOCALIZED_MISSING).value, "");
   });
 });
 
 add_task(async function test_modify() {
   await AboutConfigTest.withNewTab(async function() {
     // Test toggle for boolean prefs.
     for (let nameOfBoolPref of [
       "test.aboutconfig.modify.boolean",
-      "accessibility.typeaheadfind.autostart",
+      PREF_BOOLEAN_DEFAULT_TRUE,
     ]) {
       let row = this.getRow(nameOfBoolPref);
       // Do this a two times to reset the pref.
       for (let i = 0; i < 2; i++) {
-        row.querySelector("td.cell-edit").firstChild.click();
+        row.editColumnButton.click();
         // Check new layout and saving in backend.
         Assert.equal(this.getRow(nameOfBoolPref).value,
           "" + Preferences.get(nameOfBoolPref));
         let prefHasUserValue = Services.prefs.prefHasUserValue(nameOfBoolPref);
         Assert.equal(row.hasClass("has-user-value"), prefHasUserValue);
-        Assert.equal(row.element.lastChild.childNodes.length > 0, prefHasUserValue);
+        Assert.equal(!!row.resetColumnButton, prefHasUserValue);
       }
     }
 
     // Test abort of edit by starting with string and continuing with editing Int pref.
     let row = this.getRow("test.aboutconfig.modify.string");
-    row.querySelector("td.cell-edit").firstChild.click();
-    row.querySelector("td.cell-value").firstChild.firstChild.value = "test";
+    row.editColumnButton.click();
+    row.valueInput.value = "test";
     let intRow = this.getRow("test.aboutconfig.modify.number");
-    intRow.querySelector("td.cell-edit").firstChild.click();
-    Assert.equal(intRow.querySelector("td.cell-value").firstChild.firstChild.value,
+    intRow.editColumnButton.click();
+    Assert.equal(intRow.valueInput.value,
       Preferences.get("test.aboutconfig.modify.number"));
-    Assert.equal(this.getRow("test.aboutconfig.modify.string").value,
-      "" + Preferences.get("test.aboutconfig.modify.string"));
-    Assert.equal(row.querySelector("td.cell-value").textContent,
-      Preferences.get("test.aboutconfig.modify.string"));
+    Assert.ok(!row.valueInput);
+    Assert.equal(row.value, Preferences.get("test.aboutconfig.modify.string"));
 
     // Test regex check for Int pref.
-    intRow.querySelector("td.cell-value").firstChild.firstChild.value += "a";
-    intRow.querySelector("td.cell-edit").firstChild.click();
-    Assert.ok(!intRow.querySelector("td.cell-value").firstChild.firstChild.checkValidity());
+    intRow.valueInput.value += "a";
+    intRow.editColumnButton.click();
+    Assert.ok(!intRow.valueInput.checkValidity());
 
     // Test correct saving and DOM-update.
     for (let prefName of [
       "test.aboutconfig.modify.string",
       "test.aboutconfig.modify.number",
-      "accessibility.typeaheadfind.soundURL",
-      "accessibility.typeaheadfind.casesensitive",
+      PREF_NUMBER_DEFAULT_ZERO,
+      PREF_STRING_DEFAULT_EMPTY,
     ]) {
       row = this.getRow(prefName);
       // Activate edit and check displaying.
-      row.querySelector("td.cell-edit").firstChild.click();
-      Assert.equal(row.querySelector("td.cell-value").firstChild.firstChild.value,
-        Preferences.get(prefName));
-      row.querySelector("td.cell-value").firstChild.firstChild.value = "42";
+      row.editColumnButton.click();
+      Assert.equal(row.valueInput.value, Preferences.get(prefName));
+      row.valueInput.value = "42";
       // Save and check saving.
-      row.querySelector("td.cell-edit").firstChild.click();
+      row.editColumnButton.click();
       Assert.equal(row.value, "" + Preferences.get(prefName));
       let prefHasUserValue = Services.prefs.prefHasUserValue(prefName);
-      Assert.equal(row.element.lastChild.childNodes.length > 0, prefHasUserValue);
+      Assert.equal(!!row.resetColumnButton, prefHasUserValue);
       Assert.equal(row.hasClass("has-user-value"), prefHasUserValue);
     }
   });
 });
--- a/browser/components/aboutconfig/test/browser/browser_locked.js
+++ b/browser/components/aboutconfig/test/browser/browser_locked.js
@@ -1,51 +1,54 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
+const PREF_STRING_NO_DEFAULT = "test.aboutconfig.a";
+
 add_task(async function setup() {
   await SpecialPowers.pushPrefEnv({
     set: [
-      ["test.aboutconfig.a", "some value"],
+      [PREF_STRING_NO_DEFAULT, "some value"],
     ],
   });
 });
 
 add_task(async function test_locked() {
   registerCleanupFunction(() => {
-    Services.prefs.unlockPref("browser.search.searchEnginesURL");
-    Services.prefs.unlockPref("test.aboutconfig.a");
-    Services.prefs.unlockPref("accessibility.AOM.enabled");
+    Services.prefs.unlockPref(PREF_STRING_DEFAULT_NOTEMPTY);
+    Services.prefs.unlockPref(PREF_BOOLEAN_DEFAULT_TRUE);
+    Services.prefs.unlockPref(PREF_STRING_NO_DEFAULT);
   });
 
-  Services.prefs.lockPref("browser.search.searchEnginesURL");
-  Services.prefs.lockPref("test.aboutconfig.a");
-  Services.prefs.lockPref("accessibility.AOM.enabled");
+  Services.prefs.lockPref(PREF_STRING_DEFAULT_NOTEMPTY);
+  Services.prefs.lockPref(PREF_BOOLEAN_DEFAULT_TRUE);
+  Services.prefs.lockPref(PREF_STRING_NO_DEFAULT);
+
   await AboutConfigTest.withNewTab(async function() {
     // Test locked default string pref.
-    let lockedPref = this.getRow("browser.search.searchEnginesURL");
+    let lockedPref = this.getRow(PREF_STRING_DEFAULT_NOTEMPTY);
     Assert.ok(lockedPref.hasClass("locked"));
-    Assert.equal(lockedPref.value, "https://addons.mozilla.org/%LOCALE%/firefox/search-engines/");
-    Assert.ok(lockedPref.firstButton.classList.contains("button-edit"));
-    Assert.ok(lockedPref.firstButton.disabled);
+    Assert.equal(lockedPref.value, PREF_STRING_DEFAULT_NOTEMPTY_VALUE);
+    Assert.ok(lockedPref.editColumnButton.classList.contains("button-edit"));
+    Assert.ok(lockedPref.editColumnButton.disabled);
 
     // Test locked default boolean pref.
-    lockedPref = this.getRow("accessibility.AOM.enabled");
+    lockedPref = this.getRow(PREF_BOOLEAN_DEFAULT_TRUE);
     Assert.ok(lockedPref.hasClass("locked"));
-    Assert.equal(lockedPref.value, "false");
-    Assert.ok(lockedPref.firstButton.classList.contains("button-toggle"));
-    Assert.ok(lockedPref.firstButton.disabled);
+    Assert.equal(lockedPref.value, "true");
+    Assert.ok(lockedPref.editColumnButton.classList.contains("button-toggle"));
+    Assert.ok(lockedPref.editColumnButton.disabled);
 
     // Test locked user added pref.
-    lockedPref = this.getRow("test.aboutconfig.a");
+    lockedPref = this.getRow(PREF_STRING_NO_DEFAULT);
     Assert.ok(lockedPref.hasClass("locked"));
     Assert.equal(lockedPref.value, "");
-    Assert.ok(lockedPref.firstButton.classList.contains("button-edit"));
-    Assert.ok(lockedPref.firstButton.disabled);
+    Assert.ok(lockedPref.editColumnButton.classList.contains("button-edit"));
+    Assert.ok(lockedPref.editColumnButton.disabled);
 
-    // Test pref not locked
-    let unlockedPref = this.getRow("accessibility.indicator.enabled");
+    // Test pref not locked.
+    let unlockedPref = this.getRow(PREF_BOOLEAN_USERVALUE_TRUE);
     Assert.ok(!unlockedPref.hasClass("locked"));
-    Assert.equal(unlockedPref.value, "false");
-    Assert.ok(unlockedPref.firstButton.classList.contains("button-toggle"));
-    Assert.ok(!unlockedPref.firstButton.disabled);
+    Assert.equal(unlockedPref.value, "true");
+    Assert.ok(unlockedPref.editColumnButton.classList.contains("button-toggle"));
+    Assert.ok(!unlockedPref.editColumnButton.disabled);
   });
 });
--- a/browser/components/aboutconfig/test/browser/browser_search.js
+++ b/browser/components/aboutconfig/test/browser/browser_search.js
@@ -9,17 +9,16 @@ add_task(async function setup() {
       ["test.aboutconfig.b", "test value 3"],
     ],
   });
 });
 
 add_task(async function test_search() {
   await AboutConfigTest.withNewTab(async function() {
     let prefArray = Services.prefs.getChildList("");
-    await this.document.querySelector("button").click();
 
     // The total number of preferences may change at any time because of
     // operations running in the background, so we only test approximately.
     // The change in count would be because of one or two added preferences,
     // but we tolerate a difference of up to 50 preferences just to be safe.
     // We want thousands of prefs instead of a few dozen that are filtered.
     Assert.greater(this.rows.length, prefArray.length - 50);
 
--- a/browser/components/aboutconfig/test/browser/head.js
+++ b/browser/components/aboutconfig/test/browser/head.js
@@ -1,15 +1,27 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
 ChromeUtils.import("resource://gre/modules/Preferences.jsm", this);
 
+// List of default preferences that can be used for tests, chosen because they
+// have little or no side-effects when they are modified for a brief time. If
+// any of these preferences are removed or their default state changes, just
+// update the constant to point to a different preference with the same default.
+const PREF_BOOLEAN_DEFAULT_TRUE = "accessibility.typeaheadfind.manual";
+const PREF_BOOLEAN_USERVALUE_TRUE = "browser.dom.window.dump.enabled";
+const PREF_NUMBER_DEFAULT_ZERO = "accessibility.typeaheadfind.casesensitive";
+const PREF_STRING_DEFAULT_EMPTY = "browser.helperApps.neverAsk.openFile";
+const PREF_STRING_DEFAULT_NOTEMPTY = "accessibility.typeaheadfind.soundURL";
+const PREF_STRING_DEFAULT_NOTEMPTY_VALUE = "beep";
+const PREF_STRING_LOCALIZED_MISSING = "gecko.handlerService.schemes.irc.1.name";
+
 class AboutConfigRowTest {
   constructor(element) {
     this.element = element;
   }
 
   querySelector(selector) {
     return this.element.querySelector(selector);
   }
@@ -17,18 +29,36 @@ class AboutConfigRowTest {
   get name() {
     return this.querySelector("td").textContent;
   }
 
   get value() {
     return this.querySelector("td.cell-value").textContent;
   }
 
-  get firstButton() {
-    return this.querySelector("button");
+  /**
+   * Text input field when the row is in edit mode.
+   */
+  get valueInput() {
+    return this.querySelector("td.cell-value input");
+  }
+
+  /**
+   * This is normally "edit" or "toggle" based on the preference type, or "save"
+   * when the row is in edit mode.
+   */
+  get editColumnButton() {
+    return this.querySelector("td.cell-edit > button");
+  }
+
+  /**
+   * This can be "reset" or "delete" based on whether a default exists.
+   */
+  get resetColumnButton() {
+    return this.querySelector("td:last-child > button");
   }
 
   hasClass(className) {
     return this.element.classList.contains(className);
   }
 }
 
 class AboutConfigTest {
--- a/browser/components/shell/nsMacShellService.cpp
+++ b/browser/components/shell/nsMacShellService.cpp
@@ -1,16 +1,16 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* 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 "nsDirectoryServiceDefs.h"
 #include "nsIImageLoadingContent.h"
-#include "nsIDocument.h"
+#include "mozilla/dom/Document.h"
 #include "nsIContent.h"
 #include "nsILocalFileMac.h"
 #include "nsIObserverService.h"
 #include "nsIPrefService.h"
 #include "nsIServiceManager.h"
 #include "nsIStringBundle.h"
 #include "nsIURL.h"
 #include "nsIWebBrowserPersist.h"
--- a/browser/components/tests/browser/browser.ini
+++ b/browser/components/tests/browser/browser.ini
@@ -1,10 +1,9 @@
 [DEFAULT]
 
 [browser_bug538331.js]
 skip-if = !updater
 reason = test depends on update channel
 [browser_contentpermissionprompt.js]
 [browser_default_bookmark_toolbar_visibility.js]
 [browser_initial_tab_remoteType.js]
-skip-if = verify && !debug && os == 'mac' # Bug 1514778
 [browser_urlbar_matchBuckets_migration60.js]
--- a/caps/BasePrincipal.cpp
+++ b/caps/BasePrincipal.cpp
@@ -180,17 +180,17 @@ BasePrincipal::SetCsp(nsIContentSecurity
     return NS_ERROR_ALREADY_INITIALIZED;
   }
 
   mCSP = aCsp;
   return NS_OK;
 }
 
 NS_IMETHODIMP
-BasePrincipal::EnsureCSP(nsIDocument* aDocument,
+BasePrincipal::EnsureCSP(dom::Document* aDocument,
                          nsIContentSecurityPolicy** aCSP) {
   if (mCSP) {
     // if there is a CSP already associated with this principal
     // then just return that - do not overwrite it!!!
     NS_IF_ADDREF(*aCSP = mCSP);
     return NS_OK;
   }
 
@@ -208,17 +208,17 @@ BasePrincipal::EnsureCSP(nsIDocument* aD
 
 NS_IMETHODIMP
 BasePrincipal::GetPreloadCsp(nsIContentSecurityPolicy** aPreloadCSP) {
   NS_IF_ADDREF(*aPreloadCSP = mPreloadCSP);
   return NS_OK;
 }
 
 NS_IMETHODIMP
-BasePrincipal::EnsurePreloadCSP(nsIDocument* aDocument,
+BasePrincipal::EnsurePreloadCSP(dom::Document* aDocument,
                                 nsIContentSecurityPolicy** aPreloadCSP) {
   if (mPreloadCSP) {
     // if there is a speculative CSP already associated with this principal
     // then just return that - do not overwrite it!!!
     NS_IF_ADDREF(*aPreloadCSP = mPreloadCSP);
     return NS_OK;
   }
 
--- a/caps/BasePrincipal.h
+++ b/caps/BasePrincipal.h
@@ -16,16 +16,19 @@ class nsAtom;
 class nsIContentSecurityPolicy;
 class nsIObjectOutputStream;
 class nsIObjectInputStream;
 class nsIURI;
 
 class ExpandedPrincipal;
 
 namespace mozilla {
+namespace dom {
+class Document;
+}
 namespace extensions {
 class WebExtensionPolicy;
 }
 
 class BasePrincipal;
 
 // Codebase principals (and codebase principals embedded within expanded
 // principals) stored in SiteIdentifier are guaranteed to contain only the
@@ -100,20 +103,20 @@ class BasePrincipal : public nsJSPrincip
                                        bool* _retval) final;
   NS_IMETHOD SubsumesConsideringDomainIgnoringFPD(nsIPrincipal* other,
                                                   bool* _retval) final;
   NS_IMETHOD CheckMayLoad(nsIURI* uri, bool report,
                           bool allowIfInheritsPrincipal) final;
   NS_IMETHOD GetAddonPolicy(nsISupports** aResult) final;
   NS_IMETHOD GetCsp(nsIContentSecurityPolicy** aCsp) override;
   NS_IMETHOD SetCsp(nsIContentSecurityPolicy* aCsp) override;
-  NS_IMETHOD EnsureCSP(nsIDocument* aDocument,
+  NS_IMETHOD EnsureCSP(dom::Document* aDocument,
                        nsIContentSecurityPolicy** aCSP) override;
   NS_IMETHOD GetPreloadCsp(nsIContentSecurityPolicy** aPreloadCSP) override;
-  NS_IMETHOD EnsurePreloadCSP(nsIDocument* aDocument,
+  NS_IMETHOD EnsurePreloadCSP(dom::Document* aDocument,
                               nsIContentSecurityPolicy** aCSP) override;
   NS_IMETHOD GetCspJSON(nsAString& outCSPinJSON) override;
   NS_IMETHOD GetIsNullPrincipal(bool* aResult) override;
   NS_IMETHOD GetIsCodebasePrincipal(bool* aResult) override;
   NS_IMETHOD GetIsExpandedPrincipal(bool* aResult) override;
   NS_IMETHOD GetIsSystemPrincipal(bool* aResult) override;
   NS_IMETHOD GetIsAddonOrExpandedAddonPrincipal(bool* aResult) override;
   NS_IMETHOD GetOriginAttributes(JSContext* aCx,
--- a/caps/SystemPrincipal.cpp
+++ b/caps/SystemPrincipal.cpp
@@ -61,30 +61,30 @@ NS_IMETHODIMP
 SystemPrincipal::SetCsp(nsIContentSecurityPolicy* aCsp) {
   // Never destroy an existing CSP on the principal.
   // This method should only be called in rare cases.
 
   return NS_ERROR_FAILURE;
 }
 
 NS_IMETHODIMP
-SystemPrincipal::EnsureCSP(nsIDocument* aDocument,
+SystemPrincipal::EnsureCSP(dom::Document* aDocument,
                            nsIContentSecurityPolicy** aCSP) {
   // CSP on a system principal makes no sense
   return NS_ERROR_FAILURE;
 }
 
 NS_IMETHODIMP
 SystemPrincipal::GetPreloadCsp(nsIContentSecurityPolicy** aPreloadCSP) {
   *aPreloadCSP = nullptr;
   return NS_OK;
 }
 
 NS_IMETHODIMP
-SystemPrincipal::EnsurePreloadCSP(nsIDocument* aDocument,
+SystemPrincipal::EnsurePreloadCSP(dom::Document* aDocument,
                                   nsIContentSecurityPolicy** aPreloadCSP) {
   // CSP on a system principal makes no sense
   return NS_ERROR_FAILURE;
 }
 
 NS_IMETHODIMP
 SystemPrincipal::GetDomain(nsIURI** aDomain) {
   *aDomain = nullptr;
--- a/caps/SystemPrincipal.h
+++ b/caps/SystemPrincipal.h
@@ -35,20 +35,20 @@ class SystemPrincipal final : public Bas
   NS_DECL_NSISERIALIZABLE
   NS_IMETHOD QueryInterface(REFNSIID aIID, void** aInstancePtr) override;
   uint32_t GetHashValue() override;
   NS_IMETHOD GetURI(nsIURI** aURI) override;
   NS_IMETHOD GetDomain(nsIURI** aDomain) override;
   NS_IMETHOD SetDomain(nsIURI* aDomain) override;
   NS_IMETHOD GetCsp(nsIContentSecurityPolicy** aCsp) override;
   NS_IMETHOD SetCsp(nsIContentSecurityPolicy* aCsp) override;
-  NS_IMETHOD EnsureCSP(nsIDocument* aDocument,
+  NS_IMETHOD EnsureCSP(dom::Document* aDocument,
                        nsIContentSecurityPolicy** aCSP) override;
   NS_IMETHOD GetPreloadCsp(nsIContentSecurityPolicy** aPreloadCSP) override;
-  NS_IMETHOD EnsurePreloadCSP(nsIDocument* aDocument,
+  NS_IMETHOD EnsurePreloadCSP(dom::Document* aDocument,
                               nsIContentSecurityPolicy** aCSP) override;
   NS_IMETHOD GetBaseDomain(nsACString& aBaseDomain) override;
   NS_IMETHOD GetAddonId(nsAString& aAddonId) override;
 
   virtual nsresult GetScriptLocation(nsACString& aStr) override;
 
   nsresult GetSiteIdentifier(SiteIdentifier& aSite) override {
     aSite.Init(this);
--- a/caps/nsScriptSecurityManager.cpp
+++ b/caps/nsScriptSecurityManager.cpp
@@ -385,17 +385,17 @@ nsresult nsScriptSecurityManager::GetCha
  * that may or may not inherit)."
  */
 NS_IMETHODIMP
 nsScriptSecurityManager::GetChannelURIPrincipal(nsIChannel* aChannel,
                                                 nsIPrincipal** aPrincipal) {
   MOZ_ASSERT(aChannel, "Must have channel!");
 
   // Get the principal from the URI.  Make sure this does the same thing
-  // as nsIDocument::Reset and XULDocument::StartDocumentLoad.
+  // as Document::Reset and XULDocument::StartDocumentLoad.
   nsCOMPtr<nsIURI> uri;
   nsresult rv = NS_GetFinalChannelURI(aChannel, getter_AddRefs(uri));
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsCOMPtr<nsILoadInfo> loadInfo;
   aChannel->GetLoadInfo(getter_AddRefs(loadInfo));
 
   // Inherit the origin attributes from loadInfo.
--- a/chrome/nsChromeRegistry.cpp
+++ b/chrome/nsChromeRegistry.cpp
@@ -13,17 +13,17 @@
 #include "nsEscape.h"
 #include "nsNetUtil.h"
 #include "nsString.h"
 #include "nsQueryObject.h"
 
 #include "mozilla/dom/URL.h"
 #include "nsDOMWindowList.h"
 #include "nsIConsoleService.h"
-#include "nsIDocument.h"
+#include "mozilla/dom/Document.h"
 #include "nsIDOMWindow.h"
 #include "nsIObserverService.h"
 #include "nsIPresShell.h"
 #include "nsIScriptError.h"
 #include "nsIWindowMediator.h"
 #include "nsIPrefService.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/Printf.h"
@@ -34,16 +34,17 @@
 
 #include "unicode/uloc.h"
 
 nsChromeRegistry* nsChromeRegistry::gChromeRegistry;
 
 // DO NOT use namespace mozilla; it'll break due to a naming conflict between
 // mozilla::TextRange and a TextRange in OSX headers.
 using mozilla::StyleSheet;
+using mozilla::dom::Document;
 using mozilla::dom::IsChromeURI;
 using mozilla::dom::Location;
 
 ////////////////////////////////////////////////////////////////////////////////
 
 void nsChromeRegistry::LogMessage(const char* aMsg, ...) {
   nsCOMPtr<nsIConsoleService> console(
       do_GetService(NS_CONSOLESERVICE_CONTRACTID));
@@ -270,17 +271,17 @@ nsChromeRegistry::ConvertChromeURL(nsIUR
 }
 
 ////////////////////////////////////////////////////////////////////////
 
 // theme stuff
 
 static void FlushSkinBindingsForWindow(nsPIDOMWindowOuter* aWindow) {
   // Get the document.
-  nsCOMPtr<nsIDocument> document = aWindow->GetDoc();
+  RefPtr<Document> document = aWindow->GetDoc();
   if (!document) return;
 
   // Annihilate all XBL bindings.
   document->FlushSkinBindings();
 }
 
 // XXXbsmedberg: move this to nsIWindowMediator
 NS_IMETHODIMP nsChromeRegistry::RefreshSkins() {
@@ -334,17 +335,17 @@ nsresult nsChromeRegistry::RefreshWindow
   uint32_t length = frames->GetLength();
   for (uint32_t j = 0; j < length; j++) {
     nsCOMPtr<nsPIDOMWindowOuter> piWindow = frames->IndexedGetter(j);
     RefreshWindow(piWindow);
   }
 
   nsresult rv;
   // Get the document.
-  nsCOMPtr<nsIDocument> document = aWindow->GetDoc();
+  RefPtr<Document> document = aWindow->GetDoc();
   if (!document) return NS_OK;
 
   // Deal with the agent sheets first.  Have to do all the style sets by hand.
   nsCOMPtr<nsIPresShell> shell = document->GetShell();
   if (shell) {
     // Reload only the chrome URL agent style sheets.
     nsTArray<RefPtr<StyleSheet>> agentSheets;
     rv = shell->GetAgentStyleSheets(agentSheets);
--- a/devtools/client/shared/widgets/Chart.js
+++ b/devtools/client/shared/widgets/Chart.js
@@ -69,17 +69,17 @@ function PieTableChart(node, pie, table)
   this.pie = pie;
   this.table = table;
   EventEmitter.decorate(this);
 }
 
 /**
  * Creates the DOM for a pie+table chart.
  *
- * @param nsIDocument document
+ * @param Document document
  *        The document responsible with creating the DOM.
  * @param object
  *        An object containing all or some of the following properties:
  *          - title: a string displayed as the table chart's (description)/local
  *          - diameter: the diameter of the pie chart, in pixels
  *          - data: an array of items used to display each slice in the pie
  *                  and each row in the table;
  *                  @see `createPieChart` and `createTableChart` for details.
@@ -156,17 +156,17 @@ function createPieTableChart(document,
   });
 
   return proxy;
 }
 
 /**
  * Creates the DOM for a pie chart based on the specified properties.
  *
- * @param nsIDocument document
+ * @param Document document
  *        The document responsible with creating the DOM.
  * @param object
  *        An object containing all or some of the following properties:
  *          - data: an array of items used to display each slice; all the items
  *                  should be objects containing a `size` and a `label` property.
  *                  e.g: [{
  *                    size: 1,
  *                    label: "foo"
@@ -288,17 +288,17 @@ function createPieChart(document, { data
   }
 
   return proxy;
 }
 
 /**
  * Creates the DOM for a table chart based on the specified properties.
  *
- * @param nsIDocument document
+ * @param Document document
  *        The document responsible with creating the DOM.
  * @param object
  *        An object containing all or some of the following properties:
  *          - title: a string displayed as the chart's (description)/local
  *          - data: an array of items used to display each row; all the items
  *                  should be objects representing columns, for which the
  *                  properties' values will be displayed in each cell of a row.
  *                  e.g: [{
--- a/devtools/docs/getting-started/README.md
+++ b/devtools/docs/getting-started/README.md
@@ -2,11 +2,11 @@
 
 1. Learn [where the code is](./where-is-the-code.md) and about the [architecture](./architecture-overview.md) of the tools.
 2. [Set up your machine](./build.md) to build the tools, then [configure a development profile](development-profiles.md).
 3. You can now experiment by changing things and rebuilding, look at the [files and directories overview](../files/README.md) or you could also [find something to work on](../bugs-issues.md).
 
 ## Additional documentation
 
 * [MDN Web Docs](http://developer.mozilla.org/) (also known as *MDN*) has a lot of information about XUL elements, HTML, JS, DOM, Web APIs, Gecko-specific APIs, and more.
-* [DXR](http://dxr.mozilla.org/mozilla-central/source/) is a source code search engine - search for symbols you want to learn about, eg. `nsIDocument`. [Searchfox](http://searchfox.org/mozilla-central/source) is an alternative.
+* [DXR](http://dxr.mozilla.org/mozilla-central/source/) is a source code search engine - search for symbols you want to learn about, eg. `Document`. [Searchfox](http://searchfox.org/mozilla-central/source) is an alternative.
 
 It is a good idea to [add smart keyword searches](https://support.mozilla.org/en-US/kb/how-search-from-address-bar) for DXR and MDN, so you can search faster.
--- a/docshell/base/nsDSURIContentListener.cpp
+++ b/docshell/base/nsDSURIContentListener.cpp
@@ -5,17 +5,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsDocShell.h"
 #include "nsDSURIContentListener.h"
 #include "nsIChannel.h"
 #include "nsServiceManagerUtils.h"
 #include "nsDocShellCID.h"
 #include "nsIWebNavigationInfo.h"
-#include "nsIDocument.h"
+#include "mozilla/dom/Document.h"
 #include "nsIDOMWindow.h"
 #include "nsIHttpChannel.h"
 #include "nsError.h"
 #include "nsContentSecurityManager.h"
 #include "nsDocShellLoadTypes.h"
 #include "nsIInterfaceRequestor.h"
 #include "nsIMultiPartChannel.h"
 
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -77,17 +77,17 @@
 #include "nsIContent.h"
 #include "nsIContentInlines.h"
 #include "nsIContentSecurityPolicy.h"
 #include "nsIContentViewer.h"
 #include "nsIController.h"
 #include "nsICookieService.h"
 #include "nsIDocShellTreeItem.h"
 #include "nsIDocShellTreeOwner.h"
-#include "nsIDocument.h"
+#include "mozilla/dom/Document.h"
 #include "nsIDocumentLoaderFactory.h"
 #include "nsIDOMWindow.h"
 #include "nsIEditingSession.h"
 #include "nsIExternalProtocolService.h"
 #include "nsIFormPOSTActionChannel.h"
 #include "nsIFrame.h"
 #include "nsIGlobalObject.h"
 #include "nsIHttpChannel.h"
@@ -563,33 +563,33 @@ nsDocShell::GetInterface(const nsIID& aI
     *aSink = mContentListener;
   } else if ((aIID.Equals(NS_GET_IID(nsIScriptGlobalObject)) ||
               aIID.Equals(NS_GET_IID(nsIGlobalObject)) ||
               aIID.Equals(NS_GET_IID(nsPIDOMWindowOuter)) ||
               aIID.Equals(NS_GET_IID(mozIDOMWindowProxy)) ||
               aIID.Equals(NS_GET_IID(nsIDOMWindow))) &&
              NS_SUCCEEDED(EnsureScriptEnvironment())) {
     return mScriptGlobal->QueryInterface(aIID, aSink);
-  } else if (aIID.Equals(NS_GET_IID(nsIDocument)) &&
+  } else if (aIID.Equals(NS_GET_IID(Document)) &&
              NS_SUCCEEDED(EnsureContentViewer())) {
-    nsCOMPtr<nsIDocument> doc = mContentViewer->GetDocument();
+    RefPtr<Document> doc = mContentViewer->GetDocument();
     doc.forget(aSink);
     return *aSink ? NS_OK : NS_NOINTERFACE;
   } else if (aIID.Equals(NS_GET_IID(nsIApplicationCacheContainer))) {
     *aSink = nullptr;
 
     // Return application cache associated with this docshell, if any
 
     nsCOMPtr<nsIContentViewer> contentViewer;
     GetContentViewer(getter_AddRefs(contentViewer));
     if (!contentViewer) {
       return NS_ERROR_NO_INTERFACE;
     }
 
-    nsCOMPtr<nsIDocument> doc = contentViewer->GetDocument();
+    RefPtr<Document> doc = contentViewer->GetDocument();
     NS_ASSERTION(doc, "Should have a document.");
     if (!doc) {
       return NS_ERROR_NO_INTERFACE;
     }
 
 #if defined(DEBUG)
     MOZ_LOG(
         gDocShellLog, LogLevel::Debug,
@@ -1025,21 +1025,21 @@ nsDOMNavigationTiming* nsDocShell::GetNa
   if (nsContentUtils::GetCurrentJSContext() &&
       nsContentUtils::IsCallerChrome()) {
     return true;
   }
 
   MOZ_ASSERT(aOriginTreeItem && aTargetTreeItem, "need two docshells");
 
   // Get origin document principal
-  nsCOMPtr<nsIDocument> originDocument = aOriginTreeItem->GetDocument();
+  RefPtr<Document> originDocument = aOriginTreeItem->GetDocument();
   NS_ENSURE_TRUE(originDocument, false);
 
   // Get target principal
-  nsCOMPtr<nsIDocument> targetDocument = aTargetTreeItem->GetDocument();
+  RefPtr<Document> targetDocument = aTargetTreeItem->GetDocument();
   NS_ENSURE_TRUE(targetDocument, false);
 
   bool equal;
   nsresult rv = originDocument->NodePrincipal()->Equals(
       targetDocument->NodePrincipal(), &equal);
   if (NS_SUCCEEDED(rv) && equal) {
     return true;
   }
@@ -1204,31 +1204,31 @@ bool nsDocShell::SetCurrentURI(nsIURI* a
 }
 
 NS_IMETHODIMP
 nsDocShell::GetCharset(nsACString& aCharset) {
   aCharset.Truncate();
 
   nsIPresShell* presShell = GetPresShell();
   NS_ENSURE_TRUE(presShell, NS_ERROR_FAILURE);
-  nsIDocument* doc = presShell->GetDocument();
+  Document* doc = presShell->GetDocument();
   NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE);
   doc->GetDocumentCharacterSet()->Name(aCharset);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDocShell::GatherCharsetMenuTelemetry() {
   nsCOMPtr<nsIContentViewer> viewer;
   GetContentViewer(getter_AddRefs(viewer));
   if (!viewer) {
     return NS_OK;
   }
 
-  nsIDocument* doc = viewer->GetDocument();
+  Document* doc = viewer->GetDocument();
   if (!doc || doc->WillIgnoreCharsetOverride()) {
     return NS_OK;
   }
 
   Telemetry::ScalarSet(Telemetry::ScalarID::ENCODING_OVERRIDE_USED, true);
 
   bool isFileURL = false;
   nsIURI* url = doc->GetOriginalURI();
@@ -1341,97 +1341,97 @@ void nsDocShell::GetParentCharset(const 
                                   nsIPrincipal** aPrincipal) {
   aCharset = mParentCharset;
   *aCharsetSource = mParentCharsetSource;
   NS_IF_ADDREF(*aPrincipal = mParentCharsetPrincipal);
 }
 
 NS_IMETHODIMP
 nsDocShell::GetHasMixedActiveContentLoaded(bool* aHasMixedActiveContentLoaded) {
-  nsCOMPtr<nsIDocument> doc(GetDocument());
+  RefPtr<Document> doc(GetDocument());
   *aHasMixedActiveContentLoaded = doc && doc->GetHasMixedActiveContentLoaded();
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDocShell::GetHasMixedActiveContentBlocked(
     bool* aHasMixedActiveContentBlocked) {
-  nsCOMPtr<nsIDocument> doc(GetDocument());
+  RefPtr<Document> doc(GetDocument());
   *aHasMixedActiveContentBlocked =
       doc && doc->GetHasMixedActiveContentBlocked();
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDocShell::GetHasMixedDisplayContentLoaded(
     bool* aHasMixedDisplayContentLoaded) {
-  nsCOMPtr<nsIDocument> doc(GetDocument());
+  RefPtr<Document> doc(GetDocument());
   *aHasMixedDisplayContentLoaded =
       doc && doc->GetHasMixedDisplayContentLoaded();
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDocShell::GetHasMixedDisplayContentBlocked(
     bool* aHasMixedDisplayContentBlocked) {
-  nsCOMPtr<nsIDocument> doc(GetDocument());
+  RefPtr<Document> doc(GetDocument());
   *aHasMixedDisplayContentBlocked =
       doc && doc->GetHasMixedDisplayContentBlocked();
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDocShell::GetHasTrackingContentBlocked(bool* aHasTrackingContentBlocked) {
-  nsCOMPtr<nsIDocument> doc(GetDocument());
+  RefPtr<Document> doc(GetDocument());
   *aHasTrackingContentBlocked = doc && doc->GetHasTrackingContentBlocked();
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDocShell::GetHasTrackingContentLoaded(bool* aHasTrackingContentLoaded) {
-  nsCOMPtr<nsIDocument> doc(GetDocument());
+  RefPtr<Document> doc(GetDocument());
   *aHasTrackingContentLoaded = doc && doc->GetHasTrackingContentLoaded();
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDocShell::GetHasCookiesBlockedByPermission(
     bool* aHasCookiesBlockedByPermission) {
-  nsCOMPtr<nsIDocument> doc(GetDocument());
+  RefPtr<Document> doc(GetDocument());
   *aHasCookiesBlockedByPermission =
       doc && doc->GetHasCookiesBlockedByPermission();
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDocShell::GetHasCookiesBlockedDueToTrackers(
     bool* aHasCookiesBlockedDueToTrackers) {
-  nsCOMPtr<nsIDocument> doc(GetDocument());
+  RefPtr<Document> doc(GetDocument());
   *aHasCookiesBlockedDueToTrackers = doc && doc->GetHasTrackingCookiesBlocked();
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDocShell::GetHasAllCookiesBeenBlocked(bool* aHasAllCookiesBeenBlocked) {
-  nsCOMPtr<nsIDocument> doc(GetDocument());
+  RefPtr<Document> doc(GetDocument());
   *aHasAllCookiesBeenBlocked = doc && doc->GetHasAllCookiesBlocked();
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDocShell::GetHasForeignCookiesBeenBlocked(
     bool* aHasForeignCookiesBeenBlocked) {
-  nsCOMPtr<nsIDocument> doc(GetDocument());
+  RefPtr<Document> doc(GetDocument());
   *aHasForeignCookiesBeenBlocked = doc && doc->GetHasForeignCookiesBlocked();
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDocShell::GetHasCookiesLoaded(bool* aHasCookiesLoaded) {
-  nsCOMPtr<nsIDocument> doc(GetDocument());
+  RefPtr<Document> doc(GetDocument());
   *aHasCookiesLoaded = doc && doc->GetHasCookiesLoaded();
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDocShell::GetAllowPlugins(bool* aAllowPlugins) {
   NS_ENSURE_ARG_POINTER(aAllowPlugins);
 
@@ -1874,17 +1874,17 @@ void nsDocShell::SetOrientationLock(hal:
 
 NS_IMETHODIMP
 nsDocShell::GetMayEnableCharacterEncodingMenu(
     bool* aMayEnableCharacterEncodingMenu) {
   *aMayEnableCharacterEncodingMenu = false;
   if (!mContentViewer) {
     return NS_OK;
   }
-  nsIDocument* doc = mContentViewer->GetDocument();
+  Document* doc = mContentViewer->GetDocument();
   if (!doc) {
     return NS_OK;
   }
   if (doc->WillIgnoreCharsetOverride()) {
     return NS_OK;
   }
 
   *aMayEnableCharacterEncodingMenu = true;
@@ -2233,17 +2233,17 @@ nsIDOMStorageManager* nsDocShell::TopSes
 NS_IMETHODIMP
 nsDocShell::GetCurrentDocumentChannel(nsIChannel** aResult) {
   NS_IF_ADDREF(*aResult = GetCurrentDocChannel());
   return NS_OK;
 }
 
 nsIChannel* nsDocShell::GetCurrentDocChannel() {
   if (mContentViewer) {
-    nsIDocument* doc = mContentViewer->GetDocument();
+    Document* doc = mContentViewer->GetDocument();
     if (doc) {
       return doc->GetChannel();
     }
   }
   return nullptr;
 }
 
 NS_IMETHODIMP
@@ -2471,17 +2471,17 @@ void nsDocShell::MaybeCreateInitialClien
   }
 
   nsIPrincipal* principal =
       aPrincipal ? aPrincipal : GetInheritedPrincipal(false);
 
   // Sometimes there is no principal available when we are called from
   // CreateAboutBlankContentViewer.  For example, sometimes the principal
   // is only extracted from the load context after the document is created
-  // in nsIDocument::ResetToURI().  Ideally we would do something similar
+  // in Document::ResetToURI().  Ideally we would do something similar
   // here, but for now lets just avoid the issue by not preallocating the
   // client.
   if (!principal) {
     return;
   }
 
   nsCOMPtr<nsPIDOMWindowOuter> win = GetWindow();
   if (!win) {
@@ -2526,17 +2526,17 @@ Maybe<ClientInfo> nsDocShell::GetInitial
   if (mInitialClientSource) {
     Maybe<ClientInfo> result;
     result.emplace(mInitialClientSource->Info());
     return result;
   }
 
   nsGlobalWindowInner* innerWindow =
       mScriptGlobal ? mScriptGlobal->GetCurrentInnerWindowInternal() : nullptr;
-  nsIDocument* doc = innerWindow ? innerWindow->GetExtantDoc() : nullptr;
+  Document* doc = innerWindow ? innerWindow->GetExtantDoc() : nullptr;
 
   if (!doc || !doc->IsInitialDocument()) {
     return Maybe<ClientInfo>();
   }
 
   return innerWindow->GetClientInfo();
 }
 
@@ -2850,30 +2850,30 @@ bool nsDocShell::CanAccessItem(nsIDocShe
 
   // When the first party isolation is on, the top-level docShell may not have
   // the firstPartyDomain in its originAttributes, but its document will have
   // it. So we get the firstPartyDomain from the nodePrincipal of the document
   // before we compare the originAttributes.
   if (OriginAttributes::IsFirstPartyEnabled()) {
     if (aAccessingItem->ItemType() == nsIDocShellTreeItem::typeContent &&
         (accessingDS == accessingRootDS || accessingDS->GetIsMozBrowser())) {
-      nsCOMPtr<nsIDocument> accessingDoc = aAccessingItem->GetDocument();
+      RefPtr<Document> accessingDoc = aAccessingItem->GetDocument();
 
       if (accessingDoc) {
         nsCOMPtr<nsIPrincipal> accessingPrincipal =
             accessingDoc->NodePrincipal();
 
         accessingOA.mFirstPartyDomain =
             accessingPrincipal->OriginAttributesRef().mFirstPartyDomain;
       }
     }
 
     if (aTargetItem->ItemType() == nsIDocShellTreeItem::typeContent &&
         (targetDS == targetRootDS || targetDS->GetIsMozBrowser())) {
-      nsCOMPtr<nsIDocument> targetDoc = aAccessingItem->GetDocument();
+      RefPtr<Document> targetDoc = aAccessingItem->GetDocument();
 
       if (targetDoc) {
         nsCOMPtr<nsIPrincipal> targetPrincipal = targetDoc->NodePrincipal();
 
         targetOA.mFirstPartyDomain =
             targetPrincipal->OriginAttributesRef().mFirstPartyDomain;
       }
     }
@@ -3085,17 +3085,17 @@ bool nsDocShell::IsSandboxedFrom(nsIDocS
   if (aTargetDocShell == this) {
     return false;
   }
 
   // Default the sandbox flags to our flags, so that if we can't retrieve the
   // active document, we will still enforce our own.
   uint32_t sandboxFlags = mSandboxFlags;
   if (mContentViewer) {
-    nsCOMPtr<nsIDocument> doc = mContentViewer->GetDocument();
+    RefPtr<Document> doc = mContentViewer->GetDocument();
     if (doc) {
       sandboxFlags = doc->GetSandboxFlags();
     }
   }
 
   // If no flags, we are not sandboxed at all.
   if (!sandboxFlags) {
     return false;
@@ -3322,17 +3322,17 @@ nsDocShell::AddChild(nsIDocShellTreeItem
   if (mItemType == nsIDocShellTreeItem::typeChrome) {
     return NS_OK;
   }
 
   // get the parent's current charset
   if (!mContentViewer) {
     return NS_OK;
   }
-  nsIDocument* doc = mContentViewer->GetDocument();
+  Document* doc = mContentViewer->GetDocument();
   if (!doc) {
     return NS_OK;
   }
 
   bool isWyciwyg = false;
 
   if (mCurrentURI) {
     // Check if the url is wyciwyg
@@ -3662,17 +3662,17 @@ nsDocShell::GetCurrentSHEntry(nsISHEntry
   return NS_OK;
 }
 
 nsIScriptGlobalObject* nsDocShell::GetScriptGlobalObject() {
   NS_ENSURE_SUCCESS(EnsureScriptEnvironment(), nullptr);
   return mScriptGlobal;
 }
 
-nsIDocument* nsDocShell::GetDocument() {
+Document* nsDocShell::GetDocument() {
   NS_ENSURE_SUCCESS(EnsureContentViewer(), nullptr);
   return mContentViewer->GetDocument();
 }
 
 nsPIDOMWindowOuter* nsDocShell::GetWindow() {
   if (NS_FAILED(EnsureScriptEnvironment())) {
     return nullptr;
   }
@@ -3707,17 +3707,17 @@ NS_IMETHODIMP
 nsDocShell::GetContentBlockingLog(Promise** aPromise) {
   NS_ENSURE_ARG_POINTER(aPromise);
 
   if (!mContentViewer) {
     *aPromise = nullptr;
     return NS_ERROR_FAILURE;
   }
 
-  nsIDocument* doc = mContentViewer->GetDocument();
+  Document* doc = mContentViewer->GetDocument();
   ErrorResult rv;
   RefPtr<Promise> promise = Promise::Create(doc->GetOwnerGlobal(), rv);
   if (NS_WARN_IF(rv.Failed())) {
     return rv.StealNSResult();
   }
   promise->MaybeResolve(doc->GetContentBlockingLog()->Stringify());
   promise.forget(aPromise);
   return NS_OK;
@@ -4609,17 +4609,17 @@ nsDocShell::Reload(uint32_t aReloadFlags
 
   /* If you change this part of code, make sure bug 45297 does not re-occur */
   if (mOSHE) {
     rv = LoadHistoryEntry(mOSHE, loadType);
   } else if (mLSHE) {  // In case a reload happened before the current load is
                        // done
     rv = LoadHistoryEntry(mLSHE, loadType);
   } else {
-    nsCOMPtr<nsIDocument> doc(GetDocument());
+    RefPtr<Document> doc(GetDocument());
 
     if (!doc) {
       return NS_OK;
     }
 
     // Do not inherit owner from document
     uint32_t flags = INTERNAL_LOAD_FLAGS_NONE;
     nsAutoString srcdoc;
@@ -4735,21 +4735,21 @@ nsDocShell::Stop(uint32_t aStopFlags) {
       shellAsNav->Stop(aStopFlags);
     }
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsDocShell::GetDocument(nsIDocument** aDocument) {
+nsDocShell::GetDocument(Document** aDocument) {
   NS_ENSURE_ARG_POINTER(aDocument);
   NS_ENSURE_SUCCESS(EnsureContentViewer(), NS_ERROR_FAILURE);
 
-  nsCOMPtr<nsIDocument> doc = mContentViewer->GetDocument();
+  RefPtr<Document> doc = mContentViewer->GetDocument();
   if (!doc) {
     return NS_ERROR_NOT_AVAILABLE;
   }
 
   doc.forget(aDocument);
   return NS_OK;
 }
 
@@ -5173,17 +5173,17 @@ nsDocShell::GetPositionAndSize(int32_t* 
     SetPositionAndSize(mBounds.X(), mBounds.Y(), r.Width(), r.Height(), 0);
   }
 
   // We should really consider just getting this information from
   // our window instead of duplicating the storage and code...
   if (aWidth || aHeight) {
     // Caller wants to know our size; make sure to give them up to
     // date information.
-    nsCOMPtr<nsIDocument> doc(do_GetInterface(GetAsSupports(mParent)));
+    RefPtr<Document> doc(do_GetInterface(GetAsSupports(mParent)));
     if (doc) {
       doc->FlushPendingNotifications(FlushType::Layout);
     }
   }
 
   DoGetPositionAndSize(aX, aY, aWidth, aHeight);
   return NS_OK;
 }
@@ -5366,17 +5366,17 @@ nsDocShell::SetIsActive(bool aIsActive) 
   nsCOMPtr<nsIPresShell> pshell = GetPresShell();
   if (pshell) {
     pshell->SetIsActive(aIsActive);
   }
 
   // Tell the window about it
   if (mScriptGlobal) {
     mScriptGlobal->SetIsBackground(!aIsActive);
-    if (nsCOMPtr<nsIDocument> doc = mScriptGlobal->GetExtantDoc()) {
+    if (RefPtr<Document> doc = mScriptGlobal->GetExtantDoc()) {
       // Update orientation when the top-level browsing context becomes active.
       if (aIsActive) {
         nsCOMPtr<nsIDocShellTreeItem> parent;
         GetSameTypeParent(getter_AddRefs(parent));
         if (!parent) {
           // We only care about the top-level browsing context.
           uint16_t orientation = OrientationLock();
           ScreenOrientation::UpdateActiveOrientationLock(orientation);
@@ -5385,17 +5385,17 @@ nsDocShell::SetIsActive(bool aIsActive) 
 
       doc->PostVisibilityUpdateEvent();
     }
   }
 
   // Tell the nsDOMNavigationTiming about it
   RefPtr<nsDOMNavigationTiming> timing = mTiming;
   if (!timing && mContentViewer) {
-    nsIDocument* doc = mContentViewer->GetDocument();
+    Document* doc = mContentViewer->GetDocument();
     if (doc) {
       timing = doc->GetNavigationTiming();
     }
   }
   if (timing) {
     timing->NotifyDocShellStateChanged(
         aIsActive ? nsDOMNavigationTiming::DocShellState::eActive
                   : nsDOMNavigationTiming::DocShellState::eInactive);
@@ -5533,17 +5533,17 @@ nsDocShell::SetMixedContentChannel(nsICh
 #endif
   mMixedContentChannel = aMixedContentChannel;
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDocShell::GetFailedChannel(nsIChannel** aFailedChannel) {
   NS_ENSURE_ARG_POINTER(aFailedChannel);
-  nsIDocument* doc = GetDocument();
+  Document* doc = GetDocument();
   if (!doc) {
     *aFailedChannel = nullptr;
     return NS_OK;
   }
   NS_IF_ADDREF(*aFailedChannel = doc->GetFailedChannel());
   return NS_OK;
 }
 
@@ -5566,17 +5566,17 @@ nsDocShell::GetAllowMixedContentAndConne
   GetSameTypeRootTreeItem(getter_AddRefs(sameTypeRoot));
   NS_ASSERTION(
       sameTypeRoot,
       "No document shell root tree item from document shell tree item!");
   *aIsRootDocShell =
       sameTypeRoot.get() == static_cast<nsIDocShellTreeItem*>(this);
 
   // now get the document from sameTypeRoot
-  nsCOMPtr<nsIDocument> rootDoc = sameTypeRoot->GetDocument();
+  RefPtr<Document> rootDoc = sameTypeRoot->GetDocument();
   if (rootDoc) {
     nsCOMPtr<nsIPrincipal> rootPrincipal = rootDoc->NodePrincipal();
 
     // For things with system principal (e.g. scratchpad) there is no uri
     // aRootHasSecureConnection should be false.
     nsCOMPtr<nsIURI> rootUri;
     if (nsContentUtils::IsSystemPrincipal(rootPrincipal) ||
         NS_FAILED(rootPrincipal->GetURI(getter_AddRefs(rootUri))) || !rootUri ||
@@ -5886,17 +5886,17 @@ nsDocShell::ForceRefreshURI(nsIURI* aURI
   loadState->SetResultPrincipalURI(aURI);
   loadState->SetResultPrincipalURIIsSome(true);
   loadState->SetKeepResultPrincipalURIIfSet(true);
 
   // Set the triggering pricipal to aPrincipal if available, or current
   // document's principal otherwise.
   nsCOMPtr<nsIPrincipal> principal = aPrincipal;
   if (!principal) {
-    nsCOMPtr<nsIDocument> doc = GetDocument();
+    RefPtr<Document> doc = GetDocument();
     if (!doc) {
       return NS_ERROR_FAILURE;
     }
     principal = doc->NodePrincipal();
   }
   loadState->SetTriggeringPrincipal(principal);
   loadState->SetPrincipalIsExplicit(true);
 
@@ -6799,17 +6799,17 @@ nsresult nsDocShell::EndPageLoad(nsIWebP
 
       // Parent window
       nsCOMPtr<nsIDocShellTreeItem> parentItem;
       GetSameTypeParent(getter_AddRefs(parentItem));
       if (!parentItem) {
         return NS_OK;
       }
 
-      nsCOMPtr<nsIDocument> parentDoc;
+      RefPtr<Document> parentDoc;
       parentDoc = parentItem->GetDocument();
       if (!parentDoc) {
         return NS_OK;
       }
 
       parentDoc->AddBlockedTrackingNode(frameElement);
 
       return NS_OK;
@@ -7046,17 +7046,17 @@ nsresult nsDocShell::EnsureContentViewer
     }
   }
 
   nsresult rv = CreateAboutBlankContentViewer(principal, baseURI);
 
   NS_ENSURE_STATE(mContentViewer);
 
   if (NS_SUCCEEDED(rv)) {
-    nsCOMPtr<nsIDocument> doc(GetDocument());
+    RefPtr<Document> doc(GetDocument());
     NS_ASSERTION(doc,
                  "Should have doc if CreateAboutBlankContentViewer "
                  "succeeded!");
 
     doc->SetIsInitialDocument(true);
 
     // Documents created using EnsureContentViewer may be transient
     // placeholders created by framescripts before content has a chance to
@@ -7069,17 +7069,17 @@ nsresult nsDocShell::EnsureContentViewer
   }
 
   return rv;
 }
 
 nsresult nsDocShell::CreateAboutBlankContentViewer(
     nsIPrincipal* aPrincipal, nsIURI* aBaseURI, bool aTryToSaveOldPresentation,
     bool aCheckPermitUnload) {
-  nsCOMPtr<nsIDocument> blankDoc;
+  RefPtr<Document> blankDoc;
   nsCOMPtr<nsIContentViewer> viewer;
   nsresult rv = NS_ERROR_FAILURE;
 
   /* mCreatingDocument should never be true at this point. However, it's
      a theoretical possibility. We want to know about it and make it stop,
      and this sounds like a job for an assertion. */
   NS_ASSERTION(!mCreatingDocument,
                "infinite(?) loop creating document averted");
@@ -7217,17 +7217,17 @@ nsresult nsDocShell::CreateAboutBlankCon
 
 NS_IMETHODIMP
 nsDocShell::CreateAboutBlankContentViewer(nsIPrincipal* aPrincipal) {
   return CreateAboutBlankContentViewer(aPrincipal, nullptr);
 }
 
 bool nsDocShell::CanSavePresentation(uint32_t aLoadType,
                                      nsIRequest* aNewRequest,
-                                     nsIDocument* aNewDocument) {
+                                     Document* aNewDocument) {
   if (!mOSHE) {
     return false;  // no entry to save into
   }
 
   nsCOMPtr<nsIContentViewer> viewer = mOSHE->GetContentViewer();
   if (viewer) {
     NS_WARNING("mOSHE already has a content viewer!");
     return false;
@@ -7267,17 +7267,17 @@ bool nsDocShell::CanSavePresentation(uin
   // Don't cache the content viewer if we're in a subframe.
   nsCOMPtr<nsIDocShellTreeItem> root;
   GetSameTypeParent(getter_AddRefs(root));
   if (root && root != this) {
     return false;  // this is a subframe load
   }
 
   // If the document does not want its presentation cached, then don't.
-  nsCOMPtr<nsIDocument> doc = mScriptGlobal->GetExtantDoc();
+  RefPtr<Document> doc = mScriptGlobal->GetExtantDoc();
   return doc && doc->CanSavePresentation(aNewRequest);
 }
 
 void nsDocShell::ReattachEditorToWindow(nsISHEntry* aSHEntry) {
   MOZ_ASSERT(!mIsBeingDestroyed);
 
   NS_ASSERTION(!mEditorData,
                "Why reattach an editor when we already have one?");
@@ -7402,17 +7402,17 @@ nsDocShell::BeginRestore(nsIContentViewe
     aContentViewer = mContentViewer;
   }
 
   // Dispatch events for restoring the presentation.  We try to simulate
   // the progress notifications loading the document would cause, so we add
   // the document's channel to the loadgroup to initiate stateChange
   // notifications.
 
-  nsCOMPtr<nsIDocument> doc = aContentViewer->GetDocument();
+  RefPtr<Document> doc = aContentViewer->GetDocument();
   if (doc) {
     nsIChannel* channel = doc->GetChannel();
     if (channel) {
       mEODForCurrentDocument = false;
       mIsRestoringDocument = true;
       mLoadGroup->AddRequest(channel, nullptr);
       mIsRestoringDocument = false;
     }
@@ -7460,17 +7460,17 @@ nsDocShell::FinishRestore() {
       child->FinishRestore();
     }
   }
 
   if (mOSHE && mOSHE->HasDetachedEditor()) {
     ReattachEditorToWindow(mOSHE);
   }
 
-  nsCOMPtr<nsIDocument> doc = GetDocument();
+  RefPtr<Document> doc = GetDocument();
   if (doc) {
     // Finally, we remove the request from the loadgroup.  This will
     // cause onStateChange(STATE_STOP) to fire, which will fire the
     // pageshow event to the chrome.
 
     nsIChannel* channel = doc->GetChannel();
     if (channel) {
       mIsRestoringDocument = true;
@@ -7605,17 +7605,17 @@ nsresult nsDocShell::RestoreFromHistory(
     return NS_ERROR_FAILURE;
   }
 
   if (mSavingOldViewer) {
     // We determined that it was safe to cache the document presentation
     // at the time we initiated the new load.  We need to check whether
     // it's still safe to do so, since there may have been DOM mutations
     // or new requests initiated.
-    nsCOMPtr<nsIDocument> doc = viewer->GetDocument();
+    RefPtr<Document> doc = viewer->GetDocument();
     nsIRequest* request = nullptr;
     if (doc) {
       request = doc->GetChannel();
     }
     mSavingOldViewer = CanSavePresentation(mLoadType, request, doc);
   }
 
   nsCOMPtr<nsIContentViewer> oldCv(mContentViewer);
@@ -7741,17 +7741,17 @@ nsresult nsDocShell::RestoreFromHistory(
         rootViewParent = oldRootView->GetParent();
 
         mContentViewer->GetBounds(newBounds);
       }
     }
   }
 
   nsCOMPtr<nsIContent> container;
-  nsCOMPtr<nsIDocument> sibling;
+  RefPtr<Document> sibling;
   if (rootViewParent && rootViewParent->GetParent()) {
     nsIFrame* frame = rootViewParent->GetParent()->GetFrame();
     container = frame ? frame->GetContent() : nullptr;
   }
   if (rootViewSibling) {
     nsIFrame* frame = rootViewSibling->GetFrame();
     sibling = frame ? frame->PresShell()->GetDocument() : nullptr;
   }
@@ -7782,17 +7782,17 @@ nsresult nsDocShell::RestoreFromHistory(
 
   // Grab all of the related presentation from the SHEntry now.
   // Clearing the viewer from the SHEntry will clear all of this state.
   nsCOMPtr<nsISupports> windowState = mLSHE->GetWindowState();
   mLSHE->SetWindowState(nullptr);
 
   bool sticky = mLSHE->GetSticky();
 
-  nsCOMPtr<nsIDocument> document = mContentViewer->GetDocument();
+  RefPtr<Document> document = mContentViewer->GetDocument();
 
   nsCOMArray<nsIDocShellTreeItem> childShells;
   int32_t i = 0;
   nsCOMPtr<nsIDocShellTreeItem> child;
   while (NS_SUCCEEDED(mLSHE->ChildShellAt(i++, getter_AddRefs(child))) &&
          child) {
     childShells.AppendObject(child);
   }
@@ -7863,17 +7863,17 @@ nsresult nsDocShell::RestoreFromHistory(
     newCv->SetFullZoom(pageZoom);
     newCv->SetOverrideDPPX(overrideDPPX);
     newCv->SetAuthorStyleDisabled(styleDisabled);
   }
 
   if (document) {
     RefPtr<nsDocShell> parent = GetParentDocshell();
     if (parent) {
-      nsCOMPtr<nsIDocument> d = parent->GetDocument();
+      RefPtr<Document> d = parent->GetDocument();
       if (d) {
         if (d->EventHandlingSuppressed()) {
           document->SuppressEventHandling(d->EventHandlingSuppressed());
         }
       }
     }
 
     // Use the uri from the mLSHE we had when we entered this function
@@ -8118,17 +8118,17 @@ nsresult nsDocShell::CreateContentViewer
   // wrong information :-(
   //
 
   if (mSavingOldViewer) {
     // We determined that it was safe to cache the document presentation
     // at the time we initiated the new load.  We need to check whether
     // it's still safe to do so, since there may have been DOM mutations
     // or new requests initiated.
-    nsCOMPtr<nsIDocument> doc = viewer->GetDocument();
+    RefPtr<Document> doc = viewer->GetDocument();
     mSavingOldViewer = CanSavePresentation(mLoadType, aRequest, doc);
   }
 
   NS_ASSERTION(!mLoadingURI, "Re-entering unload?");
 
   nsCOMPtr<nsIChannel> aOpenedChannel = do_QueryInterface(aRequest);
   if (aOpenedChannel) {
     aOpenedChannel->GetURI(getter_AddRefs(mLoadingURI));
@@ -8157,17 +8157,17 @@ nsresult nsDocShell::CreateContentViewer
     // We need to set the SH entry and our current URI here and not
     // at the moment we load the page. We want the same behavior
     // of Stop() as for a normal page load. See bug 514232 for details.
 
     // Revert mLoadType to load type to state the page load failed,
     // following function calls need it.
     mLoadType = mFailedLoadType;
 
-    nsIDocument* doc = viewer->GetDocument();
+    Document* doc = viewer->GetDocument();
     if (doc) {
       doc->SetFailedChannel(failedChannel);
     }
 
     nsCOMPtr<nsIPrincipal> triggeringPrincipal;
     if (failedChannel) {
       // Make sure we have a URI to set currentURI.
       NS_GetFinalChannelURI(failedChannel, getter_AddRefs(failedURI));
@@ -8263,17 +8263,17 @@ nsresult nsDocShell::CreateContentViewer
   mEODForCurrentDocument = false;
 
   // if this document is part of a multipart document,
   // the ID can be used to distinguish it from the other parts.
   nsCOMPtr<nsIMultiPartChannel> multiPartChannel(do_QueryInterface(aRequest));
   if (multiPartChannel) {
     nsCOMPtr<nsIPresShell> shell = GetPresShell();
     if (NS_SUCCEEDED(rv) && shell) {
-      nsIDocument* doc = shell->GetDocument();
+      Document* doc = shell->GetDocument();
       if (doc) {
         uint32_t partID;
         multiPartChannel->GetPartID(&partID);
         doc->SetPartID(partID);
       }
     }
   }
 
@@ -8487,17 +8487,17 @@ nsresult nsDocShell::SetupNewViewer(nsIC
   // until we have enough of the new page to show.  Just return with the new
   // viewer still set to hidden.
 
   return NS_OK;
 }
 
 nsresult nsDocShell::SetDocCurrentStateObj(nsISHEntry* aShEntry) {
   NS_ENSURE_STATE(mContentViewer);
-  nsCOMPtr<nsIDocument> document = GetDocument();
+  RefPtr<Document> document = GetDocument();
   NS_ENSURE_TRUE(document, NS_ERROR_FAILURE);
 
   nsCOMPtr<nsIStructuredCloneContainer> scContainer;
   if (aShEntry) {
     scContainer = aShEntry->GetStateData();
 
     // If aShEntry is null, just set the document's state object to null.
   }
@@ -8799,17 +8799,17 @@ nsresult nsDocShell::InternalLoad(nsDocS
       if (NS_SUCCEEDED(rv) && shouldLoad == nsIContentPolicy::REJECT_TYPE) {
         return NS_ERROR_CONTENT_BLOCKED_SHOW_ALT;
       }
 
       return NS_ERROR_CONTENT_BLOCKED;
     }
   }
 
-  nsIDocument* doc = mContentViewer ? mContentViewer->GetDocument() : nullptr;
+  Document* doc = mContentViewer ? mContentViewer->GetDocument() : nullptr;
 
   const bool isDocumentAuxSandboxed =
       doc && (doc->GetSandboxFlags() & SANDBOXED_AUXILIARY_NAVIGATION);
 
   if (mLoadURIDelegate && aLoadState->LoadType() != LOAD_ERROR_PAGE &&
       (!targetDocShell || targetDocShell == static_cast<nsIDocShell*>(this))) {
     // Dispatch only load requests for the current or a new window to the
     // delegate, e.g., to allow for GeckoView apps to handle the load event
@@ -8932,17 +8932,17 @@ nsresult nsDocShell::InternalLoad(nsDocS
                                EmptyString(),         // Features
                                getter_AddRefs(newWin));
 
       // In some cases the Open call doesn't actually result in a new
       // window being opened.  We can detect these cases by examining the
       // document in |newWin|, if any.
       nsCOMPtr<nsPIDOMWindowOuter> piNewWin = newWin;
       if (piNewWin) {
-        nsCOMPtr<nsIDocument> newDoc = piNewWin->GetExtantDoc();
+        RefPtr<Document> newDoc = piNewWin->GetExtantDoc();
         if (!newDoc || newDoc->IsInitialDocument()) {
           isNewWindow = true;
           aLoadState->SetLoadFlag(INTERNAL_LOAD_FLAGS_FIRST_LOAD);
         }
       }
 
       nsCOMPtr<nsIWebNavigation> webNav = do_GetInterface(newWin);
       targetDocShell = do_QueryInterface(webNav);
@@ -9085,17 +9085,17 @@ nsresult nsDocShell::InternalLoad(nsDocS
       aLoadState->SourceDocShell()->IsSandboxedFrom(this)) {
     return NS_ERROR_DOM_INVALID_ACCESS_ERR;
   }
 
   // If this docshell is owned by a frameloader, make sure to cancel
   // possible frameloader initialization before loading a new page.
   nsCOMPtr<nsIDocShellTreeItem> parent = GetParentDocshell();
   if (parent) {
-    nsCOMPtr<nsIDocument> doc = parent->GetDocument();
+    RefPtr<Document> doc = parent->GetDocument();
     if (doc) {
       doc->TryCancelFrameLoaderInitialization(this);
     }
   }
 
   bool loadFromExternal = false;
 
   // Before going any further vet loads initiated by external programs.
@@ -9235,17 +9235,17 @@ nsresult nsDocShell::InternalLoad(nsDocS
 
       // we need to assign aLoadState->SHEntry() to mLSHE right here, so that on
       // History loads, SetCurrentURI() called from OnNewURI() will send proper
       // onLocationChange() notifications to the browser to update back/forward
       // buttons.
       SetHistoryEntry(&mLSHE, aLoadState->SHEntry());
 
       // Set the doc's URI according to the new history entry's URI.
-      nsCOMPtr<nsIDocument> doc = GetDocument();
+      RefPtr<Document> doc = GetDocument();
       NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE);
       doc->SetDocumentURI(aLoadState->URI());
 
       /* This is a anchor traversal with in the same page.
        * call OnNewURI() so that, this traversal will be
        * recorded in session and global history.
        */
       nsCOMPtr<nsIPrincipal> newURITriggeringPrincipal,
@@ -9616,17 +9616,17 @@ nsresult nsDocShell::InternalLoad(nsDocS
       return NS_OK;
     }
   }
 
   return rv;
 }
 
 nsIPrincipal* nsDocShell::GetInheritedPrincipal(bool aConsiderCurrentDocument) {
-  nsCOMPtr<nsIDocument> document;
+  RefPtr<Document> document;
   bool inheritedFromCurrent = false;
 
   if (aConsiderCurrentDocument && mContentViewer) {
     document = mContentViewer->GetDocument();
     inheritedFromCurrent = true;
   }
 
   if (!document) {
@@ -9815,17 +9815,17 @@ nsresult nsDocShell::DoURILoad(nsDocShel
   } else {
     loadingWindow = nullptr;
     loadingNode = mScriptGlobal->AsOuter()->GetFrameElementInternal();
     if (loadingNode) {
       // If we have a loading node, then use that as our loadingPrincipal.
       loadingPrincipal = loadingNode->NodePrincipal();
 #ifdef DEBUG
       // Get the docshell type for requestingElement.
-      nsCOMPtr<nsIDocument> requestingDoc = loadingNode->OwnerDoc();
+      RefPtr<Document> requestingDoc = loadingNode->OwnerDoc();
       nsCOMPtr<nsIDocShell> elementDocShell = requestingDoc->GetDocShell();
       // requestingElement docshell type = current docshell type.
       MOZ_ASSERT(
           mItemType == elementDocShell->ItemType(),
           "subframes should have the same docshell type as their parent");
 #endif
     } else {
       // If this isn't a top-level load and mScriptGlobal's frame element is
@@ -10553,17 +10553,17 @@ nsresult nsDocShell::ScrollToAnchor(bool
       free(str);
     }
 
     // Above will fail if the anchor name is not UTF-8.  Need to
     // convert from document charset to unicode.
     if (NS_FAILED(rv)) {
       // Get a document charset
       NS_ENSURE_TRUE(mContentViewer, NS_ERROR_FAILURE);
-      nsIDocument* doc = mContentViewer->GetDocument();
+      Document* doc = mContentViewer->GetDocument();
       NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE);
       nsAutoCString charset;
       doc->GetDocumentCharacterSet()->Name(charset);
 
       nsCOMPtr<nsITextToSubURI> textToSubURI =
           do_GetService(NS_ITEXTTOSUBURI_CONTRACTID, &rv);
       NS_ENSURE_SUCCESS(rv, rv);
 
@@ -10880,17 +10880,17 @@ bool nsDocShell::OnNewURI(nsIURI* aURI, 
 }
 
 bool nsDocShell::OnLoadingSite(nsIChannel* aChannel, bool aFireOnLocationChange,
                                bool aAddToGlobalHistory) {
   nsCOMPtr<nsIURI> uri;
   // If this a redirect, use the final url (uri)
   // else use the original url
   //
-  // Note that this should match what documents do (see nsIDocument::Reset).
+  // Note that this should match what documents do (see Document::Reset).
   NS_GetFinalChannelURI(aChannel, getter_AddRefs(uri));
   NS_ENSURE_TRUE(uri, false);
 
   // Pass false for aCloneSHChildren, since we're loading a new page here.
   return OnNewURI(uri, aChannel, nullptr, nullptr, mLoadType,
                   aFireOnLocationChange, aAddToGlobalHistory, false);
 }
 
@@ -10951,38 +10951,38 @@ nsDocShell::AddState(JS::Handle<JS::Valu
 
   // pushState effectively becomes replaceState when we've started a network
   // load but haven't adopted its document yet.  This mirrors what we do with
   // changes to the hash at this stage of the game.
   if (JustStartedNetworkLoad()) {
     aReplace = true;
   }
 
-  nsCOMPtr<nsIDocument> document = GetDocument();
+  RefPtr<Document> document = GetDocument();
   NS_ENSURE_TRUE(document, NS_ERROR_FAILURE);
 
   // Step 1: Serialize aData using structured clone.
   nsCOMPtr<nsIStructuredCloneContainer> scContainer;
 
   // scContainer->Init might cause arbitrary JS to run, and this code might
   // navigate the page we're on, potentially to a different origin! (bug
   // 634834)  To protect against this, we abort if our principal changes due
   // to the InitFromJSVal() call.
   {
-    nsCOMPtr<nsIDocument> origDocument = GetDocument();
+    RefPtr<Document> origDocument = GetDocument();
     if (!origDocument) {
       return NS_ERROR_DOM_SECURITY_ERR;
     }
     nsCOMPtr<nsIPrincipal> origPrincipal = origDocument->NodePrincipal();
 
     scContainer = new nsStructuredCloneContainer();
     rv = scContainer->InitFromJSVal(aData, aCx);
     NS_ENSURE_SUCCESS(rv, rv);
 
-    nsCOMPtr<nsIDocument> newDocument = GetDocument();
+    RefPtr<Document> newDocument = GetDocument();
     if (!newDocument) {
       return NS_ERROR_DOM_SECURITY_ERR;
     }
     nsCOMPtr<nsIPrincipal> newPrincipal = newDocument->NodePrincipal();
 
     bool principalsEqual = false;
     origPrincipal->Equals(newPrincipal, &principalsEqual);
     NS_ENSURE_TRUE(principalsEqual, NS_ERROR_DOM_SECURITY_ERR);
@@ -12207,17 +12207,17 @@ nsresult nsDocShell::SetBaseUrlForWyciwy
   nsresult rv = NS_ERROR_NOT_AVAILABLE;
 
   if (sURIFixup) {
     rv = sURIFixup->CreateExposableURI(mCurrentURI, getter_AddRefs(baseURI));
   }
 
   // Get the current document and set the base uri
   if (baseURI) {
-    nsIDocument* document = aContentViewer->GetDocument();
+    Document* document = aContentViewer->GetDocument();
     if (document) {
       document->SetBaseURI(baseURI);
     }
   }
   return rv;
 }
 
 //*****************************************************************************
@@ -12344,17 +12344,17 @@ bool nsDocShell::IsOKToLoadURI(nsIURI* a
     return true;
   }
 
   if (!mLoadingURI) {
     return false;
   }
 
   bool isPrivateWin = false;
-  nsIDocument* doc = GetDocument();
+  Document* doc = GetDocument();
   if (doc) {
     isPrivateWin =
         doc->NodePrincipal()->OriginAttributesRef().mPrivateBrowsingId > 0;
   }
 
   nsCOMPtr<nsIScriptSecurityManager> secMan =
       do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID);
   return secMan && NS_SUCCEEDED(secMan->CheckSameOriginURI(
@@ -12673,17 +12673,17 @@ nsDocShell::OnLinkClickSync(nsIContent* 
     }
   }
 
   // Get the owner document of the link that was clicked, this will be
   // the document that the link is in, or the last document that the
   // link was in. From that document, we'll get the URI to use as the
   // referer, since the current URI in this docshell may be a
   // new document that we're in the process of loading.
-  nsCOMPtr<nsIDocument> refererDoc = aContent->OwnerDoc();
+  RefPtr<Document> refererDoc = aContent->OwnerDoc();
   NS_ENSURE_TRUE(refererDoc, NS_ERROR_UNEXPECTED);
 
   // Now check that the refererDoc's inner window is the current inner
   // window for mScriptGlobal.  If it's not, then we don't want to
   // follow this link.
   nsPIDOMWindowInner* refererInner = refererDoc->GetInnerWindow();
   NS_ENSURE_TRUE(refererInner, NS_ERROR_UNEXPECTED);
   if (!mScriptGlobal ||
@@ -12812,17 +12812,17 @@ bool nsDocShell::ShouldBlockLoadingForBa
   return canGoForward;
 }
 
 bool nsDocShell::PluginsAllowedInCurrentDoc() {
   if (!mContentViewer) {
     return false;
   }
 
-  nsIDocument* doc = mContentViewer->GetDocument();
+  Document* doc = mContentViewer->GetDocument();
   if (!doc) {
     return false;
   }
 
   return doc->GetAllowPlugins();
 }
 
 //----------------------------------------------------------------------
@@ -13010,17 +13010,17 @@ bool nsDocShell::CanSetOriginAttributes(
   MOZ_ASSERT(mChildList.IsEmpty());
   if (!mChildList.IsEmpty()) {
     return false;
   }
 
   // TODO: Bug 1273058 - mContentViewer should be null when setting origin
   // attributes.
   if (mContentViewer) {
-    nsIDocument* doc = mContentViewer->GetDocument();
+    Document* doc = mContentViewer->GetDocument();
     if (doc) {
       nsIURI* uri = doc->GetDocumentURI();
       if (!uri) {
         return false;
       }
       nsCString uriSpec = uri->GetSpecOrDefault();
       MOZ_ASSERT(uriSpec.EqualsLiteral("about:blank"));
       if (!uriSpec.EqualsLiteral("about:blank")) {
@@ -13250,19 +13250,19 @@ bool nsDocShell::InFrameSwap() {
 
 UniquePtr<ClientSource> nsDocShell::TakeInitialClientSource() {
   return std::move(mInitialClientSource);
 }
 
 NS_IMETHODIMP
 nsDocShell::IssueWarning(uint32_t aWarning, bool aAsError) {
   if (mContentViewer) {
-    nsCOMPtr<nsIDocument> doc = mContentViewer->GetDocument();
+    RefPtr<Document> doc = mContentViewer->GetDocument();
     if (doc) {
-      doc->WarnOnceAbout(nsIDocument::DeprecatedOperations(aWarning), aAsError);
+      doc->WarnOnceAbout(Document::DeprecatedOperations(aWarning), aAsError);
     }
   }
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDocShell::GetEditingSession(nsIEditingSession** aEditSession) {
   if (!NS_SUCCEEDED(EnsureEditorData())) {
--- a/docshell/base/nsDocShell.h
+++ b/docshell/base/nsDocShell.h
@@ -72,17 +72,16 @@ class ClientSource;
 class EventTarget;
 }  // namespace dom
 }  // namespace mozilla
 
 class nsICommandManager;
 class nsIContentViewer;
 class nsIController;
 class nsIDocShellTreeOwner;
-class nsIDocument;
 class nsIHttpChannel;
 class nsIMutableArray;
 class nsIPrompt;
 class nsIScrollableFrame;
 class nsISecureBrowserUI;
 class nsISHistory;
 class nsIStringBundle;
 class nsIURIFixup;
@@ -724,17 +723,17 @@ class nsDocShell final : public nsDocLoa
   // session history. This checks a number of factors such as cache policy,
   // pending requests, and unload handlers.
   // |aLoadType| should be the load type that will replace the current
   // presentation. |aNewRequest| should be the request for the document to
   // be loaded in place of the current document, or null if such a request
   // has not been created yet. |aNewDocument| should be the document that will
   // replace the current document.
   bool CanSavePresentation(uint32_t aLoadType, nsIRequest* aNewRequest,
-                           nsIDocument* aNewDocument);
+                           mozilla::dom::Document* aNewDocument);
 
   // Captures the state of the supporting elements of the presentation
   // (the "window" object, docshell tree, meta-refresh loads, and security
   // state) and stores them on |mOSHE|.
   nsresult CaptureState();
 
   // Begin the toplevel restore process for |aSHEntry|.
   // This simulates a channel open, and defers the real work until
--- a/docshell/base/nsDocShellEditorData.cpp
+++ b/docshell/base/nsDocShellEditorData.cpp
@@ -124,17 +124,17 @@ nsresult nsDocShellEditorData::DetachFro
       mDocShell ? mDocShell->GetWindow() : nullptr;
   nsresult rv = mEditingSession->DetachFromWindow(domWindow);
   NS_ENSURE_SUCCESS(rv, rv);
 
   mIsDetached = true;
   mDetachedMakeEditable = mMakeEditable;
   mMakeEditable = false;
 
-  nsCOMPtr<nsIDocument> doc = domWindow->GetDoc();
+  nsCOMPtr<dom::Document> doc = domWindow->GetDoc();
   nsCOMPtr<nsIHTMLDocument> htmlDoc = do_QueryInterface(doc);
   if (htmlDoc) {
     mDetachedEditingState = htmlDoc->GetEditingState();
   }
 
   mDocShell = nullptr;
 
   return NS_OK;
@@ -146,16 +146,16 @@ nsresult nsDocShellEditorData::ReattachT
   nsCOMPtr<nsPIDOMWindowOuter> domWindow =
       mDocShell ? mDocShell->GetWindow() : nullptr;
   nsresult rv = mEditingSession->ReattachToWindow(domWindow);
   NS_ENSURE_SUCCESS(rv, rv);
 
   mIsDetached = false;
   mMakeEditable = mDetachedMakeEditable;
 
-  nsCOMPtr<nsIDocument> doc = domWindow->GetDoc();
+  RefPtr<dom::Document> doc = domWindow->GetDoc();
   nsCOMPtr<nsIHTMLDocument> htmlDoc = do_QueryInterface(doc);
   if (htmlDoc) {
     htmlDoc->SetEditingState(mDetachedEditingState);
   }
 
   return NS_OK;
 }
--- a/docshell/base/nsDocShellTreeOwner.cpp
+++ b/docshell/base/nsDocShellTreeOwner.cpp
@@ -373,17 +373,17 @@ nsDocShellTreeOwner::SizeShellTo(nsIDocS
     // XXX: this is weird, but we used to call a method here
     // (webBrowserChrome->SizeBrowserTo()) whose implementations all failed
     // like this, so...
     return NS_ERROR_NOT_IMPLEMENTED;
   }
 
   NS_ENSURE_TRUE(aShellItem, NS_ERROR_FAILURE);
 
-  nsCOMPtr<nsIDocument> document = aShellItem->GetDocument();
+  RefPtr<Document> document = aShellItem->GetDocument();
   NS_ENSURE_TRUE(document, NS_ERROR_FAILURE);
 
   NS_ENSURE_TRUE(document->GetDocumentElement(), NS_ERROR_FAILURE);
 
   // Set the preferred Size
   // XXX
   NS_ERROR("Implement this");
   /*
--- a/docshell/base/nsIDocShellTreeItem.idl
+++ b/docshell/base/nsIDocShellTreeItem.idl
@@ -3,19 +3,20 @@
  * 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 "nsISupports.idl"
 
 interface mozIDOMWindowProxy;
 interface nsIDocShellTreeOwner;
-interface nsIDocument;
 interface nsPIDOMWindowOuter;
 
+webidl Document;
+
 /**
  * The nsIDocShellTreeItem supplies the methods that are required of any item
  * that wishes to be able to live within the docshell tree either as a middle
  * node or a leaf. 
  */
 
 [scriptable, uuid(9b7c586f-9214-480c-a2c4-49b526fff1a6)]
 interface nsIDocShellTreeItem : nsISupports
@@ -179,12 +180,12 @@ interface nsIDocShellTreeItem : nsISuppo
 	                                      in nsIDocShellTreeItem aRequestor,
 	                                      in nsIDocShellTreeItem aOriginalRequestor);
 
   /**
    * Returns the DOM outer window for the content viewer.
    */
   readonly attribute mozIDOMWindowProxy domWindow;
 
-  [noscript,nostdcall,notxpcom] nsIDocument getDocument();
+  [noscript,nostdcall,notxpcom] Document getDocument();
   [noscript,nostdcall,notxpcom] nsPIDOMWindowOuter getWindow();
 };
 
--- a/docshell/base/nsIDocumentLoaderFactory.idl
+++ b/docshell/base/nsIDocumentLoaderFactory.idl
@@ -5,20 +5,21 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsISupports.idl"
 
 interface nsIChannel;
 interface nsIContentViewer;
 interface nsIStreamListener;
 interface nsIDocShell;
-interface nsIDocument;
 interface nsILoadGroup;
 interface nsIPrincipal;
 
+webidl Document;
+
 /**
  * To get a component that implements nsIDocumentLoaderFactory
  * for a given mimetype, use nsICategoryManager to find an entry
  * with the mimetype as its name in the category "Gecko-Content-Viewers".
  * The value of the entry is the contractid of the component.
  * The component is a service, so use GetService, not CreateInstance to get it.
  */
 
@@ -28,11 +29,11 @@ interface nsIDocumentLoaderFactory : nsI
                               in nsIChannel aChannel,
                               in nsILoadGroup aLoadGroup,
                               in ACString aContentType, 
                               in nsIDocShell aContainer,
                               in nsISupports aExtraInfo,
                               out nsIStreamListener aDocListenerResult);
 
     nsIContentViewer createInstanceForDocument(in nsISupports aContainer,
-                                         in nsIDocument aDocument,
+                                         in Document aDocument,
                                          in string aCommand);
 };
--- a/docshell/base/nsPingListener.cpp
+++ b/docshell/base/nsPingListener.cpp
@@ -4,24 +4,23 @@
  * 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 "nsPingListener.h"
 
 #include "mozilla/Preferences.h"
 
 #include "mozilla/dom/DocGroup.h"
+#include "mozilla/dom/Document.h"
 
-#include "nsIDocument.h"
 #include "nsIHttpChannelInternal.h"
 #include "nsIInputStream.h"
 #include "nsIProtocolHandler.h"
 #include "nsIUploadChannel2.h"
 
-#include "nsIDocument.h"
 #include "nsNetUtil.h"
 #include "nsStreamUtils.h"
 #include "nsStringStream.h"
 #include "nsWhitespaceTokenizer.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
@@ -87,17 +86,17 @@ struct MOZ_STACK_CLASS SendPingInfo {
 
 static void SendPing(void* aClosure, nsIContent* aContent, nsIURI* aURI,
                      nsIIOService* aIOService) {
   SendPingInfo* info = static_cast<SendPingInfo*>(aClosure);
   if (info->maxPings > -1 && info->numPings >= info->maxPings) {
     return;
   }
 
-  nsIDocument* doc = aContent->OwnerDoc();
+  Document* doc = aContent->OwnerDoc();
 
   nsCOMPtr<nsIChannel> chan;
   NS_NewChannel(getter_AddRefs(chan), aURI, doc,
                 info->requireSameHost
                     ? nsILoadInfo::SEC_REQUIRE_SAME_ORIGIN_DATA_IS_BLOCKED
                     : nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL,
                 nsIContentPolicy::TYPE_PING,
                 nullptr,                  // PerformanceStorage
@@ -262,17 +261,17 @@ static void ForEachPing(nsIContent* aCon
     return;
   }
 
   nsCOMPtr<nsIIOService> ios = do_GetIOService();
   if (!ios) {
     return;
   }
 
-  nsIDocument* doc = aContent->OwnerDoc();
+  Document* doc = aContent->OwnerDoc();
   nsAutoCString charset;
   doc->GetDocumentCharacterSet()->Name(charset);
 
   nsWhitespaceTokenizer tokenizer(value);
 
   while (tokenizer.hasMoreTokens()) {
     nsCOMPtr<nsIURI> uri, baseURI = aContent->GetBaseURI();
     ios->NewURI(NS_ConvertUTF16toUTF8(tokenizer.nextToken()), charset.get(),
--- a/docshell/shistory/nsSHEntryShared.cpp
+++ b/docshell/shistory/nsSHEntryShared.cpp
@@ -6,17 +6,17 @@
 
 #include "nsSHEntryShared.h"
 
 #include "nsArray.h"
 #include "nsDocShellEditorData.h"
 #include "nsIContentViewer.h"
 #include "nsIDocShell.h"
 #include "nsIDocShellTreeItem.h"
-#include "nsIDocument.h"
+#include "mozilla/dom/Document.h"
 #include "nsILayoutHistoryState.h"
 #include "nsISHistory.h"
 #include "nsIWebNavigation.h"
 #include "nsThreadUtils.h"
 
 #include "mozilla/Attributes.h"
 #include "mozilla/Preferences.h"
 
@@ -185,17 +185,17 @@ nsresult nsSHEntryShared::RemoveFromBFCa
   if (!mDocument) {
     return NS_ERROR_UNEXPECTED;
   }
 
   // DropPresentationState would clear mContentViewer & mDocument. Capture and
   // release the references asynchronously so that the document doesn't get
   // nuked mid-mutation.
   nsCOMPtr<nsIContentViewer> viewer = mContentViewer;
-  nsCOMPtr<nsIDocument> document = mDocument;
+  RefPtr<dom::Document> document = mDocument;
   RefPtr<nsSHEntryShared> self = this;
   nsresult rv = mDocument->Dispatch(
       mozilla::TaskCategory::Other,
       NS_NewRunnableFunction(
           "nsSHEntryShared::RemoveFromBFCacheAsync",
           [self, viewer, document]() {
             if (viewer) {
               viewer->Destroy();
--- a/docshell/shistory/nsSHEntryShared.h
+++ b/docshell/shistory/nsSHEntryShared.h
@@ -16,23 +16,28 @@
 #include "nsRect.h"
 #include "nsString.h"
 #include "nsStubMutationObserver.h"
 
 #include "mozilla/Attributes.h"
 
 class nsSHEntry;
 class nsISHEntry;
-class nsIDocument;
 class nsIContentViewer;
 class nsIDocShellTreeItem;
 class nsILayoutHistoryState;
 class nsDocShellEditorData;
 class nsIMutableArray;
 
+namespace mozilla {
+namespace dom {
+class Document;
+}
+}  // namespace mozilla
+
 // A document may have multiple SHEntries, either due to hash navigations or
 // calls to history.pushState.  SHEntries corresponding to the same document
 // share many members; in particular, they share state related to the
 // back/forward cache.
 //
 // nsSHEntryShared is the vehicle for this sharing.
 class nsSHEntryShared final : public nsIBFCacheEntry,
                               public nsStubMutationObserver {
@@ -79,17 +84,17 @@ class nsSHEntryShared final : public nsI
 
   uint32_t mCacheKey;
   uint32_t mLastTouched;
 
   // These members aren't copied by nsSHEntryShared::Duplicate() because
   // they're specific to a particular content viewer.
   uint64_t mID;
   nsCOMPtr<nsIContentViewer> mContentViewer;
-  nsCOMPtr<nsIDocument> mDocument;
+  RefPtr<mozilla::dom::Document> mDocument;
   nsCOMPtr<nsILayoutHistoryState> mLayoutHistoryState;
   nsCOMPtr<nsISupports> mWindowState;
   nsIntRect mViewerBounds;
   nsCOMPtr<nsIMutableArray> mRefreshURIList;
   nsExpirationState mExpirationState;
   nsAutoPtr<nsDocShellEditorData> mEditorData;
   nsWeakPtr mSHistory;
 
--- a/dom/animation/Animation.cpp
+++ b/dom/animation/Animation.cpp
@@ -11,17 +11,17 @@
 #include "mozilla/dom/DocumentTimeline.h"
 #include "mozilla/AnimationEventDispatcher.h"
 #include "mozilla/AnimationTarget.h"
 #include "mozilla/AutoRestore.h"
 #include "mozilla/Maybe.h"          // For Maybe
 #include "mozilla/TypeTraits.h"     // For std::forward<>
 #include "nsAnimationManager.h"     // For CSSAnimation
 #include "nsDOMMutationObserver.h"  // For nsAutoAnimationMutationBatch
-#include "nsIDocument.h"            // For nsIDocument
+#include "mozilla/dom/Document.h"
 #include "nsIPresShell.h"           // For nsIPresShell
 #include "nsThreadUtils.h"  // For nsRunnableMethod and nsRevocableEventPtr
 #include "nsTransitionManager.h"      // For CSSTransition
 #include "PendingAnimationTracker.h"  // For PendingAnimationTracker
 
 namespace mozilla {
 namespace dom {
 
@@ -58,22 +58,17 @@ class MOZ_RAII AutoMutationBatchForAnima
     MOZ_GUARD_OBJECT_NOTIFIER_INIT;
     Maybe<NonOwningAnimationTarget> target =
         nsNodeUtils::GetTargetForAnimation(&aAnimation);
     if (!target) {
       return;
     }
 
     // For mutation observers, we use the OwnerDoc.
-    nsIDocument* doc = target->mElement->OwnerDoc();
-    if (!doc) {
-      return;
-    }
-
-    mAutoBatch.emplace(doc);
+    mAutoBatch.emplace(target->mElement->OwnerDoc());
   }
 
  private:
   MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
   Maybe<nsAutoAnimationMutationBatch> mAutoBatch;
 };
 }  // namespace
 
@@ -87,17 +82,17 @@ class MOZ_RAII AutoMutationBatchForAnima
     const Optional<AnimationTimeline*>& aTimeline, ErrorResult& aRv) {
   nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
   RefPtr<Animation> animation = new Animation(global);
 
   AnimationTimeline* timeline;
   if (aTimeline.WasPassed()) {
     timeline = aTimeline.Value();
   } else {
-    nsIDocument* document =
+    Document* document =
         AnimationUtils::GetCurrentRealmDocument(aGlobal.Context());
     if (!document) {
       aRv.Throw(NS_ERROR_FAILURE);
       return nullptr;
     }
     timeline = document->Timeline();
   }
 
@@ -1072,18 +1067,17 @@ void Animation::PlayNoUpdate(ErrorResult
 
   mPendingState = PendingState::PlayPending;
 
   // Clear flag that causes us to sync transform animations with the main
   // thread for now. We'll set this when we go to set up compositor
   // animations if it applies.
   mSyncWithGeometricAnimations = false;
 
-  nsIDocument* doc = GetRenderedDocument();
-  if (doc) {
+  if (Document* doc = GetRenderedDocument()) {
     PendingAnimationTracker* tracker =
         doc->GetOrCreatePendingAnimationTracker();
     tracker->AddPlayPending(*this);
   } else {
     TriggerOnNextTick(Nullable<TimeDuration>());
   }
 
   UpdateTiming(SeekFlag::NoSeek, SyncNotifyFlag::Async);
@@ -1121,18 +1115,17 @@ void Animation::Pause(ErrorResult& aRv) 
 
   if (!reuseReadyPromise) {
     // Clear ready promise. We'll create a new one lazily.
     mReady = nullptr;
   }
 
   mPendingState = PendingState::PausePending;
 
-  nsIDocument* doc = GetRenderedDocument();
-  if (doc) {
+  if (Document* doc = GetRenderedDocument()) {
     PendingAnimationTracker* tracker =
         doc->GetOrCreatePendingAnimationTracker();
     tracker->AddPausePending(*this);
   } else {
     TriggerOnNextTick(Nullable<TimeDuration>());
   }
 
   UpdateTiming(SeekFlag::NoSeek, SyncNotifyFlag::Async);
@@ -1279,18 +1272,17 @@ void Animation::UpdateEffect() {
     KeyframeEffect* keyframeEffect = mEffect->AsKeyframeEffect();
     if (keyframeEffect) {
       keyframeEffect->NotifyAnimationTimingUpdated();
     }
   }
 }
 
 void Animation::FlushUnanimatedStyle() const {
-  nsIDocument* doc = GetRenderedDocument();
-  if (doc) {
+  if (Document* doc = GetRenderedDocument()) {
     doc->FlushPendingNotifications(
         ChangesToFlush(FlushType::Style, false /* flush animations */));
   }
 }
 
 void Animation::PostUpdate() {
   if (!mEffect) {
     return;
@@ -1303,18 +1295,17 @@ void Animation::PostUpdate() {
   keyframeEffect->RequestRestyle(EffectCompositor::RestyleType::Layer);
 }
 
 void Animation::CancelPendingTasks() {
   if (mPendingState == PendingState::NotPending) {
     return;
   }
 
-  nsIDocument* doc = GetRenderedDocument();
-  if (doc) {
+  if (Document* doc = GetRenderedDocument()) {
     PendingAnimationTracker* tracker = doc->GetPendingAnimationTracker();
     if (tracker) {
       if (mPendingState == PendingState::PlayPending) {
         tracker->RemovePlayPending(*this);
       } else {
         tracker->RemovePausePending(*this);
       }
     }
@@ -1341,18 +1332,17 @@ void Animation::ResetPendingTasks() {
 
 void Animation::ReschedulePendingTasks() {
   if (mPendingState == PendingState::NotPending) {
     return;
   }
 
   mPendingReadyTime.SetNull();
 
-  nsIDocument* doc = GetRenderedDocument();
-  if (doc) {
+  if (Document* doc = GetRenderedDocument()) {
     PendingAnimationTracker* tracker =
         doc->GetOrCreatePendingAnimationTracker();
     if (mPendingState == PendingState::PlayPending &&
         !tracker->IsWaitingToPlay(*this)) {
       tracker->AddPlayPending(*this);
     } else if (mPendingState == PendingState::PausePending &&
                !tracker->IsWaitingToPause(*this)) {
       tracker->AddPausePending(*this);
@@ -1396,17 +1386,17 @@ bool Animation::IsPossiblyOrphanedPendin
   }
 
   // If we have no rendered document, or we're not in our rendered document's
   // PendingAnimationTracker then there's a good chance no one is tracking us.
   //
   // If we're wrong and another document is tracking us then, at worst, we'll
   // simply start/pause the animation one tick too soon. That's better than
   // never starting/pausing the animation and is unlikely.
-  nsIDocument* doc = GetRenderedDocument();
+  Document* doc = GetRenderedDocument();
   if (!doc) {
     return true;
   }
 
   PendingAnimationTracker* tracker = doc->GetPendingAnimationTracker();
   return !tracker || (!tracker->IsWaitingToPlay(*this) &&
                       !tracker->IsWaitingToPause(*this));
 }
@@ -1414,25 +1404,25 @@ bool Animation::IsPossiblyOrphanedPendin
 StickyTimeDuration Animation::EffectEnd() const {
   if (!mEffect) {
     return StickyTimeDuration(0);
   }
 
   return mEffect->SpecifiedTiming().EndTime();
 }
 
-nsIDocument* Animation::GetRenderedDocument() const {
+Document* Animation::GetRenderedDocument() const {
   if (!mEffect || !mEffect->AsKeyframeEffect()) {
     return nullptr;
   }
 
   return mEffect->AsKeyframeEffect()->GetRenderedDocument();
 }
 
-nsIDocument* Animation::GetTimelineDocument() const {
+Document* Animation::GetTimelineDocument() const {
   return mTimeline ? mTimeline->GetDocument() : nullptr;
 }
 
 class AsyncFinishNotification : public MicroTaskRunnable {
  public:
   explicit AsyncFinishNotification(Animation* aAnimation)
       : MicroTaskRunnable(), mAnimation(aAnimation) {}
 
@@ -1490,17 +1480,17 @@ void Animation::DoFinishNotificationImme
   QueuePlaybackEvent(NS_LITERAL_STRING("finish"),
                      AnimationTimeToTimeStamp(EffectEnd()));
 }
 
 void Animation::QueuePlaybackEvent(const nsAString& aName,
                                    TimeStamp&& aScheduledEventTime) {
   // Use document for timing.
   // https://drafts.csswg.org/web-animations-1/#document-for-timing
-  nsIDocument* doc = GetTimelineDocument();
+  Document* doc = GetTimelineDocument();
   if (!doc) {
     return;
   }
 
   nsPresContext* presContext = doc->GetPresContext();
   if (!presContext) {
     return;
   }
--- a/dom/animation/Animation.h
+++ b/dom/animation/Animation.h
@@ -25,28 +25,28 @@
 
 // X11 has a #define for CurrentTime.
 #ifdef CurrentTime
 #undef CurrentTime
 #endif
 
 struct JSContext;
 class nsCSSPropertyIDSet;
-class nsIDocument;
 class nsIFrame;
 
 namespace mozilla {
 
 struct AnimationRule;
 
 namespace dom {
 
 class AsyncFinishNotification;
 class CSSAnimation;
 class CSSTransition;
+class Document;
 
 class Animation : public DOMEventTargetHelper,
                   public LinkedListElement<Animation> {
  protected:
   virtual ~Animation() {}
 
  public:
   explicit Animation(nsIGlobalObject* aGlobal)
@@ -496,18 +496,18 @@ class Animation : public DOMEventTargetH
                              aActiveDuration),
                     zeroDuration);
   }
 
   TimeStamp GetTimelineCurrentTimeAsTimeStamp() const {
     return mTimeline ? mTimeline->GetCurrentTimeAsTimeStamp() : TimeStamp();
   }
 
-  nsIDocument* GetRenderedDocument() const;
-  nsIDocument* GetTimelineDocument() const;
+  Document* GetRenderedDocument() const;
+  Document* GetTimelineDocument() const;
 
   RefPtr<AnimationTimeline> mTimeline;
   RefPtr<AnimationEffect> mEffect;
   // The beginning of the delay period.
   Nullable<TimeDuration> mStartTime;            // Timeline timescale
   Nullable<TimeDuration> mHoldTime;             // Animation timescale
   Nullable<TimeDuration> mPendingReadyTime;     // Timeline timescale
   Nullable<TimeDuration> mPreviousCurrentTime;  // Animation timescale
--- a/dom/animation/AnimationEffect.cpp
+++ b/dom/animation/AnimationEffect.cpp
@@ -30,17 +30,17 @@ NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCA
 NS_IMPL_CYCLE_COLLECTING_ADDREF(AnimationEffect)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(AnimationEffect)
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(AnimationEffect)
   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
   NS_INTERFACE_MAP_ENTRY(nsISupports)
 NS_INTERFACE_MAP_END
 
-AnimationEffect::AnimationEffect(nsIDocument* aDocument, TimingParams&& aTiming)
+AnimationEffect::AnimationEffect(Document* aDocument, TimingParams&& aTiming)
     : mDocument(aDocument), mTiming(std::move(aTiming)) {}
 
 AnimationEffect::~AnimationEffect() = default;
 
 // https://drafts.csswg.org/web-animations/#current
 bool AnimationEffect::IsCurrent() const {
   if (!mAnimation || mAnimation->PlayState() == AnimationPlayState::Finished) {
     return false;
--- a/dom/animation/AnimationEffect.h
+++ b/dom/animation/AnimationEffect.h
@@ -21,23 +21,24 @@ namespace mozilla {
 
 struct ElementPropertyTransition;
 
 namespace dom {
 
 class Animation;
 class KeyframeEffect;
 struct ComputedEffectTiming;
+class Document;
 
 class AnimationEffect : public nsISupports, public nsWrapperCache {
  public:
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(AnimationEffect)
 
-  AnimationEffect(nsIDocument* aDocument, TimingParams&& aTiming);
+  AnimationEffect(Document* aDocument, TimingParams&& aTiming);
 
   virtual KeyframeEffect* AsKeyframeEffect() { return nullptr; }
 
   virtual ElementPropertyTransition* AsTransition() { return nullptr; }
   virtual const ElementPropertyTransition* AsTransition() const {
     return nullptr;
   }
 
@@ -86,17 +87,17 @@ class AnimationEffect : public nsISuppor
   virtual bool AffectsGeometry() const = 0;
 
  protected:
   virtual ~AnimationEffect();
 
   Nullable<TimeDuration> GetLocalTime() const;
 
  protected:
-  RefPtr<nsIDocument> mDocument;
+  RefPtr<Document> mDocument;
   RefPtr<Animation> mAnimation;
   TimingParams mTiming;
 };
 
 }  // namespace dom
 }  // namespace mozilla
 
 #endif  // mozilla_dom_AnimationEffect_h
--- a/dom/animation/AnimationTimeline.h
+++ b/dom/animation/AnimationTimeline.h
@@ -12,22 +12,21 @@
 #include "nsCycleCollectionParticipant.h"
 #include "js/TypeDecls.h"
 #include "mozilla/AnimationUtils.h"
 #include "mozilla/Attributes.h"
 #include "nsHashKeys.h"
 #include "nsIGlobalObject.h"
 #include "nsTHashtable.h"
 
-class nsIDocument;
-
 namespace mozilla {
 namespace dom {
 
 class Animation;
+class Document;
 
 class AnimationTimeline : public nsISupports, public nsWrapperCache {
  public:
   explicit AnimationTimeline(nsIGlobalObject* aWindow) : mWindow(aWindow) {
     MOZ_ASSERT(mWindow);
   }
 
  protected:
@@ -91,17 +90,17 @@ class AnimationTimeline : public nsISupp
    * applied to an element it is associated with the timeline even if it has a
    * delayed start, so this includes animations that may not be active for some
    * time.
    */
   bool HasAnimations() const { return !mAnimations.IsEmpty(); }
 
   virtual void RemoveAnimation(Animation* aAnimation);
 
-  virtual nsIDocument* GetDocument() const = 0;
+  virtual Document* GetDocument() const = 0;
 
  protected:
   nsCOMPtr<nsIGlobalObject> mWindow;
 
   // Animations observing this timeline
   //
   // We store them in (a) a hashset for quick lookup, and (b) an array
   // to maintain a fixed sampling order.
--- a/dom/animation/AnimationUtils.cpp
+++ b/dom/animation/AnimationUtils.cpp
@@ -4,24 +4,26 @@
  * 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 "AnimationUtils.h"
 
 #include "nsDebug.h"
 #include "nsAtom.h"
 #include "nsIContent.h"
-#include "nsIDocument.h"
+#include "mozilla/dom/Document.h"
 #include "nsGlobalWindow.h"
 #include "nsString.h"
 #include "xpcpublic.h"  // For xpc::NativeGlobal
 #include "mozilla/EffectSet.h"
 #include "mozilla/dom/KeyframeEffect.h"
 #include "mozilla/Preferences.h"
 
+using namespace mozilla::dom;
+
 namespace mozilla {
 
 /* static */ void AnimationUtils::LogAsyncAnimationFailure(
     nsCString& aMessage, const nsIContent* aContent) {
   if (aContent) {
     aMessage.AppendLiteral(" [");
     aMessage.Append(nsAtomCString(aContent->NodeInfo()->NameAtom()));
 
@@ -32,26 +34,25 @@ namespace mozilla {
       aMessage.Append('\'');
     }
     aMessage.Append(']');
   }
   aMessage.Append('\n');
   printf_stderr("%s", aMessage.get());
 }
 
-/* static */ nsIDocument* AnimationUtils::GetCurrentRealmDocument(
-    JSContext* aCx) {
+/* static */ Document* AnimationUtils::GetCurrentRealmDocument(JSContext* aCx) {
   nsGlobalWindowInner* win = xpc::CurrentWindowOrNull(aCx);
   if (!win) {
     return nullptr;
   }
   return win->GetDoc();
 }
 
-/* static */ nsIDocument* AnimationUtils::GetDocumentFromGlobal(
+/* static */ Document* AnimationUtils::GetDocumentFromGlobal(
     JSObject* aGlobalObject) {
   nsGlobalWindowInner* win = xpc::WindowOrNull(aGlobalObject);
   if (!win) {
     return nullptr;
   }
   return win->GetDoc();
 }
 
--- a/dom/animation/AnimationUtils.h
+++ b/dom/animation/AnimationUtils.h
@@ -9,27 +9,32 @@
 
 #include "mozilla/TimeStamp.h"
 #include "mozilla/dom/BindingDeclarations.h"
 #include "mozilla/dom/Nullable.h"
 #include "nsRFPService.h"
 #include "nsStringFwd.h"
 
 class nsIContent;
-class nsIDocument;
 class nsIFrame;
 struct JSContext;
 
 namespace mozilla {
 
 class ComputedTimingFunction;
 class EffectSet;
 
+namespace dom {
+class Document;
+}
+
 class AnimationUtils {
  public:
+  typedef dom::Document Document;
+
   static dom::Nullable<double> TimeDurationToDouble(
       const dom::Nullable<TimeDuration>& aTime) {
     dom::Nullable<double> result;
 
     if (!aTime.IsNull()) {
       // 0 is an inappropriate mixin for this this area; however CSS Animations
       // needs to have it's Time Reduction Logic refactored, so it's currently
       // only clamping for RFP mode. RFP mode gives a much lower time precision,
@@ -53,24 +58,24 @@ class AnimationUtils {
   }
 
   static void LogAsyncAnimationFailure(nsCString& aMessage,
                                        const nsIContent* aContent = nullptr);
 
   /**
    * Get the document from the JS context to use when parsing CSS properties.
    */
-  static nsIDocument* GetCurrentRealmDocument(JSContext* aCx);
+  static Document* GetCurrentRealmDocument(JSContext* aCx);
 
   /**
    * Get the document from the global object, or nullptr if the document has
    * no window, to use when constructing DOM object without entering the
    * target window's compartment (see KeyframeEffect constructor).
    */
-  static nsIDocument* GetDocumentFromGlobal(JSObject* aGlobalObject);
+  static Document* GetDocumentFromGlobal(JSObject* aGlobalObject);
 
   /**
    * Checks if offscreen animation throttling is enabled.
    */
   static bool IsOffscreenThrottlingEnabled();
 
   /**
    * Returns true if the given EffectSet contains a current effect that animates
--- a/dom/animation/CSSPseudoElement.cpp
+++ b/dom/animation/CSSPseudoElement.cpp
@@ -41,17 +41,17 @@ ParentObject CSSPseudoElement::GetParent
 
 JSObject* CSSPseudoElement::WrapObject(JSContext* aCx,
                                        JS::Handle<JSObject*> aGivenProto) {
   return CSSPseudoElement_Binding::Wrap(aCx, this, aGivenProto);
 }
 
 void CSSPseudoElement::GetAnimations(const AnimationFilter& filter,
                                      nsTArray<RefPtr<Animation>>& aRetVal) {
-  nsIDocument* doc = mParentElement->GetComposedDoc();
+  Document* doc = mParentElement->GetComposedDoc();
   if (doc) {
     // We don't need to explicitly flush throttled animations here, since
     // updating the animation style of (pseudo-)elements will never affect the
     // set of running animations and it's only the set of running animations
     // that is important here.
     doc->FlushPendingNotifications(
         ChangesToFlush(FlushType::Style, false /* flush animations */));
   }
--- a/dom/animation/DocumentTimeline.cpp
+++ b/dom/animation/DocumentTimeline.cpp
@@ -45,17 +45,17 @@ NS_IMPL_RELEASE_INHERITED(DocumentTimeli
 JSObject* DocumentTimeline::WrapObject(JSContext* aCx,
                                        JS::Handle<JSObject*> aGivenProto) {
   return DocumentTimeline_Binding::Wrap(aCx, this, aGivenProto);
 }
 
 /* static */ already_AddRefed<DocumentTimeline> DocumentTimeline::Constructor(
     const GlobalObject& aGlobal, const DocumentTimelineOptions& aOptions,
     ErrorResult& aRv) {
-  nsIDocument* doc = AnimationUtils::GetCurrentRealmDocument(aGlobal.Context());
+  Document* doc = AnimationUtils::GetCurrentRealmDocument(aGlobal.Context());
   if (!doc) {
     aRv.Throw(NS_ERROR_FAILURE);
     return nullptr;
   }
   TimeDuration originTime =
       TimeDuration::FromMilliseconds(aOptions.mOriginTime);
 
   if (originTime == TimeDuration::Forever() ||
--- a/dom/animation/DocumentTimeline.h
+++ b/dom/animation/DocumentTimeline.h
@@ -6,31 +6,31 @@
 
 #ifndef mozilla_dom_DocumentTimeline_h
 #define mozilla_dom_DocumentTimeline_h
 
 #include "mozilla/dom/DocumentTimelineBinding.h"
 #include "mozilla/LinkedList.h"
 #include "mozilla/TimeStamp.h"
 #include "AnimationTimeline.h"
-#include "nsIDocument.h"
+#include "mozilla/dom/Document.h"
 #include "nsDOMNavigationTiming.h"  // for DOMHighResTimeStamp
 #include "nsRefreshDriver.h"
 
 struct JSContext;
 
 namespace mozilla {
 namespace dom {
 
 class DocumentTimeline final : public AnimationTimeline,
                                public nsARefreshObserver,
                                public nsATimerAdjustmentObserver,
                                public LinkedListElement<DocumentTimeline> {
  public:
-  DocumentTimeline(nsIDocument* aDocument, const TimeDuration& aOriginTime)
+  DocumentTimeline(Document* aDocument, const TimeDuration& aOriginTime)
       : AnimationTimeline(aDocument->GetParentObject()),
         mDocument(aDocument),
         mIsObservingRefreshDriver(false),
         mOriginTime(aOriginTime) {
     if (mDocument) {
       mDocument->Timelines().insertBack(this);
     }
   }
@@ -79,27 +79,27 @@ class DocumentTimeline final : public An
   // nsARefreshObserver methods
   void WillRefresh(TimeStamp aTime) override;
   // nsATimerAdjustmentObserver methods
   void NotifyTimerAdjusted(TimeStamp aTime) override;
 
   void NotifyRefreshDriverCreated(nsRefreshDriver* aDriver);
   void NotifyRefreshDriverDestroying(nsRefreshDriver* aDriver);
 
-  nsIDocument* GetDocument() const override { return mDocument; }
+  Document* GetDocument() const override { return mDocument; }
 
  protected:
   TimeStamp GetCurrentTimeStamp() const;
   nsRefreshDriver* GetRefreshDriver() const;
   void UnregisterFromRefreshDriver();
   void MostRecentRefreshTimeUpdated();
   void ObserveRefreshDriver(nsRefreshDriver* aDriver);
   void DisconnectRefreshDriver(nsRefreshDriver* aDriver);
 
-  nsCOMPtr<nsIDocument> mDocument;
+  RefPtr<Document> mDocument;
 
   // The most recently used refresh driver time. This is used in cases where
   // we don't have a refresh driver (e.g. because we are in a display:none
   // iframe).
   mutable TimeStamp mLastRefreshDriverTime;
   bool mIsObservingRefreshDriver;
 
   TimeDuration mOriginTime;
--- a/dom/animation/KeyframeEffect.cpp
+++ b/dom/animation/KeyframeEffect.cpp
@@ -58,17 +58,17 @@ NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INH
 NS_IMPL_CYCLE_COLLECTION_TRACE_END
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(KeyframeEffect)
 NS_INTERFACE_MAP_END_INHERITING(AnimationEffect)
 
 NS_IMPL_ADDREF_INHERITED(KeyframeEffect, AnimationEffect)
 NS_IMPL_RELEASE_INHERITED(KeyframeEffect, AnimationEffect)
 
-KeyframeEffect::KeyframeEffect(nsIDocument* aDocument,
+KeyframeEffect::KeyframeEffect(Document* aDocument,
                                const Maybe<OwningAnimationTarget>& aTarget,
                                TimingParams&& aTiming,
                                const KeyframeEffectParams& aOptions)
     : AnimationEffect(aDocument, std::move(aTiming)),
       mTarget(aTarget),
       mEffectOptions(aOptions),
       mInEffectOnLastAnimationTimingUpdate(false),
       mCumulativeChangeHint(nsChangeHint(0)) {}
@@ -626,17 +626,17 @@ KeyframeEffect::ConstructKeyframeEffect(
   // to make this works in Xray case.
   //
   // In all non-Xray cases, `aGlobal` matches the current Realm, so this
   // matches the spec behavior.
   //
   // In Xray case, the new objects should be created using the document of
   // the target global, but the KeyframeEffect constructors are called in the
   // caller's compartment to access `aKeyframes` object.
-  nsIDocument* doc = AnimationUtils::GetDocumentFromGlobal(aGlobal.Get());
+  Document* doc = AnimationUtils::GetDocumentFromGlobal(aGlobal.Get());
   if (!doc) {
     aRv.Throw(NS_ERROR_FAILURE);
     return nullptr;
   }
 
   TimingParams timingParams =
       TimingParams::FromOptionsUnion(aOptions, doc, aRv);
   if (aRv.Failed()) {
@@ -814,17 +814,17 @@ void DumpAnimationProperties(
     JS::Handle<JSObject*> aKeyframes,
     const UnrestrictedDoubleOrKeyframeAnimationOptions& aOptions,
     ErrorResult& aRv) {
   return ConstructKeyframeEffect(aGlobal, aTarget, aKeyframes, aOptions, aRv);
 }
 
 /* static */ already_AddRefed<KeyframeEffect> KeyframeEffect::Constructor(
     const GlobalObject& aGlobal, KeyframeEffect& aSource, ErrorResult& aRv) {
-  nsIDocument* doc = AnimationUtils::GetCurrentRealmDocument(aGlobal.Context());
+  Document* doc = AnimationUtils::GetCurrentRealmDocument(aGlobal.Context());
   if (!doc) {
     aRv.Throw(NS_ERROR_FAILURE);
     return nullptr;
   }
 
   // Create a new KeyframeEffect object with aSource's target,
   // iteration composite operation, composite operation, and spacing mode.
   // The constructor creates a new AnimationEffect object by
@@ -1236,17 +1236,17 @@ bool KeyframeEffect::CanThrottleOverflow
   return (!lastSyncTime.IsNull() &&
           (now - lastSyncTime) < OverflowRegionRefreshInterval());
 }
 
 bool KeyframeEffect::CanThrottleOverflowChangesInScrollable(
     nsIFrame& aFrame) const {
   // If the target element is not associated with any documents, we don't care
   // it.
-  nsIDocument* doc = GetRenderedDocument();
+  Document* doc = GetRenderedDocument();
   if (!doc) {
     return true;
   }
 
   bool hasIntersectionObservers = doc->HasIntersectionObservers();
 
   // If we know that the animation cannot cause overflow,
   // we can just disable flushes for this animation.
@@ -1309,25 +1309,25 @@ nsIFrame* KeyframeEffect::GetPrimaryFram
     frame = mTarget->mElement->GetPrimaryFrame();
     MOZ_ASSERT(mTarget->mPseudoType == CSSPseudoElementType::NotPseudo,
                "unknown mTarget->mPseudoType");
   }
 
   return frame;
 }
 
-nsIDocument* KeyframeEffect::GetRenderedDocument() const {
+Document* KeyframeEffect::GetRenderedDocument() const {
   if (!mTarget) {
     return nullptr;
   }
   return mTarget->mElement->GetComposedDoc();
 }
 
 nsIPresShell* KeyframeEffect::GetPresShell() const {
-  nsIDocument* doc = GetRenderedDocument();
+  Document* doc = GetRenderedDocument();
   if (!doc) {
     return nullptr;
   }
   return doc->GetShell();
 }
 
 /* static */ bool KeyframeEffect::IsGeometricProperty(
     const nsCSSPropertyID aProperty) {
--- a/dom/animation/KeyframeEffect.h
+++ b/dom/animation/KeyframeEffect.h
@@ -28,17 +28,16 @@
 #include "mozilla/StyleAnimationValue.h"
 #include "mozilla/dom/AnimationEffect.h"
 #include "mozilla/dom/BindingDeclarations.h"
 #include "mozilla/dom/Element.h"
 
 struct JSContext;
 class JSObject;
 class nsIContent;
-class nsIDocument;
 class nsIFrame;
 class nsIPresShell;
 
 namespace mozilla {
 
 class AnimValuesStyleRule;
 enum class CSSPseudoElementType : uint8_t;
 class ErrorResult;
@@ -101,20 +100,21 @@ struct AnimationProperty {
   }
 };
 
 struct ElementPropertyTransition;
 
 namespace dom {
 
 class Animation;
+class Document;
 
 class KeyframeEffect : public AnimationEffect {
  public:
-  KeyframeEffect(nsIDocument* aDocument,
+  KeyframeEffect(Document* aDocument,
                  const Maybe<OwningAnimationTarget>& aTarget,
                  TimingParams&& aTiming, const KeyframeEffectParams& aOptions);
 
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(KeyframeEffect,
                                                          AnimationEffect)
 
   virtual JSObject* WrapObject(JSContext* aCx,
@@ -252,17 +252,17 @@ class KeyframeEffect : public AnimationE
   bool ShouldBlockAsyncTransformAnimations(
       const nsIFrame* aFrame,
       AnimationPerformanceWarning::Type& aPerformanceWarning /* out */) const;
   bool HasGeometricProperties() const;
   bool AffectsGeometry() const override {
     return GetTarget() && HasGeometricProperties();
   }
 
-  nsIDocument* GetRenderedDocument() const;
+  Document* GetRenderedDocument() const;
   nsIPresShell* GetPresShell() const;
 
   // Associates a warning with the animated property on the specified frame
   // indicating why, for example, the property could not be animated on the
   // compositor. |aParams| and |aParamsLength| are optional parameters which
   // will be used to generate a localized message for devtools.
   void SetPerformanceWarning(nsCSSPropertyID aProperty,
                              const AnimationPerformanceWarning& aWarning);
--- a/dom/animation/KeyframeUtils.cpp
+++ b/dom/animation/KeyframeUtils.cpp
@@ -22,17 +22,17 @@
 #include "mozilla/dom/KeyframeEffect.h"  // For PropertyValuesPair etc.
 #include "mozilla/dom/Nullable.h"
 #include "jsapi.h"  // For ForOfIterator etc.
 #include "nsClassHashtable.h"
 #include "nsContentUtils.h"  // For GetContextForContent
 #include "nsCSSPropertyIDSet.h"
 #include "nsCSSProps.h"
 #include "nsCSSPseudoElements.h"  // For CSSPseudoElementType
-#include "nsIDocument.h"  // For nsIDocument::AreWebAnimationsImplicitKeyframesEnabled
+#include "mozilla/dom/Document.h"  // For Document::AreWebAnimationsImplicitKeyframesEnabled
 #include "nsIScriptError.h"
 #include "nsTArray.h"
 #include <algorithm>  // For std::stable_sort, std::min
 
 using mozilla::dom::Nullable;
 
 namespace mozilla {
 
@@ -128,22 +128,22 @@ class ComputedOffsetComparator {
 
 // ------------------------------------------------------------------
 //
 // Internal helper method declarations
 //
 // ------------------------------------------------------------------
 
 static void GetKeyframeListFromKeyframeSequence(JSContext* aCx,
-                                                nsIDocument* aDocument,
+                                                Document* aDocument,
                                                 JS::ForOfIterator& aIterator,
                                                 nsTArray<Keyframe>& aResult,
                                                 ErrorResult& aRv);
 
-static bool ConvertKeyframeSequence(JSContext* aCx, nsIDocument* aDocument,
+static bool ConvertKeyframeSequence(JSContext* aCx, Document* aDocument,
                                     JS::ForOfIterator& aIterator,
                                     nsTArray<Keyframe>& aResult);
 
 static bool GetPropertyValuesPairs(JSContext* aCx,
                                    JS::Handle<JSObject*> aObject,
                                    ListAllowance aAllowLists,
                                    nsTArray<PropertyValuesPair>& aResult);
 
@@ -152,17 +152,17 @@ static bool AppendStringOrStringSequence
                                                 ListAllowance aAllowLists,
                                                 nsTArray<nsString>& aValues);
 
 static bool AppendValueAsString(JSContext* aCx, nsTArray<nsString>& aValues,
                                 JS::Handle<JS::Value> aValue);
 
 static Maybe<PropertyValuePair> MakePropertyValuePair(
     nsCSSPropertyID aProperty, const nsAString& aStringValue,
-    nsIDocument* aDocument);
+    Document* aDocument);
 
 static bool HasValidOffsets(const nsTArray<Keyframe>& aKeyframes);
 
 #ifdef DEBUG
 static void MarkAsComputeValuesFailureKey(PropertyValuePair& aPair);
 
 #endif
 
@@ -170,32 +170,32 @@ static nsTArray<ComputedKeyframeValues> 
     const nsTArray<Keyframe>& aKeyframes, dom::Element* aElement,
     const ComputedStyle* aComputedValues);
 
 static void BuildSegmentsFromValueEntries(
     nsTArray<KeyframeValueEntry>& aEntries,
     nsTArray<AnimationProperty>& aResult);
 
 static void GetKeyframeListFromPropertyIndexedKeyframe(
-    JSContext* aCx, nsIDocument* aDocument, JS::Handle<JS::Value> aValue,
+    JSContext* aCx, Document* aDocument, JS::Handle<JS::Value> aValue,
     nsTArray<Keyframe>& aResult, ErrorResult& aRv);
 
 static bool HasImplicitKeyframeValues(const nsTArray<Keyframe>& aKeyframes,
-                                      nsIDocument* aDocument);
+                                      Document* aDocument);
 
 static void DistributeRange(const Range<Keyframe>& aRange);
 
 // ------------------------------------------------------------------
 //
 // Public API
 //
 // ------------------------------------------------------------------
 
 /* static */ nsTArray<Keyframe> KeyframeUtils::GetKeyframesFromObject(
-    JSContext* aCx, nsIDocument* aDocument, JS::Handle<JSObject*> aFrames,
+    JSContext* aCx, Document* aDocument, JS::Handle<JSObject*> aFrames,
     ErrorResult& aRv) {
   MOZ_ASSERT(!aRv.Failed());
 
   nsTArray<Keyframe> keyframes;
 
   if (!aFrames) {
     // The argument was explicitly null meaning no keyframes.
     return keyframes;
@@ -219,17 +219,17 @@ static void DistributeRange(const Range<
   }
 
   if (aRv.Failed()) {
     MOZ_ASSERT(keyframes.IsEmpty(),
                "Should not set any keyframes when there is an error");
     return keyframes;
   }
 
-  if (!nsIDocument::AreWebAnimationsImplicitKeyframesEnabled(aCx, nullptr) &&
+  if (!Document::AreWebAnimationsImplicitKeyframesEnabled(aCx, nullptr) &&
       HasImplicitKeyframeValues(keyframes, aDocument)) {
     keyframes.Clear();
     aRv.Throw(NS_ERROR_DOM_ANIM_MISSING_PROPS_ERR);
   }
 
   return keyframes;
 }
 
@@ -335,17 +335,17 @@ KeyframeUtils::GetAnimationPropertiesFro
  * @param aDocument The document to use when parsing CSS properties.
  * @param aIterator An already-initialized ForOfIterator for the JS
  *   object to iterate over as a sequence.
  * @param aResult The array into which the resulting Keyframe objects will be
  *   appended.
  * @param aRv Out param to store any errors thrown by this function.
  */
 static void GetKeyframeListFromKeyframeSequence(JSContext* aCx,
-                                                nsIDocument* aDocument,
+                                                Document* aDocument,
                                                 JS::ForOfIterator& aIterator,
                                                 nsTArray<Keyframe>& aResult,
                                                 ErrorResult& aRv) {
   MOZ_ASSERT(!aRv.Failed());
   MOZ_ASSERT(aResult.IsEmpty());
 
   // Convert the object in aIterator to a sequence of keyframes producing
   // an array of Keyframe objects.
@@ -370,17 +370,17 @@ static void GetKeyframeListFromKeyframeS
   }
 }
 
 /**
  * Converts a JS object wrapped by the given JS::ForIfIterator to an
  * IDL sequence<Keyframe> and stores the resulting Keyframe objects in
  * aResult.
  */
-static bool ConvertKeyframeSequence(JSContext* aCx, nsIDocument* aDocument,
+static bool ConvertKeyframeSequence(JSContext* aCx, Document* aDocument,
                                     JS::ForOfIterator& aIterator,
                                     nsTArray<Keyframe>& aResult) {
   JS::Rooted<JS::Value> value(aCx);
   ErrorResult parseEasingResult;
 
   for (;;) {
     bool done;
     if (!aIterator.next(&value, &done)) {
@@ -584,17 +584,17 @@ static bool AppendStringOrStringSequence
 static bool AppendValueAsString(JSContext* aCx, nsTArray<nsString>& aValues,
                                 JS::Handle<JS::Value> aValue) {
   return ConvertJSValueToString(aCx, aValue, dom::eStringify, dom::eStringify,
                                 *aValues.AppendElement());
 }
 
 static void ReportInvalidPropertyValueToConsole(
     nsCSSPropertyID aProperty, const nsAString& aInvalidPropertyValue,
-    nsIDocument* aDoc) {
+    Document* aDoc) {
   const nsString& invalidValue = PromiseFlatString(aInvalidPropertyValue);
   const NS_ConvertASCIItoUTF16 propertyName(
       nsCSSProps::GetStringValue(aProperty));
   const char16_t* params[] = {invalidValue.get(), propertyName.get()};
   nsContentUtils::ReportToConsole(
       nsIScriptError::warningFlag, NS_LITERAL_CSTRING("Animation"), aDoc,
       nsContentUtils::eDOM_PROPERTIES, "InvalidKeyframePropertyValue", params,
       ArrayLength(params));
@@ -607,17 +607,17 @@ static void ReportInvalidPropertyValueTo
  * @param aProperty The CSS property.
  * @param aStringValue The property value to parse.
  * @param aDocument The document to use when parsing.
  * @return The constructed PropertyValuePair, or Nothing() if |aStringValue| is
  *   an invalid property value.
  */
 static Maybe<PropertyValuePair> MakePropertyValuePair(
     nsCSSPropertyID aProperty, const nsAString& aStringValue,
-    nsIDocument* aDocument) {
+    Document* aDocument) {
   MOZ_ASSERT(aDocument);
   Maybe<PropertyValuePair> result;
 
   ServoCSSParser::ParsingEnvironment env =
       ServoCSSParser::GetParsingEnvironment(aDocument);
   RefPtr<RawServoDeclarationBlock> servoDeclarationBlock =
       ServoCSSParser::ParseProperty(aProperty, aStringValue, env);
 
@@ -937,17 +937,17 @@ static void BuildSegmentsFromValueEntrie
  * @param aCx The JSContext for |aValue|.
  * @param aDocument The document to use when parsing CSS properties.
  * @param aValue The JS object.
  * @param aResult The array into which the resulting AnimationProperty
  *   objects will be appended.
  * @param aRv Out param to store any errors thrown by this function.
  */
 static void GetKeyframeListFromPropertyIndexedKeyframe(
-    JSContext* aCx, nsIDocument* aDocument, JS::Handle<JS::Value> aValue,
+    JSContext* aCx, Document* aDocument, JS::Handle<JS::Value> aValue,
     nsTArray<Keyframe>& aResult, ErrorResult& aRv) {
   MOZ_ASSERT(aValue.isObject());
   MOZ_ASSERT(aResult.IsEmpty());
   MOZ_ASSERT(!aRv.Failed());
 
   // Convert the object to a property-indexed keyframe dictionary to
   // get its explicit dictionary members.
   dom::binding_detail::FastBasePropertyIndexedKeyframe keyframeDict;
@@ -1139,17 +1139,17 @@ static void GetKeyframeListFromPropertyI
  * offsets. The check is not entirely accurate but should detect most common
  * cases.
  *
  * @param aKeyframes The set of keyframes to analyze.
  * @param aDocument The document to use when parsing keyframes so we can
  *   try to detect where we have an invalid value at 0%/100%.
  */
 static bool HasImplicitKeyframeValues(const nsTArray<Keyframe>& aKeyframes,
-                                      nsIDocument* aDocument) {
+                                      Document* aDocument) {
   // We are looking to see if that every property referenced in |aKeyframes|
   // has a valid property at offset 0.0 and 1.0. The check as to whether a
   // property is valid or not, however, is not precise. We only check if the
   // property can be parsed, NOT whether it can also be converted to a
   // StyleAnimationValue since doing that requires a target element bound to
   // a document which we might not always have at the point where we want to
   // perform this check.
   //
--- a/dom/animation/KeyframeUtils.h
+++ b/dom/animation/KeyframeUtils.h
@@ -9,28 +9,28 @@
 
 #include "mozilla/KeyframeEffectParams.h"  // For CompositeOperation
 #include "nsCSSPropertyID.h"
 #include "nsTArrayForwardDeclare.h"  // For nsTArray
 #include "js/RootingAPI.h"           // For JS::Handle
 
 struct JSContext;
 class JSObject;
-class nsIDocument;
 class ComputedStyle;
 struct RawServoDeclarationBlock;
 
 namespace mozilla {
 struct AnimationProperty;
 enum class CSSPseudoElementType : uint8_t;
 class ErrorResult;
 struct Keyframe;
 struct PropertyStyleAnimationValuePair;
 
 namespace dom {
+class Document;
 class Element;
 }  // namespace dom
 }  // namespace mozilla
 
 namespace mozilla {
 
 // Represents the set of property-value pairs on a Keyframe converted to
 // computed values.
@@ -51,17 +51,17 @@ class KeyframeUtils {
    *   that is the keyframe list specification.
    * @param aRv (out) Out-param to hold any error returned by this function.
    *   Must be initially empty.
    * @return The set of processed keyframes. If an error occurs, aRv will be
    *   filled-in with the appropriate error code and an empty array will be
    *   returned.
    */
   static nsTArray<Keyframe> GetKeyframesFromObject(
-      JSContext* aCx, nsIDocument* aDocument, JS::Handle<JSObject*> aFrames,
+      JSContext* aCx, dom::Document* aDocument, JS::Handle<JSObject*> aFrames,
       ErrorResult& aRv);
 
   /**
    * Calculate the computed offset of keyframes by evenly distributing keyframes
    * with a missing offset.
    *
    * @see
    * https://drafts.csswg.org/web-animations/#calculating-computed-keyframes
--- a/dom/animation/PendingAnimationTracker.h
+++ b/dom/animation/PendingAnimationTracker.h
@@ -5,26 +5,30 @@
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_dom_PendingAnimationTracker_h
 #define mozilla_dom_PendingAnimationTracker_h
 
 #include "mozilla/dom/Animation.h"
 #include "mozilla/TypedEnumBits.h"
 #include "nsCycleCollectionParticipant.h"
-#include "nsIDocument.h"
+#include "mozilla/dom/Document.h"
 #include "nsTHashtable.h"
 
 class nsIFrame;
 
 namespace mozilla {
 
+namespace dom {
+class Document;
+}
+
 class PendingAnimationTracker final {
  public:
-  explicit PendingAnimationTracker(nsIDocument* aDocument)
+  explicit PendingAnimationTracker(dom::Document* aDocument)
       : mDocument(aDocument) {}
 
   NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(PendingAnimationTracker)
   NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS(PendingAnimationTracker)
 
   void AddPlayPending(dom::Animation& aAnimation) {
     // We'd like to assert here that IsWaitingToPause(aAnimation) is false but
     // if |aAnimation| was tracked here as a pause-pending animation when it was
@@ -81,17 +85,17 @@ class PendingAnimationTracker final {
 
   void AddPending(dom::Animation& aAnimation, AnimationSet& aSet);
   void RemovePending(dom::Animation& aAnimation, AnimationSet& aSet);
   bool IsWaiting(const dom::Animation& aAnimation,
                  const AnimationSet& aSet) const;
 
   AnimationSet mPlayPendingSet;
   AnimationSet mPausePendingSet;
-  nsCOMPtr<nsIDocument> mDocument;
+  RefPtr<dom::Document> mDocument;
 
  public:
   enum class CheckState {
     Indeterminate = 0,
     Absent = 1 << 0,
     AnimationsPresent = 1 << 1,
     TransitionsPresent = 1 << 2,
   };
--- a/dom/animation/TimingParams.cpp
+++ b/dom/animation/TimingParams.cpp
@@ -6,17 +6,17 @@
 
 #include "mozilla/TimingParams.h"
 
 #include "mozilla/AnimationUtils.h"
 #include "mozilla/dom/AnimatableBinding.h"
 #include "mozilla/dom/KeyframeAnimationOptionsBinding.h"
 #include "mozilla/dom/KeyframeEffectBinding.h"
 #include "mozilla/ServoCSSParser.h"
-#include "nsIDocument.h"
+#include "mozilla/dom/Document.h"
 
 namespace mozilla {
 
 template <class OptionsType>
 static const dom::EffectTiming& GetTimingProperties(
     const OptionsType& aOptions);
 
 template <>
@@ -30,17 +30,17 @@ template <>
 /* static */ const dom::EffectTiming& GetTimingProperties(
     const dom::UnrestrictedDoubleOrKeyframeAnimationOptions& aOptions) {
   MOZ_ASSERT(aOptions.IsKeyframeAnimationOptions());
   return aOptions.GetAsKeyframeAnimationOptions();
 }
 
 template <class OptionsType>
 /* static */ TimingParams TimingParams::FromOptionsType(
-    const OptionsType& aOptions, nsIDocument* aDocument, ErrorResult& aRv) {
+    const OptionsType& aOptions, Document* aDocument, ErrorResult& aRv) {
   TimingParams result;
 
   if (aOptions.IsUnrestrictedDouble()) {
     double durationInMs = aOptions.GetAsUnrestrictedDouble();
     if (durationInMs >= 0) {
       result.mDuration.emplace(
           StickyTimeDuration::FromMilliseconds(durationInMs));
     } else {
@@ -53,28 +53,28 @@ template <class OptionsType>
     result = FromEffectTiming(timing, aDocument, aRv);
   }
 
   return result;
 }
 
 /* static */ TimingParams TimingParams::FromOptionsUnion(
     const dom::UnrestrictedDoubleOrKeyframeEffectOptions& aOptions,
-    nsIDocument* aDocument, ErrorResult& aRv) {
+    Document* aDocument, ErrorResult& aRv) {
   return FromOptionsType(aOptions, aDocument, aRv);
 }
 
 /* static */ TimingParams TimingParams::FromOptionsUnion(
     const dom::UnrestrictedDoubleOrKeyframeAnimationOptions& aOptions,
-    nsIDocument* aDocument, ErrorResult& aRv) {
+    Document* aDocument, ErrorResult& aRv) {
   return FromOptionsType(aOptions, aDocument, aRv);
 }
 
 /* static */ TimingParams TimingParams::FromEffectTiming(
-    const dom::EffectTiming& aEffectTiming, nsIDocument* aDocument,
+    const dom::EffectTiming& aEffectTiming, Document* aDocument,
     ErrorResult& aRv) {
   TimingParams result;
 
   Maybe<StickyTimeDuration> duration =
       TimingParams::ParseDuration(aEffectTiming.mDuration, aRv);
   if (aRv.Failed()) {
     return result;
   }
@@ -103,17 +103,17 @@ template <class OptionsType>
 
   result.Update();
 
   return result;
 }
 
 /* static */ TimingParams TimingParams::MergeOptionalEffectTiming(
     const TimingParams& aSource, const dom::OptionalEffectTiming& aEffectTiming,
-    nsIDocument* aDocument, ErrorResult& aRv) {
+    Document* aDocument, ErrorResult& aRv) {
   MOZ_ASSERT(!aRv.Failed(), "Initially return value should be ok");
 
   TimingParams result = aSource;
 
   // Check for errors first
 
   Maybe<StickyTimeDuration> duration;
   if (aEffectTiming.mDuration.WasPassed()) {
@@ -178,17 +178,17 @@ template <class OptionsType>
   }
 
   result.Update();
 
   return result;
 }
 
 /* static */ Maybe<ComputedTimingFunction> TimingParams::ParseEasing(
-    const nsAString& aEasing, nsIDocument* aDocument, ErrorResult& aRv) {
+    const nsAString& aEasing, Document* aDocument, ErrorResult& aRv) {
   MOZ_ASSERT(aDocument);
 
   nsTimingFunction timingFunction;
   RefPtr<URLExtraData> url = ServoCSSParser::GetURLExtraData(aDocument);
   if (!ServoCSSParser::ParseEasing(aEasing, url, timingFunction)) {
     aRv.ThrowTypeError<dom::MSG_INVALID_EASING_ERROR>(aEasing);
     return Nothing();
   }
--- a/dom/animation/TimingParams.h
+++ b/dom/animation/TimingParams.h
@@ -13,21 +13,20 @@
 #include "mozilla/ComputedTimingFunction.h"
 #include "mozilla/Maybe.h"
 #include "mozilla/StickyTimeDuration.h"
 #include "mozilla/TimeStamp.h"  // for TimeDuration
 
 #include "mozilla/dom/AnimationEffectBinding.h"  // for FillMode
                                                  // and PlaybackDirection
 
-class nsIDocument;
-
 namespace mozilla {
 
 namespace dom {
+class Document;
 class UnrestrictedDoubleOrKeyframeEffectOptions;
 class UnrestrictedDoubleOrKeyframeAnimationOptions;
 }  // namespace dom
 
 struct TimingParams {
   TimingParams() = default;
 
   TimingParams(float aDuration, float aDelay, float aIterationCount,
@@ -51,35 +50,36 @@ struct TimingParams {
         mFill(aFillMode),
         mFunction(aFunction) {
     mDuration.emplace(aDuration);
     Update();
   }
 
   template <class OptionsType>
   static TimingParams FromOptionsType(const OptionsType& aOptions,
-                                      nsIDocument* aDocument, ErrorResult& aRv);
+                                      dom::Document* aDocument,
+                                      ErrorResult& aRv);
   static TimingParams FromOptionsUnion(
       const dom::UnrestrictedDoubleOrKeyframeEffectOptions& aOptions,
-      nsIDocument* aDocument, ErrorResult& aRv);
+      dom::Document* aDocument, ErrorResult& aRv);
   static TimingParams FromOptionsUnion(
       const dom::UnrestrictedDoubleOrKeyframeAnimationOptions& aOptions,
-      nsIDocument* aDocument, ErrorResult& aRv);
+      dom::Document* aDocument, ErrorResult& aRv);
   static TimingParams FromEffectTiming(const dom::EffectTiming& aEffectTiming,
-                                       nsIDocument* aDocument,
+                                       dom::Document* aDocument,
                                        ErrorResult& aRv);
   // Returns a copy of |aSource| where each timing property in |aSource| that
   // is also specified in |aEffectTiming| is replaced with the value from
   // |aEffectTiming|.
   //
   // If any of the values in |aEffectTiming| are invalid, |aRv.Failed()| will be
   // true and an unmodified copy of |aSource| will be returned.
   static TimingParams MergeOptionalEffectTiming(
       const TimingParams& aSource,
-      const dom::OptionalEffectTiming& aEffectTiming, nsIDocument* aDocument,
+      const dom::OptionalEffectTiming& aEffectTiming, dom::Document* aDocument,
       ErrorResult& aRv);
 
   // Range-checks and validates an UnrestrictedDoubleOrString or
   // OwningUnrestrictedDoubleOrString object and converts to a
   // StickyTimeDuration value or Nothing() if aDuration is "auto".
   // Caller must check aRv.Failed().
   template <class DoubleOrString>
   static Maybe<StickyTimeDuration> ParseDuration(DoubleOrString& aDuration,
@@ -110,17 +110,17 @@ struct TimingParams {
   static void ValidateIterations(double aIterations, ErrorResult& aRv) {
     if (IsNaN(aIterations) || aIterations < 0) {
       aRv.ThrowTypeError<dom::MSG_ENFORCE_RANGE_OUT_OF_RANGE>(
           NS_LITERAL_STRING("iterations"));
     }
   }
 
   static Maybe<ComputedTimingFunction> ParseEasing(const nsAString& aEasing,
-                                                   nsIDocument* aDocument,
+                                                   dom::Document* aDocument,
                                                    ErrorResult& aRv);
 
   static StickyTimeDuration CalcActiveDuration(
       const Maybe<StickyTimeDuration>& aDuration, double aIterations) {
     // If either the iteration duration or iteration count is zero,
     // Web Animations says that the active duration is zero. This is to
     // ensure that the result is defined when the other argument is Infinity.
     static const StickyTimeDuration zeroDuration;
--- a/dom/audiochannel/AudioChannelAgent.cpp
+++ b/dom/audiochannel/AudioChannelAgent.cpp
@@ -1,17 +1,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/. */
 
 #include "AudioChannelAgent.h"
 #include "AudioChannelService.h"
 #include "mozilla/Preferences.h"
 #include "nsContentUtils.h"
-#include "nsIDocument.h"
+#include "mozilla/dom/Document.h"
 #include "nsIDOMWindow.h"
 #include "nsPIDOMWindow.h"
 #include "nsIURI.h"
 
 using namespace mozilla::dom;
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(AudioChannelAgent)
 
@@ -81,17 +81,17 @@ nsresult AudioChannelAgent::FindCorrectW
     return NS_OK;
   }
 
   nsCOMPtr<nsPIDOMWindowInner> parent = outerParent->GetCurrentInnerWindow();
   if (!parent) {
     return NS_OK;
   }
 
-  nsCOMPtr<nsIDocument> doc = parent->GetExtantDoc();
+  nsCOMPtr<Document> doc = parent->GetExtantDoc();
   if (!doc) {
     return NS_OK;
   }
 
   if (nsContentUtils::IsChromeDoc(doc)) {
     return NS_OK;
   }
 
--- a/dom/audiochannel/AudioChannelService.cpp
+++ b/dom/audiochannel/AudioChannelService.cpp
@@ -872,17 +872,17 @@ void AudioChannelService::AudioChannelWi
     return;
   }
 
   nsCOMPtr<nsPIDOMWindowInner> inner = window->GetCurrentInnerWindow();
   if (!inner) {
     return;
   }
 
-  nsCOMPtr<nsIDocument> doc = inner->GetExtantDoc();
+  nsCOMPtr<Document> doc = inner->GetExtantDoc();
   if (!doc) {
     return;
   }
 
   if (window->GetMediaSuspend() != nsISuspendedTypes::SUSPENDED_BLOCK ||
       !doc->Hidden()) {
     return;
   }
--- a/dom/base/AnonymousContent.cpp
+++ b/dom/base/AnonymousContent.cpp
@@ -4,17 +4,17 @@
  * 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 "AnonymousContent.h"
 #include "mozilla/dom/Element.h"
 #include "mozilla/dom/AnonymousContentBinding.h"
 #include "nsComputedDOMStyle.h"
 #include "nsCycleCollectionParticipant.h"
-#include "nsIDocument.h"
+#include "mozilla/dom/Document.h"
 #include "nsIFrame.h"
 #include "nsStyledElement.h"
 #include "HTMLCanvasElement.h"
 
 namespace mozilla {
 namespace dom {
 
 // Ref counting and cycle collection
--- a/dom/base/AnonymousContent.h
+++ b/dom/base/AnonymousContent.h
@@ -5,17 +5,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_dom_AnonymousContent_h
 #define mozilla_dom_AnonymousContent_h
 
 #include "mozilla/dom/Element.h"
 #include "nsCycleCollectionParticipant.h"
 #include "nsICSSDeclaration.h"
-#include "nsIDocument.h"
+#include "mozilla/dom/Document.h"
 
 namespace mozilla {
 namespace dom {
 
 class Element;
 class UnrestrictedDoubleOrAnonymousKeyframeAnimationOptions;
 
 class AnonymousContent final {
--- a/dom/base/Attr.cpp
+++ b/dom/base/Attr.cpp
@@ -13,17 +13,17 @@
 #include "mozilla/dom/Element.h"
 #include "mozilla/EventDispatcher.h"
 #include "mozilla/InternalMutationEvent.h"
 #include "nsContentCreatorFunctions.h"
 #include "nsError.h"
 #include "nsUnicharUtils.h"
 #include "nsDOMString.h"
 #include "nsIContentInlines.h"
-#include "nsIDocument.h"
+#include "mozilla/dom/Document.h"
 #include "nsGkAtoms.h"
 #include "nsCOMArray.h"
 #include "nsNameSpaceManager.h"
 #include "nsNodeUtils.h"
 #include "nsTextNode.h"
 #include "mozAutoDocUpdate.h"
 #include "nsWrapperCacheInlines.h"
 #include "NodeUbiReporting.h"
@@ -110,20 +110,20 @@ void Attr::SetMap(nsDOMAttributeMap* aMa
 Element* Attr::GetElement() const {
   if (!mAttrMap) {
     return nullptr;
   }
   nsIContent* content = mAttrMap->GetContent();
   return content ? content->AsElement() : nullptr;
 }
 
-nsresult Attr::SetOwnerDocument(nsIDocument* aDocument) {
+nsresult Attr::SetOwnerDocument(Document* aDocument) {
   NS_ASSERTION(aDocument, "Missing document");
 
-  nsIDocument* doc = OwnerDoc();
+  Document* doc = OwnerDoc();
   NS_ASSERTION(doc != aDocument, "bad call to Attr::SetOwnerDocument");
   doc->DeleteAllPropertiesFor(this);
 
   RefPtr<dom::NodeInfo> newNodeInfo = aDocument->NodeInfoManager()->GetNodeInfo(
       mNodeInfo->NameAtom(), mNodeInfo->GetPrefixAtom(),
       mNodeInfo->NamespaceID(), ATTRIBUTE_NODE);
   NS_ASSERTION(newNodeInfo, "GetNodeInfo lies");
   mNodeInfo.swap(newNodeInfo);
--- a/dom/base/Attr.h
+++ b/dom/base/Attr.h
@@ -13,22 +13,22 @@
 
 #include "mozilla/Attributes.h"
 #include "nsINode.h"
 #include "nsString.h"
 #include "nsCOMPtr.h"
 #include "nsCycleCollectionParticipant.h"
 #include "nsStubMutationObserver.h"
 
-class nsIDocument;
-
 namespace mozilla {
 class EventChainPreVisitor;
 namespace dom {
 
+class Document;
+
 // Attribute helper class used to wrap up an attribute with a dom
 // object that implements the DOM Attr interface.
 class Attr final : public nsINode {
   virtual ~Attr() {}
 
  public:
   Attr(nsDOMAttributeMap* aAttrMap, already_AddRefed<dom::NodeInfo>&& aNodeInfo,
        const nsAString& aValue);
@@ -56,17 +56,17 @@ class Attr final : public nsINode {
   void SetMap(nsDOMAttributeMap* aMap);
 
   Element* GetElement() const;
 
   /**
    * Called when our ownerElement is moved into a new document.
    * Updates the nodeinfo of this node.
    */
-  nsresult SetOwnerDocument(nsIDocument* aDocument);
+  nsresult SetOwnerDocument(Document* aDocument);
 
   // nsINode interface
   virtual bool IsNodeOfType(uint32_t aFlags) const override;
   virtual nsresult Clone(dom::NodeInfo*, nsINode** aResult) const override;
   virtual already_AddRefed<nsIURI> GetBaseURI(
       bool aTryUseXHRDocBaseURI = false) const override;
 
   static void Initialize();
--- a/dom/base/AttrArray.cpp
+++ b/dom/base/AttrArray.cpp
@@ -18,16 +18,17 @@
 #include "nsMappedAttributeElement.h"
 #include "nsString.h"
 #include "nsHTMLStyleSheet.h"
 #include "nsMappedAttributes.h"
 #include "nsUnicharUtils.h"
 #include "nsContentUtils.h"  // nsAutoScriptBlocker
 
 using mozilla::CheckedUint32;
+using mozilla::dom::Document;
 
 AttrArray::Impl::~Impl() {
   for (InternalAttr& attr : NonMappedAttrs()) {
     attr.~InternalAttr();
   }
 
   NS_IF_RELEASE(mMappedAttrs);
 }
@@ -353,17 +354,17 @@ void AttrArray::Compact() {
 }
 
 uint32_t AttrArray::DoGetMappedAttrCount() const {
   MOZ_ASSERT(mImpl && mImpl->mMappedAttrs);
   return static_cast<uint32_t>(mImpl->mMappedAttrs->Count());
 }
 
 nsresult AttrArray::ForceMapped(nsMappedAttributeElement* aContent,
-                                nsIDocument* aDocument) {
+                                Document* aDocument) {
   nsHTMLStyleSheet* sheet = aDocument->GetAttributeStyleSheet();
   RefPtr<nsMappedAttributes> mapped =
       GetModifiableMapped(aContent, sheet, false, 0);
   return MakeMappedUnique(mapped);
 }
 
 void AttrArray::ClearMappedServoStyle() {
   if (mImpl && mImpl->mMappedAttrs) {
--- a/dom/base/AttrArray.h
+++ b/dom/base/AttrArray.h
@@ -105,17 +105,17 @@ class AttrArray {
   void Compact();
 
   size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
   bool HasMappedAttrs() const { return MappedAttrCount(); }
   const nsMappedAttributes* GetMapped() const;
 
   // Force this to have mapped attributes, even if those attributes are empty.
   nsresult ForceMapped(nsMappedAttributeElement* aContent,
-                       nsIDocument* aDocument);
+                       mozilla::dom::Document* aDocument);
 
   // Clear the servo declaration block on the mapped attributes, if any
   // Will assert off main thread
   void ClearMappedServoStyle();
 
   // Increases capacity (if necessary) to have enough space to accomodate the
   // unmapped attributes of |aOther|.
   nsresult EnsureCapacityToClone(const AttrArray& aOther);
--- a/dom/base/CharacterData.cpp
+++ b/dom/base/CharacterData.cpp
@@ -13,17 +13,17 @@
 
 #include "mozilla/DebugOnly.h"
 
 #include "mozilla/AsyncEventDispatcher.h"
 #include "mozilla/MemoryReporting.h"
 #include "mozilla/dom/Element.h"
 #include "mozilla/dom/HTMLSlotElement.h"
 #include "mozilla/dom/ShadowRoot.h"
-#include "nsIDocument.h"
+#include "mozilla/dom/Document.h"
 #include "nsReadableUtils.h"
 #include "mozilla/InternalMutationEvent.h"
 #include "nsIURI.h"
 #include "nsCOMPtr.h"
 #include "nsDOMString.h"
 #include "nsChangeHint.h"
 #include "nsCOMArray.h"
 #include "nsNodeUtils.h"
@@ -225,17 +225,17 @@ nsresult CharacterData::SetTextInternal(
 
   uint32_t endOffset = aOffset + aCount;
 
   // Make sure the text fragment can hold the new data.
   if (aLength > aCount && !mText.CanGrowBy(aLength - aCount)) {
     return NS_ERROR_OUT_OF_MEMORY;
   }
 
-  nsIDocument* document = GetComposedDoc();
+  Document* document = GetComposedDoc();
   mozAutoDocUpdate updateBatch(document, aNotify);
 
   bool haveMutationListeners =
       aNotify && nsContentUtils::HasMutationListeners(
                      this, NS_EVENT_BITS_MUTATION_CHARACTERDATAMODIFIED, this);
 
   RefPtr<nsAtom> oldValue;
   if (haveMutationListeners) {
@@ -385,17 +385,17 @@ void CharacterData::ToCString(nsAString&
       } else {
         aBuf.Append(ch);
       }
     }
   }
 }
 #endif
 
-nsresult CharacterData::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
+nsresult CharacterData::BindToTree(Document* 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() && !IsInUncomposedDoc(),
              "Already have a document.  Unbind first!");
@@ -495,17 +495,17 @@ nsresult CharacterData::BindToTree(nsIDo
 
   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);
 
-  nsIDocument* document = GetComposedDoc();
+  Document* document = GetComposedDoc();
 
   if (aNullParent) {
     if (this->IsRootOfNativeAnonymousSubtree()) {
       nsNodeUtils::NativeAnonymousChildListChange(this, true);
     }
     if (GetParent()) {
       NS_RELEASE(mParent);
     } else {
--- a/dom/base/CharacterData.h
+++ b/dom/base/CharacterData.h
@@ -18,18 +18,16 @@
 #include "nsTextFragment.h"
 #include "nsError.h"
 #include "mozilla/dom/Element.h"
 #include "nsCycleCollectionParticipant.h"
 
 #include "nsISMILAttr.h"
 #include "mozilla/dom/ShadowRoot.h"
 
-class nsIDocument;
-
 namespace mozilla {
 namespace dom {
 class HTMLSlotElement;
 }  // namespace dom
 }  // namespace mozilla
 
 #define CHARACTER_DATA_FLAG_BIT(n_) \
   NODE_FLAG_BIT(NODE_TYPE_SPECIFIC_BITS_OFFSET + (n_))
@@ -105,17 +103,17 @@ class CharacterData : public nsIContent 
                               nsIPrincipal* aSubjectPrincipal,
                               ErrorResult& aError) final {
     // Batch possible DOMSubtreeModified events.
     mozAutoSubtreeModified subtree(OwnerDoc(), nullptr);
     return SetNodeValue(aTextContent, aError);
   }
 
   // Implementation for nsIContent
-  nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent,
+  nsresult BindToTree(Document* aDocument, nsIContent* aParent,
                       nsIContent* aBindingParent) override;
 
   void UnbindFromTree(bool aDeep = true, bool aNullParent = true) override;
 
   already_AddRefed<nsINodeList> GetChildren(uint32_t aFilter) final {
     return nullptr;
   }
 
--- a/dom/base/ChildIterator.cpp
+++ b/dom/base/ChildIterator.cpp
@@ -1,23 +1,23 @@
 /* -*- 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 "ChildIterator.h"
 #include "nsContentUtils.h"
+#include "mozilla/dom/Document.h"
 #include "mozilla/dom/HTMLSlotElement.h"
 #include "mozilla/dom/XBLChildrenElement.h"
 #include "mozilla/dom/ShadowRoot.h"
 #include "nsIAnonymousContentCreator.h"
 #include "nsIFrame.h"
 #include "nsCSSAnonBoxes.h"
-#include "nsIDocument.h"
 
 namespace mozilla {
 namespace dom {
 
 ExplicitChildIterator::ExplicitChildIterator(const nsIContent* aParent,
                                              bool aStartAtBeginning)
     : mParent(aParent),
       mChild(nullptr),
--- a/dom/base/ChromeNodeList.cpp
+++ b/dom/base/ChromeNodeList.cpp
@@ -8,17 +8,17 @@
 #include "mozilla/dom/ChromeNodeListBinding.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
 already_AddRefed<ChromeNodeList> ChromeNodeList::Constructor(
     const GlobalObject& aGlobal, ErrorResult& aRv) {
   nsCOMPtr<nsPIDOMWindowInner> win = do_QueryInterface(aGlobal.GetAsSupports());
-  nsIDocument* root = win ? win->GetExtantDoc() : nullptr;
+  Document* root = win ? win->GetExtantDoc() : nullptr;
   RefPtr<ChromeNodeList> list = new ChromeNodeList(root);
   return list.forget();
 }
 
 JSObject* ChromeNodeList::WrapObject(JSContext* aCx,
                                      JS::Handle<JSObject*> aGivenProto) {
   return ChromeNodeList_Binding::Wrap(aCx, this, aGivenProto);
 }
--- a/dom/base/CustomElementRegistry.cpp
+++ b/dom/base/CustomElementRegistry.cpp
@@ -93,35 +93,35 @@ size_t LifecycleCallbackArgs::SizeOfExcl
   n += oldValue.SizeOfExcludingThisIfUnshared(aMallocSizeOf);
   n += newValue.SizeOfExcludingThisIfUnshared(aMallocSizeOf);
   n += namespaceURI.SizeOfExcludingThisIfUnshared(aMallocSizeOf);
   return n;
 }
 
 void CustomElementCallback::Call() {
   switch (mType) {
-    case nsIDocument::eConnected:
+    case Document::eConnected:
       static_cast<LifecycleConnectedCallback*>(mCallback.get())
           ->Call(mThisObject);
       break;
-    case nsIDocument::eDisconnected:
+    case Document::eDisconnected:
       static_cast<LifecycleDisconnectedCallback*>(mCallback.get())
           ->Call(mThisObject);
       break;
-    case nsIDocument::eAdopted:
+    case Document::eAdopted:
       static_cast<LifecycleAdoptedCallback*>(mCallback.get())
           ->Call(mThisObject, mAdoptedCallbackArgs.mOldDocument,
                  mAdoptedCallbackArgs.mNewDocument);
       break;
-    case nsIDocument::eAttributeChanged:
+    case Document::eAttributeChanged:
       static_cast<LifecycleAttributeChangedCallback*>(mCallback.get())
           ->Call(mThisObject, mArgs.name, mArgs.oldValue, mArgs.newValue,
                  mArgs.namespaceURI);
       break;
-    case nsIDocument::eGetCustomInterface:
+    case Document::eGetCustomInterface:
       MOZ_ASSERT_UNREACHABLE("Don't call GetCustomInterface through callback");
       break;
   }
 }
 
 void CustomElementCallback::Traverse(
     nsCycleCollectionTraversalCallback& aCb) const {
   NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(aCb, "mThisObject");
@@ -144,17 +144,17 @@ size_t CustomElementCallback::SizeOfIncl
   n += mArgs.SizeOfExcludingThis(aMallocSizeOf);
 
   // mAdoptedCallbackArgs doesn't really uniquely own its members.
 
   return n;
 }
 
 CustomElementCallback::CustomElementCallback(
-    Element* aThisObject, nsIDocument::ElementCallbackType aCallbackType,
+    Element* aThisObject, Document::ElementCallbackType aCallbackType,
     mozilla::dom::CallbackFunction* aCallback)
     : mThisObject(aThisObject), mCallback(aCallback), mType(aCallbackType) {}
 //-----------------------------------------------------
 // CustomElementConstructor
 
 already_AddRefed<Element> CustomElementConstructor::Construct(
     const char* aExecutionReason, ErrorResult& aRv) {
   CallSetup s(this, aRv, aExecutionReason,
@@ -441,52 +441,52 @@ void CustomElementRegistry::UnregisterUn
   if (mCandidatesMap.Get(aTypeName, &candidates)) {
     MOZ_ASSERT(candidates);
     candidates->RemoveEntry(weak);
   }
 }
 
 /* static */ UniquePtr<CustomElementCallback>
 CustomElementRegistry::CreateCustomElementCallback(
-    nsIDocument::ElementCallbackType aType, Element* aCustomElement,
+    Document::ElementCallbackType aType, Element* aCustomElement,
     LifecycleCallbackArgs* aArgs,
     LifecycleAdoptedCallbackArgs* aAdoptedCallbackArgs,
     CustomElementDefinition* aDefinition) {
   MOZ_ASSERT(aDefinition, "CustomElementDefinition should not be null");
   MOZ_ASSERT(aCustomElement->GetCustomElementData(),
              "CustomElementData should exist");
 
   // Let CALLBACK be the callback associated with the key NAME in CALLBACKS.
   CallbackFunction* func = nullptr;
   switch (aType) {
-    case nsIDocument::eConnected:
+    case Document::eConnected:
       if (aDefinition->mCallbacks->mConnectedCallback.WasPassed()) {
         func = aDefinition->mCallbacks->mConnectedCallback.Value();
       }
       break;
 
-    case nsIDocument::eDisconnected:
+    case Document::eDisconnected:
       if (aDefinition->mCallbacks->mDisconnectedCallback.WasPassed()) {
         func = aDefinition->mCallbacks->mDisconnectedCallback.Value();
       }
       break;
 
-    case nsIDocument::eAdopted:
+    case Document::eAdopted:
       if (aDefinition->mCallbacks->mAdoptedCallback.WasPassed()) {
         func = aDefinition->mCallbacks->mAdoptedCallback.Value();
       }
       break;
 
-    case nsIDocument::eAttributeChanged:
+    case Document::eAttributeChanged:
       if (aDefinition->mCallbacks->mAttributeChangedCallback.WasPassed()) {
         func = aDefinition->mCallbacks->mAttributeChangedCallback.Value();
       }
       break;
 
-    case nsIDocument::eGetCustomInterface:
+    case Document::eGetCustomInterface:
       MOZ_ASSERT_UNREACHABLE("Don't call GetCustomInterface through callback");
       break;
   }
 
   // If there is no such callback, stop.
   if (!func) {
     return nullptr;
   }
@@ -501,17 +501,17 @@ CustomElementRegistry::CreateCustomEleme
 
   if (aAdoptedCallbackArgs) {
     callback->SetAdoptedCallbackArgs(*aAdoptedCallbackArgs);
   }
   return callback;
 }
 
 /* static */ void CustomElementRegistry::EnqueueLifecycleCallback(
-    nsIDocument::ElementCallbackType aType, Element* aCustomElement,
+    Document::ElementCallbackType aType, Element* aCustomElement,
     LifecycleCallbackArgs* aArgs,
     LifecycleAdoptedCallbackArgs* aAdoptedCallbackArgs,
     CustomElementDefinition* aDefinition) {
   CustomElementDefinition* definition = aDefinition;
   if (!definition) {
     definition = aCustomElement->GetCustomElementDefinition();
     if (!definition ||
         definition->mLocalName != aCustomElement->NodeInfo()->NameAtom()) {
@@ -530,17 +530,17 @@ CustomElementRegistry::CreateCustomEleme
     return;
   }
 
   DocGroup* docGroup = aCustomElement->OwnerDoc()->GetDocGroup();
   if (!docGroup) {
     return;
   }
 
-  if (aType == nsIDocument::eAttributeChanged) {
+  if (aType == Document::eAttributeChanged) {
     RefPtr<nsAtom> attrName = NS_Atomize(aArgs->name);
     if (definition->mObservedAttributes.IsEmpty() ||
         !definition->mObservedAttributes.Contains(attrName)) {
       return;
     }
   }
 
   CustomElementReactionsStack* reactionsStack =
@@ -548,29 +548,29 @@ CustomElementRegistry::CreateCustomEleme
   reactionsStack->EnqueueCallbackReaction(aCustomElement, std::move(callback));
 }
 
 namespace {
 
 class CandidateFinder {
  public:
   CandidateFinder(nsTHashtable<nsRefPtrHashKey<nsIWeakReference>>& aCandidates,
-                  nsIDocument* aDoc);
+                  Document* aDoc);
   nsTArray<nsCOMPtr<Element>> OrderedCandidates();
 
  private:
   bool Traverse(Element* aRoot, nsTArray<nsCOMPtr<Element>>& aOrderedElements);
 
-  nsCOMPtr<nsIDocument> mDoc;
+  nsCOMPtr<Document> mDoc;
   nsInterfaceHashtable<nsPtrHashKey<Element>, Element> mCandidates;
 };
 
 CandidateFinder::CandidateFinder(
     nsTHashtable<nsRefPtrHashKey<nsIWeakReference>>& aCandidates,
-    nsIDocument* aDoc)
+    Document* aDoc)
     : mDoc(aDoc), mCandidates(aCandidates.Count()) {
   MOZ_ASSERT(mDoc);
   for (auto iter = aCandidates.Iter(); !iter.Done(); iter.Next()) {
     nsCOMPtr<Element> elem = do_QueryReferent(iter.Get()->GetKey());
     if (!elem) {
       continue;
     }
 
@@ -709,17 +709,17 @@ void CustomElementRegistry::Define(JSCon
   }
 
   int32_t nameSpaceID = InferNamespace(aCx, constructor);
 
   /**
    * 2. If name is not a valid custom element name, then throw a "SyntaxError"
    *    DOMException and abort these steps.
    */
-  nsIDocument* doc = mWindow->GetExtantDoc();
+  Document* doc = mWindow->GetExtantDoc();
   RefPtr<nsAtom> nameAtom(NS_Atomize(aName));
   if (!nsContentUtils::IsCustomElementName(nameAtom, nameSpaceID)) {
     aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR);
     return;
   }
 
   /**
    * 3. If this CustomElementRegistry contains an entry with name name, then
@@ -1055,17 +1055,17 @@ already_AddRefed<Promise> CustomElementR
   nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(mWindow);
   RefPtr<Promise> promise = Promise::Create(global, aRv);
 
   if (aRv.Failed()) {
     return nullptr;
   }
 
   RefPtr<nsAtom> nameAtom(NS_Atomize(aName));
-  nsIDocument* doc = mWindow->GetExtantDoc();
+  Document* doc = mWindow->GetExtantDoc();
   uint32_t nameSpaceID =
       doc ? doc->GetDefaultNamespaceID() : kNameSpaceID_XHTML;
   if (!nsContentUtils::IsCustomElementName(nameAtom, nameSpaceID)) {
     promise->MaybeReject(NS_ERROR_DOM_SYNTAX_ERR);
     return promise.forget();
   }
 
   if (mCustomDefinitions.GetWeak(nameAtom)) {
@@ -1129,26 +1129,25 @@ static void DoUpgrade(Element* aElement,
         nsAutoString attrValue, namespaceURI;
         info.mValue->ToString(attrValue);
         nsContentUtils::NameSpaceManager()->GetNameSpaceURI(namespaceID,
                                                             namespaceURI);
 
         LifecycleCallbackArgs args = {
             nsDependentAtomString(attrName), VoidString(), attrValue,
             (namespaceURI.IsEmpty() ? VoidString() : namespaceURI)};
-        nsContentUtils::EnqueueLifecycleCallback(nsIDocument::eAttributeChanged,
-                                                 aElement, &args, nullptr,
-                                                 aDefinition);
+        nsContentUtils::EnqueueLifecycleCallback(
+            Document::eAttributeChanged, aElement, &args, nullptr, aDefinition);
       }
     }
   }
 
   // Step 4.
   if (aElement->IsInComposedDoc()) {
-    nsContentUtils::EnqueueLifecycleCallback(nsIDocument::eConnected, aElement,
+    nsContentUtils::EnqueueLifecycleCallback(Document::eConnected, aElement,
                                              nullptr, nullptr, aDefinition);
   }
 
   // Step 5.
   AutoConstructionStackEntry acs(aDefinition->mConstructionStack, aElement);
 
   // Step 6 and step 7.
   DoUpgrade(aElement, aDefinition->mConstructor, aRv);
--- a/dom/base/CustomElementRegistry.h
+++ b/dom/base/CustomElementRegistry.h
@@ -38,47 +38,47 @@ struct LifecycleCallbackArgs {
   nsString oldValue;
   nsString newValue;
   nsString namespaceURI;
 
   size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const;
 };
 
 struct LifecycleAdoptedCallbackArgs {
-  nsCOMPtr<nsIDocument> mOldDocument;
-  nsCOMPtr<nsIDocument> mNewDocument;
+  RefPtr<Document> mOldDocument;
+  RefPtr<Document> mNewDocument;
 };
 
 class CustomElementCallback {
  public:
   CustomElementCallback(Element* aThisObject,
-                        nsIDocument::ElementCallbackType aCallbackType,
+                        Document::ElementCallbackType aCallbackType,
                         CallbackFunction* aCallback);
   void Traverse(nsCycleCollectionTraversalCallback& aCb) const;
   size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const;
   void Call();
   void SetArgs(LifecycleCallbackArgs& aArgs) {
-    MOZ_ASSERT(mType == nsIDocument::eAttributeChanged,
+    MOZ_ASSERT(mType == Document::eAttributeChanged,
                "Arguments are only used by attribute changed callback.");
     mArgs = aArgs;
   }
 
   void SetAdoptedCallbackArgs(
       LifecycleAdoptedCallbackArgs& aAdoptedCallbackArgs) {
-    MOZ_ASSERT(mType == nsIDocument::eAdopted,
+    MOZ_ASSERT(mType == Document::eAdopted,
                "Arguments are only used by adopted callback.");
     mAdoptedCallbackArgs = aAdoptedCallbackArgs;
   }
 
  private:
   // The this value to use for invocation of the callback.
   RefPtr<Element> mThisObject;
   RefPtr<CallbackFunction> mCallback;
   // The type of callback (eCreated, eAttached, etc.)
-  nsIDocument::ElementCallbackType mType;
+  Document::ElementCallbackType mType;
   // Arguments to be passed to the callback,
   // used by the attribute changed callback.
   LifecycleCallbackArgs mArgs;
   LifecycleAdoptedCallbackArgs mAdoptedCallbackArgs;
 };
 
 class CustomElementConstructor final : public CallbackFunction {
  public:
@@ -344,17 +344,16 @@ class CustomElementReactionsStack {
     }
 
    private:
     RefPtr<CustomElementReactionsStack> mReactionStack;
   };
 };
 
 class CustomElementRegistry final : public nsISupports, public nsWrapperCache {
-
  public:
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(CustomElementRegistry)
 
  public:
   explicit CustomElementRegistry(nsPIDOMWindowInner* aWindow);
 
  private:
@@ -394,17 +393,17 @@ class CustomElementRegistry final : publ
   CustomElementDefinition* LookupCustomElementDefinition(nsAtom* aNameAtom,
                                                          int32_t aNameSpaceID,
                                                          nsAtom* aTypeAtom);
 
   CustomElementDefinition* LookupCustomElementDefinition(
       JSContext* aCx, JSObject* aConstructor) const;
 
   static void EnqueueLifecycleCallback(
-      nsIDocument::ElementCallbackType aType, Element* aCustomElement,
+      Document::ElementCallbackType aType, Element* aCustomElement,
       LifecycleCallbackArgs* aArgs,
       LifecycleAdoptedCallbackArgs* aAdoptedCallbackArgs,
       CustomElementDefinition* aDefinition);
 
   /**
    * Upgrade an element.
    * https://html.spec.whatwg.org/multipage/scripting.html#upgrades
    */
@@ -469,17 +468,17 @@ class CustomElementRegistry final : publ
     nsWeakPtr elem = do_GetWeakReference(aElement);
     elements->PutEntry(elem);
   }
 
  private:
   ~CustomElementRegistry();
 
   static UniquePtr<CustomElementCallback> CreateCustomElementCallback(
-      nsIDocument::ElementCallbackType aType, Element* aCustomElement,
+      Document::ElementCallbackType aType, Element* aCustomElement,
       LifecycleCallbackArgs* aArgs,
       LifecycleAdoptedCallbackArgs* aAdoptedCallbackArgs,
       CustomElementDefinition* aDefinition);
 
   void UpgradeCandidates(nsAtom* aKey, CustomElementDefinition* aDefinition,
                          ErrorResult& aRv);
 
   typedef nsRefPtrHashtable<nsRefPtrHashKey<nsAtom>, CustomElementDefinition>
--- a/dom/base/DOMError.cpp
+++ b/dom/base/DOMError.cpp
@@ -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/. */
 
 #include "mozilla/dom/DOMError.h"
 #include "mozilla/dom/DOMErrorBinding.h"
 #include "mozilla/dom/DOMException.h"
 #include "mozilla/UseCounter.h"
-#include "nsIDocument.h"
+#include "mozilla/dom/Document.h"
 #include "nsPIDOMWindow.h"
 
 namespace mozilla {
 namespace dom {
 
 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(DOMError, mWindow)
 NS_IMPL_CYCLE_COLLECTING_ADDREF(DOMError)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(DOMError)
@@ -50,17 +50,17 @@ JSObject* DOMError::WrapObject(JSContext
 
 /* static */ already_AddRefed<DOMError> DOMError::Constructor(
     const GlobalObject& aGlobal, const nsAString& aName,
     const nsAString& aMessage, ErrorResult& aRv) {
   nsCOMPtr<nsPIDOMWindowInner> window =
       do_QueryInterface(aGlobal.GetAsSupports());
 
   if (window) {
-    nsCOMPtr<nsIDocument> doc = window->GetExtantDoc();
+    nsCOMPtr<Document> doc = window->GetExtantDoc();
     if (doc) {
       doc->SetDocumentAndPageUseCounter(eUseCounter_custom_DOMErrorConstructor);
     }
   }
 
   // Window is null for chrome code.
 
   RefPtr<DOMError> ret = new DOMError(window, aName, aMessage);
--- a/dom/base/DOMException.cpp
+++ b/dom/base/DOMException.cpp
@@ -6,17 +6,17 @@
 
 #include "mozilla/dom/DOMException.h"
 
 #include "mozilla/ArrayUtils.h"
 #include "mozilla/HoldDropJSObjects.h"
 #include "mozilla/dom/Exceptions.h"
 #include "nsContentUtils.h"
 #include "nsCOMPtr.h"
-#include "nsIDocument.h"
+#include "mozilla/dom/Document.h"
 #include "nsIException.h"
 #include "nsMemory.h"
 #include "xpcprivate.h"
 
 #include "mozilla/dom/DOMExceptionBinding.h"
 #include "mozilla/ErrorResult.h"
 
 using namespace mozilla;
--- a/dom/base/DOMImplementation.cpp
+++ b/dom/base/DOMImplementation.cpp
@@ -55,17 +55,17 @@ already_AddRefed<DocumentType> DOMImplem
   RefPtr<DocumentType> docType = NS_NewDOMDocumentType(
       mOwner->NodeInfoManager(), name, aPublicId, aSystemId, VoidString());
   return docType.forget();
 }
 
 nsresult DOMImplementation::CreateDocument(const nsAString& aNamespaceURI,
                                            const nsAString& aQualifiedName,
                                            DocumentType* aDoctype,
-                                           nsIDocument** aDocument) {
+                                           Document** aDocument) {
   *aDocument = nullptr;
 
   nsresult rv;
   if (!aQualifiedName.IsEmpty()) {
     const nsString& qName = PromiseFlatString(aQualifiedName);
     const char16_t* colon;
     rv = nsContentUtils::CheckQName(qName, true, &colon);
     NS_ENSURE_SUCCESS(rv, rv);
@@ -78,17 +78,17 @@ nsresult DOMImplementation::CreateDocume
     }
   }
 
   nsCOMPtr<nsIGlobalObject> scriptHandlingObject =
       do_QueryReferent(mScriptObject);
 
   NS_ENSURE_STATE(!mScriptObject || scriptHandlingObject);
 
-  nsCOMPtr<nsIDocument> doc;
+  nsCOMPtr<Document> doc;
 
   rv = NS_NewDOMDocument(getter_AddRefs(doc), aNamespaceURI, aQualifiedName,
                          aDoctype, mDocumentURI, mBaseURI,
                          mOwner->NodePrincipal(), true, scriptHandlingObject,
                          DocumentFlavorLegacyGuess);
   NS_ENSURE_SUCCESS(rv, rv);
 
   // When DOMImplementation's createDocument method is invoked with
@@ -98,33 +98,33 @@ nsresult DOMImplementation::CreateDocume
   if (aNamespaceURI.EqualsLiteral("http://www.w3.org/1999/xhtml")) {
     doc->SetContentType(NS_LITERAL_STRING("application/xhtml+xml"));
   } else if (aNamespaceURI.EqualsLiteral("http://www.w3.org/2000/svg")) {
     doc->SetContentType(NS_LITERAL_STRING("image/svg+xml"));
   } else {
     doc->SetContentType(NS_LITERAL_STRING("application/xml"));
   }
 
-  doc->SetReadyStateInternal(nsIDocument::READYSTATE_COMPLETE);
+  doc->SetReadyStateInternal(Document::READYSTATE_COMPLETE);
 
   doc.forget(aDocument);
   return NS_OK;
 }
 
-already_AddRefed<nsIDocument> DOMImplementation::CreateDocument(
+already_AddRefed<Document> DOMImplementation::CreateDocument(
     const nsAString& aNamespaceURI, const nsAString& aQualifiedName,
     DocumentType* aDoctype, ErrorResult& aRv) {
-  nsCOMPtr<nsIDocument> document;
+  nsCOMPtr<Document> document;
   aRv = CreateDocument(aNamespaceURI, aQualifiedName, aDoctype,
                        getter_AddRefs(document));
   return document.forget();
 }
 
 nsresult DOMImplementation::CreateHTMLDocument(const nsAString& aTitle,
-                                               nsIDocument** aDocument) {
+                                               Document** aDocument) {
   *aDocument = nullptr;
 
   NS_ENSURE_STATE(mOwner);
 
   // Indicate that there is no internal subset (not just an empty one)
   RefPtr<DocumentType> doctype =
       NS_NewDOMDocumentType(mOwner->NodeInfoManager(),
                             nsGkAtoms::html,  // aName
@@ -132,17 +132,17 @@ nsresult DOMImplementation::CreateHTMLDo
                             EmptyString(),    // aSystemId
                             VoidString());    // aInternalSubset
 
   nsCOMPtr<nsIGlobalObject> scriptHandlingObject =
       do_QueryReferent(mScriptObject);
 
   NS_ENSURE_STATE(!mScriptObject || scriptHandlingObject);
 
-  nsCOMPtr<nsIDocument> doc;
+  nsCOMPtr<Document> doc;
   nsresult rv = NS_NewDOMDocument(
       getter_AddRefs(doc), EmptyString(), EmptyString(), doctype, mDocumentURI,
       mBaseURI, mOwner->NodePrincipal(), true, scriptHandlingObject,
       DocumentFlavorLegacyGuess);
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsCOMPtr<Element> root =
       doc->CreateElem(NS_LITERAL_STRING("html"), nullptr, kNameSpaceID_XHTML);
@@ -167,24 +167,24 @@ nsresult DOMImplementation::CreateHTMLDo
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   nsCOMPtr<Element> body =
       doc->CreateElem(NS_LITERAL_STRING("body"), nullptr, kNameSpaceID_XHTML);
   rv = root->AppendChildTo(body, false);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  doc->SetReadyStateInternal(nsIDocument::READYSTATE_COMPLETE);
+  doc->SetReadyStateInternal(Document::READYSTATE_COMPLETE);
 
   doc.forget(aDocument);
   return NS_OK;
 }
 
-already_AddRefed<nsIDocument> DOMImplementation::CreateHTMLDocument(
+already_AddRefed<Document> DOMImplementation::CreateHTMLDocument(
     const Optional<nsAString>& aTitle, ErrorResult& aRv) {
-  nsCOMPtr<nsIDocument> document;
+  nsCOMPtr<Document> document;
   aRv = CreateHTMLDocument(aTitle.WasPassed() ? aTitle.Value() : VoidString(),
                            getter_AddRefs(document));
   return document.forget();
 }
 
 }  // namespace dom
 }  // namespace mozilla
--- a/dom/base/DOMImplementation.h
+++ b/dom/base/DOMImplementation.h
@@ -8,68 +8,69 @@
 #define mozilla_dom_DOMImplementation_h
 
 #include "nsWrapperCache.h"
 
 #include "mozilla/Attributes.h"
 #include "mozilla/ErrorResult.h"
 #include "nsCOMPtr.h"
 #include "nsCycleCollectionParticipant.h"
-#include "nsIDocument.h"
+#include "mozilla/dom/Document.h"
 #include "nsIScriptGlobalObject.h"
 #include "nsIURI.h"
 #include "nsIWeakReferenceUtils.h"
 #include "nsString.h"
 
 namespace mozilla {
 namespace dom {
+class Document;
 class DocumentType;
 
 class DOMImplementation final : public nsISupports, public nsWrapperCache {
   ~DOMImplementation() {}
 
  public:
-  DOMImplementation(nsIDocument* aOwner, nsIGlobalObject* aScriptObject,
+  DOMImplementation(Document* aOwner, nsIGlobalObject* aScriptObject,
                     nsIURI* aDocumentURI, nsIURI* aBaseURI)
       : mOwner(aOwner),
         mScriptObject(do_GetWeakReference(aScriptObject)),
         mDocumentURI(aDocumentURI),
         mBaseURI(aBaseURI) {
     MOZ_ASSERT(aOwner);
   }
 
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(DOMImplementation)
 
-  nsIDocument* GetParentObject() const { return mOwner; }
+  Document* GetParentObject() const { return mOwner; }
 
   virtual JSObject* WrapObject(JSContext* aCx,
                                JS::Handle<JSObject*> aGivenProto) override;
 
   bool HasFeature() { return true; }
 
   already_AddRefed<DocumentType> CreateDocumentType(
       const nsAString& aQualifiedName, const nsAString& aPublicId,
       const nsAString& aSystemId, ErrorResult& aRv);
 
-  already_AddRefed<nsIDocument> CreateDocument(const nsAString& aNamespaceURI,
-                                               const nsAString& aQualifiedName,
-                                               DocumentType* aDoctype,
-                                               ErrorResult& aRv);
+  already_AddRefed<Document> CreateDocument(const nsAString& aNamespaceURI,
+                                            const nsAString& aQualifiedName,
+                                            DocumentType* aDoctype,
+                                            ErrorResult& aRv);
 
-  already_AddRefed<nsIDocument> CreateHTMLDocument(
+  already_AddRefed<Document> CreateHTMLDocument(
       const Optional<nsAString>& aTitle, ErrorResult& aRv);
 
  private:
   nsresult CreateDocument(const nsAString& aNamespaceURI,
                           const nsAString& aQualifiedName,
-                          DocumentType* aDoctype, nsIDocument** aDocument);
-  nsresult CreateHTMLDocument(const nsAString& aTitle, nsIDocument** aDocument);
+                          DocumentType* aDoctype, Document** aDocument);
+  nsresult CreateHTMLDocument(const nsAString& aTitle, Document** aDocument);
 
-  nsCOMPtr<nsIDocument> mOwner;
+  nsCOMPtr<Document> mOwner;
   nsWeakPtr mScriptObject;
   nsCOMPtr<nsIURI> mDocumentURI;
   nsCOMPtr<nsIURI> mBaseURI;
 };
 
 }  // namespace dom
 }  // namespace mozilla
 
--- a/dom/base/DOMIntersectionObserver.cpp
+++ b/dom/base/DOMIntersectionObserver.cpp
@@ -221,17 +221,17 @@ static Maybe<nsRect> EdgeInclusiveInters
 }
 
 enum class BrowsingContextInfo {
   SimilarOriginBrowsingContext,
   DifferentOriginBrowsingContext,
   UnknownBrowsingContext
 };
 
-void DOMIntersectionObserver::Update(nsIDocument* aDocument,
+void DOMIntersectionObserver::Update(Document* aDocument,
                                      DOMHighResTimeStamp time) {
   Element* root = nullptr;
   nsIFrame* rootFrame = nullptr;
   nsRect rootRect;
 
   if (mRoot) {
     root = mRoot;
     rootFrame = root->GetPrimaryFrame();
--- a/dom/base/DOMIntersectionObserver.h
+++ b/dom/base/DOMIntersectionObserver.h
@@ -126,30 +126,30 @@ class DOMIntersectionObserver final : pu
   void TakeRecords(nsTArray<RefPtr<DOMIntersectionObserverEntry>>& aRetVal);
 
   mozilla::dom::IntersectionCallback* IntersectionCallback() {
     return mCallback;
   }
 
   bool SetRootMargin(const nsAString& aString);
 
-  void Update(nsIDocument* aDocument, DOMHighResTimeStamp time);
+  void Update(Document* aDocument, DOMHighResTimeStamp time);
   void Notify();
 
  protected:
   void Connect();
   void QueueIntersectionObserverEntry(Element* aTarget,
                                       DOMHighResTimeStamp time,
                                       const Maybe<nsRect>& aRootRect,
                                       const nsRect& aTargetRect,
                                       const Maybe<nsRect>& aIntersectionRect,
                                       double aIntersectionRatio);
 
   nsCOMPtr<nsPIDOMWindowInner> mOwner;
-  RefPtr<nsIDocument> mDocument;
+  RefPtr<Document> mDocument;
   RefPtr<mozilla::dom::IntersectionCallback> mCallback;
   RefPtr<Element> mRoot;
   nsStyleSides mRootMargin;
   nsTArray<double> mThresholds;
 
   // Holds raw pointers which are explicitly cleared by UnlinkTarget().
   nsTArray<Element*> mObservationTargets;
 
--- a/dom/base/DOMParser.cpp
+++ b/dom/base/DOMParser.cpp
@@ -50,21 +50,21 @@ NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(DO
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(DOMParser)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(DOMParser)
 
 static const char* StringFromSupportedType(SupportedType aType) {
   return SupportedTypeValues::strings[static_cast<int>(aType)].value;
 }
 
-already_AddRefed<nsIDocument> DOMParser::ParseFromString(const nsAString& aStr,
-                                                         SupportedType aType,
-                                                         ErrorResult& aRv) {
+already_AddRefed<Document> DOMParser::ParseFromString(const nsAString& aStr,
+                                                      SupportedType aType,
+                                                      ErrorResult& aRv) {
   if (aType == SupportedType::Text_html) {
-    nsCOMPtr<nsIDocument> document = SetUpDocument(DocumentFlavorHTML, aRv);
+    nsCOMPtr<Document> document = SetUpDocument(DocumentFlavorHTML, aRv);
     if (NS_WARN_IF(aRv.Failed())) {
       return nullptr;
     }
 
     // Keep the XULXBL state in sync with the XML case.
     if (mForceEnableXULXBL) {
       document->ForceEnableXULXBL();
     }
@@ -93,41 +93,44 @@ already_AddRefed<nsIDocument> DOMParser:
     aRv.Throw(rv);
     return nullptr;
   }
 
   return ParseFromStream(stream, NS_LITERAL_STRING("UTF-8"), utf8str.Length(),
                          aType, aRv);
 }
 
-already_AddRefed<nsIDocument> DOMParser::ParseFromBuffer(const Uint8Array& aBuf,
-                                                         SupportedType aType,
-                                                         ErrorResult& aRv) {
+already_AddRefed<Document> DOMParser::ParseFromBuffer(const Uint8Array& aBuf,
+                                                      SupportedType aType,
+                                                      ErrorResult& aRv) {
   aBuf.ComputeLengthAndData();
   return ParseFromBuffer(MakeSpan(aBuf.Data(), aBuf.Length()), aType, aRv);
 }
 
-already_AddRefed<nsIDocument> DOMParser::ParseFromBuffer(
-    Span<const uint8_t> aBuf, SupportedType aType, ErrorResult& aRv) {
+already_AddRefed<Document> DOMParser::ParseFromBuffer(Span<const uint8_t> aBuf,
+                                                      SupportedType aType,
+                                                      ErrorResult& aRv) {
   // The new stream holds a reference to the buffer
   nsCOMPtr<nsIInputStream> stream;
   nsresult rv = NS_NewByteInputStream(
       getter_AddRefs(stream), reinterpret_cast<const char*>(aBuf.Elements()),
       aBuf.Length(), NS_ASSIGNMENT_DEPEND);
   if (NS_FAILED(rv)) {
     aRv.Throw(rv);
     return nullptr;
   }
 
   return ParseFromStream(stream, VoidString(), aBuf.Length(), aType, aRv);
 }
 
-already_AddRefed<nsIDocument> DOMParser::ParseFromStream(
-    nsIInputStream* aStream, const nsAString& aCharset, int32_t aContentLength,
-    SupportedType aType, ErrorResult& aRv) {
+already_AddRefed<Document> DOMParser::ParseFromStream(nsIInputStream* aStream,
+                                                      const nsAString& aCharset,
+                                                      int32_t aContentLength,
+                                                      SupportedType aType,
+                                                      ErrorResult& aRv) {
   bool svg = (aType == SupportedType::Image_svg_xml);
 
   // For now, we can only create XML documents.
   // XXXsmaug Should we create an HTMLDocument (in XHTML mode)
   //         for "application/xhtml+xml"?
   if (aType != SupportedType::Text_xml &&
       aType != SupportedType::Application_xml &&
       aType != SupportedType::Application_xhtml_xml && !svg) {
@@ -144,17 +147,17 @@ already_AddRefed<nsIDocument> DOMParser:
     if (NS_WARN_IF(NS_FAILED(rv))) {
       aRv.Throw(rv);
       return nullptr;
     }
 
     stream = bufferedStream;
   }
 
-  nsCOMPtr<nsIDocument> document =
+  nsCOMPtr<Document> document =
       SetUpDocument(svg ? DocumentFlavorSVG : DocumentFlavorLegacyGuess, aRv);
   if (NS_WARN_IF(aRv.Failed())) {
     return nullptr;
   }
 
   // Create a fake channel
   nsCOMPtr<nsIChannel> parserChannel;
   NS_NewInputStreamChannel(getter_AddRefs(parserChannel), mDocumentURI,
@@ -264,31 +267,31 @@ already_AddRefed<DOMParser> DOMParser::C
     return nullptr;
   }
 
   RefPtr<DOMParser> domParser =
       new DOMParser(nullptr, docPrincipal, documentURI, nullptr);
   return domParser.forget();
 }
 
-already_AddRefed<nsIDocument> DOMParser::SetUpDocument(DocumentFlavor aFlavor,
-                                                       ErrorResult& aRv) {
-  // We should really just use mOwner here, but nsIDocument gets confused
+already_AddRefed<Document> DOMParser::SetUpDocument(DocumentFlavor aFlavor,
+                                                    ErrorResult& aRv) {
+  // We should really just use mOwner here, but Document gets confused
   // if we pass it a scriptHandlingObject that doesn't QI to
   // nsIScriptGlobalObject, and test_isequalnode.js (an xpcshell test without
-  // a window global) breaks. The correct solution is just to wean nsIDocument
-  // off of nsIScriptGlobalObject, but that's a yak to shave another day.
+  // a window global) breaks. The correct solution is just to wean Document off
+  // of nsIScriptGlobalObject, but that's a yak to shave another day.
   nsCOMPtr<nsIScriptGlobalObject> scriptHandlingObject =
       do_QueryInterface(mOwner);
 
   // Try to inherit a style backend.
   NS_ASSERTION(mPrincipal, "Must have principal by now");
   NS_ASSERTION(mDocumentURI, "Must have document URI by now");
 
-  nsCOMPtr<nsIDocument> doc;
+  nsCOMPtr<Document> doc;
   nsresult rv = NS_NewDOMDocument(
       getter_AddRefs(doc), EmptyString(), EmptyString(), nullptr, mDocumentURI,
       mBaseURI, mPrincipal, true, scriptHandlingObject, aFlavor);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     aRv.Throw(rv);
     return nullptr;
   }
 
--- a/dom/base/DOMParser.h
+++ b/dom/base/DOMParser.h
@@ -3,24 +3,23 @@
 /* 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_DOMParser_h_
 #define mozilla_dom_DOMParser_h_
 
 #include "nsCOMPtr.h"
-#include "nsIDocument.h"
+#include "mozilla/dom/Document.h"
 #include "nsWrapperCache.h"
 #include "mozilla/ErrorResult.h"
 #include "mozilla/Span.h"
 #include "mozilla/dom/DOMParserBinding.h"
 #include "mozilla/dom/TypedArray.h"
 
-class nsIDocument;
 class nsIGlobalObject;
 
 namespace mozilla {
 namespace dom {
 
 class DOMParser final : public nsISupports, public nsWrapperCache {
   typedef mozilla::dom::GlobalObject GlobalObject;
 
@@ -29,35 +28,35 @@ class DOMParser final : public nsISuppor
  public:
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(DOMParser)
 
   // WebIDL API
   static already_AddRefed<DOMParser> Constructor(const GlobalObject& aOwner,
                                                  mozilla::ErrorResult& rv);
 
-  already_AddRefed<nsIDocument> ParseFromString(const nsAString& aStr,
-                                                SupportedType aType,
-                                                ErrorResult& aRv);
+  already_AddRefed<Document> ParseFromString(const nsAString& aStr,
+                                             SupportedType aType,
+                                             ErrorResult& aRv);
 
   // Sequence converts to Span, so we can use this overload for both
   // the Sequence case and our internal uses.
-  already_AddRefed<nsIDocument> ParseFromBuffer(Span<const uint8_t> aBuf,
-                                                SupportedType aType,
-                                                ErrorResult& aRv);
+  already_AddRefed<Document> ParseFromBuffer(Span<const uint8_t> aBuf,
+                                             SupportedType aType,
+                                             ErrorResult& aRv);
 
-  already_AddRefed<nsIDocument> ParseFromBuffer(const Uint8Array& aBuf,
-                                                SupportedType aType,
-                                                ErrorResult& aRv);
+  already_AddRefed<Document> ParseFromBuffer(const Uint8Array& aBuf,
+                                             SupportedType aType,
+                                             ErrorResult& aRv);
 
-  already_AddRefed<nsIDocument> ParseFromStream(nsIInputStream* aStream,
-                                                const nsAString& aCharset,
-                                                int32_t aContentLength,
-                                                SupportedType aType,
-                                                ErrorResult& aRv);
+  already_AddRefed<Document> ParseFromStream(nsIInputStream* aStream,
+                                             const nsAString& aCharset,
+                                             int32_t aContentLength,
+                                             SupportedType aType,
+                                             ErrorResult& aRv);
 
   void ForceEnableXULXBL() { mForceEnableXULXBL = true; }
 
   nsIGlobalObject* GetParentObject() const { return mOwner; }
 
   virtual JSObject* WrapObject(JSContext* aCx,
                                JS::Handle<JSObject*> aGivenProto) override {
     return mozilla::dom::DOMParser_Binding::Wrap(aCx, this, aGivenProto);
@@ -65,18 +64,18 @@ class DOMParser final : public nsISuppor
 
   // A way to create a non-global-associated DOMParser from C++.
   static already_AddRefed<DOMParser> CreateWithoutGlobal(ErrorResult& aRv);
 
  private:
   DOMParser(nsIGlobalObject* aOwner, nsIPrincipal* aDocPrincipal,
             nsIURI* aDocumentURI, nsIURI* aBaseURI);
 
-  already_AddRefed<nsIDocument> SetUpDocument(DocumentFlavor aFlavor,
-                                              ErrorResult& aRv);
+  already_AddRefed<Document> SetUpDocument(DocumentFlavor aFlavor,
+                                           ErrorResult& aRv);
 
   nsCOMPtr<nsIGlobalObject> mOwner;
   nsCOMPtr<nsIPrincipal> mPrincipal;
   nsCOMPtr<nsIURI> mDocumentURI;
   nsCOMPtr<nsIURI> mBaseURI;
 
   bool mForceEnableXULXBL;
 };
--- a/dom/base/DirectionalityUtils.cpp
+++ b/dom/base/DirectionalityUtils.cpp
@@ -204,17 +204,17 @@
   gets called.
   */
 
 #include "mozilla/dom/DirectionalityUtils.h"
 
 #include "nsINode.h"
 #include "nsIContent.h"
 #include "nsIContentInlines.h"
-#include "nsIDocument.h"
+#include "mozilla/dom/Document.h"
 #include "mozilla/AutoRestore.h"
 #include "mozilla/DebugOnly.h"
 #include "mozilla/dom/Element.h"
 #include "mozilla/dom/HTMLSlotElement.h"
 #include "mozilla/dom/ShadowRoot.h"
 #include "nsUnicodeProperties.h"
 #include "nsTextFragment.h"
 #include "nsAttrValue.h"
--- a/dom/base/DispatcherTrait.h
+++ b/dom/base/DispatcherTrait.h
@@ -13,30 +13,30 @@
 class nsIRunnable;
 class nsISerialEventTarget;
 
 namespace mozilla {
 class AbstractThread;
 namespace dom {
 class TabGroup;
 
-// This trait should be attached to classes like nsIGlobalObject and nsIDocument
+// This trait should be attached to classes like nsIGlobalObject and Document
 // that have a DocGroup or TabGroup attached to them. The methods here should
 // delegate to the DocGroup or TabGroup. We can't use the Dispatcher class
 // directly because it inherits from nsISupports.
 class DispatcherTrait {
  public:
-  // This method may or may not be safe off of the main thread. For nsIDocument
-  // it is safe. For nsIGlobalWindow it is not safe.
+  // This method may or may not be safe off of the main thread. For Document it
+  // is safe. For nsIGlobalWindow it is not safe.
   virtual nsresult Dispatch(TaskCategory aCategory,
                             already_AddRefed<nsIRunnable>&& aRunnable);
 
-  // This method may or may not be safe off of the main thread. For nsIDocument
-  // it is safe. For nsIGlobalWindow it is not safe. The nsISerialEventTarget
-  // can always be used off the main thread.
+  // This method may or may not be safe off of the main thread. For Document it
+  // is safe. For nsIGlobalWindow it is not safe. The nsISerialEventTarget can
+  // always be used off the main thread.
   virtual nsISerialEventTarget* EventTargetFor(TaskCategory aCategory) const;
 
   // Must be called on the main thread. The AbstractThread can always be used
   // off the main thread.
   virtual AbstractThread* AbstractMainThreadFor(TaskCategory aCategory);
 };
 
 }  // namespace dom
--- a/dom/base/DocGroup.cpp
+++ b/dom/base/DocGroup.cpp
@@ -35,17 +35,17 @@ AutoTArray<RefPtr<DocGroup>, 2>* DocGrou
     // empty string to classify all such documents as belonging to the same
     // DocGroup.
     aKey.Truncate();
   }
 
   return rv;
 }
 
-void DocGroup::RemoveDocument(nsIDocument* aDocument) {
+void DocGroup::RemoveDocument(Document* aDocument) {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(mDocuments.Contains(aDocument));
   mDocuments.RemoveElement(aDocument);
 }
 
 DocGroup::DocGroup(TabGroup* aTabGroup, const nsACString& aKey)
     : mKey(aKey), mTabGroup(aTabGroup) {
   // This method does not add itself to mTabGroup->mDocGroups as the caller does
@@ -80,17 +80,17 @@ RefPtr<PerformanceInfoPromise> DocGroup:
   uint64_t duration = 0;
   bool isTopLevel = false;
   nsCString host;
   nsCOMPtr<nsPIDOMWindowOuter> top;
   RefPtr<AbstractThread> mainThread;
 
   // iterating on documents until we find the top window
   for (const auto& document : *this) {
-    nsCOMPtr<nsIDocument> doc = document;
+    nsCOMPtr<Document> doc = document;
     MOZ_ASSERT(doc);
     nsCOMPtr<nsIURI> docURI = doc->GetDocumentURI();
     if (!docURI) {
       continue;
     }
     docURI->GetHost(host);
     // If the host is empty, using the url
     if (host.IsEmpty()) {
@@ -196,17 +196,17 @@ void DocGroup::MoveSignalSlotListTo(nsTA
   for (RefPtr<HTMLSlotElement>& slot : mSignalSlotList) {
     slot->RemovedFromSignalSlotList();
     aDest.AppendElement(std::move(slot));
   }
   mSignalSlotList.Clear();
 }
 
 bool DocGroup::IsActive() const {
-  for (nsIDocument* doc : mDocuments) {
+  for (Document* doc : mDocuments) {
     if (doc->IsCurrentActiveDocument()) {
       return true;
     }
   }
 
   return false;
 }
 
--- a/dom/base/DocGroup.h
+++ b/dom/base/DocGroup.h
@@ -35,17 +35,17 @@ namespace dom {
 // TabGroup, browsing contexts are broken into "similar-origin" DocGroups. In
 // more detail, a DocGroup is actually a collection of documents, and a
 // TabGroup is a collection of DocGroups. A TabGroup typically will contain
 // (through its DocGroups) the documents from one or more tabs related by
 // window.opener. A DocGroup is a member of exactly one TabGroup.
 
 class DocGroup final {
  public:
-  typedef nsTArray<nsIDocument*>::iterator Iterator;
+  typedef nsTArray<Document*>::iterator Iterator;
   friend class TabGroup;
 
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(DocGroup)
 
   // Returns NS_ERROR_FAILURE and sets |aString| to an empty string if the TLD
   // service isn't available. Returns NS_OK on success, but may still set
   // |aString| may still be set to an empty string.
   static MOZ_MUST_USE nsresult GetKey(nsIPrincipal* aPrincipal,
@@ -61,17 +61,17 @@ class DocGroup final {
   mozilla::dom::CustomElementReactionsStack* CustomElementReactionsStack() {
     MOZ_ASSERT(NS_IsMainThread());
     if (!mReactionsStack) {
       mReactionsStack = new mozilla::dom::CustomElementReactionsStack();
     }
 
     return mReactionsStack;
   }
-  void RemoveDocument(nsIDocument* aWindow);
+  void RemoveDocument(Document* aWindow);
 
   // Iterators for iterating over every document within the DocGroup
   Iterator begin() {
     MOZ_ASSERT(NS_IsMainThread());
     return mDocuments.begin();
   }
   Iterator end() {
     MOZ_ASSERT(NS_IsMainThread());
@@ -106,17 +106,17 @@ class DocGroup final {
   bool IsActive() const;
 
  private:
   DocGroup(TabGroup* aTabGroup, const nsACString& aKey);
   ~DocGroup();
 
   nsCString mKey;
   RefPtr<TabGroup> mTabGroup;
-  nsTArray<nsIDocument*> mDocuments;
+  nsTArray<Document*> mDocuments;
   RefPtr<mozilla::dom::CustomElementReactionsStack> mReactionsStack;
   nsTArray<RefPtr<HTMLSlotElement>> mSignalSlotList;
   // This pointer will be null if dom.performance.enable_scheduler_timing is
   // false (default value)
   RefPtr<mozilla::PerformanceCounter> mPerformanceCounter;
 };
 
 }  // namespace dom
new file mode 100644
--- /dev/null
+++ b/dom/base/Document.cpp
@@ -0,0 +1,12879 @@
+/* -*- 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/. */
+
+/*
+ * Base class for all our document implementations.
+ */
+
+#include "AudioChannelService.h"
+#include "mozilla/dom/Document.h"
+#include "DocumentInlines.h"
+#include "mozilla/AnimationComparator.h"
+#include "mozilla/AntiTrackingCommon.h"
+#include "mozilla/ArrayUtils.h"
+#include "mozilla/AutoRestore.h"
+#include "mozilla/BinarySearch.h"
+#include "mozilla/CSSEnabledState.h"
+#include "mozilla/DebugOnly.h"
+#include "mozilla/EffectSet.h"
+#include "mozilla/EnumSet.h"
+#include "mozilla/IntegerRange.h"
+#include "mozilla/MemoryReporting.h"
+#include "mozilla/Likely.h"
+#include "mozilla/PresShell.h"
+#include "mozilla/StaticPrefs.h"
+#include "mozilla/URLExtraData.h"
+#include <algorithm>
+
+#include "mozilla/Logging.h"
+#include "plstr.h"
+#include "mozilla/Sprintf.h"
+
+#include "mozilla/Telemetry.h"
+#include "nsIInterfaceRequestor.h"
+#include "nsIInterfaceRequestorUtils.h"
+#include "nsILoadContext.h"
+#include "nsITextControlFrame.h"
+#include "nsNumberControlFrame.h"
+#include "nsUnicharUtils.h"
+#include "nsContentList.h"
+#include "nsCSSPseudoElements.h"
+#include "nsIObserver.h"
+#include "nsIBaseWindow.h"
+#include "nsILayoutHistoryState.h"
+#include "mozilla/css/Loader.h"
+#include "mozilla/css/ImageLoader.h"
+#include "nsDocShell.h"
+#include "nsDocShellLoadTypes.h"
+#include "nsIDocShellTreeItem.h"
+#include "nsCOMArray.h"
+#include "nsQueryObject.h"
+#include "mozilla/Services.h"
+#include "nsScreen.h"
+#include "ChildIterator.h"
+
+#include "mozilla/AsyncEventDispatcher.h"
+#include "mozilla/BasicEvents.h"
+#include "mozilla/EventListenerManager.h"
+#include "mozilla/EventStateManager.h"
+#include "mozilla/FullscreenChange.h"
+#include "mozilla/PendingAnimationTracker.h"
+
+#include "mozilla/dom/Attr.h"
+#include "mozilla/dom/BindingDeclarations.h"
+#include "mozilla/dom/ContentChild.h"
+#include "mozilla/dom/Element.h"
+#include "mozilla/dom/Event.h"
+#include "mozilla/dom/FeaturePolicy.h"
+#include "mozilla/dom/FramingChecker.h"
+#include "mozilla/dom/HTMLSharedElement.h"
+#include "mozilla/dom/Navigator.h"
+#include "mozilla/dom/Performance.h"
+#include "mozilla/dom/ServiceWorkerContainer.h"
+#include "mozilla/dom/ScriptLoader.h"
+#include "mozilla/dom/StyleSheetList.h"
+#include "mozilla/dom/SVGUseElement.h"
+#include "nsGenericHTMLElement.h"
+#include "mozilla/dom/CDATASection.h"
+#include "mozilla/dom/ProcessingInstruction.h"
+#include "nsDOMString.h"
+#include "nsNodeUtils.h"
+#include "nsLayoutUtils.h"  // for GetFrameForPoint
+#include "nsIFrame.h"
+#include "nsITabChild.h"
+
+#include "nsRange.h"
+#include "mozilla/dom/DocumentType.h"
+#include "mozilla/dom/NodeIterator.h"
+#include "mozilla/dom/Promise.h"
+#include "mozilla/dom/PromiseNativeHandler.h"
+#include "mozilla/dom/TreeWalker.h"
+
+#include "nsIServiceManager.h"
+#include "mozilla/dom/ServiceWorkerManager.h"
+#include "imgLoader.h"
+
+#include "nsAboutProtocolUtils.h"
+#include "nsCanvasFrame.h"
+#include "nsContentCID.h"
+#include "nsError.h"
+#include "nsPresContext.h"
+#include "nsThreadUtils.h"
+#include "nsNodeInfoManager.h"
+#include "nsIFileChannel.h"
+#include "nsIMultiPartChannel.h"
+#include "nsIRefreshURI.h"
+#include "nsIWebNavigation.h"
+#include "nsIScriptError.h"
+#include "nsISimpleEnumerator.h"
+#include "nsIRequestContext.h"
+#include "nsStyleSheetService.h"
+
+#include "nsNetUtil.h"  // for NS_NewURI
+#include "nsIInputStreamChannel.h"
+#include "nsIAuthPrompt.h"
+#include "nsIAuthPrompt2.h"
+
+#include "nsIScriptSecurityManager.h"
+#include "nsIPermissionManager.h"
+#include "nsIPrincipal.h"
+#include "ExpandedPrincipal.h"
+#include "mozilla/NullPrincipal.h"
+
+#include "nsIDOMWindow.h"
+#include "nsPIDOMWindow.h"
+#include "nsFocusManager.h"
+#include "nsICookieService.h"
+
+#include "nsBidiUtils.h"
+
+#include "nsContentCreatorFunctions.h"
+
+#include "nsIScriptContext.h"
+#include "nsBindingManager.h"
+#include "nsHTMLDocument.h"
+#include "nsIRequest.h"
+#include "mozilla/dom/BlobURLProtocolHandler.h"
+
+#include "nsCharsetSource.h"
+#include "nsIParser.h"
+#include "nsIContentSink.h"
+
+#include "mozilla/EventDispatcher.h"
+#include "mozilla/EventStates.h"
+#include "mozilla/InternalMutationEvent.h"
+#include "nsDOMCID.h"
+
+#include "jsapi.h"
+#include "nsIXPConnect.h"
+#include "xpcpublic.h"
+#include "nsCCUncollectableMarker.h"
+#include "nsIContentPolicy.h"
+#include "nsContentPolicyUtils.h"
+#include "nsICategoryManager.h"
+#include "nsIDocumentLoaderFactory.h"
+#include "nsIDocumentLoader.h"
+#include "nsIContentViewer.h"
+#include "nsIXMLContentSink.h"
+#include "nsIPrompt.h"
+#include "nsIPropertyBag2.h"
+#include "mozilla/dom/PageTransitionEvent.h"
+#include "mozilla/dom/StyleRuleChangeEvent.h"
+#include "mozilla/dom/StyleSheetChangeEvent.h"
+#include "mozilla/dom/StyleSheetApplicableStateChangeEvent.h"
+#include "nsJSUtils.h"
+#include "nsFrameLoader.h"
+#include "nsEscape.h"
+#include "nsObjectLoadingContent.h"
+#include "nsHtml5TreeOpExecutor.h"
+#include "mozilla/dom/HTMLFormElement.h"
+#include "mozilla/dom/HTMLLinkElement.h"
+#include "mozilla/dom/HTMLMediaElement.h"
+#include "mozilla/dom/HTMLIFrameElement.h"
+#include "mozilla/dom/HTMLImageElement.h"
+#include "mozilla/dom/HTMLTextAreaElement.h"
+#include "mozilla/dom/MediaSource.h"
+
+#include "mozAutoDocUpdate.h"
+#include "nsGlobalWindow.h"
+#include "mozilla/Encoding.h"
+#include "nsDOMNavigationTiming.h"
+
+#include "mozilla/SMILAnimationController.h"
+#include "imgIContainer.h"
+#include "nsSVGUtils.h"
+
+#include "nsRefreshDriver.h"
+
+// FOR CSP (autogenerated by xpidl)
+#include "nsIContentSecurityPolicy.h"
+#include "mozilla/dom/nsCSPContext.h"
+#include "mozilla/dom/nsCSPService.h"
+#include "mozilla/dom/nsCSPUtils.h"
+#include "nsHTMLStyleSheet.h"
+#include "nsHTMLCSSStyleSheet.h"
+#include "mozilla/dom/DOMImplementation.h"
+#include "mozilla/dom/ShadowRoot.h"
+#include "mozilla/dom/Comment.h"
+#include "nsTextNode.h"
+#include "mozilla/dom/Link.h"
+#include "mozilla/dom/HTMLCollectionBinding.h"
+#include "mozilla/dom/HTMLElementBinding.h"
+#include "nsXULAppAPI.h"
+#include "mozilla/dom/Touch.h"
+#include "mozilla/dom/TouchEvent.h"
+
+#include "mozilla/Preferences.h"
+
+#include "imgILoader.h"
+#include "imgRequestProxy.h"
+#include "nsWrapperCacheInlines.h"
+#include "nsSandboxFlags.h"
+#include "mozilla/dom/AnimatableBinding.h"
+#include "mozilla/dom/AnonymousContent.h"
+#include "mozilla/dom/BindingUtils.h"
+#include "mozilla/dom/ClientInfo.h"
+#include "mozilla/dom/ClientState.h"
+#include "mozilla/dom/DocumentFragment.h"
+#include "mozilla/dom/DocumentL10n.h"
+#include "mozilla/dom/DocumentTimeline.h"
+#include "mozilla/dom/Event.h"
+#include "mozilla/dom/HTMLBodyElement.h"
+#include "mozilla/dom/HTMLInputElement.h"
+#include "mozilla/dom/ImageTracker.h"
+#include "mozilla/dom/MediaQueryList.h"
+#include "mozilla/dom/NodeFilterBinding.h"
+#include "mozilla/OwningNonNull.h"
+#include "mozilla/dom/TabChild.h"
+#include "mozilla/dom/WebComponentsBinding.h"
+#include "mozilla/dom/CustomElementRegistryBinding.h"
+#include "mozilla/dom/CustomElementRegistry.h"
+#include "mozilla/dom/ServiceWorkerDescriptor.h"
+#include "mozilla/dom/TimeoutManager.h"
+#include "mozilla/ExtensionPolicyService.h"
+#include "nsFrame.h"
+#include "nsDOMCaretPosition.h"
+#include "nsViewportInfo.h"
+#include "mozilla/StaticPtr.h"
+#include "nsITextControlElement.h"
+#include "nsIEditor.h"
+#include "nsIHttpChannelInternal.h"
+#include "nsISecurityConsoleMessage.h"
+#include "nsCharSeparatedTokenizer.h"
+#include "mozilla/dom/XPathEvaluator.h"
+#include "mozilla/dom/XPathNSResolverBinding.h"
+#include "mozilla/dom/XPathResult.h"
+#include "nsIDocumentEncoder.h"
+#include "nsIDocumentActivity.h"
+#include "nsIStructuredCloneContainer.h"
+#include "nsIMutableArray.h"
+#include "mozilla/dom/DOMStringList.h"
+#include "nsWindowSizes.h"
+#include "mozilla/dom/Location.h"
+#include "mozilla/dom/FontFaceSet.h"
+#include "gfxPrefs.h"
+#include "nsISupportsPrimitives.h"
+#include "mozilla/ServoStyleSet.h"
+#include "mozilla/StyleSheet.h"
+#include "mozilla/StyleSheetInlines.h"
+#include "mozilla/dom/SVGDocument.h"
+#include "mozilla/dom/SVGSVGElement.h"
+#include "mozilla/dom/DocGroup.h"
+#include "mozilla/dom/TabGroup.h"
+#ifdef MOZ_XUL
+#include "mozilla/dom/XULBroadcastManager.h"
+#include "mozilla/dom/XULPersist.h"
+#include "mozilla/dom/TreeBoxObject.h"
+#include "nsIXULWindow.h"
+#include "nsXULCommandDispatcher.h"
+#include "nsXULPopupManager.h"
+#include "nsIDocShellTreeOwner.h"
+#endif
+#include "nsIPresShellInlines.h"
+
+#include "mozilla/DocLoadingTimelineMarker.h"
+
+#include "mozilla/dom/WindowGlobalChild.h"
+
+#include "nsISpeculativeConnect.h"
+
+#include "mozilla/MediaManager.h"
+
+#include "nsIURIClassifier.h"
+#include "nsIURIMutator.h"
+#include "mozilla/DocumentStyleRootIterator.h"
+#include "mozilla/PendingFullscreenEvent.h"
+#include "mozilla/RestyleManager.h"
+#include "mozilla/ClearOnShutdown.h"
+#include "nsHTMLTags.h"
+#include "NodeUbiReporting.h"
+#include "nsICookieService.h"
+#include "mozilla/net/ChannelEventQueue.h"
+#include "mozilla/net/RequestContextService.h"
+#include "StorageAccessPermissionRequest.h"
+#include "mozilla/dom/WindowProxyHolder.h"
+
+#define XML_DECLARATION_BITS_DECLARATION_EXISTS (1 << 0)
+#define XML_DECLARATION_BITS_ENCODING_EXISTS (1 << 1)
+#define XML_DECLARATION_BITS_STANDALONE_EXISTS (1 << 2)
+#define XML_DECLARATION_BITS_STANDALONE_YES (1 << 3)
+
+namespace mozilla {
+namespace dom {
+
+typedef nsTArray<Link*> LinkArray;
+
+static LazyLogModule gDocumentLeakPRLog("DocumentLeak");
+static LazyLogModule gCspPRLog("CSP");
+static LazyLogModule gUserInteractionPRLog("UserInteraction");
+
+static nsresult GetHttpChannelHelper(nsIChannel* aChannel,
+                                     nsIHttpChannel** aHttpChannel) {
+  nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aChannel);
+  if (httpChannel) {
+    httpChannel.forget(aHttpChannel);
+    return NS_OK;
+  }
+
+  nsCOMPtr<nsIMultiPartChannel> multipart = do_QueryInterface(aChannel);
+  if (!multipart) {
+    *aHttpChannel = nullptr;
+    return NS_OK;
+  }
+
+  nsCOMPtr<nsIChannel> baseChannel;
+  nsresult rv = multipart->GetBaseChannel(getter_AddRefs(baseChannel));
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  httpChannel = do_QueryInterface(baseChannel);
+  httpChannel.forget(aHttpChannel);
+
+  return NS_OK;
+}
+
+////////////////////////////////////////////////////////////////////
+// PrincipalFlashClassifier
+
+// Classify the flash based on the document principal.
+// The usage of this class is as follows:
+//
+// 1) Call AsyncClassify() as early as possible to asynchronously do
+//    classification against all the flash blocking related tables
+//    via nsIURIClassifier.asyncClassifyLocalWithTables.
+//
+// 2) At any time you need the classification result, call Result()
+//    and it is guaranteed to give you the result. Note that you have
+//    to specify "aIsThirdParty" to the function so please make sure
+//    you can already correctly decide if the document is third-party.
+//
+//    Behind the scenes, the sync classification API
+//    (nsIURIClassifier.classifyLocalWithTable) may be called as a fallback to
+//    synchronously get the result if the asyncClassifyLocalWithTables hasn't
+//    been done yet.
+//
+// 3) You can call Result() as many times as you want and only the first time
+//    it may unfortunately call the blocking sync API. The subsequent call
+//    will just return the result that came out at the first time.
+//
+class PrincipalFlashClassifier final : public nsIURIClassifierCallback {
+ public:
+  NS_DECL_THREADSAFE_ISUPPORTS
+  NS_DECL_NSIURICLASSIFIERCALLBACK
+
+  PrincipalFlashClassifier();
+
+  // Fire async classification based on the given principal.
+  void AsyncClassify(nsIPrincipal* aPrincipal);
+
+  // Would block if the result hasn't come out.
+  mozilla::dom::FlashClassification ClassifyMaybeSync(nsIPrincipal* aPrincipal,
+                                                      bool aIsThirdParty);
+
+ private:
+  ~PrincipalFlashClassifier() = default;
+
+  void Reset();
+  bool EnsureUriClassifier();
+  mozilla::dom::FlashClassification CheckIfClassifyNeeded(
+      nsIPrincipal* aPrincipal);
+  mozilla::dom::FlashClassification Resolve(bool aIsThirdParty);
+  mozilla::dom::FlashClassification AsyncClassifyInternal(
+      nsIPrincipal* aPrincipal);
+  void GetClassificationTables(bool aIsThirdParty, nsACString& aTables);
+
+  // For the fallback sync classification.
+  nsCOMPtr<nsIURI> mClassificationURI;
+
+  nsCOMPtr<nsIURIClassifier> mUriClassifier;
+  bool mAsyncClassified;
+  nsTArray<nsCString> mMatchedTables;
+  mozilla::dom::FlashClassification mResult;
+};
+
+}  // namespace dom
+}  // namespace mozilla
+
+extern bool sDisablePrefetchHTTPSPref;
+
+#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)
+    : PLDHashEntryHdr(std::move(aOther)),
+      mKey(std::move(aOther.mKey)),
+      mIdContentList(std::move(aOther.mIdContentList)),
+      mNameContentList(std::move(aOther.mNameContentList)),
+      mChangeCallbacks(std::move(aOther.mChangeCallbacks)),
+      mImageElement(std::move(aOther.mImageElement)) {}
+
+void nsIdentifierMapEntry::Traverse(
+    nsCycleCollectionTraversalCallback* aCallback) {
+  NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*aCallback,
+                                     "mIdentifierMap mNameContentList");
+  aCallback->NoteXPCOMChild(static_cast<nsINodeList*>(mNameContentList));
+
+  if (mImageElement) {
+    NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*aCallback,
+                                       "mIdentifierMap mImageElement element");
+    nsIContent* imageElement = mImageElement;
+    aCallback->NoteXPCOMChild(imageElement);
+  }
+}
+
+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() {
+  return mImageElement ? mImageElement.get() : GetIdElement();
+}
+
+void nsIdentifierMapEntry::AddContentChangeCallback(
+    Document::IDTargetObserver aCallback, void* aData, bool aForImage) {
+  if (!mChangeCallbacks) {
+    mChangeCallbacks = new nsTHashtable<ChangeCallbackEntry>;
+  }
+
+  ChangeCallback cc = {aCallback, aData, aForImage};
+  mChangeCallbacks->PutEntry(cc);
+}
+
+void nsIdentifierMapEntry::RemoveContentChangeCallback(
+    Document::IDTargetObserver aCallback, void* aData, bool aForImage) {
+  if (!mChangeCallbacks) return;
+  ChangeCallback cc = {aCallback, aData, aForImage};
+  mChangeCallbacks->RemoveEntry(cc);
+  if (mChangeCallbacks->Count() == 0) {
+    mChangeCallbacks = nullptr;
+  }
+}
+
+void nsIdentifierMapEntry::FireChangeCallbacks(Element* aOldElement,
+                                               Element* aNewElement,
+                                               bool aImageOnly) {
+  if (!mChangeCallbacks) return;
+
+  for (auto iter = mChangeCallbacks->ConstIter(); !iter.Done(); iter.Next()) {
+    nsIdentifierMapEntry::ChangeCallbackEntry* entry = iter.Get();
+    // Don't fire image changes for non-image observers, and don't fire element
+    // changes for image observers when an image override is active.
+    if (entry->mKey.mForImage ? (mImageElement && !aImageOnly) : aImageOnly) {
+      continue;
+    }
+
+    if (!entry->mKey.mCallback(aOldElement, aNewElement, entry->mKey.mData)) {
+      iter.Remove();
+    }
+  }
+}
+
+namespace {
+
+struct PositionComparator {
+  Element* const mElement;
+  explicit PositionComparator(Element* const aElement) : mElement(aElement) {}
+
+  int operator()(void* aElement) const {
+    Element* curElement = static_cast<Element*>(aElement);
+    MOZ_DIAGNOSTIC_ASSERT(mElement != curElement);
+    if (nsContentUtils::PositionIsBefore(mElement, curElement)) {
+      return -1;
+    }
+    return 1;
+  }
+};
+
+}  // namespace
+
+void nsIdentifierMapEntry::AddIdElement(Element* aElement) {
+  MOZ_ASSERT(aElement, "Must have element");
+  MOZ_ASSERT(!mIdContentList.Contains(nullptr), "Why is null in our list?");
+
+  // Common case
+  if (mIdContentList.IsEmpty()) {
+    mIdContentList.AppendElement(aElement);
+    FireChangeCallbacks(nullptr, aElement);
+    return;
+  }
+
+#ifdef DEBUG
+  Element* currentElement = mIdContentList.ElementAt(0);
+#endif
+
+  // We seem to have multiple content nodes for the same id, or XUL is messing
+  // with us.  Search for the right place to insert the content.
+
+  size_t idx;
+  BinarySearchIf(mIdContentList, 0, mIdContentList.Length(),
+                 PositionComparator(aElement), &idx);
+
+  mIdContentList.InsertElementAt(idx, aElement);
+
+  if (idx == 0) {
+    Element* oldElement = mIdContentList.SafeElementAt(1);
+    NS_ASSERTION(currentElement == oldElement, "How did that happen?");
+    FireChangeCallbacks(oldElement, aElement);
+  }
+}
+
+void nsIdentifierMapEntry::RemoveIdElement(Element* aElement) {
+  MOZ_ASSERT(aElement, "Missing element");
+
+  // This should only be called while the document is in an update.
+  // Assertions near the call to this method guarantee this.
+
+  // This could fire in OOM situations
+  // Only assert this in HTML documents for now as XUL does all sorts of weird
+  // crap.
+  NS_ASSERTION(!aElement->OwnerDoc()->IsHTMLDocument() ||
+                   mIdContentList.Contains(aElement),
+               "Removing id entry that doesn't exist");
+
+  // XXXbz should this ever Compact() I guess when all the content is gone
+  // we'll just get cleaned up in the natural order of things...
+  Element* currentElement = mIdContentList.SafeElementAt(0);
+  mIdContentList.RemoveElement(aElement);
+  if (currentElement == aElement) {
+    FireChangeCallbacks(currentElement, mIdContentList.SafeElementAt(0));
+  }
+}
+
+void nsIdentifierMapEntry::SetImageElement(Element* aElement) {
+  Element* oldElement = GetImageIdElement();
+  mImageElement = aElement;
+  Element* newElement = GetImageIdElement();
+  if (oldElement != newElement) {
+    FireChangeCallbacks(oldElement, newElement, true);
+  }
+}
+
+namespace mozilla {
+namespace dom {
+
+class SimpleHTMLCollection final : public nsSimpleContentList,
+                                   public nsIHTMLCollection {
+ public:
+  explicit SimpleHTMLCollection(nsINode* aRoot) : nsSimpleContentList(aRoot) {}
+
+  NS_DECL_ISUPPORTS_INHERITED
+
+  virtual nsINode* GetParentObject() override {
+    return nsSimpleContentList::GetParentObject();
+  }
+  virtual uint32_t Length() override { return nsSimpleContentList::Length(); }
+  virtual Element* GetElementAt(uint32_t aIndex) override {
+    return mElements.SafeElementAt(aIndex)->AsElement();
+  }
+
+  virtual Element* GetFirstNamedElement(const nsAString& aName,
+                                        bool& aFound) override {
+    aFound = false;
+    RefPtr<nsAtom> name = NS_Atomize(aName);
+    for (uint32_t i = 0; i < mElements.Length(); i++) {
+      MOZ_DIAGNOSTIC_ASSERT(mElements[i]);
+      Element* element = mElements[i]->AsElement();
+      if (element->GetID() == name ||
+          (element->HasName() &&
+           element->GetParsedAttr(nsGkAtoms::name)->GetAtomValue() == name)) {
+        aFound = true;
+        return element;
+      }
+    }
+    return nullptr;
+  }
+
+  virtual void GetSupportedNames(nsTArray<nsString>& aNames) override {
+    AutoTArray<nsAtom*, 8> atoms;
+    for (uint32_t i = 0; i < mElements.Length(); i++) {
+      MOZ_DIAGNOSTIC_ASSERT(mElements[i]);
+      Element* element = mElements[i]->AsElement();
+
+      nsAtom* id = element->GetID();
+      MOZ_ASSERT(id != nsGkAtoms::_empty);
+      if (id && !atoms.Contains(id)) {
+        atoms.AppendElement(id);
+      }
+
+      if (element->HasName()) {
+        nsAtom* name = element->GetParsedAttr(nsGkAtoms::name)->GetAtomValue();
+        MOZ_ASSERT(name && name != nsGkAtoms::_empty);
+        if (name && !atoms.Contains(name)) {
+          atoms.AppendElement(name);
+        }
+      }
+    }
+
+    nsString* names = aNames.AppendElements(atoms.Length());
+    for (uint32_t i = 0; i < atoms.Length(); i++) {
+      atoms[i]->ToString(names[i]);
+    }
+  }
+
+  virtual JSObject* GetWrapperPreserveColorInternal() override {
+    return nsWrapperCache::GetWrapperPreserveColor();
+  }
+  virtual void PreserveWrapperInternal(
+      nsISupports* aScriptObjectHolder) override {
+    nsWrapperCache::PreserveWrapper(aScriptObjectHolder);
+  }
+  virtual JSObject* WrapObject(JSContext* aCx,
+                               JS::Handle<JSObject*> aGivenProto) override {
+    return HTMLCollection_Binding::Wrap(aCx, this, aGivenProto);
+  }
+
+  using nsBaseContentList::Item;
+
+ private:
+  virtual ~SimpleHTMLCollection() {}
+};
+
+NS_IMPL_ISUPPORTS_INHERITED(SimpleHTMLCollection, nsSimpleContentList,
+                            nsIHTMLCollection)
+
+}  // namespace dom
+}  // namespace mozilla
+
+void nsIdentifierMapEntry::AddNameElement(nsINode* aNode, Element* aElement) {
+  if (!mNameContentList) {
+    mNameContentList = new SimpleHTMLCollection(aNode);
+  }
+
+  mNameContentList->AppendElement(aElement);
+}
+
+void nsIdentifierMapEntry::RemoveNameElement(Element* aElement) {
+  if (mNameContentList) {
+    mNameContentList->RemoveElement(aElement);
+  }
+}
+
+bool nsIdentifierMapEntry::HasIdElementExposedAsHTMLDocumentProperty() {
+  Element* idElement = GetIdElement();
+  return idElement &&
+         nsGenericHTMLElement::ShouldExposeIdAsHTMLDocumentProperty(idElement);
+}
+
+size_t nsIdentifierMapEntry::SizeOfExcludingThis(
+    MallocSizeOf aMallocSizeOf) const {
+  return mKey.mString.SizeOfExcludingThisIfUnshared(aMallocSizeOf);
+}
+
+// Helper structs for the content->subdoc map
+
+class SubDocMapEntry : public PLDHashEntryHdr {
+ public:
+  // Both of these are strong references
+  Element* mKey;  // must be first, to look like PLDHashEntryStub
+  Document* mSubDocument;
+};
+
+class nsOnloadBlocker final : public nsIRequest {
+ public:
+  nsOnloadBlocker() {}
+
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSIREQUEST
+
+ private:
+  ~nsOnloadBlocker() {}
+};
+
+NS_IMPL_ISUPPORTS(nsOnloadBlocker, nsIRequest)
+
+NS_IMETHODIMP
+nsOnloadBlocker::GetName(nsACString& aResult) {
+  aResult.AssignLiteral("about:document-onload-blocker");
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsOnloadBlocker::IsPending(bool* _retval) {
+  *_retval = true;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsOnloadBlocker::GetStatus(nsresult* status) {
+  *status = NS_OK;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsOnloadBlocker::Cancel(nsresult status) { return NS_OK; }
+NS_IMETHODIMP
+nsOnloadBlocker::Suspend(void) { return NS_OK; }
+NS_IMETHODIMP
+nsOnloadBlocker::Resume(void) { return NS_OK; }
+
+NS_IMETHODIMP
+nsOnloadBlocker::GetLoadGroup(nsILoadGroup** aLoadGroup) {
+  *aLoadGroup = nullptr;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsOnloadBlocker::SetLoadGroup(nsILoadGroup* aLoadGroup) { return NS_OK; }
+
+NS_IMETHODIMP
+nsOnloadBlocker::GetLoadFlags(nsLoadFlags* aLoadFlags) {
+  *aLoadFlags = nsIRequest::LOAD_NORMAL;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsOnloadBlocker::SetLoadFlags(nsLoadFlags aLoadFlags) { return NS_OK; }
+
+// ==================================================================
+
+namespace mozilla {
+namespace dom {
+
+ExternalResourceMap::ExternalResourceMap() : mHaveShutDown(false) {}
+
+Document* ExternalResourceMap::RequestResource(
+    nsIURI* aURI, nsIURI* aReferrer, uint32_t aReferrerPolicy,
+    nsINode* aRequestingNode, Document* aDisplayDocument,
+    ExternalResourceLoad** aPendingLoad) {
+  // If we ever start allowing non-same-origin loads here, we might need to do
+  // something interesting with aRequestingPrincipal even for the hashtable
+  // gets.
+  MOZ_ASSERT(aURI, "Must have a URI");
+  MOZ_ASSERT(aRequestingNode, "Must have a node");
+  *aPendingLoad = nullptr;
+  if (mHaveShutDown) {
+    return nullptr;
+  }
+
+  // First, make sure we strip the ref from aURI.
+  nsCOMPtr<nsIURI> clone;
+  nsresult rv = NS_GetURIWithoutRef(aURI, getter_AddRefs(clone));
+  if (NS_FAILED(rv) || !clone) {
+    return nullptr;
+  }
+
+  ExternalResource* resource;
+  mMap.Get(clone, &resource);
+  if (resource) {
+    return resource->mDocument;
+  }
+
+  RefPtr<PendingLoad>& loadEntry = mPendingLoads.GetOrInsert(clone);
+  if (loadEntry) {
+    RefPtr<PendingLoad> load(loadEntry);
+    load.forget(aPendingLoad);
+    return nullptr;
+  }
+
+  RefPtr<PendingLoad> load(new PendingLoad(aDisplayDocument));
+  loadEntry = load;
+
+  if (NS_FAILED(load->StartLoad(clone, aReferrer, aReferrerPolicy,
+                                aRequestingNode))) {
+    // Make sure we don't thrash things by trying this load again, since
+    // chances are it failed for good reasons (security check, etc).
+    AddExternalResource(clone, nullptr, nullptr, aDisplayDocument);
+  } else {
+    load.forget(aPendingLoad);
+  }
+
+  return nullptr;
+}
+
+void ExternalResourceMap::EnumerateResources(Document::SubDocEnumFunc aCallback,
+                                             void* aData) {
+  for (auto iter = mMap.Iter(); !iter.Done(); iter.Next()) {
+    ExternalResourceMap::ExternalResource* resource = iter.UserData();
+    if (resource->mDocument && !aCallback(resource->mDocument, aData)) {
+      break;
+    }
+  }
+}
+
+void ExternalResourceMap::Traverse(
+    nsCycleCollectionTraversalCallback* aCallback) const {
+  // mPendingLoads will get cleared out as the requests complete, so
+  // no need to worry about those here.
+  for (auto iter = mMap.ConstIter(); !iter.Done(); iter.Next()) {
+    ExternalResourceMap::ExternalResource* resource = iter.UserData();
+
+    NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*aCallback,
+                                       "mExternalResourceMap.mMap entry"
+                                       "->mDocument");
+    aCallback->NoteXPCOMChild(ToSupports(resource->mDocument));
+
+    NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*aCallback,
+                                       "mExternalResourceMap.mMap entry"
+                                       "->mViewer");
+    aCallback->NoteXPCOMChild(resource->mViewer);
+
+    NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*aCallback,
+                                       "mExternalResourceMap.mMap entry"
+                                       "->mLoadGroup");
+    aCallback->NoteXPCOMChild(resource->mLoadGroup);
+  }
+}
+
+void ExternalResourceMap::HideViewers() {
+  for (auto iter = mMap.Iter(); !iter.Done(); iter.Next()) {
+    nsCOMPtr<nsIContentViewer> viewer = iter.UserData()->mViewer;
+    if (viewer) {
+      viewer->Hide();
+    }
+  }
+}
+
+void ExternalResourceMap::ShowViewers() {
+  for (auto iter = mMap.Iter(); !iter.Done(); iter.Next()) {
+    nsCOMPtr<nsIContentViewer> viewer = iter.UserData()->mViewer;
+    if (viewer) {
+      viewer->Show();
+    }
+  }
+}
+
+void TransferZoomLevels(Document* aFromDoc, Document* aToDoc) {
+  MOZ_ASSERT(aFromDoc && aToDoc, "transferring zoom levels from/to null doc");
+
+  nsPresContext* fromCtxt = aFromDoc->GetPresContext();
+  if (!fromCtxt) return;
+
+  nsPresContext* toCtxt = aToDoc->GetPresContext();
+  if (!toCtxt) return;
+
+  toCtxt->SetFullZoom(fromCtxt->GetFullZoom());
+  toCtxt->SetBaseMinFontSize(fromCtxt->BaseMinFontSize());
+  toCtxt->SetTextZoom(fromCtxt->TextZoom());
+  toCtxt->SetOverrideDPPX(fromCtxt->GetOverrideDPPX());
+}
+
+void TransferShowingState(Document* aFromDoc, Document* aToDoc) {
+  MOZ_ASSERT(aFromDoc && aToDoc, "transferring showing state from/to null doc");
+
+  if (aFromDoc->IsShowing()) {
+    aToDoc->OnPageShow(true, nullptr);
+  }
+}
+
+nsresult ExternalResourceMap::AddExternalResource(nsIURI* aURI,
+                                                  nsIContentViewer* aViewer,
+                                                  nsILoadGroup* aLoadGroup,
+                                                  Document* aDisplayDocument) {
+  MOZ_ASSERT(aURI, "Unexpected call");
+  MOZ_ASSERT((aViewer && aLoadGroup) || (!aViewer && !aLoadGroup),
+             "Must have both or neither");
+
+  RefPtr<PendingLoad> load;
+  mPendingLoads.Remove(aURI, getter_AddRefs(load));
+
+  nsresult rv = NS_OK;
+
+  nsCOMPtr<Document> doc;
+  if (aViewer) {
+    doc = aViewer->GetDocument();
+    NS_ASSERTION(doc, "Must have a document");
+
+    if (doc->IsXULDocument()) {
+      // We don't handle XUL stuff here yet.
+      rv = NS_ERROR_NOT_AVAILABLE;
+    } else {
+      doc->SetDisplayDocument(aDisplayDocument);
+
+      // Make sure that hiding our viewer will tear down its presentation.
+      aViewer->SetSticky(false);
+
+      rv = aViewer->Init(nullptr, nsIntRect(0, 0, 0, 0));
+      if (NS_SUCCEEDED(rv)) {
+        rv = aViewer->Open(nullptr, nullptr);
+      }
+    }
+
+    if (NS_FAILED(rv)) {
+      doc = nullptr;
+      aViewer = nullptr;
+      aLoadGroup = nullptr;
+    }
+  }
+
+  ExternalResource* newResource = new ExternalResource();
+  mMap.Put(aURI, newResource);
+
+  newResource->mDocument = doc;
+  newResource->mViewer = aViewer;
+  newResource->mLoadGroup = aLoadGroup;
+  if (doc) {
+    TransferZoomLevels(aDisplayDocument, doc);
+    TransferShowingState(aDisplayDocument, doc);
+  }
+
+  const nsTArray<nsCOMPtr<nsIObserver>>& obs = load->Observers();
+  for (uint32_t i = 0; i < obs.Length(); ++i) {
+    obs[i]->Observe(ToSupports(doc), "external-resource-document-created",
+                    nullptr);
+  }
+
+  return rv;
+}
+
+NS_IMPL_ISUPPORTS(ExternalResourceMap::PendingLoad, nsIStreamListener,
+                  nsIRequestObserver)
+
+NS_IMETHODIMP
+ExternalResourceMap::PendingLoad::OnStartRequest(nsIRequest* aRequest,
+                                                 nsISupports* aContext) {
+  ExternalResourceMap& map = mDisplayDocument->ExternalResourceMap();
+  if (map.HaveShutDown()) {
+    return NS_BINDING_ABORTED;
+  }
+
+  nsCOMPtr<nsIContentViewer> viewer;
+  nsCOMPtr<nsILoadGroup> loadGroup;
+  nsresult rv =
+      SetupViewer(aRequest, getter_AddRefs(viewer), getter_AddRefs(loadGroup));
+
+  // Make sure to do this no matter what
+  nsresult rv2 =
+      map.AddExternalResource(mURI, viewer, loadGroup, mDisplayDocument);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+  if (NS_FAILED(rv2)) {
+    mTargetListener = nullptr;
+    return rv2;
+  }
+
+  return mTargetListener->OnStartRequest(aRequest, aContext);
+}
+
+nsresult ExternalResourceMap::PendingLoad::SetupViewer(
+    nsIRequest* aRequest, nsIContentViewer** aViewer,
+    nsILoadGroup** aLoadGroup) {
+  MOZ_ASSERT(!mTargetListener, "Unexpected call to OnStartRequest");
+  *aViewer = nullptr;
+  *aLoadGroup = nullptr;
+
+  nsCOMPtr<nsIChannel> chan(do_QueryInterface(aRequest));
+  NS_ENSURE_TRUE(chan, NS_ERROR_UNEXPECTED);
+
+  nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(aRequest));
+  if (httpChannel) {
+    bool requestSucceeded;
+    if (NS_FAILED(httpChannel->GetRequestSucceeded(&requestSucceeded)) ||
+        !requestSucceeded) {
+      // Bail out on this load, since it looks like we have an HTTP error page
+      return NS_BINDING_ABORTED;
+    }
+  }
+
+  nsAutoCString type;
+  chan->GetContentType(type);
+
+  nsCOMPtr<nsILoadGroup> loadGroup;
+  chan->GetLoadGroup(getter_AddRefs(loadGroup));
+
+  // Give this document its own loadgroup
+  nsCOMPtr<nsILoadGroup> newLoadGroup =
+      do_CreateInstance(NS_LOADGROUP_CONTRACTID);
+  NS_ENSURE_TRUE(newLoadGroup, NS_ERROR_OUT_OF_MEMORY);
+  newLoadGroup->SetLoadGroup(loadGroup);
+
+  nsCOMPtr<nsIInterfaceRequestor> callbacks;
+  loadGroup->GetNotificationCallbacks(getter_AddRefs(callbacks));
+
+  nsCOMPtr<nsIInterfaceRequestor> newCallbacks =
+      new LoadgroupCallbacks(callbacks);
+  newLoadGroup->SetNotificationCallbacks(newCallbacks);
+
+  // This is some serious hackery cribbed from docshell
+  nsCOMPtr<nsICategoryManager> catMan =
+      do_GetService(NS_CATEGORYMANAGER_CONTRACTID);
+  NS_ENSURE_TRUE(catMan, NS_ERROR_NOT_AVAILABLE);
+  nsCString contractId;
+  nsresult rv =
+      catMan->GetCategoryEntry("Gecko-Content-Viewers", type, contractId);
+  NS_ENSURE_SUCCESS(rv, rv);
+  nsCOMPtr<nsIDocumentLoaderFactory> docLoaderFactory =
+      do_GetService(contractId.get());
+  NS_ENSURE_TRUE(docLoaderFactory, NS_ERROR_NOT_AVAILABLE);
+
+  nsCOMPtr<nsIContentViewer> viewer;
+  nsCOMPtr<nsIStreamListener> listener;
+  rv = docLoaderFactory->CreateInstance(
+      "external-resource", chan, newLoadGroup, type, nullptr, nullptr,
+      getter_AddRefs(listener), getter_AddRefs(viewer));
+  NS_ENSURE_SUCCESS(rv, rv);
+  NS_ENSURE_TRUE(viewer, NS_ERROR_UNEXPECTED);
+
+  nsCOMPtr<nsIParser> parser = do_QueryInterface(listener);
+  if (!parser) {
+    /// We don't want to deal with the various fake documents yet
+    return NS_ERROR_NOT_IMPLEMENTED;
+  }
+
+  // We can't handle HTML and other weird things here yet.
+  nsIContentSink* sink = parser->GetContentSink();
+  nsCOMPtr<nsIXMLContentSink> xmlSink = do_QueryInterface(sink);
+  if (!xmlSink) {
+    return NS_ERROR_NOT_IMPLEMENTED;
+  }
+
+  listener.swap(mTargetListener);
+  viewer.forget(aViewer);
+  newLoadGroup.forget(aLoadGroup);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+ExternalResourceMap::PendingLoad::OnDataAvailable(nsIRequest* aRequest,
+                                                  nsISupports* aContext,
+                                                  nsIInputStream* aStream,
+                                                  uint64_t aOffset,
+                                                  uint32_t aCount) {
+  // mTargetListener might be null if SetupViewer or AddExternalResource failed.
+  NS_ENSURE_TRUE(mTargetListener, NS_ERROR_FAILURE);
+  if (mDisplayDocument->ExternalResourceMap().HaveShutDown()) {
+    return NS_BINDING_ABORTED;
+  }
+  return mTargetListener->OnDataAvailable(aRequest, aContext, aStream, aOffset,
+                                          aCount);
+}
+
+NS_IMETHODIMP
+ExternalResourceMap::PendingLoad::OnStopRequest(nsIRequest* aRequest,
+                                                nsISupports* aContext,
+                                                nsresult aStatus) {
+  // mTargetListener might be null if SetupViewer or AddExternalResource failed
+  if (mTargetListener) {
+    nsCOMPtr<nsIStreamListener> listener;
+    mTargetListener.swap(listener);
+    return listener->OnStopRequest(aRequest, aContext, aStatus);
+  }
+
+  return NS_OK;
+}
+
+nsresult ExternalResourceMap::PendingLoad::StartLoad(nsIURI* aURI,
+                                                     nsIURI* aReferrer,
+                                                     uint32_t aReferrerPolicy,
+                                                     nsINode* aRequestingNode) {
+  MOZ_ASSERT(aURI, "Must have a URI");
+  MOZ_ASSERT(aRequestingNode, "Must have a node");
+
+  nsCOMPtr<nsILoadGroup> loadGroup =
+      aRequestingNode->OwnerDoc()->GetDocumentLoadGroup();
+
+  nsresult rv = NS_OK;
+  nsCOMPtr<nsIChannel> channel;
+  rv = NS_NewChannel(getter_AddRefs(channel), aURI, aRequestingNode,
+                     nsILoadInfo::SEC_REQUIRE_SAME_ORIGIN_DATA_INHERITS,
+                     nsIContentPolicy::TYPE_OTHER,
+                     nullptr,  // aPerformanceStorage
+                     loadGroup);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(channel));
+  if (httpChannel) {
+    rv = httpChannel->SetReferrerWithPolicy(aReferrer, aReferrerPolicy);
+    Unused << NS_WARN_IF(NS_FAILED(rv));
+  }
+
+  mURI = aURI;
+
+  return channel->AsyncOpen2(this);
+}
+
+NS_IMPL_ISUPPORTS(ExternalResourceMap::LoadgroupCallbacks,
+                  nsIInterfaceRequestor)
+
+#define IMPL_SHIM(_i) \
+  NS_IMPL_ISUPPORTS(ExternalResourceMap::LoadgroupCallbacks::_i##Shim, _i)
+
+IMPL_SHIM(nsILoadContext)
+IMPL_SHIM(nsIProgressEventSink)
+IMPL_SHIM(nsIChannelEventSink)
+IMPL_SHIM(nsISecurityEventSink)
+IMPL_SHIM(nsIApplicationCacheContainer)
+
+#undef IMPL_SHIM
+
+#define IID_IS(_i) aIID.Equals(NS_GET_IID(_i))
+
+#define TRY_SHIM(_i)                                 \
+  PR_BEGIN_MACRO                                     \
+  if (IID_IS(_i)) {                                  \
+    nsCOMPtr<_i> real = do_GetInterface(mCallbacks); \
+    if (!real) {                                     \
+      return NS_NOINTERFACE;                         \
+    }                                                \
+    nsCOMPtr<_i> shim = new _i##Shim(this, real);    \
+    shim.forget(aSink);                              \
+    return NS_OK;                                    \
+  }                                                  \
+  PR_END_MACRO
+
+NS_IMETHODIMP
+ExternalResourceMap::LoadgroupCallbacks::GetInterface(const nsIID& aIID,
+                                                      void** aSink) {
+  if (mCallbacks && (IID_IS(nsIPrompt) || IID_IS(nsIAuthPrompt) ||
+                     IID_IS(nsIAuthPrompt2) || IID_IS(nsITabChild))) {
+    return mCallbacks->GetInterface(aIID, aSink);
+  }
+
+  *aSink = nullptr;
+
+  TRY_SHIM(nsILoadContext);
+  TRY_SHIM(nsIProgressEventSink);
+  TRY_SHIM(nsIChannelEventSink);
+  TRY_SHIM(nsISecurityEventSink);
+  TRY_SHIM(nsIApplicationCacheContainer);
+
+  return NS_NOINTERFACE;
+}
+
+#undef TRY_SHIM
+#undef IID_IS
+
+ExternalResourceMap::ExternalResource::~ExternalResource() {
+  if (mViewer) {
+    mViewer->Close(nullptr);
+    mViewer->Destroy();
+  }
+}
+
+// ==================================================================
+// =
+// ==================================================================
+
+// If we ever have an nsIDocumentObserver notification for stylesheet title
+// changes we should update the list from that instead of overriding
+// EnsureFresh.
+class DOMStyleSheetSetList final : public DOMStringList {
+ public:
+  explicit DOMStyleSheetSetList(Document* aDocument);
+
+  void Disconnect() { mDocument = nullptr; }
+
+  virtual void EnsureFresh() override;
+
+ protected:
+  Document* mDocument;  // Our document; weak ref.  It'll let us know if it
+                        // dies.
+};
+
+DOMStyleSheetSetList::DOMStyleSheetSetList(Document* aDocument)
+    : mDocument(aDocument) {
+  NS_ASSERTION(mDocument, "Must have document!");
+}
+
+void DOMStyleSheetSetList::EnsureFresh() {
+  MOZ_ASSERT(NS_IsMainThread());
+
+  mNames.Clear();
+
+  if (!mDocument) {
+    return;  // Spec says "no exceptions", and we have no style sets if we have
+             // no document, for sure
+  }
+
+  size_t count = mDocument->SheetCount();
+  nsAutoString title;
+  for (size_t index = 0; index < count; index++) {
+    StyleSheet* sheet = mDocument->SheetAt(index);
+    NS_ASSERTION(sheet, "Null sheet in sheet list!");
+    sheet->GetTitle(title);
+    if (!title.IsEmpty() && !mNames.Contains(title) && !Add(title)) {
+      return;
+    }
+  }
+}
+
+// ==================================================================
+Document::SelectorCache::SelectorCache(nsIEventTarget* aEventTarget)
+    : nsExpirationTracker<SelectorCacheKey, 4>(1000, "Document::SelectorCache",
+                                               aEventTarget) {}
+
+Document::SelectorCache::~SelectorCache() { AgeAllGenerations(); }
+
+void Document::SelectorCache::NotifyExpired(SelectorCacheKey* aSelector) {
+  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(aSelector);
+
+  // There is no guarantee that this method won't be re-entered when selector
+  // matching is ongoing because "memory-pressure" could be notified immediately
+  // when OOM happens according to the design of nsExpirationTracker.
+  // The perfect solution is to delete the |aSelector| and its
+  // RawServoSelectorList in mTable asynchronously.
+  // We remove these objects synchronously for now because NotifyExpired() will
+  // never be triggered by "memory-pressure" which is not implemented yet in
+  // the stage 2 of mozalloc_handle_oom().
+  // Once these objects are removed asynchronously, we should update the warning
+  // added in mozalloc_handle_oom() as well.
+  RemoveObject(aSelector);
+  mTable.Remove(aSelector->mKey);
+  delete aSelector;
+}
+
+struct Document::FrameRequest {
+  FrameRequest(FrameRequestCallback& aCallback, int32_t aHandle)
+      : mCallback(&aCallback), mHandle(aHandle) {}
+
+  // Conversion operator so that we can append these to a
+  // FrameRequestCallbackList
+  operator const RefPtr<FrameRequestCallback>&() const { return mCallback; }
+
+  // Comparator operators to allow RemoveElementSorted with an
+  // integer argument on arrays of FrameRequest
+  bool operator==(int32_t aHandle) const { return mHandle == aHandle; }
+  bool operator<(int32_t aHandle) const { return mHandle < aHandle; }
+
+  RefPtr<FrameRequestCallback> mCallback;
+  int32_t mHandle;
+};
+
+// ==================================================================
+// =
+// ==================================================================
+Document::Document(const char* aContentType)
+    : nsINode(nullptr),
+      DocumentOrShadowRoot(*this),
+      mReferrerPolicySet(false),
+      mReferrerPolicy(mozilla::net::RP_Unset),
+      mBlockAllMixedContent(false),
+      mBlockAllMixedContentPreloads(false),
+      mUpgradeInsecureRequests(false),
+      mUpgradeInsecurePreloads(false),
+      mCharacterSet(WINDOWS_1252_ENCODING),
+      mCharacterSetSource(0),
+      mParentDocument(nullptr),
+      mCachedRootElement(nullptr),
+      mNodeInfoManager(nullptr),
+#ifdef DEBUG
+      mStyledLinksCleared(false),
+#endif
+      mBidiEnabled(false),
+      mMathMLEnabled(false),
+      mIsInitialDocumentInWindow(false),
+      mIgnoreDocGroupMismatches(false),
+      mLoadedAsData(false),
+      mLoadedAsInteractiveData(false),
+      mMayStartLayout(true),
+      mHaveFiredTitleChange(false),
+      mIsShowing(false),
+      mVisible(true),
+      mRemovedFromDocShell(false),
+      // mAllowDNSPrefetch starts true, so that we can always reliably && it
+      // with various values that might disable it.  Since we never prefetch
+      // unless we get a window, and in that case the docshell value will get
+      // &&-ed in, this is safe.
+      mAllowDNSPrefetch(true),
+      mIsStaticDocument(false),
+      mCreatingStaticClone(false),
+      mInUnlinkOrDeletion(false),
+      mHasHadScriptHandlingObject(false),
+      mIsBeingUsedAsImage(false),
+      mIsSyntheticDocument(false),
+      mHasLinksToUpdateRunnable(false),
+      mFlushingPendingLinkUpdates(false),
+      mMayHaveDOMMutationObservers(false),
+      mMayHaveAnimationObservers(false),
+      mHasMixedActiveContentLoaded(false),
+      mHasMixedActiveContentBlocked(false),
+      mHasMixedDisplayContentLoaded(false),
+      mHasMixedDisplayContentBlocked(false),
+      mHasMixedContentObjectSubrequest(false),
+      mHasCSP(false),
+      mHasUnsafeEvalCSP(false),
+      mHasUnsafeInlineCSP(false),
+      mBFCacheDisallowed(false),
+      mHasHadDefaultView(false),
+      mStyleSheetChangeEventsEnabled(false),
+      mIsSrcdocDocument(false),
+      mDidDocumentOpen(false),
+      mHasDisplayDocument(false),
+      mFontFaceSetDirty(true),
+      mGetUserFontSetCalled(false),
+      mDidFireDOMContentLoaded(true),
+      mHasScrollLinkedEffect(false),
+      mFrameRequestCallbacksScheduled(false),
+      mIsTopLevelContentDocument(false),
+      mIsContentDocument(false),
+      mDidCallBeginLoad(false),
+      mAllowPaymentRequest(false),
+      mEncodingMenuDisabled(false),
+      mIsSVGGlyphsDocument(false),
+      mInDestructor(false),
+      mIsGoingAway(false),
+      mInXBLUpdate(false),
+      mNeedsReleaseAfterStackRefCntRelease(false),
+      mStyleSetFilled(false),
+      mSSApplicableStateNotificationPending(false),
+      mMayHaveTitleElement(false),
+      mDOMLoadingSet(false),
+      mDOMInteractiveSet(false),
+      mDOMCompleteSet(false),
+      mAutoFocusFired(false),
+      mScrolledToRefAlready(false),
+      mChangeScrollPosWhenScrollingToRef(false),
+      mHasWarnedAboutBoxObjects(false),
+      mDelayFrameLoaderInitialization(false),
+      mSynchronousDOMContentLoaded(false),
+      mMaybeServiceWorkerControlled(false),
+      mAllowZoom(false),
+      mValidScaleFloat(false),
+      mValidMaxScale(false),
+      mScaleStrEmpty(false),
+      mWidthStrEmpty(false),
+      mParserAborted(false),
+      mReportedUseCounters(false),
+      mHasReportedShadowDOMUsage(false),
+      mDocTreeHadAudibleMedia(false),
+      mDocTreeHadPlayRevoked(false),
+#ifdef DEBUG
+      mWillReparent(false),
+#endif
+      mHasDelayedRefreshEvent(false),
+      mPendingFullscreenRequests(0),
+      mXMLDeclarationBits(0),
+      mOnloadBlockCount(0),
+      mAsyncOnloadBlockCount(0),
+      mCompatMode(eCompatibility_FullStandards),
+      mReadyState(ReadyState::READYSTATE_UNINITIALIZED),
+#ifdef MOZILLA_INTERNAL_API
+      mVisibilityState(dom::VisibilityState::Hidden),
+#else
+      mDummy(0),
+#endif
+      mType(eUnknown),
+      mDefaultElementType(0),
+      mAllowXULXBL(eTriUnset),
+      mBidiOptions(IBMBIDI_DEFAULT_BIDI_OPTIONS),
+      mSandboxFlags(0),
+      mPartID(0),
+      mMarkedCCGeneration(0),
+      mPresShell(nullptr),
+      mSubtreeModifiedDepth(0),
+      mPreloadPictureDepth(0),
+      mEventsSuppressed(0),
+      mIgnoreDestructiveWritesCounter(0),
+      mFrameRequestCallbackCounter(0),
+      mStaticCloneCount(0),
+      mWindow(nullptr),
+      mBFCacheEntry(nullptr),
+      mInSyncOperationCount(0),
+      mBlockDOMContentLoaded(0),
+      mUseCounters(0),
+      mChildDocumentUseCounters(0),
+      mNotifiedPageForUseCounter(0),
+      mUserHasInteracted(false),
+      mHasUserInteractionTimerScheduled(false),
+      mUserGestureActivated(false),
+      mStackRefCnt(0),
+      mUpdateNestLevel(0),
+      mViewportType(Unknown),
+      mViewportOverflowType(ViewportOverflowType::NoOverflow),
+      mSubDocuments(nullptr),
+      mHeaderData(nullptr),
+      mPrincipalFlashClassifier(new PrincipalFlashClassifier()),
+      mFlashClassification(FlashClassification::Unclassified),
+      mBoxObjectTable(nullptr),
+      mCurrentOrientationAngle(0),
+      mCurrentOrientationType(OrientationType::Portrait_primary),
+      mServoRestyleRootDirtyBits(0),
+      mThrowOnDynamicMarkupInsertionCounter(0),
+      mIgnoreOpensDuringUnloadCounter(0),
+      mDocLWTheme(Doc_Theme_Uninitialized),
+      mSavedResolution(1.0f) {
+  MOZ_LOG(gDocumentLeakPRLog, LogLevel::Debug, ("DOCUMENT %p created", this));
+
+  SetIsInDocument();
+  SetIsConnected(true);
+
+  if (StaticPrefs::layout_css_use_counters_enabled()) {
+    mStyleUseCounters.reset(Servo_UseCounters_Create());
+  }
+
+  SetContentTypeInternal(nsDependentCString(aContentType));
+
+  // Start out mLastStyleSheetSet as null, per spec
+  SetDOMStringToNull(mLastStyleSheetSet);
+
+  // void state used to differentiate an empty source from an unselected source
+  mPreloadPictureFoundSource.SetIsVoid(true);
+}
+
+void Document::ClearAllBoxObjects() {
+  if (mBoxObjectTable) {
+    for (auto iter = mBoxObjectTable->Iter(); !iter.Done(); iter.Next()) {
+      nsPIBoxObject* boxObject = iter.UserData();
+      if (boxObject) {
+        boxObject->Clear();
+      }
+    }
+    delete mBoxObjectTable;
+    mBoxObjectTable = nullptr;
+  }
+}
+
+bool Document::IsAboutPage() const {
+  nsCOMPtr<nsIPrincipal> principal = NodePrincipal();
+  nsCOMPtr<nsIURI> uri;
+  principal->GetURI(getter_AddRefs(uri));
+  bool isAboutScheme = true;
+  if (uri) {
+    uri->SchemeIs("about", &isAboutScheme);
+  }
+  return isAboutScheme;
+}
+
+void Document::ConstructUbiNode(void* storage) {
+  JS::ubi::Concrete<Document>::construct(storage, this);
+}
+
+Document::~Document() {
+  MOZ_LOG(gDocumentLeakPRLog, LogLevel::Debug, ("DOCUMENT %p destroyed", this));
+  MOZ_ASSERT(!IsTopLevelContentDocument() || !IsResourceDoc(),
+             "Can't be top-level and a resource doc at the same time");
+
+  NS_ASSERTION(!mIsShowing, "Destroying a currently-showing document");
+
+  if (IsTopLevelContentDocument()) {
+    // don't report for about: pages
+    if (!IsAboutPage()) {
+      // Record the page load
+      uint32_t pageLoaded = 1;
+      Accumulate(Telemetry::MIXED_CONTENT_UNBLOCK_COUNTER, pageLoaded);
+      // Record the mixed content status of the docshell in Telemetry
+      enum {
+        NO_MIXED_CONTENT = 0,  // There is no Mixed Content on the page
+        MIXED_DISPLAY_CONTENT =
+            1,  // The page attempted to load Mixed Display Content
+        MIXED_ACTIVE_CONTENT =
+            2,  // The page attempted to load Mixed Active Content
+        MIXED_DISPLAY_AND_ACTIVE_CONTENT =
+            3  // The page attempted to load Mixed Display & Mixed Active
+               // Content
+      };
+
+      bool mixedActiveLoaded = GetHasMixedActiveContentLoaded();
+      bool mixedActiveBlocked = GetHasMixedActiveContentBlocked();
+
+      bool mixedDisplayLoaded = GetHasMixedDisplayContentLoaded();
+      bool mixedDisplayBlocked = GetHasMixedDisplayContentBlocked();
+
+      bool hasMixedDisplay = (mixedDisplayBlocked || mixedDisplayLoaded);
+      bool hasMixedActive = (mixedActiveBlocked || mixedActiveLoaded);
+
+      uint32_t mixedContentLevel = NO_MIXED_CONTENT;
+      if (hasMixedDisplay && hasMixedActive) {
+        mixedContentLevel = MIXED_DISPLAY_AND_ACTIVE_CONTENT;
+      } else if (hasMixedActive) {
+        mixedContentLevel = MIXED_ACTIVE_CONTENT;
+      } else if (hasMixedDisplay) {
+        mixedContentLevel = MIXED_DISPLAY_CONTENT;
+      }
+      Accumulate(Telemetry::MIXED_CONTENT_PAGE_LOAD, mixedContentLevel);
+
+      // record mixed object subrequest telemetry
+      if (mHasMixedContentObjectSubrequest) {
+        /* mixed object subrequest loaded on page*/
+        Accumulate(Telemetry::MIXED_CONTENT_OBJECT_SUBREQUEST, 1);
+      } else {
+        /* no mixed object subrequests loaded on page*/
+        Accumulate(Telemetry::MIXED_CONTENT_OBJECT_SUBREQUEST, 0);
+      }
+
+      // record CSP telemetry on this document
+      if (mHasCSP) {
+        Accumulate(Telemetry::CSP_DOCUMENTS_COUNT, 1);
+      }
+      if (mHasUnsafeInlineCSP) {
+        Accumulate(Telemetry::CSP_UNSAFE_INLINE_DOCUMENTS_COUNT, 1);
+      }
+      if (mHasUnsafeEvalCSP) {
+        Accumulate(Telemetry::CSP_UNSAFE_EVAL_DOCUMENTS_COUNT, 1);
+      }
+
+      if (MOZ_UNLIKELY(mMathMLEnabled)) {
+        ScalarAdd(Telemetry::ScalarID::MATHML_DOC_COUNT, 1);
+      }
+
+      ScalarAdd(Telemetry::ScalarID::MEDIA_PAGE_COUNT, 1);
+      if (mDocTreeHadAudibleMedia) {
+        ScalarAdd(Telemetry::ScalarID::MEDIA_PAGE_HAD_MEDIA_COUNT, 1);
+      }
+      if (mDocTreeHadPlayRevoked) {
+        ScalarAdd(Telemetry::ScalarID::MEDIA_PAGE_HAD_PLAY_REVOKED_COUNT, 1);
+      }
+
+      if (IsHTMLDocument()) {
+        switch (GetCompatibilityMode()) {
+          case eCompatibility_FullStandards:
+            Telemetry::AccumulateCategorical(
+                Telemetry::LABELS_QUIRKS_MODE::FullStandards);
+            break;
+          case eCompatibility_AlmostStandards:
+            Telemetry::AccumulateCategorical(
+                Telemetry::LABELS_QUIRKS_MODE::AlmostStandards);
+            break;
+          case eCompatibility_NavQuirks:
+            Telemetry::AccumulateCategorical(
+                Telemetry::LABELS_QUIRKS_MODE::NavQuirks);
+            break;
+          default:
+            MOZ_ASSERT_UNREACHABLE("Unknown quirks mode");
+            break;
+        }
+      }
+    }
+  }
+
+  ReportUseCounters();
+
+  mInDestructor = true;
+  mInUnlinkOrDeletion = true;
+
+  mozilla::DropJSObjects(this);
+
+  // Clear mObservers to keep it in sync with the mutationobserver list
+  mObservers.Clear();
+
+  mIntersectionObservers.Clear();
+
+  if (mStyleSheetSetList) {
+    mStyleSheetSetList->Disconnect();
+  }
+
+  if (mAnimationController) {
+    mAnimationController->Disconnect();
+  }
+
+  MOZ_ASSERT(mTimelines.isEmpty());
+
+  mParentDocument = nullptr;
+
+  // Kill the subdocument map, doing this will release its strong
+  // references, if any.
+  delete mSubDocuments;
+  mSubDocuments = nullptr;
+
+  // Destroy link map now so we don't waste time removing
+  // links one by one
+  DestroyElementMaps();
+
+  nsAutoScriptBlocker scriptBlocker;
+
+  // Invalidate cached array of child nodes
+  InvalidateChildNodes();
+
+  // We should not have child nodes when destructor is called,
+  // since child nodes keep their owner document alive.
+  MOZ_ASSERT(!HasChildren());
+
+  mCachedRootElement = nullptr;
+
+  for (auto& sheets : mAdditionalSheets) {
+    for (StyleSheet* sheet : sheets) {
+      sheet->ClearAssociatedDocumentOrShadowRoot();
+    }
+  }
+
+  if (mAttrStyleSheet) {
+    mAttrStyleSheet->SetOwningDocument(nullptr);
+  }
+
+  if (mListenerManager) {
+    mListenerManager->Disconnect();
+    UnsetFlags(NODE_HAS_LISTENERMANAGER);
+  }
+
+  if (mScriptLoader) {
+    mScriptLoader->DropDocumentReference();
+  }
+
+  if (mCSSLoader) {
+    // Could be null here if Init() failed or if we have been unlinked.
+    mCSSLoader->DropDocumentReference();
+  }
+
+  if (mStyleImageLoader) {
+    mStyleImageLoader->DropDocumentReference();
+  }
+
+  if (mXULBroadcastManager) {
+    mXULBroadcastManager->DropDocumentReference();
+  }
+
+  if (mXULPersist) {
+    mXULPersist->DropDocumentReference();
+  }
+
+  delete mHeaderData;
+
+  ClearAllBoxObjects();
+
+  mPendingTitleChangeEvent.Revoke();
+
+  mPlugins.Clear();
+
+  MOZ_ASSERT(mDOMMediaQueryLists.isEmpty(),
+             "must not have media query lists left");
+
+  if (mNodeInfoManager) {
+    mNodeInfoManager->DropDocumentReference();
+  }
+
+  if (mDocGroup) {
+    mDocGroup->RemoveDocument(this);
+  }
+
+  UnlinkOriginalDocumentIfStatic();
+}
+
+NS_INTERFACE_TABLE_HEAD(Document)
+  NS_WRAPPERCACHE_INTERFACE_TABLE_ENTRY
+  NS_INTERFACE_TABLE_BEGIN
+    NS_INTERFACE_TABLE_ENTRY_AMBIGUOUS(Document, nsISupports, nsINode)
+    NS_INTERFACE_TABLE_ENTRY(Document, nsINode)
+    NS_INTERFACE_TABLE_ENTRY(Document, Document)
+    NS_INTERFACE_TABLE_ENTRY(Document, nsIScriptObjectPrincipal)
+    NS_INTERFACE_TABLE_ENTRY(Document, mozilla::dom::EventTarget)
+    NS_INTERFACE_TABLE_ENTRY(Document, nsISupportsWeakReference)
+    NS_INTERFACE_TABLE_ENTRY(Document, nsIRadioGroupContainer)
+    NS_INTERFACE_TABLE_ENTRY(Document, nsIMutationObserver)
+    NS_INTERFACE_TABLE_ENTRY(Document, nsIApplicationCacheContainer)
+  NS_INTERFACE_TABLE_END
+  NS_INTERFACE_TABLE_TO_MAP_SEGUE_CYCLE_COLLECTION(Document)
+NS_INTERFACE_MAP_END
+
+NS_IMPL_CYCLE_COLLECTING_ADDREF(Document)
+NS_IMETHODIMP_(MozExternalRefCountType)
+Document::Release() {
+  MOZ_ASSERT(0 != mRefCnt, "dup release");
+  NS_ASSERT_OWNINGTHREAD(Document);
+  nsISupports* base = NS_CYCLE_COLLECTION_CLASSNAME(Document)::Upcast(this);
+  bool shouldDelete = false;
+  nsrefcnt count = mRefCnt.decr(base, &shouldDelete);
+  NS_LOG_RELEASE(this, count, "Document");
+  if (count == 0) {
+    if (mStackRefCnt && !mNeedsReleaseAfterStackRefCntRelease) {
+      mNeedsReleaseAfterStackRefCntRelease = true;
+      NS_ADDREF_THIS();
+      return mRefCnt.get();
+    }
+    mRefCnt.incr(base);
+    nsNodeUtils::LastRelease(this);
+    mRefCnt.decr(base);
+    if (shouldDelete) {
+      mRefCnt.stabilizeForDeletion();
+      DeleteCycleCollectable();
+    }
+  }
+  return count;
+}
+
+NS_IMETHODIMP_(void)
+Document::DeleteCycleCollectable() { delete this; }
+
+NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(Document)
+  if (Element::CanSkip(tmp, aRemovingAllowed)) {
+    EventListenerManager* elm = tmp->GetExistingListenerManager();
+    if (elm) {
+      elm->MarkForCC();
+    }
+    return true;
+  }
+NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_END
+
+NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_BEGIN(Document)
+  return Element::CanSkipInCC(tmp);
+NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_END
+
+NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_BEGIN(Document)
+  return Element::CanSkipThis(tmp);
+NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_END
+
+static const char* kNSURIs[] = {"([none])", "(xmlns)", "(xml)", "(xhtml)",
+                                "(XLink)",  "(XSLT)",  "(XBL)", "(MathML)",
+                                "(RDF)",    "(XUL)"};
+
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(Document)
+  if (MOZ_UNLIKELY(cb.WantDebugInfo())) {
+    char name[512];
+    nsAutoCString loadedAsData;
+    if (tmp->IsLoadedAsData()) {
+      loadedAsData.AssignLiteral("data");
+    } else {
+      loadedAsData.AssignLiteral("normal");
+    }
+    uint32_t nsid = tmp->GetDefaultNamespaceID();
+    nsAutoCString uri;
+    if (tmp->mDocumentURI) uri = tmp->mDocumentURI->GetSpecOrDefault();
+    if (nsid < ArrayLength(kNSURIs)) {
+      SprintfLiteral(name, "Document %s %s %s", loadedAsData.get(),
+                     kNSURIs[nsid], uri.get());
+    } else {
+      SprintfLiteral(name, "Document %s %s", loadedAsData.get(), uri.get());
+    }
+    cb.DescribeRefCountedNode(tmp->mRefCnt.get(), name);
+  } else {
+    NS_IMPL_CYCLE_COLLECTION_DESCRIBE(Document, tmp->mRefCnt.get())
+  }
+
+  if (!nsINode::Traverse(tmp, cb)) {
+    return NS_SUCCESS_INTERRUPTED_TRAVERSE;
+  }
+
+  if (tmp->mMaybeEndOutermostXBLUpdateRunner) {
+    // The cached runnable keeps a reference to the document object..
+    NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(
+        cb, "mMaybeEndOutermostXBLUpdateRunner.mObj");
+    cb.NoteXPCOMChild(ToSupports(tmp));
+  }
+
+  for (auto iter = tmp->mIdentifierMap.ConstIter(); !iter.Done(); iter.Next()) {
+    iter.Get()->Traverse(&cb);
+  }
+
+  tmp->mExternalResourceMap.Traverse(&cb);
+
+  // Traverse all Document pointer members.
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSecurityInfo)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDisplayDocument)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFontFaceSet)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mReadyForIdle)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocumentL10n)
+
+  // Traverse all Document nsCOMPtrs.
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mParser)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mScriptGlobalObject)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mListenerManager)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDOMStyleSheets)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mStyleSheetSetList)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mScriptLoader)
+
+  DocumentOrShadowRoot::Traverse(tmp, cb);
+
+  // The boxobject for an element will only exist as long as it's in the
+  // document, so we'll traverse the table here instead of from the element.
+  if (tmp->mBoxObjectTable) {
+    for (auto iter = tmp->mBoxObjectTable->Iter(); !iter.Done(); iter.Next()) {
+      NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mBoxObjectTable entry");
+      cb.NoteXPCOMChild(iter.UserData());
+    }
+  }
+
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mChannel)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLayoutHistoryState)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOnloadBlocker)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDOMImplementation)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mImageMaps)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOrientationPendingPromise)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOriginalDocument)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCachedEncoder)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mStateObjectCached)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocumentTimeline)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPendingAnimationTracker)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTemplateContentsOwner)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mChildrenCollection)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mImages);
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mEmbeds);
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLinks);
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mForms);
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mScripts);
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mApplets);
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mAnchors);
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mAnonymousContents)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCommandDispatcher)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFeaturePolicy)
+
+  // Traverse all our nsCOMArrays.
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mStyleSheets)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPreloadingImages)
+
+  for (uint32_t i = 0; i < tmp->mFrameRequestCallbacks.Length(); ++i) {
+    NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mFrameRequestCallbacks[i]");
+    cb.NoteXPCOMChild(tmp->mFrameRequestCallbacks[i].mCallback);
+  }
+
+  // Traverse animation components
+  if (tmp->mAnimationController) {
+    tmp->mAnimationController->Traverse(&cb);
+  }
+
+  if (tmp->mSubDocuments) {
+    for (auto iter = tmp->mSubDocuments->Iter(); !iter.Done(); iter.Next()) {
+      auto entry = static_cast<SubDocMapEntry*>(iter.Get());
+
+      NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mSubDocuments entry->mKey");
+      cb.NoteXPCOMChild(entry->mKey);
+      NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb,
+                                         "mSubDocuments entry->mSubDocument");
+      cb.NoteXPCOMChild(ToSupports(entry->mSubDocument));
+    }
+  }
+
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCSSLoader)
+
+  // We own only the items in mDOMMediaQueryLists that have listeners;
+  // this reference is managed by their AddListener and RemoveListener
+  // methods.
+  for (MediaQueryList* mql = tmp->mDOMMediaQueryLists.getFirst(); mql;
+       mql = static_cast<LinkedListElement<MediaQueryList>*>(mql)->getNext()) {
+    if (mql->HasListeners() &&
+        NS_SUCCEEDED(mql->CheckInnerWindowCorrectness())) {
+      NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mDOMMediaQueryLists item");
+      cb.NoteXPCOMChild(mql);
+    }
+  }
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
+
+NS_IMPL_CYCLE_COLLECTION_CLASS(Document)
+
+NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(Document)
+
+NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(Document)
+  tmp->mInUnlinkOrDeletion = true;
+
+  // Clear out our external resources
+  tmp->mExternalResourceMap.Shutdown();
+
+  nsAutoScriptBlocker scriptBlocker;
+
+  nsINode::Unlink(tmp);
+
+  while (tmp->HasChildren()) {
+    // Hold a strong ref to the node when we remove it, because we may be
+    // the last reference to it.
+    // If this code changes, change the corresponding code in Document's
+    // unlink impl and ContentUnbinder::UnbindSubtree.
+    nsCOMPtr<nsIContent> child = tmp->GetLastChild();
+    tmp->DisconnectChild(child);
+    child->UnbindFromTree();
+  }
+
+  tmp->UnlinkOriginalDocumentIfStatic();
+
+  tmp->mCachedRootElement = nullptr;  // Avoid a dangling pointer
+  NS_IMPL_CYCLE_COLLECTION_UNLINK(mDisplayDocument)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK(mMaybeEndOutermostXBLUpdateRunner)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK(mDOMImplementation)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK(mImageMaps)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK(mCachedEncoder)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocumentTimeline)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK(mPendingAnimationTracker)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK(mTemplateContentsOwner)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK(mChildrenCollection)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK(mImages);
+  NS_IMPL_CYCLE_COLLECTION_UNLINK(mEmbeds);
+  NS_IMPL_CYCLE_COLLECTION_UNLINK(mLinks);
+  NS_IMPL_CYCLE_COLLECTION_UNLINK(mForms);
+  NS_IMPL_CYCLE_COLLECTION_UNLINK(mScripts);
+  NS_IMPL_CYCLE_COLLECTION_UNLINK(mApplets);
+  NS_IMPL_CYCLE_COLLECTION_UNLINK(mAnchors);
+  NS_IMPL_CYCLE_COLLECTION_UNLINK(mOrientationPendingPromise)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK(mFontFaceSet)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK(mReadyForIdle);
+  NS_IMPL_CYCLE_COLLECTION_UNLINK(mCommandDispatcher)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocumentL10n);
+  NS_IMPL_CYCLE_COLLECTION_UNLINK(mFeaturePolicy)
+
+  tmp->mParentDocument = nullptr;
+
+  NS_IMPL_CYCLE_COLLECTION_UNLINK(mPreloadingImages)
+
+  NS_IMPL_CYCLE_COLLECTION_UNLINK(mIntersectionObservers)
+
+  tmp->ClearAllBoxObjects();
+
+  if (tmp->mListenerManager) {
+    tmp->mListenerManager->Disconnect();
+    tmp->UnsetFlags(NODE_HAS_LISTENERMANAGER);
+    tmp->mListenerManager = nullptr;
+  }
+
+  NS_IMPL_CYCLE_COLLECTION_UNLINK(mDOMStyleSheets)
+
+  if (tmp->mStyleSheetSetList) {
+    tmp->mStyleSheetSetList->Disconnect();
+    tmp->mStyleSheetSetList = nullptr;
+  }
+
+  delete tmp->mSubDocuments;
+  tmp->mSubDocuments = nullptr;
+
+  tmp->mFrameRequestCallbacks.Clear();
+  MOZ_RELEASE_ASSERT(!tmp->mFrameRequestCallbacksScheduled,
+                     "How did we get here without our presshell going away "
+                     "first?");
+
+  DocumentOrShadowRoot::Unlink(tmp);
+
+  // Document has a pretty complex destructor, so we're going to
+  // assume that *most* cycles you actually want to break somewhere
+  // else, and not unlink an awful lot here.
+
+  tmp->mIdentifierMap.Clear();
+  tmp->mExpandoAndGeneration.OwnerUnlinked();
+
+  if (tmp->mAnimationController) {
+    tmp->mAnimationController->Unlink();
+  }
+
+  tmp->mPendingTitleChangeEvent.Revoke();
+
+  if (tmp->mCSSLoader) {
+    tmp->mCSSLoader->DropDocumentReference();
+    NS_IMPL_CYCLE_COLLECTION_UNLINK(mCSSLoader)
+  }
+
+  // We own only the items in mDOMMediaQueryLists that have listeners;
+  // this reference is managed by their AddListener and RemoveListener
+  // methods.
+  for (MediaQueryList* mql = tmp->mDOMMediaQueryLists.getFirst(); mql;) {
+    MediaQueryList* next =
+        static_cast<LinkedListElement<MediaQueryList>*>(mql)->getNext();
+    mql->Disconnect();
+    mql = next;
+  }
+
+  tmp->mInUnlinkOrDeletion = false;
+NS_IMPL_CYCLE_COLLECTION_UNLINK_END
+
+nsresult Document::Init() {
+  if (mCSSLoader || mStyleImageLoader || mNodeInfoManager || mScriptLoader) {
+    return NS_ERROR_ALREADY_INITIALIZED;
+  }
+
+  // Force initialization.
+  nsINode::nsSlots* slots = Slots();
+
+  // Prepend self as mutation-observer whether we need it or not (some
+  // subclasses currently do, other don't). This is because the code in
+  // nsNodeUtils always notifies the first observer first, expecting the
+  // first observer to be the document.
+  slots->mMutationObservers.PrependElementUnlessExists(
+      static_cast<nsIMutationObserver*>(this));
+
+  mOnloadBlocker = new nsOnloadBlocker();
+  mCSSLoader = new mozilla::css::Loader(this);
+  // Assume we're not quirky, until we know otherwise
+  mCSSLoader->SetCompatibilityMode(eCompatibility_FullStandards);
+
+  mStyleImageLoader = new mozilla::css::ImageLoader(this);
+
+  mNodeInfoManager = new nsNodeInfoManager();
+  nsresult rv = mNodeInfoManager->Init(this);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  // mNodeInfo keeps NodeInfoManager alive!
+  mNodeInfo = mNodeInfoManager->GetDocumentNodeInfo();
+  NS_ENSURE_TRUE(mNodeInfo, NS_ERROR_OUT_OF_MEMORY);
+  MOZ_ASSERT(mNodeInfo->NodeType() == DOCUMENT_NODE,
+             "Bad NodeType in aNodeInfo");
+
+  NS_ASSERTION(OwnerDoc() == this, "Our nodeinfo is busted!");
+
+  // If after creation the owner js global is not set for a document
+  // we use the default compartment for this document, instead of creating
+  // wrapper in some random compartment when the document is exposed to js
+  // via some events.
+  nsCOMPtr<nsIGlobalObject> global =
+      xpc::NativeGlobal(xpc::PrivilegedJunkScope());
+  NS_ENSURE_TRUE(global, NS_ERROR_FAILURE);
+  mScopeObject = do_GetWeakReference(global);
+  MOZ_ASSERT(mScopeObject);
+
+  mScriptLoader = new dom::ScriptLoader(this);
+
+  // we need to create a policy here so getting the policy within
+  // ::Policy() can *always* return a non null policy
+  mFeaturePolicy = new FeaturePolicy(this);
+  mFeaturePolicy->SetDefaultOrigin(NodePrincipal());
+
+  mozilla::HoldJSObjects(this);
+
+  return NS_OK;
+}
+
+void Document::DeleteAllProperties() { PropertyTable().DeleteAllProperties(); }
+
+void Document::DeleteAllPropertiesFor(nsINode* aNode) {
+  PropertyTable().DeleteAllPropertiesFor(aNode);
+}
+
+bool Document::IsVisibleConsideringAncestors() const {
+  const Document* parent = this;
+  do {
+    if (!parent->IsVisible()) {
+      return false;
+    }
+  } while ((parent = parent->GetParentDocument()));
+
+  return true;
+}
+
+void Document::Reset(nsIChannel* aChannel, nsILoadGroup* aLoadGroup) {
+  nsCOMPtr<nsIURI> uri;
+  nsCOMPtr<nsIPrincipal> principal;
+  if (aChannel) {
+    // Note: this code is duplicated in XULDocument::StartDocumentLoad and
+    // nsScriptSecurityManager::GetChannelResultPrincipal.
+    // Note: this should match nsDocShell::OnLoadingSite
+    NS_GetFinalChannelURI(aChannel, getter_AddRefs(uri));
+
+    bool isWyciwyg = false;
+    uri->SchemeIs("wyciwyg", &isWyciwyg);
+    if (isWyciwyg) {
+      nsCOMPtr<nsIURI> cleanURI;
+      nsresult rv =
+          nsContentUtils::RemoveWyciwygScheme(uri, getter_AddRefs(cleanURI));
+      if (NS_SUCCEEDED(rv)) {
+        uri = cleanURI;
+      }
+    }
+
+    nsIScriptSecurityManager* securityManager =
+        nsContentUtils::GetSecurityManager();
+    if (securityManager) {
+      securityManager->GetChannelResultPrincipal(aChannel,
+                                                 getter_AddRefs(principal));
+    }
+  }
+
+  principal = MaybeDowngradePrincipal(principal);
+
+  ResetToURI(uri, aLoadGroup, principal);
+
+  // Note that, since mTiming does not change during a reset, the
+  // navigationStart time remains unchanged and therefore any future new
+  // timeline will have the same global clock time as the old one.
+  mDocumentTimeline = nullptr;
+
+  nsCOMPtr<nsIPropertyBag2> bag = do_QueryInterface(aChannel);
+  if (bag) {
+    nsCOMPtr<nsIURI> baseURI;
+    bag->GetPropertyAsInterface(NS_LITERAL_STRING("baseURI"),
+                                NS_GET_IID(nsIURI), getter_AddRefs(baseURI));
+    if (baseURI) {
+      mDocumentBaseURI = baseURI;
+      mChromeXHRDocBaseURI = nullptr;
+    }
+  }
+
+  mChannel = aChannel;
+}
+
+/**
+ * Determine whether the principal is allowed access to the localization system.
+ * We don't want the web to ever see this but all our UI including in content
+ * pages should pass this test.
+ */
+bool PrincipalAllowsL10n(nsIPrincipal* principal) {
+  // The system principal is always allowed.
+  if (nsContentUtils::IsSystemPrincipal(principal)) {
+    return true;
+  }
+
+  nsCOMPtr<nsIURI> uri;
+  nsresult rv = principal->GetURI(getter_AddRefs(uri));
+  NS_ENSURE_SUCCESS(rv, false);
+
+  bool hasFlags;
+
+  // Allow access to uris that cannot be loaded by web content.
+  rv = NS_URIChainHasFlags(uri, nsIProtocolHandler::URI_DANGEROUS_TO_LOAD,
+                           &hasFlags);
+  NS_ENSURE_SUCCESS(rv, false);
+  if (hasFlags) {
+    return true;
+  }
+
+  // UI resources also get access.
+  rv = NS_URIChainHasFlags(uri, nsIProtocolHandler::URI_IS_UI_RESOURCE,
+                           &hasFlags);
+  NS_ENSURE_SUCCESS(rv, false);
+  return hasFlags;
+}
+
+void Document::ResetToURI(nsIURI* aURI, nsILoadGroup* aLoadGroup,
+                          nsIPrincipal* aPrincipal) {
+  MOZ_ASSERT(aURI, "Null URI passed to ResetToURI");
+
+  MOZ_LOG(gDocumentLeakPRLog, LogLevel::Debug,
+          ("DOCUMENT %p ResetToURI %s", this, aURI->GetSpecOrDefault().get()));
+
+  mSecurityInfo = nullptr;
+
+  nsCOMPtr<nsILoadGroup> group = do_QueryReferent(mDocumentLoadGroup);
+  if (!aLoadGroup || group != aLoadGroup) {
+    mDocumentLoadGroup = nullptr;
+  }
+
+  // Delete references to sub-documents and kill the subdocument map,
+  // if any. It holds strong references
+  delete mSubDocuments;
+  mSubDocuments = nullptr;
+
+  // Destroy link map now so we don't waste time removing
+  // links one by one
+  DestroyElementMaps();
+
+  bool oldVal = mInUnlinkOrDeletion;
+  mInUnlinkOrDeletion = true;
+  {  // Scope for update
+    MOZ_AUTO_DOC_UPDATE(this, true);
+
+    // Invalidate cached array of child nodes
+    InvalidateChildNodes();
+
+    while (HasChildren()) {
+      nsCOMPtr<nsIContent> content = GetLastChild();
+      nsIContent* previousSibling = content->GetPreviousSibling();
+      DisconnectChild(content);
+      if (content == mCachedRootElement) {
+        // Immediately clear mCachedRootElement, now that it's been removed
+        // from mChildren, so that GetRootElement() will stop returning this
+        // now-stale value.
+        mCachedRootElement = nullptr;
+      }
+      nsNodeUtils::ContentRemoved(this, content, previousSibling);
+      content->UnbindFromTree();
+    }
+    MOZ_ASSERT(!mCachedRootElement,
+               "After removing all children, there should be no root elem");
+  }
+  mInUnlinkOrDeletion = oldVal;
+
+  // Reset our stylesheets
+  ResetStylesheetsToURI(aURI);
+
+  // Release the listener manager
+  if (mListenerManager) {
+    mListenerManager->Disconnect();
+    mListenerManager = nullptr;
+  }
+
+  // Release the stylesheets list.
+  mDOMStyleSheets = nullptr;
+
+  // Release our principal after tearing down the document, rather than before.
+  // This ensures that, during teardown, the document and the dying window
+  // (which already nulled out its document pointer and cached the principal)
+  // have matching principals.
+  SetPrincipal(nullptr);
+
+  // Clear the original URI so SetDocumentURI sets it.
+  mOriginalURI = nullptr;
+
+  SetDocumentURI(aURI);
+  mChromeXHRDocURI = nullptr;
+  // If mDocumentBaseURI is null, Document::GetBaseURI() returns
+  // mDocumentURI.
+  mDocumentBaseURI = nullptr;
+  mChromeXHRDocBaseURI = nullptr;
+
+  if (aLoadGroup) {
+    mDocumentLoadGroup = do_GetWeakReference(aLoadGroup);
+    // there was an assertion here that aLoadGroup was not null.  This
+    // is no longer valid: nsDocShell::SetDocument does not create a
+    // load group, and it works just fine
+
+    // XXXbz what does "just fine" mean exactly?  And given that there
+    // is no nsDocShell::SetDocument, what is this talking about?
+
+    if (IsContentDocument()) {
+      // Inform the associated request context about this load start so
+      // any of its internal load progress flags gets reset.
+      nsCOMPtr<nsIRequestContextService> rcsvc =
+          mozilla::net::RequestContextService::GetOrCreate();
+      if (rcsvc) {
+        nsCOMPtr<nsIRequestContext> rc;
+        rcsvc->GetRequestContextFromLoadGroup(aLoadGroup, getter_AddRefs(rc));
+        if (rc) {
+          rc->BeginLoad();
+        }
+      }
+    }
+  }
+
+  mLastModified.Truncate();
+  // XXXbz I guess we're assuming that the caller will either pass in
+  // a channel with a useful type or call SetContentType?
+  SetContentTypeInternal(EmptyCString());
+  mContentLanguage.Truncate();
+  mBaseTarget.Truncate();
+  mReferrer.Truncate();
+
+  mXMLDeclarationBits = 0;
+
+  // Now get our new principal
+  if (aPrincipal) {
+    SetPrincipal(aPrincipal);
+  } else {
+    nsIScriptSecurityManager* securityManager =
+        nsContentUtils::GetSecurityManager();
+    if (securityManager) {
+      nsCOMPtr<nsILoadContext> loadContext(mDocumentContainer);
+
+      if (!loadContext && aLoadGroup) {
+        nsCOMPtr<nsIInterfaceRequestor> cbs;
+        aLoadGroup->GetNotificationCallbacks(getter_AddRefs(cbs));
+        loadContext = do_GetInterface(cbs);
+      }
+
+      MOZ_ASSERT(loadContext,
+                 "must have a load context or pass in an explicit principal");
+
+      nsCOMPtr<nsIPrincipal> principal;
+      nsresult rv = securityManager->GetLoadContextCodebasePrincipal(
+          mDocumentURI, loadContext, getter_AddRefs(principal));
+      if (NS_SUCCEEDED(rv)) {
+        SetPrincipal(principal);
+      }
+    }
+  }
+
+  if (mFontFaceSet) {
+    mFontFaceSet->RefreshStandardFontLoadPrincipal();
+  }
+
+  // Refresh the principal on the realm.
+  if (nsPIDOMWindowInner* win = GetInnerWindow()) {
+    nsGlobalWindowInner::Cast(win)->RefreshRealmPrincipal();
+  }
+}
+
+already_AddRefed<nsIPrincipal> Document::MaybeDowngradePrincipal(
+    nsIPrincipal* aPrincipal) {
+  if (!aPrincipal) {
+    return nullptr;
+  }
+
+  // We can't load a document with an expanded principal. If we're given one,
+  // automatically downgrade it to the last principal it subsumes (which is the
+  // extension principal, in the case of extension content scripts).
+  auto* basePrin = BasePrincipal::Cast(aPrincipal);
+  if (basePrin->Is<ExpandedPrincipal>()) {
+    MOZ_DIAGNOSTIC_ASSERT(false,
+                          "Should never try to create a document with "
+                          "an expanded principal");
+
+    auto* expanded = basePrin->As<ExpandedPrincipal>();
+    return do_AddRef(expanded->AllowList().LastElement());
+  }
+
+  if (nsContentUtils::IsSystemPrincipal(aPrincipal)) {
+    // We basically want the parent document here, but because this is very
+    // early in the load, GetParentDocument() returns null, so we use the
+    // docshell hierarchy to get this information instead.
+    if (mDocumentContainer) {
+      nsCOMPtr<nsIDocShellTreeItem> parentDocShellItem;
+      mDocumentContainer->GetParent(getter_AddRefs(parentDocShellItem));
+      nsCOMPtr<nsIDocShell> parentDocShell =
+          do_QueryInterface(parentDocShellItem);
+      if (parentDocShell) {
+        nsCOMPtr<Document> parentDoc;
+        parentDoc = parentDocShell->GetDocument();
+        if (!parentDoc ||
+            !nsContentUtils::IsSystemPrincipal(parentDoc->NodePrincipal())) {
+          nsCOMPtr<nsIPrincipal> nullPrincipal =
+              do_CreateInstance("@mozilla.org/nullprincipal;1");
+          return nullPrincipal.forget();
+        }
+      }
+    }
+  }
+  nsCOMPtr<nsIPrincipal> principal(aPrincipal);
+  return principal.forget();
+}
+
+void Document::RemoveDocStyleSheetsFromStyleSets() {
+  // The stylesheets should forget us
+  for (StyleSheet* sheet : Reversed(mStyleSheets)) {
+    sheet->ClearAssociatedDocumentOrShadowRoot();
+
+    if (sheet->IsApplicable()) {
+      nsCOMPtr<nsIPresShell> shell = GetShell();
+      if (shell) {
+        shell->StyleSet()->RemoveDocStyleSheet(sheet);
+      }
+    }
+    // XXX Tell observers?
+  }
+}
+
+void Document::RemoveStyleSheetsFromStyleSets(
+    const nsTArray<RefPtr<StyleSheet>>& aSheets, SheetType aType) {
+  // The stylesheets should forget us
+  for (StyleSheet* sheet : Reversed(aSheets)) {
+    sheet->ClearAssociatedDocumentOrShadowRoot();
+
+    if (sheet->IsApplicable()) {
+      nsCOMPtr<nsIPresShell> shell = GetShell();
+      if (shell) {
+        shell->StyleSet()->RemoveStyleSheet(aType, sheet);
+      }
+    }
+    // XXX Tell observers?
+  }
+}
+
+void Document::ResetStylesheetsToURI(nsIURI* aURI) {
+  MOZ_ASSERT(aURI);
+
+  if (mStyleSetFilled) {
+    // Skip removing style sheets from the style set if we know we haven't
+    // filled the style set.  (This allows us to avoid calling
+    // GetStyleBackendType() too early.)
+    RemoveDocStyleSheetsFromStyleSets();
+    RemoveStyleSheetsFromStyleSets(mAdditionalSheets[eAgentSheet],
+                                   SheetType::Agent);
+    RemoveStyleSheetsFromStyleSets(mAdditionalSheets[eUserSheet],
+                                   SheetType::User);
+    RemoveStyleSheetsFromStyleSets(mAdditionalSheets[eAuthorSheet],
+                                   SheetType::Doc);
+
+    if (nsStyleSheetService* sheetService =
+            nsStyleSheetService::GetInstance()) {
+      RemoveStyleSheetsFromStyleSets(*sheetService->AuthorStyleSheets(),
+                                     SheetType::Doc);
+    }
+
+    mStyleSetFilled = false;
+  }
+
+  // Release all the sheets
+  mStyleSheets.Clear();
+  for (auto& sheets : mAdditionalSheets) {
+    sheets.Clear();
+  }
+
+  // NOTE:  We don't release the catalog sheets.  It doesn't really matter
+  // now, but it could in the future -- in which case not releasing them
+  // is probably the right thing to do.
+
+  // Now reset our inline style and attribute sheets.
+  if (mAttrStyleSheet) {
+    mAttrStyleSheet->Reset();
+    mAttrStyleSheet->SetOwningDocument(this);
+  } else {
+    mAttrStyleSheet = new nsHTMLStyleSheet(this);
+  }
+
+  if (!mStyleAttrStyleSheet) {
+    mStyleAttrStyleSheet = new nsHTMLCSSStyleSheet();
+  }
+
+  // Now set up our style sets
+  if (nsIPresShell* shell = GetShell()) {
+    FillStyleSet(shell->StyleSet());
+    if (shell->StyleSet()->StyleSheetsHaveChanged()) {
+      shell->ApplicableStylesChanged();
+    }
+  }
+}
+
+static void AppendSheetsToStyleSet(ServoStyleSet* aStyleSet,
+                                   const nsTArray<RefPtr<StyleSheet>>& aSheets,
+                                   SheetType aType) {
+  for (StyleSheet* sheet : Reversed(aSheets)) {
+    aStyleSet->AppendStyleSheet(aType, sheet);
+  }
+}
+
+void Document::FillStyleSet(ServoStyleSet* aStyleSet) {
+  MOZ_ASSERT(aStyleSet, "Must have a style set");
+  MOZ_ASSERT(aStyleSet->SheetCount(SheetType::Doc) == 0,
+             "Style set already has document sheets?");
+
+  MOZ_ASSERT(!mStyleSetFilled);
+
+  for (StyleSheet* sheet : Reversed(mStyleSheets)) {
+    if (sheet->IsApplicable()) {
+      aStyleSet->AddDocStyleSheet(sheet, this);
+    }
+  }
+
+  if (nsStyleSheetService* sheetService = nsStyleSheetService::GetInstance()) {
+    nsTArray<RefPtr<StyleSheet>>& sheets = *sheetService->AuthorStyleSheets();
+    for (StyleSheet* sheet : sheets) {
+      aStyleSet->AppendStyleSheet(SheetType::Doc, sheet);
+    }
+  }
+
+  AppendSheetsToStyleSet(aStyleSet, mAdditionalSheets[eAgentSheet],
+                         SheetType::Agent);
+  AppendSheetsToStyleSet(aStyleSet, mAdditionalSheets[eUserSheet],
+                         SheetType::User);
+  AppendSheetsToStyleSet(aStyleSet, mAdditionalSheets[eAuthorSheet],
+                         SheetType::Doc);
+
+  mStyleSetFilled = true;
+}
+
+static void WarnIfSandboxIneffective(nsIDocShell* aDocShell,
+                                     uint32_t aSandboxFlags,
+                                     nsIChannel* aChannel) {
+  // If the document is sandboxed (via the HTML5 iframe sandbox
+  // attribute) and both the allow-scripts and allow-same-origin
+  // keywords are supplied, the sandboxed document can call into its
+  // parent document and remove its sandboxing entirely - we print a
+  // warning to the web console in this case.
+  if (aSandboxFlags & SANDBOXED_NAVIGATION &&
+      !(aSandboxFlags & SANDBOXED_SCRIPTS) &&
+      !(aSandboxFlags & SANDBOXED_ORIGIN)) {
+    nsCOMPtr<nsIDocShellTreeItem> parentAsItem;
+    aDocShell->GetSameTypeParent(getter_AddRefs(parentAsItem));
+    nsCOMPtr<nsIDocShell> parentDocShell = do_QueryInterface(parentAsItem);
+    if (!parentDocShell) {
+      return;
+    }
+
+    // Don't warn if our parent is not the top-level document.
+    nsCOMPtr<nsIDocShellTreeItem> grandParentAsItem;
+    parentDocShell->GetSameTypeParent(getter_AddRefs(grandParentAsItem));
+    if (grandParentAsItem) {
+      return;
+    }
+
+    nsCOMPtr<nsIChannel> parentChannel;
+    parentDocShell->GetCurrentDocumentChannel(getter_AddRefs(parentChannel));
+    if (!parentChannel) {
+      return;
+    }
+    nsresult rv = nsContentUtils::CheckSameOrigin(aChannel, parentChannel);
+    if (NS_FAILED(rv)) {
+      return;
+    }
+
+    nsCOMPtr<Document> parentDocument = parentDocShell->GetDocument();
+    nsCOMPtr<nsIURI> iframeUri;
+    parentChannel->GetURI(getter_AddRefs(iframeUri));
+    nsContentUtils::ReportToConsole(
+        nsIScriptError::warningFlag, NS_LITERAL_CSTRING("Iframe Sandbox"),
+        parentDocument, nsContentUtils::eSECURITY_PROPERTIES,
+        "BothAllowScriptsAndSameOriginPresent", nullptr, 0, iframeUri);
+  }
+}
+
+bool Document::IsSynthesized() {
+  nsCOMPtr<nsILoadInfo> loadInfo = mChannel ? mChannel->GetLoadInfo() : nullptr;
+  return loadInfo && loadInfo->GetServiceWorkerTaintingSynthesized();
+}
+
+// static
+bool Document::IsCallerChromeOrAddon(JSContext* aCx, JSObject* aObject) {
+  nsIPrincipal* principal = nsContentUtils::SubjectPrincipal(aCx);
+  return principal && (nsContentUtils::IsSystemPrincipal(principal) ||
+                       principal->GetIsAddonOrExpandedAddonPrincipal());
+}
+
+nsresult Document::StartDocumentLoad(const char* aCommand, nsIChannel* aChannel,
+                                     nsILoadGroup* aLoadGroup,
+                                     nsISupports* aContainer,
+                                     nsIStreamListener** aDocListener,
+                                     bool aReset, nsIContentSink* aSink) {
+  if (MOZ_LOG_TEST(gDocumentLeakPRLog, LogLevel::Debug)) {
+    nsCOMPtr<nsIURI> uri;
+    aChannel->GetURI(getter_AddRefs(uri));
+    MOZ_LOG(gDocumentLeakPRLog, LogLevel::Debug,
+            ("DOCUMENT %p StartDocumentLoad %s", this,
+             uri ? uri->GetSpecOrDefault().get() : ""));
+  }
+
+  MOZ_ASSERT(
+      NodePrincipal()->GetAppId() != nsIScriptSecurityManager::UNKNOWN_APP_ID,
+      "Document should never have UNKNOWN_APP_ID");
+
+  MOZ_ASSERT(GetReadyStateEnum() == Document::READYSTATE_UNINITIALIZED,
+             "Bad readyState");
+  SetReadyStateInternal(READYSTATE_LOADING);
+
+  if (nsCRT::strcmp(kLoadAsData, aCommand) == 0) {
+    mLoadedAsData = true;
+    // We need to disable script & style loading in this case.
+    // We leave them disabled even in EndLoad(), and let anyone
+    // who puts the document on display to worry about enabling.
+
+    // Do not load/process scripts when loading as data
+    ScriptLoader()->SetEnabled(false);
+
+    // styles
+    CSSLoader()->SetEnabled(
+        false);  // Do not load/process styles when loading as data
+  } else if (nsCRT::strcmp("external-resource", aCommand) == 0) {
+    // Allow CSS, but not scripts
+    ScriptLoader()->SetEnabled(false);
+  }
+
+  mMayStartLayout = false;
+  MOZ_ASSERT(!mReadyForIdle,
+             "We should never hit DOMContentLoaded before this point");
+
+  if (aReset) {
+    Reset(aChannel, aLoadGroup);
+  }
+
+  nsAutoCString contentType;
+  nsCOMPtr<nsIPropertyBag2> bag = do_QueryInterface(aChannel);
+  if ((bag && NS_SUCCEEDED(bag->GetPropertyAsACString(
+                  NS_LITERAL_STRING("contentType"), contentType))) ||
+      NS_SUCCEEDED(aChannel->GetContentType(contentType))) {
+    // XXX this is only necessary for viewsource:
+    nsACString::const_iterator start, end, semicolon;
+    contentType.BeginReading(start);
+    contentType.EndReading(end);
+    semicolon = start;
+    FindCharInReadable(';', semicolon, end);
+    SetContentTypeInternal(Substring(start, semicolon));
+  }
+
+  RetrieveRelevantHeaders(aChannel);
+
+  mChannel = aChannel;
+  nsCOMPtr<nsIInputStreamChannel> inStrmChan = do_QueryInterface(mChannel);
+  if (inStrmChan) {
+    bool isSrcdocChannel;
+    inStrmChan->GetIsSrcdocChannel(&isSrcdocChannel);
+    if (isSrcdocChannel) {
+      mIsSrcdocDocument = true;
+    }
+  }
+
+  if (mChannel) {
+    nsLoadFlags loadFlags;
+    mChannel->GetLoadFlags(&loadFlags);
+    bool isDocument = false;
+    mChannel->GetIsDocument(&isDocument);
+    if (loadFlags & nsIRequest::LOAD_DOCUMENT_NEEDS_COOKIE && isDocument &&
+        IsSynthesized() && XRE_IsContentProcess()) {
+      ContentChild::UpdateCookieStatus(mChannel);
+    }
+  }
+
+  // If this document is being loaded by a docshell, copy its sandbox flags
+  // to the document, and store the fullscreen enabled flag. These are
+  // immutable after being set here.
+  nsCOMPtr<nsIDocShell> docShell = do_QueryInterface(aContainer);
+
+  // If this is an error page, don't inherit sandbox flags from docshell
+  nsCOMPtr<nsILoadInfo> loadInfo = aChannel->GetLoadInfo();
+  if (docShell && !(loadInfo && loadInfo->GetLoadErrorPage())) {
+    nsresult rv = docShell->GetSandboxFlags(&mSandboxFlags);
+    NS_ENSURE_SUCCESS(rv, rv);
+    WarnIfSandboxIneffective(docShell, mSandboxFlags, GetChannel());
+  }
+
+  // The CSP directive upgrade-insecure-requests not only applies to the
+  // toplevel document, but also to nested documents. Let's propagate that
+  // flag from the parent to the nested document.
+  nsCOMPtr<nsIDocShellTreeItem> treeItem = this->GetDocShell();
+  if (treeItem) {
+    nsCOMPtr<nsIDocShellTreeItem> sameTypeParent;
+    treeItem->GetSameTypeParent(getter_AddRefs(sameTypeParent));
+    if (sameTypeParent) {
+      Document* doc = sameTypeParent->GetDocument();
+      mBlockAllMixedContent = doc->GetBlockAllMixedContent(false);
+      // if the parent document makes use of block-all-mixed-content
+      // then subdocument preloads should always be blocked.
+      mBlockAllMixedContentPreloads =
+          mBlockAllMixedContent || doc->GetBlockAllMixedContent(true);
+
+      mUpgradeInsecureRequests = doc->GetUpgradeInsecureRequests(false);
+      // if the parent document makes use of upgrade-insecure-requests
+      // then subdocument preloads should always be upgraded.
+      mUpgradeInsecurePreloads =
+          mUpgradeInsecureRequests || doc->GetUpgradeInsecureRequests(true);
+    }
+  }
+
+  // If this is not a data document, set CSP.
+  if (!mLoadedAsData) {
+    nsresult rv = InitCSP(aChannel);
+    NS_ENSURE_SUCCESS(rv, rv);
+  }
+
+  // Initialize FeaturePolicy
+  nsresult rv = InitFeaturePolicy(aChannel);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  // XFO needs to be checked after CSP because it is ignored if
+  // the CSP defines frame-ancestors.
+  if (!FramingChecker::CheckFrameOptions(aChannel, docShell, NodePrincipal())) {
+    MOZ_LOG(gCspPRLog, LogLevel::Debug,
+            ("XFO doesn't like frame's ancestry, not loading."));
+    // stop!  ERROR page!
+    aChannel->Cancel(NS_ERROR_CSP_FRAME_ANCESTOR_VIOLATION);
+  }
+
+  // Perform a async flash classification based on the doc principal
+  // in an early stage to reduce the blocking time.
+  mFlashClassification = FlashClassification::Unclassified;
+  mPrincipalFlashClassifier->AsyncClassify(GetPrincipal());
+
+  return NS_OK;
+}
+
+void Document::SendToConsole(nsCOMArray<nsISecurityConsoleMessage>& aMessages) {
+  for (uint32_t i = 0; i < aMessages.Length(); ++i) {
+    nsAutoString messageTag;
+    aMessages[i]->GetTag(messageTag);
+
+    nsAutoString category;
+    aMessages[i]->GetCategory(category);
+
+    nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
+                                    NS_ConvertUTF16toUTF8(category), this,
+                                    nsContentUtils::eSECURITY_PROPERTIES,
+                                    NS_ConvertUTF16toUTF8(messageTag).get());
+  }
+}
+
+void Document::ApplySettingsFromCSP(bool aSpeculative) {
+  nsresult rv = NS_OK;
+  if (!aSpeculative) {
+    // 1) apply settings from regular CSP
+    nsCOMPtr<nsIContentSecurityPolicy> csp;
+    rv = NodePrincipal()->GetCsp(getter_AddRefs(csp));
+    NS_ENSURE_SUCCESS_VOID(rv);
+    if (csp) {
+      // Set up 'block-all-mixed-content' if not already inherited
+      // from the parent context or set by any other CSP.
+      if (!mBlockAllMixedContent) {
+        rv = csp->GetBlockAllMixedContent(&mBlockAllMixedContent);
+        NS_ENSURE_SUCCESS_VOID(rv);
+      }
+      if (!mBlockAllMixedContentPreloads) {
+        mBlockAllMixedContentPreloads = mBlockAllMixedContent;
+      }
+
+      // Set up 'upgrade-insecure-requests' if not already inherited
+      // from the parent context or set by any other CSP.
+      if (!mUpgradeInsecureRequests) {
+        rv = csp->GetUpgradeInsecureRequests(&mUpgradeInsecureRequests);
+        NS_ENSURE_SUCCESS_VOID(rv);
+      }
+      if (!mUpgradeInsecurePreloads) {
+        mUpgradeInsecurePreloads = mUpgradeInsecureRequests;
+      }
+    }
+    return;
+  }
+
+  // 2) apply settings from speculative csp
+  nsCOMPtr<nsIContentSecurityPolicy> preloadCsp;
+  rv = NodePrincipal()->GetPreloadCsp(getter_AddRefs(preloadCsp));
+  NS_ENSURE_SUCCESS_VOID(rv);
+  if (preloadCsp) {
+    if (!mBlockAllMixedContentPreloads) {
+      rv = preloadCsp->GetBlockAllMixedContent(&mBlockAllMixedContentPreloads);
+      NS_ENSURE_SUCCESS_VOID(rv);
+    }
+    if (!mUpgradeInsecurePreloads) {
+      rv = preloadCsp->GetUpgradeInsecureRequests(&mUpgradeInsecurePreloads);
+      NS_ENSURE_SUCCESS_VOID(rv);
+    }
+  }
+}
+
+nsresult Document::InitCSP(nsIChannel* aChannel) {
+  MOZ_ASSERT(!mScriptGlobalObject,
+             "CSP must be initialized before mScriptGlobalObject is set!");
+  if (!StaticPrefs::security_csp_enable()) {
+    MOZ_LOG(gCspPRLog, LogLevel::Debug,
+            ("CSP is disabled, skipping CSP init for document %p", this));
+    return NS_OK;
+  }
+
+  nsAutoCString tCspHeaderValue, tCspROHeaderValue;
+
+  nsCOMPtr<nsIHttpChannel> httpChannel;
+  nsresult rv = GetHttpChannelHelper(aChannel, getter_AddRefs(httpChannel));
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  if (httpChannel) {
+    Unused << httpChannel->GetResponseHeader(
+        NS_LITERAL_CSTRING("content-security-policy"), tCspHeaderValue);
+
+    Unused << httpChannel->GetResponseHeader(
+        NS_LITERAL_CSTRING("content-security-policy-report-only"),
+        tCspROHeaderValue);
+  }
+  NS_ConvertASCIItoUTF16 cspHeaderValue(tCspHeaderValue);
+  NS_ConvertASCIItoUTF16 cspROHeaderValue(tCspROHeaderValue);
+
+  // Check if this is a document from a WebExtension.
+  nsCOMPtr<nsIPrincipal> principal = NodePrincipal();
+  auto addonPolicy = BasePrincipal::Cast(principal)->AddonPolicy();
+
+  // Check if this is a signed content to apply default CSP.
+  bool applySignedContentCSP = false;
+  nsCOMPtr<nsILoadInfo> loadInfo = aChannel->GetLoadInfo();
+  if (loadInfo && loadInfo->GetVerifySignedContent()) {
+    applySignedContentCSP = true;
+  }
+
+  // If there's no CSP to apply, go ahead and return early
+  if (!addonPolicy && !applySignedContentCSP && cspHeaderValue.IsEmpty() &&
+      cspROHeaderValue.IsEmpty()) {
+    if (MOZ_LOG_TEST(gCspPRLog, LogLevel::Debug)) {
+      nsCOMPtr<nsIURI> chanURI;
+      aChannel->GetURI(getter_AddRefs(chanURI));
+      nsAutoCString aspec;
+      chanURI->GetAsciiSpec(aspec);
+      MOZ_LOG(gCspPRLog, LogLevel::Debug,
+              ("no CSP for document, %s", aspec.get()));
+    }
+
+    return NS_OK;
+  }
+
+  MOZ_LOG(gCspPRLog, LogLevel::Debug,
+          ("Document is an add-on or CSP header specified %p", this));
+
+  nsCOMPtr<nsIContentSecurityPolicy> csp;
+  rv = principal->EnsureCSP(this, getter_AddRefs(csp));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  // ----- if the doc is an addon, apply its CSP.
+  if (addonPolicy) {
+    nsCOMPtr<nsIAddonPolicyService> aps =
+        do_GetService("@mozilla.org/addons/policy-service;1");
+
+    nsAutoString addonCSP;
+    Unused << ExtensionPolicyService::GetSingleton().GetBaseCSP(addonCSP);
+    csp->AppendPolicy(addonCSP, false, false);
+
+    csp->AppendPolicy(addonPolicy->ContentSecurityPolicy(), false, false);
+  }
+
+  // ----- if the doc is a signed content, apply the default CSP.
+  // Note that when the content signing becomes a standard, we might have
+  // to restrict this enforcement to "remote content" only.
+  if (applySignedContentCSP) {
+    nsAutoString signedContentCSP;
+    Preferences::GetString("security.signed_content.CSP.default",
+                           signedContentCSP);
+    csp->AppendPolicy(signedContentCSP, false, false);
+  }
+
+  // ----- if there's a full-strength CSP header, apply it.
+  if (!cspHeaderValue.IsEmpty()) {
+    rv = CSP_AppendCSPFromHeader(csp, cspHeaderValue, false);
+    NS_ENSURE_SUCCESS(rv, rv);
+  }
+
+  // ----- if there's a report-only CSP header, apply it.
+  if (!cspROHeaderValue.IsEmpty()) {
+    rv = CSP_AppendCSPFromHeader(csp, cspROHeaderValue, true);
+    NS_ENSURE_SUCCESS(rv, rv);
+  }
+
+  // ----- Enforce sandbox policy if supplied in CSP header
+  // The document may already have some sandbox flags set (e.g. if the document
+  // is an iframe with the sandbox attribute set). If we have a CSP sandbox
+  // directive, intersect the CSP sandbox flags with the existing flags. This
+  // corresponds to the _least_ permissive policy.
+  uint32_t cspSandboxFlags = SANDBOXED_NONE;
+  rv = csp->GetCSPSandboxFlags(&cspSandboxFlags);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  // Probably the iframe sandbox attribute already caused the creation of a
+  // new NullPrincipal. Only create a new NullPrincipal if CSP requires so
+  // and no one has been created yet.
+  bool needNewNullPrincipal = (cspSandboxFlags & SANDBOXED_ORIGIN) &&
+                              !(mSandboxFlags & SANDBOXED_ORIGIN);
+
+  mSandboxFlags |= cspSandboxFlags;
+
+  if (needNewNullPrincipal) {
+    principal = NullPrincipal::CreateWithInheritedAttributes(principal);
+    principal->SetCsp(csp);
+    SetPrincipal(principal);
+  }
+
+  // ----- Enforce frame-ancestor policy on any applied policies
+  nsCOMPtr<nsIDocShell> docShell(mDocumentContainer);
+  if (docShell) {
+    bool safeAncestry = false;
+
+    // PermitsAncestry sends violation reports when necessary
+    rv = csp->PermitsAncestry(docShell, &safeAncestry);
+
+    if (NS_FAILED(rv) || !safeAncestry) {
+      MOZ_LOG(gCspPRLog, LogLevel::Debug,
+              ("CSP doesn't like frame's ancestry, not loading."));
+      // stop!  ERROR page!
+      aChannel->Cancel(NS_ERROR_CSP_FRAME_ANCESTOR_VIOLATION);
+    }
+  }
+  ApplySettingsFromCSP(false);
+  return NS_OK;
+}
+
+nsresult Document::InitFeaturePolicy(nsIChannel* aChannel) {
+  MOZ_ASSERT(mFeaturePolicy, "we should only call init once");
+
+  mFeaturePolicy->ResetDeclaredPolicy();
+
+  if (!StaticPrefs::dom_security_featurePolicy_enabled()) {
+    return NS_OK;
+  }
+
+  mFeaturePolicy->SetDefaultOrigin(NodePrincipal());
+
+  RefPtr<FeaturePolicy> parentPolicy = nullptr;
+  if (mDocumentContainer) {
+    nsPIDOMWindowOuter* containerWindow = mDocumentContainer->GetWindow();
+    if (containerWindow) {
+      nsCOMPtr<nsINode> node = containerWindow->GetFrameElementInternal();
+      HTMLIFrameElement* iframe = HTMLIFrameElement::FromNodeOrNull(node);
+      if (iframe) {
+        parentPolicy = iframe->Policy();
+      }
+    }
+  }
+
+  if (parentPolicy) {
+    // Let's inherit the policy from the parent HTMLIFrameElement if it exists.
+    mFeaturePolicy->InheritPolicy(parentPolicy);
+  }
+
+  // We don't want to parse the http Feature-Policy header if this pref is off.
+  if (!StaticPrefs::dom_security_featurePolicy_header_enabled()) {
+    return NS_OK;
+  }
+
+  nsCOMPtr<nsIHttpChannel> httpChannel;
+  nsresult rv = GetHttpChannelHelper(aChannel, getter_AddRefs(httpChannel));
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  if (!httpChannel) {
+    return NS_OK;
+  }
+
+  // query the policy from the header
+  nsAutoCString value;
+  rv = httpChannel->GetResponseHeader(NS_LITERAL_CSTRING("Feature-Policy"),
+                                      value);
+  if (NS_SUCCEEDED(rv)) {
+    mFeaturePolicy->SetDeclaredPolicy(this, NS_ConvertUTF8toUTF16(value),
+                                      NodePrincipal(), nullptr);
+  }
+
+  return NS_OK;
+}
+
+void Document::StopDocumentLoad() {
+  if (mParser) {
+    mParserAborted = true;
+    mParser->Terminate();
+  }
+}
+
+void Document::SetDocumentURI(nsIURI* aURI) {
+  nsCOMPtr<nsIURI> oldBase = GetDocBaseURI();
+  mDocumentURI = aURI;
+  nsIURI* newBase = GetDocBaseURI();
+
+  bool equalBases = false;
+  // Changing just the ref of a URI does not change how relative URIs would
+  // resolve wrt to it, so we can treat the bases as equal as long as they're
+  // equal ignoring the ref.
+  if (oldBase && newBase) {
+    oldBase->EqualsExceptRef(newBase, &equalBases);
+  } else {
+    equalBases = !oldBase && !newBase;
+  }
+
+  // If this is the first time we're setting the document's URI, set the
+  // document's original URI.
+  if (!mOriginalURI) mOriginalURI = mDocumentURI;
+
+  // If changing the document's URI changed the base URI of the document, we
+  // need to refresh the hrefs of all the links on the page.
+  if (!equalBases) {
+    RefreshLinkHrefs();
+  }
+
+  // Tell our WindowGlobalParent that the document's URI has been changed.
+  nsPIDOMWindowInner* inner = GetInnerWindow();
+  WindowGlobalChild* wgc = inner ? inner->GetWindowGlobalChild() : nullptr;
+  if (wgc) {
+    Unused << wgc->SendUpdateDocumentURI(mDocumentURI);
+  }
+}
+
+static void GetFormattedTimeString(PRTime aTime,
+                                   nsAString& aFormattedTimeString) {
+  PRExplodedTime prtime;
+  PR_ExplodeTime(aTime, PR_LocalTimeParameters, &prtime);
+  // "MM/DD/YYYY hh:mm:ss"
+  char formatedTime[24];
+  if (SprintfLiteral(formatedTime, "%02d/%02d/%04d %02d:%02d:%02d",
+                     prtime.tm_month + 1, prtime.tm_mday, int(prtime.tm_year),
+                     prtime.tm_hour, prtime.tm_min, prtime.tm_sec)) {
+    CopyASCIItoUTF16(nsDependentCString(formatedTime), aFormattedTimeString);
+  } else {
+    // If we for whatever reason failed to find the last modified time
+    // (or even the current time), fall back to what NS4.x returned.
+    aFormattedTimeString.AssignLiteral(u"01/01/1970 00:00:00");
+  }
+}
+
+void Document::GetLastModified(nsAString& aLastModified) const {
+  if (!mLastModified.IsEmpty()) {
+    aLastModified.Assign(mLastModified);
+  } else {
+    GetFormattedTimeString(PR_Now(), aLastModified);
+  }
+}
+
+static void IncrementExpandoGeneration(Document& aDoc) {
+  ++aDoc.mExpandoAndGeneration.generation;
+}
+
+void Document::AddToNameTable(Element* aElement, nsAtom* aName) {
+  MOZ_ASSERT(
+      nsGenericHTMLElement::ShouldExposeNameAsHTMLDocumentProperty(aElement),
+      "Only put elements that need to be exposed as document['name'] in "
+      "the named table.");
+
+  nsIdentifierMapEntry* entry = mIdentifierMap.PutEntry(aName);
+
+  // Null for out-of-memory
+  if (entry) {
+    if (!entry->HasNameElement() &&
+        !entry->HasIdElementExposedAsHTMLDocumentProperty()) {
+      IncrementExpandoGeneration(*this);
+    }
+    entry->AddNameElement(this, aElement);
+  }
+}
+
+void Document::RemoveFromNameTable(Element* aElement, nsAtom* aName) {
+  // Speed up document teardown
+  if (mIdentifierMap.Count() == 0) return;
+
+  nsIdentifierMapEntry* entry = mIdentifierMap.GetEntry(aName);
+  if (!entry)  // Could be false if the element was anonymous, hence never added
+    return;
+
+  entry->RemoveNameElement(aElement);
+  if (!entry->HasNameElement() &&
+      !entry->HasIdElementExposedAsHTMLDocumentProperty()) {
+    IncrementExpandoGeneration(*this);
+  }
+}
+
+void Document::AddToIdTable(Element* aElement, nsAtom* aId) {
+  nsIdentifierMapEntry* entry = mIdentifierMap.PutEntry(aId);
+
+  if (entry) { /* True except on OOM */
+    if (nsGenericHTMLElement::ShouldExposeIdAsHTMLDocumentProperty(aElement) &&
+        !entry->HasNameElement() &&
+        !entry->HasIdElementExposedAsHTMLDocumentProperty()) {
+      IncrementExpandoGeneration(*this);
+    }
+    entry->AddIdElement(aElement);
+  }
+}
+
+void Document::RemoveFromIdTable(Element* aElement, nsAtom* aId) {
+  NS_ASSERTION(aId, "huhwhatnow?");
+
+  // Speed up document teardown
+  if (mIdentifierMap.Count() == 0) {
+    return;
+  }
+
+  nsIdentifierMapEntry* entry = mIdentifierMap.GetEntry(aId);
+  if (!entry)  // Can be null for XML elements with changing ids.
+    return;
+
+  entry->RemoveIdElement(aElement);
+  if (nsGenericHTMLElement::ShouldExposeIdAsHTMLDocumentProperty(aElement) &&
+      !entry->HasNameElement() &&
+      !entry->HasIdElementExposedAsHTMLDocumentProperty()) {
+    IncrementExpandoGeneration(*this);
+  }
+  if (entry->IsEmpty()) {
+    mIdentifierMap.RemoveEntry(entry);
+  }
+}
+
+void Document::SetPrincipal(nsIPrincipal* aNewPrincipal) {
+  if (aNewPrincipal && mAllowDNSPrefetch && sDisablePrefetchHTTPSPref) {
+    nsCOMPtr<nsIURI> uri;
+    aNewPrincipal->GetURI(getter_AddRefs(uri));
+    bool isHTTPS;
+    if (!uri || NS_FAILED(uri->SchemeIs("https", &isHTTPS)) || isHTTPS) {
+      mAllowDNSPrefetch = false;
+    }
+  }
+  mNodeInfoManager->SetDocumentPrincipal(aNewPrincipal);
+
+#ifdef DEBUG
+  // Validate that the docgroup is set correctly by calling its getter and
+  // triggering its sanity check.
+  //
+  // If we're setting the principal to null, we don't want to perform the check,
+  // as the document is entering an intermediate state where it does not have a
+  // principal. It will be given another real principal shortly which we will
+  // check. It's not unsafe to have a document which has a null principal in the
+  // same docgroup as another document, so this should not be a problem.
+  if (aNewPrincipal) {
+    GetDocGroup();
+  }
+#endif
+}
+
+mozilla::dom::DocGroup* Document::GetDocGroup() const {
+#ifdef DEBUG
+  // Sanity check that we have an up-to-date and accurate docgroup
+  if (mDocGroup) {
+    nsAutoCString docGroupKey;
+
+    // GetKey() can fail, e.g. after the TLD service has shut down.
+    nsresult rv = mozilla::dom::DocGroup::GetKey(NodePrincipal(), docGroupKey);
+    if (NS_SUCCEEDED(rv)) {
+      MOZ_ASSERT(mDocGroup->MatchesKey(docGroupKey));
+    }
+    // XXX: Check that the TabGroup is correct as well!
+  }
+#endif
+
+  return mDocGroup;
+}
+
+nsresult Document::Dispatch(TaskCategory aCategory,
+                            already_AddRefed<nsIRunnable>&& aRunnable) {
+  // Note that this method may be called off the main thread.
+  if (mDocGroup) {
+    return mDocGroup->Dispatch(aCategory, std::move(aRunnable));
+  }
+  return DispatcherTrait::Dispatch(aCategory, std::move(aRunnable));
+}
+
+nsISerialEventTarget* Document::EventTargetFor(TaskCategory aCategory) const {
+  if (mDocGroup) {
+    return mDocGroup->EventTargetFor(aCategory);
+  }
+  return DispatcherTrait::EventTargetFor(aCategory);
+}
+
+AbstractThread* Document::AbstractMainThreadFor(
+    mozilla::TaskCategory aCategory) {
+  MOZ_ASSERT(NS_IsMainThread());
+  if (mDocGroup) {
+    return mDocGroup->AbstractMainThreadFor(aCategory);
+  }
+  return DispatcherTrait::AbstractMainThreadFor(aCategory);
+}
+
+void Document::NoteScriptTrackingStatus(const nsACString& aURL,
+                                        bool aIsTracking) {
+  if (aIsTracking) {
+    mTrackingScripts.PutEntry(aURL);
+  } else {
+    MOZ_ASSERT(!mTrackingScripts.Contains(aURL));
+  }
+}
+
+bool Document::IsScriptTracking(const nsACString& aURL) const {
+  return mTrackingScripts.Contains(aURL);
+}
+
+NS_IMETHODIMP
+Document::GetApplicationCache(nsIApplicationCache** aApplicationCache) {
+  NS_IF_ADDREF(*aApplicationCache = mApplicationCache);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+Document::SetApplicationCache(nsIApplicationCache* aApplicationCache) {
+  mApplicationCache = aApplicationCache;
+  return NS_OK;
+}
+
+void Document::GetContentType(nsAString& aContentType) {
+  CopyUTF8toUTF16(GetContentTypeInternal(), aContentType);
+}
+
+void Document::SetContentType(const nsAString& aContentType) {
+  SetContentTypeInternal(NS_ConvertUTF16toUTF8(aContentType));
+}
+
+bool Document::GetAllowPlugins() {
+  // First, we ask our docshell if it allows plugins.
+  nsCOMPtr<nsIDocShell> docShell(mDocumentContainer);
+
+  if (docShell) {
+    bool allowPlugins = false;
+    docShell->GetAllowPlugins(&allowPlugins);
+    if (!allowPlugins) {
+      return false;
+    }
+
+    // If the docshell allows plugins, we check whether
+    // we are sandboxed and plugins should not be allowed.
+    if (mSandboxFlags & SANDBOXED_PLUGINS) {
+      return false;
+    }
+  }
+
+  FlashClassification classification = DocumentFlashClassification();
+  if (classification == FlashClassification::Denied) {
+    return false;
+  }
+
+  return true;
+}
+
+void Document::InitializeLocalization(nsTArray<nsString>& aResourceIds) {
+  MOZ_ASSERT(!mDocumentL10n, "mDocumentL10n should not be initialized yet");
+
+  DocumentL10n* l10n = new DocumentL10n(this);
+  MOZ_ALWAYS_TRUE(l10n->Init(aResourceIds));
+  mDocumentL10n = l10n;
+}
+
+DocumentL10n* Document::GetL10n() { return mDocumentL10n; }
+
+bool Document::DocumentSupportsL10n(JSContext* aCx, JSObject* aObject) {
+  nsCOMPtr<nsIPrincipal> callerPrincipal =
+      nsContentUtils::SubjectPrincipal(aCx);
+  return PrincipalAllowsL10n(callerPrincipal);
+}
+
+void Document::LocalizationLinkAdded(Element* aLinkElement) {
+  if (!PrincipalAllowsL10n(NodePrincipal())) {
+    return;
+  }
+
+  nsAutoString href;
+  aLinkElement->GetAttr(kNameSpaceID_None, nsGkAtoms::href, href);
+  // If the link is added after the DocumentL10n instance
+  // has been initialized, just pass the resource ID to it.
+  if (mDocumentL10n) {
+    AutoTArray<nsString, 1> resourceIds;
+    resourceIds.AppendElement(href);
+    mDocumentL10n->AddResourceIds(resourceIds);
+  } else if (mReadyState >= READYSTATE_INTERACTIVE) {
+    // Otherwise, if the document has already been parsed
+    // we need to lazily initialize the localization.
+    AutoTArray<nsString, 1> resourceIds;
+    resourceIds.AppendElement(href);
+    InitializeLocalization(resourceIds);
+    mDocumentL10n->TriggerInitialDocumentTranslation();
+  } else {
+    // Otherwise, we're still parsing the document.
+    // In that case, add it to the pending list. This list
+    // will be resolved once the end of l10n resource
+    // container is reached.
+    mL10nResources.AppendElement(href);
+  }
+}
+
+void Document::LocalizationLinkRemoved(Element* aLinkElement) {
+  if (!PrincipalAllowsL10n(NodePrincipal())) {
+    return;
+  }
+
+  nsAutoString href;
+  aLinkElement->GetAttr(kNameSpaceID_None, nsGkAtoms::href, href);
+  if (mDocumentL10n) {
+    AutoTArray<nsString, 1> resourceIds;
+    resourceIds.AppendElement(href);
+    uint32_t remaining = mDocumentL10n->RemoveResourceIds(resourceIds);
+    if (remaining == 0) {
+      mDocumentL10n = nullptr;
+    }
+  } else {
+    mL10nResources.RemoveElement(href);
+  }
+}
+
+/**
+ * This method should be called once the end of the l10n
+ * resource container has been parsed.
+ *
+ * In XUL this is the end of the first </linkset>,
+ * In XHTML/HTML this is the end of </head>.
+ *
+ * This milestone is used to allow for batch
+ * localization context I/O and building done
+ * once when all resources in the document have been
+ * collected.
+ */
+void Document::OnL10nResourceContainerParsed() {
+  if (!mL10nResources.IsEmpty()) {
+    InitializeLocalization(mL10nResources);
+    mL10nResources.Clear();
+  }
+}
+
+void Document::TriggerInitialDocumentTranslation() {
+  if (mDocumentL10n) {
+    mDocumentL10n->TriggerInitialDocumentTranslation();
+  }
+}
+
+bool Document::IsWebAnimationsEnabled(JSContext* aCx, JSObject* /*unused*/) {
+  MOZ_ASSERT(NS_IsMainThread());
+
+  return nsContentUtils::IsSystemCaller(aCx) ||
+         nsContentUtils::AnimationsAPICoreEnabled();
+}
+
+bool Document::IsWebAnimationsEnabled(CallerType aCallerType) {
+  MOZ_ASSERT(NS_IsMainThread());
+
+  return aCallerType == dom::CallerType::System ||
+         nsContentUtils::AnimationsAPICoreEnabled();
+}
+
+bool Document::IsWebAnimationsGetAnimationsEnabled(JSContext* aCx,
+                                                   JSObject* /*unused*/
+) {
+  MOZ_ASSERT(NS_IsMainThread());
+
+  return nsContentUtils::IsSystemCaller(aCx) ||
+         StaticPrefs::dom_animations_api_getAnimations_enabled();
+}
+
+bool Document::AreWebAnimationsImplicitKeyframesEnabled(JSContext* aCx,
+                                                        JSObject* /*unused*/
+) {
+  MOZ_ASSERT(NS_IsMainThread());
+
+  return nsContentUtils::IsSystemCaller(aCx) ||
+         StaticPrefs::dom_animations_api_implicit_keyframes_enabled();
+}
+
+bool Document::AreWebAnimationsTimelinesEnabled(JSContext* aCx,
+                                                JSObject* /*unused*/
+) {
+  MOZ_ASSERT(NS_IsMainThread());
+
+  return nsContentUtils::IsSystemCaller(aCx) ||
+         StaticPrefs::dom_animations_api_timelines_enabled();
+}
+
+DocumentTimeline* Document::Timeline() {
+  if (!mDocumentTimeline) {
+    mDocumentTimeline = new DocumentTimeline(this, TimeDuration(0));
+  }
+
+  return mDocumentTimeline;
+}
+
+void Document::GetAnimations(nsTArray<RefPtr<Animation>>& aAnimations) {
+  // Hold a strong ref for the root element since Element::GetAnimations() calls
+  // FlushPendingNotifications() which may destroy the element.
+  RefPtr<Element> root = GetRootElement();
+  if (!root) {
+    return;
+  }
+  AnimationFilter filter;
+  filter.mSubtree = true;
+  root->GetAnimations(filter, aAnimations);
+}
+
+SVGSVGElement* Document::GetSVGRootElement() const {
+  Element* root = GetRootElement();
+  if (!root || !root->IsSVGElement(nsGkAtoms::svg)) {
+    return nullptr;
+  }
+  return static_cast<SVGSVGElement*>(root);
+}
+
+/* Return true if the document is in the focused top-level window, and is an
+ * ancestor of the focused DOMWindow. */
+bool Document::HasFocus(ErrorResult& rv) const {
+  nsIFocusManager* fm = nsFocusManager::GetFocusManager();
+  if (!fm) {
+    rv.Throw(NS_ERROR_NOT_AVAILABLE);
+    return false;
+  }
+
+  // Is there a focused DOMWindow?
+  nsCOMPtr<mozIDOMWindowProxy> focusedWindow;
+  fm->GetFocusedWindow(getter_AddRefs(focusedWindow));
+  if (!focusedWindow) {
+    return false;
+  }
+
+  nsPIDOMWindowOuter* piWindow = nsPIDOMWindowOuter::From(focusedWindow);
+
+  // Are we an ancestor of the focused DOMWindow?
+  for (Document* currentDoc = piWindow->GetDoc(); currentDoc;
+       currentDoc = currentDoc->GetParentDocument()) {
+    if (currentDoc == this) {
+      // Yes, we are an ancestor