2011-02-15 Dirk Schulze <krit@webkit.org>
authorkrit@webkit.org <krit@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 15 Feb 2011 11:16:12 +0000 (11:16 +0000)
committerkrit@webkit.org <krit@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 15 Feb 2011 11:16:12 +0000 (11:16 +0000)
        Reviewed by Nikolas Zimmermann.

        SVG animation doesn't support attribute value 'inherit'
        https://bugs.webkit.org/show_bug.cgi?id=54410

        Check support for 'inherit' and 'currentColor' on SVG animations.

        * svg/animations/animate-currentColor-expected.txt: Added.
        * svg/animations/animate-currentColor.html: Added.
        * svg/animations/animate-inherit-css-property-expected.txt: Added.
        * svg/animations/animate-inherit-css-property.html: Added.
        * svg/animations/script-tests/animate-currentColor.js: Added.
        (sample1):
        (sample2):
        (sample3):
        (executeTest):
        * svg/animations/script-tests/animate-inherit-css-property.js: Added.
        (sample1):
        (sample2):
        (sample3):
        (executeTest):
2011-02-15  Dirk Schulze  <krit@webkit.org>

        Reviewed by Nikolas Zimmermann.

        SVG animation doesn't support attribute value 'inherit'
        https://bugs.webkit.org/show_bug.cgi?id=54410

        SVG animation does not support 'inherit' as value for CSS property animations. With the patch, SVG determines
        if the attribute of the target element is an animatable CSS Property and computes the style during the
        animation.

        This fixes the following tests on the W3C test suite:
        * animate-elem-84-t.svg
        * animate-elem-85-t.svg

        Tests: svg/animations/animate-currentColor.html
               svg/animations/animate-inherit-css-property.html

        * svg/SVGAnimateElement.cpp:
        (WebCore::adjustForCurrentColor):
        (WebCore::adjustForInheritance):
        (WebCore::SVGAnimateElement::calculateAnimatedValue): When a property value is 'inherit' or 'currentColor'
        during the animation, get the computed style of the property since the values could be animated themselves.
        (WebCore::inheritsFromProperty):
        (WebCore::attributeValueIsCurrentColor):
        (WebCore::SVGAnimateElement::calculateFromAndToValues): Check if 'from', 'by' or 'to' value has the
        string 'inherit' or 'currentColor' and if the attribute supports one of these values.
        (WebCore::SVGAnimateElement::calculateFromAndByValues): Ditto.
        * svg/SVGAnimateElement.h:
        * svg/SVGAnimationElement.cpp:
        (WebCore::SVGAnimationElement::isTargetAttributeCSSProperty): Check if target element is stylable and
        the attribute is an animatable CSS property by using the CSS property map in SVGStyledElement.
        (WebCore::SVGAnimationElement::setTargetAttributeAnimatedValue): s/target/targetElement/ for consistency.
        * svg/SVGAnimationElement.h:
        * svg/SVGStyledElement.cpp:
        (WebCore::SVGStyledElement::isAnimatableCSSProperty): Checks if the CSS property is animatable.
        * svg/SVGStyledElement.h:
        * svg/animation/SMILTimeContainer.cpp: Use the new function isTargetAttributeCSSProperty to determine
        if the target element is stylable and the attribute is an animatable CSS property.
        (WebCore::SMILTimeContainer::baseValueFor):

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

15 files changed:
LayoutTests/ChangeLog
LayoutTests/svg/animations/animate-currentColor-expected.txt [new file with mode: 0644]
LayoutTests/svg/animations/animate-currentColor.html [new file with mode: 0644]
LayoutTests/svg/animations/animate-inherit-css-property-expected.txt [new file with mode: 0644]
LayoutTests/svg/animations/animate-inherit-css-property.html [new file with mode: 0644]
LayoutTests/svg/animations/script-tests/animate-currentColor.js [new file with mode: 0644]
LayoutTests/svg/animations/script-tests/animate-inherit-css-property.js [new file with mode: 0644]
Source/WebCore/ChangeLog
Source/WebCore/svg/SVGAnimateElement.cpp
Source/WebCore/svg/SVGAnimateElement.h
Source/WebCore/svg/SVGAnimationElement.cpp
Source/WebCore/svg/SVGAnimationElement.h
Source/WebCore/svg/SVGStyledElement.cpp
Source/WebCore/svg/SVGStyledElement.h
Source/WebCore/svg/animation/SMILTimeContainer.cpp

