Merge mozilla-central to autoland. a=merge CLOSED TREE
authorCiure Andrei <aciure@mozilla.com>
Fri, 04 Jan 2019 01:03:06 +0200
changeset 512465 95d275f757c3501fcdc8e00e84f8ae1a3be0cf48
parent 512464 ec8667678f3a7fa4d6259b070a35a4c4a5c14209 (current diff)
parent 512444 b762378e8c7e1127f555f54d2ab770a5a4c9e430 (diff)
child 512466 0097778657282369dc3e4201818aff8c7ebfa9c3
push id1953
push userffxbld-merge
push dateMon, 11 Mar 2019 12:10:20 +0000
treeherdermozilla-release@9c35dcbaa899 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone66.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge mozilla-central to autoland. a=merge CLOSED TREE
caps/BasePrincipal.cpp
caps/BasePrincipal.h
dom/base/nsContentPolicyUtils.h
dom/base/nsContentUtils.cpp
dom/base/nsContentUtils.h
dom/base/nsDocument.cpp
dom/base/nsGlobalWindowOuter.cpp
dom/base/nsIDocument.h
dom/base/nsIDocumentInlines.h
dom/events/Clipboard.cpp
dom/html/nsGenericHTMLFrameElement.cpp
dom/media/DOMMediaStream.cpp
dom/security/nsContentSecurityManager.cpp
layout/base/AccessibleCaretManager.cpp
layout/base/AccessibleCaretManager.h
layout/base/nsRefreshDriver.cpp
layout/base/nsRefreshDriver.h
netwerk/base/nsNetUtil.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
toolkit/mozapps/extensions/AddonManagerWebAPI.cpp
--- 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)