Title: [115947] trunk
Revision
115947
Author
zimmerm...@webkit.org
Date
2012-05-03 01:45:14 -0700 (Thu, 03 May 2012)

Log Message

Fix multiple begin values support - especially with seeking through setCurrentTime
https://bugs.webkit.org/show_bug.cgi?id=85372

Reviewed by Zoltan Herczeg.

Source/WebCore:

Multiple begin values aka. begin="0s; 2s" aren't correctly handled - resulting in broken & unexpected behavior.
Supporting seeking properly on documents containing such animations is very important, otherwise we can't reliable
test animations using either reftests or the SVG JS animation test framework.

Testcase:
<rect height="100" fill="green">
    <animate attributeName="width" begin="0s; 2s" dur="8s" from="0" to="100" fill="freeze"/>
</rect>

What's expected?
Two times should be contained in the 'begin' times list in SVGSMILElement: m_beginTimes = { 0s, 2s }.
The initial first resolved interval is: m_intervalBegin=0.0s, m_intervalEnd=8.0s.

During t=0s..1.9999s the m_intervalBegin/m_intervalEnd are correct.
At t=2s, a new interval can be started. m_intervalEnd should be set to nextBeginTime, where nextBeginTime=2s.
The current interval should get cropped to: m_intervalBegin=0s, m_intervalEnd=2s. The following call to
resolveNextInterval() sees that elapsed >= m_intervalEnd, and thus moves on to the next interval.
m_intervalBegin should be 2s and m_intervalEnd=10s after that.

In trunk this behavior is only partly implemented and broken. Especially broken together with seeking via SVGSVGElement.setCurrentTime.
That's because we don't correctly seek to the right interval in case of multiple begin values, eg. if we sample an animation with
begin="0s; 3s" dur="6s" we always remain in the first interval and don't move on.

Fix all of these issues, making lots more tests work in Dr. Olaf Hofmanns SVG Animation test suite.

Tests: svg/animations/multiple-begin-additive-animation.html
       svg/animations/multiple-begin-animation-discrete-expected.svg
       svg/animations/multiple-begin-animation-discrete.svg
       svg/animations/multiple-begin-animation-expected.svg
       svg/animations/multiple-begin-animation.svg

* svg/animation/SMILTimeContainer.cpp:
(WebCore::SMILTimeContainer::begin):
(WebCore::SMILTimeContainer::setElapsed):
(WebCore::SMILTimeContainer::updateAnimations):
* svg/animation/SMILTimeContainer.h:
(SMILTimeContainer):
* svg/animation/SVGSMILElement.cpp:
(WebCore::SVGSMILElement::findInstanceTime):
(WebCore::SVGSMILElement::resolveInterval):
(WebCore::SVGSMILElement::resolveNextInterval):
(WebCore):
(WebCore::SVGSMILElement::checkRestart):
(WebCore::SVGSMILElement::seekToIntervalCorrespondingToTime):
(WebCore::SVGSMILElement::progress):
* svg/animation/SVGSMILElement.h:
(SVGSMILElement):

LayoutTests:

* svg/animations/multiple-begin-additive-animation-expected.txt: Added.
* svg/animations/multiple-begin-additive-animation.html: Added.
* svg/animations/multiple-begin-animation-discrete-expected.svg: Added.
* svg/animations/multiple-begin-animation-discrete.svg: Added.
* svg/animations/multiple-begin-animation-expected.svg: Added.
* svg/animations/multiple-begin-animation.svg: Added.
* svg/animations/resources/multiple-begin-additive-animation.svg: Added.
* svg/animations/script-tests/multiple-begin-additive-animation.js: Added.
(checkBaseValues):
(sample1):
(sample2):
(sample3):
(sample4):
(sample5):
(sample6):
(sample7):
(sample8):
(sample9):
(sample10):
(sample11):
(sample12):
(sample13):
(executeTest):

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (115946 => 115947)


