Bug 1332353. Make it clearer when a stylesheet is really owned by its mDocument. r=heycam
authorBoris Zbarsky <bzbarsky@mit.edu>
Thu, 19 Jan 2017 23:49:44 -0500
changeset 330188 2b1fcb4b8c8854eea5190c22bdd31c9aca3510f1
parent 330187 cdc8e1a140e298a55cff0eedb053bd0155b360f7
child 330254 4ec5bc4fff15bf293a7118065df335847d0e2f96
push id85913
push userbzbarsky@mozilla.com
push dateFri, 20 Jan 2017 04:52:26 +0000
treeherdermozilla-inbound@2b1fcb4b8c88 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersheycam
bugs1332353
milestone53.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 1332353. Make it clearer when a stylesheet is really owned by its mDocument. r=heycam
dom/base/nsDOMWindowUtils.cpp
dom/base/nsDocument.cpp
editor/libeditor/HTMLEditor.cpp
layout/style/CSSStyleSheet.cpp
layout/style/CSSStyleSheet.h
layout/style/Loader.cpp
layout/style/ServoStyleRule.cpp
layout/style/ServoStyleSheet.cpp
layout/style/ServoStyleSheet.h
layout/style/StyleRule.cpp
layout/style/StyleSheet.cpp
layout/style/StyleSheet.h
layout/style/StyleSheetInlines.h
layout/style/nsDOMCSSDeclaration.cpp
layout/style/nsMediaList.cpp
--- a/dom/base/nsDOMWindowUtils.cpp
+++ b/dom/base/nsDOMWindowUtils.cpp
@@ -3462,17 +3462,17 @@ nsDOMWindowUtils::AddSheet(nsIPreloadedS
   NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE);
 
   StyleSheet* sheet = nullptr;
   auto preloadedSheet = static_cast<PreloadedStyleSheet*>(aSheet);
   nsresult rv = preloadedSheet->GetSheet(doc->GetStyleBackendType(), &sheet);
   NS_ENSURE_SUCCESS(rv, rv);
   NS_ENSURE_TRUE(sheet, NS_ERROR_FAILURE);
 
-  if (sheet->GetOwningDocument()) {
+  if (sheet->GetAssociatedDocument()) {
     return NS_ERROR_INVALID_ARG;
   }
 
   nsIDocument::additionalSheetType type = convertSheetType(aSheetType);
   return doc->AddAdditionalStyleSheet(type, sheet);
 }
 
 NS_IMETHODIMP
