Bug 617817: Don't automatically recompose <set> & indefinite-duration animations, since we know they always have the same effect. r=birtles a=roc
authorDaniel Holbert <dholbert@cs.stanford.edu>
Fri, 10 Dec 2010 10:33:13 -0800
changeset 59084 89e633e31dad283de4e541b988eafae4a815ba20
parent 59083 5677a819829a93139c49da9fa43a0b6a23b10a4e
child 59085 fcd702dc1ec7f7f5d7788b25995f5197ec4eb6ce
push id1
push usershaver@mozilla.com
push dateTue, 04 Jan 2011 17:58:04 +0000
reviewersbirtles, roc
bugs617817
milestone2.0b8pre
Bug 617817: Don't automatically recompose <set> & indefinite-duration animations, since we know they always have the same effect. r=birtles a=roc
content/smil/nsSMILAnimationFunction.cpp
content/smil/nsSMILAnimationFunction.h
content/smil/nsSMILSetAnimationFunction.h
--- a/content/smil/nsSMILAnimationFunction.cpp
+++ b/content/smil/nsSMILAnimationFunction.cpp
@@ -79,26 +79,27 @@ nsAttrValue::EnumTable nsSMILAnimationFu
 // Any negative number should be fine as a sentinel here,
 // because valid distances are non-negative.
 #define COMPUTE_DISTANCE_ERROR (-1)
 
 //----------------------------------------------------------------------
 // Constructors etc.
 
 nsSMILAnimationFunction::nsSMILAnimationFunction()
-  : mIsActive(PR_FALSE),
+  : mSampleTime(-1),
+    mRepeatIteration(0),
+    mBeginTime(LL_MININT),
+    mAnimationElement(nsnull),
+    mErrorFlags(0),
+    mIsActive(PR_FALSE),
     mIsFrozen(PR_FALSE),
-    mSampleTime(-1),
-    mRepeatIteration(0),
     mLastValue(PR_FALSE),
     mHasChanged(PR_TRUE),
     mValueNeedsReparsingEverySample(PR_FALSE),