--- trunk/LayoutTests/ChangeLog	2012-05-03 08:22:58 UTC (rev 115946)
+++ trunk/LayoutTests/ChangeLog	2012-05-03 08:45:14 UTC (rev 115947)
@@ -1,3 +1,34 @@
+2012-05-03  Nikolas Zimmermann  <nzimmerm...@rim.com>
+
+        Fix multiple begin values support - especially with seeking through setCurrentTime
+        https://bugs.webkit.org/show_bug.cgi?id=85372
+
+        Reviewed by Zoltan Herczeg.
+
+        * svg/animations/multiple-begin-additive-animation-expected.txt: Added.
+        * svg/animations/multiple-begin-additive-animation.html: Added.
+        * svg/animations/multiple-begin-animation-discrete-expected.svg: Added.
+        * svg/animations/multiple-begin-animation-discrete.svg: Added.
+        * svg/animations/multiple-begin-animation-expected.svg: Added.
+        * svg/animations/multiple-begin-animation.svg: Added.
+        * svg/animations/resources/multiple-begin-additive-animation.svg: Added.
+        * svg/animations/script-tests/multiple-begin-additive-animation.js: Added.
+        (checkBaseValues):
+        (sample1):
+        (sample2):
+        (sample3):
+        (sample4):
+        (sample5):
+        (sample6):
+        (sample7):
+        (sample8):
+        (sample9):
+        (sample10):
+        (sample11):
+        (sample12):
+        (sample13):
+        (executeTest):
+
 2012-05-03  Dongwoo Im  <dw...@samsung.com>
 
         [EFL][DRT] Implement the LayoutTestController's methods related to the Page Visibility API.

Added: trunk/LayoutTests/svg/animations/multiple-begin-additive-animation-expected.txt (0 => 115947)


--- trunk/LayoutTests/svg/animations/multiple-begin-additive-animation-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/svg/animations/multiple-begin-additive-animation-expected.txt	2012-05-03 08:45:14 UTC (rev 115947)
@@ -0,0 +1,44 @@
+SVG 1.1 dynamic animation tests
+
+
+This tests additive='sum' support on animate elements with multiple begin times
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS rect.x.animVal.value is 0
+PASS rect.y.animVal.value is 100
+PASS rect.x.animVal.value is 0
+PASS rect.y.animVal.value is 166.67
+PASS rect.x.animVal.value is 0
+PASS rect.y.animVal.value is 366.60
+PASS rect.x.animVal.value is 0
+PASS rect.y.animVal.value is 366.73
+PASS rect.x.animVal.value is 0
+PASS rect.y.animVal.value is 499.93
+PASS rect.x.animVal.value is 400
+PASS rect.y.animVal.value is 500.06
+PASS rect.x.animVal.value is 400
+PASS rect.y.animVal.value is 566.67
+PASS rect.x.animVal.value is 400
+PASS rect.y.animVal.value is 633.33
+PASS rect.x.animVal.value is 400
+PASS rect.y.animVal.value is 633.33
+PASS rect.x.animVal.value is 400
+PASS rect.y.animVal.value is 700
+PASS rect.x.animVal.value is 400
+PASS rect.y.animVal.value is 766.60
+PASS rect.x.animVal.value is 0
+PASS rect.y.animVal.value is 766.67
+PASS rect.x.animVal.value is 0
+PASS rect.y.animVal.value is 833.33
+PASS rect.x.animVal.value is 0
+PASS rect.y.animVal.value is 900
+PASS rect.x.animVal.value is 0
+PASS rect.y.animVal.value is 900
+PASS rect.x.animVal.value is 0
+PASS rect.y.animVal.value is 900
+PASS successfullyParsed is true
+
+TEST COMPLETE
+

Added: trunk/LayoutTests/svg/animations/multiple-begin-additive-animation.html (0 => 115947)


--- trunk/LayoutTests/svg/animations/multiple-begin-additive-animation.html	                        (rev 0)
+++ trunk/LayoutTests/svg/animations/multiple-begin-additive-animation.html	2012-05-03 08:45:14 UTC (rev 115947)
@@ -0,0 +1,14 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<script src=""
+<script src=""
+<script src=""
+</head>
+<body _onload_="runSMILTest()">
+<h1>SVG 1.1 dynamic animation tests</h1>
+<p id="description"></p>
+<div id="console"></div>
+<script src=""
+</body>
+</html>

Added: trunk/LayoutTests/svg/animations/multiple-begin-animation-discrete-expected.svg (0 => 115947)


