Bug 1415940 Part 1: Expand StyleSheet dirty flag into a bitfield, to allow more types of dirtiness. draft
authorBrad Werth <bwerth@mozilla.com>
Wed, 03 Jan 2018 14:25:56 -0800
changeset 722738 5244f46fd61e5d378b8a1507d6f2e0cbffefe78b
parent 722672 6ffbba9ce0ef9ec77a63445f068f2e218ed4830f
child 722739 01d737e095c278c015ddd6dc8def2038a5683a03
push id96224
push userbwerth@mozilla.com
push dateFri, 19 Jan 2018 19:24:40 +0000
bugs1415940
milestone59.0a1
Bug 1415940 Part 1: Expand StyleSheet dirty flag into a bitfield, to allow more types of dirtiness. MozReview-Commit-ID: 7IasNqj85il
dom/base/nsTreeSanitizer.cpp
layout/style/CSSStyleSheet.cpp
layout/style/Loader.cpp
layout/style/ServoStyleSheet.cpp
layout/style/StyleSheet.cpp
layout/style/StyleSheet.h
--- a/dom/base/nsTreeSanitizer.cpp
+++ b/dom/base/nsTreeSanitizer.cpp
@@ -1107,18 +1107,18 @@ nsTreeSanitizer::SanitizeStyleSheet(cons
   } else {
     // Create the CSS parser, and parse the CSS text.
     nsCSSParser parser(nullptr, sheet->AsGecko());
     rv = parser.ParseSheet(aOriginal, aDocument->GetDocumentURI(), aBaseURI,
                            aDocument->NodePrincipal(), 0);
   }
   NS_ENSURE_SUCCESS(rv, true);
   // Mark the sheet as complete.