index f41c52b..42c4a35 100644 (file)
@@ -1,3 +1,27 @@
+2011-02-15  Dirk Schulze  <krit@webkit.org>
+
+        Reviewed by Nikolas Zimmermann.
+
+        SVG animation doesn't support attribute value 'inherit'
+        https://bugs.webkit.org/show_bug.cgi?id=54410
+
+        Check support for 'inherit' and 'currentColor' on SVG animations.
+
+        * svg/animations/animate-currentColor-expected.txt: Added.
+        * svg/animations/animate-currentColor.html: Added.
+        * svg/animations/animate-inherit-css-property-expected.txt: Added.
+        * svg/animations/animate-inherit-css-property.html: Added.
+        * svg/animations/script-tests/animate-currentColor.js: Added.
+        (sample1):
+        (sample2):
+        (sample3):
+        (executeTest):
+        * svg/animations/script-tests/animate-inherit-css-property.js: Added.
+        (sample1):
+        (sample2):
+        (sample3):
+        (executeTest):
+
 2011-02-15  Pavel Feldman  <pfeldman@chromium.org>
 
         Not reviewed: inspector tests expectations update.
diff --git a/LayoutTests/svg/animations/animate-currentColor-expected.txt b/LayoutTests/svg/animations/animate-currentColor-expected.txt
new file mode 100644 (file)
index 0000000..2279ff4
--- /dev/null
@@ -0,0 +1,14 @@
+SVG 1.1 dynamic animation tests
+
+Tests animation on 'currentColor'.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS rect.style.fill is '#FF0000'
+PASS rect.style.fill is '#804000'
+PASS rect.style.fill is '#008000'
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/svg/animations/animate-currentColor.html b/LayoutTests/svg/animations/animate-currentColor.html
new file mode 100644 (file)
index 0000000..04ef42a
--- /dev/null
@@ -0,0 +1,15 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<link rel="stylesheet" href="../../fast/js/resources/js-test-style.css">
+<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>
+<h1>SVG 1.1 dynamic animation tests</h1>
+<p id="description"></p>
+<div id="console"></div>
+<script src="script-tests/animate-currentColor.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/svg/animations/animate-inherit-css-property-expected.txt b/LayoutTests/svg/animations/animate-inherit-css-property-expected.txt
new file mode 100644 (file)
index 0000000..d48de4e
--- /dev/null
@@ -0,0 +1,14 @@
+SVG 1.1 dynamic animation tests
+
+Tests animation with 'inherit'.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS rect.style.fill is '#FF0000'
+PASS rect.style.fill is '#804000'
+PASS rect.style.fill is '#008000'
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/svg/animations/animate-inherit-css-property.html b/LayoutTests/svg/animations/animate-inherit-css-property.html
new file mode 100644 (file)
index 0000000..53eb4e8
--- /dev/null
@@ -0,0 +1,15 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<link rel="stylesheet" href="../../fast/js/resources/js-test-style.css">
+<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>
+<h1>SVG 1.1 dynamic animation tests</h1>
+<p id="description"></p>
+<div id="console"></div>
+<script src="script-tests/animate-inherit-css-property.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/svg/animations/script-tests/animate-currentColor.js b/LayoutTests/svg/animations/script-tests/animate-currentColor.js
new file mode 100644 (file)
index 0000000..215c3e4
--- /dev/null
@@ -0,0 +1,54 @@
+description("Tests animation on 'currentColor'.");
+createSVGTestCase();
+
+// Setup test document
+var rect = createSVGElement("rect");
+rect.setAttribute("id", "rect");
+rect.setAttribute("width", "100px");
+rect.setAttribute("height", "100px");
+rect.setAttribute("fill", "red");
+rect.setAttribute("color", "green");
+
+var animateCurrentColor = createSVGElement("animateColor");
+animateCurrentColor.setAttribute("id", "animateCurrentColor");
+animateCurrentColor.setAttribute("attributeName", "fill");
+animateCurrentColor.setAttribute("from", "red");
+animateCurrentColor.setAttribute("to", "currentColor");
+animateCurrentColor.setAttribute("dur", "3s");
+animateCurrentColor.setAttribute("begin", "click");
+animateCurrentColor.setAttribute("fill", "freeze");
+rect.appendChild(animateCurrentColor);
+rootSVGElement.appendChild(rect);
+
+// Setup animation test
+function sample1() {
+    // Check initial/end conditions
+    shouldBe("rect.style.fill", "'#FF0000'");
+}
+
+function sample2() {
+    // Check half-time conditions
+    shouldBe("rect.style.fill", "'#804000'");
+}
+
+function sample3() {
+    // Check half-time conditions
+    shouldBe("rect.style.fill", "'#008000'");
+}
+
+function executeTest() {
+    const expectedValues = [
+        // [animationId, time, elementId, sampleCallback]
+        ["animateCurrentColor", 0.0,    "rect", sample1],
+        ["animateCurrentColor", 1.5,    "rect", sample2],
+        ["animateCurrentColor", 3.0,    "rect", sample3]
+    ];
+
+    runAnimationTest(expectedValues);
+}
+
+// Begin test async
+rect.setAttribute("onclick", "executeTest()");
+window.setTimeout("triggerUpdate(50, 50)", 0);
+var successfullyParsed = true;
+
diff --git a/LayoutTests/svg/animations/script-tests/animate-inherit-css-property.js b/LayoutTests/svg/animations/script-tests/animate-inherit-css-property.js
new file mode 100644 (file)
index 0000000..9930bff
--- /dev/null
@@ -0,0 +1,57 @@
+description("Tests animation with 'inherit'.");
+createSVGTestCase();
+
+// Setup test document
+var g = createSVGElement("g");
+g.setAttribute("fill", "green");
+
+var rect = createSVGElement("rect");
+rect.setAttribute("id", "rect");
+rect.setAttribute("width", "100px");
+rect.setAttribute("height", "100px");
+rect.setAttribute("fill", "red");
+g.appendChild(rect);
+
+var animateInherit = createSVGElement("animateColor");
+animateInherit.setAttribute("id", "animateInherit");
+animateInherit.setAttribute("attributeName", "fill");
+animateInherit.setAttribute("from", "red");
+animateInherit.setAttribute("to", "inherit");
+animateInherit.setAttribute("dur", "3s");
+animateInherit.setAttribute("begin", "click");
+animateInherit.setAttribute("fill", "freeze");
+rect.appendChild(animateInherit);
+rootSVGElement.appendChild(g);
+
+// Setup animation test
+function sample1() {
+    // Check initial/end conditions
+    shouldBe("rect.style.fill", "'#FF0000'");
+}
+
+function sample2() {
+    // Check half-time conditions
+    shouldBe("rect.style.fill", "'#804000'");
+}
+
+function sample3() {
+    // Check half-time conditions
+    shouldBe("rect.style.fill", "'#008000'");
+}
+
+function executeTest() {
+    const expectedValues = [
+        // [animationId, time, elementId, sampleCallback]
+        ["animateInherit", 0.0,    "rect", sample1],
+        ["animateInherit", 1.5,    "rect", sample2],
+        ["animateInherit", 3.0,    "rect", sample3]
+    ];
+
+    runAnimationTest(expectedValues);
+}
+
+// Begin test async
+rect.setAttribute("onclick", "executeTest()");
+window.setTimeout("triggerUpdate(50, 50)", 0);
+var successfullyParsed = true;
+
index 344034c..35a4c59 100644 (file)
@@ -1,3 +1,44 @@
+2011-02-15  Dirk Schulze  <krit@webkit.org>
+
+        Reviewed by Nikolas Zimmermann.
+
+        SVG animation doesn't support attribute value 'inherit'
+        https://bugs.webkit.org/show_bug.cgi?id=54410
+
+        SVG animation does not support 'inherit' as value for CSS property animations. With the patch, SVG determines
+        if the attribute of the target element is an animatable CSS Property and computes the style during the
+        animation.
+
+        This fixes the following tests on the W3C test suite:
+        * animate-elem-84-t.svg
+        * animate-elem-85-t.svg
+
+        Tests: svg/animations/animate-currentColor.html
+               svg/animations/animate-inherit-css-property.html
+
+        * svg/SVGAnimateElement.cpp:
+        (WebCore::adjustForCurrentColor):
+        (WebCore::adjustForInheritance):
+        (WebCore::SVGAnimateElement::calculateAnimatedValue): When a property value is 'inherit' or 'currentColor'
+        during the animation, get the computed style of the property since the values could be animated themselves.
+        (WebCore::inheritsFromProperty):
+        (WebCore::attributeValueIsCurrentColor):
+        (WebCore::SVGAnimateElement::calculateFromAndToValues): Check if 'from', 'by' or 'to' value has the
+        string 'inherit' or 'currentColor' and if the attribute supports one of these values.
+        (WebCore::SVGAnimateElement::calculateFromAndByValues): Ditto.
+        * svg/SVGAnimateElement.h:
+        * svg/SVGAnimationElement.cpp:
+        (WebCore::SVGAnimationElement::isTargetAttributeCSSProperty): Check if target element is stylable and
+        the attribute is an animatable CSS property by using the CSS property map in SVGStyledElement.
+        (WebCore::SVGAnimationElement::setTargetAttributeAnimatedValue): s/target/targetElement/ for consistency.
+        * svg/SVGAnimationElement.h:
+        * svg/SVGStyledElement.cpp: 
+        (WebCore::SVGStyledElement::isAnimatableCSSProperty): Checks if the CSS property is animatable.
+        * svg/SVGStyledElement.h:
+        * svg/animation/SMILTimeContainer.cpp: Use the new function isTargetAttributeCSSProperty to determine
+        if the target element is stylable and the attribute is an animatable CSS property.
+        (WebCore::SMILTimeContainer::baseValueFor):
+
 2011-02-15  Antti Koivisto  <antti@apple.com>
 
         Reviewed by Andreas Kling.