--- trunk/LayoutTests/svg/animations/multiple-begin-animation-discrete-expected.svg	                        (rev 0)
+++ trunk/LayoutTests/svg/animations/multiple-begin-animation-discrete-expected.svg	2012-05-03 08:45:14 UTC (rev 115947)
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1 Tiny//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11-tiny.dtd">
+<svg xmlns="http://www.w3.org/2000/svg">
+    <rect width="100" height="100" fill="red"/>
+    <rect width="100" height="100" fill="green"/>
+</svg>

Added: trunk/LayoutTests/svg/animations/multiple-begin-animation-discrete.svg (0 => 115947)


--- trunk/LayoutTests/svg/animations/multiple-begin-animation-discrete.svg	                        (rev 0)
+++ trunk/LayoutTests/svg/animations/multiple-begin-animation-discrete.svg	2012-05-03 08:45:14 UTC (rev 115947)
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1 Tiny//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11-tiny.dtd">
+<svg xmlns="http://www.w3.org/2000/svg" _onload_="loaded()">
+<rect width="100" height="100" fill="green">
+    <animate attributeName="width" attributeType="XML" calcMode="discrete" begin="0s; 3s" from="100" to="0" dur="8s"/>
+</rect>
+<script>
+if (window.layoutTestController)
+    layoutTestController.waitUntilDone();
+
+function loaded() {
+    document.documentElement.setCurrentTime(6.5);
+    document.documentElement.pauseAnimations();
+
+    if (window.layoutTestController)
+        layoutTestController.notifyDone();
+}
+</script>
+</svg>

Added: trunk/LayoutTests/svg/animations/multiple-begin-animation-expected.svg (0 => 115947)


--- trunk/LayoutTests/svg/animations/multiple-begin-animation-expected.svg	                        (rev 0)
+++ trunk/LayoutTests/svg/animations/multiple-begin-animation-expected.svg	2012-05-03 08:45:14 UTC (rev 115947)
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1 Tiny//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11-tiny.dtd">
+<svg xmlns="http://www.w3.org/2000/svg">
+    <rect width="100" height="100" fill="green"/>
+</svg>

Added: trunk/LayoutTests/svg/animations/multiple-begin-animation.svg (0 => 115947)


--- trunk/LayoutTests/svg/animations/multiple-begin-animation.svg	                        (rev 0)
+++ trunk/LayoutTests/svg/animations/multiple-begin-animation.svg	2012-05-03 08:45:14 UTC (rev 115947)
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1 Tiny//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11-tiny.dtd">
+<svg xmlns="http://www.w3.org/2000/svg" _onload_="loaded()">
+<rect width="10" height="100" fill="green">
+    <animate attributeName="width" attributeType="XML" begin="0s; 2s" from="0" to="200" dur="4s" fill="freeze"/>
+</rect>
+<script>
+if (window.layoutTestController)
+    layoutTestController.waitUntilDone();
+
+function loaded() {
+    document.documentElement.setCurrentTime(4);
+    document.documentElement.pauseAnimations();
+
+    if (window.layoutTestController)
+        layoutTestController.notifyDone();
+}
+</script>
+</svg>

Added: trunk/LayoutTests/svg/animations/resources/multiple-begin-additive-animation.svg (0 => 115947)


--- trunk/LayoutTests/svg/animations/resources/multiple-begin-additive-animation.svg	                        (rev 0)
+++ trunk/LayoutTests/svg/animations/resources/multiple-begin-additive-animation.svg	2012-05-03 08:45:14 UTC (rev 115947)
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1 Tiny//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11-tiny.dtd">
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1000 1000">
+<rect width="100" height="100" fill="green">
+    <animate id="an1" attributeName="y" attributeType="XML" begin="0s" dur="12s" from="100" to="900" fill="freeze" />
+    <animate attributeName="x" attributeType="XML" calcMode="discrete" begin="0s; 2s" from="0" to="400" dur="8s" additive="sum" />
+</rect>
+</svg>

Added: trunk/LayoutTests/svg/animations/script-tests/multiple-begin-additive-animation.js (0 => 115947)