-    mBeginTime(LL_MININT),
-    mAnimationElement(nsnull),
-    mErrorFlags(0)
+    mPrevSampleWasSingleValueAnimation(PR_FALSE)
 {
 }
 
 void
 nsSMILAnimationFunction::SetAnimationElement(
     nsISMILAnimationElement* aAnimationElement)
 {
   mAnimationElement = aAnimationElement;
@@ -171,21 +172,27 @@ nsSMILAnimationFunction::UnsetAttr(nsIAt
   return foundMatch;
 }
 
 void
 nsSMILAnimationFunction::SampleAt(nsSMILTime aSampleTime,
                                   const nsSMILTimeValue& aSimpleDuration,
                                   PRUint32 aRepeatIteration)
 {
-  if (mHasChanged || mLastValue || mSampleTime != aSampleTime ||
-      mSimpleDuration != aSimpleDuration ||
-      mRepeatIteration != aRepeatIteration) {
-    mHasChanged = PR_TRUE;
-  }
+  // * Update mHasChanged ("Might this sample be different from prev one?")
+  // Were we previously sampling a fill="freeze" final val? (We're not anymore.)
+  mHasChanged |= mLastValue;
+
+  // Are we sampling at a new point in simple duration? And does that matter?
+  mHasChanged |=
+    (mSampleTime != aSampleTime || mSimpleDuration != aSimpleDuration) &&
+    !IsValueFixedForSimpleDuration();
+
+  // Are we on a new repeat and accumulating across repeats?
+  mHasChanged |= (mRepeatIteration != aRepeatIteration) && GetAccumulate();
 
   mSampleTime       = aSampleTime;
   mSimpleDuration   = aSimpleDuration;
   mRepeatIteration  = aRepeatIteration;
   mLastValue        = PR_FALSE;
 }
 
 void
@@ -218,16 +225,17 @@ nsSMILAnimationFunction::Inactivate(PRBo
   mHasChanged = PR_TRUE;
 }
 
 void
 nsSMILAnimationFunction::ComposeResult(const nsISMILAttr& aSMILAttr,
                                        nsSMILValue& aResult)
 {
   mHasChanged = PR_FALSE;
+  mPrevSampleWasSingleValueAnimation = PR_FALSE;
 
   // Skip animations that are inactive or in error
   if (!IsActiveOrFrozen() || mErrorFlags != 0)
     return;
 
   // Get the animation values
   nsSMILValueArray values;
   nsresult rv = GetValues(aSMILAttr, values);
@@ -255,16 +263,17 @@ nsSMILAnimationFunction::ComposeResult(c
     return;
 
   nsSMILValue result;
 
   if (values.Length() == 1 && !IsToAnimation()) {
 
     // Single-valued animation
     result = values[0];
+    mPrevSampleWasSingleValueAnimation = PR_TRUE;
 
   } else if (mLastValue) {
 
     // Sampling last value
     const nsSMILValue& last = values[values.Length() - 1];
     result = last;
 
     // See comment in AccumulateResult: to-animation does not accumulate
@@ -915,16 +924,23 @@ nsSMILAnimationFunction::CheckKeySplines
       (IsToAnimation() && splineSpecs != 1)) {
     SetKeySplinesErrorFlag(PR_TRUE);
     return;
   }
 
   SetKeySplinesErrorFlag(PR_FALSE);
 }
 
+PRBool
+nsSMILAnimationFunction::IsValueFixedForSimpleDuration() const
+{
+  return mSimpleDuration.IsIndefinite() ||
+    (!mHasChanged && mPrevSampleWasSingleValueAnimation);
+}
+
 //----------------------------------------------------------------------
 // Property getters
 
 PRBool
 nsSMILAnimationFunction::GetAccumulate() const
 {
   const nsAttrValue* value = GetAttr(nsGkAtoms::accumulate);
   if (!value)
--- a/content/smil/nsSMILAnimationFunction.h
+++ b/content/smil/nsSMILAnimationFunction.h
@@ -339,16 +339,20 @@ protected:
   void         CheckKeySplines(PRUint32 aNumValues);
 
   virtual PRBool IsToAnimation() const {
     return !HasAttr(nsGkAtoms::values) &&
             HasAttr(nsGkAtoms::to) &&
            !HasAttr(nsGkAtoms::from);
   }
 
+  // Returns PR_TRUE if we know our composited value won't change over the
+  // simple duration of this animation (for a fixed base value).
+  virtual PRBool IsValueFixedForSimpleDuration() const;
+
   inline PRBool IsAdditive() const {
     /*
      * Animation is additive if:
      *
      * (1) additive = "sum" (GetAdditive() == true), or
      * (2) it is 'by animation' (by is set, from and values are not)
      *
      * Although animation is not additive if it is 'to animation'
@@ -404,30 +408,24 @@ protected:
 
   static nsAttrValue::EnumTable sAdditiveTable[];
   static nsAttrValue::EnumTable sCalcModeTable[];
   static nsAttrValue::EnumTable sAccumulateTable[];
 
   nsTArray<double>              mKeyTimes;
   nsTArray<nsSMILKeySpline>     mKeySplines;
 
-  PRPackedBool                  mIsActive;
-  PRPackedBool                  mIsFrozen;
-
   // These are the parameters provided by the previous sample. Currently we
   // perform lazy calculation. That is, we only calculate the result if and when
   // instructed by the compositor. This allows us to apply the result directly
   // to the animation value and allows the compositor to filter out functions
   // that it determines will not contribute to the final result.
   nsSMILTime                    mSampleTime; // sample time within simple dur
   nsSMILTimeValue               mSimpleDuration;
   PRUint32                      mRepeatIteration;
-  PRPackedBool                  mLastValue;
-  PRPackedBool                  mHasChanged;
-  PRPackedBool                  mValueNeedsReparsingEverySample;
 
   nsSMILTime                    mBeginTime; // document time
 
   // The owning animation element. This is used for sorting based on document
   // position and for fetching attribute values stored in the element.
   // Raw pointer is OK here, because this nsSMILAnimationFunction can't outlive
   // its owning animation element.
   nsISMILAnimationElement*      mAnimationElement;
@@ -461,11 +459,19 @@ protected:
   // @see
   // http://www.w3.org/TR/2001/REC-smil-animation-20010904/#FromToByAndAdditive
   nsSMILValue                   mFrozenValue;
 
   // Allows us to check whether an animation function has changed target from
   // sample to sample (because if neither target nor animated value have
   // changed, we don't have to do anything).
   nsSMILWeakTargetIdentifier    mLastTarget;
+
+  // Boolean flags
+  PRPackedBool                  mIsActive:1;
+  PRPackedBool                  mIsFrozen:1;
+  PRPackedBool                  mLastValue:1;
+  PRPackedBool                  mHasChanged:1;
+  PRPackedBool                  mValueNeedsReparsingEverySample:1;
+  PRPackedBool                  mPrevSampleWasSingleValueAnimation:1;
 };
 
 #endif // NS_SMILANIMATIONFUNCTION_H_
--- a/content/smil/nsSMILSetAnimationFunction.h
+++ b/content/smil/nsSMILSetAnimationFunction.h
@@ -76,16 +76,21 @@ public:
 protected:
   // Although <set> animation might look like to-animation, unlike to-animation,
   // it never interpolates values.
   // Returning PR_FALSE here will mean this animation function gets treated as
   // a single-valued function and no interpolation will be attempted.
   NS_OVERRIDE virtual PRBool IsToAnimation() const {
     return PR_FALSE;
   }
+
+  // <set> applies the exact same value across the simple duration.
+  NS_OVERRIDE virtual PRBool IsValueFixedForSimpleDuration() const {
+    return PR_TRUE;
+  }
   NS_OVERRIDE virtual PRBool             HasAttr(nsIAtom* aAttName) const;
   NS_OVERRIDE virtual const nsAttrValue* GetAttr(nsIAtom* aAttName) const;
   NS_OVERRIDE virtual PRBool             GetAttr(nsIAtom* aAttName,
                                                  nsAString& aResult) const;
   NS_OVERRIDE virtual PRBool WillReplace() const;
 
   PRBool IsDisallowedAttribute(const nsIAtom* aAttribute) const;
 };