Bug 1535788 - Make the Document own the StyleSet. r=heycam
authorEmilio Cobos Álvarez <emilio@crisal.io>
Wed, 03 Apr 2019 07:02:00 +0000
changeset 467757 60c20a0f320cc769a8da229cdf6edfbbf38d3ed3
parent 467756 d71df181f3d948fa113de06223649f5e6298b47b
child 467758 8f1ab2cf557e21edbd9a16692d965165eb752d4a
push id112658
push useraciure@mozilla.com
push dateThu, 04 Apr 2019 04:41:45 +0000
treeherdermozilla-inbound@a36718c8163e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersheycam
bugs1535788
milestone68.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 1535788 - Make the Document own the StyleSet. r=heycam This is the last step to be able to call matchMedia on display: none iframes. This is green, except for some startup preference query tests that I'm going to address in a blocking bug (making LangGroupFontPrefs global, basically). The setup is similar to the ShadowRoot one, except we don't eagerly keep the StyleSet around up-to-date, we only fill it if it ever had a pres context. Differential Revision: https://phabricator.services.mozilla.com/D23903
dom/base/Document.cpp
dom/base/Document.h
dom/base/DocumentOrShadowRoot.cpp
dom/base/ShadowRoot.cpp
dom/canvas/CanvasRenderingContext2D.cpp
dom/html/nsHTMLDocument.cpp
editor/libeditor/HTMLAnonymousNodeEditor.cpp
layout/base/PresShell.cpp
layout/base/PresShell.h
layout/base/nsDocumentViewer.cpp
layout/base/nsIDocumentViewerPrint.h
layout/base/nsIPresShell.h
layout/base/nsIPresShellInlines.h
layout/base/nsPresContext.cpp
layout/base/nsPresContext.h
layout/base/nsPresContextInlines.h
layout/base/nsStyleSheetService.cpp
layout/inspector/InspectorUtils.cpp
layout/printing/nsPrintJob.cpp
layout/style/Loader.cpp
layout/style/MediaFeatureChange.h
layout/style/ServoStyleSet.cpp
layout/style/ServoStyleSet.h
servo/ports/geckolib/glue.rs
--- a/dom/base/Document.cpp
+++ b/dom/base/Document.cpp
@@ -40,16 +40,17 @@
 #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 "nsLayoutStylesheetCache.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"
@@ -1215,16 +1216,17 @@ Document::Document(const char* aContentT
       mAllowPaymentRequest(false),
       mEncodingMenuDisabled(false),
       mIsSVGGlyphsDocument(false),
       mInDestructor(false),
       mIsGoingAway(false),
       mInXBLUpdate(false),
       mNeedsReleaseAfterStackRefCntRelease(false),
       mStyleSetFilled(false),
+      mQuirkSheetAdded(false),
       mSSApplicableStateNotificationPending(false),
       mMayHaveTitleElement(false),
       mDOMLoadingSet(false),
       mDOMInteractiveSet(false),
       mDOMCompleteSet(false),
       mAutoFocusFired(false),
       mScrolledToRefAlready(false),
       mChangeScrollPosWhenScrollingToRef(false),
@@ -1644,34 +1646,29 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_
 
   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) {
@@ -1703,17 +1700,16 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mAnchors);
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mAnonymousContents)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCommandDispatcher)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFeaturePolicy)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSuppressedEventListener)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPrototypeDocument)
 
   // 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
