Fix numeric precision issue in SVG animations
authorpdr@google.com <pdr@google.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 3 May 2012 22:44:50 +0000 (22:44 +0000)
committerpdr@google.com <pdr@google.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 3 May 2012 22:44:50 +0000 (22:44 +0000)
https://bugs.webkit.org/show_bug.cgi?id=85502

Reviewed by Dirk Schulze.

Source/WebCore:

r93938 had a bug where floating point numbers where compared exactly,
exposing a bug when floating point precision was not sufficient. This
change compares against an epsilon value to get around these precision
issues.

Test: svg/animations/animate-end-attribute-numeric-precision.html

* svg/animation/SVGSMILElement.cpp:
(WebCore::SVGSMILElement::calculateAnimationPercentAndRepeat):

LayoutTests:

* svg/animations/animate-end-attribute-numeric-precision-expected.txt: Added.
* svg/animations/animate-end-attribute-numeric-precision.html: Added.
* svg/animations/script-tests/animate-end-attribute-numeric-precision.js: Added.
(sample1):
(sample2):
(executeTest):

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@116030 268f45cc-cd09-0410-ab3c-d52691b4dbfc

LayoutTests/ChangeLog
LayoutTests/svg/animations/animate-end-attribute-numeric-precision-expected.txt [new file with mode: 0644]
LayoutTests/svg/animations/animate-end-attribute-numeric-precision.html [new file with mode: 0644]
LayoutTests/svg/animations/script-tests/animate-end-attribute-numeric-precision.js [new file with mode: 0644]
Source/WebCore/ChangeLog
Source/WebCore/svg/animation/SVGSMILElement.cpp

index 9ac2100..fe6fc62 100644 (file)
@@ -1,3 +1,17 @@
+2012-05-03  Philip Rogers  <pdr@google.com>
+
+        Fix numeric precision issue in SVG animations
+        https://bugs.webkit.org/show_bug.cgi?id=85502
+
+        Reviewed by Dirk Schulze.
+
+        * svg/animations/animate-end-attribute-numeric-precision-expected.txt: Added.
+        * svg/animations/animate-end-attribute-numeric-precision.html: Added.
+        * svg/animations/script-tests/animate-end-attribute-numeric-precision.js: Added.
+        (sample1):
+        (sample2):
+        (executeTest):
+
 2012-05-03  Zhenyao Mo  <zmo@google.com>
 
         Unreviewed, rebaseline.
diff --git a/LayoutTests/svg/animations/animate-end-attribute-numeric-precision-expected.txt b/LayoutTests/svg/animations/animate-end-attribute-numeric-precision-expected.txt
new file mode 100644 (file)
index 0000000..03211db
--- /dev/null
@@ -0,0 +1,15 @@
+SVG 1.1 dynamic animation tests
+
+Tests end conditions are respected properly near the limits of float numeric precision
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS rect.x.animVal.value is 100
+PASS rect.x.baseVal.value is 100
+PASS rect.x.animVal.value is 300
+PASS rect.x.baseVal.value is 100
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/svg/animations/animate-end-attribute-numeric-precision.html b/LayoutTests/svg/animations/animate-end-attribute-numeric-precision.html
new file mode 100644 (file)
index 0000000..09e7143
--- /dev/null
@@ -0,0 +1,15 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<!-- Tests numeric precision issues in animations -->
+<script src="../../fast/js/resources/js-test-pre.js"></script>
+<script src="../dynamic-updates/resources/SVGTestCase.js"></script>
+<script src="resources/SVGAnimationTestCase.js"></script>
+</head>
+<body onload="runSMILTest()">
+<h1>SVG 1.1 dynamic animation tests</h1>
+<p id="description"></p>
+<div id="console"></div>
+<script src="script-tests/animate-end-attribute-numeric-precision.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/svg/animations/script-tests/animate-end-attribute-numeric-precision.js b/LayoutTests/svg/animations/script-tests/animate-end-attribute-numeric-precision.js
new file mode 100644 (file)
index 0000000..00a49a8
--- /dev/null
@@ -0,0 +1,44 @@
+description("Tests end conditions are respected properly near the limits of float numeric precision");
+createSVGTestCase();
+
+// Setup test document
+var rect = createSVGElement("rect");
+rect.setAttribute("id", "rect");
+rect.setAttribute("x", "100");
+rect.setAttribute("width", "100");
+rect.setAttribute("height", "100");
+rect.setAttribute("fill", "green");
+
+var animate = createSVGElement("animate");
+animate.setAttribute("id", "animation");
+animate.setAttribute("attributeName", "x");
+animate.setAttribute("values", "0;300");
+animate.setAttribute("begin", "0.333333333333333s");
+animate.setAttribute("dur", "0.4256483205159505s");
+animate.setAttribute("fill", "freeze");
+rect.appendChild(animate);
+rootSVGElement.appendChild(rect);
+
+// Setup animation test
+function sample1() {
+    shouldBeCloseEnough("rect.x.animVal.value", "100");
+    shouldBe("rect.x.baseVal.value", "100");
+}
+
+function sample2() {
+    shouldBeCloseEnough("rect.x.animVal.value", "300");
+    shouldBe("rect.x.baseVal.value", "100");
+}
+
+function executeTest() {
+    const expectedValues = [
+        // [animationId, time, sampleCallback]
+        ["animation", 0.0, sample1],
+        ["animation", 1.0, sample2]
+    ];
+
+    runAnimationTest(expectedValues);
+}
+
+var successfullyParsed = true;
+executeTest();
index 21d5cfa..65b5ba0 100644 (file)
@@ -1,3 +1,20 @@
+2012-05-03  Philip Rogers  <pdr@google.com>
+
+        Fix numeric precision issue in SVG animations
+        https://bugs.webkit.org/show_bug.cgi?id=85502
+
+        Reviewed by Dirk Schulze.
+
+        r93938 had a bug where floating point numbers where compared exactly,
+        exposing a bug when floating point precision was not sufficient. This
+        change compares against an epsilon value to get around these precision
+        issues.
+
+        Test: svg/animations/animate-end-attribute-numeric-precision.html
+
+        * svg/animation/SVGSMILElement.cpp:
+        (WebCore::SVGSMILElement::calculateAnimationPercentAndRepeat):
+
 2012-05-03  Joshua Bell  <jsbell@chromium.org>
 
         Fix coding style issues in IDBLevelDBCoding.cpp
index a0c0d08..ff80f07 100644 (file)
@@ -956,11 +956,11 @@ float SVGSMILElement::calculateAnimationPercentAndRepeat(SMILTime elapsed, unsig
         if (fmod(repeatingDuration.value(), !simpleDuration.value()))
             repeat--;
 
-        SMILTime simpleEndTime = fmod(m_intervalEnd.value() - m_intervalBegin.value(), simpleDuration.value());
-        if (simpleEndTime.value())
-            return narrowPrecisionToFloat(simpleEndTime.value() / simpleDuration.value());
-
-        return 1.f;
+        double percent = (m_intervalEnd.value() - m_intervalBegin.value()) / simpleDuration.value();
+        percent = percent - floor(percent);
+        if (percent < numeric_limits<float>::epsilon() || 1 - percent < numeric_limits<float>::epsilon())
+            return 1.0f;
+        return narrowPrecisionToFloat(percent);
     }
     repeat = static_cast<unsigned>(activeTime.value() / simpleDuration.value());
     SMILTime simpleTime = fmod(activeTime.value(), simpleDuration.value());