Bug 1294299 part 10 - Implement DeclarationBlock.EnsureMutable. r=heycam draft
authorXidorn Quan <me@upsuper.org>
Mon, 24 Oct 2016 11:32:33 +1100
changeset 432591 9cd973749c07e4e32ba2599e3d0cd85713548846
parent 432590 de45a64c715d17421dc8a0f7717531a94f4c1f32
child 432592 af4978457607505cc44441d28f4b053a7a18c769
push id34373
push userxquan@mozilla.com
push dateWed, 02 Nov 2016 11:29:39 +0000
reviewersheycam
bugs1294299
milestone52.0a1
Bug 1294299 part 10 - Implement DeclarationBlock.EnsureMutable. r=heycam MozReview-Commit-ID: KpaypyY5moC
layout/style/Declaration.cpp
layout/style/Declaration.h
layout/style/DeclarationBlock.h
layout/style/DeclarationBlockInlines.h
layout/style/nsDOMCSSDeclaration.cpp
--- a/layout/style/Declaration.cpp
+++ b/layout/style/Declaration.cpp
@@ -1808,29 +1808,16 @@ Declaration::GetNthProperty(uint32_t aIn
 
 void
 Declaration::InitializeEmpty()
 {
   MOZ_ASSERT(!mData && !mImportantData, "already initialized");
   mData = nsCSSCompressedDataBlock::CreateEmptyBlock();
 }
 
-already_AddRefed<Declaration>
-Declaration::EnsureMutable()
-{
-  MOZ_ASSERT(mData, "should only be called when not expanded");
-  RefPtr<Declaration> result;
-  if (!IsMutable()) {
-    result = new Declaration(*this);
-  } else {
-    result = this;
-  }
-  return result.forget();
-}
-
 size_t
 Declaration::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
 {
   size_t n = aMallocSizeOf(this);
   n += mOrder.ShallowSizeOfExcludingThis(aMallocSizeOf);
   n += mData          ? mData         ->SizeOfIncludingThis(aMallocSizeOf) : 0;
   n += mImportantData ? mImportantData->SizeOfIncludingThis(aMallocSizeOf) : 0;
   if (mVariables) {
--- a/layout/style/Declaration.h
+++ b/layout/style/Declaration.h
@@ -183,16 +183,20 @@ public:
   // Returns whether we actually had a property at aIndex
   bool GetNthProperty(uint32_t aIndex, nsAString& aReturn) const;
 
   void ToString(nsAString& aString) const;
 
   nsCSSCompressedDataBlock* GetNormalBlock() const { return mData; }
   nsCSSCompressedDataBlock* GetImportantBlock() const { return mImportantData; }
 
+  void AssertNotExpanded() const {
+    MOZ_ASSERT(mData, "should only be called when not expanded");
+  }
+
   /**
    * Initialize this declaration as holding no data.  Cannot fail.
    */
   void InitializeEmpty();
 
   /**
    * Transfer all of the state from |aExpandedData| into this declaration.
    * After calling, |aExpandedData| should be in its initial state.
@@ -218,17 +222,17 @@ public:
     AssertMutable();
     aExpandedData->AssertInitialState();
 
     MOZ_ASSERT(mData, "oops");
     aExpandedData->Expand(mData.forget(), mImportantData.forget());
   }
 
   void MapImportantRuleInfoInto(nsRuleData *aRuleData) const {
-    MOZ_ASSERT(mData, "called while expanded");
+    AssertNotExpanded();
     MOZ_ASSERT(mImportantData || mImportantVariables,
                "must have important data or variables");
     if (mImportantData) {
       mImportantData->MapRuleInfoInto(aRuleData);
     }
     if (mImportantVariables) {
       mImportantVariables->MapRuleInfoInto(aRuleData);
     }
@@ -246,17 +250,17 @@ public:
    * |aFromBlock|.  |aChanged| is set to true if the declaration
    * changed as a result of the call, and to false otherwise.
    */
   bool TryReplaceValue(nsCSSPropertyID aProperty, bool aIsImportant,
                          nsCSSExpandedDataBlock& aFromBlock,
                          bool* aChanged)
   {
     AssertMutable();
-    MOZ_ASSERT(mData, "called while expanded");
+    AssertNotExpanded();
 
     if (nsCSSProps::IsShorthand(aProperty)) {
       *aChanged = false;
       return false;
     }
     nsCSSCompressedDataBlock *block = aIsImportant ? mImportantData : mData;
     // mImportantData might be null
     if (!block) {
@@ -276,21 +280,16 @@ public:
   }
 
   bool HasNonImportantValueFor(nsCSSPropertyID aProperty) const {
     MOZ_ASSERT(!nsCSSProps::IsShorthand(aProperty), "must be longhand");
     return !!mData->ValueFor(aProperty);
   }
 
   /**
-   * Copy |this|, if necessary to ensure that it can be modified.
-   */
-  already_AddRefed<Declaration> EnsureMutable();
-
-  /**
    * Clear the data, in preparation for its replacement with entirely
    * new data by a call to |CompressFrom|.
    */
   void ClearData() {
     AssertMutable();
     mData = nullptr;
     mImportantData = nullptr;
     mVariables = nullptr;
--- a/layout/style/DeclarationBlock.h
+++ b/layout/style/DeclarationBlock.h
@@ -58,16 +58,21 @@ public:
   }
 
   /**
    * Mark this declaration as unmodifiable.  It's 'const' so it can
    * be called from ToString.
    */
   void SetImmutable() const { mImmutable = true; }
 
+  /**
+   * Copy |this|, if necessary to ensure that it can be modified.
+   */
+  inline already_AddRefed<DeclarationBlock> EnsureMutable();
+
   void SetOwningRule(css::Rule* aRule) {
     MOZ_ASSERT(!mContainer.mOwningRule || !aRule,
                "should never overwrite one rule with another");
     mContainer.mOwningRule = aRule;
   }
 
   css::Rule* GetOwningRule() const {
     if (mContainer.mRaw & 0x1) {
--- a/layout/style/DeclarationBlockInlines.h
+++ b/layout/style/DeclarationBlockInlines.h
@@ -33,16 +33,30 @@ DeclarationBlock::Clone() const
   if (IsGecko()) {
     result = new css::Declaration(*AsGecko());
   } else {
     result = new ServoDeclarationBlock(*AsServo());
   }
   return result.forget();
 }
 
+already_AddRefed<DeclarationBlock>
+DeclarationBlock::EnsureMutable()
+{
+#ifdef DEBUG
+  if (IsGecko()) {
+    AsGecko()->AssertNotExpanded();
+  }
+#endif
+  if (!IsMutable()) {
+    return Clone();
+  }
+  return do_AddRef(this);
+}
+
 void
 DeclarationBlock::ToString(nsAString& aString) const
 {
   MOZ_STYLO_FORWARD(ToString, (aString))
 }
 
 uint32_t
 DeclarationBlock::Count() const
--- a/layout/style/nsDOMCSSDeclaration.cpp
+++ b/layout/style/nsDOMCSSDeclaration.cpp
@@ -274,121 +274,120 @@ nsDOMCSSDeclaration::GetCSSParsingEnviro
   aCSSParseEnv.mCSSLoader = document ? document->CSSLoader() : nullptr;
 }
 
 nsresult
 nsDOMCSSDeclaration::ParsePropertyValue(const nsCSSPropertyID aPropID,
                                         const nsAString& aPropValue,
                                         bool aIsImportant)
 {
-  css::Declaration* olddecl = GetCSSDeclaration(eOperation_Modify)->AsGecko();
+  DeclarationBlock* olddecl = GetCSSDeclaration(eOperation_Modify);
   if (!olddecl) {
     return NS_ERROR_NOT_AVAILABLE;
   }
 
   CSSParsingEnvironment env;
   GetCSSParsingEnvironment(env);
   if (!env.mPrincipal) {
     return NS_ERROR_NOT_AVAILABLE;
   }
 
   // For nsDOMCSSAttributeDeclaration, SetCSSDeclaration will lead to
   // Attribute setting code, which leads in turn to BeginUpdate.  We
   // need to start the update now so that the old rule doesn't get used
   // between when we mutate the declaration and when we set the new
   // rule (see stack in bug 209575).
   mozAutoDocConditionalContentUpdateBatch autoUpdate(DocToUpdate(), true);
-  RefPtr<css::Declaration> decl = olddecl->EnsureMutable();
+  RefPtr<DeclarationBlock> decl = olddecl->EnsureMutable();
 
   nsCSSParser cssParser(env.mCSSLoader);
   bool changed;
-  cssParser.ParseProperty(aPropID, aPropValue, env.mSheetURI, env.mBaseURI,
-                          env.mPrincipal, decl, &changed, aIsImportant);
+  cssParser.ParseProperty(aPropID, aPropValue,
+                          env.mSheetURI, env.mBaseURI, env.mPrincipal,
+                          decl->AsGecko(), &changed, aIsImportant);
   if (!changed) {
     // Parsing failed -- but we don't throw an exception for that.
     return NS_OK;
   }
 
   return SetCSSDeclaration(decl);
 }
 
 nsresult
 nsDOMCSSDeclaration::ParseCustomPropertyValue(const nsAString& aPropertyName,
                                               const nsAString& aPropValue,
                                               bool aIsImportant)
 {
   MOZ_ASSERT(nsCSSProps::IsCustomPropertyName(aPropertyName));
 
-  css::Declaration* olddecl = GetCSSDeclaration(eOperation_Modify)->AsGecko();
+  DeclarationBlock* olddecl = GetCSSDeclaration(eOperation_Modify);
   if (!olddecl) {
     return NS_ERROR_NOT_AVAILABLE;
   }
 
   CSSParsingEnvironment env;
   GetCSSParsingEnvironment(env);
   if (!env.mPrincipal) {
     return NS_ERROR_NOT_AVAILABLE;
   }
 
   // For nsDOMCSSAttributeDeclaration, SetCSSDeclaration will lead to
   // Attribute setting code, which leads in turn to BeginUpdate.  We
   // need to start the update now so that the old rule doesn't get used
   // between when we mutate the declaration and when we set the new
   // rule (see stack in bug 209575).
   mozAutoDocConditionalContentUpdateBatch autoUpdate(DocToUpdate(), true);
-  RefPtr<css::Declaration> decl = olddecl->EnsureMutable();
+  RefPtr<DeclarationBlock> decl = olddecl->EnsureMutable();
 
   nsCSSParser cssParser(env.mCSSLoader);
   bool changed;
   cssParser.ParseVariable(Substring(aPropertyName,
                                     CSS_CUSTOM_NAME_PREFIX_LENGTH),
                           aPropValue, env.mSheetURI,
-                          env.mBaseURI, env.mPrincipal, decl,
+                          env.mBaseURI, env.mPrincipal, decl->AsGecko(),
                           &changed, aIsImportant);
   if (!changed) {
     // Parsing failed -- but we don't throw an exception for that.
     return NS_OK;
   }
 
   return SetCSSDeclaration(decl);
 }
 
 nsresult
 nsDOMCSSDeclaration::RemovePropertyInternal(nsCSSPropertyID aPropID)
 {
-  css::Declaration* olddecl =
-    GetCSSDeclaration(eOperation_RemoveProperty)->AsGecko();
+  DeclarationBlock* olddecl = GetCSSDeclaration(eOperation_RemoveProperty);
   if (!olddecl) {
     return NS_OK; // no decl, so nothing to remove
   }
 
   // For nsDOMCSSAttributeDeclaration, SetCSSDeclaration will lead to
   // Attribute setting code, which leads in turn to BeginUpdate.  We
   // need to start the update now so that the old rule doesn't get used
   // between when we mutate the declaration and when we set the new
   // rule (see stack in bug 209575).
   mozAutoDocConditionalContentUpdateBatch autoUpdate(DocToUpdate(), true);
 
-  RefPtr<css::Declaration> decl = olddecl->EnsureMutable();
-  decl->RemovePropertyByID(aPropID);
+  RefPtr<DeclarationBlock> decl = olddecl->EnsureMutable();
+  decl->AsGecko()->RemovePropertyByID(aPropID);
   return SetCSSDeclaration(decl);
 }
 
 nsresult
 nsDOMCSSDeclaration::RemovePropertyInternal(const nsAString& aPropertyName)
 {
-  css::Declaration* olddecl =
-    GetCSSDeclaration(eOperation_RemoveProperty)->AsGecko();
+  DeclarationBlock* olddecl = GetCSSDeclaration(eOperation_RemoveProperty);
   if (!olddecl) {
     return NS_OK; // no decl, so nothing to remove
   }
 
   // For nsDOMCSSAttributeDeclaration, SetCSSDeclaration will lead to
   // Attribute setting code, which leads in turn to BeginUpdate.  We
   // need to start the update now so that the old rule doesn't get used
   // between when we mutate the declaration and when we set the new
   // rule (see stack in bug 209575).
   mozAutoDocConditionalContentUpdateBatch autoUpdate(DocToUpdate(), true);
 
-  RefPtr<css::Declaration> decl = olddecl->EnsureMutable();
-  decl->RemoveProperty(aPropertyName);
+  RefPtr<DeclarationBlock> decl = olddecl->EnsureMutable();
+  decl->AsGecko()->RemoveProperty(aPropertyName);
   return SetCSSDeclaration(decl);
 }