Bug 1524314 Part 2 - Use RAII notifier classes to simplify code r=dholbert
☠☠ backed out by d08b9d599f25 ☠ ☠
authorlongsonr <longsonr@gmail.com>
Sat, 09 Mar 2019 17:50:53 +0000
changeset 521259 2d1f2814e41d53c985643fbb9c73f4af2caaa3ec
parent 521258 6838e7d3960f9888ecdfcd6eda67fa1afae76190
child 521260 d08b9d599f252613a3e68758ed2a4e9b0459066c
push id10862
push userffxbld-merge
push dateMon, 11 Mar 2019 13:01:11 +0000
treeherdermozilla-beta@a2e7f5c935da [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdholbert
bugs1524314
milestone67.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 1524314 Part 2 - Use RAII notifier classes to simplify code r=dholbert
dom/svg/SVGAnimatedPreserveAspectRatio.cpp
dom/svg/SVGAnimatedPreserveAspectRatio.h
dom/svg/SVGBoolean.cpp
dom/svg/SVGBoolean.h
dom/svg/SVGEnum.cpp
dom/svg/SVGEnum.h
dom/svg/SVGInteger.cpp
dom/svg/SVGInteger.h
dom/svg/SVGIntegerPair.cpp
dom/svg/SVGIntegerPair.h
dom/svg/SVGNumberPair.cpp
dom/svg/SVGNumberPair.h
dom/svg/SVGViewBox.cpp
dom/svg/SVGViewBox.h
dom/svg/nsSVGLength2.cpp
dom/svg/nsSVGLength2.h
dom/svg/nsSVGNumber2.cpp
dom/svg/nsSVGNumber2.h
--- a/dom/svg/SVGAnimatedPreserveAspectRatio.cpp
+++ b/dom/svg/SVGAnimatedPreserveAspectRatio.cpp
@@ -8,19 +8,20 @@
 
 #include "mozilla/ArrayUtils.h"
 #include "mozilla/SMILValue.h"
 #include "mozilla/SVGContentUtils.h"
 #include "mozilla/dom/SVGAnimatedPreserveAspectRatioBinding.h"
 #include "SMILEnumType.h"
 #include "SVGAttrTearoffTable.h"
 
-using namespace mozilla;
 using namespace mozilla::dom;
 
+namespace mozilla {
+
 ////////////////////////////////////////////////////////////////////////
 // SVGAnimatedPreserveAspectRatio class
 NS_SVG_VAL_IMPL_CYCLE_COLLECTION_WRAPPERCACHED(
     DOMSVGAnimatedPreserveAspectRatio, mSVGElement)
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(DOMSVGAnimatedPreserveAspectRatio)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(DOMSVGAnimatedPreserveAspectRatio)
 
@@ -31,16 +32,54 @@ NS_INTERFACE_MAP_END
 
 JSObject* DOMSVGAnimatedPreserveAspectRatio::WrapObject(
     JSContext* aCx, JS::Handle<JSObject*> aGivenProto) {
   return SVGAnimatedPreserveAspectRatio_Binding::Wrap(aCx, this, aGivenProto);
 }
 
 /* Implementation */
 
+//----------------------------------------------------------------------
+// Helper class: AutoChangePreserveAspectRatioNotifier
+// Stack-based helper class to pair calls to WillChangePreserveAspectRatio and
+// DidChangePreserveAspectRatio.
+class MOZ_RAII AutoChangePreserveAspectRatioNotifier {
+ public:
+  AutoChangePreserveAspectRatioNotifier(
+      SVGAnimatedPreserveAspectRatio* aPreserveAspectRatio,
+      SVGElement* aSVGElement,
+      bool aDoSetAttr = true MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
+      : mPreserveAspectRatio(aPreserveAspectRatio),
+        mSVGElement(aSVGElement),
+        mDoSetAttr(aDoSetAttr) {
+    MOZ_GUARD_OBJECT_NOTIFIER_INIT;
+    MOZ_ASSERT(mPreserveAspectRatio, "Expecting non-null preserveAspectRatio");
+    MOZ_ASSERT(mSVGElement, "Expecting non-null element");
+    if (mDoSetAttr) {
+      mEmptyOrOldValue = mSVGElement->WillChangePreserveAspectRatio();
+    }
+  }
+
+  ~AutoChangePreserveAspectRatioNotifier() {
+    if (mDoSetAttr) {
+      mSVGElement->DidChangePreserveAspectRatio(mEmptyOrOldValue);
+    }
+    if (mPreserveAspectRatio->mIsAnimated) {
+      mSVGElement->AnimationNeedsResample();
+    }
+  }
+
+ private:
+  SVGAnimatedPreserveAspectRatio* const mPreserveAspectRatio;
+  SVGElement* const mSVGElement;
+  nsAttrValue mEmptyOrOldValue;
+  bool mDoSetAttr;
+  MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
+};
+
 static SVGAttrTearoffTable<SVGAnimatedPreserveAspectRatio,
                            DOMSVGAnimatedPreserveAspectRatio>
     sSVGAnimatedPAspectRatioTearoffTable;
 static SVGAttrTearoffTable<SVGAnimatedPreserveAspectRatio,
                            DOMSVGPreserveAspectRatio>
     sBaseSVGPAspectRatioTearoffTable;
 static SVGAttrTearoffTable<SVGAnimatedPreserveAspectRatio,
                            DOMSVGPreserveAspectRatio>
@@ -81,58 +120,45 @@ DOMSVGAnimatedPreserveAspectRatio::AnimV
 nsresult SVGAnimatedPreserveAspectRatio::SetBaseValueString(
     const nsAString& aValueAsString, SVGElement* aSVGElement, bool aDoSetAttr) {
   SVGPreserveAspectRatio val;
   nsresult res = SVGPreserveAspectRatio::FromString(aValueAsString, &val);
   if (NS_FAILED(res)) {
     return res;
   }
 
-  nsAttrValue emptyOrOldValue;
-  if (aDoSetAttr) {
-    emptyOrOldValue = aSVGElement->WillChangePreserveAspectRatio();
-  }
+  AutoChangePreserveAspectRatioNotifier notifier(this, aSVGElement, aDoSetAttr);
 
   mBaseVal = val;
   mIsBaseSet = true;
-
   if (!mIsAnimated) {
     mAnimVal = mBaseVal;
   }
-  if (aDoSetAttr) {
-    aSVGElement->DidChangePreserveAspectRatio(emptyOrOldValue);
-  }
-  if (mIsAnimated) {
-    aSVGElement->AnimationNeedsResample();
-  }
   return NS_OK;
 }
 
 void SVGAnimatedPreserveAspectRatio::GetBaseValueString(
     nsAString& aValueAsString) const {
   mBaseVal.ToString(aValueAsString);
 }
 
 void SVGAnimatedPreserveAspectRatio::SetBaseValue(
     const SVGPreserveAspectRatio& aValue, SVGElement* aSVGElement) {
   if (mIsBaseSet && mBaseVal == aValue) {
     return;
   }
 
-  nsAttrValue emptyOrOldValue = aSVGElement->WillChangePreserveAspectRatio();
+  AutoChangePreserveAspectRatioNotifier notifier(this, aSVGElement);
+
   mBaseVal = aValue;
   mIsBaseSet = true;
 
   if (!mIsAnimated) {
     mAnimVal = mBaseVal;
   }
-  aSVGElement->DidChangePreserveAspectRatio(emptyOrOldValue);
-  if (mIsAnimated) {
-    aSVGElement->AnimationNeedsResample();
-  }
 }
 
 static uint64_t PackPreserveAspectRatio(const SVGPreserveAspectRatio& par) {
   // All preserveAspectRatio values are enum values (do not interpolate), so we
   // can safely collate them and treat them as a single enum as for SMIL.
   uint64_t packed = 0;
   packed |= uint64_t(par.GetAlign()) << 8;
   packed |= uint64_t(par.GetMeetOrSlice());
@@ -208,8 +234,10 @@ void SMILPreserveAspectRatio::ClearAnimV
 nsresult SMILPreserveAspectRatio::SetAnimValue(const SMILValue& aValue) {
   NS_ASSERTION(aValue.mType == SMILEnumType::Singleton(),
                "Unexpected type to assign animated value");
   if (aValue.mType == SMILEnumType::Singleton()) {
     mVal->SetAnimValue(aValue.mU.mUint, mSVGElement);
   }
   return NS_OK;
 }
+
+}  // namespace mozilla
--- a/dom/svg/SVGAnimatedPreserveAspectRatio.h
+++ b/dom/svg/SVGAnimatedPreserveAspectRatio.h
@@ -20,16 +20,18 @@ namespace mozilla {
 class SMILValue;
 
 namespace dom {
 class DOMSVGAnimatedPreserveAspectRatio;
 class SVGAnimationElement;
 }  // namespace dom
 
 class SVGAnimatedPreserveAspectRatio final {
+  friend class AutoChangePreserveAspectRatioNotifier;
+
  public:
   void Init() {
     mBaseVal.mAlign =
         dom::SVGPreserveAspectRatio_Binding::SVG_PRESERVEASPECTRATIO_XMIDYMID;
     mBaseVal.mMeetOrSlice =
         dom::SVGPreserveAspectRatio_Binding::SVG_MEETORSLICE_MEET;
     mAnimVal = mBaseVal;
     mIsAnimated = false;
--- a/dom/svg/SVGBoolean.cpp
+++ b/dom/svg/SVGBoolean.cpp
@@ -13,16 +13,43 @@
 #include "mozilla/dom/SVGAnimatedBoolean.h"
 
 using namespace mozilla::dom;
 
 namespace mozilla {
 
 /* Implementation */
 
+//----------------------------------------------------------------------
+// Helper class: AutoChangeBooleanNotifier
+// Stack-based helper class to ensure DidChangeBoolean is called.
+class MOZ_RAII AutoChangeBooleanNotifier {
+ public:
+  AutoChangeBooleanNotifier(SVGBoolean* aBoolean,
+                            SVGElement* aSVGElement
+                                MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
+      : mBoolean(aBoolean), mSVGElement(aSVGElement) {
+    MOZ_GUARD_OBJECT_NOTIFIER_INIT;
+    MOZ_ASSERT(mBoolean, "Expecting non-null boolean");
+    MOZ_ASSERT(mSVGElement, "Expecting non-null element");
+  }
+
+  ~AutoChangeBooleanNotifier() {
+    mSVGElement->DidChangeBoolean(mBoolean->mAttrEnum);
+    if (mBoolean->mIsAnimated) {
+      mSVGElement->AnimationNeedsResample();
+    }
+  }
+
+ private:
+  SVGBoolean* const mBoolean;
+  SVGElement* const mSVGElement;
+  MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
+};
+
 static inline SVGAttrTearoffTable<SVGBoolean, SVGAnimatedBoolean>&
 SVGAnimatedBooleanTearoffTable() {
   static SVGAttrTearoffTable<SVGBoolean, SVGAnimatedBoolean>
       sSVGAnimatedBooleanTearoffTable;
   return sSVGAnimatedBooleanTearoffTable;
 }
 
 static bool GetValueFromString(const nsAString& aValueAsString, bool& aValue) {
@@ -75,23 +102,22 @@ nsAtom* SVGBoolean::GetBaseValueAtom() c
   return mBaseVal ? nsGkAtoms::_true : nsGkAtoms::_false;
 }
 
 void SVGBoolean::SetBaseValue(bool aValue, SVGElement* aSVGElement) {
   if (aValue == mBaseVal) {
     return;
   }
 
+  AutoChangeBooleanNotifier notifier(this, aSVGElement);
+
   mBaseVal = aValue;
   if (!mIsAnimated) {
     mAnimVal = mBaseVal;
-  } else {
-    aSVGElement->AnimationNeedsResample();
   }
-  aSVGElement->DidChangeBoolean(mAttrEnum);
 }
 
 void SVGBoolean::SetAnimValue(bool aValue, SVGElement* aSVGElement) {
   if (mIsAnimated && mAnimVal == aValue) {
     return;
   }
   mAnimVal = aValue;
   mIsAnimated = true;
--- a/dom/svg/SVGBoolean.h
+++ b/dom/svg/SVGBoolean.h
@@ -22,16 +22,17 @@ class SMILValue;
 namespace dom {
 class SVGAnimationElement;
 class SVGAnimatedBoolean;
 class SVGElement;
 }  // namespace dom
 
 class SVGBoolean {
  public:
+  friend class AutoChangeBooleanNotifier;
   typedef mozilla::dom::SVGElement SVGElement;
 
   void Init(uint8_t aAttrEnum = 0xff, bool aValue = false) {
     mAnimVal = mBaseVal = aValue;
     mAttrEnum = aAttrEnum;
     mIsAnimated = false;
   }
 
--- a/dom/svg/SVGEnum.cpp
+++ b/dom/svg/SVGEnum.cpp
@@ -12,16 +12,42 @@
 #include "nsError.h"
 #include "SMILEnumType.h"
 #include "SVGAttrTearoffTable.h"
 
 using namespace mozilla::dom;
 
 namespace mozilla {
 
+//----------------------------------------------------------------------
+// Helper class: AutoChangeEnumNotifier
+// Stack-based helper class to ensure DidChangeEnum is called.
+class MOZ_RAII AutoChangeEnumNotifier {
+ public:
+  AutoChangeEnumNotifier(
+      SVGEnum* aEnum, SVGElement* aSVGElement MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
+      : mEnum(aEnum), mSVGElement(aSVGElement) {
+    MOZ_GUARD_OBJECT_NOTIFIER_INIT;
+    MOZ_ASSERT(mEnum, "Expecting non-null enum");
+    MOZ_ASSERT(mSVGElement, "Expecting non-null element");
+  }
+
+  ~AutoChangeEnumNotifier() {
+    mSVGElement->DidChangeEnum(mEnum->mAttrEnum);
+    if (mEnum->mIsAnimated) {
+      mSVGElement->AnimationNeedsResample();
+    }
+  }
+
+ private:
+  SVGEnum* const mEnum;
+  SVGElement* const mSVGElement;
+  MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
+};
+
 static SVGAttrTearoffTable<SVGEnum, SVGEnum::DOMAnimatedEnum>
     sSVGAnimatedEnumTearoffTable;
 
 const SVGEnumMapping* SVGEnum::GetMapping(SVGElement* aSVGElement) {
   SVGElement::EnumAttributesInfo info = aSVGElement->GetEnumInfo();
 
   NS_ASSERTION(info.mEnumCount > 0 && mAttrEnum < info.mEnumCount,
                "mapping request for a non-attrib enum");
@@ -70,23 +96,22 @@ nsAtom* SVGEnum::GetBaseValueAtom(SVGEle
 
 nsresult SVGEnum::SetBaseValue(uint16_t aValue, SVGElement* aSVGElement) {
   const SVGEnumMapping* mapping = GetMapping(aSVGElement);
 
   while (mapping && mapping->mKey) {
     if (mapping->mVal == aValue) {
       mIsBaseSet = true;
       if (mBaseVal != uint8_t(aValue)) {
+        AutoChangeEnumNotifier notifier(this, aSVGElement);
+
         mBaseVal = uint8_t(aValue);
         if (!mIsAnimated) {
           mAnimVal = mBaseVal;
-        } else {
-          aSVGElement->AnimationNeedsResample();
         }
-        aSVGElement->DidChangeEnum(mAttrEnum);
       }
       return NS_OK;
     }
     mapping++;
   }
   return NS_ERROR_DOM_TYPE_ERR;
 }
 
--- a/dom/svg/SVGEnum.h
+++ b/dom/svg/SVGEnum.h
@@ -29,16 +29,17 @@ typedef uint8_t SVGEnumValue;
 
 struct SVGEnumMapping {
   nsStaticAtom* const mKey;
   const SVGEnumValue mVal;
 };
 
 class SVGEnum {
  public:
+  friend class AutoChangeEnumNotifier;
   typedef mozilla::dom::SVGElement SVGElement;
 
   void Init(uint8_t aAttrEnum, uint16_t aValue) {
     mAnimVal = mBaseVal = uint8_t(aValue);
     mAttrEnum = aAttrEnum;
     mIsAnimated = false;
     mIsBaseSet = false;
   }
--- a/dom/svg/SVGInteger.cpp
+++ b/dom/svg/SVGInteger.cpp
@@ -13,16 +13,43 @@
 #include "mozilla/SVGContentUtils.h"
 
 using namespace mozilla::dom;
 
 namespace mozilla {
 
 /* Implementation */
 
+//----------------------------------------------------------------------
+// Helper class: AutoChangeIntegerNotifier
+// Stack-based helper class ensure DidChangeInteger is called.
+class MOZ_RAII AutoChangeIntegerNotifier {
+ public:
+  AutoChangeIntegerNotifier(SVGInteger *aInteger,
+                            SVGElement *aSVGElement
+                                MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
+      : mInteger(aInteger), mSVGElement(aSVGElement) {
+    MOZ_GUARD_OBJECT_NOTIFIER_INIT;
+    MOZ_ASSERT(mInteger, "Expecting non-null integer");
+    MOZ_ASSERT(mSVGElement, "Expecting non-null element");
+  }
+
+  ~AutoChangeIntegerNotifier() {
+    mSVGElement->DidChangeInteger(mInteger->mAttrEnum);
+    if (mInteger->mIsAnimated) {
+      mSVGElement->AnimationNeedsResample();
+    }
+  }
+
+ private:
+  SVGInteger *const mInteger;
+  SVGElement *const mSVGElement;
+  MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
+};
+
 static SVGAttrTearoffTable<SVGInteger, SVGInteger::DOMAnimatedInteger>
     sSVGAnimatedIntegerTearoffTable;
 
 nsresult SVGInteger::SetBaseValueString(const nsAString &aValueAsString,
                                         SVGElement *aSVGElement) {
   int32_t value;
 
   if (!SVGContentUtils::ParseInteger(aValueAsString, value)) {
@@ -48,24 +75,23 @@ void SVGInteger::SetBaseValue(int aValue
   // We can't just rely on SetParsedAttrValue (as called by DidChangeInteger)
   // detecting redundant changes since it will compare false if the existing
   // attribute value has an associated serialized version (a string value) even
   // if the integers match due to the way integers are stored in nsAttrValue.
   if (aValue == mBaseVal && mIsBaseSet) {
     return;
   }
 
+  AutoChangeIntegerNotifier notifier(this, aSVGElement);
+
   mBaseVal = aValue;
   mIsBaseSet = true;
   if (!mIsAnimated) {
     mAnimVal = mBaseVal;
-  } else {
-    aSVGElement->AnimationNeedsResample();
   }
-  aSVGElement->DidChangeInteger(mAttrEnum);
 }
 
 void SVGInteger::SetAnimValue(int aValue, SVGElement *aSVGElement) {
   if (mIsAnimated && aValue == mAnimVal) {
     return;
   }
   mAnimVal = aValue;
   mIsAnimated = true;
--- a/dom/svg/SVGInteger.h
+++ b/dom/svg/SVGInteger.h
@@ -20,16 +20,17 @@ namespace mozilla {
 class SMILValue;
 
 namespace dom {
 class SVGAnimationElement;
 }  // namespace dom
 
 class SVGInteger {
  public:
+  friend class AutoChangeIntegerNotifier;
   typedef mozilla::dom::SVGElement SVGElement;
 
   void Init(uint8_t aAttrEnum = 0xff, int32_t aValue = 0) {
     mAnimVal = mBaseVal = aValue;
     mAttrEnum = aAttrEnum;
     mIsAnimated = false;
     mIsBaseSet = false;
   }
--- a/dom/svg/SVGIntegerPair.cpp
+++ b/dom/svg/SVGIntegerPair.cpp
@@ -13,16 +13,49 @@
 #include "SVGIntegerPairSMILType.h"
 #include "mozilla/SMILValue.h"
 #include "mozilla/SVGContentUtils.h"
 
 using namespace mozilla::dom;
 
 namespace mozilla {
 
+//----------------------------------------------------------------------
+// Helper class: AutoChangeIntegerPairNotifier
+// Stack-based helper class to pair calls to WillChangeIntegerPair and
+// DidChangeIntegerPair.
+class MOZ_RAII AutoChangeIntegerPairNotifier {
+ public:
+  AutoChangeIntegerPairNotifier(SVGIntegerPair* aIntegerPair,
+                                SVGElement* aSVGElement
+                                    MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
+      : mIntegerPair(aIntegerPair), mSVGElement(aSVGElement) {
+    MOZ_GUARD_OBJECT_NOTIFIER_INIT;
+    MOZ_ASSERT(mIntegerPair, "Expecting non-null integerPair");
+    MOZ_ASSERT(mSVGElement, "Expecting non-null element");
+
+    mEmptyOrOldValue =
+        mSVGElement->WillChangeIntegerPair(mIntegerPair->mAttrEnum);
+  }
+
+  ~AutoChangeIntegerPairNotifier() {
+    mSVGElement->DidChangeIntegerPair(mIntegerPair->mAttrEnum,
+                                      mEmptyOrOldValue);
+    if (mIntegerPair->mIsAnimated) {
+      mSVGElement->AnimationNeedsResample();
+    }
+  }
+
+ private:
+  SVGIntegerPair* const mIntegerPair;
+  SVGElement* const mSVGElement;
+  nsAttrValue mEmptyOrOldValue;
+  MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
+};
+
 static SVGAttrTearoffTable<SVGIntegerPair, SVGIntegerPair::DOMAnimatedInteger>
     sSVGFirstAnimatedIntegerTearoffTable;
 static SVGAttrTearoffTable<SVGIntegerPair, SVGIntegerPair::DOMAnimatedInteger>
     sSVGSecondAnimatedIntegerTearoffTable;
 
 /* Implementation */
 
 static nsresult ParseIntegerOptionalInteger(const nsAString& aValue,
@@ -90,44 +123,40 @@ void SVGIntegerPair::GetBaseValueString(
 
 void SVGIntegerPair::SetBaseValue(int32_t aValue, PairIndex aPairIndex,
                                   SVGElement* aSVGElement) {
   uint32_t index = (aPairIndex == eFirst ? 0 : 1);
   if (mIsBaseSet && mBaseVal[index] == aValue) {
     return;
   }
 
-  nsAttrValue emptyOrOldValue = aSVGElement->WillChangeIntegerPair(mAttrEnum);
+  AutoChangeIntegerPairNotifier notifier(this, aSVGElement);
+
   mBaseVal[index] = aValue;
   mIsBaseSet = true;
   if (!mIsAnimated) {
     mAnimVal[index] = aValue;
-  } else {
-    aSVGElement->AnimationNeedsResample();
   }
-  aSVGElement->DidChangeIntegerPair(mAttrEnum, emptyOrOldValue);
 }
 
 void SVGIntegerPair::SetBaseValues(int32_t aValue1, int32_t aValue2,
                                    SVGElement* aSVGElement) {
   if (mIsBaseSet && mBaseVal[0] == aValue1 && mBaseVal[1] == aValue2) {
     return;
   }
 
-  nsAttrValue emptyOrOldValue = aSVGElement->WillChangeIntegerPair(mAttrEnum);
+  AutoChangeIntegerPairNotifier notifier(this, aSVGElement);
+
   mBaseVal[0] = aValue1;
   mBaseVal[1] = aValue2;
   mIsBaseSet = true;
   if (!mIsAnimated) {
     mAnimVal[0] = aValue1;
     mAnimVal[1] = aValue2;
-  } else {
-    aSVGElement->AnimationNeedsResample();
   }
-  aSVGElement->DidChangeIntegerPair(mAttrEnum, emptyOrOldValue);
 }
 
 void SVGIntegerPair::SetAnimValue(const int32_t aValue[2],
                                   SVGElement* aSVGElement) {
   if (mIsAnimated && mAnimVal[0] == aValue[0] && mAnimVal[1] == aValue[1]) {
     return;
   }
   mAnimVal[0] = aValue[0];
--- a/dom/svg/SVGIntegerPair.h
+++ b/dom/svg/SVGIntegerPair.h
@@ -20,16 +20,17 @@ class SMILValue;
 
 namespace dom {
 class SVGAnimationElement;
 class SVGElement;
 }  // namespace dom
 
 class SVGIntegerPair {
  public:
+  friend class AutoChangeIntegerPairNotifier;
   typedef mozilla::dom::SVGElement SVGElement;
 
   enum PairIndex { eFirst, eSecond };
 
   void Init(uint8_t aAttrEnum = 0xff, int32_t aValue1 = 0,
             int32_t aValue2 = 0) {
     mAnimVal[0] = mBaseVal[0] = aValue1;
     mAnimVal[1] = mBaseVal[1] = aValue2;
--- a/dom/svg/SVGNumberPair.cpp
+++ b/dom/svg/SVGNumberPair.cpp
@@ -11,16 +11,48 @@
 #include "SVGNumberPairSMILType.h"
 #include "mozilla/SMILValue.h"
 #include "mozilla/SVGContentUtils.h"
 
 using namespace mozilla::dom;
 
 namespace mozilla {
 
+//----------------------------------------------------------------------
+// Helper class: AutoChangeNumberPairNotifier
+// Stack-based helper class to pair calls to WillChangeNumberPair and
+// DidChangeNumberPair.
+class MOZ_RAII AutoChangeNumberPairNotifier {
+ public:
+  AutoChangeNumberPairNotifier(SVGNumberPair* aNumberPair,
+                               SVGElement* aSVGElement
+                                   MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
+      : mNumberPair(aNumberPair), mSVGElement(aSVGElement) {
+    MOZ_GUARD_OBJECT_NOTIFIER_INIT;
+    MOZ_ASSERT(mNumberPair, "Expecting non-null numberPair");
+    MOZ_ASSERT(mSVGElement, "Expecting non-null element");
+
+    mEmptyOrOldValue =
+        mSVGElement->WillChangeNumberPair(mNumberPair->mAttrEnum);
+  }
+
+  ~AutoChangeNumberPairNotifier() {
+    mSVGElement->DidChangeNumberPair(mNumberPair->mAttrEnum, mEmptyOrOldValue);
+    if (mNumberPair->mIsAnimated) {
+      mSVGElement->AnimationNeedsResample();
+    }
+  }
+
+ private:
+  SVGNumberPair* const mNumberPair;
+  SVGElement* const mSVGElement;
+  nsAttrValue mEmptyOrOldValue;
+  MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
+};
+
 static SVGAttrTearoffTable<SVGNumberPair, SVGNumberPair::DOMAnimatedNumber>
     sSVGFirstAnimatedNumberTearoffTable;
 static SVGAttrTearoffTable<SVGNumberPair, SVGNumberPair::DOMAnimatedNumber>
     sSVGSecondAnimatedNumberTearoffTable;
 
 static nsresult ParseNumberOptionalNumber(const nsAString& aValue,
                                           float aValues[2]) {
   nsCharSeparatedTokenizerTemplate<nsContentUtils::IsHTMLWhitespace> tokenizer(
@@ -84,43 +116,41 @@ void SVGNumberPair::GetBaseValueString(n
 }
 
 void SVGNumberPair::SetBaseValue(float aValue, PairIndex aPairIndex,
                                  SVGElement* aSVGElement) {
   uint32_t index = (aPairIndex == eFirst ? 0 : 1);
   if (mIsBaseSet && mBaseVal[index] == aValue) {
     return;
   }
-  nsAttrValue emptyOrOldValue = aSVGElement->WillChangeNumberPair(mAttrEnum);
+
+  AutoChangeNumberPairNotifier notifier(this, aSVGElement);
+
   mBaseVal[index] = aValue;
   mIsBaseSet = true;
   if (!mIsAnimated) {
     mAnimVal[index] = aValue;
-  } else {
-    aSVGElement->AnimationNeedsResample();
   }
-  aSVGElement->DidChangeNumberPair(mAttrEnum, emptyOrOldValue);
 }
 
 void SVGNumberPair::SetBaseValues(float aValue1, float aValue2,
                                   SVGElement* aSVGElement) {
   if (mIsBaseSet && mBaseVal[0] == aValue1 && mBaseVal[1] == aValue2) {
     return;
   }
-  nsAttrValue emptyOrOldValue = aSVGElement->WillChangeNumberPair(mAttrEnum);
+
+  AutoChangeNumberPairNotifier notifier(this, aSVGElement);
+
   mBaseVal[0] = aValue1;
   mBaseVal[1] = aValue2;
   mIsBaseSet = true;
   if (!mIsAnimated) {
     mAnimVal[0] = aValue1;
     mAnimVal[1] = aValue2;
-  } else {
-    aSVGElement->AnimationNeedsResample();
   }
-  aSVGElement->DidChangeNumberPair(mAttrEnum, emptyOrOldValue);
 }
 
 void SVGNumberPair::SetAnimValue(const float aValue[2],
                                  SVGElement* aSVGElement) {
   if (mIsAnimated && mAnimVal[0] == aValue[0] && mAnimVal[1] == aValue[1]) {
     return;
   }
   mAnimVal[0] = aValue[0];
--- a/dom/svg/SVGNumberPair.h
+++ b/dom/svg/SVGNumberPair.h
@@ -22,16 +22,17 @@ class SMILValue;
 
 namespace dom {
 class SVGAnimationElement;
 class SVGElement;
 }  // namespace dom
 
 class SVGNumberPair {
  public:
+  friend class AutoChangeNumberPairNotifier;
   typedef mozilla::dom::SVGElement SVGElement;
 
   enum PairIndex { eFirst, eSecond };
 
   void Init(uint8_t aAttrEnum = 0xff, float aValue1 = 0, float aValue2 = 0) {
     mAnimVal[0] = mBaseVal[0] = aValue1;
     mAnimVal[1] = mBaseVal[1] = aValue2;
     mAttrEnum = aAttrEnum;
--- a/dom/svg/SVGViewBox.cpp
+++ b/dom/svg/SVGViewBox.cpp
@@ -87,16 +87,52 @@ NS_INTERFACE_MAP_END
 
 static SVGAttrTearoffTable<SVGViewBox, SVGViewBox::DOMBaseVal>
     sBaseSVGViewBoxTearoffTable;
 static SVGAttrTearoffTable<SVGViewBox, SVGViewBox::DOMAnimVal>
     sAnimSVGViewBoxTearoffTable;
 SVGAttrTearoffTable<SVGViewBox, SVGAnimatedRect>
     SVGViewBox::sSVGAnimatedRectTearoffTable;
 
+//----------------------------------------------------------------------
+// Helper class: AutoChangeViewBoxNotifier
+// Stack-based helper class to pair calls to WillChangeViewBox and
+// DidChangeViewBox.
+class MOZ_RAII AutoChangeViewBoxNotifier {
+ public:
+  AutoChangeViewBoxNotifier(
+      SVGViewBox* aViewBox, SVGElement* aSVGElement,
+      bool aDoSetAttr = true MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
+      : mViewBox(aViewBox), mSVGElement(aSVGElement), mDoSetAttr(aDoSetAttr) {
+    MOZ_GUARD_OBJECT_NOTIFIER_INIT;
+    MOZ_ASSERT(mViewBox, "Expecting non-null viewBox");
+    MOZ_ASSERT(mSVGElement, "Expecting non-null element");
+
+    if (mDoSetAttr) {
+      mEmptyOrOldValue = mSVGElement->WillChangeViewBox();
+    }
+  }
+
+  ~AutoChangeViewBoxNotifier() {
+    if (mDoSetAttr) {
+      mSVGElement->DidChangeViewBox(mEmptyOrOldValue);
+    }
+    if (mViewBox->mAnimVal) {
+      mSVGElement->AnimationNeedsResample();
+    }
+  }
+
+ private:
+  SVGViewBox* const mViewBox;
+  SVGElement* const mSVGElement;
+  nsAttrValue mEmptyOrOldValue;
+  bool mDoSetAttr;
+  MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
+};
+
 /* Implementation of SVGViewBox methods */
 
 void SVGViewBox::Init() {
   mHasBaseVal = false;
   // We shouldn't use mBaseVal for rendering (its usages should be guarded with
   // "mHasBaseVal" checks), but just in case we do by accident, this will
   // ensure that we treat it as "none" and ignore its numeric values:
   mBaseVal.none = true;
@@ -139,54 +175,41 @@ void SVGViewBox::SetBaseValue(const SVGV
     // This method is used to set a single x, y, width
     // or height value. It can't create a base value
     // as the other components may be undefined. We record
     // the new value though, so as not to lose data.
     mBaseVal = aRect;
     return;
   }
 
-  nsAttrValue emptyOrOldValue = aSVGElement->WillChangeViewBox();
+  AutoChangeViewBoxNotifier notifier(this, aSVGElement);
 
   mBaseVal = aRect;
   mHasBaseVal = true;
-
-  aSVGElement->DidChangeViewBox(emptyOrOldValue);
-  if (mAnimVal) {
-    aSVGElement->AnimationNeedsResample();
-  }
 }
 
 nsresult SVGViewBox::SetBaseValueString(const nsAString& aValue,
                                         SVGElement* aSVGElement,
                                         bool aDoSetAttr) {
   SVGViewBoxRect viewBox;
 
   nsresult rv = SVGViewBoxRect::FromString(aValue, &viewBox);
   if (NS_FAILED(rv)) {
     return rv;
   }
   // Comparison against mBaseVal is only valid if we currently have a base val.
   if (mHasBaseVal && viewBox == mBaseVal) {
     return NS_OK;
   }
 
-  nsAttrValue emptyOrOldValue;
-  if (aDoSetAttr) {
-    emptyOrOldValue = aSVGElement->WillChangeViewBox();
-  }
+  AutoChangeViewBoxNotifier notifier(this, aSVGElement, aDoSetAttr);
+
   mHasBaseVal = true;
   mBaseVal = viewBox;
 
-  if (aDoSetAttr) {
-    aSVGElement->DidChangeViewBox(emptyOrOldValue);
-  }
-  if (mAnimVal) {
-    aSVGElement->AnimationNeedsResample();
-  }
   return NS_OK;
 }
 
 void SVGViewBox::GetBaseValueString(nsAString& aValue) const {
   if (mBaseVal.none) {
     aValue.AssignLiteral("none");
     return;
   }
@@ -202,18 +225,17 @@ already_AddRefed<SVGAnimatedRect> SVGVie
   if (!domAnimatedRect) {
     domAnimatedRect = new SVGAnimatedRect(this, aSVGElement);
     sSVGAnimatedRectTearoffTable.AddTearoff(this, domAnimatedRect);
   }
 
   return domAnimatedRect.forget();
 }
 
-already_AddRefed<SVGIRect> SVGViewBox::ToDOMBaseVal(
-    SVGElement* aSVGElement) {
+already_AddRefed<SVGIRect> SVGViewBox::ToDOMBaseVal(SVGElement* aSVGElement) {
   if (!mHasBaseVal || mBaseVal.none) {
     return nullptr;
   }
 
   RefPtr<DOMBaseVal> domBaseVal = sBaseSVGViewBoxTearoffTable.GetTearoff(this);
   if (!domBaseVal) {
     domBaseVal = new DOMBaseVal(this, aSVGElement);
     sBaseSVGViewBoxTearoffTable.AddTearoff(this, domBaseVal);
@@ -221,18 +243,17 @@ already_AddRefed<SVGIRect> SVGViewBox::T
 
   return domBaseVal.forget();
 }
 
 SVGViewBox::DOMBaseVal::~DOMBaseVal() {
   sBaseSVGViewBoxTearoffTable.RemoveTearoff(mVal);
 }
 
-already_AddRefed<SVGIRect> SVGViewBox::ToDOMAnimVal(
-    SVGElement* aSVGElement) {
+already_AddRefed<SVGIRect> SVGViewBox::ToDOMAnimVal(SVGElement* aSVGElement) {
   if ((mAnimVal && mAnimVal->none) ||
       (!mAnimVal && (!mHasBaseVal || mBaseVal.none))) {
     return nullptr;
   }
 
   RefPtr<DOMAnimVal> domAnimVal = sAnimSVGViewBoxTearoffTable.GetTearoff(this);
   if (!domAnimVal) {
     domAnimVal = new DOMAnimVal(this, aSVGElement);
--- a/dom/svg/SVGViewBox.h
+++ b/dom/svg/SVGViewBox.h
@@ -42,16 +42,17 @@ struct SVGViewBoxRect {
         none(rhs.none) {}
   bool operator==(const SVGViewBoxRect& aOther) const;
 
   static nsresult FromString(const nsAString& aStr, SVGViewBoxRect* aViewBox);
 };
 
 class SVGViewBox {
  public:
+  friend class AutoChangeViewBoxNotifier;
   typedef mozilla::dom::SVGElement SVGElement;
 
   void Init();
 
   /**
    * Returns true if the corresponding "viewBox" attribute defined a rectangle
    * with finite values and nonnegative width/height.
    * Returns false if the viewBox was set to an invalid
--- a/dom/svg/nsSVGLength2.cpp
+++ b/dom/svg/nsSVGLength2.cpp
@@ -17,16 +17,52 @@
 #include "SMILFloatType.h"
 #include "SVGAttrTearoffTable.h"
 #include "nsSVGIntegrationUtils.h"
 #include "nsTextFormatter.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
+//----------------------------------------------------------------------
+// Helper class: AutoChangeLengthNotifier
+// Stack-based helper class to pair calls to WillChangeLength and
+// DidChangeLength.
+class MOZ_RAII AutoChangeLengthNotifier {
+ public:
+  AutoChangeLengthNotifier(
+      nsSVGLength2* aLength, SVGElement* aSVGElement,
+      bool aDoSetAttr = true MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
+      : mLength(aLength), mSVGElement(aSVGElement), mDoSetAttr(aDoSetAttr) {
+    MOZ_GUARD_OBJECT_NOTIFIER_INIT;
+    MOZ_ASSERT(mLength, "Expecting non-null length");
+    MOZ_ASSERT(mSVGElement, "Expecting non-null element");
+
+    if (mDoSetAttr) {
+      mEmptyOrOldValue = mSVGElement->WillChangeLength(mLength->mAttrEnum);
+    }
+  }
+
+  ~AutoChangeLengthNotifier() {
+    if (mDoSetAttr) {
+      mSVGElement->DidChangeLength(mLength->mAttrEnum, mEmptyOrOldValue);
+    }
+    if (mLength->mIsAnimated) {
+      mSVGElement->AnimationNeedsResample();
+    }
+  }
+
+ private:
+  nsSVGLength2* const mLength;
+  SVGElement* const mSVGElement;
+  nsAttrValue mEmptyOrOldValue;
+  bool mDoSetAttr;
+  MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
+};
+
 static const nsStaticAtom* const unitMap[] = {
     nullptr, /* SVG_LENGTHTYPE_UNKNOWN */
     nullptr, /* SVG_LENGTHTYPE_NUMBER */
     nsGkAtoms::percentage,
     nsGkAtoms::em,
     nsGkAtoms::ex,
     nsGkAtoms::px,
     nsGkAtoms::cm,
@@ -226,29 +262,22 @@ float nsSVGLength2::GetPixelsPerUnit(con
 
 void nsSVGLength2::SetBaseValueInSpecifiedUnits(float aValue,
                                                 SVGElement* aSVGElement,
                                                 bool aDoSetAttr) {
   if (mIsBaseSet && mBaseVal == aValue) {
     return;
   }
 
-  nsAttrValue emptyOrOldValue;
-  if (aDoSetAttr) {
-    emptyOrOldValue = aSVGElement->WillChangeLength(mAttrEnum);
-  }
+  AutoChangeLengthNotifier notifier(this, aSVGElement, aDoSetAttr);
+
   mBaseVal = aValue;
   mIsBaseSet = true;
   if (!mIsAnimated) {
     mAnimVal = mBaseVal;
-  } else {
-    aSVGElement->AnimationNeedsResample();
-  }
-  if (aDoSetAttr) {
-    aSVGElement->DidChangeLength(mAttrEnum, emptyOrOldValue);
   }
 }
 
 nsresult nsSVGLength2::ConvertToSpecifiedUnits(uint16_t unitType,
                                                SVGElement* aSVGElement) {
   if (!IsValidUnitType(unitType)) return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
 
   if (mIsBaseSet && mSpecifiedUnitType == uint8_t(unitType)) return NS_OK;
@@ -265,50 +294,46 @@ nsresult nsSVGLength2::ConvertToSpecifie
   if (!IsFinite(valueInSpecifiedUnits)) {
     return NS_ERROR_ILLEGAL_VALUE;
   }
 
   // Even though we're not changing the visual effect this length will have
   // on the document, we still need to send out notifications in case we have
   // mutation listeners, since the actual string value of the attribute will
   // change.
-  nsAttrValue emptyOrOldValue = aSVGElement->WillChangeLength(mAttrEnum);
+  AutoChangeLengthNotifier notifier(this, aSVGElement);
 
   mSpecifiedUnitType = uint8_t(unitType);
   // Setting aDoSetAttr to false here will ensure we don't call
   // Will/DidChangeAngle a second time (and dispatch duplicate notifications).
   SetBaseValueInSpecifiedUnits(valueInSpecifiedUnits, aSVGElement, false);
 
-  aSVGElement->DidChangeLength(mAttrEnum, emptyOrOldValue);
-
   return NS_OK;
 }
 
 nsresult nsSVGLength2::NewValueSpecifiedUnits(uint16_t unitType,
                                               float valueInSpecifiedUnits,
                                               SVGElement* aSVGElement) {
   NS_ENSURE_FINITE(valueInSpecifiedUnits, NS_ERROR_ILLEGAL_VALUE);
 
   if (!IsValidUnitType(unitType)) return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
 
   if (mIsBaseSet && mBaseVal == valueInSpecifiedUnits &&
       mSpecifiedUnitType == uint8_t(unitType)) {
     return NS_OK;
   }
 
-  nsAttrValue emptyOrOldValue = aSVGElement->WillChangeLength(mAttrEnum);
+  AutoChangeLengthNotifier notifier(this, aSVGElement);
+
   mBaseVal = valueInSpecifiedUnits;
   mIsBaseSet = true;
   mSpecifiedUnitType = uint8_t(unitType);
   if (!mIsAnimated) {
     mAnimVal = mBaseVal;
-  } else {
-    aSVGElement->AnimationNeedsResample();
   }
-  aSVGElement->DidChangeLength(mAttrEnum, emptyOrOldValue);
   return NS_OK;
 }
 
 already_AddRefed<DOMSVGLength> nsSVGLength2::ToDOMBaseVal(
     SVGElement* aSVGElement) {
   return DOMSVGLength::GetTearOff(this, aSVGElement, false);
 }
 
@@ -329,32 +354,25 @@ nsresult nsSVGLength2::SetBaseValueStrin
     return NS_ERROR_DOM_SYNTAX_ERR;
   }
 
   if (mIsBaseSet && mBaseVal == float(value) &&
       mSpecifiedUnitType == uint8_t(unitType)) {
     return NS_OK;
   }
 
-  nsAttrValue emptyOrOldValue;
-  if (aDoSetAttr) {
-    emptyOrOldValue = aSVGElement->WillChangeLength(mAttrEnum);
-  }
+  AutoChangeLengthNotifier notifier(this, aSVGElement, aDoSetAttr);
+
   mBaseVal = value;
   mIsBaseSet = true;
   mSpecifiedUnitType = uint8_t(unitType);
   if (!mIsAnimated) {
     mAnimVal = mBaseVal;
-  } else {
-    aSVGElement->AnimationNeedsResample();
   }
 
-  if (aDoSetAttr) {
-    aSVGElement->DidChangeLength(mAttrEnum, emptyOrOldValue);
-  }
   return NS_OK;
 }
 
 void nsSVGLength2::GetBaseValueString(nsAString& aValueAsString) const {
   GetValueString(aValueAsString, mBaseVal, mSpecifiedUnitType);
 }
 
 void nsSVGLength2::GetAnimValueString(nsAString& aValueAsString) const {
--- a/dom/svg/nsSVGLength2.h
+++ b/dom/svg/nsSVGLength2.h
@@ -81,16 +81,17 @@ class NonSVGFrameUserSpaceMetrics : publ
  private:
   nsIFrame* mFrame;
 };
 
 }  // namespace dom
 }  // namespace mozilla
 
 class nsSVGLength2 {
+  friend class AutoChangeLengthNotifier;
   friend class mozilla::dom::SVGAnimatedLength;
   friend class mozilla::dom::DOMSVGLength;
   typedef mozilla::dom::DOMSVGLength DOMSVGLength;
   typedef mozilla::dom::SVGElement SVGElement;
   typedef mozilla::dom::SVGViewportElement SVGViewportElement;
   typedef mozilla::dom::UserSpaceMetrics UserSpaceMetrics;
   typedef mozilla::SMILAttr SMILAttr;
   typedef mozilla::SMILValue SMILValue;
--- a/dom/svg/nsSVGNumber2.cpp
+++ b/dom/svg/nsSVGNumber2.cpp
@@ -13,16 +13,43 @@
 #include "SMILFloatType.h"
 #include "SVGAttrTearoffTable.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
 /* Implementation */
 
+//----------------------------------------------------------------------
+// Helper class: AutoChangeNumberNotifier
+// Stack-based helper class to ensure DidChangeNumber is called.
+class MOZ_RAII AutoChangeNumberNotifier {
+ public:
+  AutoChangeNumberNotifier(nsSVGNumber2* aNumber,
+                           SVGElement* aSVGElement
+                               MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
+      : mNumber(aNumber), mSVGElement(aSVGElement) {
+    MOZ_GUARD_OBJECT_NOTIFIER_INIT;
+    MOZ_ASSERT(mNumber, "Expecting non-null number");
+    MOZ_ASSERT(mSVGElement, "Expecting non-null element");
+  }
+
+  ~AutoChangeNumberNotifier() {
+    mSVGElement->DidChangeNumber(mNumber->mAttrEnum);
+    if (mNumber->mIsAnimated) {
+      mSVGElement->AnimationNeedsResample();
+    }
+  }
+
+ private:
+  nsSVGNumber2* const mNumber;
+  SVGElement* const mSVGElement;
+  MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
+};
+
 static SVGAttrTearoffTable<nsSVGNumber2, nsSVGNumber2::DOMAnimatedNumber>
     sSVGAnimatedNumberTearoffTable;
 
 static bool GetValueFromString(const nsAString& aString,
                                bool aPercentagesAllowed, float& aValue) {
   RangedPtr<const char16_t> iter = SVGContentUtils::GetStartRangedPtr(aString);
   const RangedPtr<const char16_t> end =
       SVGContentUtils::GetEndRangedPtr(aString);
@@ -71,24 +98,23 @@ void nsSVGNumber2::GetBaseValueString(ns
   aValueAsString.AppendFloat(mBaseVal);
 }
 
 void nsSVGNumber2::SetBaseValue(float aValue, SVGElement* aSVGElement) {
   if (mIsBaseSet && aValue == mBaseVal) {
     return;
   }
 
+  AutoChangeNumberNotifier notifier(this, aSVGElement);
+
   mBaseVal = aValue;
   mIsBaseSet = true;
   if (!mIsAnimated) {
     mAnimVal = mBaseVal;
-  } else {
-    aSVGElement->AnimationNeedsResample();
   }
-  aSVGElement->DidChangeNumber(mAttrEnum);
 }
 
 void nsSVGNumber2::SetAnimValue(float aValue, SVGElement* aSVGElement) {
   if (mIsAnimated && aValue == mAnimVal) {
     return;
   }
   mAnimVal = aValue;
   mIsAnimated = true;
--- a/dom/svg/nsSVGNumber2.h
+++ b/dom/svg/nsSVGNumber2.h
@@ -23,16 +23,17 @@ class SMILValue;
 
 namespace dom {
 class SVGAnimationElement;
 }  // namespace dom
 }  // namespace mozilla
 
 class nsSVGNumber2 {
  public:
+  friend class AutoChangeNumberNotifier;
   typedef mozilla::SMILAttr SMILAttr;
   typedef mozilla::SMILValue SMILValue;
   typedef mozilla::dom::SVGElement SVGElement;
 
   void Init(uint8_t aAttrEnum = 0xff, float aValue = 0) {
     mAnimVal = mBaseVal = aValue;
     mAttrEnum = aAttrEnum;
     mIsAnimated = false;