Bug 1358966 - Make an argument of ComputePacedTotalDistances an array of double. r?birtles draft
authorHiroyuki Ikezoe <hikezoe@mozilla.com>
Tue, 06 Jun 2017 12:54:56 +0900
changeset 589367 108e89413f9aa8395a6c97f1cb9989559cba3b81
parent 589366 5020ba9ddd23584f0c9a3ff19a9a69271878847c
child 589368 7b0bb8148f9a3f55b6e181eab1f384bc374b4063
push id62344
push userhikezoe@mozilla.com
push dateTue, 06 Jun 2017 03:58:54 +0000
reviewersbirtles
bugs1358966
milestone55.0a1
Bug 1358966 - Make an argument of ComputePacedTotalDistances an array of double. r?birtles MozReview-Commit-ID: F6nwbcFQQuj
dom/smil/nsSMILAnimationFunction.cpp
dom/smil/nsSMILAnimationFunction.h
--- a/dom/smil/nsSMILAnimationFunction.cpp
+++ b/dom/smil/nsSMILAnimationFunction.cpp
@@ -486,16 +486,25 @@ nsSMILAnimationFunction::AccumulateResul
     // If the target attribute type doesn't support addition, Add will
     // fail and we leave aResult untouched.
     aResult.Add(lastValue, mRepeatIteration);
   }
 
   return NS_OK;
 }
 
+static void
+ClampDistances(AutoTArray<double, 1>& aDistances)
+{
+  for (size_t i = 0; i < aDistances.Length(); i++) {
+    MOZ_ASSERT(aDistances[i] >= 0.0f, "distance values must be non-negative");
+    aDistances[i] = std::max(aDistances[i], 0.0);
+  }
+}
+
 /*
  * Given the simple progress for a paced animation, this method:
  *  - determines which two elements of the values array we're in between
  *    (returned as aFrom and aTo)
  *  - determines where we are between them
  *    (returned as aIntervalProgress)
  *
  * Returns NS_OK, or NS_ERROR_FAILURE if our values don't support distance
@@ -519,114 +528,133 @@ nsSMILAnimationFunction::ComputePacedPos
   // same as our overall progress.
   if (aValues.Length() == 2) {
     aIntervalProgress = aSimpleProgress;
     aFrom = &aValues[0];
     aTo = &aValues[1];
     return NS_OK;
   }
 
-  double totalDistance = ComputePacedTotalDistance(aValues);
-  if (totalDistance == COMPUTE_DISTANCE_ERROR)
-    return NS_ERROR_FAILURE;
-
-  // If we have 0 total distance, then it's unclear where our "paced" position
-  // should be.  We can just fail, which drops us into discrete animation mode.
-  // (That's fine, since our values are apparently indistinguishable anyway.)
-  if (totalDistance == 0.0) {
+  AutoTArray<double, 1> totalDistances;
+  if (!ComputePacedTotalDistances(aValues, totalDistances)) {
     return NS_ERROR_FAILURE;
   }
 
   // total distance we should have moved at this point in time.
   // (called 'remainingDist' due to how it's used in loop below)
-  double remainingDist = aSimpleProgress * totalDistance;
-
-  // Must be satisfied, because totalDistance is a sum of (non-negative)
-  // distances, and aSimpleProgress is non-negative
-  NS_ASSERTION(remainingDist >= 0, "distance values must be non-negative");
+  AutoTArray<double, 1> remainingDists;
+  size_t len = totalDistances.Length();
+  remainingDists.SetLength(len);
+  for (size_t i = 0; i < len; i++) {
+    // If we have 0 total distance, then it's unclear where our "paced" position
+    // should be.  We can just fail, which drops us into discrete animation mode.
+    // (That's fine, since our values are apparently indistinguishable anyway.)
+    if (totalDistances[i] == 0.0f) {
+      return NS_ERROR_FAILURE;
+    }
+    remainingDists[i] = aSimpleProgress * totalDistances[i];
+    // Must be satisfied, because totalDistance is a sum of (non-negative)
+    // distances, and aSimpleProgress is non-negative
+    NS_ASSERTION(remainingDists[i] >= 0, "distance values must be non-negative");
+  }
 
   // Find where remainingDist puts us in the list of values
   // Note: We could optimize this next loop by caching the
   // interval-distances in an array, but maybe that's excessive.
   for (uint32_t i = 0; i < aValues.Length() - 1; i++) {
     // Note: The following assertion is valid because remainingDist should
     // start out non-negative, and this loop never shaves off more than its
     // current value.
-    NS_ASSERTION(remainingDist >= 0, "distance values must be non-negative");
+    for (size_t j = 0; j < len; j++) {
+      NS_ASSERTION(remainingDists[j] >= 0, "distance values must be non-negative");
+    }
 
     AutoTArray<double, 1> curIntervalDists;
 
 #ifdef DEBUG
     nsresult rv =
 #endif
       aValues[i].ComputeDistance(aValues[i+1], curIntervalDists);
     MOZ_ASSERT(NS_SUCCEEDED(rv),
-               "If we got through ComputePacedTotalDistance, we should "
+               "If we got through ComputePacedTotalDistances, we should "
                "be able to recompute each sub-distance without errors");
 
-    NS_ASSERTION(curIntervalDists[0] >= 0,
-                 "distance values must be non-negative");
-    // Clamp distance value at 0, just in case ComputeDistance is evil.
-    curIntervalDists[0] = std::max(curIntervalDists[0], 0.0);
+    ClampDistances(curIntervalDists);
 
-    if (remainingDist >= curIntervalDists[0]) {
-      remainingDist -= curIntervalDists[0];
+    if (remainingDists[0] >= curIntervalDists[0]) {
+      remainingDists[0] -= curIntervalDists[0];
     } else {
       // NOTE: If we get here, then curIntervalDist necessarily is not 0. Why?
       // Because this clause is only hit when remainingDist < curIntervalDist,
       // and if curIntervalDist were 0, that would mean remainingDist would
       // have to be < 0.  But that can't happen, because remainingDist (as
       // a distance) is non-negative by definition.
       NS_ASSERTION(curIntervalDists[0] != 0,
                    "We should never get here with this set to 0...");
 
       // We found the right spot -- an interpolated position between
       // values i and i+1.
       aFrom = &aValues[i];
       aTo = &aValues[i+1];
-      aIntervalProgress = remainingDist / curIntervalDists[0];
+      aIntervalProgress = remainingDists[0] / curIntervalDists[0];
       return NS_OK;
     }
   }
 
   NS_NOTREACHED("shouldn't complete loop & get here -- if we do, "
                 "then aSimpleProgress was probably out of bounds");
   return NS_ERROR_FAILURE;
 }
 
+static void
+AccumulateDistances(AutoTArray<double, 1>& aTotalDistances,
+                    AutoTArray<double, 1>& aDistances)
+{
+  MOZ_ASSERT(aDistances.Length() == aTotalDistances.Length());
+
+  for (size_t i = 0; i < aDistances.Length(); i++) {
+    aTotalDistances[i] += aDistances[i];
+  }
+}
+
 /*
  * Computes the total distance to be travelled by a paced animation.
  *
- * Returns the total distance, or returns COMPUTE_DISTANCE_ERROR if
- * our values don't support distance computation.
+ * Returns false if our values don't support distance computation.
  */