--- trunk/LayoutTests/svg/animations/script-tests/multiple-begin-additive-animation.js	                        (rev 0)
+++ trunk/LayoutTests/svg/animations/script-tests/multiple-begin-additive-animation.js	2012-05-03 08:45:14 UTC (rev 115947)
@@ -0,0 +1,117 @@
+description("This tests additive='sum' support on animate elements with multiple begin times");
+embedSVGTestCase("resources/multiple-begin-additive-animation.svg");
+
+// Setup animation test
+function checkBaseValues() {
+return;
+    shouldBe("rect.x.baseVal.value", "0");
+    shouldBe("rect.y.baseVal.value", "0");
+}
+
+function sample1() {
+    shouldBe("rect.x.animVal.value", "0");
+    shouldBeCloseEnough("rect.y.animVal.value", "100");
+    checkBaseValues();
+}
+
+function sample2() {
+    shouldBe("rect.x.animVal.value", "0");
+    shouldBeCloseEnough("rect.y.animVal.value", "166.67");
+    checkBaseValues();
+}
+
+function sample3() {
+    shouldBe("rect.x.animVal.value", "0");
+    shouldBeCloseEnough("rect.y.animVal.value", "366.60");
+    checkBaseValues();
+}
+
+function sample4() {
+    shouldBe("rect.x.animVal.value", "0");
+    shouldBeCloseEnough("rect.y.animVal.value", "366.73");
+    checkBaseValues();
+}
+
+function sample5() {
+    shouldBe("rect.x.animVal.value", "0");
+    shouldBeCloseEnough("rect.y.animVal.value", "499.93");
+    checkBaseValues();
+}
+
+function sample6() {
+    shouldBe("rect.x.animVal.value", "400");
+    shouldBeCloseEnough("rect.y.animVal.value", "500.06");
+    checkBaseValues();
+}
+
+function sample7() {
+    shouldBe("rect.x.animVal.value", "400");
+    shouldBeCloseEnough("rect.y.animVal.value", "566.67");
+    checkBaseValues();
+}
+
+function sample8() {
+    shouldBe("rect.x.animVal.value", "400");
+    shouldBeCloseEnough("rect.y.animVal.value", "633.33");
+    checkBaseValues();
+}
+
+function sample9() {
+    shouldBe("rect.x.animVal.value", "400");
+    shouldBeCloseEnough("rect.y.animVal.value", "700");
+    checkBaseValues();
+}
+
+function sample10() {
+    shouldBe("rect.x.animVal.value", "400");
+    shouldBeCloseEnough("rect.y.animVal.value", "766.60");
+    checkBaseValues();
+}
+
+function sample11() {
+    shouldBe("rect.x.animVal.value", "0");
+    shouldBeCloseEnough("rect.y.animVal.value", "766.67");
+    checkBaseValues();
+}
+
+function sample12() {
+    shouldBe("rect.x.animVal.value", "0");
+    shouldBeCloseEnough("rect.y.animVal.value", "833.33");
+    checkBaseValues();
+}
+
+function sample13() {
+    shouldBe("rect.x.animVal.value", "0");
+    shouldBeCloseEnough("rect.y.animVal.value", "900");
+    checkBaseValues();
+}
+
+function executeTest() {
+    rect = rootSVGElement.ownerDocument.getElementsByTagName("rect")[0];
+
+    // All animations in the test file use the same duration, so it's not needed to list all sample points individually for an5/an6/an7/an8.
+    const expectedValues = [
+        // [animationId, time, sampleCallback]
+        ["an1", 0.0,    sample1],
+        ["an1", 1.0,    sample2],
+        ["an1", 3.999,  sample3],
+        ["an1", 4.001,  sample4],
+        ["an1", 5.999,  sample5],
+        ["an1", 6.001,  sample6],
+        ["an1", 7.0,    sample7],
+        ["an1", 7.999,  sample8],
+        ["an1", 8.001,  sample8],
+        ["an1", 9.0,    sample9],
+        ["an1", 9.999,  sample10],
+        ["an1", 10.001, sample11],
+        ["an1", 11.0,   sample12],
+        ["an1", 11.999, sample13],
+        ["an1", 12.001, sample13],
+        ["an1", 60.0,   sample13]
+    ];
+
+    runAnimationTest(expectedValues);
+}
+
+window.animationStartsImmediately = true;
+var successfullyParsed = true;

Modified: trunk/Source/WebCore/ChangeLog (115946 => 115947)


--- trunk/Source/WebCore/ChangeLog	2012-05-03 08:22:58 UTC (rev 115946)
+++ trunk/Source/WebCore/ChangeLog	2012-05-03 08:45:14 UTC (rev 115947)
@@ -1,3 +1,58 @@
+2012-05-03  Nikolas Zimmermann  <nzimmerm...@rim.com>
+
+        Fix multiple begin values support - especially with seeking through setCurrentTime
+        https://bugs.webkit.org/show_bug.cgi?id=85372
+
+        Reviewed by Zoltan Herczeg.
+
+        Multiple begin values aka. begin="0s; 2s" aren't correctly handled - resulting in broken & unexpected behavior.
+        Supporting seeking properly on documents containing such animations is very important, otherwise we can't reliable
+        test animations using either reftests or the SVG JS animation test framework.
+
+        Testcase:
+        <rect height="100" fill="green">
+            <animate attributeName="width" begin="0s; 2s" dur="8s" from="0" to="100" fill="freeze"/>
+        </rect>
+
+        What's expected?
+        Two times should be contained in the 'begin' times list in SVGSMILElement: m_beginTimes = { 0s, 2s }.
+        The initial first resolved interval is: m_intervalBegin=0.0s, m_intervalEnd=8.0s.
+
+        During t=0s..1.9999s the m_intervalBegin/m_intervalEnd are correct.
+        At t=2s, a new interval can be started. m_intervalEnd should be set to nextBeginTime, where nextBeginTime=2s.
+        The current interval should get cropped to: m_intervalBegin=0s, m_intervalEnd=2s. The following call to
+        resolveNextInterval() sees that elapsed >= m_intervalEnd, and thus moves on to the next interval.
+        m_intervalBegin should be 2s and m_intervalEnd=10s after that.
+
+        In trunk this behavior is only partly implemented and broken. Especially broken together with seeking via SVGSVGElement.setCurrentTime.
+        That's because we don't correctly seek to the right interval in case of multiple begin values, eg. if we sample an animation with
+        begin="0s; 3s" dur="6s" we always remain in the first interval and don't move on.
+
+        Fix all of these issues, making lots more tests work in Dr. Olaf Hofmanns SVG Animation test suite.
+
+        Tests: svg/animations/multiple-begin-additive-animation.html
+               svg/animations/multiple-begin-animation-discrete-expected.svg
+               svg/animations/multiple-begin-animation-discrete.svg
+               svg/animations/multiple-begin-animation-expected.svg
+               svg/animations/multiple-begin-animation.svg
+
+        * svg/animation/SMILTimeContainer.cpp:
+        (WebCore::SMILTimeContainer::begin):
+        (WebCore::SMILTimeContainer::setElapsed):
+        (WebCore::SMILTimeContainer::updateAnimations):
+        * svg/animation/SMILTimeContainer.h:
+        (SMILTimeContainer):
+        * svg/animation/SVGSMILElement.cpp:
+        (WebCore::SVGSMILElement::findInstanceTime):
+        (WebCore::SVGSMILElement::resolveInterval):
+        (WebCore::SVGSMILElement::resolveNextInterval):
+        (WebCore):
+        (WebCore::SVGSMILElement::checkRestart):
+        (WebCore::SVGSMILElement::seekToIntervalCorrespondingToTime):
+        (WebCore::SVGSMILElement::progress):
+        * svg/animation/SVGSMILElement.h:
+        (SVGSMILElement):
+
 2012-05-03  Dana Jansens  <dan...@chromium.org>
 
         [chromium] Don't add small opaque areas to the occlusion tracker's Region

Modified: trunk/Source/WebCore/svg/animation/SMILTimeContainer.cpp (115946 => 115947)


--- trunk/Source/WebCore/svg/animation/SMILTimeContainer.cpp	2012-05-03 08:22:58 UTC (rev 115946)
+++ trunk/Source/WebCore/svg/animation/SMILTimeContainer.cpp	2012-05-03 08:45:14 UTC (rev 115947)
@@ -89,8 +89,10 @@
     ASSERT(!m_beginTime);
     double now = currentTime();
 
