Bug 1425769: Base class for ShadowRoot and Document to manage style state. r=smaug
authorEmilio Cobos Álvarez <emilio@crisal.io>
Sun, 17 Dec 2017 22:29:10 +0100
changeset 396863 f42c0478255d9b29a44a2f671a5cf05ac5ac2ab5
parent 396862 e4f5ec55f5e21a7b82b391d61779ac4845c651b6
child 396864 deb775eb35bb3e157e89646ede5416b5f00cf8ee
push id98389
push userbtara@mozilla.com
push dateTue, 19 Dec 2017 22:17:30 +0000
treeherdermozilla-inbound@05eec51a4ec2 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug
bugs1425769
milestone59.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1425769: Base class for ShadowRoot and Document to manage style state. r=smaug This also removes some confusing comments around nsIDocument regarding some kind of "special" stylesheets, which don't seem to exist anymore, and consolidates StyleSheetList so that we only have one implementation. I think that fixes a potential leak on the shadow root code (even though the API is v0 only), given the pointer from the ShadowRootStyleSheetList to the ShadowRoot wasn't being CCd. Also, more stuff could be renamed, methods removed, etc, feel free to suggest more cleanup, I've done mostly the minimal. Next steps are moving the stylesets there and stop using the proto binding sheet list / resources. MozReview-Commit-ID: D9hnDgPQAS5
chrome/nsChromeRegistry.cpp
dom/base/ShadowRoot.cpp
dom/base/ShadowRoot.h
dom/base/StyleScope.cpp
dom/base/StyleScope.h
dom/base/StyleSheetList.cpp
dom/base/StyleSheetList.h
dom/base/moz.build
dom/base/nsDocument.cpp
dom/base/nsDocument.h
dom/base/nsIDocument.h
dom/base/nsIDocumentInlines.h
layout/inspector/inDOMUtils.cpp
layout/style/Loader.cpp
layout/style/ServoStyleSet.cpp
layout/style/nsStyleSet.cpp
--- a/chrome/nsChromeRegistry.cpp
+++ b/chrome/nsChromeRegistry.cpp
@@ -416,33 +416,32 @@ nsresult nsChromeRegistry::RefreshWindow
         if (NS_FAILED(rv)) return rv;
       }
     }
 
     rv = shell->SetAgentStyleSheets(newAgentSheets);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
-  int32_t count = document->GetNumberOfStyleSheets();
+  size_t count = document->SheetCount();
 
   // Build an array of style sheets we need to reload.
   nsTArray<RefPtr<StyleSheet>> oldSheets(count);
   nsTArray<RefPtr<StyleSheet>> newSheets(count);
 
   // Iterate over the style sheets.
-  for (int32_t i = 0; i < count; i++) {
+  for (size_t i = 0; i < count; i++) {
     // Get the style sheet
-    StyleSheet* styleSheet = document->GetStyleSheetAt(i);
-    oldSheets.AppendElement(styleSheet);
+    oldSheets.AppendElement(document->SheetAt(i));
   }
 
   // Iterate over our old sheets and kick off a sync load of the new
   // sheet if and only if it's a non-inline sheet with a chrome URL.
   for (StyleSheet* sheet : oldSheets) {
-    MOZ_ASSERT(sheet, "GetStyleSheetAt shouldn't return nullptr for "
+    MOZ_ASSERT(sheet, "SheetAt shouldn't return nullptr for "
                       "in-range sheet indexes");
     nsIURI* uri = sheet->GetSheetURI();
 
     if (!sheet->IsInline() && IsChromeURI(uri)) {
       // Reload the sheet.
       RefPtr<StyleSheet> newSheet;
       // XXX what about chrome sheets that have a title or are disabled?  This
       // only works by sheer dumb luck.
--- a/dom/base/ShadowRoot.cpp
+++ b/dom/base/ShadowRoot.cpp
@@ -22,29 +22,29 @@
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(ShadowRoot)
 
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(ShadowRoot,
                                                   DocumentFragment)
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mStyleSheetList)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDOMStyleSheets)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mAssociatedBinding)
   for (auto iter = tmp->mIdentifierMap.ConstIter(); !iter.Done();
        iter.Next()) {
     iter.Get()->Traverse(&cb);
   }
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(ShadowRoot)
   if (tmp->GetHost()) {
     tmp->GetHost()->RemoveMutationObserver(tmp);
   }
-  NS_IMPL_CYCLE_COLLECTION_UNLINK(mStyleSheetList)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK(mDOMStyleSheets)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mAssociatedBinding)
   tmp->mIdentifierMap.Clear();
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END_INHERITED(DocumentFragment)
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ShadowRoot)
   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIContent)
   NS_INTERFACE_MAP_ENTRY(nsIMutationObserver)
 NS_INTERFACE_MAP_END_INHERITING(DocumentFragment)
