Bug 542670 Patch B: Add specialized implementations for nsISMILType::IsEqual. r=roc
authorDaniel Holbert <dholbert@cs.stanford.edu>
Sat, 20 Feb 2010 13:13:11 -0800
changeset 38350 a3cd5f10742bba8fa5f3d200e36f7ad6d56cba3d
parent 38349 da48199647d07a8e7a2a4aef12a8a4a2802fec8e
child 38351 26d2ef4bf7bf354c7a03f136a717da51b3b71958
push idunknown
push userunknown
push dateunknown
reviewersroc
bugs542670
milestone1.9.3a2pre
Bug 542670 Patch B: Add specialized implementations for nsISMILType::IsEqual. r=roc
content/smil/SMILBoolType.cpp
content/smil/SMILBoolType.h
content/smil/SMILEnumType.cpp
content/smil/SMILEnumType.h
content/smil/SMILIntegerType.cpp
content/smil/SMILIntegerType.h
content/smil/nsISMILType.h
content/smil/nsSMILCSSValueType.cpp
content/smil/nsSMILCSSValueType.h
content/smil/nsSMILFloatType.cpp
content/smil/nsSMILFloatType.h
content/smil/nsSMILNullType.cpp
content/smil/nsSMILNullType.h
content/svg/content/src/SVGOrientSMILType.cpp
content/svg/content/src/SVGOrientSMILType.h
content/svg/content/src/SVGViewBoxSMILType.cpp
content/svg/content/src/SVGViewBoxSMILType.h
content/svg/content/src/nsSVGSMILTransform.h
content/svg/content/src/nsSVGTransformSMILAttr.cpp
content/svg/content/src/nsSVGTransformSMILType.cpp
content/svg/content/src/nsSVGTransformSMILType.h
content/svg/content/src/nsSVGViewBox.cpp
content/svg/content/src/nsSVGViewBox.h
--- a/content/smil/SMILBoolType.cpp
+++ b/content/smil/SMILBoolType.cpp
@@ -65,16 +65,26 @@ nsresult
 SMILBoolType::Assign(nsSMILValue& aDest, const nsSMILValue& aSrc) const
 {
   NS_PRECONDITION(aDest.mType == aSrc.mType, "Incompatible SMIL types");
   NS_PRECONDITION(aDest.mType == this, "Unexpected SMIL value");
   aDest.mU.mBool = aSrc.mU.mBool;
   return NS_OK;
 }
 
