Title: [128131] trunk
Revision
128131
Author
p...@google.com
Date
2012-09-10 17:07:26 -0700 (Mon, 10 Sep 2012)

Log Message

Source/WebCore: Remove unnecessary codepaths in SMILTimeContainer::updateAnimations
https://bugs.webkit.org/show_bug.cgi?id=96224

Reviewed by Nikolas Zimmermann.

This change removes two sources of unnecessary code in
SMILTimeContainer::updateAnimations:
    1) After r117711 we now accumulate the result of multiple
       animations into the first _contributing_ animation
       element. As a result it is no longer necessary to
       track both which elements are contributing AND which elements
       we are storing results into. Both cases are now handled
       together with resultsElements.

    2) r32044 added a second sort of the animation elements
       in order to process animateTransform last. This change
       was added 4 years ago, before we correctly handled <use>
       and the instance tree, and I think the extra sort is no
       longer necessary. A test has been added to ensure this
       is the case.

This change also does a minor cleanup of resultsElements. Previously,
we added animation elements to resultsElements and then removed them
if the animation element did not contribute. After this change, we
only add to resultsElements (no more add-then-remove).

Test: svg/animations/use-animate-transform-and-position.html

* svg/animation/SMILTimeContainer.cpp:
(WebCore::SMILTimeContainer::sortByPriority):
(WebCore::SMILTimeContainer::updateAnimations):

LayoutTests: Remove unnecessary work in SMILTimeContainer::updateAnimations
https://bugs.webkit.org/show_bug.cgi?id=96224

Reviewed by Nikolas Zimmermann.

This change should have no functional differences but a test
is being added to show that. SMILTimeContainer::updateAnimations
contained a comment explaining why a animateTransform needed to be
processed last but that is no longer the case (as the test shows).

* svg/animations/script-tests/use-animate-transform-and-position.js: Added.
(sample1):
(sample2):
(sample3):
(sample4):
(sample5):
(executeTest):
* svg/animations/use-animate-transform-and-position-expected.txt: Added.
* svg/animations/use-animate-transform-and-position.html: Added.

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (128130 => 128131)


--- trunk/LayoutTests/ChangeLog	2012-09-10 23:55:38 UTC (rev 128130)
+++ trunk/LayoutTests/ChangeLog	2012-09-11 00:07:26 UTC (rev 128131)
@@ -1,3 +1,25 @@
+2012-09-10  Philip Rogers  <p...@google.com>
+
+        Remove unnecessary work in SMILTimeContainer::updateAnimations
+        https://bugs.webkit.org/show_bug.cgi?id=96224
+
+        Reviewed by Nikolas Zimmermann.
+
+        This change should have no functional differences but a test
+        is being added to show that. SMILTimeContainer::updateAnimations
+        contained a comment explaining why a animateTransform needed to be
+        processed last but that is no longer the case (as the test shows).
+
+        * svg/animations/script-tests/use-animate-transform-and-position.js: Added.
+        (sample1):
+        (sample2):
+        (sample3):
+        (sample4):
+        (sample5):
+        (executeTest):
+        * svg/animations/use-animate-transform-and-position-expected.txt: Added.
+        * svg/animations/use-animate-transform-and-position.html: Added.
+
 2012-09-10  Jer Noble  <jer.no...@apple.com>
 
         Unreviewed; rolling out r128081.

Added: trunk/LayoutTests/svg/animations/script-tests/use-animate-transform-and-position.js (0 => 128131)


--- trunk/LayoutTests/svg/animations/script-tests/use-animate-transform-and-position.js	                        (rev 0)
+++ trunk/LayoutTests/svg/animations/script-tests/use-animate-transform-and-position.js	2012-09-11 00:07:26 UTC (rev 128131)
@@ -0,0 +1,149 @@
+description("Test animation of use element where the instance is also animated with animate and animateTransform");
+createSVGTestCase();
+
+// Setup test document
+var rect = createSVGElement("rect");
+rect.setAttribute("id", "rect");
+rect.setAttribute("x", "10");
+rect.setAttribute("y", "10");
+rect.setAttribute("width", "100");
+rect.setAttribute("height", "100");
+rect.setAttribute("fill", "green");
+rect.setAttribute("onclick", "executeTest()");
+
+var animate1 = createSVGElement("animate");
+animate1.setAttribute("id", "animate1");
+animate1.setAttribute("attributeName", "x");
+animate1.setAttribute("begin", "1s");
+animate1.setAttribute("dur", "10s");
+animate1.setAttribute("from", "10");
+animate1.setAttribute("to", "110");
+rect.appendChild(animate1);
+rootSVGElement.appendChild(rect);
+
+var use = createSVGElement("use");
+use.setAttribute("id", "use");
+use.setAttributeNS('http://www.w3.org/1999/xlink', 'xlink:href', '#rect');
+use.setAttribute("x", "0");
+use.setAttribute("y", "0");
+rootSVGElement.appendChild(use);
+
+var animateTransform1 = createSVGElement("animateTransform");
+animateTransform1.setAttribute("id", "animateTransform1");
+animateTransform1.setAttribute("attributeName", "transform");
+animateTransform1.setAttribute("type", "translate");
+animateTransform1.setAttribute("begin", "0s");
+animateTransform1.setAttribute("dur", "10s");
+animateTransform1.setAttribute("from", "0 100");
+animateTransform1.setAttribute("to", "0 200");
+use.appendChild(animateTransform1);
+
+var animate2 = createSVGElement("animate");
+animate2.setAttribute("id", "animate2");
+animate2.setAttribute("attributeName", "x");
+animate2.setAttribute("begin", "2s");
+animate2.setAttribute("dur", "10s");
+animate2.setAttribute("from", "0");
+animate2.setAttribute("to", "100");
+use.appendChild(animate2);
+
+var animateTransform2 = createSVGElement("animateTransform");
+animateTransform2.setAttribute("id", "animateTransform2");
+animateTransform2.setAttribute("attributeName", "transform");
+animateTransform2.setAttribute("type", "translate");
+animateTransform2.setAttribute("begin", "3s");
+animateTransform2.setAttribute("dur", "10s");
+animateTransform2.setAttribute("from", "0 130");
+animateTransform2.setAttribute("to", "0 100");
+use.appendChild(animateTransform2);
+
+// Setup animation test
+function sample1() {
+    // Check initial/end conditions
+    shouldBe("rect.x.animVal.value", "10");
+    shouldBe("rect.x.baseVal.value", "10");
+    shouldBe("rect.y.animVal.value", "10");
+    shouldBe("rect.y.baseVal.value", "10");
+    shouldBe("use.x.animVal.value", "0");
+    shouldBe("use.x.baseVal.value", "0");
+    shouldBe("use.y.animVal.value", "0");
+    shouldBe("use.y.baseVal.value", "0");
+    shouldBe("use.transform.baseVal.numberOfItems", "0");
+}
+
+function sample2() {
+    shouldBe("rect.x.animVal.value", "15");
+    shouldBe("rect.x.baseVal.value", "10");
+    shouldBe("rect.y.animVal.value", "10");
+    shouldBe("rect.y.baseVal.value", "10");
+    shouldBe("use.x.animVal.value", "0");
+    shouldBe("use.x.baseVal.value", "0");
+    shouldBe("use.y.animVal.value", "0");
+    shouldBe("use.y.baseVal.value", "0");
+    shouldBe("use.transform.animVal.numberOfItems", "1");
+    shouldBe("use.transform.baseVal.numberOfItems", "0");
+    shouldBe("use.transform.animVal.getItem(0).matrix.e", "0");
+    shouldBe("use.transform.animVal.getItem(0).matrix.f", "115");
+}
+
+function sample3() {
+    shouldBe("rect.x.animVal.value", "25");
+    shouldBe("rect.x.baseVal.value", "10");
+    shouldBe("rect.y.animVal.value", "10");
+    shouldBe("rect.y.baseVal.value", "10");
+    shouldBe("use.x.animVal.value", "5");
+    shouldBe("use.x.baseVal.value", "0");
+    shouldBe("use.y.animVal.value", "0");
+    shouldBe("use.y.baseVal.value", "0");
+    shouldBe("use.transform.animVal.numberOfItems", "1");
+    shouldBe("use.transform.baseVal.numberOfItems", "0");
+    shouldBe("use.transform.animVal.getItem(0).matrix.e", "0");
+    shouldBe("use.transform.animVal.getItem(0).matrix.f", "125");
+}
+
+function sample4() {
+    shouldBe("rect.x.animVal.value", "35");
+    shouldBe("rect.x.baseVal.value", "10");
+    shouldBe("rect.y.animVal.value", "10");
+    shouldBe("rect.y.baseVal.value", "10");
+    shouldBeCloseEnough("use.x.animVal.value", "15");
+    shouldBe("use.x.baseVal.value", "0");
+    shouldBe("use.y.animVal.value", "0");
+    shouldBe("use.y.baseVal.value", "0");
+    shouldBe("use.transform.animVal.numberOfItems", "1");
+    shouldBe("use.transform.baseVal.numberOfItems", "0");
+    shouldBe("use.transform.animVal.getItem(0).matrix.e", "0");
+    shouldBeCloseEnough("use.transform.animVal.getItem(0).matrix.f", "128.5");
+}
+
+function sample5() {
+    shouldBe("rect.x.animVal.value", "45");
+    shouldBe("rect.x.baseVal.value", "10");
+    shouldBe("rect.y.animVal.value", "10");
+    shouldBe("rect.y.baseVal.value", "10");
+    shouldBe("use.x.animVal.value", "25");
+    shouldBe("use.x.baseVal.value", "0");
+    shouldBe("use.y.animVal.value", "0");
+    shouldBe("use.y.baseVal.value", "0");
+    shouldBe("use.transform.animVal.numberOfItems", "1");
+    shouldBe("use.transform.baseVal.numberOfItems", "0");
+    shouldBe("use.transform.animVal.getItem(0).matrix.e", "0");
+    shouldBe("use.transform.animVal.getItem(0).matrix.f", "125.5");
+}
+
+function executeTest() {
+    const expectedValues = [
+        // [animationId, time, sampleCallback]
+        ["animate1", 0.0,   sample1],
+        ["animate1", 0.5,   sample2],
+        ["animate1", 1.5,   sample3],
+        ["animate1", 2.5,   sample4],
+        ["animate1", 3.5,   sample5]
+    ];
+
+    runAnimationTest(expectedValues);
+}
+
+window.clickX = 50;
+window.clickY = 50;
+var successfullyParsed = true;