-  MOZ_ASSERT(!sheet->IsModified(),
-             "should not get marked modified during parsing");
+  MOZ_ASSERT(!sheet->HasForcedUniqueInner(),
+             "should not get a forced unique inner during parsing");
   sheet->SetComplete();
   // Loop through all the rules found in the CSS text
   ErrorResult err;
   RefPtr<dom::CSSRuleList> rules =
     sheet->GetCssRules(*nsContentUtils::GetSystemPrincipal(), err);
   err.SuppressException();
   if (!rules) {
     return true;
--- a/layout/style/CSSStyleSheet.cpp
+++ b/layout/style/CSSStyleSheet.cpp
@@ -348,17 +348,17 @@ CSSStyleSheet::CSSStyleSheet(const CSSSt
                aParentToUse,
                aOwnerRuleToUse,
                aDocumentToUse,
                aOwningNodeToUse)
   , mInRuleProcessorCache(false)
   , mScopeElement(nullptr)
   , mRuleProcessors(nullptr)
 {
-  if (mDirty) { // CSSOM's been there, force full copy now
+  if (HasForcedUniqueInner()) { // CSSOM's been there, force full copy now
     NS_ASSERTION(mInner->mComplete,
                  "Why have rules been accessed on an incomplete sheet?");
     // FIXME: handle failure?
     //
     // NOTE: It's important to call this from the subclass, since it could
     // access uninitialized members otherwise.
     EnsureUniqueInner();
   }
@@ -605,17 +605,17 @@ CSSStyleSheet::ClearRuleCascades()
   if (mParent) {
     static_cast<CSSStyleSheet*>(mParent)->ClearRuleCascades();
   }
 }
 
 void
 CSSStyleSheet::DidDirty()
 {
-  MOZ_ASSERT(!mInner->mComplete || mDirty,
+  MOZ_ASSERT(!mInner->mComplete || HasForcedUniqueInner(),
              "caller must have called WillDirty()");
   ClearRuleCascades();
 }
 
 nsresult
 CSSStyleSheet::RegisterNamespaceRule(css::Rule* aRule)
 {
   if (!Inner()->mNameSpaceMap) {
--- a/layout/style/Loader.cpp
+++ b/layout/style/Loader.cpp
@@ -998,19 +998,22 @@ Loader::CreateSheet(nsIURI* aURI,
     }
 
     if (sheet) {
       // This sheet came from the XUL cache or our per-document hashtable; it
       // better be a complete sheet.
       NS_ASSERTION(sheet->IsComplete(),
                    "Sheet thinks it's not complete while we think it is");
 
-      // Make sure it hasn't been modified; if it has, we can't use it
-      if (sheet->IsModified()) {
-        LOG(("  Not cloning completed sheet %p because it's been modified",
+      // Make sure it hasn't been forced to have a unique inner;
+      // that is an indication that its rules have been exposed to
+      // CSSOM and so we can't use it.
+      if (sheet->HasForcedUniqueInner()) {
+        LOG(("  Not cloning completed sheet %p because it has a "
+             "forced unique inner",
              sheet.get()));
         sheet = nullptr;
         fromCompleteSheets = false;
       }
     }
 
     // Then loading sheets
     if (!sheet && !aSyncLoad) {
@@ -1051,20 +1054,21 @@ Loader::CreateSheet(nsIURI* aURI,
                                             &debugEqual)) && debugEqual),
                        "Principals should be the same");
 #endif
         }
       }
     }
 
     if (sheet) {
-      // The sheet we have now should be either incomplete or unmodified
-      NS_ASSERTION(!sheet->IsModified() ||
+      // The sheet we have now should be either incomplete or without
+      // a forced unique inner.
+      NS_ASSERTION(!sheet->HasForcedUniqueInner() ||
                    !sheet->IsComplete(),
-                   "Unexpected modified complete sheet");
+                   "Unexpected complete sheet with forced unique inner");
       NS_ASSERTION(sheet->IsComplete() ||
                    aSheetState != eSheetComplete,
                    "Sheet thinks it's not complete while we think it is");
 
       RefPtr<StyleSheet> clonedSheet =
         sheet->Clone(nullptr, nullptr, nullptr, nullptr);
       *aSheet = Move(clonedSheet);
       if (*aSheet && fromCompleteSheets &&
@@ -1807,18 +1811,18 @@ Loader::DoSheetComplete(SheetLoadData* a
 
   // Go through and deal with the whole linked list.
   SheetLoadData* data = aLoadData;
   while (data) {
     if (!data->mSheetAlreadyComplete) {
       // If mSheetAlreadyComplete, then the sheet could well be modified between
       // when we posted the async call to SheetComplete and now, since the sheet
       // was page-accessible during that whole time.
-      MOZ_ASSERT(!data->mSheet->IsModified(),
-                 "should not get marked modified during parsing");
+      MOZ_ASSERT(!data->mSheet->HasForcedUniqueInner(),
+                 "should not get a forced unique inner during parsing");
       data->mSheet->SetComplete();
       data->ScheduleLoadEventIfNeeded(aStatus);
     }
     if (data->mMustNotify && (data->mObserver || !mObservers.IsEmpty())) {
       // Don't notify here so we don't trigger script.  Remember the
       // info we need to notify, then do it later when it's safe.
       aDatasToNotify.AppendElement(data);
 
--- a/layout/style/ServoStyleSheet.cpp
+++ b/layout/style/ServoStyleSheet.cpp
@@ -144,17 +144,17 @@ ServoStyleSheet::ServoStyleSheet(const S
                                  nsIDocument* aDocumentToUse,
                                  nsINode* aOwningNodeToUse)
   : StyleSheet(aCopy,
                aParentToUse,
                aOwnerRuleToUse,
                aDocumentToUse,
                aOwningNodeToUse)
 {
-  if (mDirty) { // CSSOM's been there, force full copy now
+  if (HasForcedUniqueInner()) { // CSSOM's been there, force full copy now
     NS_ASSERTION(mInner->mComplete,
                  "Why have rules been accessed on an incomplete sheet?");
     // FIXME: handle failure?
     //
     // NOTE: It's important to call this from the subclass, since this could
     // access uninitialized members otherwise.
     EnsureUniqueInner();
   }
--- a/layout/style/StyleSheet.cpp
+++ b/layout/style/StyleSheet.cpp
@@ -23,17 +23,17 @@ namespace mozilla {
 StyleSheet::StyleSheet(StyleBackendType aType, css::SheetParsingMode aParsingMode)
   : mParent(nullptr)
   , mDocument(nullptr)
   , mOwningNode(nullptr)
   , mOwnerRule(nullptr)
   , mParsingMode(aParsingMode)
   , mType(aType)
   , mDisabled(false)
-  , mDirty(false)
+  , mDirtyFlags(0)
   , mDocumentAssociationMode(NotOwnedByDocument)
   , mInner(nullptr)
 {
 }
 
 StyleSheet::StyleSheet(const StyleSheet& aCopy,
                        StyleSheet* aParentToUse,
                        dom::CSSImportRule* aOwnerRuleToUse,
@@ -42,17 +42,17 @@ StyleSheet::StyleSheet(const StyleSheet&
   : mParent(aParentToUse)
   , mTitle(aCopy.mTitle)
   , mDocument(aDocumentToUse)
   , mOwningNode(aOwningNodeToUse)
   , mOwnerRule(aOwnerRuleToUse)
   , mParsingMode(aCopy.mParsingMode)
   , mType(aCopy.mType)
   , mDisabled(aCopy.mDisabled)
-  , mDirty(aCopy.mDirty)
+  , mDirtyFlags(aCopy.mDirtyFlags)
   // 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)
   , mInner(aCopy.mInner) // Shallow copy, but concrete subclasses will fix up.
 {
   MOZ_ASSERT(mInner, "Should only copy StyleSheets with an mInner.");
   mInner->AddSheet(this);
 
@@ -191,17 +191,19 @@ bool
 StyleSheet::IsComplete() const
 {
   return SheetInfo().mComplete;
 }
 
 void
 StyleSheet::SetComplete()
 {
-  NS_ASSERTION(!mDirty, "Can't set a dirty sheet complete!");
+  NS_ASSERTION(!HasForcedUniqueInner(),
+               "Can't complete a sheet that's already been forced "
+               "unique.");
   SheetInfo().mComplete = true;
   if (mDocument && !mDisabled) {
     // Let the document know
     mDocument->BeginUpdate(UPDATE_STYLE);
     mDocument->SetStyleSheetApplicableState(this, true);
     mDocument->EndUpdate(UPDATE_STYLE);
   }
 
@@ -372,17 +374,17 @@ StyleSheet::DropStyleSet(const StyleSetH
   NS_ASSERTION(found, "didn't find style set");
 }
 
 void
 StyleSheet::EnsureUniqueInner()
 {
   MOZ_ASSERT(mInner->mSheets.Length() != 0,
              "unexpected number of outers");
-  mDirty = true;
+  mDirtyFlags |= FORCED_UNIQUE_INNER;
 
   if (HasUniqueInner()) {
     // already unique
     return;
   }
 
   // If this stylesheet is for XBL with Servo, don't bother cloning
   // it, as it may break ServoStyleRuleMap. XBL stylesheets are not
--- a/layout/style/StyleSheet.h
+++ b/layout/style/StyleSheet.h
@@ -127,17 +127,18 @@ public:
   inline bool IsApplicable() const;
   inline bool HasRules() const;
 
   virtual already_AddRefed<StyleSheet> Clone(StyleSheet* aCloneParent,
                                              dom::CSSImportRule* aCloneOwnerRule,
                                              nsIDocument* aCloneDocument,
                                              nsINode* aCloneOwningNode) const = 0;
 
-  bool IsModified() const { return mDirty; }
+  bool HasForcedUniqueInner() const { return mDirtyFlags &
+                                             FORCED_UNIQUE_INNER; }
 
   inline bool HasUniqueInner() const;
   void EnsureUniqueInner();
 
   // Append all of this sheet's child sheets to aArray.
   void AppendAllChildSheets(nsTArray<StyleSheet*>& aArray);
 
   // style sheet owner info
@@ -333,17 +334,20 @@ 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;
 
-  bool mDirty; // has been modified
+  enum dirtyFlagAttributes {
+    FORCED_UNIQUE_INNER = 0x1,
+  };
+  uint8_t mDirtyFlags; // has been modified
 
   // 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;
 
   // Core information we get from parsed sheets, which are shared amongst
   // StyleSheet clones.