--- a/dom/base/nsDocument.cpp
+++ b/dom/base/nsDocument.cpp
@@ -1480,17 +1480,17 @@ nsDocument::~nsDocument()
     mChildren.ChildAt(indx)->UnbindFromTree();
     mChildren.RemoveChildAt(indx);
   }
   mFirstChild = nullptr;
   mCachedRootElement = nullptr;
 
   // Let the stylesheets know we're going away
   for (StyleSheet* sheet : mStyleSheets) {
-    sheet->SetOwningDocument(nullptr);
+    sheet->ClearAssociatedDocument();
   }
   if (mAttrStyleSheet) {
     mAttrStyleSheet->SetOwningDocument(nullptr);
   }
   // We don't own the mOnDemandBuiltInUASheets, so we don't need to reset them.
 
   if (mListenerManager) {
     mListenerManager->Disconnect();
@@ -2121,17 +2121,17 @@ nsDocument::ResetToURI(nsIURI *aURI, nsI
   }
 }
 
 void
 nsDocument::RemoveDocStyleSheetsFromStyleSets()
 {
   // The stylesheets should forget us
   for (StyleSheet* sheet : Reversed(mStyleSheets)) {
-    sheet->SetOwningDocument(nullptr);
+    sheet->ClearAssociatedDocument();
 
     if (sheet->IsApplicable()) {
       nsCOMPtr<nsIPresShell> shell = GetShell();
       if (shell) {
         shell->StyleSet()->RemoveDocStyleSheet(sheet);
       }
     }
     // XXX Tell observers?
@@ -2140,17 +2140,17 @@ nsDocument::RemoveDocStyleSheetsFromStyl
 
 void
 nsDocument::RemoveStyleSheetsFromStyleSets(
     const nsTArray<RefPtr<StyleSheet>>& aSheets,
     SheetType aType)
 {
   // The stylesheets should forget us
   for (StyleSheet* sheet : Reversed(aSheets)) {
-    sheet->SetOwningDocument(nullptr);
+    sheet->ClearAssociatedDocument();
 
     if (sheet->IsApplicable()) {
       nsCOMPtr<nsIPresShell> shell = GetShell();
       if (shell) {
         shell->StyleSet()->RemoveStyleSheet(aType, sheet);
       }
     }
     // XXX Tell observers?
@@ -4077,17 +4077,17 @@ nsDocument::NotifyStyleSheetRemoved(Styl
   }
 }
 
 void
 nsDocument::AddStyleSheet(StyleSheet* aSheet)
 {
   NS_PRECONDITION(aSheet, "null arg");
   mStyleSheets.AppendElement(aSheet);
-  aSheet->SetOwningDocument(this);
+  aSheet->SetAssociatedDocument(this, StyleSheet::OwnedByDocument);
 
   if (aSheet->IsApplicable()) {
     AddStyleSheetToStyleSets(aSheet);
   }
 
   NotifyStyleSheetAdded(aSheet, true);
 }
 
@@ -4114,17 +4114,17 @@ nsDocument::RemoveStyleSheet(StyleSheet*
   if (!mIsGoingAway) {
     if (aSheet->IsApplicable()) {
       RemoveStyleSheetFromStyleSets(aSheet);
     }
 
     NotifyStyleSheetRemoved(aSheet, true);
   }
 
-  aSheet->SetOwningDocument(nullptr);
+  aSheet->ClearAssociatedDocument();
 }
 
 void
 nsDocument::UpdateStyleSheets(nsTArray<RefPtr<StyleSheet>>& aOldSheets,
                               nsTArray<RefPtr<StyleSheet>>& aNewSheets)
 {
   BeginUpdate(UPDATE_STYLE);
 
@@ -4142,17 +4142,17 @@ nsDocument::UpdateStyleSheets(nsTArray<R
     NS_ASSERTION(oldSheet, "None of the old sheets should be null");
     int32_t oldIndex = mStyleSheets.IndexOf(oldSheet);
     RemoveStyleSheet(oldSheet);  // This does the right notifications
 
     // Now put the new one in its place.  If it's null, just ignore it.
     StyleSheet* newSheet = aNewSheets[i];
     if (newSheet) {
       mStyleSheets.InsertElementAt(oldIndex, newSheet);
-      newSheet->SetOwningDocument(this);
+      newSheet->SetAssociatedDocument(this, StyleSheet::OwnedByDocument);
       if (newSheet->IsApplicable()) {
         AddStyleSheetToStyleSets(newSheet);
       }
 
       NotifyStyleSheetAdded(newSheet, true);
     }
   }
 
@@ -4161,17 +4161,17 @@ nsDocument::UpdateStyleSheets(nsTArray<R
 
 void
 nsDocument::InsertStyleSheetAt(StyleSheet* aSheet, int32_t aIndex)
 {
   NS_PRECONDITION(aSheet, "null ptr");
 
   mStyleSheets.InsertElementAt(aIndex, aSheet);
 
-  aSheet->SetOwningDocument(this);
+  aSheet->SetAssociatedDocument(this, StyleSheet::OwnedByDocument);
 
   if (aSheet->IsApplicable()) {
     AddStyleSheetToStyleSets(aSheet);
   }
 
   NotifyStyleSheetAdded(aSheet, true);
 }
 
@@ -4289,17 +4289,17 @@ nsDocument::LoadAdditionalStyleSheet(add
     default:
       MOZ_CRASH("impossible value for aType");
   }
 
   RefPtr<StyleSheet> sheet;
   nsresult rv = loader->LoadSheetSync(aSheetURI, parsingMode, true, &sheet);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  sheet->SetOwningDocument(this);
+  sheet->SetAssociatedDocument(this, StyleSheet::OwnedByDocument);
   MOZ_ASSERT(sheet->IsApplicable());
 
   return AddAdditionalStyleSheet(aType, sheet);
 }
 
 nsresult
 nsDocument::AddAdditionalStyleSheet(additionalSheetType aType, StyleSheet* aSheet)
 {
@@ -4347,17 +4347,17 @@ nsDocument::RemoveAdditionalStyleSheet(a
       }
     }
 
     // Passing false, so documet.styleSheets.length will not be affected by
     // these additional sheets.
     NotifyStyleSheetRemoved(sheetRef, false);
     EndUpdate(UPDATE_STYLE);
 
-    sheetRef->SetOwningDocument(nullptr);
+    sheetRef->ClearAssociatedDocument();
   }
 }
 
 StyleSheet*
 nsDocument::GetFirstAdditionalAuthorSheet()
 {
   return mAdditionalSheets[eAuthorSheet].SafeElementAt(0);
 }
@@ -12017,17 +12017,17 @@ nsIDocument::DocAddSizeOfIncludingThis(n
 
 static size_t
 SizeOfOwnedSheetArrayExcludingThis(const nsTArray<RefPtr<StyleSheet>>& aSheets,
                                    MallocSizeOf aMallocSizeOf)
 {
   size_t n = 0;
   n += aSheets.ShallowSizeOfExcludingThis(aMallocSizeOf);
   for (StyleSheet* sheet : aSheets) {
-    if (!sheet->GetOwningDocument()) {
+    if (!sheet->GetAssociatedDocument()) {
       // Avoid over-reporting shared sheets.
       continue;
     }
     n += sheet->SizeOfIncludingThis(aMallocSizeOf);
   }
   return n;
 }
 
--- a/editor/libeditor/HTMLEditor.cpp
+++ b/editor/libeditor/HTMLEditor.cpp
@@ -2947,17 +2947,17 @@ NS_IMETHODIMP
 HTMLEditor::EnableStyleSheet(const nsAString& aURL,
                              bool aEnable)
 {
   RefPtr<StyleSheet> sheet = GetStyleSheetForURL(aURL);
   NS_ENSURE_TRUE(sheet, NS_OK); // Don't fail if sheet not found
 
   // Ensure the style sheet is owned by our document.
   nsCOMPtr<nsIDocument> doc = do_QueryReferent(mDocWeak);
-  sheet->SetOwningDocument(doc);
+  sheet->SetAssociatedDocument(doc, StyleSheet::NotOwnedByDocument);
 
   if (sheet->IsServo()) {
     // XXXheycam ServoStyleSheets don't support being enabled/disabled yet.
     NS_ERROR("stylo: ServoStyleSheets can't be disabled yet");
     return NS_ERROR_FAILURE;
   }
   return sheet->AsGecko()->SetDisabled(!aEnable);
 }
@@ -2969,17 +2969,17 @@ HTMLEditor::EnableExistingStyleSheet(con
 
   // Enable sheet if already loaded.
   if (!sheet) {
     return false;
   }
 
   // Ensure the style sheet is owned by our document.
   nsCOMPtr<nsIDocument> doc = do_QueryReferent(mDocWeak);
-  sheet->SetOwningDocument(doc);
+  sheet->SetAssociatedDocument(doc, StyleSheet::NotOwnedByDocument);
 
   if (sheet->IsServo()) {
     // XXXheycam ServoStyleSheets don't support being enabled/disabled yet.
     NS_ERROR("stylo: ServoStyleSheets can't be disabled yet");
     return true;
   }
   sheet->AsGecko()->SetDisabled(false);
   return true;
--- a/layout/style/CSSStyleSheet.cpp
+++ b/layout/style/CSSStyleSheet.cpp
@@ -146,25 +146,27 @@ static bool SetStyleSheetReference(css::
 }
 
 struct ChildSheetListBuilder {
   RefPtr<CSSStyleSheet>* sheetSlot;
   CSSStyleSheet* parent;
 
   void SetParentLinks(CSSStyleSheet* aSheet) {
     aSheet->mParent = parent;
-    aSheet->SetOwningDocument(parent->mDocument);
+    aSheet->SetAssociatedDocument(parent->mDocument,
+                                  parent->mDocumentAssociationMode);
   }
 
   static void ReparentChildList(CSSStyleSheet* aPrimarySheet,
                                 CSSStyleSheet* aFirstChild)
   {
     for (CSSStyleSheet *child = aFirstChild; child; child = child->mNext) {
       child->mParent = aPrimarySheet;
-      child->SetOwningDocument(aPrimarySheet->mDocument);
+      child->SetAssociatedDocument(aPrimarySheet->mDocument,
+                                   aPrimarySheet->mDocumentAssociationMode);
     }
   }
 };
   
 bool
 CSSStyleSheet::RebuildChildList(css::Rule* aRule, void* aBuilder)
 {
   int32_t type = aRule->GetType();
@@ -607,26 +609,32 @@ CSSStyleSheet::EnabledStateChangedIntern
 
 CSSStyleSheet*
 CSSStyleSheet::GetParentSheet() const
 {
   return mParent;
 }
 
 void
-CSSStyleSheet::SetOwningDocument(nsIDocument* aDocument)
-{ // not ref counted
+CSSStyleSheet::SetAssociatedDocument(nsIDocument* aDocument,
+                                     DocumentAssociationMode aAssociationMode)
+{
+  MOZ_ASSERT_IF(!aDocument, aAssociationMode == NotOwnedByDocument);
+
+  // not ref counted
   mDocument = aDocument;
+  mDocumentAssociationMode = aAssociationMode;
+
   // Now set the same document on all our child sheets....
   // XXXbz this is a little bogus; see the XXX comment where we
   // declare mFirstChild.
   for (CSSStyleSheet* child = mInner->mFirstChild;
        child; child = child->mNext) {
     if (child->mParent == this) {
-      child->SetOwningDocument(aDocument);
+      child->SetAssociatedDocument(aDocument, aAssociationMode);
     }
   }
 }
 
 uint64_t
 CSSStyleSheet::FindOwningWindowInnerID() const
 {
   uint64_t windowID = 0;
--- a/layout/style/CSSStyleSheet.h
+++ b/layout/style/CSSStyleSheet.h
@@ -112,17 +112,18 @@ public:
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(CSSStyleSheet, StyleSheet)
 
   NS_DECLARE_STATIC_IID_ACCESSOR(NS_CSS_STYLE_SHEET_IMPL_CID)
 
   bool HasRules() const;
 
   // style sheet owner info
   CSSStyleSheet* GetParentSheet() const;  // may be null
-  void SetOwningDocument(nsIDocument* aDocument);
+  void SetAssociatedDocument(nsIDocument* aDocument,
+                             DocumentAssociationMode aAssociationMode);
 
   // Find the ID of the owner inner window.
   uint64_t FindOwningWindowInnerID() const;
 #ifdef DEBUG
   void List(FILE* out = stdout, int32_t aIndent = 0) const;
 #endif
 
   void AppendStyleSheet(CSSStyleSheet* aSheet);
--- a/layout/style/Loader.cpp
+++ b/layout/style/Loader.cpp
@@ -2213,23 +2213,23 @@ Loader::LoadChildSheet(StyleSheet* aPare
     LOG_WARN(("  Not enabled"));
     return NS_ERROR_NOT_AVAILABLE;
   }
 
   LOG_URI("  Child uri: '%s'", aURL);
 
   nsCOMPtr<nsINode> owningNode;
 
-  // check for an owning document: if none, don't bother walking up the parent
-  // sheets
+  // check for an associated document: if none, don't bother walking up the
+  // parent sheets
   //
   // FIXME(emilio): Figure out whether this walk up is necessary (try seems
   // green without it), and fix the parenting of stylesheets in the servo case
   // if that's the case.
-  if (aParentSheet->GetOwningDocument() && aParentSheet->IsGecko()) {
+  if (aParentSheet->GetAssociatedDocument() && aParentSheet->IsGecko()) {
     StyleSheet* topSheet = aParentSheet;
     while (StyleSheet* parent = topSheet->GetParentSheet()) {
       topSheet = parent;
     }
     owningNode = topSheet->GetOwnerNode();
   }
 
   nsISupports* context = owningNode;
--- a/layout/style/ServoStyleRule.cpp
+++ b/layout/style/ServoStyleRule.cpp
@@ -65,25 +65,25 @@ ServoStyleRuleDeclaration::GetCSSDeclara
   return mDecls;
 }
 
 nsresult
 ServoStyleRuleDeclaration::SetCSSDeclaration(DeclarationBlock* aDecl)
 {
   ServoStyleRule* rule = Rule();
   if (RefPtr<ServoStyleSheet> sheet = rule->GetStyleSheet()->AsServo()) {
-    nsCOMPtr<nsIDocument> owningDoc = sheet->GetOwningDocument();
-    mozAutoDocUpdate updateBatch(owningDoc, UPDATE_STYLE, true);
+    nsCOMPtr<nsIDocument> doc = sheet->GetAssociatedDocument();
+    mozAutoDocUpdate updateBatch(doc, UPDATE_STYLE, true);
     if (aDecl != mDecls) {
       RefPtr<ServoDeclarationBlock> decls = aDecl->AsServo();
       Servo_StyleRule_SetStyle(rule->Raw(), decls->Raw());
       mDecls = decls.forget();
     }
-    if (owningDoc) {
-      owningDoc->StyleRuleChanged(sheet, rule);
+    if (doc) {
+      doc->StyleRuleChanged(sheet, rule);
     }
   }
   return NS_OK;
 }
 
 nsIDocument*
 ServoStyleRuleDeclaration::DocToUpdate()
 {
--- a/layout/style/ServoStyleSheet.cpp
+++ b/layout/style/ServoStyleSheet.cpp
@@ -50,29 +50,33 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 bool
 ServoStyleSheet::HasRules() const
 {
   return mSheet && Servo_StyleSheet_HasRules(mSheet);
 }
 
 void
-ServoStyleSheet::SetOwningDocument(nsIDocument* aDocument)
+ServoStyleSheet::SetAssociatedDocument(nsIDocument* aDocument,
+                                       DocumentAssociationMode aAssociationMode)
 {
+  MOZ_ASSERT_IF(!aDocument, aAssociationMode == NotOwnedByDocument);
+
   // XXXheycam: Traverse to child ServoStyleSheets to set this, like
-  // CSSStyleSheet::SetOwningDocument does.
+  // CSSStyleSheet::SetAssociatedDocument does.
 
   mDocument = aDocument;
+  mDocumentAssociationMode = aAssociationMode;
 }
 
 ServoStyleSheet*
 ServoStyleSheet::GetParentSheet() const
 {
   // XXXheycam: When we implement support for child sheets, we'll have
-  // to fix SetOwningDocument to propagate the owning document down
+  // to fix SetAssociatedDocument to propagate the associated document down
   // to the children.
   MOZ_CRASH("stylo: not implemented");
 }
 
 void
 ServoStyleSheet::AppendStyleSheet(ServoStyleSheet* aSheet)
 {
   aSheet->mDocument = mDocument;
--- a/layout/style/ServoStyleSheet.h
+++ b/layout/style/ServoStyleSheet.h
@@ -33,17 +33,18 @@ public:
                   net::ReferrerPolicy aReferrerPolicy,
                   const dom::SRIMetadata& aIntegrity);
 
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(ServoStyleSheet, StyleSheet)
 
   bool HasRules() const;
 
-  void SetOwningDocument(nsIDocument* aDocument);
+  void SetAssociatedDocument(nsIDocument* aDocument,
+                             DocumentAssociationMode aAssociationMode);
 
   ServoStyleSheet* GetParentSheet() const;
   void AppendStyleSheet(ServoStyleSheet* aSheet);
 
   MOZ_MUST_USE nsresult ParseSheet(css::Loader* aLoader,
                                    const nsAString& aInput,
                                    nsIURI* aSheetURI,
                                    nsIURI* aBaseURI,
--- a/layout/style/StyleRule.cpp
+++ b/layout/style/StyleRule.cpp
@@ -1201,32 +1201,32 @@ DOMCSSDeclarationImpl::GetParentRule(nsI
 }
 
 nsresult
 DOMCSSDeclarationImpl::SetCSSDeclaration(DeclarationBlock* aDecl)
 {
   NS_PRECONDITION(mRule,
          "can only be called when |GetCSSDeclaration| returned a declaration");
 
-  nsCOMPtr<nsIDocument> owningDoc;
+  nsCOMPtr<nsIDocument> doc;
   RefPtr<CSSStyleSheet> sheet = mRule->GetStyleSheet();
   if (sheet) {
-    owningDoc = sheet->GetOwningDocument();
+    doc = sheet->GetAssociatedDocument();
   }
 
-  mozAutoDocUpdate updateBatch(owningDoc, UPDATE_STYLE, true);
+  mozAutoDocUpdate updateBatch(doc, UPDATE_STYLE, true);
 
   mRule->SetDeclaration(aDecl->AsGecko());
 
   if (sheet) {
     sheet->DidDirty();
   }
 
-  if (owningDoc) {
-    owningDoc->StyleRuleChanged(sheet, mRule);
+  if (doc) {
+    doc->StyleRuleChanged(sheet, mRule);
   }
   return NS_OK;
 }
 
 nsIDocument*
 DOMCSSDeclarationImpl::DocToUpdate()
 {
   return nullptr;
--- a/layout/style/StyleSheet.cpp
+++ b/layout/style/StyleSheet.cpp
@@ -19,28 +19,32 @@
 namespace mozilla {
 
 StyleSheet::StyleSheet(StyleBackendType aType, css::SheetParsingMode aParsingMode)
   : mDocument(nullptr)
   , mOwningNode(nullptr)
   , mParsingMode(aParsingMode)
   , mType(aType)
   , mDisabled(false)
+  , mDocumentAssociationMode(NotOwnedByDocument)
 {
 }
 
 StyleSheet::StyleSheet(const StyleSheet& aCopy,
                        nsIDocument* aDocumentToUse,
                        nsINode* aOwningNodeToUse)
   : mTitle(aCopy.mTitle)
   , mDocument(aDocumentToUse)
   , mOwningNode(aOwningNodeToUse)
   , mParsingMode(aCopy.mParsingMode)
   , mType(aCopy.mType)
   , mDisabled(aCopy.mDisabled)
+    // We only use this constructor during cloning.  It's the cloner's
+    // responsibility to notify us if we end up being owned by a document.
+  , mDocumentAssociationMode(NotOwnedByDocument)
 {
   if (aCopy.mMedia) {
     // XXX This is wrong; we should be keeping @import rules and
     // sheets in sync!
     mMedia = aCopy.mMedia->Clone();
   }
 }
 
--- a/layout/style/StyleSheet.h
+++ b/layout/style/StyleSheet.h
@@ -101,18 +101,32 @@ public:
    * should never be inserted into a style set.  A sheet may not be
    * applicable for a variety of reasons including being disabled and
    * being incomplete.
    */
   inline bool IsApplicable() const;
   inline bool HasRules() const;
 
   // style sheet owner info
-  nsIDocument* GetOwningDocument() const { return mDocument; }
-  inline void SetOwningDocument(nsIDocument* aDocument);
+  enum DocumentAssociationMode {
+    // OwnedByDocument means mDocument owns us (possibly via a chain of other
+    // stylesheets).
+    OwnedByDocument,
+    // NotOwnedByDocument means we're owned by something that might have a
+    // different lifetime than mDocument.
+    NotOwnedByDocument
+  };
+  nsIDocument* GetAssociatedDocument() const { return mDocument; }
+  bool IsOwnedByDocument() const {
+    return mDocumentAssociationMode == OwnedByDocument;
+  }
+  // aDocument must not be null.
+  inline void SetAssociatedDocument(nsIDocument* aDocument,
+                                    DocumentAssociationMode aMode);
+  inline void ClearAssociatedDocument();
   nsINode* GetOwnerNode() const { return mOwningNode; }
   inline StyleSheet* GetParentSheet() const;
 
   inline void AppendStyleSheet(StyleSheet* aSheet);
 
   // Principal() never returns a null pointer.
   inline nsIPrincipal* Principal() const;
   /**
@@ -220,13 +234,18 @@ protected:
 
   // mParsingMode controls access to nonstandard style constructs that
   // are not safe for use on the public Web but necessary in UA sheets
   // and/or useful in user sheets.
   css::SheetParsingMode mParsingMode;
 
   const StyleBackendType mType;
   bool                  mDisabled;
+
+  // mDocumentAssociationMode determines whether mDocument directly owns us (in
+  // the sense that if it's known-live then we're known-live).  Always
+  // NotOwnedByDocument when mDocument is null.
+  DocumentAssociationMode mDocumentAssociationMode;
 };
 
 } // namespace mozilla
 
 #endif // mozilla_StyleSheet_h
--- a/layout/style/StyleSheetInlines.h
+++ b/layout/style/StyleSheetInlines.h
@@ -78,19 +78,27 @@ StyleSheet::IsApplicable() const
 
 bool
 StyleSheet::HasRules() const
 {
   MOZ_STYLO_FORWARD(HasRules, ())
 }
 
 void
-StyleSheet::SetOwningDocument(nsIDocument* aDocument)
+StyleSheet::SetAssociatedDocument(nsIDocument* aDocument,
+                                  DocumentAssociationMode aAssociationMode)
 {
-  MOZ_STYLO_FORWARD(SetOwningDocument, (aDocument))
+  MOZ_ASSERT(aDocument);
+  MOZ_STYLO_FORWARD(SetAssociatedDocument, (aDocument, aAssociationMode))
+}
+
+void
+StyleSheet::ClearAssociatedDocument()
+{
+  MOZ_STYLO_FORWARD(SetAssociatedDocument, (nullptr, NotOwnedByDocument));
 }
 
 StyleSheet*
 StyleSheet::GetParentSheet() const
 {
   MOZ_STYLO_FORWARD(GetParentSheet, ())
 }
 
--- a/layout/style/nsDOMCSSDeclaration.cpp
+++ b/layout/style/nsDOMCSSDeclaration.cpp
@@ -262,17 +262,17 @@ nsDOMCSSDeclaration::GetCSSParsingEnviro
                                                      CSSParsingEnvironment& aCSSParseEnv)
 {
   StyleSheet* sheet = aRule ? aRule->GetStyleSheet() : nullptr;
   if (!sheet) {
     aCSSParseEnv.mPrincipal = nullptr;
     return;
   }
 
-  nsIDocument* document = sheet->GetOwningDocument();
+  nsIDocument* document = sheet->GetAssociatedDocument();
   aCSSParseEnv.mSheetURI = sheet->GetSheetURI();
   aCSSParseEnv.mBaseURI = sheet->GetBaseURI();
   aCSSParseEnv.mPrincipal = sheet->Principal();
   aCSSParseEnv.mCSSLoader = document ? document->CSSLoader() : nullptr;
 }
 
 nsresult
 nsDOMCSSDeclaration::ParsePropertyValue(const nsCSSPropertyID aPropID,
--- a/layout/style/nsMediaList.cpp
+++ b/layout/style/nsMediaList.cpp
@@ -578,17 +578,17 @@ nsMediaList::GetMediaText(nsAString& aMe
   GetText(aMediaText);
   return NS_OK;
 }
 
 // "sheet" should be a StyleSheet and "doc" should be an
 // nsCOMPtr<nsIDocument>
 #define BEGIN_MEDIA_CHANGE(sheet, doc)                         \
   if (sheet) {                                                 \
-    doc = sheet->GetOwningDocument();                          \
+    doc = sheet->GetAssociatedDocument();                      \
   }                                                            \
   mozAutoDocUpdate updateBatch(doc, UPDATE_STYLE, true);       \
   if (sheet) {                                                 \
     sheet->WillDirty();                                        \
   }
 
 #define END_MEDIA_CHANGE(sheet, doc)                           \
   if (sheet) {                                                 \