Added: trunk/LayoutTests/svg/animations/use-animate-transform-and-position-expected.txt (0 => 128131)


--- trunk/LayoutTests/svg/animations/use-animate-transform-and-position-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/svg/animations/use-animate-transform-and-position-expected.txt	2012-09-11 00:07:26 UTC (rev 128131)
@@ -0,0 +1,68 @@
+SVG 1.1 dynamic animation tests
+
+Test animation of use element where the instance is also animated with animate and animateTransform
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS rect.x.animVal.value is 10
+PASS rect.x.baseVal.value is 10
+PASS rect.y.animVal.value is 10
+PASS rect.y.baseVal.value is 10
+PASS use.x.animVal.value is 0
+PASS use.x.baseVal.value is 0
+PASS use.y.animVal.value is 0
+PASS use.y.baseVal.value is 0
+PASS use.transform.baseVal.numberOfItems is 0
+PASS rect.x.animVal.value is 15
+PASS rect.x.baseVal.value is 10
+PASS rect.y.animVal.value is 10
+PASS rect.y.baseVal.value is 10
+PASS use.x.animVal.value is 0
+PASS use.x.baseVal.value is 0
+PASS use.y.animVal.value is 0
+PASS use.y.baseVal.value is 0
+PASS use.transform.animVal.numberOfItems is 1
+PASS use.transform.baseVal.numberOfItems is 0
+PASS use.transform.animVal.getItem(0).matrix.e is 0
+PASS use.transform.animVal.getItem(0).matrix.f is 115
+PASS rect.x.animVal.value is 25
+PASS rect.x.baseVal.value is 10
+PASS rect.y.animVal.value is 10
+PASS rect.y.baseVal.value is 10
+PASS use.x.animVal.value is 5
+PASS use.x.baseVal.value is 0
+PASS use.y.animVal.value is 0
+PASS use.y.baseVal.value is 0
+PASS use.transform.animVal.numberOfItems is 1
+PASS use.transform.baseVal.numberOfItems is 0
+PASS use.transform.animVal.getItem(0).matrix.e is 0
+PASS use.transform.animVal.getItem(0).matrix.f is 125
+PASS rect.x.animVal.value is 35
+PASS rect.x.baseVal.value is 10
+PASS rect.y.animVal.value is 10
+PASS rect.y.baseVal.value is 10
+PASS use.x.animVal.value is 15
+PASS use.x.baseVal.value is 0
+PASS use.y.animVal.value is 0
+PASS use.y.baseVal.value is 0
+PASS use.transform.animVal.numberOfItems is 1
+PASS use.transform.baseVal.numberOfItems is 0
+PASS use.transform.animVal.getItem(0).matrix.e is 0
+PASS use.transform.animVal.getItem(0).matrix.f is 128.5
+PASS rect.x.animVal.value is 45
+PASS rect.x.baseVal.value is 10
+PASS rect.y.animVal.value is 10
+PASS rect.y.baseVal.value is 10
+PASS use.x.animVal.value is 25
+PASS use.x.baseVal.value is 0
+PASS use.y.animVal.value is 0
+PASS use.y.baseVal.value is 0
+PASS use.transform.animVal.numberOfItems is 1
+PASS use.transform.baseVal.numberOfItems is 0
+PASS use.transform.animVal.getItem(0).matrix.e is 0
+PASS use.transform.animVal.getItem(0).matrix.f is 125.5
+PASS successfullyParsed is true
+
+TEST COMPLETE
+