-double
-nsSMILAnimationFunction::ComputePacedTotalDistance(
-    const nsSMILValueArray& aValues) const
+bool
+nsSMILAnimationFunction::ComputePacedTotalDistances(
+    const nsSMILValueArray& aValues,
+    AutoTArray<double, 1>& aTotalDistances) const
 {
   NS_ASSERTION(GetCalcMode() == CALC_PACED,
                "Calling paced-specific function, but not in paced mode");
 
-  double totalDistance = 0.0;
   for (uint32_t i = 0; i < aValues.Length() - 1; i++) {
     AutoTArray<double, 1> tmpDists;
     nsresult rv = aValues[i].ComputeDistance(aValues[i+1], tmpDists);
     if (NS_FAILED(rv)) {
-      return COMPUTE_DISTANCE_ERROR;
+      return false;
     }
 
     // Clamp distance value to 0, just in case we have an evil ComputeDistance
     // implementation somewhere
-    MOZ_ASSERT(tmpDists[0] >= 0.0f, "distance values must be non-negative");
-    tmpDists[0] = std::max(tmpDists[0], 0.0);
+    ClampDistances(tmpDists);
 
-    totalDistance += tmpDists[0];
+    if (i == 0) {
+      size_t len = tmpDists.Length();
+      aTotalDistances.SetLength(len);
+      for (size_t j = 0; j < len; j++) {
+        aTotalDistances[i] = 0.0;
+      }
+    }
+    AccumulateDistances(aTotalDistances, tmpDists);
   }
 
-  return totalDistance;
+  return true;
 }
 
 double
 nsSMILAnimationFunction::ScaleSimpleProgress(double aProgress,
                                              nsSMILCalcMode aCalcMode)
 {
   if (!HasAttr(nsGkAtoms::keyTimes))
     return aProgress;
--- a/dom/smil/nsSMILAnimationFunction.h
+++ b/dom/smil/nsSMILAnimationFunction.h
@@ -308,17 +308,18 @@ protected:
   nsresult AccumulateResult(const nsSMILValueArray& aValues,
                             nsSMILValue& aResult);
 
   nsresult ComputePacedPosition(const nsSMILValueArray& aValues,
                                 double aSimpleProgress,
                                 double& aIntervalProgress,
                                 const nsSMILValue*& aFrom,
                                 const nsSMILValue*& aTo);
-  double   ComputePacedTotalDistance(const nsSMILValueArray& aValues) const;
+  bool ComputePacedTotalDistances(const nsSMILValueArray& aValues,
+                                  AutoTArray<double, 1>& aTotalDistances) const;
 
   /**
    * Adjust the simple progress, that is, the point within the simple duration,
    * by applying any keyTimes.
    */
   double   ScaleSimpleProgress(double aProgress, nsSMILCalcMode aCalcMode);
   /**
    * Adjust the progress within an interval, that is, between two animation