+    // If 'm_presetStartTime' is set, the timeline was modified via setElapsed() before the document began.
+    // In this case pass on 'seekToTime=true' to updateAnimations().
     m_beginTime = now - m_presetStartTime;
-    updateAnimations(SMILTime(m_presetStartTime));
+    updateAnimations(SMILTime(m_presetStartTime), m_presetStartTime ? true : false);
     m_presetStartTime = 0;
 
     if (m_pauseTime) {
@@ -126,6 +128,9 @@
         return;
     }
 
+    if (m_beginTime)
+        m_timer.stop();
+
     m_beginTime = currentTime() - time.value();
     m_accumulatedPauseTime = 0;
 
@@ -134,7 +139,7 @@
     for (unsigned n = 0; n < toReset.size(); ++n)
         toReset[n]->reset();
 
-    updateAnimations(time);
+    updateAnimations(time, true);
 }
 
 void SMILTimeContainer::startTimer(SMILTime fireTime, SMILTime minimumDelay)
@@ -202,7 +207,7 @@
     std::sort(smilElements.begin(), smilElements.end(), applyOrderSortFunction);
 }
 
-void SMILTimeContainer::updateAnimations(SMILTime elapsed)
+void SMILTimeContainer::updateAnimations(SMILTime elapsed, bool seekToTime)
 {
     SMILTime earliersFireTime = SMILTime::unresolved();
 
@@ -247,7 +252,7 @@
         }
 
         // This will calculate the contribution from the animation and add it to the resultsElement.
-        animation->progress(elapsed, resultElement);
+        animation->progress(elapsed, resultElement, seekToTime);
 
         SMILTime nextFireTime = animation->nextProgressTime();
         if (nextFireTime.isFinite())

Modified: trunk/Source/WebCore/svg/animation/SMILTimeContainer.h (115946 => 115947)


--- trunk/Source/WebCore/svg/animation/SMILTimeContainer.h	2012-05-03 08:22:58 UTC (rev 115946)
+++ trunk/Source/WebCore/svg/animation/SMILTimeContainer.h	2012-05-03 08:45:14 UTC (rev 115947)
@@ -68,7 +68,7 @@
     
     void timerFired(Timer<SMILTimeContainer>*);
     void startTimer(SMILTime fireTime, SMILTime minimumDelay = 0);
-    void updateAnimations(SMILTime elapsed);
+    void updateAnimations(SMILTime elapsed, bool seekToTime = false);
     
     void updateDocumentOrderIndexes();
     void sortByPriority(Vector<SVGSMILElement*>& smilElements, SMILTime elapsed);

Modified: trunk/Source/WebCore/svg/animation/SVGSMILElement.cpp (115946 => 115947)


--- trunk/Source/WebCore/svg/animation/SVGSMILElement.cpp	2012-05-03 08:22:58 UTC (rev 115946)
+++ trunk/Source/WebCore/svg/animation/SVGSMILElement.cpp	2012-05-03 08:45:14 UTC (rev 115947)
@@ -696,37 +696,32 @@
 
     const SMILTimeWithOrigin* result = binarySearch<const SMILTimeWithOrigin, SMILTime, extractTimeFromVector>(list.begin(), sizeOfList, minimumTime, WTF::KeyMustNotBePresentInArray);
     int indexOfResult = result - list.begin();
-    if (sizeOfList - 1 > indexOfResult && list[indexOfResult].time() < minimumTime)
-        ++indexOfResult;
-
     ASSERT(indexOfResult < sizeOfList);
     const SMILTime& currentTime = list[indexOfResult].time();
 
-    // "The special value "indefinite" does not yield an instance time in the begin list."
+    // The special value "indefinite" does not yield an instance time in the begin list.
     if (currentTime.isIndefinite() && beginOrEnd == Begin)
         return SMILTime::unresolved();
 
     if (currentTime < minimumTime)
         return beginOrEnd == Begin ? SMILTime::unresolved() : SMILTime::indefinite();
+    if (currentTime > minimumTime)
+        return currentTime;
 
-    // If the equals is NOT accepted, we have to find a bigger one.
-    if (currentTime == minimumTime && !equalsMinimumOK) {
-        if (indexOfResult + 1 >= sizeOfList)
-            return beginOrEnd == Begin ? SMILTime::unresolved() : SMILTime::indefinite();
-    }
+    ASSERT(currentTime == minimumTime);
+    if (equalsMinimumOK)
+        return currentTime;
 