Added: trunk/LayoutTests/svg/animations/use-animate-transform-and-position.html (0 => 128131)


--- trunk/LayoutTests/svg/animations/use-animate-transform-and-position.html	                        (rev 0)
+++ trunk/LayoutTests/svg/animations/use-animate-transform-and-position.html	2012-09-11 00:07:26 UTC (rev 128131)
@@ -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>
\ No newline at end of file

Modified: trunk/Source/WebCore/ChangeLog (128130 => 128131)


--- trunk/Source/WebCore/ChangeLog	2012-09-10 23:55:38 UTC (rev 128130)
+++ trunk/Source/WebCore/ChangeLog	2012-09-11 00:07:26 UTC (rev 128131)
@@ -1,3 +1,37 @@
+2012-09-10  Philip Rogers  <p...@google.com>
+
+        Remove unnecessary codepaths in SMILTimeContainer::updateAnimations
+        https://bugs.webkit.org/show_bug.cgi?id=96224
+
+        Reviewed by Nikolas Zimmermann.
+
+        This change removes two sources of unnecessary code in
+        SMILTimeContainer::updateAnimations:
+            1) After r117711 we now accumulate the result of multiple
+               animations into the first _contributing_ animation
+               element. As a result it is no longer necessary to
+               track both which elements are contributing AND which elements
+               we are storing results into. Both cases are now handled
+               together with resultsElements.
+
+            2) r32044 added a second sort of the animation elements
+               in order to process animateTransform last. This change
+               was added 4 years ago, before we correctly handled <use>
+               and the instance tree, and I think the extra sort is no
+               longer necessary. A test has been added to ensure this
+               is the case.
+
+        This change also does a minor cleanup of resultsElements. Previously,
+        we added animation elements to resultsElements and then removed them
+        if the animation element did not contribute. After this change, we
+        only add to resultsElements (no more add-then-remove).
+
+        Test: svg/animations/use-animate-transform-and-position.html
+
+        * svg/animation/SMILTimeContainer.cpp:
+        (WebCore::SMILTimeContainer::sortByPriority):
+        (WebCore::SMILTimeContainer::updateAnimations):
+
 2012-09-10  Ojan Vafai  <o...@chromium.org>
 
         Rename box-sizing applying methods to be more clear about just applying box-sizing.

Modified: trunk/Source/WebCore/svg/animation/SMILTimeContainer.cpp (128130 => 128131)


--- trunk/Source/WebCore/svg/animation/SMILTimeContainer.cpp	2012-09-10 23:55:38 UTC (rev 128130)
+++ trunk/Source/WebCore/svg/animation/SMILTimeContainer.cpp	2012-09-11 00:07:26 UTC (rev 128131)
@@ -204,18 +204,6 @@
         updateDocumentOrderIndexes();
     std::sort(smilElements.begin(), smilElements.end(), PriorityCompare(elapsed));
 }
