Bug 1428491: Make the style set know about a document, not a pres context. r=heycam
☠☠ backed out by da9adac5500f ☠ ☠
authorEmilio Cobos Álvarez <emilio@crisal.io>
Fri, 05 Jan 2018 13:51:08 +0100
changeset 453711 dbfd798e491b86e55ec11b8d5cccc260e885f619
parent 453710 3fa7cfb635b74eec51e67549b2b06214f6fba749
child 453712 308e79e6c98f0f38c3c7c1652fd6ceae35a12955
push id1648
push usermtabara@mozilla.com
push dateThu, 01 Mar 2018 12:45:47 +0000
treeherdermozilla-release@cbb9688c2eeb [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersheycam
bugs1428491
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 1428491: Make the style set know about a document, not a pres context. r=heycam MozReview-Commit-ID: I7T41NiHuJv
dom/base/nsDocument.cpp
layout/style/ServoStyleSet.cpp
layout/style/ServoStyleSet.h
--- a/dom/base/nsDocument.cpp
+++ b/dom/base/nsDocument.cpp
@@ -4019,20 +4019,19 @@ nsDocument::CreateShell(nsPresContext* a
       if (node->IsElement()) {
         MOZ_ASSERT(!node->AsElement()->HasServoData());
       }
     }
 #endif
   }
 
   RefPtr<PresShell> shell = new PresShell;
-  shell->Init(this, aContext, aViewManager, aStyleSet);
-
   // Note: we don't hold a ref to the shell (it holds a ref to us)
   mPresShell = shell;
+  shell->Init(this, aContext, aViewManager, aStyleSet);
 
   // Make sure to never paint if we belong to an invisible DocShell.
   nsCOMPtr<nsIDocShell> docShell(mDocumentContainer);
   if (docShell && docShell->IsInvisible())
     shell->SetNeverPainting(true);
 
   MOZ_LOG(gDocumentLeakPRLog, LogLevel::Debug, ("DOCUMENT %p with PressShell %p and DocShell %p",
                                                 this, shell.get(), docShell.get()));
--- a/layout/style/ServoStyleSet.cpp
+++ b/layout/style/ServoStyleSet.cpp
@@ -76,32 +76,32 @@ private:
 // Sets up for one or more calls to Servo_TraverseSubtree.
 class MOZ_RAII AutoPrepareTraversal
 {
 public:
   explicit AutoPrepareTraversal(ServoStyleSet* aSet)
     // For markers for animations, we have already set the markers in
     // ServoRestyleManager::PostRestyleEventForAnimations so that we don't need
     // to care about animation restyles here.
-    : mTimelineMarker(aSet->mPresContext->GetDocShell(), false)
+    : mTimelineMarker(aSet->mDocument->GetDocShell(), false)
     , mSetInServoTraversal(aSet)
   {
     MOZ_ASSERT(!aSet->StylistNeedsUpdate());
   }
 
 private:
   AutoRestyleTimelineMarker mTimelineMarker;
   AutoSetInServoTraversal mSetInServoTraversal;
 };
 
 } // namespace mozilla
 
 ServoStyleSet::ServoStyleSet(Kind aKind)
   : mKind(aKind)
-  , mPresContext(nullptr)
+  , mDocument(nullptr)
   , mAuthorStyleDisabled(false)
   , mStylistState(StylistState::NotDirty)
   , mUserFontSetUpdateGeneration(0)
   , mUserFontCacheUpdateGeneration(0)
   , mNeedsRestyleAfterEnsureUniqueInner(false)
 {
 }
 
@@ -126,34 +126,50 @@ ServoStyleSet::CreateXBLServoStyleSet(
   // decide a particular SheetType to add them to style set. This type
   // doesn't affect the place where we pull those rules from
   // stylist::push_applicable_declarations_as_xbl_only_stylist().
   set->ReplaceSheets(SheetType::Doc, aNewSheets);
 
   // Update stylist immediately.
   set->UpdateStylist();
 
-  // The PresContext of the bound document could be destroyed anytime later,
-  // which shouldn't be used for XBL styleset, so we clear it here to avoid
-  // dangling pointer.
-  set->mPresContext = nullptr;
+  // XBL resources are shared for a given URL, even across documents, so we
+  // can't safely keep this reference.
+  set->mDocument = nullptr;
 
   return set;
 }
 
