SVG Animations update baseVal instead of animVal
authorzimmermann@webkit.org <zimmermann@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 27 Apr 2012 13:50:44 +0000 (13:50 +0000)
committerzimmermann@webkit.org <zimmermann@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 27 Apr 2012 13:50:44 +0000 (13:50 +0000)
https://bugs.webkit.org/show_bug.cgi?id=12437

Reviewed by Dirk Schulze.

Source/WebCore:

Cleanup animation code, remove last remaining crufts of the old setAttribute() animation model.
Now only two animation modes remain: animate SVG DOM animVal properties or CSS properties.

Stop caching base values per string in SMILTimeContainer, as it breaks additive="sum" for CSS
properties if the underlying base value is changed from the outside (eg. when calling
style.fontSize="20px", if font-size was 10px, and we're running an additive by-animation with 50px).

This requires us to cache the computed style of a SVGElement, without SMIL style property changes,
in SVGElementRareData, similar to how the computed style itself is cached in ElementRareData.
To be able to compute the base value for a CSS property at any time, we have to exclude any
previous animation effects residing in the SMIL animated style properties, per SMIL2/3 specs.

NOTE: This doesn't change or affect the way CSS Animations/Transitions are applied, we still
      have some bugs in that area, but this patch doesn't address them. The idea is to only
      remove the cache, to pave the way for future additive="sum" patches.

Tests: svg/animations/change-css-property-while-animating-fill-freeze.html
       svg/animations/change-css-property-while-animating-fill-remove.html

* dom/Element.cpp:
(WebCore::Element::recalcStyle):
* dom/Node.h:
* svg/SVGAnimateElement.cpp:
(WebCore::propertyTypesAreConsistent):
(WebCore::SVGAnimateElement::resetToBaseValue):
(WebCore::SVGAnimateElement::applyResultsToTarget):
* svg/SVGAnimateElement.h:
(SVGAnimateElement):
* svg/SVGAnimateMotionElement.cpp:
(WebCore::SVGAnimateMotionElement::resetToBaseValue):
* svg/SVGAnimateMotionElement.h:
(SVGAnimateMotionElement):
* svg/SVGAnimationElement.cpp:
(WebCore::applyCSSPropertyToTarget):
(WebCore::SVGAnimationElement::setTargetAttributeAnimatedCSSValue):
* svg/SVGAnimationElement.h:
* svg/SVGElement.cpp:
(WebCore::SVGElement::SVGElement):
(WebCore::SVGElement::willRecalcStyle):
(WebCore):
(WebCore::SVGElement::rareSVGData):
(WebCore::SVGElement::ensureRareSVGData):
(WebCore::SVGElement::computedStyle):
(WebCore::SVGElement::isAnimatableAttribute):
* svg/SVGElement.h:
(SVGElement):
* svg/SVGElementRareData.h:
(WebCore::SVGElementRareData::SVGElementRareData):
(WebCore::SVGElementRareData::ensureAnimatedSMILStyleProperties):
(WebCore::SVGElementRareData::destroyAnimatedSMILStyleProperties):
(WebCore::SVGElementRareData::overrideComputedStyle):
(WebCore::SVGElementRareData::setUseOverrideComputedStyle):
* svg/animation/SMILTimeContainer.cpp:
(WebCore::SMILTimeContainer::updateAnimations):
* svg/animation/SMILTimeContainer.h:
(SMILTimeContainer):
* svg/animation/SVGSMILElement.h:
(SVGSMILElement):

LayoutTests:

Add tests that change the CSS property while an animation is running, finally fixed now for both SVG DOM & CSS animations.

* svg/animations/change-css-property-while-animating-fill-freeze-expected.txt: Added.
* svg/animations/change-css-property-while-animating-fill-freeze.html: Added.
* svg/animations/change-css-property-while-animating-fill-remove-expected.txt: Added.
* svg/animations/change-css-property-while-animating-fill-remove.html: Added.
* svg/animations/resources/change-css-property-while-animating-fill-freeze.svg: Added.
* svg/animations/resources/change-css-property-while-animating-fill-remove.svg: Added.
* svg/animations/script-tests/change-css-property-while-animating-fill-freeze.js: Added.
(sample1):
(sample2):
(sample3):
(sample4):
(sample5):
(executeTest):
* svg/animations/script-tests/change-css-property-while-animating-fill-remove.js: Added.
(sample1):
(sample2):
(sample3):
(sample4):
(sample5):
(executeTest):

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

24 files changed:
LayoutTests/ChangeLog
LayoutTests/svg/animations/change-css-property-while-animating-fill-freeze-expected.txt [new file with mode: 0644]
LayoutTests/svg/animations/change-css-property-while-animating-fill-freeze.html [new file with mode: 0644]
LayoutTests/svg/animations/change-css-property-while-animating-fill-remove-expected.txt [new file with mode: 0644]
LayoutTests/svg/animations/change-css-property-while-animating-fill-remove.html [new file with mode: 0644]
LayoutTests/svg/animations/resources/change-css-property-while-animating-fill-freeze.svg [new file with mode: 0644]
LayoutTests/svg/animations/resources/change-css-property-while-animating-fill-remove.svg [new file with mode: 0644]
LayoutTests/svg/animations/script-tests/change-css-property-while-animating-fill-freeze.js [new file with mode: 0644]
LayoutTests/svg/animations/script-tests/change-css-property-while-animating-fill-remove.js [new file with mode: 0644]
Source/WebCore/ChangeLog
Source/WebCore/css/StyleResolver.cpp
Source/WebCore/css/StyleResolver.h
Source/WebCore/svg/SVGAnimateElement.cpp
Source/WebCore/svg/SVGAnimateElement.h
Source/WebCore/svg/SVGAnimateMotionElement.cpp
Source/WebCore/svg/SVGAnimateMotionElement.h
Source/WebCore/svg/SVGAnimationElement.cpp
Source/WebCore/svg/SVGAnimationElement.h
Source/WebCore/svg/SVGElement.cpp
Source/WebCore/svg/SVGElement.h
Source/WebCore/svg/SVGElementRareData.h
Source/WebCore/svg/animation/SMILTimeContainer.cpp
Source/WebCore/svg/animation/SMILTimeContainer.h
Source/WebCore/svg/animation/SVGSMILElement.h

index 6f5c917..f5bc295 100644 (file)
@@ -1,3 +1,33 @@
+2012-04-27  Nikolas Zimmermann  <nzimmermann@rim.com>
+
+        SVG Animations update baseVal instead of animVal
+        https://bugs.webkit.org/show_bug.cgi?id=12437
+
+        Reviewed by Dirk Schulze.
+
+        Add tests that change the CSS property while an animation is running, finally fixed now for both SVG DOM & CSS animations.
+
+        * svg/animations/change-css-property-while-animating-fill-freeze-expected.txt: Added.
+        * svg/animations/change-css-property-while-animating-fill-freeze.html: Added.
+        * svg/animations/change-css-property-while-animating-fill-remove-expected.txt: Added.
+        * svg/animations/change-css-property-while-animating-fill-remove.html: Added.
+        * svg/animations/resources/change-css-property-while-animating-fill-freeze.svg: Added.
+        * svg/animations/resources/change-css-property-while-animating-fill-remove.svg: Added.
+        * svg/animations/script-tests/change-css-property-while-animating-fill-freeze.js: Added.
+        (sample1):
+        (sample2):
+        (sample3):
+        (sample4):
+        (sample5):
+        (executeTest):
+        * svg/animations/script-tests/change-css-property-while-animating-fill-remove.js: Added.
+        (sample1):
+        (sample2):
+        (sample3):
+        (sample4):
+        (sample5):
+        (executeTest):
+
 2012-04-27  Philippe Normand  <pnormand@igalia.com>
 
         Unreviewed, GTK test_expectations update.
diff --git a/LayoutTests/svg/animations/change-css-property-while-animating-fill-freeze-expected.txt b/LayoutTests/svg/animations/change-css-property-while-animating-fill-freeze-expected.txt
new file mode 100644 (file)
index 0000000..331b657
--- /dev/null
@@ -0,0 +1,18 @@
+SVG 1.1 dynamic animation tests
+
+
+This tests scripting a CSS property while animation is running
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS getComputedStyle(rect).getPropertyCSSValue('opacity').getFloatValue(CSSPrimitiveValue.CSS_NUMBER) is 0
+PASS getComputedStyle(rect).getPropertyCSSValue('opacity').getFloatValue(CSSPrimitiveValue.CSS_NUMBER) is 0.25
+PASS getComputedStyle(rect).getPropertyCSSValue('opacity').getFloatValue(CSSPrimitiveValue.CSS_NUMBER) is 0.25
+PASS getComputedStyle(rect).getPropertyCSSValue('opacity').getFloatValue(CSSPrimitiveValue.CSS_NUMBER) is 0.5
+PASS getComputedStyle(rect).getPropertyCSSValue('opacity').getFloatValue(CSSPrimitiveValue.CSS_NUMBER) is 0.5
+PASS getComputedStyle(rect).getPropertyCSSValue('opacity').getFloatValue(CSSPrimitiveValue.CSS_NUMBER) is 0.5
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/svg/animations/change-css-property-while-animating-fill-freeze.html b/LayoutTests/svg/animations/change-css-property-while-animating-fill-freeze.html
new file mode 100644 (file)
index 0000000..bbddfed
--- /dev/null
@@ -0,0 +1,14 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<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/change-css-property-while-animating-fill-freeze.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/svg/animations/change-css-property-while-animating-fill-remove-expected.txt b/LayoutTests/svg/animations/change-css-property-while-animating-fill-remove-expected.txt
new file mode 100644 (file)
index 0000000..65f33cd
--- /dev/null
@@ -0,0 +1,18 @@
+SVG 1.1 dynamic animation tests
+
+
+This tests scripting a CSS property while animation is running
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS getComputedStyle(rect).getPropertyCSSValue('opacity').getFloatValue(CSSPrimitiveValue.CSS_NUMBER) is 0
+PASS getComputedStyle(rect).getPropertyCSSValue('opacity').getFloatValue(CSSPrimitiveValue.CSS_NUMBER) is 0.25
+PASS getComputedStyle(rect).getPropertyCSSValue('opacity').getFloatValue(CSSPrimitiveValue.CSS_NUMBER) is 0.25
+PASS getComputedStyle(rect).getPropertyCSSValue('opacity').getFloatValue(CSSPrimitiveValue.CSS_NUMBER) is 0.5
+PASS getComputedStyle(rect).getPropertyCSSValue('opacity').getFloatValue(CSSPrimitiveValue.CSS_NUMBER) is 1
+PASS getComputedStyle(rect).getPropertyCSSValue('opacity').getFloatValue(CSSPrimitiveValue.CSS_NUMBER) is 1
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/svg/animations/change-css-property-while-animating-fill-remove.html b/LayoutTests/svg/animations/change-css-property-while-animating-fill-remove.html
new file mode 100644 (file)
index 0000000..15d6b21
--- /dev/null
@@ -0,0 +1,14 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<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/change-css-property-while-animating-fill-remove.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/svg/animations/resources/change-css-property-while-animating-fill-freeze.svg b/LayoutTests/svg/animations/resources/change-css-property-while-animating-fill-freeze.svg
new file mode 100644 (file)
index 0000000..364b1c3
--- /dev/null
@@ -0,0 +1,10 @@
+<?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" xmlns:xlink="http://www.w3.org/1999/xlink">
+
+<!-- an1: Change opacity from 0 to 0.5 in 4s, a script at 2s will set the opacity CSS property to 1, fill is freeze so this won't have any visible effect, nor any effect to the computed style -->
+<rect opacity="0" width="100" height="100" fill="green">
+    <animate id="an1" attributeType="CSS" attributeName="opacity" fill="freeze" from="0" to="0.5" begin="0s" dur="4s"/>
+</rect>
+
+</svg>
diff --git a/LayoutTests/svg/animations/resources/change-css-property-while-animating-fill-remove.svg b/LayoutTests/svg/animations/resources/change-css-property-while-animating-fill-remove.svg
new file mode 100644 (file)
index 0000000..078f71a
--- /dev/null
@@ -0,0 +1,10 @@
+<?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" xmlns:xlink="http://www.w3.org/1999/xlink">
+
+<!-- an1: Change opacity from 0 to 0.5 in 4s, a script at 2s will set the opacity CSS property to 1, fill is not freeze, so after the animation ends the opacity should be 1, not 0 -->
+<rect opacity="0" width="100" height="100" fill="green">
+    <animate id="an1" attributeType="CSS" attributeName="opacity" fill="remove" from="0" to="0.5" begin="0s" dur="4s"/>
+</rect>
+
+</svg>
diff --git a/LayoutTests/svg/animations/script-tests/change-css-property-while-animating-fill-freeze.js b/LayoutTests/svg/animations/script-tests/change-css-property-while-animating-fill-freeze.js
new file mode 100644 (file)
index 0000000..1ece051
--- /dev/null
@@ -0,0 +1,43 @@
+description("This tests scripting a CSS property while animation is running");
+embedSVGTestCase("resources/change-css-property-while-animating-fill-freeze.svg");
+
+// Setup animation test
+function sample1() {
+    shouldBeCloseEnough("getComputedStyle(rect).getPropertyCSSValue('opacity').getFloatValue(CSSPrimitiveValue.CSS_NUMBER)", "0");
+}
+
+function sample2() {
+    shouldBeCloseEnough("getComputedStyle(rect).getPropertyCSSValue('opacity').getFloatValue(CSSPrimitiveValue.CSS_NUMBER)", "0.25");
+    rect.setAttribute("opacity", "1");
+}
+
+function sample3() {
+    shouldBeCloseEnough("getComputedStyle(rect).getPropertyCSSValue('opacity').getFloatValue(CSSPrimitiveValue.CSS_NUMBER)", "0.25");
+}
+
+function sample4() {
+    shouldBeCloseEnough("getComputedStyle(rect).getPropertyCSSValue('opacity').getFloatValue(CSSPrimitiveValue.CSS_NUMBER)", "0.5");
+}
+
+function sample5() {
+    shouldBeCloseEnough("getComputedStyle(rect).getPropertyCSSValue('opacity').getFloatValue(CSSPrimitiveValue.CSS_NUMBER)", "0.5");
+}
+
+function executeTest() {
+    rect = rootSVGElement.ownerDocument.getElementsByTagName("rect")[0];
+
+    const expectedValues = [
+        // [animationId, time, sampleCallback]
+        ["an1", 0.0,   sample1],
+        ["an1", 2.0,   sample2],
+        ["an1", 2.001, sample3],
+        ["an1", 3.999, sample4],
+        ["an1", 4.001, sample5],
+        ["an1", 60.0,  sample5]
+    ];
+
+    runAnimationTest(expectedValues);
+}
+
+window.animationStartsImmediately = true;
+var successfullyParsed = true;
diff --git a/LayoutTests/svg/animations/script-tests/change-css-property-while-animating-fill-remove.js b/LayoutTests/svg/animations/script-tests/change-css-property-while-animating-fill-remove.js
new file mode 100644 (file)
index 0000000..6b6a2e3
--- /dev/null
@@ -0,0 +1,43 @@
+description("This tests scripting a CSS property while animation is running");
+embedSVGTestCase("resources/change-css-property-while-animating-fill-remove.svg");
+
+// Setup animation test
+function sample1() {
+    shouldBeCloseEnough("getComputedStyle(rect).getPropertyCSSValue('opacity').getFloatValue(CSSPrimitiveValue.CSS_NUMBER)", "0");
+}
+
+function sample2() {
+    shouldBeCloseEnough("getComputedStyle(rect).getPropertyCSSValue('opacity').getFloatValue(CSSPrimitiveValue.CSS_NUMBER)", "0.25");
+    rect.setAttribute("opacity", "1");
+}
+
+function sample3() {
+    shouldBeCloseEnough("getComputedStyle(rect).getPropertyCSSValue('opacity').getFloatValue(CSSPrimitiveValue.CSS_NUMBER)", "0.25");
+}
+
+function sample4() {
+    shouldBeCloseEnough("getComputedStyle(rect).getPropertyCSSValue('opacity').getFloatValue(CSSPrimitiveValue.CSS_NUMBER)", "0.5");
+}
+
+function sample5() {
+    shouldBeCloseEnough("getComputedStyle(rect).getPropertyCSSValue('opacity').getFloatValue(CSSPrimitiveValue.CSS_NUMBER)", "1");
+}
+
+function executeTest() {
+    rect = rootSVGElement.ownerDocument.getElementsByTagName("rect")[0];
+
+    const expectedValues = [
+        // [animationId, time, sampleCallback]
+        ["an1", 0.0,   sample1],
+        ["an1", 2.0,   sample2],
+        ["an1", 2.001, sample3],
+        ["an1", 3.999, sample4],
+        ["an1", 4.001, sample5],
+        ["an1", 60.0,  sample5]
+    ];
+
+    runAnimationTest(expectedValues);
+}
+
+window.animationStartsImmediately = true;
+var successfullyParsed = true;
index 5f4e857..da78d6a 100644 (file)
@@ -1,3 +1,69 @@
+2012-04-27  Nikolas Zimmermann  <nzimmermann@rim.com>
+
+        SVG Animations update baseVal instead of animVal
+        https://bugs.webkit.org/show_bug.cgi?id=12437
+
+        Reviewed by Dirk Schulze.
+
+        Cleanup animation code, remove last remaining crufts of the old setAttribute() animation model.
+        Now only two animation modes remain: animate SVG DOM animVal properties or CSS properties.
+
+        Stop caching base values per string in SMILTimeContainer, as it breaks additive="sum" for CSS
+        properties if the underlying base value is changed from the outside (eg. when calling
+        style.fontSize="20px", if font-size was 10px, and we're running an additive by-animation with 50px).
+
+        This requires us to cache the computed style of a SVGElement, without SMIL style property changes,
+        in SVGElementRareData, similar to how the computed style itself is cached in ElementRareData.
+        To be able to compute the base value for a CSS property at any time, we have to exclude any
+        previous animation effects residing in the SMIL animated style properties, per SMIL2/3 specs.
+
+        NOTE: This doesn't change or affect the way CSS Animations/Transitions are applied, we still
+              have some bugs in that area, but this patch doesn't address them. The idea is to only
+              remove the cache, to pave the way for future additive="sum" patches.
+
+        Tests: svg/animations/change-css-property-while-animating-fill-freeze.html
+               svg/animations/change-css-property-while-animating-fill-remove.html
+
+        * dom/Element.cpp:
+        (WebCore::Element::recalcStyle):
+        * dom/Node.h:
+        * svg/SVGAnimateElement.cpp:
+        (WebCore::propertyTypesAreConsistent):
+        (WebCore::SVGAnimateElement::resetToBaseValue):
+        (WebCore::SVGAnimateElement::applyResultsToTarget):
+        * svg/SVGAnimateElement.h:
+        (SVGAnimateElement):
+        * svg/SVGAnimateMotionElement.cpp:
+        (WebCore::SVGAnimateMotionElement::resetToBaseValue):
+        * svg/SVGAnimateMotionElement.h:
+        (SVGAnimateMotionElement):
+        * svg/SVGAnimationElement.cpp:
+        (WebCore::applyCSSPropertyToTarget):
+        (WebCore::SVGAnimationElement::setTargetAttributeAnimatedCSSValue):
+        * svg/SVGAnimationElement.h:
+        * svg/SVGElement.cpp:
+        (WebCore::SVGElement::SVGElement):
+        (WebCore::SVGElement::willRecalcStyle):
+        (WebCore):
+        (WebCore::SVGElement::rareSVGData):
+        (WebCore::SVGElement::ensureRareSVGData):
+        (WebCore::SVGElement::computedStyle):
+        (WebCore::SVGElement::isAnimatableAttribute):
+        * svg/SVGElement.h:
+        (SVGElement):
+        * svg/SVGElementRareData.h:
+        (WebCore::SVGElementRareData::SVGElementRareData):
+        (WebCore::SVGElementRareData::ensureAnimatedSMILStyleProperties):
+        (WebCore::SVGElementRareData::destroyAnimatedSMILStyleProperties):
+        (WebCore::SVGElementRareData::overrideComputedStyle):
+        (WebCore::SVGElementRareData::setUseOverrideComputedStyle):
+        * svg/animation/SMILTimeContainer.cpp:
+        (WebCore::SMILTimeContainer::updateAnimations):
+        * svg/animation/SMILTimeContainer.h:
+        (SMILTimeContainer):
+        * svg/animation/SVGSMILElement.h:
+        (SVGSMILElement):
+
 2012-04-26  Alexander Pavlov  <apavlov@chromium.org>
 
         Web Inspector: Implement the "Disable JavaScript" option in the settings dialog
index f9db4c7..86e0e5c 100644 (file)
@@ -1075,7 +1075,7 @@ void StyleResolver::sortMatchedRules()
     std::sort(m_matchedRules.begin(), m_matchedRules.end(), compareRules);
 }
 
-void StyleResolver::matchAllRules(MatchResult& result)
+void StyleResolver::matchAllRules(MatchResult& result, bool includeSMILProperties)
 {
     matchUARules(result);
 
@@ -1115,7 +1115,7 @@ void StyleResolver::matchAllRules(MatchResult& result)
 
 #if ENABLE(SVG)
     // Now check SMIL animation override style.
-    if (m_matchAuthorAndUserStyles && m_styledElement && m_styledElement->isSVGElement())
+    if (includeSMILProperties && m_matchAuthorAndUserStyles && m_styledElement && m_styledElement->isSVGElement())
         addElementStyleProperties(result, static_cast<SVGElement*>(m_styledElement)->animatedSMILStyleProperties(), false /* isCacheable */);
 #endif
 }
@@ -1623,7 +1623,7 @@ PassRefPtr<RenderStyle> StyleResolver::styleForElement(Element* element, RenderS
     if (matchingBehavior == MatchOnlyUserAgentRules)
         matchUARules(matchResult);
     else
-        matchAllRules(matchResult);
+        matchAllRules(matchResult, matchingBehavior != MatchAllRulesExcludingSMIL);
 
     applyMatchedProperties(matchResult);
 
index 2927169..3916a73 100644 (file)
@@ -114,6 +114,7 @@ enum StyleSharingBehavior {
 
 enum RuleMatchingBehavior {
     MatchAllRules,
+    MatchAllRulesExcludingSMIL,
     MatchOnlyUserAgentRules,
 };
 
@@ -336,7 +337,7 @@ private:
     static void addMatchedProperties(MatchResult&, StylePropertySet* properties, StyleRule* = 0, unsigned linkMatchType = SelectorChecker::MatchAll, bool inRegionRule = false);
     void addElementStyleProperties(MatchResult&, StylePropertySet*, bool isCacheable = true);
 
-    void matchAllRules(MatchResult&);
+    void matchAllRules(MatchResult&, bool includeSMILProperties);
     void matchUARules(MatchResult&);
     void matchUARules(MatchResult&, RuleSet*);
     void matchAuthorRules(MatchResult&, bool includeEmptyRules);
index 14f2f30..7993fa5 100644 (file)
@@ -25,7 +25,6 @@
 #if ENABLE(SVG)
 #include "SVGAnimateElement.h"
 
-#include "CSSComputedStyleDeclaration.h"
 #include "CSSParser.h"
 #include "CSSPropertyNames.h"
 #include "QualifiedName.h"
@@ -141,7 +140,7 @@ bool SVGAnimateElement::calculateFromAndToValues(const String& fromString, const
     if (!targetElement)
         return false;
 
-    determinePropertyValueTypes(fromString, toString); 
+    determinePropertyValueTypes(fromString, toString);
     ensureAnimator()->calculateFromAndToValues(m_fromType, m_toType, fromString, toString);
     ASSERT(m_animatedPropertyType == m_animator->type());
     return true;
@@ -158,7 +157,7 @@ bool SVGAnimateElement::calculateFromAndByValues(const String& fromString, const
 
     ASSERT(!hasTagName(SVGNames::setTag));
 
-    determinePropertyValueTypes(fromString, byString); 
+    determinePropertyValueTypes(fromString, byString);
     ensureAnimator()->calculateFromAndByValues(m_fromType, m_toType, fromString, byString);
     ASSERT(m_animatedPropertyType == m_animator->type());
     return true;
@@ -179,36 +178,40 @@ static inline bool propertyTypesAreConsistent(AnimatedPropertyType expectedPrope
 }
 #endif
 
-void SVGAnimateElement::resetToBaseValue(const String& baseString)
+void SVGAnimateElement::resetToBaseValue()
 {
-    // If animatedProperty is not null, we're dealing with a SVG DOM primitive animation.
-    // In that case we don't need any base value strings, but can directly operate on these
-    // SVG DOM primitives, like SVGLength.
     SVGAnimatedTypeAnimator* animator = ensureAnimator();
     ASSERT(m_animatedPropertyType == animator->type());
 
     SVGElement* targetElement = this->targetElement();
     const QualifiedName& attributeName = this->attributeName();
     ShouldApplyAnimation shouldApply = shouldApplyAnimation(targetElement, attributeName);
-    if (shouldApply == ApplyXMLAnimation)
+    if (shouldApply == ApplyXMLAnimation) {
+        // SVG DOM animVal animation code-path.
         m_animatedProperties = animator->findAnimatedPropertiesForAttributeName(targetElement, attributeName);
-    else
-        ASSERT(m_animatedProperties.isEmpty());
+        ASSERT(!m_animatedProperties.isEmpty());
 
-    if (m_animatedProperties.isEmpty()) {
-        // Legacy fallback code path, uses the passed-in baseString, which is cached.
+        ASSERT(propertyTypesAreConsistent(m_animatedPropertyType, m_animatedProperties));
         if (!m_animatedType)
-            m_animatedType = animator->constructFromString(baseString);
+            m_animatedType = animator->startAnimValAnimation(m_animatedProperties);
         else
-            m_animatedType->setValueAsString(attributeName, baseString);
+            animator->resetAnimValToBaseVal(m_animatedProperties, m_animatedType.get());
         return;
     }
 
-    ASSERT(propertyTypesAreConsistent(m_animatedPropertyType, m_animatedProperties));
+    // CSS properties animation code-path.
+    ASSERT(m_animatedProperties.isEmpty());
+    String baseValue;
+
+    if (shouldApply == ApplyCSSAnimation) {
+        ASSERT(SVGAnimationElement::isTargetAttributeCSSProperty(targetElement, attributeName));
+        computeCSSPropertyValue(targetElement, cssPropertyID(attributeName.localName()), baseValue, false);
+    }
+
     if (!m_animatedType)
-        m_animatedType = animator->startAnimValAnimation(m_animatedProperties);
+        m_animatedType = animator->constructFromString(baseValue);
     else
-        animator->resetAnimValToBaseVal(m_animatedProperties, m_animatedType.get());
+        m_animatedType->setValueAsString(attributeName, baseValue);
 }
 
 void SVGAnimateElement::applyResultsToTarget()
@@ -219,8 +222,8 @@ void SVGAnimateElement::applyResultsToTarget()
     ASSERT(m_animator);
 
     if (m_animatedProperties.isEmpty()) {
-        // CSS / legacy XML change code-path.
-        setTargetAttributeAnimatedValue(m_animatedType.get());
+        // CSS properties animation code-path.
+        setTargetAttributeAnimatedCSSValue(m_animatedType.get());
         return;
     }
 
index 4776482..b911b87 100644 (file)
@@ -43,7 +43,7 @@ public:
 protected:
     SVGAnimateElement(const QualifiedName&, Document*);
 
-    virtual void resetToBaseValue(const String&);
+    virtual void resetToBaseValue();
     virtual bool calculateFromAndToValues(const String& fromString, const String& toString);
     virtual bool calculateFromAndByValues(const String& fromString, const String& byString);
     virtual void calculateAnimatedValue(float percentage, unsigned repeat, SVGSMILElement* resultElement);
@@ -55,7 +55,7 @@ protected:
 
 private:
     SVGAnimatedTypeAnimator* ensureAnimator();
-    
+
     virtual bool hasValidAttributeType();
     AnimatedPropertyType m_animatedPropertyType;
 
index e729bad..4d9e971 100644 (file)
@@ -166,7 +166,7 @@ static bool parsePoint(const String& s, FloatPoint& point)
     return !skipOptionalSVGSpaces(cur, end);
 }
     
-void SVGAnimateMotionElement::resetToBaseValue(const String&)
+void SVGAnimateMotionElement::resetToBaseValue()
 {
     if (!hasValidAttributeType())
         return;
index 89ced76..91c0855 100644 (file)
@@ -39,7 +39,7 @@ private:
     bool isSupportedAttribute(const QualifiedName&);
     virtual void parseAttribute(Attribute*) OVERRIDE;
 
-    virtual void resetToBaseValue(const String&);
+    virtual void resetToBaseValue();
     virtual bool calculateFromAndToValues(const String& fromString, const String& toString);
     virtual bool calculateFromAndByValues(const String& fromString, const String& byString);
     virtual void calculateAnimatedValue(float percentage, unsigned repeat, SVGSMILElement* resultElement);
index d8671f1..cd6915f 100644 (file)
@@ -341,53 +341,33 @@ bool SVGAnimationElement::isTargetAttributeCSSProperty(SVGElement* targetElement
     return SVGStyledElement::isAnimatableCSSProperty(attributeName);
 }
 
-static inline void setTargetAttributeAnimatedCSSValue(SVGElement* targetElement, const QualifiedName& attributeName, const String& value)
+static inline void applyCSSPropertyToTarget(SVGElement* targetElement, CSSPropertyID id, const String& value)
 {
     StylePropertySet* propertySet = targetElement->ensureAnimatedSMILStyleProperties();
-    if (propertySet->setProperty(cssPropertyID(attributeName.localName()), value, false, 0))
-        targetElement->setNeedsStyleRecalc();
+    if (propertySet->setProperty(id, value, false, 0))
+        targetElement->setNeedsStyleRecalc(SyntheticStyleChange);
 }
 
-void SVGAnimationElement::applyAnimatedValue(SVGAnimationElement::ShouldApplyAnimation shouldApply, SVGElement* targetElement, const QualifiedName& attributeName, SVGAnimatedType* animatedType)
+void SVGAnimationElement::setTargetAttributeAnimatedCSSValue(SVGAnimatedType* animatedType)
 {
     ASSERT(animatedType);
-
-    switch (shouldApply) {
-    case DontApplyAnimation:
-        ASSERT_NOT_REACHED();
-        break;
-    case ApplyCSSAnimation:
-        setTargetAttributeAnimatedCSSValue(targetElement, attributeName, animatedType->valueAsString());
-        break;
-    case ApplyXMLAnimation:
-        // FIXME: Deprecated legacy code path which mutates the DOM.
-        targetElement->setAttribute(attributeName, animatedType->valueAsString());
-        break;
-    }
-}
-
-void SVGAnimationElement::setTargetAttributeAnimatedValue(SVGAnimatedType* animatedType)
-{
-    ASSERT(animatedType);
-
     SVGElement* targetElement = this->targetElement();
+    ASSERT(targetElement);
+
     const QualifiedName& attributeName = this->attributeName();
-    ShouldApplyAnimation shouldApply = shouldApplyAnimation(targetElement, attributeName);
-    if (shouldApply == DontApplyAnimation)
-        return;
+    ASSERT(attributeName != anyQName());
+    CSSPropertyID id = cssPropertyID(attributeName.localName());
 
-    // Scope this block, so instances updates will be unblocked, before we try to update the instances.
-    {
-        SVGElementInstance::InstanceUpdateBlocker blocker(targetElement);
-        applyAnimatedValue(shouldApply, targetElement, attributeName, animatedType);
-    }
+    const String& valueAsString = animatedType->valueAsString();
+    SVGElementInstance::InstanceUpdateBlocker blocker(targetElement);
+    applyCSSPropertyToTarget(targetElement, id, valueAsString);
 
     // If the target element has instances, update them as well, w/o requiring the <use> tree to be rebuilt.
     const HashSet<SVGElementInstance*>& instances = targetElement->instancesForElement();
     const HashSet<SVGElementInstance*>::const_iterator end = instances.end();
     for (HashSet<SVGElementInstance*>::const_iterator it = instances.begin(); it != end; ++it) {
         if (SVGElement* shadowTreeElement = (*it)->shadowTreeElement())
-            applyAnimatedValue(shouldApply, shadowTreeElement, attributeName, animatedType);
+            applyCSSPropertyToTarget(shadowTreeElement, id, valueAsString);
     }
 }
 
@@ -654,6 +634,22 @@ void SVGAnimationElement::updateAnimation(float percent, unsigned repeat, SVGSMI
     calculateAnimatedValue(effectivePercent, repeat, resultElement);
 }
 
+void SVGAnimationElement::computeCSSPropertyValue(SVGElement* element, CSSPropertyID id, String& value, bool includeSMILProperties)
+{
+    ASSERT(element);
+    ASSERT(element->isStyled());
+
+    // If includeSMILProperties=false, don't include any properties resulting from SMIL animations, as we want to retrieve the "base value".
+    if (!includeSMILProperties) {
+        ASSERT(element == targetElement());
+        element->setUseOverrideComputedStyle(true);
+    }
+
+    value = CSSComputedStyleDeclaration::create(element)->getPropertyValue(id);
+    if (!includeSMILProperties)
+        element->setUseOverrideComputedStyle(false);
+}
+
 void SVGAnimationElement::adjustForInheritance(SVGElement* targetElement, const QualifiedName& attributeName, String& value)
 {
     // FIXME: At the moment the computed style gets returned as a String and needs to get parsed again.
@@ -665,8 +661,9 @@ void SVGAnimationElement::adjustForInheritance(SVGElement* targetElement, const
         return;
 
     SVGElement* svgParent = static_cast<SVGElement*>(parent);
-    if (svgParent->isStyled())
-        value = CSSComputedStyleDeclaration::create(svgParent)->getPropertyValue(cssPropertyID(attributeName.localName()));
+    if (!svgParent->isStyled())
+        return;
+    computeCSSPropertyValue(svgParent, cssPropertyID(attributeName.localName()), value, true);
 }
 
 static bool inheritsFromProperty(SVGElement* targetElement, const QualifiedName& attributeName, const String& value)
index 49cfec9..abfaa7a 100644 (file)
@@ -194,6 +194,7 @@ public:
 protected:
     SVGAnimationElement(const QualifiedName&, Document*);
 
+    void computeCSSPropertyValue(SVGElement*, CSSPropertyID, String& value, bool includeSMILProperties);
     virtual void determinePropertyValueTypes(const String& from, const String& to);
 
     bool isSupportedAttribute(const QualifiedName&);
@@ -212,7 +213,7 @@ protected:
     String fromValue() const;
 
     String targetAttributeBaseValue();
-    void setTargetAttributeAnimatedValue(SVGAnimatedType*);
+    void setTargetAttributeAnimatedCSSValue(SVGAnimatedType*);
 
     // from SVGSMILElement
     virtual void startedActiveInterval();
index e3b5e69..628ea5a 100644 (file)
@@ -61,6 +61,7 @@ SVGElement::SVGElement(const QualifiedName& tagName, Document* document, Constru
     : StyledElement(tagName, document, constructionType)
 {
     setHasCustomStyleForRenderer();
+    setHasCustomWillOrDidRecalcStyle();
 }
 
 PassRefPtr<SVGElement> SVGElement::create(const QualifiedName& tagName, Document* document)
@@ -91,6 +92,17 @@ SVGElement::~SVGElement()
     document()->accessSVGExtensions()->removeAllElementReferencesForTarget(this);
 }
 
+bool SVGElement::willRecalcStyle(StyleChange change)
+{
+    if (!hasRareSVGData() || styleChangeType() == SyntheticStyleChange)
+        return true;
+    // If the style changes because of a regular property change (not induced by SMIL animations themselves)
+    // reset the "computed style without SMIL style properties", so the base value change gets reflected.
+    if (change > NoChange || needsStyleRecalc())
+        rareSVGData()->setNeedsOverrideComputedStyleUpdate();
+    return true;
+}
+
 SVGElementRareData* SVGElement::rareSVGData() const
 {
     ASSERT(hasRareSVGData());
@@ -504,6 +516,26 @@ StylePropertySet* SVGElement::ensureAnimatedSMILStyleProperties()
     return ensureRareSVGData()->ensureAnimatedSMILStyleProperties();
 }
 
+void SVGElement::setUseOverrideComputedStyle(bool value)
+{
+    if (hasRareSVGData())
+        rareSVGData()->setUseOverrideComputedStyle(value);
+}
+
+RenderStyle* SVGElement::computedStyle(PseudoId pseudoElementSpecifier)
+{
+    if (!hasRareSVGData() || !rareSVGData()->useOverrideComputedStyle())
+        return Element::computedStyle(pseudoElementSpecifier);
+
+    RenderStyle* parentStyle = 0;
+    if (Element* parent = parentOrHostElement()) {
+        if (RenderObject* renderer = parent->renderer())
+            parentStyle = renderer->style();
+    }
+
+    return rareSVGData()->overrideComputedStyle(this, parentStyle);
+}
+
 #ifndef NDEBUG
 bool SVGElement::isAnimatableAttribute(const QualifiedName& name)
 {
index 0105096..5c9a3dc 100644 (file)
@@ -109,6 +109,7 @@ public:
 
     StylePropertySet* animatedSMILStyleProperties() const;
     StylePropertySet* ensureAnimatedSMILStyleProperties();
+    void setUseOverrideComputedStyle(bool);
 
     virtual bool haveLoadedRequiredResources();
 
@@ -131,6 +132,10 @@ protected:
 private:
     friend class SVGElementInstance;
 
+    RenderStyle* computedStyle(PseudoId = NOPSEUDO);
+    virtual RenderStyle* virtualComputedStyle(PseudoId pseudoElementSpecifier = NOPSEUDO) { return computedStyle(pseudoElementSpecifier); }
+    virtual bool willRecalcStyle(StyleChange);
+
     virtual bool rendererIsNeeded(const NodeRenderingContext&) { return false; }
 
     virtual bool isSupported(StringImpl* feature, StringImpl* version) const;
index a9d7afb..5069485 100644 (file)
@@ -21,6 +21,7 @@
 #define SVGElementRareData_h
 
 #include "CSSParserMode.h"
+#include "StyleResolver.h"
 #include <wtf/HashSet.h>
 #include <wtf/Noncopyable.h>
 #include <wtf/StdLibExtras.h>
@@ -41,6 +42,8 @@ public:
         , m_correspondingElement(0)
         , m_instancesUpdatesBlocked(false)
         , m_hasPendingResources(false)
+        , m_useOverrideComputedStyle(false)
+        , m_needsOverrideComputedStyleUpdate(false)
     {
     }
 
@@ -78,9 +81,8 @@ public:
     StylePropertySet* animatedSMILStyleProperties() const { return m_animatedSMILStyleProperties.get(); }
     StylePropertySet* ensureAnimatedSMILStyleProperties()
     {
-        if (!m_animatedSMILStyleProperties) {
+        if (!m_animatedSMILStyleProperties)
             m_animatedSMILStyleProperties = StylePropertySet::create(SVGAttributeMode);
-        }
         return m_animatedSMILStyleProperties.get();
     }
 
@@ -89,6 +91,24 @@ public:
         m_animatedSMILStyleProperties.clear();
     }
 
+    RenderStyle* overrideComputedStyle(Element* element, RenderStyle* parentStyle)
+    {
+        ASSERT(element);
+        if (!element->document() || !m_useOverrideComputedStyle)
+            return 0;
+        if (!m_overrideComputedStyle || m_needsOverrideComputedStyleUpdate) {
+            // The style computed here contains no CSS Animations/Transitions or SMIL induced rules - this is needed to compute the "base value" for the SMIL animation sandwhich model.
+            m_overrideComputedStyle = element->document()->styleResolver()->styleForElement(element, parentStyle, DisallowStyleSharing, MatchAllRulesExcludingSMIL);
+            m_needsOverrideComputedStyleUpdate = false;
+        }
+        ASSERT(m_overrideComputedStyle);
+        return m_overrideComputedStyle.get();
+    }
+
+    bool useOverrideComputedStyle() const { return m_useOverrideComputedStyle; }
+    void setUseOverrideComputedStyle(bool value) { m_useOverrideComputedStyle = value; }
+    void setNeedsOverrideComputedStyleUpdate() { m_needsOverrideComputedStyleUpdate = true; }
+
 private:
     HashSet<SVGElementInstance*> m_elementInstances;
     SVGCursorElement* m_cursorElement;
@@ -96,7 +116,10 @@ private:
     SVGElement* m_correspondingElement;
     bool m_instancesUpdatesBlocked : 1;
     bool m_hasPendingResources : 1;
+    bool m_useOverrideComputedStyle : 1;
+    bool m_needsOverrideComputedStyleUpdate : 1;
     RefPtr<StylePropertySet> m_animatedSMILStyleProperties;
+    RefPtr<RenderStyle> m_overrideComputedStyle;
 };
 
 }
index c496383..7a92dd8 100644 (file)
 #include "SMILTimeContainer.h"
 
 #if ENABLE(SVG)
-#include "CSSComputedStyleDeclaration.h"
-#include "CSSParser.h"
 #include "Document.h"
-#include "SVGAnimationElement.h"
 #include "SVGNames.h"
 #include "SVGSMILElement.h"
 #include "SVGSVGElement.h"
@@ -205,27 +202,6 @@ static void sortByApplyOrder(Vector<SVGSMILElement*>& smilElements)
     std::sort(smilElements.begin(), smilElements.end(), applyOrderSortFunction);
 }
 
-String SMILTimeContainer::baseValueFor(ElementAttributePair key)
-{
-    // FIXME: We wouldn't need to do this if we were keeping base values around properly in DOM.
-    // Currently animation overwrites them so we need to save them somewhere.
-    BaseValueMap::iterator it = m_savedBaseValues.find(key);
-    if (it != m_savedBaseValues.end())
-        return it->second;
-    
-    SVGElement* targetElement = key.first;
-    QualifiedName attributeName = key.second;
-    ASSERT(targetElement);
-    ASSERT(attributeName != anyQName());
-    String baseValue;
-    if (SVGAnimationElement::isTargetAttributeCSSProperty(targetElement, attributeName))
-        baseValue = CSSComputedStyleDeclaration::create(targetElement)->getPropertyValue(cssPropertyID(attributeName.localName()));
-    else
-        baseValue = targetElement->getAttribute(attributeName);
-    m_savedBaseValues.add(key, baseValue);
-    return baseValue;
-}
-
 void SMILTimeContainer::updateAnimations(SMILTime elapsed)
 {
     SMILTime earliersFireTime = SMILTime::unresolved();
@@ -240,6 +216,7 @@ void SMILTimeContainer::updateAnimations(SMILTime elapsed)
     sortByPriority(toAnimate, elapsed);
     
     // Calculate animation contributions.
+    typedef pair<SVGElement*, QualifiedName> ElementAttributePair;
     typedef HashMap<ElementAttributePair, RefPtr<SVGSMILElement> > ResultElementMap;
     ResultElementMap resultsElements;
     for (unsigned n = 0; n < toAnimate.size(); ++n) {
@@ -265,11 +242,7 @@ void SMILTimeContainer::updateAnimations(SMILTime elapsed)
             if (!animation->hasValidAttributeType())
                 continue;
             resultElement = animation;
-            // FIXME: As soon as we stop mutating the DOM, we can stop passing the cached baseValue here.
-            // Caching the baseValue results in wrong additive="sum" behaviour. Reason: the m_savedBaseValues
-            // is NEVER reset, it always contains the state of the baseValue, at the point where we first
-            // called baseValueFor(), typically at the beginning of the animation.
-            resultElement->resetToBaseValue(baseValueFor(key));
+            resultElement->resetToBaseValue();
             resultsElements.add(key, resultElement);
         }
 
index d4d06da..f96cb99 100644 (file)
@@ -73,9 +73,6 @@ private:
     void updateDocumentOrderIndexes();
     void sortByPriority(Vector<SVGSMILElement*>& smilElements, SMILTime elapsed);
     
-    typedef pair<SVGElement*, QualifiedName> ElementAttributePair;
-    String baseValueFor(ElementAttributePair);
-    
     double m_beginTime;
     double m_pauseTime;
     double m_accumulatedPauseTime;
@@ -87,9 +84,6 @@ private:
 
     typedef HashSet<SVGSMILElement*> TimingElementSet;
     TimingElementSet m_scheduledAnimations;
-    
-    typedef HashMap<ElementAttributePair, String> BaseValueMap;
-    BaseValueMap m_savedBaseValues;
 
     SVGSVGElement* m_ownerSVGElement;
 };
index 1a1f47e..0cb0130 100644 (file)
@@ -105,7 +105,7 @@ public:
     void setDocumentOrderIndex(unsigned index) { m_documentOrderIndex = index; }
 
     virtual bool isAdditive() const = 0;
-    virtual void resetToBaseValue(const String&) = 0;
+    virtual void resetToBaseValue() = 0;
     virtual void applyResultsToTarget() = 0;
 
 protected: