Bug 681645 - SMIL: accommodate floating-point errors in discrete animations; r=dholbert
authorBrian Birtles <birtles@gmail.com>
Fri, 02 Sep 2011 08:13:45 +0900
changeset 76426 bff12708b423cef63dff3bfe0f3d479e2e8206c7
parent 76425 1a78f5c53b5847d41fc680b511d8fd1b964008f3
child 76427 7a01e603335dc905ddda0e6690d09a1e45e1f7bb
push id3
push userfelipc@gmail.com
push dateFri, 30 Sep 2011 20:09:13 +0000
reviewersdholbert
bugs681645
milestone9.0a1
Bug 681645 - SMIL: accommodate floating-point errors in discrete animations; r=dholbert
content/smil/nsSMILAnimationFunction.cpp
layout/reftests/svg/smil/anim-discrete-values-2.svg
layout/reftests/svg/smil/anim-discrete-values-3.svg
layout/reftests/svg/smil/reftest.list
--- a/content/smil/nsSMILAnimationFunction.cpp
+++ b/content/smil/nsSMILAnimationFunction.cpp
@@ -473,16 +473,31 @@ nsSMILAnimationFunction::InterpolateResu
   }
 
   // Discrete-CalcMode case
   // Note: If interpolation failed (isn't supported for this type), the SVG
   // spec says to force discrete mode.
   if (calcMode == CALC_DISCRETE || NS_FAILED(rv)) {
     double scaledSimpleProgress =
       ScaleSimpleProgress(simpleProgress, CALC_DISCRETE);
+
+    // Floating-point errors can mean that, for example, a sample time of 29s in
+    // a 100s duration animation gives us a simple progress of 0.28999999999
+    // instead of the 0.29 we'd expect. Normally this isn't a noticeable
+    // problem, but when we have sudden jumps in animation values (such as is
+    // the case here with discrete animation) we can get unexpected results.
+    //
+    // To counteract this, before we perform a floor() on the animation
+    // progress, we add a tiny fudge factor to push us into the correct interval
+    // in cases where floating-point errors might cause us to fall short.
+    static const double kFloatingPointFudgeFactor = 1.0e-16;
+    if (scaledSimpleProgress + kFloatingPointFudgeFactor <= 1.0) {
+      scaledSimpleProgress += kFloatingPointFudgeFactor;
+    }
+
     if (IsToAnimation()) {
       // We don't follow SMIL 3, 12.6.4, where discrete to animations
       // are the same as <set> animations.  Instead, we treat it as a
       // discrete animation with two values (the underlying value and
       // the to="" value), and honor keyTimes="" as well.
       PRUint32 index = (PRUint32)floor(scaledSimpleProgress * 2);
       aResult = index == 0 ? aBaseValue : aValues[0];
     } else {
new file mode 100644
--- /dev/null
+++ b/layout/reftests/svg/smil/anim-discrete-values-2.svg
@@ -0,0 +1,31 @@
+<svg xmlns="http://www.w3.org/2000/svg"
+     xmlns:xlink="http://www.w3.org/1999/xlink"
+     class="reftest-wait"
+     onload="setTimeAndSnapshot(29, true)">
+  <script xlink:href="smil-util.js" type="text/javascript"/>
+  <title>Test discrete keyTimes are scaled correctly (Bug 681645)</title>
+  <rect x="15" y="15" width="200" height="200" fill="blue">
+    <animate attributeName="fill" begin="0" dur="100s"
+             calcMode="discrete"
+             values="red;red;red;red;red;red;red;red;red;red;
+                     red;red;red;red;red;red;red;red;red;red;
+                     red;red;red;red;red;red;red;red;red;blue;
+                     red;red;red;red;red;red;red;red;red;red;
+                     red;red;red;red;red;red;red;red;red;red;
+                     red;red;red;red;red;red;red;red;red;red;
+                     red;red;red;red;red;red;red;red;red;red;
+                     red;red;red;red;red;red;red;red;red;red;
+                     red;red;red;red;red;red;red;red;red;red;
+                     red;red;red;red;red;red;red;red;red;red"
+           keyTimes="0.00;0.01;0.02;0.03;0.04;0.05;0.06;0.07;0.08;0.09;
+                     0.10;0.11;0.12;0.13;0.14;0.15;0.16;0.17;0.18;0.19;
+                     0.20;0.21;0.22;0.23;0.24;0.25;0.26;0.27;0.28;0.29;
+                     0.30;0.31;0.32;0.33;0.34;0.35;0.36;0.37;0.38;0.39;
+                     0.40;0.41;0.42;0.43;0.44;0.45;0.46;0.47;0.48;0.49;
+                     0.50;0.51;0.52;0.53;0.54;0.55;0.56;0.57;0.58;0.59;
+                     0.60;0.61;0.62;0.63;0.64;0.65;0.66;0.67;0.68;0.69;
+                     0.70;0.71;0.72;0.73;0.74;0.75;0.76;0.77;0.78;0.79;
+                     0.80;0.81;0.82;0.83;0.84;0.85;0.86;0.87;0.88;0.89;
+                     0.90;0.91;0.92;0.93;0.94;0.95;0.96;0.97;0.98;0.99"/>
+  </rect>
+</svg>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/svg/smil/anim-discrete-values-3.svg
@@ -0,0 +1,21 @@
+<svg xmlns="http://www.w3.org/2000/svg"
+     xmlns:xlink="http://www.w3.org/1999/xlink"
+     class="reftest-wait"
+     onload="setTimeAndSnapshot(29, true)">
+  <script xlink:href="smil-util.js" type="text/javascript"/>
+  <title>Test discrete keyTimes are scaled correctly (Bug 681645)</title>
+  <rect x="15" y="15" width="200" height="200" fill="blue">
+    <animate attributeName="fill" begin="0" dur="100s"
+             calcMode="discrete"
+             values="red;red;red;red;red;red;red;red;red;red;
+                     red;red;red;red;red;red;red;red;red;red;
+                     red;red;red;red;red;red;red;red;red;blue;
+                     red;red;red;red;red;red;red;red;red;red;
+                     red;red;red;red;red;red;red;red;red;red;
+                     red;red;red;red;red;red;red;red;red;red;
+                     red;red;red;red;red;red;red;red;red;red;
+                     red;red;red;red;red;red;red;red;red;red;
+                     red;red;red;red;red;red;red;red;red;red;
+                     red;red;red;red;red;red;red;red;red;red"/>
+  </rect>
+</svg>
--- a/layout/reftests/svg/smil/reftest.list
+++ b/layout/reftests/svg/smil/reftest.list
@@ -50,16 +50,18 @@ include syncbase/reftest.list
 # seek tests
 include seek/reftest.list
 
 # event tests
 include event/reftest.list
 
 # General tests
 == anim-discrete-values-1.svg      anim-standard-ref.svg
+== anim-discrete-values-2.svg      anim-standard-ref.svg
+== anim-discrete-values-3.svg      anim-standard-ref.svg
 == anim-discrete-replace-sum-1.svg anim-standard-ref.svg
 == anim-discrete-sum-none-1.svg    anim-standard-ref.svg
 == anim-discrete-sum-sum-1.svg     anim-standard-ref.svg
 
 == anim-discrete-to-1.svg          anim-standard-ref.svg
 == anim-discrete-to-2.svg          anim-standard-ref.svg
 == anim-discrete-to-3.svg          anim-standard-ref.svg
 == anim-discrete-to-4.svg          anim-standard-ref.svg