index 0dfe086..3659049 100644 (file)
@@ -24,6 +24,8 @@
 #if ENABLE(SVG) && ENABLE(SVG_ANIMATION)
 #include "SVGAnimateElement.h"
 
+#include "CSSComputedStyleDeclaration.h"
+#include "CSSParser.h"
 #include "CSSPropertyNames.h"
 #include "ColorDistance.h"
 #include "FloatConversion.h"
@@ -35,6 +37,7 @@
 #include "SVGPathParserFactory.h"
 #include "SVGPathSegList.h"
 #include "SVGPointList.h"
+#include "SVGStyledElement.h"
 
 using namespace std;
 
@@ -85,15 +88,29 @@ static bool parseNumberValueAndUnit(const String& in, double& value, String& uni
     return ok;
 }
 
-static inline bool adjustForCurrentColor(Color& color, const String& value, SVGElement* target)
+static inline void adjustForCurrentColor(SVGElement* targetElement, Color& color)
 {
-    if (!target || !target->isStyled() || value != "currentColor")
-        return false;
+    ASSERT(targetElement);
     
-    if (RenderObject* targetRenderer = target->renderer())
+    if (RenderObject* targetRenderer = targetElement->renderer())
         color = targetRenderer->style()->visitedDependentColor(CSSPropertyColor);
+    else
+        color = Color();
+}
 