-    while (indexOfResult < sizeOfList - 1 && currentTime == list[indexOfResult + 1].time())
+    // If the equals is not accepted, return the next bigger item in the list.
+    SMILTime nextTime = currentTime;
+    while (indexOfResult < sizeOfList - 1) {
+        nextTime = list[indexOfResult + 1].time();
+        if (nextTime > minimumTime)
+            return nextTime;
         ++indexOfResult;
-
-    if (currentTime > minimumTime)
-        return currentTime;
-    if (currentTime == minimumTime) {
-        if (indexOfResult + 1 < sizeOfList - 1)
-            return list[indexOfResult + 1].time();
-        return beginOrEnd == Begin ? SMILTime::unresolved() : SMILTime::indefinite();
     }
 
-    return currentTime;
+    return beginOrEnd == Begin ? SMILTime::unresolved() : SMILTime::indefinite();
 }
 
 SMILTime SVGSMILElement::repeatingDuration() const
@@ -767,12 +762,12 @@
 
 void SVGSMILElement::resolveInterval(bool first, SMILTime& beginResult, SMILTime& endResult) const
 {
-    // See the pseudocode in
-    // http://www.w3.org/TR/2001/REC-smil-animation-20010904/#Timing-BeginEnd-LifeCycle
+    // See the pseudocode in http://www.w3.org/TR/SMIL3/smil-timing.html#q90.
     SMILTime beginAfter = first ? -numeric_limits<double>::infinity() : m_intervalEnd;
     SMILTime lastIntervalTempEnd = numeric_limits<double>::infinity();
     while (true) {
-        SMILTime tempBegin = findInstanceTime(Begin, beginAfter, true);
+        bool equalsMinimumOK = !first || m_intervalEnd > m_intervalBegin;
+        SMILTime tempBegin = findInstanceTime(Begin, beginAfter, equalsMinimumOK);
         if (tempBegin.isUnresolved())
             break;
         SMILTime tempEnd;
@@ -788,13 +783,11 @@
             }
             tempEnd = resolveActiveEnd(tempBegin, tempEnd);
         }
-        if (tempEnd > 0 || !first) {
+        if (!first || (tempEnd > 0 || (!tempBegin.value() && !tempEnd.value()))) {
             beginResult = tempBegin;
             endResult = tempEnd;
             return;
         }
-        if (restart() == RestartNever)
-            break;
 
         beginAfter = tempEnd;
         lastIntervalTempEnd = tempEnd;
@@ -820,7 +813,7 @@
     }
 }
 
-void SVGSMILElement::resolveNextInterval()
+void SVGSMILElement::resolveNextInterval(bool notifyDependents)
 {
     SMILTime begin;
     SMILTime end;
@@ -830,7 +823,8 @@
     if (!begin.isUnresolved() && begin != m_intervalBegin) {
         m_intervalBegin = begin;
         m_intervalEnd = end;
-        notifyDependentsIntervalChanged(NewInterval);
+        if (notifyDependents)
+            notifyDependentsIntervalChanged(NewInterval);
         m_nextProgressTime = min(m_nextProgressTime, m_intervalBegin);
     }
 }
@@ -884,16 +878,16 @@
     m_nextProgressTime = elapsed;
     reschedule();
 }
-    
+
 void SVGSMILElement::checkRestart(SMILTime elapsed)
 {
     ASSERT(!m_isWaitingForFirstInterval);
     ASSERT(elapsed >= m_intervalBegin);
-    
+
     Restart restart = this->restart();
     if (restart == RestartNever)
         return;
-    
+
     if (elapsed < m_intervalEnd) {
         if (restart != RestartAlways)
             return;
@@ -902,11 +896,45 @@
             m_intervalEnd = nextBegin;
             notifyDependentsIntervalChanged(ExistingInterval);
         }
-    } 
+    }
+
     if (elapsed >= m_intervalEnd)
-        resolveNextInterval();
+        resolveNextInterval(true);
 }