+nsPresContext*
+ServoStyleSet::GetPresContext()
+{
+  if (!mDocument) {
+    return nullptr;
+  }
+
+  auto* shell = mDocument->GetShell();
+  if (!shell) {
+    return nullptr;
+  }
+
+  return shell->GetPresContext();
+}
+
 void
 ServoStyleSet::Init(nsPresContext* aPresContext, nsBindingManager* aBindingManager)
 {
-  mPresContext = aPresContext;
+  mDocument = aPresContext->Document();
+  MOZ_ASSERT(GetPresContext() == aPresContext);
+
   mLastPresContextUsesXBLStyleSet = aPresContext;
 
   mRawSet.reset(Servo_StyleSet_Init(aPresContext));
   mBindingManager = aBindingManager;
 
-  mPresContext->DeviceContext()->InitFontCache();
+  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
@@ -174,29 +190,25 @@ ServoStyleSet::Init(nsPresContext* aPres
 void
 ServoStyleSet::Shutdown()
 {
   // Make sure we drop our cached style contexts before the presshell arena
   // starts going away.
   ClearNonInheritingStyleContexts();
   mRawSet = nullptr;
   mStyleRuleMap = nullptr;
-
-  // Also drop the reference to the pres context to avoid notifications from our
-  // stylesheets to dereference a null restyle manager, see bug 1422634.
-  //
-  // We should really fix bug 154199...
-  mPresContext = nullptr;
 }
 
 void
 ServoStyleSet::InvalidateStyleForCSSRuleChanges()
 {
   MOZ_ASSERT(StylistNeedsUpdate());
-  mPresContext->RestyleManager()->AsServo()->PostRestyleEventForCSSRuleChanges();
+  if (nsPresContext* pc = GetPresContext()) {
+    pc->RestyleManager()->AsServo()->PostRestyleEventForCSSRuleChanges();
+  }
 }
 
 bool
 ServoStyleSet::SetPresContext(nsPresContext* aPresContext)
 {
   MOZ_ASSERT(IsForXBL(), "Only XBL styleset can set PresContext!");
 
   mLastPresContextUsesXBLStyleSet = aPresContext;
@@ -213,20 +225,22 @@ ServoStyleSet::SetPresContext(nsPresCont
 }
 
 nsRestyleHint
 ServoStyleSet::MediumFeaturesChanged(bool aViewportChanged)
 {
   bool viewportUnitsUsed = false;
   bool rulesChanged = MediumFeaturesChangedRules(&viewportUnitsUsed);
 
-  if (mBindingManager &&
-      mBindingManager->MediumFeaturesChanged(mPresContext)) {
-    SetStylistXBLStyleSheetsDirty();
-    rulesChanged = true;
+  if (nsPresContext* pc = GetPresContext()) {
+    if (mDocument->BindingManager()->MediumFeaturesChanged(pc)) {
+      // TODO(emilio): We could technically just restyle the bound elements.
+      SetStylistXBLStyleSheetsDirty();
+      rulesChanged = true;
+    }
   }
 
   if (rulesChanged) {
     return eRestyle_Subtree;
   }
 
   if (viewportUnitsUsed && aViewportChanged) {
     return eRestyle_ForceDescendants;
@@ -291,17 +305,17 @@ ServoStyleSet::AddSizeOfIncludingThis(ns
   }
 
   // Measurement of the following members may be added later if DMD finds it is
   // worthwhile:
   // - mSheets
   // - mNonInheritingStyleContexts
   //
   // The following members are not measured:
-  // - mPresContext, because it a non-owning pointer
+  // - mDocument, because it a non-owning pointer
 }
 
 bool
 ServoStyleSet::GetAuthorStyleDisabled() const
 {
   return mAuthorStyleDisabled;
 }
 
@@ -341,48 +355,52 @@ ServoStyleSet::ResolveStyleFor(Element* 
   }
 
   return ResolveServoStyle(aElement);
 }
 
 const ServoElementSnapshotTable&
 ServoStyleSet::Snapshots()
 {
-  return mPresContext->RestyleManager()->AsServo()->Snapshots();
+  MOZ_ASSERT(GetPresContext(), "Styling a document without a shell?");
+  return GetPresContext()->RestyleManager()->AsServo()->Snapshots();
 }
 
 void
 ServoStyleSet::ResolveMappedAttrDeclarationBlocks()
 {
-  if (nsHTMLStyleSheet* sheet = mPresContext->Document()->GetAttributeStyleSheet()) {
+  if (nsHTMLStyleSheet* sheet = mDocument->GetAttributeStyleSheet()) {
     sheet->CalculateMappedServoDeclarations();
   }
 
-  mPresContext->Document()->ResolveScheduledSVGPresAttrs();
+  mDocument->ResolveScheduledSVGPresAttrs();
 }
 
 void
 ServoStyleSet::PreTraverseSync()
 {
   // Get the Document's root element to ensure that the cache is valid before
   // calling into the (potentially-parallel) Servo traversal, where a cache hit
   // is necessary to avoid a data race when updating the cache.
-  mozilla::Unused << mPresContext->Document()->GetRootElement();
+  mozilla::Unused << mDocument->GetRootElement();
 
   ResolveMappedAttrDeclarationBlocks();
 
   nsMediaFeatures::InitSystemMetrics();
 
   LookAndFeel::NativeInit();
 
-  if (gfxUserFontSet* userFontSet = mPresContext->Document()->GetUserFontSet()) {
+  nsPresContext* presContext = GetPresContext();
+  MOZ_ASSERT(presContext,
+             "For now, we don't call into here without a pres context");
+  if (gfxUserFontSet* userFontSet = mDocument->GetUserFontSet()) {
     // Ensure that the @font-face data is not stale
     uint64_t generation = userFontSet->GetGeneration();
     if (generation != mUserFontSetUpdateGeneration) {
-      mPresContext->DeviceContext()->UpdateFontCacheUserFonts(userFontSet);
+      presContext->DeviceContext()->UpdateFontCacheUserFonts(userFontSet);
       mUserFontSetUpdateGeneration = generation;
     }
 
     // Ensure that the FontFaceSet's cached document principal is up to date.
     FontFaceSet* fontFaceSet =
       static_cast<FontFaceSet::UserFontSet*>(userFontSet)->GetFontFaceSet();
     fontFaceSet->UpdateStandardFontLoadPrincipal();
     bool principalChanged = fontFaceSet->HasStandardFontLoadPrincipalChanged();
@@ -395,39 +413,39 @@ ServoStyleSet::PreTraverseSync()
     }
     if (cacheGeneration != mUserFontCacheUpdateGeneration || principalChanged) {
       gfxUserFontSet::UserFontCache::UpdateAllowedFontSets(userFontSet);
       mUserFontCacheUpdateGeneration = cacheGeneration;
     }
   }
 
   UpdateStylistIfNeeded();
-  mPresContext->CacheAllLangs();
+  presContext->CacheAllLangs();
 }
 
 void
 ServoStyleSet::PreTraverse(ServoTraversalFlags aFlags, Element* aRoot)
 {
   PreTraverseSync();
 
   // Process animation stuff that we should avoid doing during the parallel
   // traversal.
   nsSMILAnimationController* smilController =
-    mPresContext->Document()->HasAnimationController()
-    ? mPresContext->Document()->GetAnimationController()
+    mDocument->HasAnimationController()
+    ? mDocument->GetAnimationController()
     : nullptr;
 
+  MOZ_ASSERT(GetPresContext());
   if (aRoot) {
-    mPresContext->EffectCompositor()
-                ->PreTraverseInSubtree(aFlags, aRoot);
+    GetPresContext()->EffectCompositor()->PreTraverseInSubtree(aFlags, aRoot);
     if (smilController) {
       smilController->PreTraverseInSubtree(aRoot);
     }
   } else {
-    mPresContext->EffectCompositor()->PreTraverse(aFlags);
+    GetPresContext()->EffectCompositor()->PreTraverse(aFlags);
     if (smilController) {
       smilController->PreTraverse();
     }
   }
 }
 
 static inline already_AddRefed<ServoStyleContext>
 ResolveStyleForTextOrFirstLetterContinuation(
@@ -916,60 +934,61 @@ ServoStyleSet::ProbePseudoElementStyle(E
   }
 
   return computedValues.forget();
 }
 
 bool
 ServoStyleSet::StyleDocument(ServoTraversalFlags aFlags)
 {
-  nsIDocument* doc = mPresContext->Document();
-  if (!doc->GetServoRestyleRoot()) {
+  MOZ_ASSERT(GetPresContext(), "Styling a document without a shell?");
+
+  if (!mDocument->GetServoRestyleRoot()) {
     return false;
   }
 
   PreTraverse(aFlags);
   AutoPrepareTraversal guard(this);
   const SnapshotTable& snapshots = Snapshots();
 
   // Restyle the document from the root element and each of the document level
   // NAC subtree roots.
   bool postTraversalRequired = false;
 
-  Element* rootElement = doc->GetRootElement();
+  Element* rootElement = mDocument->GetRootElement();
   MOZ_ASSERT_IF(rootElement, rootElement->HasServoData());
 
   if (ShouldTraverseInParallel()) {
     aFlags |= ServoTraversalFlags::ParallelTraversal;
   }
 
   // Do the first traversal.
-  DocumentStyleRootIterator iter(doc->GetServoRestyleRoot());
+  DocumentStyleRootIterator iter(mDocument->GetServoRestyleRoot());
   while (Element* root = iter.GetNextStyleRoot()) {
     MOZ_ASSERT(MayTraverseFrom(root));
 
     Element* parent = root->GetFlattenedTreeParentElementForStyle();
     MOZ_ASSERT_IF(parent,
                   !parent->HasAnyOfFlags(Element::kAllServoDescendantBits));
 
     postTraversalRequired |=
       Servo_TraverseSubtree(root, mRawSet.get(), &snapshots, aFlags);
     postTraversalRequired |=
       root->HasAnyOfFlags(Element::kAllServoDescendantBits | NODE_NEEDS_FRAME);
 
     if (parent) {
-      MOZ_ASSERT(root == doc->GetServoRestyleRoot());
+      MOZ_ASSERT(root == mDocument->GetServoRestyleRoot());
       if (parent->HasDirtyDescendantsForServo()) {
         // If any style invalidation was triggered in our siblings, then we may
         // need to post-traverse them, even if the root wasn't restyled after
         // all.
-        uint32_t existingBits = doc->GetServoRestyleRootDirtyBits();
+        uint32_t existingBits = mDocument->GetServoRestyleRootDirtyBits();
         // We need to propagate the existing bits to the parent.
         parent->SetFlags(existingBits);
-        doc->SetServoRestyleRoot(
+        mDocument->SetServoRestyleRoot(
             parent,
             existingBits | ELEMENT_HAS_DIRTY_DESCENDANTS_FOR_SERVO);
         postTraversalRequired = true;
       }
     }
   }
 
   // If there are still animation restyles needed, trigger a second traversal to
@@ -979,32 +998,33 @@ ServoStyleSet::StyleDocument(ServoTraver
   // PreTraverse on the EffectCompositor might alter the style root. But we
   // don't need to worry about NAC, since document-level NAC shouldn't have
   // animations.
   //
   // We don't need to do this for SMIL since SMIL only updates its animation
   // values once at the begin of a tick. As a result, even if the previous
   // traversal caused, for example, the font-size to change, the SMIL style
   // won't be updated until the next tick anyway.
-  if (mPresContext->EffectCompositor()->PreTraverse(aFlags)) {
-    nsINode* styleRoot = doc->GetServoRestyleRoot();
+  if (GetPresContext()->EffectCompositor()->PreTraverse(aFlags)) {
+    nsINode* styleRoot = mDocument->GetServoRestyleRoot();
     Element* root = styleRoot->IsElement() ? styleRoot->AsElement() : rootElement;
 
     postTraversalRequired |=
       Servo_TraverseSubtree(root, mRawSet.get(), &snapshots, aFlags);
     postTraversalRequired |=
       root->HasAnyOfFlags(Element::kAllServoDescendantBits | NODE_NEEDS_FRAME);
   }
 
   return postTraversalRequired;
 }
 
 void
 ServoStyleSet::StyleNewSubtree(Element* aRoot)
 {
+  MOZ_ASSERT(GetPresContext());
   MOZ_ASSERT(!aRoot->HasServoData());
   PreTraverseSync();
   AutoPrepareTraversal guard(this);
 
   // Do the traversal. The snapshots will not be used.
   const SnapshotTable& snapshots = Snapshots();
   auto flags = ServoTraversalFlags::Empty;
   if (ShouldTraverseInParallel()) {
@@ -1014,17 +1034,17 @@ ServoStyleSet::StyleNewSubtree(Element* 
   DebugOnly<bool> postTraversalRequired =
     Servo_TraverseSubtree(aRoot, mRawSet.get(), &snapshots, flags);
   MOZ_ASSERT(!postTraversalRequired);
 
   // Annoyingly, the newly-styled content may have animations that need
   // starting, which requires traversing them again. Mark the elements
   // that need animation processing, then do a forgetful traversal to
   // update the styles and clear the animation bits.
-  if (mPresContext->EffectCompositor()->PreTraverseInSubtree(flags, aRoot)) {
+  if (GetPresContext()->EffectCompositor()->PreTraverseInSubtree(flags, aRoot)) {
     postTraversalRequired =
       Servo_TraverseSubtree(aRoot, mRawSet.get(), &snapshots,
                             ServoTraversalFlags::AnimationOnly |
                             ServoTraversalFlags::Forgetful |
                             ServoTraversalFlags::ClearAnimationOnlyDirtyDescendants);
     MOZ_ASSERT(!postTraversalRequired);
   }
 }
@@ -1045,33 +1065,34 @@ ServoStyleSet::MarkOriginsDirty(OriginFl
 void
 ServoStyleSet::SetStylistStyleSheetsDirty()
 {
   mStylistState |= StylistState::StyleSheetsDirty;
 
   // We need to invalidate cached style in getComputedStyle for undisplayed
   // elements, since we don't know if any of the style sheet change that we
   // do would affect undisplayed elements.
-  if (mPresContext) {
-    // XBL sheets don't have a pres context, but invalidating the restyle generation
-    // in that case is handled by SetXBLStyleSheetsDirty in the "master" stylist.
-    mPresContext->RestyleManager()->AsServo()->IncrementUndisplayedRestyleGeneration();
+  if (nsPresContext* presContext = GetPresContext()) {
+    // XBL sheets don't have a pres context, but invalidating the restyle
+    // generation in that case is handled by SetXBLStyleSheetsDirty in the
+    // "master" stylist.
+    presContext->RestyleManager()->AsServo()->IncrementUndisplayedRestyleGeneration();
   }
 }
 
 void
 ServoStyleSet::SetStylistXBLStyleSheetsDirty()
 {
   mStylistState |= StylistState::XBLStyleSheetsDirty;
 
   // We need to invalidate cached style in getComputedStyle for undisplayed
   // elements, since we don't know if any of the style sheet change that we
   // do would affect undisplayed elements.
-  MOZ_ASSERT(mPresContext);
-  mPresContext->RestyleManager()->AsServo()->IncrementUndisplayedRestyleGeneration();
+  MOZ_ASSERT(GetPresContext());
+  GetPresContext()->RestyleManager()->AsServo()->IncrementUndisplayedRestyleGeneration();
 }
 
 void
 ServoStyleSet::RuleAdded(ServoStyleSheet& aSheet, css::Rule& aRule)
 {
   if (mStyleRuleMap) {
     mStyleRuleMap->RuleAdded(aSheet, aRule);
   }
@@ -1097,17 +1118,17 @@ ServoStyleSet::RuleChanged(ServoStyleShe
   // FIXME(emilio): Could be more granular based on aRule.
   MarkOriginsDirty(aSheet.GetOrigin());
 }
 
 #ifdef DEBUG
 void
 ServoStyleSet::AssertTreeIsClean()
 {
-  DocumentStyleRootIterator iter(mPresContext->Document());
+  DocumentStyleRootIterator iter(mDocument);
   while (Element* root = iter.GetNextStyleRoot()) {
     Servo_AssertTreeIsClean(root);
   }
 }
 #endif
 
 bool
 ServoStyleSet::GetKeyframesForName(nsAtom* aName,
@@ -1270,17 +1291,19 @@ ServoStyleSet::ClearNonInheritingStyleCo
   }
 }
 
 already_AddRefed<ServoStyleContext>
 ServoStyleSet::ResolveStyleLazilyInternal(Element* aElement,
                                           CSSPseudoElementType aPseudoType,
                                           StyleRuleInclusion aRuleInclusion)
 {
-  mPresContext->EffectCompositor()->PreTraverse(aElement, aPseudoType);
+  MOZ_ASSERT(GetPresContext(),
+             "For now, no style resolution without a pres context");
+  GetPresContext()->EffectCompositor()->PreTraverse(aElement, aPseudoType);
   MOZ_ASSERT(!StylistNeedsUpdate());
 
   AutoSetInServoTraversal guard(this);
 
   /**
    * NB: This is needed because we process animations and transitions on the
    * pseudo-elements themselves, not on the parent's EagerPseudoStyles.
    *
@@ -1308,27 +1331,27 @@ ServoStyleSet::ResolveStyleLazilyInterna
   RefPtr<ServoStyleContext> computedValues =
     Servo_ResolveStyleLazily(elementForStyleResolution,
                              pseudoTypeForStyleResolution,
                              aRuleInclusion,
                              &Snapshots(),
                              mRawSet.get(),
                              /* aIgnoreExistingStyles = */ false).Consume();
 
-  if (mPresContext->EffectCompositor()->PreTraverse(aElement, aPseudoType)) {
+  if (GetPresContext()->EffectCompositor()->PreTraverse(aElement, aPseudoType)) {
     computedValues =
       Servo_ResolveStyleLazily(elementForStyleResolution,
                                pseudoTypeForStyleResolution,
                                aRuleInclusion,
                                &Snapshots(),
                                mRawSet.get(),
                                /* aIgnoreExistingStyles = */ false).Consume();
   }
 
-  MOZ_DIAGNOSTIC_ASSERT(computedValues->PresContext() == mPresContext ||
+  MOZ_DIAGNOSTIC_ASSERT(computedValues->PresContext() == GetPresContext() ||
                         aElement->OwnerDoc()->GetBFCacheEntry());
 
   return computedValues.forget();
 }
 
 bool
 ServoStyleSet::AppendFontFaceRules(nsTArray<nsFontFaceRuleContainer>& aArray)
 {
@@ -1367,25 +1390,24 @@ void
 ServoStyleSet::UpdateStylist()
 {
   MOZ_ASSERT(StylistNeedsUpdate());
 
   if (mStylistState & StylistState::StyleSheetsDirty) {
     // There's no need to compute invalidations and such for an XBL styleset,
     // since they are loaded and unloaded synchronously, and they don't have to
     // deal with dynamic content changes.
-    Element* root =
-      IsMaster() ? mPresContext->Document()->GetDocumentElement() : nullptr;
-
+    Element* root = IsMaster() ? mDocument->GetRootElement() : nullptr;
     Servo_StyleSet_FlushStyleSheets(mRawSet.get(), root);
   }
 
   if (MOZ_UNLIKELY(mStylistState & StylistState::XBLStyleSheetsDirty)) {
     MOZ_ASSERT(IsMaster(), "Only master styleset can mark XBL stylesets dirty!");
-    mBindingManager->UpdateBoundContentBindingsForServo(mPresContext);
+    MOZ_ASSERT(GetPresContext(), "How did they get dirty?");
+    mDocument->BindingManager()->UpdateBoundContentBindingsForServo(GetPresContext());
   }
 
   mStylistState = StylistState::NotDirty;
 }
 
 void
 ServoStyleSet::MaybeGCRuleTree()
 {
@@ -1412,17 +1434,18 @@ ServoStyleSet::MayTraverseFrom(const Ele
   }
 
   return !Servo_Element_IsDisplayNone(parent->AsElement());
 }
 
 bool
 ServoStyleSet::ShouldTraverseInParallel() const
 {
-  return mPresContext->PresShell()->IsActive();
+  MOZ_ASSERT(mDocument->GetShell(), "Styling a document without a shell?");
+  return mDocument->GetShell()->IsActive();
 }
 
 void
 ServoStyleSet::PrependSheetOfType(SheetType aType,
                                   ServoStyleSheet* aSheet)
 {
   aSheet->AddStyleSet(this);
   mSheets[aType].InsertElementAt(0, aSheet);
--- a/layout/style/ServoStyleSet.h
+++ b/layout/style/ServoStyleSet.h
@@ -595,23 +595,37 @@ private:
                          ServoStyleSheet* aSheet,
                          ServoStyleSheet* aBeforeSheet);
 
   void RemoveSheetOfType(SheetType aType,
                          ServoStyleSheet* aSheet);
 
   const Kind mKind;
 
-  // Nullptr if this is an XBL style set, or if we've been already detached from
-  // our shell.
-  nsPresContext* MOZ_NON_OWNING_REF mPresContext = nullptr;
+  // 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.
+  nsIDocument* 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
+   * have an associated pres shell.
+   */
+  nsPresContext* GetPresContext();
 
   // Because XBL style set could be used by multiple PresContext, we need to
   // store the last PresContext pointer which uses this XBL styleset for
   // computing medium rule changes.
+  //
+  // FIXME(emilio): This is a hack, and is broken. See bug 1406875.
   void* MOZ_NON_OWNING_REF mLastPresContextUsesXBLStyleSet = nullptr;
 
   UniquePtr<RawServoStyleSet> mRawSet;
   EnumeratedArray<SheetType, SheetType::Count,
                   nsTArray<RefPtr<ServoStyleSheet>>> mSheets;
   bool mAuthorStyleDisabled;
   StylistState mStylistState;
   uint64_t mUserFontSetUpdateGeneration;