@@ -1809,18 +1805,16 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(Do
   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;
 
@@ -1830,17 +1824,16 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(Do
                      "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();
 
@@ -1908,16 +1901,18 @@ nsresult Document::Init() {
 
   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());
 
+  mStyleSet = MakeUnique<ServoStyleSet>(*this);
+
   mozilla::HoldJSObjects(this);
 
   return NS_OK;
 }
 
 void Document::DeleteAllProperties() { PropertyTable().DeleteAllProperties(); }
 
 void Document::DeleteAllPropertiesFor(nsINode* aNode) {
@@ -2200,41 +2195,34 @@ already_AddRefed<nsIPrincipal> Document:
       }
     }
   }
   nsCOMPtr<nsIPrincipal> principal(aPrincipal);
   return principal.forget();
 }
 
 void Document::RemoveDocStyleSheetsFromStyleSets() {
+  MOZ_ASSERT(mStyleSetFilled);
   // The stylesheets should forget us
   for (StyleSheet* sheet : Reversed(mStyleSheets)) {
     sheet->ClearAssociatedDocumentOrShadowRoot();
-
     if (sheet->IsApplicable()) {
-      RefPtr<PresShell> presShell = GetPresShell();
-      if (presShell) {
-        presShell->StyleSet()->RemoveDocStyleSheet(sheet);
-      }
+      mStyleSet->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()) {
-      RefPtr<PresShell> presShell = GetPresShell();
-      if (presShell) {
-        presShell->StyleSet()->RemoveStyleSheet(aType, sheet);
-      }
+    if (mStyleSetFilled && sheet->IsApplicable()) {
+      mStyleSet->RemoveStyleSheet(aType, sheet);
     }
     // XXX Tell observers?
   }
 }
 
 void Document::ResetStylesheetsToURI(nsIURI* aURI) {
   MOZ_ASSERT(aURI);
 
@@ -2250,18 +2238,16 @@ void Document::ResetStylesheetsToURI(nsI
     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();
   }
 
@@ -2276,61 +2262,155 @@ void Document::ResetStylesheetsToURI(nsI
   } else {
     mAttrStyleSheet = new nsHTMLStyleSheet(this);
   }
 
   if (!mStyleAttrStyleSheet) {
     mStyleAttrStyleSheet = new nsHTMLCSSStyleSheet();
   }
 
-  // Now set up our style sets
-  if (PresShell* presShell = GetPresShell()) {
-    FillStyleSet(presShell->StyleSet());
-    if (presShell->StyleSet()->StyleSheetsHaveChanged()) {
-      presShell->ApplicableStylesChanged();
+  if (mStyleSetFilled) {
+    FillStyleSetDocumentSheets();
+
+    if (mStyleSet->StyleSheetsHaveChanged()) {
+      if (PresShell* presShell = GetPresShell()) {
+        presShell->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,
+void Document::FillStyleSetUserAndUASheets() {
+  // Make sure this does the same thing as PresShell::Add{User,Agent}Sheet wrt
+  // ordering.
+
+  // The document will fill in the document sheets when we create the presshell
+  auto cache = nsLayoutStylesheetCache::Singleton();
+
+  nsStyleSheetService* sheetService = nsStyleSheetService::GetInstance();
+  MOZ_ASSERT(sheetService,
+             "should never be creating a StyleSet after the style sheet "
+             "service has gone");
+
+  for (StyleSheet* sheet : *sheetService->UserStyleSheets()) {
+    mStyleSet->AppendStyleSheet(SheetType::User, sheet);
+  }
+
+  StyleSheet* sheet = IsInChromeDocShell() ? cache->GetUserChromeSheet()
+                                           : cache->GetUserContentSheet();
+  if (sheet) {
+    mStyleSet->AppendStyleSheet(SheetType::User, sheet);
+  }
+
+  mStyleSet->AppendStyleSheet(SheetType::Agent, cache->UASheet());
+
+  if (MOZ_LIKELY(NodeInfoManager()->MathMLEnabled())) {
+    mStyleSet->AppendStyleSheet(SheetType::Agent, cache->MathMLSheet());
+  }
+
+  if (MOZ_LIKELY(NodeInfoManager()->SVGEnabled())) {
+    mStyleSet->AppendStyleSheet(SheetType::Agent, cache->SVGSheet());
+  }
+
+  mStyleSet->AppendStyleSheet(SheetType::Agent, cache->HTMLSheet());
+
+  if (nsLayoutUtils::ShouldUseNoFramesSheet(this)) {
+    mStyleSet->AppendStyleSheet(SheetType::Agent, cache->NoFramesSheet());
+  }
+
+  if (nsLayoutUtils::ShouldUseNoScriptSheet(this)) {
+    mStyleSet->AppendStyleSheet(SheetType::Agent, cache->NoScriptSheet());
+  }
+
+  mStyleSet->AppendStyleSheet(SheetType::Agent, cache->CounterStylesSheet());
+
+  // Load the minimal XUL rules for scrollbars and a few other XUL things
+  // that non-XUL (typically HTML) documents commonly use.
+  mStyleSet->AppendStyleSheet(SheetType::Agent, cache->MinimalXULSheet());
+
+  // Only load the full XUL sheet if we'll need it.
+  if (LoadsFullXULStyleSheetUpFront()) {
+    mStyleSet->AppendStyleSheet(SheetType::Agent, cache->XULSheet());
+  }
+
+  MOZ_ASSERT(!mQuirkSheetAdded);
+  if (mCompatMode == eCompatibility_NavQuirks) {
+    mStyleSet->AppendStyleSheet(SheetType::Agent, cache->QuirkSheet());
+    mQuirkSheetAdded = true;
+  }
+
+  mStyleSet->AppendStyleSheet(SheetType::Agent, cache->FormsSheet());
+  mStyleSet->AppendStyleSheet(SheetType::Agent, cache->ScrollbarsSheet());
+  mStyleSet->AppendStyleSheet(SheetType::Agent, cache->PluginProblemSheet());
+
+  for (StyleSheet* sheet : *sheetService->AgentStyleSheets()) {
+    mStyleSet->AppendStyleSheet(SheetType::Agent, sheet);
+  }
+}
+
+void Document::FillStyleSet() {
+  MOZ_ASSERT(!mStyleSetFilled);
+  FillStyleSetUserAndUASheets();
+  FillStyleSetDocumentSheets();
+  mStyleSetFilled = true;
+}
+
+void Document::FillStyleSetDocumentSheets() {
+  MOZ_ASSERT(mStyleSet->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],
+      mStyleSet->AddDocStyleSheet(sheet, this);
+    }
+  }
+
+  nsStyleSheetService* sheetService = nsStyleSheetService::GetInstance();
+  for (StyleSheet* sheet : *sheetService->AuthorStyleSheets()) {
+    mStyleSet->AppendStyleSheet(SheetType::Doc, sheet);
+  }
+
+  AppendSheetsToStyleSet(mStyleSet.get(), mAdditionalSheets[eAgentSheet],
                          SheetType::Agent);
-  AppendSheetsToStyleSet(aStyleSet, mAdditionalSheets[eUserSheet],
+  AppendSheetsToStyleSet(mStyleSet.get(), mAdditionalSheets[eUserSheet],
                          SheetType::User);
-  AppendSheetsToStyleSet(aStyleSet, mAdditionalSheets[eAuthorSheet],
+  AppendSheetsToStyleSet(mStyleSet.get(), mAdditionalSheets[eAuthorSheet],
                          SheetType::Doc);
-
-  mStyleSetFilled = true;
+}
+
+void Document::CompatibilityModeChanged() {
+  MOZ_ASSERT(IsHTMLOrXHTML());
+  CSSLoader()->SetCompatibilityMode(mCompatMode);
+  mStyleSet->CompatibilityModeChanged();
+  if (!mStyleSetFilled) {
+    MOZ_ASSERT(!mQuirkSheetAdded);
+    return;
+  }
+  if (mQuirkSheetAdded == NeedsQuirksSheet()) {
+    return;
+  }
+  auto cache = nsLayoutStylesheetCache::Singleton();
+  StyleSheet* sheet = cache->QuirkSheet();
+  if (mQuirkSheetAdded) {
+    mStyleSet->RemoveStyleSheet(SheetType::Agent, sheet);
+  } else {
+    mStyleSet->AppendStyleSheet(SheetType::Agent, sheet);
+  }
+  mQuirkSheetAdded = !mQuirkSheetAdded;
+  if (PresShell* presShell = GetPresShell()) {
+    presShell->ApplicableStylesChanged();
+  }
 }
 
 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
@@ -3585,29 +3665,39 @@ static inline void AssertNoStaleServoDat
         }
       }
     }
   }
 #endif
 }
 
 already_AddRefed<PresShell> Document::CreatePresShell(
-    nsPresContext* aContext, nsViewManager* aViewManager,
-    UniquePtr<ServoStyleSet> aStyleSet) {
-  NS_ASSERTION(!mPresShell, "We have a presshell already!");
+    nsPresContext* aContext, nsViewManager* aViewManager) {
+  MOZ_ASSERT(!mPresShell, "We have a presshell already!");
 
   NS_ENSURE_FALSE(GetBFCacheEntry(), nullptr);
 
-  FillStyleSet(aStyleSet.get());
   AssertNoStaleServoDataIn(*this);
 
   RefPtr<PresShell> presShell = new PresShell;
   // Note: we don't hold a ref to the shell (it holds a ref to us)
   mPresShell = presShell;
-  presShell->Init(this, aContext, aViewManager, std::move(aStyleSet));
+
+  bool hadStyleSheets = mStyleSetFilled;
+  if (!hadStyleSheets) {
+    FillStyleSet();
+  }
+
+  presShell->Init(this, aContext, aViewManager);
+
+  if (hadStyleSheets) {
+    // Gaining a shell causes changes in how media queries are evaluated, so
+    // invalidate that.
+    aContext->MediaFeatureValuesChanged({MediaFeatureChange::kAllChanges});
+  }
 
   // Make sure to never paint if we belong to an invisible DocShell.
   nsCOMPtr<nsIDocShell> docShell(mDocumentContainer);
   if (docShell && docShell->IsInvisible()) {
     presShell->SetNeverPainting(true);
   }
 
   MOZ_LOG(gDocumentLeakPRLog, LogLevel::Debug,
@@ -3700,31 +3790,32 @@ bool Document::ShouldThrottleFrameReques
 }
 
 void Document::DeletePresShell() {
   mExternalResourceMap.HideViewers();
   if (nsPresContext* presContext = mPresShell->GetPresContext()) {
     presContext->RefreshDriver()->CancelPendingFullscreenEvents(this);
   }
 
+  mStyleSet->ShellDetachedFromDocument();
+
   // When our shell goes away, request that all our images be immediately
   // discarded, so we don't carry around decoded image data for a document we
   // no longer intend to paint.
   ImageTracker()->RequestDiscardAll();
 
   // Now that we no longer have a shell, we need to forget about any FontFace
   // objects for @font-face rules that came from the style set. There's no need
   // to call EnsureStyleFlush either, the shell is going away anyway, so there's
   // no point on it.
   MarkUserFontSetDirty();
 
   PresShell* oldPresShell = mPresShell;
   mPresShell = nullptr;
   UpdateFrameRequestCallbackSchedulingState(oldPresShell);
-  mStyleSetFilled = false;
 
   ClearStaleServoData();
   AssertNoStaleServoDataIn(*this);
 }
 
 void Document::SetBFCacheEntry(nsIBFCacheEntry* aEntry) {
   MOZ_ASSERT(IsBFCachingAllowed() || !aEntry, "You should have checked!");
 
@@ -3908,19 +3999,21 @@ void Document::RemoveChildNode(nsIConten
   mCachedRootElement = nullptr;
   nsINode::RemoveChildNode(aKid, aNotify);
   MOZ_ASSERT(mCachedRootElement != aKid,
              "Stale pointer in mCachedRootElement, after we tried to clear it "
              "(maybe somebody called GetRootElement() too early?)");
 }
 
 void Document::AddStyleSheetToStyleSets(StyleSheet* aSheet) {
-  if (PresShell* presShell = GetPresShell()) {
-    presShell->StyleSet()->AddDocStyleSheet(aSheet, this);
-    presShell->ApplicableStylesChanged();
+  if (mStyleSetFilled) {
+    mStyleSet->AddDocStyleSheet(aSheet, this);
+    if (PresShell* presShell = GetPresShell()) {
+      presShell->ApplicableStylesChanged();
+    }
   }
 }
 
 #define DO_STYLESHEET_NOTIFICATION(className, type, memberName, argName) \
   do {                                                                   \
     className##Init init;                                                \
     init.mBubbles = true;                                                \
     init.mCancelable = true;                                             \
@@ -3948,19 +4041,21 @@ void Document::NotifyStyleSheetRemoved(S
                                        bool aDocumentSheet) {
   if (StyleSheetChangeEventsEnabled()) {
     DO_STYLESHEET_NOTIFICATION(StyleSheetChangeEvent, "StyleSheetRemoved",
                                mDocumentSheet, aDocumentSheet);
   }
 }
 
 void Document::RemoveStyleSheetFromStyleSets(StyleSheet* aSheet) {
-  if (PresShell* presShell = GetPresShell()) {
-    presShell->StyleSet()->RemoveDocStyleSheet(aSheet);
-    presShell->ApplicableStylesChanged();
+  if (mStyleSetFilled) {
+    mStyleSet->RemoveDocStyleSheet(aSheet);
+    if (PresShell* presShell = GetPresShell()) {
+      presShell->ApplicableStylesChanged();
+    }
   }
 }
 
 void Document::RemoveStyleSheet(StyleSheet* aSheet) {
   MOZ_ASSERT(aSheet);
   RefPtr<StyleSheet> sheet = DocumentOrShadowRoot::RemoveSheet(*aSheet);
 
   if (!sheet) {
@@ -4130,20 +4225,22 @@ nsresult Document::LoadAdditionalStyleSh
 nsresult Document::AddAdditionalStyleSheet(additionalSheetType aType,
                                            StyleSheet* aSheet) {
   if (mAdditionalSheets[aType].Contains(aSheet)) return NS_ERROR_INVALID_ARG;
 
   if (!aSheet->IsApplicable()) return NS_ERROR_INVALID_ARG;
 
   mAdditionalSheets[aType].AppendElement(aSheet);
 
-  if (PresShell* presShell = GetPresShell()) {
+  if (mStyleSetFilled) {
     SheetType type = ConvertAdditionalSheetType(aType);
-    presShell->StyleSet()->AppendStyleSheet(type, aSheet);
-    presShell->ApplicableStylesChanged();
+    mStyleSet->AppendStyleSheet(type, aSheet);
+    if (PresShell* presShell = GetPresShell()) {
+      presShell->ApplicableStylesChanged();
+    }
   }
 
   // Passing false, so documet.styleSheets.length will not be affected by
   // these additional sheets.
   NotifyStyleSheetAdded(aSheet, false);
   return NS_OK;
 }
 
@@ -4155,20 +4252,22 @@ void Document::RemoveAdditionalStyleShee
 
   int32_t i = FindSheet(mAdditionalSheets[aType], aSheetURI);
   if (i >= 0) {
     RefPtr<StyleSheet> sheetRef = sheets[i];
     sheets.RemoveElementAt(i);
 
     if (!mIsGoingAway) {
       MOZ_ASSERT(sheetRef->IsApplicable());
-      if (PresShell* presShell = GetPresShell()) {
+      if (mStyleSetFilled) {
         SheetType type = ConvertAdditionalSheetType(aType);
-        presShell->StyleSet()->RemoveStyleSheet(type, sheetRef);
-        presShell->ApplicableStylesChanged();
+        mStyleSet->RemoveStyleSheet(type, sheetRef);
+        if (PresShell* presShell = GetPresShell()) {
+          presShell->ApplicableStylesChanged();
+        }
       }
     }
 
     // Passing false, so documet.styleSheets.length will not be affected by
     // these additional sheets.
     NotifyStyleSheetRemoved(sheetRef, false);
     sheetRef->ClearAssociatedDocumentOrShadowRoot();
   }
@@ -11663,18 +11762,17 @@ void Document::FlushUserFontSet() {
   if (!mFontFaceSetDirty) {
     return;
   }
 
   mFontFaceSetDirty = false;
 
   if (gfxPlatform::GetPlatform()->DownloadableFontsEnabled()) {
     nsTArray<nsFontFaceRuleContainer> rules;
-    PresShell* presShell = GetPresShell();
-    if (presShell && !presShell->StyleSet()->AppendFontFaceRules(rules)) {
+    if (mStyleSetFilled && !mStyleSet->AppendFontFaceRules(rules)) {
       return;
     }
 
     if (!mFontFaceSet && !rules.IsEmpty()) {
       nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(GetScopeObject());
       mFontFaceSet = new FontFaceSet(window, this);
     }
 
@@ -11682,16 +11780,17 @@ void Document::FlushUserFontSet() {
     if (mFontFaceSet) {
       changed = mFontFaceSet->UpdateRules(rules);
     }
 
     // We need to enqueue a style change reflow (for later) to
     // reflect that we're modifying @font-face rules.  (However,
     // without a reflow, nothing will happen to start any downloads
     // that are needed.)
+    PresShell* presShell = GetPresShell();
     if (changed && presShell) {
       if (nsPresContext* presContext = presShell->GetPresContext()) {
         presContext->UserFontSetUpdated();
       }
     }
   }
 }
 
--- a/dom/base/Document.h
+++ b/dom/base/Document.h
@@ -1239,19 +1239,18 @@ class Document : public nsINode,
 
   /**
    * Create a new presentation shell that will use aContext for its
    * presentation context (presentation contexts <b>must not</b> be
    * shared among multiple presentation shells). The caller of this
    * method is responsible for calling BeginObservingDocument() on the
    * presshell if the presshell should observe document mutations.
    */
-  already_AddRefed<PresShell> CreatePresShell(
-      nsPresContext* aContext, nsViewManager* aViewManager,
-      UniquePtr<ServoStyleSet> aStyleSet);
+  already_AddRefed<PresShell> CreatePresShell(nsPresContext* aContext,
+                                              nsViewManager* aViewManager);
   void DeletePresShell();
 
   PresShell* GetPresShell() const {
     return GetBFCacheEntry() ? nullptr : mPresShell;
   }
 
   inline PresShell* GetObservingPresShell() const;
 
@@ -1626,16 +1625,24 @@ class Document : public nsINode,
   // Get the "body" in the sense of document.body: The first <body> or
   // <frameset> that's a child of a root <html>
   nsGenericHTMLElement* GetBody();
   // Set the "body" in the sense of document.body.
   void SetBody(nsGenericHTMLElement* aBody, ErrorResult& rv);
   // Get the "head" element in the sense of document.head.
   HTMLSharedElement* GetHead();
 
+  ServoStyleSet* StyleSetForPresShellOrMediaQueryEvaluation() const {
+    return mStyleSet.get();
+  }
+
+  // Whether we filled the style set with any style sheet. Only meant to be used
+  // from DocumentOrShadowRoot::Traverse.
+  bool StyleSetFilled() const { return mStyleSetFilled; }
+
   /**
    * Accessors to the collection of stylesheets owned by this document.
    * Style sheets are ordered, most significant last.
    */
 
   StyleSheetList* StyleSheets() {
     return &DocumentOrShadowRoot::EnsureDOMStyleSheets();
   }
@@ -3779,17 +3786,24 @@ class Document : public nsINode,
   }
 
   void UpdateDocumentStates(EventStates);
 
   void RemoveDocStyleSheetsFromStyleSets();
   void RemoveStyleSheetsFromStyleSets(
       const nsTArray<RefPtr<StyleSheet>>& aSheets, SheetType aType);
   void ResetStylesheetsToURI(nsIURI* aURI);
-  void FillStyleSet(ServoStyleSet* aStyleSet);
+  void FillStyleSet();
+  void FillStyleSetUserAndUASheets();
+  void FillStyleSetDocumentSheets();
+  void CompatibilityModeChanged();
+  bool NeedsQuirksSheet() const {
+    // SVG documents never load quirk.css.
+    return mCompatMode == eCompatibility_NavQuirks && !IsSVGDocument();
+  }
   void AddStyleSheetToStyleSets(StyleSheet* aSheet);
   void RemoveStyleSheetFromStyleSets(StyleSheet* aSheet);
   void NotifyStyleSheetAdded(StyleSheet* aSheet, bool aDocumentSheet);
   void NotifyStyleSheetRemoved(StyleSheet* aSheet, bool aDocumentSheet);
   void NotifyStyleSheetApplicableStateChanged();
   // Just like EnableStyleSheetsForSet, but doesn't check whether
   // aSheetSet is null and allows the caller to control whether to set
   // aSheetSet as the preferred set in the CSSLoader.
@@ -3803,16 +3817,17 @@ class Document : public nsINode,
   }
 
   mutable std::bitset<eDeprecatedOperationCount> mDeprecationWarnedAbout;
   mutable std::bitset<eDocumentWarningCount> mDocWarningWarnedAbout;
 
   // Lazy-initialization to have mDocGroup initialized in prior to the
   // SelectorCaches.
   UniquePtr<SelectorCache> mSelectorCache;
+  UniquePtr<ServoStyleSet> mStyleSet;
 
  protected:
   friend class nsDocumentOnStack;
 
   void IncreaseStackRefCnt() { ++mStackRefCnt; }
 
   void DecreaseStackRefCnt() {
     if (--mStackRefCnt == 0 && mNeedsReleaseAfterStackRefCntRelease) {
@@ -4160,20 +4175,22 @@ class Document : public nsINode,
 
   // True if the document has been detached from its content viewer.
   bool mIsGoingAway : 1;
 
   bool mInXBLUpdate : 1;
 
   bool mNeedsReleaseAfterStackRefCntRelease : 1;
 
-  // Whether we have filled our pres shell's style set with the document's
-  // additional sheets and sheets from the nsStyleSheetService.
+  // Whether we have filled our style set with all the stylesheets.
   bool mStyleSetFilled : 1;
 
+  // Whether we have a quirks mode stylesheet in the style set.
+  bool mQuirkSheetAdded : 1;
+
   // Keeps track of whether we have a pending
   // 'style-sheet-applicable-state-changed' notification.
   bool mSSApplicableStateNotificationPending : 1;
 
   // True if this document has ever had an HTML or SVG <title> element
   // bound to it
   bool mMayHaveTitleElement : 1;
 
--- a/dom/base/DocumentOrShadowRoot.cpp
+++ b/dom/base/DocumentOrShadowRoot.cpp
@@ -583,29 +583,54 @@ nsRadioGroupStruct* DocumentOrShadowRoot
 nsRadioGroupStruct* DocumentOrShadowRoot::GetOrCreateRadioGroup(
     const nsAString& aName) {
   return mRadioGroups.LookupForAdd(aName).OrInsert(
       []() { return new nsRadioGroupStruct(); });
 }
 
 void DocumentOrShadowRoot::Traverse(DocumentOrShadowRoot* tmp,
                                     nsCycleCollectionTraversalCallback& cb) {
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mStyleSheets)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDOMStyleSheets)
+  for (StyleSheet* sheet : tmp->mStyleSheets) {
+    if (!sheet->IsApplicable()) {
+      continue;
+    }
+    // The style set or mServoStyles keep more references to it if the sheet is
+    // applicable.
+    if (tmp->mKind == Kind::ShadowRoot) {
+      NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mServoStyles->sheets[i]");
+      cb.NoteXPCOMChild(sheet);
+    } else if (tmp->AsNode().AsDocument()->StyleSetFilled()) {
+      NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(
+          cb, "mStyleSet->mStyleSheets[SheetType::Author][i]");
+      cb.NoteXPCOMChild(sheet);
+      NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(
+          cb, "mStyleSet->mRawSet.stylist.stylesheets.author[i]");
+      cb.NoteXPCOMChild(sheet);
+    }
+  }
+  for (auto iter = tmp->mIdentifierMap.ConstIter(); !iter.Done(); iter.Next()) {
+    iter.Get()->Traverse(&cb);
+  }
   for (auto iter = tmp->mRadioGroups.Iter(); !iter.Done(); iter.Next()) {
     nsRadioGroupStruct* radioGroup = iter.UserData();
     NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(
         cb, "mRadioGroups entry->mSelectedRadioButton");
     cb.NoteXPCOMChild(ToSupports(radioGroup->mSelectedRadioButton));
 
     uint32_t i, count = radioGroup->mRadioButtons.Count();
     for (i = 0; i < count; ++i) {
       NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(
           cb, "mRadioGroups entry->mRadioButtons[i]");
       cb.NoteXPCOMChild(radioGroup->mRadioButtons[i]);
     }
   }
 }
 
 void DocumentOrShadowRoot::Unlink(DocumentOrShadowRoot* tmp) {
+  NS_IMPL_CYCLE_COLLECTION_UNLINK(mDOMStyleSheets)
+  tmp->mIdentifierMap.Clear();
   tmp->mRadioGroups.Clear();
 }
 
 }  // namespace dom
 }  // namespace mozilla
--- a/dom/base/ShadowRoot.cpp
+++ b/dom/base/ShadowRoot.cpp
@@ -25,38 +25,23 @@
 #include "mozilla/dom/StyleSheetList.h"
 
 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(mStyleSheets)
-  for (StyleSheet* sheet : tmp->mStyleSheets) {
-    // mServoStyles keeps another reference to it if applicable.
-    if (sheet->IsApplicable()) {
-      MOZ_ASSERT(tmp->mServoStyles);
-      NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mServoStyles->sheets[i]");
-      cb.NoteXPCOMChild(sheet);
-    }
-  }
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDOMStyleSheets)
-  for (auto iter = tmp->mIdentifierMap.ConstIter(); !iter.Done(); iter.Next()) {
-    iter.Get()->Traverse(&cb);
-  }
   DocumentOrShadowRoot::Traverse(tmp, 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(mDOMStyleSheets)
-  tmp->mIdentifierMap.Clear();
   DocumentOrShadowRoot::Unlink(tmp);
 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_ENTRY(nsIRadioGroupContainer)
 NS_INTERFACE_MAP_END_INHERITING(DocumentFragment)
--- a/dom/canvas/CanvasRenderingContext2D.cpp
+++ b/dom/canvas/CanvasRenderingContext2D.cpp
@@ -15,16 +15,17 @@
 
 #include "nsContentUtils.h"
 
 #include "mozilla/dom/Document.h"
 #include "mozilla/dom/HTMLCanvasElement.h"
 #include "SVGObserverUtils.h"
 #include "nsPresContext.h"
 #include "nsIPresShell.h"
+#include "nsIPresShellInlines.h"
 
 #include "nsIInterfaceRequestorUtils.h"
 #include "nsIFrame.h"
 #include "nsError.h"
 
 #include "nsCSSPseudoElements.h"
 #include "nsComputedDOMStyle.h"
 
--- a/dom/html/nsHTMLDocument.cpp
+++ b/dom/html/nsHTMLDocument.cpp
@@ -504,17 +504,17 @@ nsresult nsHTMLDocument::StartDocumentLo
   bool forceUtf8 =
       mIsPlainText && nsContentUtils::IsUtf8OnlyPlainTextType(contentType);
 
   bool loadAsHtml5 = true;
 
   if (!viewSource && xhtml) {
     // We're parsing XHTML as XML, remember that.
     mType = eXHTML;
-    mCompatMode = eCompatibility_FullStandards;
+    SetCompatibilityMode(eCompatibility_FullStandards);
     loadAsHtml5 = false;
   }
 
   // TODO: Proper about:blank treatment is bug 543435
   if (loadAsHtml5 && view) {
     // mDocumentURI hasn't been set, yet, so get the URI from the channel
     nsCOMPtr<nsIURI> uri;
     aChannel->GetOriginalURI(getter_AddRefs(uri));
@@ -523,18 +523,16 @@ nsresult nsHTMLDocument::StartDocumentLo
     bool isAbout = false;
     if (uri && NS_SUCCEEDED(uri->SchemeIs("about", &isAbout)) && isAbout) {
       if (uri->GetSpecOrDefault().EqualsLiteral("about:blank")) {
         loadAsHtml5 = false;
       }
     }
   }
 
-  CSSLoader()->SetCompatibilityMode(mCompatMode);
-
   nsresult rv = Document::StartDocumentLoad(aCommand, aChannel, aLoadGroup,
                                             aContainer, aDocListener, aReset);
   if (NS_FAILED(rv)) {
     return rv;
   }
 
   // Store the security info for future use.
   aChannel->GetSecurityInfo(getter_AddRefs(mSecurityInfo));
@@ -777,20 +775,17 @@ void nsHTMLDocument::EndLoad() {
 void nsHTMLDocument::SetCompatibilityMode(nsCompatibility aMode) {
   NS_ASSERTION(IsHTMLDocument() || aMode == eCompatibility_FullStandards,
                "Bad compat mode for XHTML document!");
 
   if (mCompatMode == aMode) {
     return;
   }
   mCompatMode = aMode;
-  CSSLoader()->SetCompatibilityMode(mCompatMode);
-  if (nsPresContext* pc = GetPresContext()) {
-    pc->CompatibilityModeChanged();
-  }
+  CompatibilityModeChanged();
 }
 
 bool nsHTMLDocument::UseWidthDeviceWidthFallbackViewport() const {
   if (mIsPlainText) {
     // Plain text documents are simple enough that font inflation doesn't offer
     // any appreciable advantage over defaulting to "width=device-width" and
     // subsequently turning on word-wrapping.
     return true;
--- a/editor/libeditor/HTMLAnonymousNodeEditor.cpp
+++ b/editor/libeditor/HTMLAnonymousNodeEditor.cpp
@@ -22,16 +22,17 @@
 #include "nsIDOMWindow.h"
 #include "mozilla/dom/Document.h"
 #include "nsIDocumentObserver.h"
 #include "nsIHTMLAbsPosEditor.h"
 #include "nsIHTMLInlineTableEditor.h"
 #include "nsIHTMLObjectResizer.h"
 #include "nsStubMutationObserver.h"
 #include "nsINode.h"
+#include "nsIPresShellInlines.h"
 #include "nsISupportsImpl.h"
 #include "nsISupportsUtils.h"
 #include "nsLiteralString.h"
 #include "nsPresContext.h"
 #include "nsReadableUtils.h"
 #include "nsString.h"
 #include "nsStringFwd.h"
 #include "nsUnicharUtils.h"
--- a/layout/base/PresShell.cpp
+++ b/layout/base/PresShell.cpp
@@ -892,32 +892,30 @@ PresShell::~PresShell() {
   // be re-used by another presentation.
   if (mPaintingIsFrozen) {
     mPresContext->RefreshDriver()->Thaw();
   }
 
   MOZ_ASSERT(mAllocatedPointers.IsEmpty(),
              "Some pres arena objects were not freed");
 
-  mStyleSet = nullptr;
   mFrameManager = nullptr;
   mFrameConstructor = nullptr;
 
   mCurrentEventContent = nullptr;
 }
 
 /**
  * Initialize the presentation shell. Create view manager and style
  * manager.
  * Note this can't be merged into our constructor because caret initialization
  * calls AddRef() on us.
  */
 void PresShell::Init(Document* aDocument, nsPresContext* aPresContext,
-                     nsViewManager* aViewManager,
-                     UniquePtr<ServoStyleSet> aStyleSet) {
+                     nsViewManager* aViewManager) {
   MOZ_ASSERT(aDocument, "null ptr");
   MOZ_ASSERT(aPresContext, "null ptr");
   MOZ_ASSERT(aViewManager, "null ptr");
   MOZ_ASSERT(!mDocument, "already initialized");
 
   if (!aDocument || !aPresContext || !aViewManager || mDocument) {
     return;
   }
@@ -939,26 +937,17 @@ void PresShell::Init(Document* aDocument
 
   // The document viewer owns both view manager and pres shell.
   mViewManager->SetPresShell(this);
 
   // Bind the context to the presentation shell.
   mPresContext = aPresContext;
   mPresContext->AttachShell(this);
 
-  // Now we can initialize the style set. Make sure to set the member before
-  // calling Init, since various subroutines need to find the style set off
-  // the PresContext during initialization.
-  mStyleSet = std::move(aStyleSet);
-  mStyleSet->Init(aPresContext);
-
-  // Notify our prescontext that it now has a compatibility mode.  Note that
-  // this MUST happen after we set up our style set but before we create any
-  // frames.
-  mPresContext->CompatibilityModeChanged();
+  mPresContext->DeviceContext()->InitFontCache();
 
   // Add the preference style sheet.
   UpdatePreferenceStyles();
 
   bool accessibleCaretEnabled =
       AccessibleCaretEnabled(mDocument->GetDocShell());
   if (accessibleCaretEnabled) {
     // Need to happen before nsFrameSelection has been set up.
@@ -1271,18 +1260,17 @@ void PresShell::Destroy() {
 
   if (mAccessibleCaretEventHub) {
     mAccessibleCaretEventHub->Terminate();
     mAccessibleCaretEventHub = nullptr;
   }
 
   // release our pref style sheet, if we have one still
   //
-  // FIXME(emilio): Why do we need to do this? The stylist is getting nixed with
-  // us anyway.
+  // TODO(emilio): Should we move the preference sheet tracking to the Document?
   RemovePreferenceStyles();
 
   mIsDestroying = true;
 
   // We can't release all the event content in
   // mCurrentEventContentStack here since there might be code on the
   // stack that will release the event content too. Double release
   // bad!
@@ -1305,17 +1293,16 @@ void PresShell::Destroy() {
 
   if (mViewManager) {
     // Clear the view manager's weak pointer back to |this| in case it
     // was leaked.
     mViewManager->SetPresShell(nullptr);
     mViewManager = nullptr;
   }
 
-  mStyleSet->BeginShutdown();
   nsRefreshDriver* rd = GetPresContext()->RefreshDriver();
 
   // This shell must be removed from the document before the frame
   // hierarchy is torn down to avoid finding deleted frames through
   // this presshell while the frames are being torn down
   if (mDocument) {
     NS_ASSERTION(mDocument->GetPresShell() == this, "Wrong shell?");
     mDocument->ClearServoRestyleRoot();
@@ -1356,19 +1343,16 @@ void PresShell::Destroy() {
   nsTArray<WeakFrame*> toRemove(mWeakFrames.Count());
   for (auto iter = mWeakFrames.Iter(); !iter.Done(); iter.Next()) {
     toRemove.AppendElement(iter.Get()->GetKey());
   }
   for (WeakFrame* weakFrame : toRemove) {
     weakFrame->Clear(this);
   }
 
-  // Let the style set do its cleanup.
-  mStyleSet->Shutdown();
-
   if (mPresContext) {
     // We hold a reference to the pres context, and it holds a weak link back
     // to us. To avoid the pres context having a dangling reference, set its
     // pres shell to nullptr
     mPresContext->DetachShell();
 
     // Clear the link handler (weak reference) as well
     mPresContext->SetLinkHandler(nullptr);
@@ -1405,31 +1389,31 @@ void nsIPresShell::StartObservingRefresh
   }
 }
 
 nsRefreshDriver* nsIPresShell::GetRefreshDriver() const {
   return mPresContext ? mPresContext->RefreshDriver() : nullptr;
 }
 
 void nsIPresShell::SetAuthorStyleDisabled(bool aStyleDisabled) {
-  if (aStyleDisabled != mStyleSet->GetAuthorStyleDisabled()) {
-    mStyleSet->SetAuthorStyleDisabled(aStyleDisabled);
+  if (aStyleDisabled != StyleSet()->GetAuthorStyleDisabled()) {
+    StyleSet()->SetAuthorStyleDisabled(aStyleDisabled);
     ApplicableStylesChanged();
 
     nsCOMPtr<nsIObserverService> observerService =
         mozilla::services::GetObserverService();
     if (observerService) {
       observerService->NotifyObservers(
           ToSupports(mDocument), "author-style-disabled-changed", nullptr);
     }
   }
 }
 
 bool nsIPresShell::GetAuthorStyleDisabled() const {
-  return mStyleSet->GetAuthorStyleDisabled();
+  return StyleSet()->GetAuthorStyleDisabled();
 }
 
 void nsIPresShell::UpdatePreferenceStyles() {
   if (!mDocument) {
     return;
   }
 
   // If the document doesn't have a window there's no need to notify
@@ -1458,23 +1442,23 @@ void nsIPresShell::UpdatePreferenceStyle
   }
 
   RemovePreferenceStyles();
 
   // NOTE(emilio): This sheet is added as an agent sheet, because we don't want
   // it to be modifiable from devtools and similar, see bugs 1239336 and
   // 1436782. I think it conceptually should be a user sheet, and could be
   // without too much trouble I'd think.
-  mStyleSet->AppendStyleSheet(SheetType::Agent, newPrefSheet);
+  StyleSet()->AppendStyleSheet(SheetType::Agent, newPrefSheet);
   mPrefStyleSheet = newPrefSheet;
 }
 
 void nsIPresShell::RemovePreferenceStyles() {
   if (mPrefStyleSheet) {
-    mStyleSet->RemoveStyleSheet(SheetType::Agent, mPrefStyleSheet);
+    StyleSet()->RemoveStyleSheet(SheetType::Agent, mPrefStyleSheet);
     mPrefStyleSheet = nullptr;
   }
 }
 
 void nsIPresShell::AddUserSheet(StyleSheet* aSheet) {
   // Make sure this does what nsDocumentViewer::CreateStyleSet does wrt
   // ordering. We want this new sheet to come after all the existing stylesheet
   // service sheets (which are at the start), but before other user sheets; see
@@ -1491,51 +1475,52 @@ void nsIPresShell::AddUserSheet(StyleShe
   MOZ_ASSERT(aSheet);
   MOZ_ASSERT(userSheets.LastElement() == aSheet);
 
   size_t index = userSheets.Length() - 1;
 
   // Assert that all of userSheets (except for the last, new element) matches up
   // with what's in the style set.
   for (size_t i = 0; i < index; ++i) {
-    MOZ_ASSERT(mStyleSet->StyleSheetAt(SheetType::User, i) == userSheets[i]);
-  }
-
-  if (index == static_cast<size_t>(mStyleSet->SheetCount(SheetType::User))) {
-    mStyleSet->AppendStyleSheet(SheetType::User, aSheet);
+    MOZ_ASSERT(StyleSet()->StyleSheetAt(SheetType::User, i) == userSheets[i]);
+  }
+
+  if (index == static_cast<size_t>(StyleSet()->SheetCount(SheetType::User))) {
+    StyleSet()->AppendStyleSheet(SheetType::User, aSheet);
   } else {
-    StyleSheet* ref = mStyleSet->StyleSheetAt(SheetType::User, index);
-    mStyleSet->InsertStyleSheetBefore(SheetType::User, aSheet, ref);
+    StyleSheet* ref = StyleSet()->StyleSheetAt(SheetType::User, index);
+    StyleSet()->InsertStyleSheetBefore(SheetType::User, aSheet, ref);
   }
 
   ApplicableStylesChanged();
 }
 
 void nsIPresShell::AddAgentSheet(StyleSheet* aSheet) {
   // Make sure this does what nsDocumentViewer::CreateStyleSet does
   // wrt ordering.
-  mStyleSet->AppendStyleSheet(SheetType::Agent, aSheet);
+  StyleSet()->AppendStyleSheet(SheetType::Agent, aSheet);
   ApplicableStylesChanged();
 }
 
 void nsIPresShell::AddAuthorSheet(StyleSheet* aSheet) {
   // Document specific "additional" Author sheets should be stronger than the
   // ones added with the StyleSheetService.
   StyleSheet* firstAuthorSheet = mDocument->GetFirstAdditionalAuthorSheet();
   if (firstAuthorSheet) {
-    mStyleSet->InsertStyleSheetBefore(SheetType::Doc, aSheet, firstAuthorSheet);
+    StyleSet()->InsertStyleSheetBefore(SheetType::Doc, aSheet,
+                                       firstAuthorSheet);
   } else {
-    mStyleSet->AppendStyleSheet(SheetType::Doc, aSheet);
+    StyleSet()->AppendStyleSheet(SheetType::Doc, aSheet);
   }
 
   ApplicableStylesChanged();
 }
 
 void nsIPresShell::RemoveSheet(SheetType aType, StyleSheet* aSheet) {
-  mStyleSet->RemoveStyleSheet(aType, aSheet);
+  StyleSet()->RemoveStyleSheet(aType, aSheet);
   ApplicableStylesChanged();
 }
 
 NS_IMETHODIMP
 PresShell::SetDisplaySelection(int16_t aToggle) {
   RefPtr<nsFrameSelection> frameSelection = mSelection;
   frameSelection->SetDisplaySelection(aToggle);
   return NS_OK;
@@ -4084,17 +4069,17 @@ void PresShell::DoFlushPendingNotificati
     if (MOZ_LIKELY(!mIsDestroying)) {
       viewManager->FlushDelayedResize(false);
       mPresContext->FlushPendingMediaFeatureValuesChanged();
     }
 
     if (MOZ_LIKELY(!mIsDestroying)) {
       // Now that we have flushed media queries, update the rules before looking
       // up @font-face / @counter-style / @font-feature-values rules.
-      mStyleSet->UpdateStylistIfNeeded();
+      StyleSet()->UpdateStylistIfNeeded();
 
       // Flush any pending update of the user font set, since that could
       // cause style changes (for updating ex/ch units, and to cause a
       // reflow).
       mDocument->FlushUserFontSet();
 
       mPresContext->FlushCounterStyles();
 
@@ -4229,17 +4214,17 @@ void PresShell::ContentStateChanged(Docu
 
 void PresShell::DocumentStatesChanged(Document* aDocument,
                                       EventStates aStateMask) {
   MOZ_ASSERT(!mIsDocumentGone, "Unexpected DocumentStatesChanged");
   MOZ_ASSERT(aDocument == mDocument, "Unexpected aDocument");
   MOZ_ASSERT(!aStateMask.IsEmpty());
 
   if (mDidInitialize) {
-    mStyleSet->InvalidateStyleForDocumentStateChanges(aStateMask);
+    StyleSet()->InvalidateStyleForDocumentStateChanges(aStateMask);
   }
 
   if (aStateMask.HasState(NS_DOCUMENT_STATE_WINDOW_INACTIVE)) {
     if (nsIFrame* root = mFrameConstructor->GetRootFrame()) {
       root->SchedulePaint();
     }
   }
 }
@@ -5899,17 +5884,17 @@ class nsAutoNotifyDidPaint {
   }
 
  private:
   PresShell* mShell;
   uint32_t mFlags;
 };
 
 void nsIPresShell::RecordShadowStyleChange(ShadowRoot& aShadowRoot) {
-  mStyleSet->RecordShadowStyleChange(aShadowRoot);
+  StyleSet()->RecordShadowStyleChange(aShadowRoot);
   ApplicableStylesChanged();
 }
 
 void PresShell::Paint(nsView* aViewToPaint, const nsRegion& aDirtyRegion,
                       uint32_t aFlags) {
   nsCString url;
   nsIURI* uri = mDocument->GetDocumentURI();
   Document* contentRoot = GetPrimaryContentDocument();
@@ -8793,41 +8778,41 @@ void PresShell::RespectDisplayportSuppre
 }
 
 bool PresShell::IsDisplayportSuppressed() {
   return sDisplayPortSuppressionRespected && mActiveSuppressDisplayport > 0;
 }
 
 nsresult PresShell::GetAgentStyleSheets(nsTArray<RefPtr<StyleSheet>>& aSheets) {
   aSheets.Clear();
-  int32_t sheetCount = mStyleSet->SheetCount(SheetType::Agent);
+  int32_t sheetCount = StyleSet()->SheetCount(SheetType::Agent);
 
   if (!aSheets.SetCapacity(sheetCount, fallible)) {
     return NS_ERROR_OUT_OF_MEMORY;
   }
 
   for (int32_t i = 0; i < sheetCount; ++i) {
-    StyleSheet* sheet = mStyleSet->StyleSheetAt(SheetType::Agent, i);
+    StyleSheet* sheet = StyleSet()->StyleSheetAt(SheetType::Agent, i);
     aSheets.AppendElement(sheet);
   }
 
   return NS_OK;
 }
 
 nsresult PresShell::SetAgentStyleSheets(
     const nsTArray<RefPtr<StyleSheet>>& aSheets) {
-  return mStyleSet->ReplaceSheets(SheetType::Agent, aSheets);
+  return StyleSet()->ReplaceSheets(SheetType::Agent, aSheets);
 }
 
 nsresult PresShell::AddOverrideStyleSheet(StyleSheet* aSheet) {
-  return mStyleSet->AppendStyleSheet(SheetType::Override, aSheet);
+  return StyleSet()->AppendStyleSheet(SheetType::Override, aSheet);
 }
 
 nsresult PresShell::RemoveOverrideStyleSheet(StyleSheet* aSheet) {
-  return mStyleSet->RemoveStyleSheet(SheetType::Override, aSheet);
+  return StyleSet()->RemoveStyleSheet(SheetType::Override, aSheet);
 }
 
 static void FreezeElement(nsISupports* aSupports, void* /* unused */) {
   nsCOMPtr<nsIObjectLoadingContent> olc(do_QueryInterface(aSupports));
   if (olc) {
     olc->StopPluginInstance();
   }
 }
@@ -9830,52 +9815,16 @@ FindTopFrame(nsIFrame* aRoot)
     }
   }
   return nullptr;
 }
 #endif
 
 #ifdef DEBUG
 
-static void CopySheetsIntoClone(ServoStyleSet* aSet, ServoStyleSet* aClone) {
-  int32_t i, n = aSet->SheetCount(SheetType::Override);
-  for (i = 0; i < n; i++) {
-    StyleSheet* ss = aSet->StyleSheetAt(SheetType::Override, i);
-    if (ss) aClone->AppendStyleSheet(SheetType::Override, ss);
-  }
-
-  // The document expects to insert document stylesheets itself
-#  if 0
-  n = aSet->SheetCount(SheetType::Doc);
-  for (i = 0; i < n; i++) {
-    StyleSheet* ss = aSet->StyleSheetAt(SheetType::Doc, i);
-    if (ss)
-      aClone->AddDocStyleSheet(ss, mDocument);
-  }
-#  endif
-
-  n = aSet->SheetCount(SheetType::User);
-  for (i = 0; i < n; i++) {
-    StyleSheet* ss = aSet->StyleSheetAt(SheetType::User, i);
-    if (ss) aClone->AppendStyleSheet(SheetType::User, ss);
-  }
-
-  n = aSet->SheetCount(SheetType::Agent);
-  for (i = 0; i < n; i++) {
-    StyleSheet* ss = aSet->StyleSheetAt(SheetType::Agent, i);
-    if (ss) aClone->AppendStyleSheet(SheetType::Agent, ss);
-  }
-}
-
-UniquePtr<ServoStyleSet> nsIPresShell::CloneStyleSet(ServoStyleSet* aSet) {
-  auto clone = MakeUnique<ServoStyleSet>();
-  CopySheetsIntoClone(aSet, clone.get());
-  return clone;
-}
-
 // After an incremental reflow, we verify the correctness by doing a
 // full reflow into a fresh frame tree.
 bool nsIPresShell::VerifyIncrementalReflow() {
   if (VERIFY_REFLOW_NOISY & gVerifyReflowFlags) {
     printf("Building Verification Tree...\n");
   }
 
   // Create a presentation context to view the new frame tree
@@ -9912,23 +9861,19 @@ bool nsIPresShell::VerifyIncrementalRefl
 
   // Setup hierarchical relationship in view manager
   vm->SetRootView(view);
 
   // Make the new presentation context the same size as our
   // presentation context.
   cx->SetVisibleArea(mPresContext->GetVisibleArea());
 
-  // Create a new presentation shell to view the document. Use the
-  // exact same style information that this document has.
-  UniquePtr<ServoStyleSet> newSet = CloneStyleSet(StyleSet());
-
-  RefPtr<PresShell> presShell =
-      mDocument->CreatePresShell(cx, vm, std::move(newSet));
+  RefPtr<PresShell> presShell = mDocument->CreatePresShell(cx, vm);
   NS_ENSURE_TRUE(presShell, false);
+
   // Note that after we create the shell, we must make sure to destroy it
   presShell->SetVerifyReflowEnable(
       false);  // turn off verify reflow while we're
                // reflowing the test frame tree
   vm->SetPresShell(presShell);
   {
     nsAutoCauseReflowNotifier crNotifier(this);
     presShell->Initialize();
@@ -9998,19 +9943,19 @@ void PresShell::ListComputedStyles(FILE*
     nsIFrame* rootElementFrame = rootElement->GetPrimaryFrame();
     if (rootElementFrame) {
       rootElementFrame->Style()->List(out, aIndent);
     }
   }
 }
 
 void PresShell::ListStyleSheets(FILE* out, int32_t aIndent) {
-  int32_t sheetCount = mStyleSet->SheetCount(SheetType::Doc);
+  int32_t sheetCount = StyleSet()->SheetCount(SheetType::Doc);
   for (int32_t i = 0; i < sheetCount; ++i) {
-    mStyleSet->StyleSheetAt(SheetType::Doc, i)->List(out, aIndent);
+    StyleSet()->StyleSheetAt(SheetType::Doc, i)->List(out, aIndent);
     fputs("\n", out);
   }
 }
 #endif
 
 //=============================================================
 //=============================================================
 //-- Debug Reflow Counts
@@ -10904,20 +10849,16 @@ static SheetType ToSheetType(uint32_t aS
 nsresult nsIPresShell::HasRuleProcessorUsedByMultipleStyleSets(
     uint32_t aSheetType, bool* aRetVal) {
   *aRetVal = false;
   return NS_OK;
 }
 
 void nsIPresShell::NotifyStyleSheetServiceSheetAdded(StyleSheet* aSheet,
                                                      uint32_t aSheetType) {
-  if (!mStyleSet) {
-    return;
-  }
-
   switch (aSheetType) {
     case nsIStyleSheetService::AGENT_SHEET:
       AddAgentSheet(aSheet);
       break;
     case nsIStyleSheetService::USER_SHEET:
       AddUserSheet(aSheet);
       break;
     case nsIStyleSheetService::AUTHOR_SHEET:
@@ -10926,20 +10867,16 @@ void nsIPresShell::NotifyStyleSheetServi
     default:
       MOZ_ASSERT_UNREACHABLE("unexpected aSheetType value");
       break;
   }
 }
 
 void nsIPresShell::NotifyStyleSheetServiceSheetRemoved(StyleSheet* aSheet,
                                                        uint32_t aSheetType) {
-  if (!mStyleSet) {
-    return;
-  }
-
   RemoveSheet(ToSheetType(aSheetType), aSheet);
 }
 
 nsIContent* PresShell::EventHandler::GetOverrideClickTarget(
     WidgetGUIEvent* aGUIEvent, nsIFrame* aFrame) {
   if (aGUIEvent->mMessage != eMouseUp) {
     return nullptr;
   }
--- a/layout/base/PresShell.h
+++ b/layout/base/PresShell.h
@@ -59,27 +59,27 @@ typedef nsTHashtable<nsPtrHashKey<nsIFra
 // to get the pref for any reason.
 #define PAINTLOCK_EVENT_DELAY 5
 
 class PresShell final : public nsIPresShell,
                         public nsISelectionController,
                         public nsIObserver,
                         public nsSupportsWeakReference {
   typedef layers::FocusTarget FocusTarget;
+  typedef dom::Element Element;
 
  public:
   PresShell();
 
   // nsISupports
   NS_DECL_ISUPPORTS
 
   static bool AccessibleCaretEnabled(nsIDocShell* aDocShell);
 
-  void Init(Document* aDocument, nsPresContext* aPresContext,
-            nsViewManager* aViewManager, UniquePtr<ServoStyleSet> aStyleSet);
+  void Init(Document*, nsPresContext*, nsViewManager*);
   void Destroy() override;
 
   NS_IMETHOD GetSelectionFromScript(RawSelectionType aRawSelectionType,
                                     dom::Selection** aSelection) override;
   dom::Selection* GetSelection(RawSelectionType aRawSelectionType) override;
 
   dom::Selection* GetCurrentSelection(SelectionType aSelectionType) override;
 
--- a/layout/base/nsDocumentViewer.cpp
+++ b/layout/base/nsDocumentViewer.cpp
@@ -721,22 +721,18 @@ nsresult nsDocumentViewer::InitPresentat
   MOZ_ASSERT(!nsContentUtils::IsSafeToRunScript(),
              "InitPresentationStuff must only be called when scripts are "
              "blocked");
 
   if (GetIsPrintPreview()) return NS_OK;
 
   NS_ASSERTION(!mPresShell, "Someone should have destroyed the presshell!");
 
-  // Create the style set...
-  UniquePtr<ServoStyleSet> styleSet = CreateStyleSet(mDocument);
-
   // Now make the shell for the document
-  mPresShell = mDocument->CreatePresShell(mPresContext, mViewManager,
-                                          std::move(styleSet));
+  mPresShell = mDocument->CreatePresShell(mPresContext, mViewManager);
   if (!mPresShell) {
     return NS_ERROR_FAILURE;
   }
 
   if (aDoInitialReflow) {
     // Since Initialize() will create frames for *all* items
     // that are currently in the document tree, we need to flush
     // any pending notifications to prevent the content sink from
@@ -2286,91 +2282,16 @@ nsDocumentViewer::RequestWindowClose(boo
     mDeferredWindowClose = true;
   } else
 #endif
     *aCanClose = true;
 
   return NS_OK;
 }
 
-UniquePtr<ServoStyleSet> nsDocumentViewer::CreateStyleSet(Document* aDocument) {
-  // Make sure this does the same thing as PresShell::Add{User,Agent}Sheet wrt
-  // ordering.
-
-  // The document will fill in the document sheets when we create the presshell
-  auto cache = nsLayoutStylesheetCache::Singleton();
-  nsStyleSheetService* sheetService = nsStyleSheetService::GetInstance();
-
-  MOZ_ASSERT(sheetService,
-             "should never be creating a StyleSet after the style sheet "
-             "service has gone");
-
-  auto styleSet = MakeUnique<ServoStyleSet>();
-
-  // User sheets
-
-  for (StyleSheet* sheet : *sheetService->UserStyleSheets()) {
-    styleSet->AppendStyleSheet(SheetType::User, sheet);
-  }
-
-  StyleSheet* sheet = nsContentUtils::IsInChromeDocshell(aDocument)
-                          ? cache->GetUserChromeSheet()
-                          : cache->GetUserContentSheet();
-
-  if (sheet) {
-    styleSet->AppendStyleSheet(SheetType::User, sheet);
-  }
-
-  // Agent sheets
-
-  styleSet->AppendStyleSheet(SheetType::Agent, cache->UASheet());
-
-  if (MOZ_LIKELY(mDocument->NodeInfoManager()->MathMLEnabled())) {
-    styleSet->AppendStyleSheet(SheetType::Agent, cache->MathMLSheet());
-  }
-
-  if (MOZ_LIKELY(mDocument->NodeInfoManager()->SVGEnabled())) {
-    styleSet->AppendStyleSheet(SheetType::Agent, cache->SVGSheet());
-  }
-
-  styleSet->AppendStyleSheet(SheetType::Agent, cache->HTMLSheet());
-
-  // We don't add quirk.css here; nsPresContext::CompatibilityModeChanged will
-  // append it if needed.
-
-  if (nsLayoutUtils::ShouldUseNoFramesSheet(aDocument)) {
-    styleSet->AppendStyleSheet(SheetType::Agent, cache->NoFramesSheet());
-  }
-
-  if (nsLayoutUtils::ShouldUseNoScriptSheet(aDocument)) {
-    styleSet->AppendStyleSheet(SheetType::Agent, cache->NoScriptSheet());
-  }
-
-  styleSet->AppendStyleSheet(SheetType::Agent, cache->CounterStylesSheet());
-
-  // Load the minimal XUL rules for scrollbars and a few other XUL things
-  // that non-XUL (typically HTML) documents commonly use.
-  styleSet->AppendStyleSheet(SheetType::Agent, cache->MinimalXULSheet());
-
-  // Only load the full XUL sheet if we'll need it.
-  if (aDocument->LoadsFullXULStyleSheetUpFront()) {
-    styleSet->AppendStyleSheet(SheetType::Agent, cache->XULSheet());
-  }
-
-  styleSet->AppendStyleSheet(SheetType::Agent, cache->FormsSheet());
-  styleSet->AppendStyleSheet(SheetType::Agent, cache->ScrollbarsSheet());
-  styleSet->AppendStyleSheet(SheetType::Agent, cache->PluginProblemSheet());
-
-  for (StyleSheet* sheet : *sheetService->AgentStyleSheets()) {
-    styleSet->AppendStyleSheet(SheetType::Agent, sheet);
-  }
-
-  return styleSet;
-}
-
 NS_IMETHODIMP
 nsDocumentViewer::ClearHistoryEntry() {
   if (mDocument) {
     nsJSContext::PokeGC(JS::GCReason::PAGE_HIDE,
                         mDocument->GetWrapperPreserveColor(), NS_GC_DELAY * 2);
   }
 
   mSHEntry = nullptr;
--- a/layout/base/nsIDocumentViewerPrint.h
+++ b/layout/base/nsIDocumentViewerPrint.h
@@ -34,22 +34,16 @@ class nsIDocumentViewerPrint : public ns
   NS_DECLARE_STATIC_IID_ACCESSOR(NS_IDOCUMENT_VIEWER_PRINT_IID)
 
   virtual void SetIsPrinting(bool aIsPrinting) = 0;
   virtual bool GetIsPrinting() = 0;
 
   virtual void SetIsPrintPreview(bool aIsPrintPreview) = 0;
   virtual bool GetIsPrintPreview() = 0;
 
-  // The style set returned by CreateStyleSet is in the middle of an
-  // update batch so that the caller can add sheets to it if needed.
-  // Callers should call EndUpdate() on it when ready to use.
-  virtual mozilla::UniquePtr<mozilla::ServoStyleSet> CreateStyleSet(
-      mozilla::dom::Document* aDocument) = 0;
-
   /**
    * This is used by nsPagePrintTimer to make nsDocumentViewer::Destroy()
    * a no-op until printing is finished.  That prevents the nsDocumentViewer
    * and its document, presshell and prescontext from going away.
    */
   virtual void IncrementDestroyBlockedCount() = 0;
   virtual void DecrementDestroyBlockedCount() = 0;
 
@@ -77,18 +71,16 @@ NS_DEFINE_STATIC_IID_ACCESSOR(nsIDocumen
                               NS_IDOCUMENT_VIEWER_PRINT_IID)
 
 /* Use this macro when declaring classes that implement this interface. */
 #define NS_DECL_NSIDOCUMENTVIEWERPRINT                          \
   void SetIsPrinting(bool aIsPrinting) override;                \
   bool GetIsPrinting() override;                                \
   void SetIsPrintPreview(bool aIsPrintPreview) override;        \
   bool GetIsPrintPreview() override;                            \
-  mozilla::UniquePtr<mozilla::ServoStyleSet> CreateStyleSet(    \
-      mozilla::dom::Document* aDocument) override;              \
   void IncrementDestroyBlockedCount() override;                 \
   void DecrementDestroyBlockedCount() override;                 \
   void OnDonePrinting() override;                               \
   bool IsInitializedForPrintPreview() override;                 \
   void InitializeForPrintPreview() override;                    \
   void SetPrintPreviewPresentation(nsViewManager* aViewManager, \
                                    nsPresContext* aPresContext, \
                                    nsIPresShell* aPresShell) override;
--- a/layout/base/nsIPresShell.h
+++ b/layout/base/nsIPresShell.h
@@ -267,17 +267,17 @@ class nsIPresShell : public nsStubDocume
   /**
    * Set the document accessible for this pres shell.
    */
   void SetDocAccessible(mozilla::a11y::DocAccessible* aDocAccessible) {
     mDocAccessible = aDocAccessible;
   }
 #endif
 
-  mozilla::ServoStyleSet* StyleSet() const { return mStyleSet.get(); }
+  inline mozilla::ServoStyleSet* StyleSet() const;
 
   nsCSSFrameConstructor* FrameConstructor() const {
     return mFrameConstructor.get();
   }
 
   /* Enable/disable author style level. Disabling author style disables the
    * entire author level of the cascade, including the HTML preshint level.
    */
@@ -1773,18 +1773,16 @@ class nsIPresShell : public nsStubDocume
   void CancelPostedReflowCallbacks();
   void FlushPendingScrollAnchorAdjustments();
 
   void SetPendingVisualScrollUpdate(
       const nsPoint& aVisualViewportOffset,
       FrameMetrics::ScrollOffsetUpdateType aUpdateType);
 
 #ifdef DEBUG
-  mozilla::UniquePtr<mozilla::ServoStyleSet> CloneStyleSet(
-      mozilla::ServoStyleSet*);
   bool VerifyIncrementalReflow();
   void DoVerifyReflow();
   void VerifyHasDirtyRootAncestor(nsIFrame* aFrame);
   void ShowEventTargetDebug();
 
   bool mInVerifyReflow = false;
   // The reflow root under which we're currently reflowing.  Null when
   // not in reflow.
@@ -1852,19 +1850,18 @@ class nsIPresShell : public nsStubDocume
   // IMPORTANT: The ownership implicit in the following member variables
   // has been explicitly checked.  If you add any members to this class,
   // please make the ownership explicit (pinkerton, scc).
 
   // These are the same Document and PresContext owned by the DocViewer.
   // we must share ownership.
   RefPtr<Document> mDocument;
   RefPtr<nsPresContext> mPresContext;
-  // mStyleSet owns it but we maintain a ref, may be null
+  // The document's style set owns it but we maintain a ref, may be null.
   RefPtr<mozilla::StyleSheet> mPrefStyleSheet;
-  mozilla::UniquePtr<mozilla::ServoStyleSet> mStyleSet;
   mozilla::UniquePtr<nsCSSFrameConstructor> mFrameConstructor;
   nsViewManager* mViewManager;  // [WEAK] docViewer owns it so I don't have to
   nsPresArena<8192> mFrameArena;
   RefPtr<nsFrameSelection> mSelection;
   RefPtr<nsCaret> mCaret;
   RefPtr<nsCaret> mOriginalCaret;
   RefPtr<mozilla::AccessibleCaretEventHub> mAccessibleCaretEventHub;
   // Pointer into mFrameConstructor - this is purely so that GetRootFrame() can
--- a/layout/base/nsIPresShellInlines.h
+++ b/layout/base/nsIPresShellInlines.h
@@ -4,16 +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/. */
 
 #ifndef nsIPresShellInlines_h
 #define nsIPresShellInlines_h
 
 #include "mozilla/PresShell.h"
 #include "mozilla/dom/Document.h"
+#include "mozilla/dom/Element.h"
 
 void nsIPresShell::SetNeedLayoutFlush() {
   mNeedLayoutFlush = true;
   if (mozilla::dom::Document* doc = mDocument->GetDisplayDocument()) {
     if (mozilla::PresShell* shell = doc->GetPresShell()) {
       shell->mNeedLayoutFlush = true;
     }
   }
@@ -49,16 +50,20 @@ void nsIPresShell::SetNeedThrottledAnima
   mNeedThrottledAnimationFlush = true;
   if (mozilla::dom::Document* doc = mDocument->GetDisplayDocument()) {
     if (mozilla::PresShell* presShell = doc->GetPresShell()) {
       presShell->mNeedThrottledAnimationFlush = true;
     }
   }
 }
 
+mozilla::ServoStyleSet* nsIPresShell::StyleSet() const {
+  return mDocument->StyleSetForPresShellOrMediaQueryEvaluation();
+}
+
 namespace mozilla {
 
 /* static */
 inline void PresShell::EventHandler::OnPresShellDestroy(Document* aDocument) {
   if (sLastKeyDownEventTargetElement &&
       sLastKeyDownEventTargetElement->OwnerDoc() == aDocument) {
     sLastKeyDownEventTargetElement = nullptr;
   }
--- a/layout/base/nsPresContext.cpp
+++ b/layout/base/nsPresContext.cpp
@@ -842,54 +842,16 @@ nsRootPresContext* nsPresContext::GetRoo
   for (;;) {
     nsPresContext* parent = pc->GetParentPresContext();
     if (!parent) break;
     pc = parent;
   }
   return pc->IsRoot() ? static_cast<nsRootPresContext*>(pc) : nullptr;
 }
 
-void nsPresContext::CompatibilityModeChanged() {
-  if (!mShell) {
-    return;
-  }
-
-  ServoStyleSet* styleSet = mShell->StyleSet();
-  styleSet->CompatibilityModeChanged();
-
-  mShell->EnsureStyleFlush();
-
-  if (mDocument->IsSVGDocument()) {
-    // SVG documents never load quirk.css.
-    return;
-  }
-
-  bool needsQuirkSheet = CompatibilityMode() == eCompatibility_NavQuirks;
-  if (mQuirkSheetAdded == needsQuirkSheet) {
-    return;
-  }
-
-  auto cache = nsLayoutStylesheetCache::Singleton();
-  StyleSheet* sheet = cache->QuirkSheet();
-
-  if (needsQuirkSheet) {
-    // quirk.css needs to come after html.css; we just keep it at the end.
-    DebugOnly<nsresult> rv =
-        styleSet->AppendStyleSheet(SheetType::Agent, sheet);
-    NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "failed to insert quirk.css");
-  } else {
-    DebugOnly<nsresult> rv =
-        styleSet->RemoveStyleSheet(SheetType::Agent, sheet);
-    NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "failed to remove quirk.css");
-  }
-
-  mQuirkSheetAdded = needsQuirkSheet;
-  mShell->ApplicableStylesChanged();
-}
-
 // Helper function for setting Anim Mode on image
 static void SetImgAnimModeOnImgReq(imgIRequest* aImgReq, uint16_t aMode) {
   if (aImgReq) {
     nsCOMPtr<imgIContainer> imgCon;
     aImgReq->GetImage(getter_AddRefs(imgCon));
     if (imgCon) {
       imgCon->SetAnimationMode(aMode);
     }
--- a/layout/base/nsPresContext.h
+++ b/layout/base/nsPresContext.h
@@ -290,21 +290,16 @@ class nsPresContext : public nsISupports
 
   /**
    * Access compatibility mode for this context.  This is the same as
    * our document's compatibility mode.
    */
   nsCompatibility CompatibilityMode() const;
 
   /**
-   * Notify the context that the document's compatibility mode has changed
-   */
-  void CompatibilityModeChanged();
-
-  /**
    * Access the image animation mode for this context
    */
   uint16_t ImageAnimationMode() const { return mImageAnimationMode; }
   void SetImageAnimationMode(uint16_t aMode);
 
   /**
    * Get medium of presentation
    */
--- a/layout/base/nsPresContextInlines.h
+++ b/layout/base/nsPresContextInlines.h
@@ -1,21 +1,21 @@
 /* -*- 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 nsIPresContextInlines_h
-#define nsIPresContextInlines_h
+#ifndef nsPresContextInlines_h
+#define nsPresContextInlines_h
 
 #include "mozilla/PresShell.h"
 #include "nsCSSFrameConstructor.h"
 
 inline mozilla::ServoStyleSet* nsPresContext::StyleSet() const {
-  return GetPresShell()->StyleSet();
+  return mDocument->StyleSetForPresShellOrMediaQueryEvaluation();
 }
 
 inline nsCSSFrameConstructor* nsPresContext::FrameConstructor() {
   return PresShell()->FrameConstructor();
 }
 
-#endif  // #ifndef nsIPresContextInlines_h
+#endif  // #ifndef nsPresContextInlines_h
--- a/layout/base/nsStyleSheetService.cpp
+++ b/layout/base/nsStyleSheetService.cpp
@@ -19,16 +19,17 @@
 #include "nsIURI.h"
 #include "nsCOMPtr.h"
 #include "nsICategoryManager.h"
 #include "nsISupportsPrimitives.h"
 #include "nsISimpleEnumerator.h"
 #include "nsNetUtil.h"
 #include "nsIConsoleService.h"
 #include "nsIObserverService.h"
+#include "nsIPresShellInlines.h"
 #include "nsLayoutStatics.h"
 #include "nsLayoutUtils.h"
 
 using namespace mozilla;
 
 nsStyleSheetService* nsStyleSheetService::gInstance = nullptr;
 
 nsStyleSheetService::nsStyleSheetService() {
--- a/layout/inspector/InspectorUtils.cpp
+++ b/layout/inspector/InspectorUtils.cpp
@@ -13,16 +13,17 @@
 #include "nsArray.h"
 #include "nsAutoPtr.h"
 #include "nsIServiceManager.h"
 #include "nsString.h"
 #include "nsIStyleSheetLinkingElement.h"
 #include "nsIContentInlines.h"
 #include "mozilla/dom/Document.h"
 #include "nsIDOMWindow.h"
+#include "nsIPresShellInlines.h"
 #include "nsXBLBinding.h"
 #include "nsXBLPrototypeBinding.h"
 #include "nsIMutableArray.h"
 #include "nsBindingManager.h"
 #include "ChildIterator.h"
 #include "nsComputedDOMStyle.h"
 #include "mozilla/EventStateManager.h"
 #include "nsAtom.h"
--- a/layout/printing/nsPrintJob.cpp
+++ b/layout/printing/nsPrintJob.cpp
@@ -2230,21 +2230,18 @@ nsresult nsPrintJob::ReflowPrintObject(c
   nsresult rv = aPO->mPresContext->Init(printData->mPrintDC);
   NS_ENSURE_SUCCESS(rv, rv);
 
   aPO->mViewManager = new nsViewManager();
 
   rv = aPO->mViewManager->Init(printData->mPrintDC);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  UniquePtr<ServoStyleSet> styleSet =
-      mDocViewerPrint->CreateStyleSet(aPO->mDocument);
-
-  aPO->mPresShell = aPO->mDocument->CreatePresShell(
-      aPO->mPresContext, aPO->mViewManager, std::move(styleSet));
+  aPO->mPresShell =
+      aPO->mDocument->CreatePresShell(aPO->mPresContext, aPO->mViewManager);
   if (!aPO->mPresShell) {
     return NS_ERROR_FAILURE;
   }
 
   // If we're printing selection then remove the unselected nodes from our
   // cloned document.
   int16_t printRangeType = nsIPrintSettings::kRangeAllPages;
   printData->mPrintSettings->GetPrintRange(&printRangeType);
--- a/layout/style/Loader.cpp
+++ b/layout/style/Loader.cpp
@@ -364,18 +364,19 @@ Loader::Loader()
       mSyncCallback(false)
 #endif
 {
 }
 
 Loader::Loader(DocGroup* aDocGroup) : Loader() { mDocGroup = aDocGroup; }
 
 Loader::Loader(Document* aDocument) : Loader() {
+  MOZ_ASSERT(aDocument, "We should get a valid document from the caller!");
   mDocument = aDocument;
-  MOZ_ASSERT(mDocument, "We should get a valid document from the caller!");
+  mCompatMode = aDocument->GetCompatibilityMode();
 }
 
 Loader::~Loader() {
   NS_ASSERTION(!mSheets || mSheets->mLoadingDatas.Count() == 0,
                "How did we get destroyed when there are loading data?");
   NS_ASSERTION(!mSheets || mSheets->mPendingDatas.Count() == 0,
                "How did we get destroyed when there are pending data?");
   // Note: no real need to revoke our stylesheet loaded events -- they
--- a/layout/style/MediaFeatureChange.h
+++ b/layout/style/MediaFeatureChange.h
@@ -39,16 +39,18 @@ enum class MediaFeatureChangeReason {
   // display-mode changed on the document, thus the display-mode media queries
   // may have changed.
   DisplayModeChange = 1 << 7,
 };
 
 MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(MediaFeatureChangeReason)
 
 struct MediaFeatureChange {
+  static const auto kAllChanges = static_cast<MediaFeatureChangeReason>(~0);
+
   RestyleHint mRestyleHint;
   nsChangeHint mChangeHint;
   MediaFeatureChangeReason mReason;
 
   MOZ_IMPLICIT MediaFeatureChange(MediaFeatureChangeReason aReason)
       : MediaFeatureChange(RestyleHint{0}, nsChangeHint(0), aReason) {}
 
   MediaFeatureChange(RestyleHint aRestyleHint, nsChangeHint aChangeHint,
--- a/layout/style/ServoStyleSet.cpp
+++ b/layout/style/ServoStyleSet.cpp
@@ -87,67 +87,39 @@ class MOZ_RAII AutoPrepareTraversal {
 
  private:
   AutoRestyleTimelineMarker mTimelineMarker;
   AutoSetInServoTraversal mSetInServoTraversal;
 };
 
 }  // namespace mozilla
 
-ServoStyleSet::ServoStyleSet()
-    : mDocument(nullptr),
+ServoStyleSet::ServoStyleSet(Document& aDocument)
+    : mDocument(&aDocument),
       mAuthorStyleDisabled(false),
       mStylistState(StylistState::NotDirty),
       mUserFontSetUpdateGeneration(0),
-      mNeedsRestyleAfterEnsureUniqueInner(false) {}
+      mNeedsRestyleAfterEnsureUniqueInner(false) {
+  PreferenceSheet::EnsureInitialized();
+  mRawSet.reset(Servo_StyleSet_Init(&aDocument));
+}
 
 ServoStyleSet::~ServoStyleSet() {
   for (auto& sheetArray : mSheets) {
     for (auto& sheet : sheetArray) {
       sheet->DropStyleSet(this);
     }
   }
 }
 
 nsPresContext* ServoStyleSet::GetPresContext() {
-  if (!mDocument) {
-    return nullptr;
-  }
-
   return mDocument->GetPresContext();
 }
 
-void ServoStyleSet::Init(nsPresContext* aPresContext) {
-  mDocument = aPresContext->Document();
-  MOZ_ASSERT(GetPresContext() == aPresContext);
-
-  mRawSet.reset(Servo_StyleSet_Init(aPresContext));
-
-  aPresContext->DeviceContext()->InitFontCache();
-
-  // Now that we have an mRawSet, go ahead and notify about whatever stylesheets
-  // we have so far.
-  for (auto& sheetArray : mSheets) {
-    for (auto& sheet : sheetArray) {
-      // There's no guarantee this will create a list on the servo side whose
-      // ordering matches the list that would have been created had all those
-      // sheets been appended/prepended/etc after we had mRawSet. That's okay
-      // because Servo only needs to maintain relative ordering within a sheet
-      // type, which this preserves.
-
-      MOZ_ASSERT(sheet->RawContents(),
-                 "We should only append non-null raw sheets.");
-      Servo_StyleSet_AppendStyleSheet(mRawSet.get(), sheet);
-    }
-  }
-
-  // We added prefilled stylesheets into mRawSet, so the stylist is dirty.
-  // The Stylist should be updated later when necessary.
-  SetStylistStyleSheetsDirty();
-
+void ServoStyleSet::ShellAttachedToDocument() {
   // We may have Shadow DOM style changes that we weren't notified about because
   // the document didn't have a shell, if the ShadowRoot was created in a
   // display: none iframe.
   //
   // Now that we got a shell, we may need to get them up-to-date.
   //
   // TODO(emilio, bug 1418159): This wouldn't be needed if the StyleSet was
   // owned by the document.
@@ -160,21 +132,20 @@ void EnumerateShadowRoots(const Document
   for (auto iter = shadowRoots.ConstIter(); !iter.Done(); iter.Next()) {
     ShadowRoot* root = iter.Get()->GetKey();
     MOZ_ASSERT(root);
     MOZ_DIAGNOSTIC_ASSERT(root->IsInComposedDoc());
     aCb(*root);
   }
 }
 
-void ServoStyleSet::Shutdown() {
+void ServoStyleSet::ShellDetachedFromDocument() {
   // Make sure we drop our cached styles before the presshell arena starts going
   // away.
   ClearNonInheritingComputedStyles();
-  mRawSet = nullptr;
   mStyleRuleMap = nullptr;
 }
 
 void ServoStyleSet::RecordShadowStyleChange(ShadowRoot& aShadowRoot) {
   // TODO(emilio): We could keep track of the actual shadow roots that need
   // their styles recomputed.
   SetStylistXBLStyleSheetsDirty();
 
@@ -625,41 +596,38 @@ nsresult ServoStyleSet::AppendStyleSheet
   MOZ_ASSERT(aSheet->IsApplicable());
   MOZ_ASSERT(IsCSSSheetType(aType));
   MOZ_ASSERT(aSheet->RawContents(),
              "Raw sheet should be in place before insertion.");
 
   RemoveSheetOfType(aType, aSheet);
   AppendSheetOfType(aType, aSheet);
 
-  if (mRawSet) {
-    // Maintain a mirrored list of sheets on the servo side.
-    // Servo will remove aSheet from its original position as part of the call
-    // to Servo_StyleSet_AppendStyleSheet.
-    Servo_StyleSet_AppendStyleSheet(mRawSet.get(), aSheet);
-    SetStylistStyleSheetsDirty();
-  }
+  // Maintain a mirrored list of sheets on the servo side.
+  // Servo will remove aSheet from its original position as part of the call
+  // to Servo_StyleSet_AppendStyleSheet.
+  Servo_StyleSet_AppendStyleSheet(mRawSet.get(), aSheet);
+  SetStylistStyleSheetsDirty();
 
   if (mStyleRuleMap) {
     mStyleRuleMap->SheetAdded(*aSheet);
   }
 
   return NS_OK;
 }
 
 nsresult ServoStyleSet::RemoveStyleSheet(SheetType aType, StyleSheet* aSheet) {
   MOZ_ASSERT(aSheet);
   MOZ_ASSERT(IsCSSSheetType(aType));
 
   RemoveSheetOfType(aType, aSheet);
-  if (mRawSet) {
-    // Maintain a mirrored list of sheets on the servo side.
-    Servo_StyleSet_RemoveStyleSheet(mRawSet.get(), aSheet);
-    SetStylistStyleSheetsDirty();
-  }
+
+  // Maintain a mirrored list of sheets on the servo side.
+  Servo_StyleSet_RemoveStyleSheet(mRawSet.get(), aSheet);
+  SetStylistStyleSheetsDirty();
 
   if (mStyleRuleMap) {
     mStyleRuleMap->SheetRemoved(*aSheet);
   }
 
   return NS_OK;
 }
 
@@ -670,30 +638,26 @@ nsresult ServoStyleSet::ReplaceSheets(
   // to express. If the need ever arises, we can easily make this more efficent,
   // probably by aligning the representations better between engines.
 
   SetStylistStyleSheetsDirty();
 
   // Remove all the existing sheets first.
   for (const auto& sheet : mSheets[aType]) {
     sheet->DropStyleSet(this);
-    if (mRawSet) {
-      Servo_StyleSet_RemoveStyleSheet(mRawSet.get(), sheet);
-    }
+    Servo_StyleSet_RemoveStyleSheet(mRawSet.get(), sheet);
   }
   mSheets[aType].Clear();
 
   // Add in all the new sheets.
   for (auto& sheet : aNewSheets) {
     AppendSheetOfType(aType, sheet);
-    if (mRawSet) {
-      MOZ_ASSERT(sheet->RawContents(),
-                 "Raw sheet should be in place before replacement.");
-      Servo_StyleSet_AppendStyleSheet(mRawSet.get(), sheet);
-    }
+    MOZ_ASSERT(sheet->RawContents(),
+               "Raw sheet should be in place before replacement.");
+    Servo_StyleSet_AppendStyleSheet(mRawSet.get(), sheet);
   }
 
   // Just don't bother calling SheetRemoved / SheetAdded, and recreate the rule
   // map when needed.
   mStyleRuleMap = nullptr;
   return NS_OK;
 }
 
@@ -709,22 +673,20 @@ nsresult ServoStyleSet::InsertStyleSheet
   MOZ_ASSERT(aReferenceSheet->RawContents(),
              "Reference sheet should have a raw sheet.");
 
   // Servo will remove aNewSheet from its original position as part of the
   // call to Servo_StyleSet_InsertStyleSheetBefore.
   RemoveSheetOfType(aType, aNewSheet);
   InsertSheetOfType(aType, aNewSheet, aReferenceSheet);
 
-  if (mRawSet) {
-    // Maintain a mirrored list of sheets on the servo side.
-    Servo_StyleSet_InsertStyleSheetBefore(mRawSet.get(), aNewSheet,
-                                          aReferenceSheet);
-    SetStylistStyleSheetsDirty();
-  }
+  // Maintain a mirrored list of sheets on the servo side.
+  Servo_StyleSet_InsertStyleSheetBefore(mRawSet.get(), aNewSheet,
+                                        aReferenceSheet);
+  SetStylistStyleSheetsDirty();
 
   if (mStyleRuleMap) {
     mStyleRuleMap->SheetAdded(*aNewSheet);
   }
 
   return NS_OK;
 }
 
@@ -767,30 +729,26 @@ nsresult ServoStyleSet::AddDocStyleSheet
   size_t index = aDocument->FindDocStyleSheetInsertionPoint(
       mSheets[SheetType::Doc], *aSheet);
 
   if (index < mSheets[SheetType::Doc].Length()) {
     // This case is insert before.
     StyleSheet* beforeSheet = mSheets[SheetType::Doc][index];
     InsertSheetOfType(SheetType::Doc, aSheet, beforeSheet);
 
-    if (mRawSet) {
-      // Maintain a mirrored list of sheets on the servo side.
-      Servo_StyleSet_InsertStyleSheetBefore(mRawSet.get(), aSheet, beforeSheet);
-      SetStylistStyleSheetsDirty();
-    }
+    // Maintain a mirrored list of sheets on the servo side.
+    Servo_StyleSet_InsertStyleSheetBefore(mRawSet.get(), aSheet, beforeSheet);
+    SetStylistStyleSheetsDirty();
   } else {
     // This case is append.
     AppendSheetOfType(SheetType::Doc, aSheet);
 
-    if (mRawSet) {
-      // Maintain a mirrored list of sheets on the servo side.
-      Servo_StyleSet_AppendStyleSheet(mRawSet.get(), aSheet);
-      SetStylistStyleSheetsDirty();
-    }
+    // Maintain a mirrored list of sheets on the servo side.
+    Servo_StyleSet_AppendStyleSheet(mRawSet.get(), aSheet);
+    SetStylistStyleSheetsDirty();
   }
 
   if (mStyleRuleMap) {
     mStyleRuleMap->SheetAdded(*aSheet);
   }
 
   return NS_OK;
 }
@@ -965,20 +923,16 @@ void ServoStyleSet::StyleNewSubtree(Elem
         aRoot, mRawSet.get(), &snapshots,
         ServoTraversalFlags::AnimationOnly | ServoTraversalFlags::Forgetful |
             ServoTraversalFlags::ClearAnimationOnlyDirtyDescendants);
     MOZ_ASSERT(!postTraversalRequired);
   }
 }
 
 void ServoStyleSet::MarkOriginsDirty(OriginFlags aChangedOrigins) {
-  if (MOZ_UNLIKELY(!mRawSet)) {
-    return;
-  }
-
   SetStylistStyleSheetsDirty();
   Servo_StyleSet_NoteStyleSheetsChanged(mRawSet.get(), aChangedOrigins);
 }
 
 void ServoStyleSet::SetStylistStyleSheetsDirty() {
   // Note that there's another hidden mutator of mStylistState for XBL style
   // sets in MediumFeaturesChanged...
   //
--- a/layout/style/ServoStyleSet.h
+++ b/layout/style/ServoStyleSet.h
@@ -90,22 +90,21 @@ class ServoStyleSet {
   // Used for debug assertions. We make this debug-only to prevent callers from
   // accidentally using it instead of IsInServoTraversal, which is cheaper. We
   // can change this if a use-case arises.
   static bool IsCurrentThreadInServoTraversal();
 #endif
 
   static ServoStyleSet* Current() { return sInServoTraversal; }
 
-  ServoStyleSet();
+  explicit ServoStyleSet(dom::Document&);
   ~ServoStyleSet();
 
-  void Init(nsPresContext* aPresContext);
-  void BeginShutdown() {}
-  void Shutdown();
+  void ShellAttachedToDocument();
+  void ShellDetachedFromDocument();
 
   // Called when a rules in a stylesheet in this set, or a child sheet of that,
   // are mutated from CSSOM.
   void RuleAdded(StyleSheet&, css::Rule&);
   void RuleRemoved(StyleSheet&, css::Rule&);
   void RuleChanged(StyleSheet& aSheet, css::Rule* aRule);
 
   // Runs style invalidation due to document state changes.
@@ -500,20 +499,18 @@ class ServoStyleSet {
 
   void AppendSheetOfType(SheetType aType, StyleSheet* aSheet);
 
   void InsertSheetOfType(SheetType aType, StyleSheet* aSheet,
                          StyleSheet* aBeforeSheet);
 
   void RemoveSheetOfType(SheetType aType, StyleSheet* aSheet);
 
-  // The owner document of this style set. Null if this is an XBL style set.
-  //
-  // TODO(emilio): This should become a DocumentOrShadowRoot, and be owned by it
-  // directly instead of the shell, eventually.
+  // The owner document of this style set. Never null, and always outlives the
+  // StyleSet.
   dom::Document* mDocument;
 
   const nsPresContext* GetPresContext() const {
     return const_cast<ServoStyleSet*>(this)->GetPresContext();
   }
 
   /**
    * Return the associated pres context if we're the master style set and we
--- a/servo/ports/geckolib/glue.rs
+++ b/servo/ports/geckolib/glue.rs
@@ -3512,24 +3512,18 @@ pub extern "C" fn Servo_ComputedValues_G
 
     rules.assign_from_iter_pod(result.into_iter().map(|src| {
         src.with_arc(|a| {
             a.with_raw_offset_arc(|arc| *Locked::<StyleRule>::arc_as_borrowed(arc) as *const _)
         })
     }))
 }
 
-/// See the comment in `Device` to see why it's ok to pass an owned reference to
-/// the pres context (hint: the context outlives the StyleSet, that holds the
-/// device alive).
-#[no_mangle]
-pub extern "C" fn Servo_StyleSet_Init(
-    pres_context: &structs::nsPresContext,
-) -> *mut RawServoStyleSet {
-    let doc = pres_context.mDocument.mRawPtr;
+#[no_mangle]
+pub extern "C" fn Servo_StyleSet_Init(doc: &structs::Document) -> *mut RawServoStyleSet {
     let data = Box::new(PerDocumentStyleData::new(doc));
     Box::into_raw(data) as *mut RawServoStyleSet
 }
 
 #[no_mangle]
 pub extern "C" fn Servo_StyleSet_RebuildCachedData(raw_data: &RawServoStyleSet) {
     let mut data = PerDocumentStyleData::from_ffi(raw_data).borrow_mut();
     data.stylist.device_mut().rebuild_cached_data();