-    return true;
+static inline void adjustForInheritance(SVGElement* targetElement, const String& attributeName, String& value)
+{
+    // FIXME: At the moment the computed style gets returned as a String and needs to get parsed again.
+    // In the future we might want to work with the value type directly to avoid the String parsing.
+    ASSERT(targetElement);
+
+    Element* parent = targetElement->parentElement();
+    if (!parent || !parent->isSVGElement())
+        return;
+
+    SVGElement* svgParent = static_cast<SVGElement*>(parent);
+    if (svgParent->isStyled())
+        value = computedStyle(svgParent)->getPropertyValue(cssPropertyID(attributeName));
 }
 
 SVGAnimateElement::PropertyType SVGAnimateElement::determinePropertyType(const String& attribute) const
@@ -115,13 +132,21 @@ SVGAnimateElement::PropertyType SVGAnimateElement::determinePropertyType(const S
 
 void SVGAnimateElement::calculateAnimatedValue(float percentage, unsigned repeat, SVGSMILElement* resultElement)
 {
-    ASSERT(percentage >= 0.f && percentage <= 1.f);
+    ASSERT(percentage >= 0 && percentage <= 1);
     ASSERT(resultElement);
-    bool isInFirstHalfOfAnimation = percentage < 0.5;
+    bool isInFirstHalfOfAnimation = percentage < 0.5f;
     AnimationMode animationMode = this->animationMode();
+    SVGElement* targetElement = 0;
+    // Avoid targetElement() call if possible. It might slow down animations.
+    if (m_fromPropertyValueType == InheritValue || m_toPropertyValueType == InheritValue
+        || m_fromPropertyValueType == CurrentColorValue || m_toPropertyValueType == CurrentColorValue) {
+        targetElement = this->targetElement();
+        if (!targetElement)
+            return;
+    }
     
     if (hasTagName(SVGNames::setTag))
-        percentage = 1.f;
+        percentage = 1;
     if (!resultElement->hasTagName(SVGNames::animateTag) && !resultElement->hasTagName(SVGNames::animateColorTag) 
         && !resultElement->hasTagName(SVGNames::setTag))
         return;
@@ -134,6 +159,20 @@ void SVGAnimateElement::calculateAnimatedValue(float percentage, unsigned repeat
         if (animationMode == ToAnimation)
             m_fromNumber = results->m_animatedNumber;
         
+        // Replace 'currentColor' / 'inherit' by their computed property values.
+        if (m_fromPropertyValueType == InheritValue) {
+            String fromNumberString;
+            adjustForInheritance(targetElement, attributeName(), fromNumberString);
+            if (!parseNumberValueAndUnit(fromNumberString, m_fromNumber, m_numberUnit))
+                return;
+        }
+        if (m_toPropertyValueType == InheritValue) {
+            String toNumberString;
+            adjustForInheritance(targetElement, attributeName(), toNumberString);
+            if (!parseNumberValueAndUnit(toNumberString, m_toNumber, m_numberUnit))
+                return;
+        }
+
         double number;
         if (calcMode() == CalcModeDiscrete)
             number = isInFirstHalfOfAnimation ? m_fromNumber : m_toNumber;
@@ -152,6 +191,23 @@ void SVGAnimateElement::calculateAnimatedValue(float percentage, unsigned repeat
     if (m_propertyType == ColorProperty) {
         if (animationMode == ToAnimation)
             m_fromColor = results->m_animatedColor;
+
+        // Replace 'currentColor' / 'inherit' by their computed property values.
+        if (m_fromPropertyValueType == CurrentColorValue)
+            adjustForCurrentColor(targetElement, m_fromColor);
+        else if (m_fromPropertyValueType == InheritValue) {
+            String fromColorString;
+            adjustForInheritance(targetElement, attributeName(), fromColorString);
+            m_fromColor = SVGColor::colorFromRGBColorString(fromColorString);
+        }
+        if (m_toPropertyValueType == CurrentColorValue)
+            adjustForCurrentColor(targetElement, m_toColor);
+        else if (m_toPropertyValueType == InheritValue) {
+            String toColorString;
+            adjustForInheritance(targetElement, attributeName(), toColorString);
+            m_toColor = SVGColor::colorFromRGBColorString(toColorString);
+        }
+
         Color color;
         if (calcMode() == CalcModeDiscrete)
             color = isInFirstHalfOfAnimation ? m_fromColor : m_toColor;
@@ -216,7 +272,13 @@ void SVGAnimateElement::calculateAnimatedValue(float percentage, unsigned repeat
         return;
     }
     ASSERT(animationMode == FromToAnimation || animationMode == ToAnimation || animationMode == ValuesAnimation);
-    if ((animationMode == FromToAnimation && percentage > 0.5f) || animationMode == ToAnimation || percentage == 1.0f)
+    // Replace 'currentColor' / 'inherit' by their computed property values.
+    if (m_fromPropertyValueType == InheritValue)
+        adjustForInheritance(targetElement, attributeName(), m_fromString);
+    if (m_toPropertyValueType == InheritValue)
+        adjustForInheritance(targetElement, attributeName(), m_toString);
+
+    if ((animationMode == FromToAnimation && percentage > 0.5f) || animationMode == ToAnimation || percentage == 1)
         results->m_animatedString = m_toString;
     else
         results->m_animatedString = m_fromString;
@@ -224,17 +286,45 @@ void SVGAnimateElement::calculateAnimatedValue(float percentage, unsigned repeat
     results->m_propertyType = StringProperty;
 }
 
+static bool inheritsFromProperty(SVGElement* targetElement, const String& attributeName, const String& value)
+{
+    ASSERT(targetElement);
+    DEFINE_STATIC_LOCAL(const AtomicString, inherit, ("inherit"));
+
+    if (value.isEmpty() || value != inherit || !targetElement->isStyled())
+        return false;
+    return SVGStyledElement::isAnimatableCSSProperty(QualifiedName(nullAtom, attributeName, nullAtom));
+}
+
+static bool attributeValueIsCurrentColor(const String& value)
+{
+    DEFINE_STATIC_LOCAL(const AtomicString, currentColor, ("currentColor"));
+    return value == currentColor;
+}
+
 bool SVGAnimateElement::calculateFromAndToValues(const String& fromString, const String& toString)
 {
+    SVGElement* targetElement = this->targetElement();
+    if (!targetElement)
+        return false;
+    m_fromPropertyValueType = inheritsFromProperty(targetElement, attributeName(), fromString) ? InheritValue : CurrentColorValue;
+    m_toPropertyValueType = inheritsFromProperty(targetElement, attributeName(), toString) ? InheritValue : CurrentColorValue;
+
     // FIXME: Needs more solid way determine target attribute type.
     m_propertyType = determinePropertyType(attributeName());
     if (m_propertyType == ColorProperty) {
-        SVGElement* targetElement = this->targetElement();
-        if (!adjustForCurrentColor(m_fromColor, fromString, targetElement))
+        bool fromIsCurrentColor = attributeValueIsCurrentColor(fromString);
+        bool toIsCurrentColor = attributeValueIsCurrentColor(toString);
+        if (fromIsCurrentColor)
+            m_fromPropertyValueType = CurrentColorValue;
+        else
             m_fromColor = SVGColor::colorFromRGBColorString(fromString);
-        if (!adjustForCurrentColor(m_toColor, toString, targetElement))
+        if (toIsCurrentColor)
+            m_toPropertyValueType = CurrentColorValue;
+        else
             m_toColor = SVGColor::colorFromRGBColorString(toString);
-        if ((m_fromColor.isValid() && m_toColor.isValid()) || (m_toColor.isValid() && animationMode() == ToAnimation))
+        if (((m_fromColor.isValid() || fromIsCurrentColor) && (m_toColor.isValid() || toIsCurrentColor))
+            || ((m_toColor.isValid() || toIsCurrentColor) && animationMode() == ToAnimation))
             return true;
     } else if (m_propertyType == NumberProperty) {
         m_numberUnit = String();
@@ -268,16 +358,28 @@ bool SVGAnimateElement::calculateFromAndToValues(const String& fromString, const
 
 bool SVGAnimateElement::calculateFromAndByValues(const String& fromString, const String& byString)
 {
+    SVGElement* targetElement = this->targetElement();
+    if (!targetElement)
+        return false;
+    m_fromPropertyValueType = inheritsFromProperty(targetElement, attributeName(), fromString) ? InheritValue : CurrentColorValue;
+    m_toPropertyValueType = inheritsFromProperty(targetElement, attributeName(), byString) ? InheritValue : CurrentColorValue;
+
     ASSERT(!hasTagName(SVGNames::setTag));
     m_propertyType = determinePropertyType(attributeName());
     if (m_propertyType == ColorProperty) {
-        SVGElement* targetElement = this->targetElement();
-        if (!adjustForCurrentColor(m_fromColor, fromString, targetElement))
-            m_fromColor = fromString.isEmpty() ? Color() : SVGColor::colorFromRGBColorString(fromString);
-        if (!adjustForCurrentColor(m_toColor, byString, targetElement))
+        bool fromIsCurrentColor = attributeValueIsCurrentColor(fromString);
+        bool byIsCurrentColor = attributeValueIsCurrentColor(byString);
+        if (fromIsCurrentColor)
+            m_fromPropertyValueType = CurrentColorValue;
+        else
+            m_fromColor = SVGColor::colorFromRGBColorString(fromString);
+        if (byIsCurrentColor)
+            m_toPropertyValueType = CurrentColorValue;
+        else
             m_toColor = SVGColor::colorFromRGBColorString(byString);
-        m_toColor = ColorDistance::addColorsAndClamp(m_fromColor, m_toColor);
-        if (!m_fromColor.isValid() || !m_toColor.isValid())
+        
+        if ((!m_fromColor.isValid() && !fromIsCurrentColor)
+            || (!m_toColor.isValid() && !byIsCurrentColor))
             return false;
     } else {
         m_numberUnit = String();
index 3217c4a..70c0dd0 100644 (file)
@@ -51,10 +51,19 @@ protected:
     virtual float calculateDistance(const String& fromString, const String& toString);
 
 private:
+    // If we have 'currentColor' or 'inherit' as animation value, we need to grab the value during the animation
+    // since the value can be animated itself.
+    enum AnimatedPropertyValueType {
+        RegularPropertyValue,
+        CurrentColorValue,
+        InheritValue
+    };
     enum PropertyType { NumberProperty, ColorProperty, StringProperty, PathProperty, PointsProperty };
     PropertyType determinePropertyType(const String& attribute) const;
     PropertyType m_propertyType;
 
+    AnimatedPropertyValueType m_fromPropertyValueType;
+    AnimatedPropertyValueType m_toPropertyValueType;
     double m_fromNumber;
     double m_toNumber;
     double m_animatedNumber;
index c56e3b6..0e7f820 100644 (file)
@@ -41,6 +41,7 @@
 #include "SVGElementInstance.h"
 #include "SVGNames.h"
 #include "SVGParserUtilities.h"
+#include "SVGStyledElement.h"
 #include "SVGURIReference.h"
 #include "SVGUseElement.h"
 #include "XLinkNames.h"
@@ -293,67 +294,56 @@ bool SVGAnimationElement::hasValidTarget() const
 {
     return targetElement();
 }
-    
-bool SVGAnimationElement::attributeIsCSS(const String& attributeName)
-{
-    // FIXME: We should have a map of all SVG properties and their attribute types so we
-    // could validate animations better. The spec is very vague about this.
-    unsigned id = cssPropertyID(attributeName);
-    // SVG range
-    if (id >= CSSPropertyClipPath && id <= CSSPropertyWritingMode)
-        return true;
-    // Regular CSS properties also in SVG
-    return id == CSSPropertyColor || id == CSSPropertyDisplay || id == CSSPropertyOpacity
-            || (id >= CSSPropertyFont && id <= CSSPropertyFontWeight) 
-            || id == CSSPropertyOverflow || id == CSSPropertyVisibility;
-}
-    
-bool SVGAnimationElement::targetAttributeIsCSS() const
+
+bool SVGAnimationElement::isTargetAttributeCSSProperty(SVGElement* targetElement, const String& attributeName)
 {
-    AttributeType type = attributeType();
-    if (type == AttributeTypeCSS)
-        return true;
-    if (type == AttributeTypeXML)
+    ASSERT(targetElement);
+    if (!targetElement->isStyled())
         return false;
-    return attributeIsCSS(attributeName());
+
+    return SVGStyledElement::isAnimatableCSSProperty(QualifiedName(nullAtom, attributeName, nullAtom));
 }
 
 void SVGAnimationElement::setTargetAttributeAnimatedValue(const String& value)
 {
     if (!hasValidTarget())
         return;
-    SVGElement* target = targetElement();
+    SVGElement* targetElement = this->targetElement();
     String attributeName = this->attributeName();
-    if (!target || attributeName.isEmpty() || value.isNull())
+    if (!targetElement || attributeName.isEmpty() || value.isNull())
         return;
 
     // We don't want the instance tree to get rebuild. Instances are updated in the loop below.
-    if (target->isStyled())
-        static_cast<SVGStyledElement*>(target)->setInstanceUpdatesBlocked(true);
+    if (targetElement->isStyled())
+        static_cast<SVGStyledElement*>(targetElement)->setInstanceUpdatesBlocked(true);
         
+    bool attributeIsCSSProperty = isTargetAttributeCSSProperty(targetElement, attributeName);
+    // Stop animation, if attributeType is set to CSS by the user, but the attribute itself is not a CSS property.
+    if (!attributeIsCSSProperty && attributeType() == AttributeTypeCSS)
+        return;
+
     ExceptionCode ec;
-    bool isCSS = targetAttributeIsCSS();
-    if (isCSS) {
+    if (attributeIsCSSProperty) {
         // FIXME: This should set the override style, not the inline style.
         // Sadly override styles are not yet implemented.
-        target->style()->setProperty(attributeName, value, "", ec);
+        targetElement->style()->setProperty(attributeName, value, "", ec);
     } else {
         // FIXME: This should set the 'presentation' value, not the actual 
         // attribute value. Whatever that means in practice.
-        target->setAttribute(attributeName, value, ec);
+        targetElement->setAttribute(attributeName, value, ec);
     }
     
-    if (target->isStyled())
-        static_cast<SVGStyledElement*>(target)->setInstanceUpdatesBlocked(false);
+    if (targetElement->isStyled())
+        static_cast<SVGStyledElement*>(targetElement)->setInstanceUpdatesBlocked(false);
     
     // If the target element is used in an <use> instance tree, update that as well.
-    const HashSet<SVGElementInstance*>& instances = target->instancesForElement();
+    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) {
         SVGElement* shadowTreeElement = (*it)->shadowTreeElement();
         if (!shadowTreeElement)
             continue;
-        if (isCSS)
+        if (attributeIsCSSProperty)
             shadowTreeElement->style()->setProperty(attributeName, value, "", ec);
         else
             shadowTreeElement->setAttribute(attributeName, value, ec);
index 59d7f9e..d968f35 100644 (file)
@@ -55,8 +55,8 @@ public:
     virtual void beginElementAt(float offset);
     virtual void endElement();
     virtual void endElementAt(float offset);
-    
-    static bool attributeIsCSS(const String& attributeName);
+
+    static bool isTargetAttributeCSSProperty(SVGElement*, const String&);
 
 protected:
     SVGAnimationElement(const QualifiedName&, Document*);
@@ -80,7 +80,6 @@ protected:
     
     String targetAttributeBaseValue() const;
     void setTargetAttributeAnimatedValue(const String&);
-    bool targetAttributeIsCSS() const;
     
     bool isAdditive() const;
     bool isAccumulated() const;
index 7f3b041..5740b05 100644 (file)
@@ -273,6 +273,11 @@ AnimatedAttributeType SVGStyledElement::animatedPropertyTypeForCSSProperty(const
     return AnimatedUnknown;
 }
 
+bool SVGStyledElement::isAnimatableCSSProperty(const QualifiedName& attrName)
+{
+    return cssPropertyToTypeMap().contains(attrName);
+}
+
 void SVGStyledElement::fillPassedAttributeToPropertyTypeMap(AttributeToPropertyTypeMap& attributeToPropertyTypeMap)
 {
     attributeToPropertyTypeMap.set(HTMLNames::classAttr, AnimatedString);
index 85a2b5a..b6c0b96 100644 (file)
@@ -53,6 +53,7 @@ public:
     void setInstanceUpdatesBlocked(bool);
 
     AnimatedAttributeType animatedPropertyTypeForCSSProperty(const QualifiedName&);
+    static bool isAnimatableCSSProperty(const QualifiedName&);
 
     virtual AffineTransform localCoordinateSpaceTransform(SVGLocatable::CTMScope) const;
 
index 3251d5b..cf7122e 100644 (file)
@@ -196,15 +196,15 @@ String SMILTimeContainer::baseValueFor(ElementAttributePair key)
     if (it != m_savedBaseValues.end())
         return it->second;
     
-    SVGElement* target = key.first;
+    SVGElement* targetElement = key.first;
     String attributeName = key.second;
-    ASSERT(target);
+    ASSERT(targetElement);
     ASSERT(!attributeName.isEmpty());
     String baseValue;
-    if (SVGAnimationElement::attributeIsCSS(attributeName))
-        baseValue = computedStyle(target)->getPropertyValue(cssPropertyID(attributeName));
+    if (SVGAnimationElement::isTargetAttributeCSSProperty(targetElement, attributeName))
+        baseValue = computedStyle(targetElement)->getPropertyValue(cssPropertyID(attributeName));
     else
-        baseValue = target->getAttribute(attributeName);
+        baseValue = targetElement->getAttribute(attributeName);
     m_savedBaseValues.add(key, baseValue);
     return baseValue;
 }