+PRBool
+SMILBoolType::IsEqual(const nsSMILValue& aLeft,
+                      const nsSMILValue& aRight) const
+{
+  NS_PRECONDITION(aLeft.mType == aRight.mType, "Incompatible SMIL types");
+  NS_PRECONDITION(aLeft.mType == this, "Unexpected type for SMIL value");
+
+  return aLeft.mU.mBool == aRight.mU.mBool;
+}
+
 nsresult
 SMILBoolType::Add(nsSMILValue& aDest, const nsSMILValue& aValueToAdd,
                   PRUint32 aCount) const
 {
   NS_PRECONDITION(aValueToAdd.mType == aDest.mType,
                   "Trying to add invalid types");
   NS_PRECONDITION(aValueToAdd.mType == this, "Unexpected source type");
   return NS_ERROR_FAILURE; // bool values can't be added to each other
--- a/content/smil/SMILBoolType.h
+++ b/content/smil/SMILBoolType.h
@@ -50,16 +50,18 @@ public:
 protected:
   // nsISMILType Methods
   // -------------------
   virtual nsresult Init(nsSMILValue& aValue) const;
   virtual void     Destroy(nsSMILValue&) const;
   virtual nsresult Assign(nsSMILValue& aDest, const nsSMILValue& aSrc) const;
   virtual nsresult Add(nsSMILValue& aDest, const nsSMILValue& aValueToAdd,
                        PRUint32 aCount) const;
+  virtual PRBool IsEqual(const nsSMILValue& aLeft,
+                         const nsSMILValue& aRight) const;
   virtual nsresult ComputeDistance(const nsSMILValue& aFrom,
                                    const nsSMILValue& aTo,
                                    double& aDistance) const;
   virtual nsresult Interpolate(const nsSMILValue& aStartVal,
                                const nsSMILValue& aEndVal,
                                double aUnitDistance,
                                nsSMILValue& aResult) const;
 
--- a/content/smil/SMILEnumType.cpp
+++ b/content/smil/SMILEnumType.cpp
@@ -65,16 +65,26 @@ nsresult
 SMILEnumType::Assign(nsSMILValue& aDest, const nsSMILValue& aSrc) const
 {
   NS_PRECONDITION(aDest.mType == aSrc.mType, "Incompatible SMIL types");
   NS_PRECONDITION(aDest.mType == this, "Unexpected SMIL value");
   aDest.mU.mUint = aSrc.mU.mUint;
   return NS_OK;
 }
 
+PRBool
+SMILEnumType::IsEqual(const nsSMILValue& aLeft,
+                      const nsSMILValue& aRight) const
+{
+  NS_PRECONDITION(aLeft.mType == aRight.mType, "Incompatible SMIL types");
+  NS_PRECONDITION(aLeft.mType == this, "Unexpected type for SMIL value");
+
+  return aLeft.mU.mUint == aRight.mU.mUint;
+}
+
 nsresult
 SMILEnumType::Add(nsSMILValue& aDest, const nsSMILValue& aValueToAdd,
                   PRUint32 aCount) const
 {
   NS_PRECONDITION(aValueToAdd.mType == aDest.mType,
                   "Trying to add invalid types");
   NS_PRECONDITION(aValueToAdd.mType == this, "Unexpected source type");
   return NS_ERROR_FAILURE; // enum values can't be added to each other
--- a/content/smil/SMILEnumType.h
+++ b/content/smil/SMILEnumType.h
@@ -48,16 +48,18 @@ public:
   static SMILEnumType sSingleton;
 
 protected:
   // nsISMILType Methods
   // -------------------
   virtual nsresult Init(nsSMILValue& aValue) const;
   virtual void     Destroy(nsSMILValue&) const;
   virtual nsresult Assign(nsSMILValue& aDest, const nsSMILValue& aSrc) const;
+  virtual PRBool   IsEqual(const nsSMILValue& aLeft,
+                           const nsSMILValue& aRight) const;
   virtual nsresult Add(nsSMILValue& aDest, const nsSMILValue& aValueToAdd,
                        PRUint32 aCount) const;
   virtual nsresult ComputeDistance(const nsSMILValue& aFrom,
                                    const nsSMILValue& aTo,
                                    double& aDistance) const;
   virtual nsresult Interpolate(const nsSMILValue& aStartVal,
                                const nsSMILValue& aEndVal,
                                double aUnitDistance,
--- a/content/smil/SMILIntegerType.cpp
+++ b/content/smil/SMILIntegerType.cpp
@@ -64,16 +64,26 @@ nsresult
 SMILIntegerType::Assign(nsSMILValue& aDest, const nsSMILValue& aSrc) const
 {
   NS_PRECONDITION(aDest.mType == aSrc.mType, "Incompatible SMIL types");
   NS_PRECONDITION(aDest.mType == this, "Unexpected SMIL value");
   aDest.mU.mInt = aSrc.mU.mInt;
   return NS_OK;
 }
 
+PRBool
+SMILIntegerType::IsEqual(const nsSMILValue& aLeft,
+                         const nsSMILValue& aRight) const
+{
+  NS_PRECONDITION(aLeft.mType == aRight.mType, "Incompatible SMIL types");
+  NS_PRECONDITION(aLeft.mType == this, "Unexpected type for SMIL value");
+
+  return aLeft.mU.mInt == aRight.mU.mInt;
+}
+
 nsresult
 SMILIntegerType::Add(nsSMILValue& aDest, const nsSMILValue& aValueToAdd,
                      PRUint32 aCount) const
 {
   NS_PRECONDITION(aValueToAdd.mType == aDest.mType,
                   "Trying to add invalid types");
   NS_PRECONDITION(aValueToAdd.mType == this, "Unexpected source type");
   aDest.mU.mInt += aValueToAdd.mU.mInt * aCount;
--- a/content/smil/SMILIntegerType.h
+++ b/content/smil/SMILIntegerType.h
@@ -42,16 +42,18 @@
 namespace mozilla {
 
 class SMILIntegerType : public nsISMILType
 {
 public:
   virtual nsresult Init(nsSMILValue& aValue) const;
   virtual void     Destroy(nsSMILValue&) const;
   virtual nsresult Assign(nsSMILValue& aDest, const nsSMILValue& aSrc) const;
+  virtual PRBool   IsEqual(const nsSMILValue& aLeft,
+                           const nsSMILValue& aRight) const;
   virtual nsresult Add(nsSMILValue& aDest, const nsSMILValue& aValueToAdd,
                        PRUint32 aCount) const;
   virtual nsresult ComputeDistance(const nsSMILValue& aFrom,
                                    const nsSMILValue& aTo,
                                    double& aDistance) const;
   virtual nsresult Interpolate(const nsSMILValue& aStartVal,
                                const nsSMILValue& aEndVal,
                                double aUnitDistance,
--- a/content/smil/nsISMILType.h
+++ b/content/smil/nsISMILType.h
@@ -129,18 +129,17 @@ protected:
    *
    * @param   aLeft       The left-hand side of the equality check.
    * @param   aRight      The right-hand side of the equality check.
    * @return  PR_TRUE if we're sure the values are equal, PR_FALSE otherwise.
    *
    * @pre aDest.mType == aSrc.mType == this
    */
   virtual PRBool IsEqual(const nsSMILValue& aLeft,
-                         const nsSMILValue& aRight) const
-  { return PR_FALSE; }
+                         const nsSMILValue& aRight) const = 0;
 
   /**
    * Adds two values.
    *
    * The count parameter facilitates repetition.
    *
    * By equation,
    *
--- a/content/smil/nsSMILCSSValueType.cpp
+++ b/content/smil/nsSMILCSSValueType.cpp
@@ -167,16 +167,45 @@ nsSMILCSSValueType::Assign(nsSMILValue& 
     // fully-initialized dest, barely-initialized src -- clear dest
     delete destWrapper;
     aDest.mU.mPtr = destWrapper = nsnull;
   } // else, both are barely-initialized -- nothing to do.
 
   return NS_OK;
 }
 
+PRBool
+nsSMILCSSValueType::IsEqual(const nsSMILValue& aLeft,
+                            const nsSMILValue& aRight) const
+{
+  NS_ABORT_IF_FALSE(aLeft.mType == aRight.mType, "Incompatible SMIL types");
+  NS_ABORT_IF_FALSE(aLeft.mType == this, "Unexpected SMIL value");
+  const ValueWrapper* leftWrapper = ExtractValueWrapper(aLeft);
+  const ValueWrapper* rightWrapper = ExtractValueWrapper(aRight);
+
+  if (leftWrapper) {
+    if (rightWrapper) {
+      // Both non-null
+      NS_WARN_IF_FALSE(leftWrapper != rightWrapper,
+                       "Two nsSMILValues with matching ValueWrapper ptr");
+      // mPresContext doesn't really matter for equality comparison
+      return (leftWrapper->mPropID == rightWrapper->mPropID &&
+              leftWrapper->mCSSValue == rightWrapper->mCSSValue);
+    }
+    // Left non-null, right null
+    return PR_FALSE;
+  }
+  if (rightWrapper) {
+    // Left null, right non-null
+    return PR_FALSE;
+  }
+  // Both null
+  return PR_TRUE;
+}
+
 nsresult
 nsSMILCSSValueType::Add(nsSMILValue& aDest, const nsSMILValue& aValueToAdd,
                         PRUint32 aCount) const
 {
   NS_ABORT_IF_FALSE(aValueToAdd.mType == aDest.mType,
                     "Trying to add invalid types");
   NS_ABORT_IF_FALSE(aValueToAdd.mType == this, "Unexpected source type");
 
--- a/content/smil/nsSMILCSSValueType.h
+++ b/content/smil/nsSMILCSSValueType.h
@@ -59,16 +59,18 @@ public:
 
 protected:
   // nsISMILType Methods
   // -------------------
   NS_OVERRIDE virtual nsresult Init(nsSMILValue& aValue) const;
   NS_OVERRIDE virtual void     Destroy(nsSMILValue&) const;
   NS_OVERRIDE virtual nsresult Assign(nsSMILValue& aDest,
                                       const nsSMILValue& aSrc) const;
+  NS_OVERRIDE virtual PRBool   IsEqual(const nsSMILValue& aLeft,
+                                       const nsSMILValue& aRight) const;
   NS_OVERRIDE virtual nsresult Add(nsSMILValue& aDest,
                                    const nsSMILValue& aValueToAdd,
                                    PRUint32 aCount) const;
   NS_OVERRIDE virtual nsresult ComputeDistance(const nsSMILValue& aFrom,
                                                const nsSMILValue& aTo,
                                                double& aDistance) const;
   NS_OVERRIDE virtual nsresult Interpolate(const nsSMILValue& aStartVal,
                                            const nsSMILValue& aEndVal,
--- a/content/smil/nsSMILFloatType.cpp
+++ b/content/smil/nsSMILFloatType.cpp
@@ -65,16 +65,26 @@ nsresult
 nsSMILFloatType::Assign(nsSMILValue& aDest, const nsSMILValue& aSrc) const
 {
   NS_PRECONDITION(aDest.mType == aSrc.mType, "Incompatible SMIL types");
   NS_PRECONDITION(aDest.mType == this, "Unexpected SMIL value");
   aDest.mU.mDouble = aSrc.mU.mDouble;
   return NS_OK;
 }
 
+PRBool
+nsSMILFloatType::IsEqual(const nsSMILValue& aLeft,
+                         const nsSMILValue& aRight) const
+{
+  NS_PRECONDITION(aLeft.mType == aRight.mType, "Incompatible SMIL types");
+  NS_PRECONDITION(aLeft.mType == this, "Unexpected type for SMIL value");
+
+  return aLeft.mU.mDouble == aRight.mU.mDouble;
+}
+
 nsresult
 nsSMILFloatType::Add(nsSMILValue& aDest, const nsSMILValue& aValueToAdd,
                      PRUint32 aCount) const
 {
   NS_PRECONDITION(aValueToAdd.mType == aDest.mType,
                   "Trying to add invalid types");
   NS_PRECONDITION(aValueToAdd.mType == this, "Unexpected source type");
   aDest.mU.mDouble += aValueToAdd.mU.mDouble * aCount;
--- a/content/smil/nsSMILFloatType.h
+++ b/content/smil/nsSMILFloatType.h
@@ -48,16 +48,18 @@ public:
   static nsSMILFloatType sSingleton;
 
 protected:
   // nsISMILType Methods
   // -------------------
   virtual nsresult Init(nsSMILValue& aValue) const;
   virtual void     Destroy(nsSMILValue&) const;
   virtual nsresult Assign(nsSMILValue& aDest, const nsSMILValue& aSrc) const;
+  virtual PRBool   IsEqual(const nsSMILValue& aLeft,
+                           const nsSMILValue& aRight) const;
   virtual nsresult Add(nsSMILValue& aDest, const nsSMILValue& aValueToAdd,
                        PRUint32 aCount) const;
   virtual nsresult ComputeDistance(const nsSMILValue& aFrom,
                                    const nsSMILValue& aTo,
                                    double& aDistance) const;
   virtual nsresult Interpolate(const nsSMILValue& aStartVal,
                                const nsSMILValue& aEndVal,
                                double aUnitDistance,
--- a/content/smil/nsSMILNullType.cpp
+++ b/content/smil/nsSMILNullType.cpp
@@ -47,16 +47,26 @@ nsSMILNullType::Assign(nsSMILValue& aDes
 {
   NS_PRECONDITION(aDest.mType == aSrc.mType, "Incompatible SMIL types");
   NS_PRECONDITION(aSrc.mType == this, "Unexpected source type");
   aDest.mU    = aSrc.mU;
   aDest.mType = &sSingleton;
   return NS_OK;
 }
 
+PRBool
+nsSMILNullType::IsEqual(const nsSMILValue& aLeft,
+                        const nsSMILValue& aRight) const
+{
+  NS_PRECONDITION(aLeft.mType == aRight.mType, "Incompatible SMIL types");
+  NS_PRECONDITION(aLeft.mType == this, "Unexpected type for SMIL value");
+
+  return PR_TRUE;  // All null-typed values are equivalent.
+}
+
 nsresult
 nsSMILNullType::Add(nsSMILValue& aDest, const nsSMILValue& aValueToAdd,
                     PRUint32 aCount) const
 {
   NS_NOTREACHED("Adding NULL type");
   return NS_ERROR_FAILURE;
 }
 
--- a/content/smil/nsSMILNullType.h
+++ b/content/smil/nsSMILNullType.h
@@ -51,16 +51,18 @@ protected:
   // nsISMILType Methods
   // -------------------
   virtual nsresult Init(nsSMILValue& aValue) const { return NS_OK; }
   virtual void Destroy(nsSMILValue& aValue) const {}
   virtual nsresult Assign(nsSMILValue& aDest, const nsSMILValue& aSrc) const;
 
   // The remaining methods should never be called, so although they're very
   // simple they don't need to be inline.
+  virtual PRBool   IsEqual(const nsSMILValue& aLeft,
+                           const nsSMILValue& aRight) const;
   virtual nsresult Add(nsSMILValue& aDest, const nsSMILValue& aValueToAdd,
                        PRUint32 aCount) const;
   virtual nsresult ComputeDistance(const nsSMILValue& aFrom,
                                    const nsSMILValue& aTo,
                                    double& aDistance) const;
   virtual nsresult Interpolate(const nsSMILValue& aStartVal,
                                const nsSMILValue& aEndVal,
                                double aUnitDistance,
--- a/content/svg/content/src/SVGOrientSMILType.cpp
+++ b/content/svg/content/src/SVGOrientSMILType.cpp
@@ -73,16 +73,29 @@ SVGOrientSMILType::Assign(nsSMILValue& a
   NS_PRECONDITION(aDest.mType == this, "Unexpected SMIL value.");
 
   aDest.mU.mOrient.mAngle = aSrc.mU.mOrient.mAngle;
   aDest.mU.mOrient.mUnit = aSrc.mU.mOrient.mUnit;
   aDest.mU.mOrient.mOrientType = aSrc.mU.mOrient.mOrientType;
   return NS_OK;
 }
 
+PRBool
+SVGOrientSMILType::IsEqual(const nsSMILValue& aLeft,
+                           const nsSMILValue& aRight) const
+{
+  NS_PRECONDITION(aLeft.mType == aRight.mType, "Incompatible SMIL types");
+  NS_PRECONDITION(aLeft.mType == this, "Unexpected type for SMIL value");
+
+  return
+    aLeft.mU.mOrient.mAngle == aRight.mU.mOrient.mAngle &&
+    aLeft.mU.mOrient.mUnit == aRight.mU.mOrient.mUnit &&
+    aLeft.mU.mOrient.mOrientType == aRight.mU.mOrient.mOrientType;
+}
+
 nsresult
 SVGOrientSMILType::Add(nsSMILValue& aDest, const nsSMILValue& aValueToAdd,
                        PRUint32 aCount) const
 {
   NS_PRECONDITION(aValueToAdd.mType == aDest.mType,
                   "Trying to add invalid types");
   NS_PRECONDITION(aValueToAdd.mType == this, "Unexpected source type");
 
--- a/content/svg/content/src/SVGOrientSMILType.h
+++ b/content/svg/content/src/SVGOrientSMILType.h
@@ -62,16 +62,18 @@ public:
   static SVGOrientSMILType sSingleton;
 
 protected:
   // nsISMILType Methods
   // -------------------
   virtual nsresult Init(nsSMILValue& aValue) const;
   virtual void     Destroy(nsSMILValue&) const;
   virtual nsresult Assign(nsSMILValue& aDest, const nsSMILValue& aSrc) const;
+  virtual PRBool   IsEqual(const nsSMILValue& aLeft,
+                           const nsSMILValue& aRight) const;
   virtual nsresult Add(nsSMILValue& aDest, const nsSMILValue& aValueToAdd,
                        PRUint32 aCount) const;
   virtual nsresult ComputeDistance(const nsSMILValue& aFrom,
                                    const nsSMILValue& aTo,
                                    double& aDistance) const;
   virtual nsresult Interpolate(const nsSMILValue& aStartVal,
                                const nsSMILValue& aEndVal,
                                double aUnitDistance,
--- a/content/svg/content/src/SVGViewBoxSMILType.cpp
+++ b/content/svg/content/src/SVGViewBoxSMILType.cpp
@@ -73,16 +73,30 @@ SVGViewBoxSMILType::Assign(nsSMILValue& 
   NS_PRECONDITION(aDest.mType == this, "Unexpected SMIL value");
 
   const nsSVGViewBoxRect* src = static_cast<const nsSVGViewBoxRect*>(aSrc.mU.mPtr);
   nsSVGViewBoxRect* dst = static_cast<nsSVGViewBoxRect*>(aDest.mU.mPtr);
   *dst = *src;
   return NS_OK;
 }
 
+PRBool
+SVGViewBoxSMILType::IsEqual(const nsSMILValue& aLeft,
+                            const nsSMILValue& aRight) const
+{
+  NS_PRECONDITION(aLeft.mType == aRight.mType, "Incompatible SMIL types");
+  NS_PRECONDITION(aLeft.mType == this, "Unexpected type for SMIL value");
+
+  const nsSVGViewBoxRect* leftBox =
+    static_cast<const nsSVGViewBoxRect*>(aLeft.mU.mPtr);
+  const nsSVGViewBoxRect* rightBox =
+    static_cast<nsSVGViewBoxRect*>(aRight.mU.mPtr);
+  return *leftBox == *rightBox;
+}
+
 nsresult
 SVGViewBoxSMILType::Add(nsSMILValue& aDest, const nsSMILValue& aValueToAdd,
                         PRUint32 aCount) const
 {
   NS_PRECONDITION(aValueToAdd.mType == aDest.mType,
                   "Trying to add invalid types");
   NS_PRECONDITION(aValueToAdd.mType == this, "Unexpected source type");
 
--- a/content/svg/content/src/SVGViewBoxSMILType.h
+++ b/content/svg/content/src/SVGViewBoxSMILType.h
@@ -48,16 +48,18 @@ public:
   static SVGViewBoxSMILType sSingleton;
 
 protected:
   // nsISMILType Methods
   // -------------------
   virtual nsresult Init(nsSMILValue& aValue) const;
   virtual void     Destroy(nsSMILValue&) const;
   virtual nsresult Assign(nsSMILValue& aDest, const nsSMILValue& aSrc) const;
+  virtual PRBool   IsEqual(const nsSMILValue& aLeft,
+                           const nsSMILValue& aRight) const;
   virtual nsresult Add(nsSMILValue& aDest, const nsSMILValue& aValueToAdd,
                        PRUint32 aCount) const;
   virtual nsresult ComputeDistance(const nsSMILValue& aFrom,
                                    const nsSMILValue& aTo,
                                    double& aDistance) const;
   virtual nsresult Interpolate(const nsSMILValue& aStartVal,
                                const nsSMILValue& aEndVal,
                                double aUnitDistance,
--- a/content/svg/content/src/nsSVGSMILTransform.h
+++ b/content/svg/content/src/nsSVGSMILTransform.h
@@ -70,41 +70,69 @@ public:
     TRANSFORM_TRANSLATE,
     TRANSFORM_SCALE,
     TRANSFORM_ROTATE,
     TRANSFORM_SKEWX,
     TRANSFORM_SKEWY,
     TRANSFORM_MATRIX
   };
 
+  // Number of float-params required in constructor, if constructing one of the
+  // 'simple' transform types (all but TRANSFORM_MATRIX)
+  static const PRUint32 NUM_SIMPLE_PARAMS = 3;
+
+  // Number of float-params required in constructor for TRANSFORM_MATRIX type.
+  // This is also the number of params we actually store, regardless of type.
+  static const PRUint32 NUM_STORED_PARAMS = 6;
+
   explicit nsSVGSMILTransform(TransformType aType)
   : mTransformType(aType)
   {
-    for (int i = 0; i < 6; ++i) {
+    for (PRUint32 i = 0; i < NUM_STORED_PARAMS; ++i) {
+      mParams[i] = 0;
+    }
+  }
+
+  nsSVGSMILTransform(TransformType aType, float (&aParams)[NUM_SIMPLE_PARAMS])
+  : mTransformType(aType)
+  {
+    for (PRUint32 i = 0; i < NUM_SIMPLE_PARAMS; ++i) {
+      mParams[i] = aParams[i];
+    }
+    for (PRUint32 i = NUM_SIMPLE_PARAMS; i < NUM_STORED_PARAMS; ++i) {
       mParams[i] = 0;
     }
   }
 
-  nsSVGSMILTransform(TransformType aType, float (&aParams)[3])
-  : mTransformType(aType)
-  {
-    for (int i = 0; i < 3; ++i) {
-      mParams[i] = aParams[i];
-    }
-    for (int i = 3; i < 6; ++i) {
-      mParams[i] = 0;
-    }
-  }
-
-  explicit nsSVGSMILTransform(float (&aParams)[6])
+  explicit nsSVGSMILTransform(float (&aParams)[NUM_STORED_PARAMS])
   : mTransformType(TRANSFORM_MATRIX)
   {
-    for (int i = 0; i < 6; ++i) {
+    for (PRUint32 i = 0; i < NUM_STORED_PARAMS; ++i) {
       mParams[i] = aParams[i];
     }
   }
 
+  PRBool operator==(const nsSVGSMILTransform& aOther) const
+  {
+    if (mTransformType != aOther.mTransformType)
+      return PR_FALSE;
+
+    for (PRUint32 i = 0; i < NUM_STORED_PARAMS; ++i) {
+      if (mParams[i] != aOther.mParams[i]) {
+        return PR_FALSE;
+      }
+    }
+
+    // Found no differences.
+    return PR_TRUE;
+  }
+
+  PRBool operator!=(const nsSVGSMILTransform& aOther) const
+  {
+    return !(*this == aOther);
+  }
+
   TransformType mTransformType;
 
-  float mParams[6];
+  float mParams[NUM_STORED_PARAMS];
 };
 
 #endif // NS_SVGSMILTRANSFORM_H_
--- a/content/svg/content/src/nsSVGTransformSMILAttr.cpp
+++ b/content/svg/content/src/nsSVGTransformSMILAttr.cpp
@@ -44,16 +44,17 @@
 #include "nsIDOMSVGMatrix.h"
 #include "nsSVGMatrix.h"
 #include "nsSMILValue.h"
 #include "nsSMILNullType.h"
 #include "nsISMILAnimationElement.h"
 #include "nsSVGElement.h"
 #include "nsISVGValue.h"
 #include "prdtoa.h"
+#include "prlog.h"
 
 nsresult
 nsSVGTransformSMILAttr::ValueFromString(const nsAString& aStr,
                                      const nsISMILAnimationElement* aSrcElement,
                                      nsSMILValue& aValue) const
 {
   NS_ENSURE_TRUE(aSrcElement, NS_ERROR_FAILURE);
   NS_ASSERTION(aValue.IsNull(),
@@ -134,16 +135,19 @@ nsSVGTransformSMILAttr::SetAnimValue(con
 
 void
 nsSVGTransformSMILAttr::ParseValue(const nsAString& aSpec,
                                    const nsIAtom* aTransformType,
                                    nsSMILValue& aResult)
 {
   NS_ASSERTION(aResult.IsNull(), "Unexpected type for SMIL value");
 
+  // nsSVGSMILTransform constructor should be expecting array with 3 params
+  PR_STATIC_ASSERT(nsSVGSMILTransform::NUM_SIMPLE_PARAMS == 3);
+
   float params[3] = { 0.f };
   PRInt32 numParsed = ParseParameterList(aSpec, params, 3);
   nsSVGSMILTransform::TransformType transformType;
 
   if (aTransformType == nsGkAtoms::translate) {
     // tx [ty=0]
     if (numParsed != 1 && numParsed != 2)
       return;
@@ -248,16 +252,18 @@ nsSVGTransformSMILAttr::AppendSVGTransfo
   PRUint16 svgTransformType = nsIDOMSVGTransform::SVG_TRANSFORM_MATRIX;
   aTransform->GetType(&svgTransformType);
 
   nsCOMPtr<nsIDOMSVGMatrix> matrix;
   nsresult rv = aTransform->GetMatrix(getter_AddRefs(matrix));
   if (NS_FAILED(rv) || !matrix)
     return NS_ERROR_FAILURE;
 
+  // nsSVGSMILTransform constructor should be expecting array with 3 params
+  PR_STATIC_ASSERT(nsSVGSMILTransform::NUM_SIMPLE_PARAMS == 3);
   float params[3] = { 0.f };
   nsSVGSMILTransform::TransformType transformType;
 
   switch (svgTransformType)
   {
     case nsIDOMSVGTransform::SVG_TRANSFORM_TRANSLATE:
       {
         matrix->GetE(&params[0]);
@@ -299,16 +305,19 @@ nsSVGTransformSMILAttr::AppendSVGTransfo
       {
         aTransform->GetAngle(&params[0]);
         transformType = nsSVGSMILTransform::TRANSFORM_SKEWY;
       }
       break;
 
     case nsIDOMSVGTransform::SVG_TRANSFORM_MATRIX:
       {
+        // nsSVGSMILTransform constructor for TRANSFORM_MATRIX type should be
+        // expecting array with 6 params
+        PR_STATIC_ASSERT(nsSVGSMILTransform::NUM_STORED_PARAMS == 6);
         float mx[6];
         matrix->GetA(&mx[0]);
         matrix->GetB(&mx[1]);
         matrix->GetC(&mx[2]);
         matrix->GetD(&mx[3]);
         matrix->GetE(&mx[4]);
         matrix->GetF(&mx[5]);
         return nsSVGTransformSMILType::AppendTransform(nsSVGSMILTransform(mx),
--- a/content/svg/content/src/nsSVGTransformSMILType.cpp
+++ b/content/svg/content/src/nsSVGTransformSMILType.cpp
@@ -85,16 +85,45 @@ nsSVGTransformSMILType::Assign(nsSMILVal
   PRBool result = dstTransforms->SetCapacity(srcTransforms->Length());
   NS_ENSURE_TRUE(result,NS_ERROR_OUT_OF_MEMORY);
 
   *dstTransforms = *srcTransforms;
 
   return NS_OK;
 }
 
+PRBool
+nsSVGTransformSMILType::IsEqual(const nsSMILValue& aLeft,
+                                const nsSMILValue& aRight) const
+{
+  NS_PRECONDITION(aLeft.mType == aRight.mType, "Incompatible SMIL types");
+  NS_PRECONDITION(aLeft.mType == this, "Unexpected SMIL type");
+
+  const TransformArray& leftArr
+    (*static_cast<const TransformArray*>(aLeft.mU.mPtr));
+  const TransformArray& rightArr
+    (*static_cast<const TransformArray*>(aRight.mU.mPtr));
+
+  // If array-lengths don't match, we're trivially non-equal.
+  if (leftArr.Length() != rightArr.Length()) {
+    return PR_FALSE;
+  }
+
+  // Array-lengths match -- check each array-entry for equality.
+  PRUint32 length = leftArr.Length(); // == rightArr->Length(), if we get here
+  for (PRUint32 i = 0; i < length; ++i) {
+    if (leftArr[i] != rightArr[i]) {
+      return PR_FALSE;
+    }
+  }
+  
+  // Found no differences.
+  return PR_TRUE;
+}
+
 nsresult
 nsSVGTransformSMILType::Add(nsSMILValue& aDest, const nsSMILValue& aValueToAdd,
                             PRUint32 aCount) const
 {
   NS_PRECONDITION(aDest.mType == this, "Unexpected SMIL type");
   NS_PRECONDITION(aDest.mType == aValueToAdd.mType, "Incompatible SMIL types");
 
   TransformArray& dstTransforms(*static_cast<TransformArray*>(aDest.mU.mPtr));
--- a/content/svg/content/src/nsSVGTransformSMILType.h
+++ b/content/svg/content/src/nsSVGTransformSMILType.h
@@ -110,16 +110,18 @@ public:
   static nsSVGTransformSMILType sSingleton;
 
 protected:
   // nsISMILType Methods
   // -------------------
   virtual nsresult Init(nsSMILValue& aValue) const;
   virtual void     Destroy(nsSMILValue& aValue) const;
   virtual nsresult Assign(nsSMILValue& aDest, const nsSMILValue& aSrc) const;
+  virtual PRBool   IsEqual(const nsSMILValue& aLeft,
+                           const nsSMILValue& aRight) const;
   virtual nsresult Add(nsSMILValue& aDest,
                        const nsSMILValue& aValueToAdd,
                        PRUint32 aCount) const;
   virtual nsresult SandwichAdd(nsSMILValue& aDest,
                                const nsSMILValue& aValueToAdd) const;
   virtual nsresult ComputeDistance(const nsSMILValue& aFrom,
                                    const nsSMILValue& aTo,
                                    double& aDistance) const;
--- a/content/svg/content/src/nsSVGViewBox.cpp
+++ b/content/svg/content/src/nsSVGViewBox.cpp
@@ -41,16 +41,32 @@
 #include "nsTextFormatter.h"
 #ifdef MOZ_SMIL
 #include "nsSMILValue.h"
 #include "SVGViewBoxSMILType.h"
 #endif // MOZ_SMIL
 
 using namespace mozilla;
 
+/* Implementation of nsSVGViewBoxRect methods */
+
+PRBool
+nsSVGViewBoxRect::operator==(const nsSVGViewBoxRect& aOther) const
+{
+  if (&aOther == this)
+    return PR_TRUE;
+
+  return x == aOther.x &&
+    y == aOther.y &&
+    width == aOther.width &&
+    height == aOther.height;
+}
+
+/* Cycle collection macros for nsSVGViewBox */
+
 NS_SVG_VAL_IMPL_CYCLE_COLLECTION(nsSVGViewBox::DOMBaseVal, mSVGElement)
 NS_SVG_VAL_IMPL_CYCLE_COLLECTION(nsSVGViewBox::DOMAnimVal, mSVGElement)
 NS_SVG_VAL_IMPL_CYCLE_COLLECTION(nsSVGViewBox::DOMAnimatedRect, mSVGElement)
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsSVGViewBox::DOMBaseVal)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsSVGViewBox::DOMBaseVal)
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsSVGViewBox::DOMAnimVal)
@@ -72,17 +88,17 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(
 NS_INTERFACE_MAP_END
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsSVGViewBox::DOMAnimatedRect)
   NS_INTERFACE_MAP_ENTRY(nsIDOMSVGAnimatedRect)
   NS_INTERFACE_MAP_ENTRY(nsISupports)
   NS_INTERFACE_MAP_ENTRY_CONTENT_CLASSINFO(SVGAnimatedRect)
 NS_INTERFACE_MAP_END
 
-/* Implementation */
+/* Implementation of nsSVGViewBox methods */
 
 void
 nsSVGViewBox::Init()
 {
   mBaseVal = nsSVGViewBoxRect();
   mAnimVal = nsnull;
   mHasBaseVal = PR_FALSE;
 }
--- a/content/svg/content/src/nsSVGViewBox.h
+++ b/content/svg/content/src/nsSVGViewBox.h
@@ -49,16 +49,17 @@ struct nsSVGViewBoxRect
   float x, y;
   float width, height;
 
   nsSVGViewBoxRect() : x(0), y(0), width(0), height(0) {}
   nsSVGViewBoxRect(float aX, float aY, float aWidth, float aHeight) :
     x(aX), y(aY), width(aWidth), height(aHeight) {}
   nsSVGViewBoxRect(const nsSVGViewBoxRect& rhs) :
     x(rhs.x), y(rhs.y), width(rhs.width), height(rhs.height) {}
+  PRBool operator==(const nsSVGViewBoxRect& aOther) const;
 };
 
 class nsSVGViewBox
 {
 
 public:
 
   void Init();