@@ -205,45 +205,62 @@ ShadowRoot::StyleSheetChanged()
 }
 
 void
 ShadowRoot::InsertSheet(StyleSheet* aSheet,
                         nsIContent* aLinkingContent)
 {
   nsCOMPtr<nsIStyleSheetLinkingElement>
     linkingElement = do_QueryInterface(aLinkingContent);
+
+  // FIXME(emilio, bug 1410578): <link> should probably also be allowed here.
   MOZ_ASSERT(linkingElement, "The only styles in a ShadowRoot should come "
                              "from <style>.");
 
   linkingElement->SetStyleSheet(aSheet); // This sets the ownerNode on the sheet
 
+  MOZ_DIAGNOSTIC_ASSERT(mProtoBinding->SheetCount() == StyleScope::SheetCount());
+#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
+  // FIXME(emilio, bug 1425759): For now we keep them duplicated, the proto
+  // binding will disappear soon (tm).
+  {
+    size_t i = 0;
+    for (RefPtr<StyleSheet>& sheet : mStyleSheets) {
+      MOZ_DIAGNOSTIC_ASSERT(sheet.get() == mProtoBinding->StyleSheetAt(i++));
+    }
+  }
+#endif
+
   // Find the correct position to insert into the style sheet list (must
   // be in tree order).
-  for (size_t i = 0; i <= mProtoBinding->SheetCount(); i++) {
-    if (i == mProtoBinding->SheetCount()) {
+  for (size_t i = 0; i <= SheetCount(); i++) {
+    if (i == SheetCount()) {
+      AppendStyleSheet(*aSheet);
       mProtoBinding->AppendStyleSheet(aSheet);
       break;
     }
 
-    nsINode* sheetOwningNode = mProtoBinding->StyleSheetAt(i)->GetOwnerNode();
+    nsINode* sheetOwningNode = SheetAt(i)->GetOwnerNode();
     if (nsContentUtils::PositionIsBefore(aLinkingContent, sheetOwningNode)) {
+      InsertSheetAt(i, *aSheet);
       mProtoBinding->InsertStyleSheetAt(i, aSheet);
       break;
     }
   }
 
   if (aSheet->IsApplicable()) {
     StyleSheetChanged();
   }
 }
 
 void
 ShadowRoot::RemoveSheet(StyleSheet* aSheet)
 {
   mProtoBinding->RemoveStyleSheet(aSheet);
+  StyleScope::RemoveSheet(*aSheet);
 
   if (aSheet->IsApplicable()) {
     StyleSheetChanged();
   }
 }
 
 Element*
 ShadowRoot::GetElementById(const nsAString& aElementId)
@@ -488,26 +505,16 @@ ShadowRoot::SetApplyAuthorStyles(bool aA
   nsIPresShell* shell = OwnerDoc()->GetShell();
   if (shell) {
     OwnerDoc()->BeginUpdate(UPDATE_STYLE);
     shell->RecordShadowStyleChange(this);
     OwnerDoc()->EndUpdate(UPDATE_STYLE);
   }
 }
 
-StyleSheetList*
-ShadowRoot::StyleSheets()
-{
-  if (!mStyleSheetList) {
-    mStyleSheetList = new ShadowRootStyleSheetList(this);
-  }
-
-  return mStyleSheetList;
-}
-
 /**
  * Returns whether the web components pool population algorithm
  * on the host would contain |aContent|. This function ignores
  * insertion points in the pool, thus should only be used to
  * test nodes that have not yet been distributed.
  */
 bool
 ShadowRoot::IsPooledNode(nsIContent* aContent) const
@@ -615,43 +622,8 @@ ShadowRoot::ContentRemoved(nsIDocument* 
 
 nsresult
 ShadowRoot::Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
                   bool aPreallocateChildren) const
 {
   *aResult = nullptr;
   return NS_ERROR_DOM_DATA_CLONE_ERR;
 }
-
-NS_IMPL_CYCLE_COLLECTION_INHERITED(ShadowRootStyleSheetList, StyleSheetList,
-                                   mShadowRoot)
-
-NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ShadowRootStyleSheetList)
-NS_INTERFACE_MAP_END_INHERITING(StyleSheetList)
-
-NS_IMPL_ADDREF_INHERITED(ShadowRootStyleSheetList, StyleSheetList)
-NS_IMPL_RELEASE_INHERITED(ShadowRootStyleSheetList, StyleSheetList)
-
-ShadowRootStyleSheetList::ShadowRootStyleSheetList(ShadowRoot* aShadowRoot)
-  : mShadowRoot(aShadowRoot)
-{
-}
-
-ShadowRootStyleSheetList::~ShadowRootStyleSheetList()
-{
-}
-
-StyleSheet*
-ShadowRootStyleSheetList::IndexedGetter(uint32_t aIndex, bool& aFound)
-{
-  aFound = aIndex < mShadowRoot->mProtoBinding->SheetCount();
-  if (!aFound) {
-    return nullptr;
-  }
-  return mShadowRoot->mProtoBinding->StyleSheetAt(aIndex);
-}
-
-uint32_t
-ShadowRootStyleSheetList::Length()
-{
-  return mShadowRoot->mProtoBinding->SheetCount();
-}
-
--- a/dom/base/ShadowRoot.h
+++ b/dom/base/ShadowRoot.h
@@ -3,18 +3,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_dom_shadowroot_h__
 #define mozilla_dom_shadowroot_h__
 
 #include "mozilla/dom/DocumentFragment.h"
-#include "mozilla/dom/StyleSheetList.h"
-#include "mozilla/StyleSheet.h"
+#include "mozilla/dom/StyleScope.h"
 #include "nsCOMPtr.h"
 #include "nsCycleCollectionParticipant.h"
 #include "nsIContentInlines.h"
 #include "nsIdentifierMapEntry.h"
 #include "nsTHashtable.h"
 
 class nsAtom;
 class nsIContent;
@@ -22,55 +21,63 @@ class nsXBLPrototypeBinding;
 
 namespace mozilla {
 
 class EventChainPreVisitor;
 
 namespace dom {
 
 class Element;
-class ShadowRootStyleSheetList;
 
 class ShadowRoot final : public DocumentFragment,
+                         public StyleScope,
                          public nsStubMutationObserver
 {
-  friend class ShadowRootStyleSheetList;
 public:
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(ShadowRoot,
                                            DocumentFragment)
   NS_DECL_ISUPPORTS_INHERITED
 
   NS_DECL_NSIMUTATIONOBSERVER_ATTRIBUTECHANGED
   NS_DECL_NSIMUTATIONOBSERVER_CONTENTAPPENDED
   NS_DECL_NSIMUTATIONOBSERVER_CONTENTINSERTED
   NS_DECL_NSIMUTATIONOBSERVER_CONTENTREMOVED
 
   ShadowRoot(Element* aElement, bool aClosed,
              already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo,
              nsXBLPrototypeBinding* aProtoBinding);
 
   // Shadow DOM v1
   Element* Host();
-  ShadowRootMode Mode()
+  ShadowRootMode Mode() const
   {
     return mMode;
   }
-  bool IsClosed()
+  bool IsClosed() const
   {
     return mMode == ShadowRootMode::Closed;
   }
 
+  // StyleScope.
+  nsINode& AsNode() final
+  {
+    return *this;
+  }
+
   // [deprecated] Shadow DOM v0
   void AddToIdTable(Element* aElement, nsAtom* aId);
   void RemoveFromIdTable(Element* aElement, nsAtom* aId);
   void InsertSheet(StyleSheet* aSheet, nsIContent* aLinkingContent);
   void RemoveSheet(StyleSheet* aSheet);
   bool ApplyAuthorStyles();
   void SetApplyAuthorStyles(bool aApplyAuthorStyles);
-  StyleSheetList* StyleSheets();
+  StyleSheetList* StyleSheets()
+  {
+    return &StyleScope::EnsureDOMStyleSheets();
+  }
 
   /**
    * Distributes all the explicit children of the pool host to the content
    * insertion points in this ShadowRoot.
    */
   void DistributeAllNodes();
 
 private:
@@ -150,53 +157,29 @@ protected:
   nsTHashtable<nsIdentifierMapEntry> mIdentifierMap;
   nsXBLPrototypeBinding* mProtoBinding;
 
   // It is necessary to hold a reference to the associated nsXBLBinding
   // because the binding holds a reference on the nsXBLDocumentInfo that
   // owns |mProtoBinding|.
   RefPtr<nsXBLBinding> mAssociatedBinding;
 
-  RefPtr<ShadowRootStyleSheetList> mStyleSheetList;
-
   // A boolean that indicates that an insertion point was added or removed
   // from this ShadowRoot and that the nodes need to be redistributed into
   // the insertion points. After this flag is set, nodes will be distributed
   // on the next mutation event.
   bool mInsertionPointChanged;
 
   // Flag to indicate whether the descendants of this shadow root are part of the
   // composed document. Ideally, we would use a node flag on nodes to
   // mark whether it is in the composed document, but we have run out of flags
   // so instead we track it here.
   bool mIsComposedDocParticipant;
 
   nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
                  bool aPreallocateChildren) const override;
 };
 
-class ShadowRootStyleSheetList : public StyleSheetList
-{
-public:
-  explicit ShadowRootStyleSheetList(ShadowRoot* aShadowRoot);
-
-  NS_DECL_ISUPPORTS_INHERITED
-  NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(ShadowRootStyleSheetList, StyleSheetList)
-
-  virtual nsINode* GetParentObject() const override
-  {
-    return mShadowRoot;
-  }
-
-  uint32_t Length() override;
-  StyleSheet* IndexedGetter(uint32_t aIndex, bool& aFound) override;
-
-protected:
-  virtual ~ShadowRootStyleSheetList();
-
-  RefPtr<ShadowRoot> mShadowRoot;
-};
-
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_shadowroot_h__
 
new file mode 100644
--- /dev/null
+++ b/dom/base/StyleScope.cpp
@@ -0,0 +1,27 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "StyleScope.h"
+#include "mozilla/dom/StyleSheetList.h"
+
+namespace mozilla {
+namespace dom {
+
+StyleScope::~StyleScope()
+{
+}
+
+StyleSheetList&
+StyleScope::EnsureDOMStyleSheets()
+{
+  if (!mDOMStyleSheets) {
+    mDOMStyleSheets = new StyleSheetList(*this);
+  }
+  return *mDOMStyleSheets;
+}
+
+}
+}
new file mode 100644
--- /dev/null
+++ b/dom/base/StyleScope.h
@@ -0,0 +1,81 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_dom_StyleScope_h__
+#define mozilla_dom_StyleScope_h__
+
+#include "nsTArray.h"
+
+class nsINode;
+
+namespace mozilla {
+class StyleSheet;
+
+namespace dom {
+
+class StyleSheetList;
+
+/**
+ * A class meant to be shared by ShadowRoot and Document, that holds a list of
+ * stylesheets.
+ *
+ * TODO(emilio, bug 1418159): In the future this should hold most of the
+ * relevant style state, this should allow us to fix bug 548397.
+ */
+class StyleScope
+{
+public:
+  virtual nsINode& AsNode() = 0;
+
+  const nsINode& AsNode() const
+  {
+    return const_cast<StyleScope&>(*this).AsNode();
+  }
+
+  StyleSheet* SheetAt(size_t aIndex) const
+  {
+    return mStyleSheets.SafeElementAt(aIndex);
+  }
+
+  size_t SheetCount() const
+  {
+    return mStyleSheets.Length();
+  }
+
+  int32_t IndexOfSheet(const StyleSheet& aSheet) const
+  {
+    return mStyleSheets.IndexOf(&aSheet);
+  }
+
+  void InsertSheetAt(size_t aIndex, StyleSheet& aSheet)
+  {
+    mStyleSheets.InsertElementAt(aIndex, &aSheet);
+  }
+
+  void RemoveSheet(StyleSheet& aSheet)
+  {
+    mStyleSheets.RemoveElement(&aSheet);
+  }
+
+  void AppendStyleSheet(StyleSheet& aSheet)
+  {
+    mStyleSheets.AppendElement(&aSheet);
+  }
+
+  StyleSheetList& EnsureDOMStyleSheets();
+
+  ~StyleScope();
+
+protected:
+  nsTArray<RefPtr<mozilla::StyleSheet>> mStyleSheets;
+  RefPtr<mozilla::dom::StyleSheetList> mDOMStyleSheets;
+};
+
+}
+
+}
+
+#endif
--- a/dom/base/StyleSheetList.cpp
+++ b/dom/base/StyleSheetList.cpp
@@ -3,26 +3,28 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/dom/StyleSheetList.h"
 
 #include "mozilla/CSSStyleSheet.h"
 #include "mozilla/dom/StyleSheetListBinding.h"
+#include "nsStubDocumentObserver.h"
 
 namespace mozilla {
 namespace dom {
 
 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(StyleSheetList)
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(StyleSheetList)
   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
   NS_INTERFACE_MAP_ENTRY(nsIDOMStyleSheetList)
-  NS_INTERFACE_MAP_ENTRY(nsISupports)
+  NS_INTERFACE_MAP_ENTRY(nsIMutationObserver)
+  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMStyleSheetList)
 NS_INTERFACE_MAP_END
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(StyleSheetList)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(StyleSheetList)
 
 /* virtual */ JSObject*
 StyleSheetList::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
 {
@@ -38,10 +40,29 @@ StyleSheetList::GetLength(uint32_t* aLen
 
 NS_IMETHODIMP
 StyleSheetList::SlowItem(uint32_t aIndex, nsIDOMStyleSheet** aItem)
 {
   NS_IF_ADDREF(*aItem = Item(aIndex));
   return NS_OK;
 }
 
+void
+StyleSheetList::NodeWillBeDestroyed(const nsINode* aNode)
+{
+  mStyleScope = nullptr;
+}
+
+StyleSheetList::StyleSheetList(StyleScope& aScope)
+  : mStyleScope(&aScope)
+{
+  mStyleScope->AsNode().AddMutationObserver(this);
+}
+
+StyleSheetList::~StyleSheetList()
+{
+  if (mStyleScope) {
+    mStyleScope->AsNode().RemoveMutationObserver(this);
+  }
+}
+
 } // namespace dom
 } // namespace mozilla
--- a/dom/base/StyleSheetList.h
+++ b/dom/base/StyleSheetList.h
@@ -2,46 +2,74 @@
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_dom_StyleSheetList_h
 #define mozilla_dom_StyleSheetList_h
 
+#include "mozilla/dom/StyleScope.h"
 #include "nsIDOMStyleSheetList.h"
 #include "nsWrapperCache.h"
+#include "nsStubDocumentObserver.h"
 
 class nsINode;
 
 namespace mozilla {
 class StyleSheet;
 
 namespace dom {
 
-class StyleSheetList : public nsIDOMStyleSheetList
-                     , public nsWrapperCache
+class StyleSheetList final : public nsIDOMStyleSheetList
+                           , public nsWrapperCache
+                           , public nsStubDocumentObserver
 {
 public:
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
-  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(StyleSheetList)
+  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_AMBIGUOUS(StyleSheetList, nsIDOMStyleSheetList)
+
   NS_DECL_NSIDOMSTYLESHEETLIST
 
+  NS_DECL_NSIMUTATIONOBSERVER_NODEWILLBEDESTROYED
+
+  explicit StyleSheetList(StyleScope& aScope);
+
   virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override final;
 
-  virtual nsINode* GetParentObject() const = 0;
+  nsINode* GetParentObject() const
+  {
+    return mStyleScope ? &mStyleScope->AsNode() : nullptr;
+  }
+
+  uint32_t Length() const
+  {
+    return mStyleScope ? mStyleScope->SheetCount() : 0;
+  }
 
-  virtual uint32_t Length() = 0;
-  virtual StyleSheet* IndexedGetter(uint32_t aIndex, bool& aFound) = 0;
-  StyleSheet* Item(uint32_t aIndex)
+  StyleSheet* IndexedGetter(uint32_t aIndex, bool& aFound) const
+  {
+    if (!mStyleScope) {
+      aFound = false;
+      return nullptr;
+    }
+
+    StyleSheet* sheet = mStyleScope->SheetAt(aIndex);
+    aFound = !!sheet;
+    return sheet;
+  }
+
+  StyleSheet* Item(uint32_t aIndex) const
   {
     bool dummy = false;
     return IndexedGetter(aIndex, dummy);
   }
 
 protected:
-  virtual ~StyleSheetList() {}
+  virtual ~StyleSheetList();
+
+  StyleScope* mStyleScope; // Weak, cleared on "NodeWillBeDestroyed".
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_StyleSheetList_h
--- a/dom/base/moz.build
+++ b/dom/base/moz.build
@@ -202,16 +202,17 @@ EXPORTS.mozilla.dom += [
     'ResponsiveImageSelector.h',
     'SameProcessMessageQueue.h',
     'ScreenOrientation.h',
     'Selection.h',
     'ShadowRoot.h',
     'StructuredCloneBlob.h',
     'StructuredCloneHolder.h',
     'StructuredCloneTags.h',
+    'StyleScope.h',
     'StyleSheetList.h',
     'SubtleCrypto.h',
     'TabGroup.h',
     'Text.h',
     'Timeout.h',
     'TimeoutHandler.h',
     'TimeoutManager.h',
     'TreeWalker.h',
@@ -345,16 +346,17 @@ UNIFIED_SOURCES += [
     'ResponsiveImageSelector.cpp',
     'SameProcessMessageQueue.cpp',
     'ScreenOrientation.cpp',
     'Selection.cpp',
     'SelectionChangeListener.cpp',
     'ShadowRoot.cpp',
     'StructuredCloneBlob.cpp',
     'StructuredCloneHolder.cpp',
+    'StyleScope.cpp',
     'StyleSheetList.cpp',
     'SubtleCrypto.cpp',
     'TabGroup.cpp',
     'Text.cpp',
     'TextInputProcessor.cpp',
     'ThirdPartyUtil.cpp',
     'Timeout.cpp',
     'TimeoutBudgetManager.cpp',
--- a/dom/base/nsDocument.cpp
+++ b/dom/base/nsDocument.cpp
@@ -727,88 +727,16 @@ struct nsRadioGroupStruct
    * A strong pointer to the currently selected radio button.
    */
   RefPtr<HTMLInputElement> mSelectedRadioButton;
   nsCOMArray<nsIFormControl> mRadioButtons;
   uint32_t mRequiredRadioCount;
   bool mGroupSuffersFromValueMissing;
 };
 
-
-nsDOMStyleSheetList::nsDOMStyleSheetList(nsIDocument *aDocument)
-{
-  mLength = -1;
-  // Not reference counted to avoid circular references.
-  // The document will tell us when its going away.
-  mDocument = aDocument;
-  mDocument->AddObserver(this);
-}
-
-nsDOMStyleSheetList::~nsDOMStyleSheetList()
-{
-  if (mDocument) {
-    mDocument->RemoveObserver(this);
-  }
-}
-
-NS_IMPL_ISUPPORTS_INHERITED(nsDOMStyleSheetList, StyleSheetList,
-                            nsIDocumentObserver,
-                            nsIMutationObserver)
-
-uint32_t
-nsDOMStyleSheetList::Length()
-{
-  if (!mDocument) {
-    return 0;
-  }
-
-  // XXX Find the number and then cache it. We'll use the
-  // observer notification to figure out if new ones have
-  // been added or removed.
-  if (-1 == mLength) {
-    mLength = mDocument->GetNumberOfStyleSheets();
-  }
-  return mLength;
-}
-
-StyleSheet*
-nsDOMStyleSheetList::IndexedGetter(uint32_t aIndex, bool& aFound)
-{
-  if (!mDocument || aIndex >= (uint32_t)mDocument->GetNumberOfStyleSheets()) {
-    aFound = false;
-    return nullptr;
-  }
-  aFound = true;
-  return mDocument->GetStyleSheetAt(aIndex);
-}
-
-void
-nsDOMStyleSheetList::NodeWillBeDestroyed(const nsINode *aNode)
-{
-  mDocument = nullptr;
-}
-
-void
-nsDOMStyleSheetList::StyleSheetAdded(StyleSheet* aStyleSheet,
-                                     bool aDocumentSheet)
-{
-  if (aDocumentSheet && -1 != mLength) {
-    mLength++;
-  }
-}
-
-void
-nsDOMStyleSheetList::StyleSheetRemoved(StyleSheet* aStyleSheet,
-                                       bool aDocumentSheet)
-{
-  if (aDocumentSheet && -1 != mLength) {
-    mLength--;
-  }
-}
-
 // nsOnloadBlocker implementation
 NS_IMPL_ISUPPORTS(nsOnloadBlocker, nsIRequest)
 
 NS_IMETHODIMP
 nsOnloadBlocker::GetName(nsACString &aResult)
 {
   aResult.AssignLiteral("about:document-onload-blocker");
   return NS_OK;
@@ -1355,20 +1283,20 @@ nsDOMStyleSheetSetList::EnsureFresh()
 
   mNames.Clear();
 
   if (!mDocument) {
     return; // Spec says "no exceptions", and we have no style sets if we have
             // no document, for sure
   }
 
-  int32_t count = mDocument->GetNumberOfStyleSheets();
+  size_t count = mDocument->SheetCount();
   nsAutoString title;
-  for (int32_t index = 0; index < count; index++) {
-    StyleSheet* sheet = mDocument->GetStyleSheetAt(index);
+  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;
     }
   }
 }
 
@@ -4579,34 +4507,16 @@ nsDocument::AddOnDemandBuiltInUASheet(St
       // nsDocumentViewer::CreateStyleSet though?
       shell->StyleSet()->PrependStyleSheet(SheetType::Agent, aSheet);
     }
   }
 
   NotifyStyleSheetAdded(aSheet, false);
 }
 
-int32_t
-nsDocument::GetNumberOfStyleSheets() const
-{
-  return mStyleSheets.Length();
-}
-
-StyleSheet*
-nsDocument::GetStyleSheetAt(int32_t aIndex) const
-{
-  return mStyleSheets.SafeElementAt(aIndex, nullptr);
-}
-
-int32_t
-nsDocument::GetIndexOfStyleSheet(const StyleSheet* aSheet) const
-{
-  return mStyleSheets.IndexOf(aSheet);
-}
-
 void
 nsDocument::AddStyleSheetToStyleSets(StyleSheet* aSheet)
 {
   MOZ_DIAGNOSTIC_ASSERT(aSheet->IsServo() == IsStyledByServo());
   nsCOMPtr<nsIPresShell> shell = GetShell();
   if (shell) {
     shell->StyleSet()->AddDocStyleSheet(aSheet, this);
   }
@@ -4736,21 +4646,23 @@ nsDocument::UpdateStyleSheets(nsTArray<R
       NotifyStyleSheetAdded(newSheet, true);
     }
   }
 
   EndUpdate(UPDATE_STYLE);
 }
 
 void
-nsDocument::InsertStyleSheetAt(StyleSheet* aSheet, int32_t aIndex)
-{
-  NS_PRECONDITION(aSheet, "null ptr");
-
+nsDocument::InsertStyleSheetAt(StyleSheet* aSheet, size_t aIndex)
+{
+  MOZ_ASSERT(aSheet);
   MOZ_DIAGNOSTIC_ASSERT(aSheet->IsServo() == IsStyledByServo());
+
+  // FIXME(emilio): Stop touching StyleScope's members directly, and use an
+  // accessor.
   mStyleSheets.InsertElementAt(aIndex, aSheet);
 
   aSheet->SetAssociatedDocument(this, StyleSheet::OwnedByDocument);
 
   if (aSheet->IsApplicable()) {
     AddStyleSheetToStyleSets(aSheet);
   }
 
@@ -6451,42 +6363,33 @@ nsDocument::GetElementsByTagNameNS(const
 
 NS_IMETHODIMP
 nsDocument::GetStyleSheets(nsIDOMStyleSheetList** aStyleSheets)
 {
   NS_ADDREF(*aStyleSheets = StyleSheets());
   return NS_OK;
 }
 
-StyleSheetList*
-nsDocument::StyleSheets()
-{
-  if (!mDOMStyleSheets) {
-    mDOMStyleSheets = new nsDOMStyleSheetList(this);
-  }
-  return mDOMStyleSheets;
-}
-
 NS_IMETHODIMP
 nsDocument::GetMozSelectedStyleSheetSet(nsAString& aSheetSet)
 {
   nsIDocument::GetSelectedStyleSheetSet(aSheetSet);
   return NS_OK;
 }
 
 void
 nsIDocument::GetSelectedStyleSheetSet(nsAString& aSheetSet)
 {
   aSheetSet.Truncate();
 
   // Look through our sheets, find the selected set title
-  int32_t count = GetNumberOfStyleSheets();
+  size_t count = SheetCount();
   nsAutoString title;
-  for (int32_t index = 0; index < count; index++) {
-    StyleSheet* sheet = GetStyleSheetAt(index);
+  for (size_t index = 0; index < count; index++) {
+    StyleSheet* sheet = SheetAt(index);
     NS_ASSERTION(sheet, "Null sheet in sheet list!");
 
     if (sheet->Disabled()) {
       // Disabled sheets don't affect the currently selected set
       continue;
     }
 
     sheet->GetTitle(title);
@@ -6585,20 +6488,20 @@ nsDocument::EnableStyleSheetsForSet(cons
   }
 }
 
 void
 nsDocument::EnableStyleSheetsForSetInternal(const nsAString& aSheetSet,
                                             bool aUpdateCSSLoader)
 {
   BeginUpdate(UPDATE_STYLE);
-  int32_t count = GetNumberOfStyleSheets();
+  size_t count = SheetCount();
   nsAutoString title;
-  for (int32_t index = 0; index < count; index++) {
-    StyleSheet* sheet = GetStyleSheetAt(index);
+  for (size_t index = 0; index < count; index++) {
+    StyleSheet* sheet = SheetAt(index);
     NS_ASSERTION(sheet, "Null sheet in sheet list!");
 
     sheet->GetTitle(title);
     if (!title.IsEmpty()) {
       sheet->SetEnabled(title.Equals(aSheetSet));
     }
   }
   if (aUpdateCSSLoader) {
@@ -10280,19 +10183,19 @@ nsIDocument::CreateStaticClone(nsIDocShe
         clonedDoc->mOriginalDocument = mOriginalDocument;
       } else {
         clonedDoc->mOriginalDocument = this;
       }
 
       clonedDoc->mOriginalDocument->mStaticCloneCount++;
 
       MOZ_ASSERT(GetStyleBackendType() == clonedDoc->GetStyleBackendType());
-      int32_t sheetsCount = GetNumberOfStyleSheets();
-      for (int32_t i = 0; i < sheetsCount; ++i) {
-        RefPtr<StyleSheet> sheet = GetStyleSheetAt(i);
+      size_t sheetsCount = SheetCount();
+      for (size_t i = 0; i < sheetsCount; ++i) {
+        RefPtr<StyleSheet> sheet = SheetAt(i);
         if (sheet) {
           if (sheet->IsApplicable()) {
             RefPtr<StyleSheet> clonedSheet =
               sheet->Clone(nullptr, nullptr, clonedDoc, nullptr);
             NS_WARNING_ASSERTION(clonedSheet,
                                  "Cloning a stylesheet didn't work!");
             if (clonedSheet) {
               clonedDoc->AddStyleSheet(clonedSheet);
--- a/dom/base/nsDocument.h
+++ b/dom/base/nsDocument.h
@@ -144,46 +144,16 @@ public:
     delete mNext;
   }
 
   RefPtr<nsAtom> mField;
   nsString          mData;
   nsDocHeaderData*  mNext;
 };
 
-class nsDOMStyleSheetList : public mozilla::dom::StyleSheetList,
-                            public nsStubDocumentObserver
-{
-public:
-  explicit nsDOMStyleSheetList(nsIDocument* aDocument);
-
-  NS_DECL_ISUPPORTS_INHERITED
-
-  // nsIDocumentObserver
-  NS_DECL_NSIDOCUMENTOBSERVER_STYLESHEETADDED
-  NS_DECL_NSIDOCUMENTOBSERVER_STYLESHEETREMOVED
-
-  // nsIMutationObserver
-  NS_DECL_NSIMUTATIONOBSERVER_NODEWILLBEDESTROYED
-
-  virtual nsINode* GetParentObject() const override
-  {
-    return mDocument;
-  }
-
-  uint32_t Length() override;
-  mozilla::StyleSheet* IndexedGetter(uint32_t aIndex, bool& aFound) override;
-
-protected:
-  virtual ~nsDOMStyleSheetList();
-
-  int32_t       mLength;
-  nsIDocument*  mDocument;
-};
-
 class nsOnloadBlocker final : public nsIRequest
 {
 public:
   nsOnloadBlocker() {}
 
   NS_DECL_ISUPPORTS
   NS_DECL_NSIREQUEST
 
@@ -473,35 +443,27 @@ public:
   virtual nsresult SetSubDocumentFor(Element* aContent,
                                      nsIDocument* aSubDoc) override;
   virtual nsIDocument* GetSubDocumentFor(nsIContent* aContent) const override;
   virtual Element* FindContentForSubDocument(nsIDocument *aDocument) const override;
   virtual Element* GetRootElementInternal() const override;
 
   virtual void EnsureOnDemandBuiltInUASheet(mozilla::StyleSheet* aSheet) override;
 
-  /**
-   * Get the (document) style sheets owned by this document.
-   * These are ordered, highest priority last
-   */
-  virtual int32_t GetNumberOfStyleSheets() const override;
-  virtual mozilla::StyleSheet* GetStyleSheetAt(int32_t aIndex) const override;
-  virtual int32_t GetIndexOfStyleSheet(
-      const mozilla::StyleSheet* aSheet) const override;
   virtual void AddStyleSheet(mozilla::StyleSheet* aSheet) override;
   virtual void RemoveStyleSheet(mozilla::StyleSheet* aSheet) override;
 
   virtual void UpdateStyleSheets(
       nsTArray<RefPtr<mozilla::StyleSheet>>& aOldSheets,
       nsTArray<RefPtr<mozilla::StyleSheet>>& aNewSheets) override;
   virtual void AddStyleSheetToStyleSets(mozilla::StyleSheet* aSheet);
   virtual void RemoveStyleSheetFromStyleSets(mozilla::StyleSheet* aSheet);
 
   virtual void InsertStyleSheetAt(mozilla::StyleSheet* aSheet,
-                                  int32_t aIndex) override;
+                                  size_t aIndex) override;
   virtual void SetStyleSheetApplicableState(mozilla::StyleSheet* aSheet,
                                             bool aApplicable) override;
 
   virtual nsresult LoadAdditionalStyleSheet(additionalSheetType aType,
                                             nsIURI* aSheetURI) override;
   virtual nsresult AddAdditionalStyleSheet(additionalSheetType aType,
                                            mozilla::StyleSheet* aSheet) override;
   virtual void RemoveAdditionalStyleSheet(additionalSheetType aType,
@@ -983,17 +945,17 @@ public:
   virtual void DocAddSizeOfExcludingThis(nsWindowSizes& aWindowSizes) const override;
   // DocAddSizeOfIncludingThis is inherited from nsIDocument.
 
   virtual nsIDOMNode* AsDOMNode() override { return this; }
 
   // WebIDL bits
   virtual mozilla::dom::DOMImplementation*
     GetImplementation(mozilla::ErrorResult& rv) override;
-  virtual mozilla::dom::StyleSheetList* StyleSheets() override;
+
   virtual void SetSelectedStyleSheetSet(const nsAString& aSheetSet) override;
   virtual void GetLastStyleSheetSet(nsString& aSheetSet) override;
   virtual mozilla::dom::DOMStringList* StyleSheetSets() override;
   virtual void EnableStyleSheetsForSet(const nsAString& aSheetSet) override;
   virtual already_AddRefed<Element> CreateElement(const nsAString& aTagName,
                                                   const mozilla::dom::ElementCreationOptionsOrString& aOptions,
                                                   ErrorResult& rv) override;
   virtual already_AddRefed<Element> CreateElementNS(const nsAString& aNamespaceURI,
@@ -1137,17 +1099,16 @@ protected:
   // parsed into.
   nsCOMPtr<nsIParser> mParser;
 
   // Weak reference to our sink for in case we no longer have a parser.  This
   // will allow us to flush out any pending stuff from the sink even if
   // EndLoad() has already happened.
   nsWeakPtr mWeakSink;
 
-  nsTArray<RefPtr<mozilla::StyleSheet>> mStyleSheets;
   nsTArray<RefPtr<mozilla::StyleSheet>> mOnDemandBuiltInUASheets;
   nsTArray<RefPtr<mozilla::StyleSheet>> mAdditionalSheets[AdditionalSheetTypeCount];
 
   // Array of observers
   nsTObserverArray<nsIDocumentObserver*> mObservers;
 
   // Array of intersection observers
   nsTHashtable<nsPtrHashKey<mozilla::dom::DOMIntersectionObserver>>
@@ -1174,17 +1135,16 @@ protected:
   RefPtr<PrincipalFlashClassifier> mPrincipalFlashClassifier;
   mozilla::dom::FlashClassification mFlashClassification;
   // Do not use this value directly. Call the |IsThirdParty()| method, which
   // caches its result here.
   mozilla::Maybe<bool> mIsThirdParty;
 
 public:
   RefPtr<mozilla::EventListenerManager> mListenerManager;
-  RefPtr<mozilla::dom::StyleSheetList> mDOMStyleSheets;
   RefPtr<nsDOMStyleSheetSetList> mStyleSheetSetList;
   RefPtr<mozilla::dom::ScriptLoader> mScriptLoader;
   nsDocHeaderData* mHeaderData;
   /* mIdentifierMap works as follows for IDs:
    * 1) Attribute changes affect the table immediately (removing and adding
    *    entries as needed).
    * 2) Removals from the DOM affect the table immediately
    * 3) Additions to the DOM always update existing entries for names, and add
--- a/dom/base/nsIDocument.h
+++ b/dom/base/nsIDocument.h
@@ -29,16 +29,17 @@
 #include "mozilla/UseCounter.h"
 #include "mozilla/WeakPtr.h"
 #include "Units.h"
 #include "nsContentListDeclarations.h"
 #include "nsExpirationTracker.h"
 #include "nsClassHashtable.h"
 #include "mozilla/CORSMode.h"
 #include "mozilla/dom/DispatcherTrait.h"
+#include "mozilla/dom/StyleScope.h"
 #include "mozilla/LinkedList.h"
 #include "mozilla/NotNull.h"
 #include "mozilla/SegmentedVector.h"
 #include "mozilla/ServoBindingTypes.h"
 #include "mozilla/StyleBackendType.h"
 #include "mozilla/StyleSheet.h"
 #include "mozilla/TimeStamp.h"
 #include "mozilla/UniquePtr.h"
@@ -207,16 +208,17 @@ enum class HSTSPrimingState {
 // Some function forward-declarations
 class nsContentList;
 
 //----------------------------------------------------------------------
 
 // Document interface.  This is implemented by all document objects in
 // Gecko.
 class nsIDocument : public nsINode,
+                    public mozilla::dom::StyleScope,
                     public mozilla::dom::DispatcherTrait
 {
   typedef mozilla::dom::GlobalObject GlobalObject;
 
 protected:
   using Encoding = mozilla::Encoding;
   template <typename T> using NotNull = mozilla::NotNull<T>;
 
@@ -1317,50 +1319,35 @@ public:
    * supplied by add-ons or by the app (Firefox OS or Firefox Mobile, for
    * example), since their sheets should override built-in sheets.
    *
    * TODO We can get rid of the whole concept of delayed loading if we fix
    * bug 77999.
    */
   virtual void EnsureOnDemandBuiltInUASheet(mozilla::StyleSheet* aSheet) = 0;
 
-  /**
-   * Get the number of (document) stylesheets
-   *
-   * @return the number of stylesheets
-   * @throws no exceptions
-   */
-  virtual int32_t GetNumberOfStyleSheets() const = 0;
-
-  /**
-   * Get a particular stylesheet
-   * @param aIndex the index the stylesheet lives at.  This is zero-based
-   * @return the stylesheet at aIndex.  Null if aIndex is out of range.
-   * @throws no exceptions
-   */
-  virtual mozilla::StyleSheet* GetStyleSheetAt(int32_t aIndex) const = 0;
+  nsINode& AsNode() final
+  {
+    return *this;
+  }
+
+  mozilla::dom::StyleSheetList* StyleSheets()
+  {
+    return &StyleScope::EnsureDOMStyleSheets();
+  }
 
   /**
    * Insert a sheet at a particular spot in the stylesheet list (zero-based)
    * @param aSheet the sheet to insert
-   * @param aIndex the index to insert at.  This index will be
-   *   adjusted for the "special" sheets.
+   * @param aIndex the index to insert at.
    * @throws no exceptions
    */
   virtual void InsertStyleSheetAt(mozilla::StyleSheet* aSheet,
-                                  int32_t aIndex) = 0;
-
-  /**
-   * Get the index of a particular stylesheet.  This will _always_
-   * consider the "special" sheets as part of the sheet list.
-   * @param aSheet the sheet to get the index of
-   * @return aIndex the index of the sheet in the full list
-   */
-  virtual int32_t GetIndexOfStyleSheet(
-      const mozilla::StyleSheet* aSheet) const = 0;
+                                  size_t aIndex) = 0;
+
 
   /**
    * Replace the stylesheets in aOldSheets with the stylesheets in
    * aNewSheets. The two lists must have equal length, and the sheet
    * at positon J in the first list will be replaced by the sheet at
    * position J in the second list.  Some sheets in the second list
    * may be null; if so the corresponding sheets in the first list
    * will simply be removed.
@@ -1407,17 +1394,17 @@ public:
    * be inserted at to maintain document ordering.
    *
    * Type T has to cast to StyleSheet*.
    *
    * Defined in nsIDocumentInlines.h.
    */
   template<typename T>
   size_t FindDocStyleSheetInsertionPoint(const nsTArray<T>& aDocSheets,
-                                         mozilla::StyleSheet* aSheet);
+                                         const mozilla::StyleSheet& aSheet);
 
   /**
    * Get this document's CSSLoader.  This is guaranteed to not return null.
    */
   mozilla::css::Loader* CSSLoader() const {
     return mCSSLoader;
   }
 
@@ -2979,17 +2966,16 @@ public:
   {
     return mVisibilityState != mozilla::dom::VisibilityState::Visible;
   }
   mozilla::dom::VisibilityState VisibilityState() const
   {
     return mVisibilityState;
   }
 #endif
-  virtual mozilla::dom::StyleSheetList* StyleSheets() = 0;
   void GetSelectedStyleSheetSet(nsAString& aSheetSet);
   virtual void SetSelectedStyleSheetSet(const nsAString& aSheetSet) = 0;
   virtual void GetLastStyleSheetSet(nsString& aSheetSet) = 0;
   void GetPreferredStyleSheetSet(nsAString& aSheetSet);
   virtual mozilla::dom::DOMStringList* StyleSheetSets() = 0;
   virtual void EnableStyleSheetsForSet(const nsAString& aSheetSet) = 0;
   Element* ElementFromPoint(float aX, float aY);
   void ElementsFromPoint(float aX,
--- a/dom/base/nsIDocumentInlines.h
+++ b/dom/base/nsIDocumentInlines.h
@@ -16,29 +16,29 @@ nsIDocument::GetBodyElement()
 {
   return static_cast<mozilla::dom::HTMLBodyElement*>(GetHtmlChildElement(nsGkAtoms::body));
 }
 
 template<typename T>
 size_t
 nsIDocument::FindDocStyleSheetInsertionPoint(
     const nsTArray<T>& aDocSheets,
-    mozilla::StyleSheet* aSheet)
+    const mozilla::StyleSheet& aSheet)
 {
   nsStyleSheetService* sheetService = nsStyleSheetService::GetInstance();
 
   // lowest index first
-  int32_t newDocIndex = GetIndexOfStyleSheet(aSheet);
+  int32_t newDocIndex = IndexOfSheet(aSheet);
 
-  int32_t count = aDocSheets.Length();
-  int32_t index;
-  for (index = 0; index < count; index++) {
-    mozilla::StyleSheet* sheet = static_cast<mozilla::StyleSheet*>(
-      aDocSheets[index]);
-    int32_t sheetDocIndex = GetIndexOfStyleSheet(sheet);
+  size_t count = aDocSheets.Length();
+  size_t index = 0;
+  for (; index < count; index++) {
+    auto* sheet = static_cast<mozilla::StyleSheet*>(aDocSheets[index]);
+    MOZ_ASSERT(sheet);
+    int32_t sheetDocIndex = IndexOfSheet(*sheet);
     if (sheetDocIndex > newDocIndex)
       break;
 
     // If the sheet is not owned by the document it can be an author
     // sheet registered at nsStyleSheetService or an additional author
     // sheet on the document, which means the new
     // doc sheet should end up before it.
     if (sheetDocIndex < 0) {
--- a/layout/inspector/inDOMUtils.cpp
+++ b/layout/inspector/inDOMUtils.cpp
@@ -108,18 +108,18 @@ inDOMUtils::GetAllStyleSheets(nsIDOMDocu
       if (!sheetSet.Contains(sheet)) {
         sheetSet.PutEntry(sheet);
         sheets.AppendElement(sheet);
       }
     }
   }
 
   // Get the document sheets.
-  for (int32_t i = 0; i < document->GetNumberOfStyleSheets(); i++) {
-    sheets.AppendElement(document->GetStyleSheetAt(i));
+  for (size_t i = 0; i < document->SheetCount(); i++) {
+    sheets.AppendElement(document->SheetAt(i));
   }
 
   nsISupports** ret = static_cast<nsISupports**>(moz_xmalloc(sheets.Length() *
                                                  sizeof(nsISupports*)));
 
   for (size_t i = 0; i < sheets.Length(); i++) {
     NS_ADDREF(ret[i] = NS_ISUPPORTS_CAST(nsIDOMCSSStyleSheet*, sheets[i]));
   }
--- a/layout/style/Loader.cpp
+++ b/layout/style/Loader.cpp
@@ -1185,29 +1185,29 @@ Loader::InsertSheetInDoc(StyleSheet* aSh
                          nsIDocument* aDocument)
 {
   LOG(("css::Loader::InsertSheetInDoc"));
   NS_PRECONDITION(aSheet, "Nothing to insert");
   NS_PRECONDITION(aDocument, "Must have a document to insert into");
 
   // XXX Need to cancel pending sheet loads for this element, if any
 
-  int32_t sheetCount = aDocument->GetNumberOfStyleSheets();
+  int32_t sheetCount = aDocument->SheetCount();
 
   /*
    * Start the walk at the _end_ of the list, since in the typical
    * case we'll just want to append anyway.  We want to break out of
    * the loop when insertionPoint points to just before the index we
    * want to insert at.  In other words, when we leave the loop
    * insertionPoint is the index of the stylesheet that immediately
    * precedes the one we're inserting.
    */
   int32_t insertionPoint;
   for (insertionPoint = sheetCount - 1; insertionPoint >= 0; --insertionPoint) {
-    StyleSheet* curSheet = aDocument->GetStyleSheetAt(insertionPoint);
+    StyleSheet* curSheet = aDocument->SheetAt(insertionPoint);
     NS_ASSERTION(curSheet, "There must be a sheet here!");
     nsCOMPtr<nsINode> sheetOwner = curSheet->GetOwnerNode();
     if (sheetOwner && !aLinkingContent) {
       // Keep moving; all sheets with a sheetOwner come after all
       // sheets without a linkingNode
       continue;
     }
 
--- a/layout/style/ServoStyleSet.cpp
+++ b/layout/style/ServoStyleSet.cpp
@@ -832,17 +832,17 @@ ServoStyleSet::AddDocStyleSheet(ServoSty
   MOZ_ASSERT(aSheet->IsApplicable());
   MOZ_ASSERT(aSheet->RawContents(), "Raw sheet should be in place by this point.");
 
   RefPtr<StyleSheet> strong(aSheet);
 
   RemoveSheetOfType(SheetType::Doc, aSheet);
 
   size_t index =
-    aDocument->FindDocStyleSheetInsertionPoint(mSheets[SheetType::Doc], aSheet);
+    aDocument->FindDocStyleSheetInsertionPoint(mSheets[SheetType::Doc], *aSheet);
 
   if (index < mSheets[SheetType::Doc].Length()) {
     // This case is insert before.
     ServoStyleSheet *beforeSheet = mSheets[SheetType::Doc][index];
     InsertSheetOfType(SheetType::Doc, aSheet, beforeSheet);
 
     if (mRawSet) {
       // Maintain a mirrored list of sheets on the servo side.
--- a/layout/style/nsStyleSet.cpp
+++ b/layout/style/nsStyleSet.cpp
@@ -721,17 +721,17 @@ nsStyleSet::AddDocStyleSheet(CSSStyleShe
 
   SheetType type = aSheet->GetScopeElement() ?
                      SheetType::ScopedDoc :
                      SheetType::Doc;
   nsTArray<RefPtr<CSSStyleSheet>>& sheets = mSheets[type];
 
   bool present = sheets.RemoveElement(aSheet);
 
-  size_t index = aDocument->FindDocStyleSheetInsertionPoint(sheets, aSheet);
+  size_t index = aDocument->FindDocStyleSheetInsertionPoint(sheets, *aSheet);
   sheets.InsertElementAt(index, aSheet);
 
   if (!present) {
     aSheet->AddStyleSet(StyleSetHandle(this));
   }
 
   return DirtyRuleProcessors(type);
 }