-    
+
+void SVGSMILElement::seekToIntervalCorrespondingToTime(SMILTime elapsed)
+{
+    ASSERT(!m_isWaitingForFirstInterval);
+    ASSERT(elapsed >= m_intervalBegin);
+
+    // Manually seek from interval to interval, just as if the animation would run regulary.
+    while (true) {
+        // Figure out the next value in the begin time list after the current interval begin.
+        SMILTime nextBegin = findInstanceTime(Begin, m_intervalBegin, false);
+
+        // If the 'nextBegin' time is unresolved (eg. just one defined interval), we're done seeking.
+        if (nextBegin.isUnresolved())
+            return;
+
+        // If the 'nextBegin' time is larger than or equal to the current interval end time, we're done seeking.
+        // If the 'elapsed' time is smaller than the next begin interval time, we're done seeking.
+        if (nextBegin < m_intervalEnd && elapsed >= nextBegin) {
+            // End current interval, and start a new interval from the 'nextBegin' time.
+            m_intervalEnd = nextBegin;
+            resolveNextInterval(false);
+            continue;
+        }
+
+        // If the desired 'elapsed' time is past the current interval, advance to the next.
+        if (elapsed >= m_intervalEnd) {
+            resolveNextInterval(false);
+            continue;
+        }
+
+        return;
+    }
+}
+
 float SVGSMILElement::calculateAnimationPercentAndRepeat(SMILTime elapsed, unsigned& repeat) const
 {
     SMILTime simpleDuration = this->simpleDuration();
@@ -974,7 +1002,7 @@
     return (m_activeState == Active && (fill() == FillFreeze || elapsed <= m_intervalBegin + repeatingDuration())) || m_activeState == Frozen;
 }
     
-void SVGSMILElement::progress(SMILTime elapsed, SVGSMILElement* resultElement)
+void SVGSMILElement::progress(SMILTime elapsed, SVGSMILElement* resultElement, bool seekToTime)
 {
     ASSERT(m_timeContainer);
     ASSERT(m_isWaitingForFirstInterval || m_intervalBegin.isFinite());
@@ -1003,15 +1031,19 @@
         m_activeState = Active;
         startedActiveInterval();
     }
-    
-    unsigned repeat;
+
+    // This call may obtain a new interval -- never call calculateAnimationPercentAndRepeat() before!
+    if (seekToTime) {
+        seekToIntervalCorrespondingToTime(elapsed);
+        ASSERT(elapsed >= m_intervalBegin);
+    }
+
+    unsigned repeat = 0;
     float percent = calculateAnimationPercentAndRepeat(elapsed, repeat);
-
     checkRestart(elapsed);
 
     ActiveState oldActiveState = m_activeState;
     m_activeState = determineActiveState(elapsed);
-    
     if (isContributing(elapsed)) {
         if (resultElement)
             updateAnimation(percent, repeat, resultElement);

Modified: trunk/Source/WebCore/svg/animation/SVGSMILElement.h (115946 => 115947)


--- trunk/Source/WebCore/svg/animation/SVGSMILElement.h	2012-05-03 08:22:58 UTC (rev 115946)
+++ trunk/Source/WebCore/svg/animation/SVGSMILElement.h	2012-05-03 08:45:14 UTC (rev 115947)
@@ -89,7 +89,8 @@
     SMILTime previousIntervalBegin() const { return m_previousIntervalBegin; }
     SMILTime simpleDuration() const;
 
-    void progress(SMILTime elapsed, SVGSMILElement* resultsElement);
+    void seekToIntervalCorrespondingToTime(SMILTime elapsed);
+    void progress(SMILTime elapsed, SVGSMILElement* resultsElement, bool seekToTime);
     SMILTime nextProgressTime() const;
 
     void reset();
@@ -129,7 +130,7 @@
     
     SMILTime findInstanceTime(BeginOrEnd, SMILTime minimumTime, bool equalsMinimumOK) const;
     void resolveFirstInterval();
-    void resolveNextInterval();
+    void resolveNextInterval(bool notifyDependents);
     void resolveInterval(bool first, SMILTime& beginResult, SMILTime& endResult) const;
     SMILTime resolveActiveEnd(SMILTime resolvedBegin, SMILTime resolvedEnd) const;
     SMILTime repeatingDuration() const;
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
http://lists.webkit.org/mailman/listinfo.cgi/webkit-changes

Reply via email to