-    
-static bool applyOrderSortFunction(SVGSMILElement* a, SVGSMILElement* b)
-{
-    if (!a->hasTagName(SVGNames::animateTransformTag) && b->hasTagName(SVGNames::animateTransformTag))
-        return true;
-    return false;
-}
-    
-static void sortByApplyOrder(Vector<SVGSMILElement*>& smilElements)
-{
-    std::sort(smilElements.begin(), smilElements.end(), applyOrderSortFunction);
-}
 
 void SMILTimeContainer::updateAnimations(SMILTime elapsed, bool seekToTime)
 {
@@ -229,12 +217,11 @@
     // FIXME: This should also consider timing relationships between the elements. Dependents
     // have higher priority.
     sortByPriority(toAnimate, elapsed);
-    
+
     // Calculate animation contributions.
     typedef pair<SVGElement*, QualifiedName> ElementAttributePair;
-    typedef HashMap<ElementAttributePair, RefPtr<SVGSMILElement> > ResultElementMap;
+    typedef HashMap<ElementAttributePair, SVGSMILElement*> ResultElementMap;
     ResultElementMap resultsElements;
-    HashSet<SVGSMILElement*> contributingElements;
     for (unsigned n = 0; n < toAnimate.size(); ++n) {
         SVGSMILElement* animation = toAnimate[n];
         ASSERT(animation->timeContainer() == this);
@@ -242,7 +229,7 @@
         SVGElement* targetElement = animation->targetElement();
         if (!targetElement)
             continue;
-        
+
         QualifiedName attributeName = animation->attributeName();
         if (attributeName == anyQName()) {
             if (animation->hasTagName(SVGNames::animateMotionTag))
@@ -250,51 +237,36 @@
             else
                 continue;
         }
-        
+
         // Results are accumulated to the first animation that animates and contributes to a particular element/attribute pair.
         ElementAttributePair key(targetElement, attributeName); 
-        SVGSMILElement* resultElement = resultsElements.get(key).get();
-        bool accumulatedResultElement = false;
+        SVGSMILElement* resultElement = resultsElements.get(key);
         if (!resultElement) {
             if (!animation->hasValidAttributeType())
                 continue;
             resultElement = animation;
-            resultsElements.add(key, resultElement);
-            accumulatedResultElement = true;
-        }
+        } else
+            ASSERT(resultElement != animation);
 
         // This will calculate the contribution from the animation and add it to the resultsElement.
-        if (animation->progress(elapsed, resultElement, seekToTime))
-            contributingElements.add(resultElement);
-        else if (accumulatedResultElement)
-            resultsElements.remove(key);
+        if (animation->progress(elapsed, resultElement, seekToTime) && resultElement == animation)
+            resultsElements.add(key, resultElement);
 
         SMILTime nextFireTime = animation->nextProgressTime();
         if (nextFireTime.isFinite())
             earliersFireTime = min(nextFireTime, earliersFireTime);
     }
-    
-    Vector<SVGSMILElement*> animationsToApply;
-    ResultElementMap::iterator end = resultsElements.end();
-    for (ResultElementMap::iterator it = resultsElements.begin(); it != end; ++it) {
-        SVGSMILElement* animation = it->second.get();
-        if (contributingElements.contains(animation))
-            animationsToApply.append(animation);
-    }
 
-    unsigned animationsToApplySize = animationsToApply.size();
-    if (!animationsToApplySize) {
+    unsigned resultsToApplySize = resultsElements.size();
+    if (!resultsToApplySize) {
         startTimer(earliersFireTime, animationFrameDelay);
         return;
     }
 
-    // Sort <animateTranform> to be the last one to be applied. <animate> may change transform attribute as
-    // well (directly or indirectly by modifying <use> x/y) and this way transforms combine properly.
-    sortByApplyOrder(animationsToApply);
-
     // Apply results to target elements.
-    for (unsigned i = 0; i < animationsToApplySize; ++i)
-        animationsToApply[i]->applyResultsToTarget();
+    ResultElementMap::iterator end = resultsElements.end();
+    for (ResultElementMap::iterator it = resultsElements.begin(); it != end; ++it)
+        it->second->applyResultsToTarget();
 
     startTimer(earliersFireTime, animationFrameDelay);
     Document::updateStyleForAllDocuments();
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
http://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to