Enable animVal support for SVGTransformList
https://bugs.webkit.org/show_bug.cgi?id=80758

Reviewed by Antti Koivisto.

Source/WebCore:

Enable animVal support for SVGTransformList. SVGTransformLists are only animatable
via <animateTransform>, not via <animate> directly. Still we can handle it in the
same framework as all other types used for <animate>, as we also need proper animVal
support for <animateTransform>.

This patch removes the special <animateTransform> implementation, and lets
SVGAnimateTransformElement inherit from SVGAnimateElement, just like its done
for SVGAnimateColorElement & SVGSetElement.

All existing code (calculateFromAndToValues/FromAndByValues/etc..) are moved from
SVGAnimateTransform right into the SVGAnimatedTransformListAnimator.

This doesn't change <animateTransform> behavior, it just simplies the code
and enables animVal support for SVGTransformLists - all covered by existing tests.

* CMakeLists.txt:
* GNUmakefile.list.am:
* Target.pri:
* WebCore.gypi:
* WebCore.xcodeproj/project.pbxproj:
* svg/SVGAllInOne.cpp:
* svg/SVGAnimateElement.cpp:
(WebCore::SVGAnimateElement::SVGAnimateElement):
(WebCore::SVGAnimateElement::determineAnimatedPropertyType):
(WebCore::SVGAnimateElement::calculateAnimatedValue):
(WebCore::SVGAnimateElement::applyResultsToTarget):
* svg/SVGAnimateTransformElement.cpp:
(WebCore::SVGAnimateTransformElement::SVGAnimateTransformElement):
(WebCore::SVGAnimateTransformElement::hasValidAttributeType):
(WebCore::SVGAnimateTransformElement::parseAttribute):
* svg/SVGAnimateTransformElement.h:
(WebCore::SVGAnimateTransformElement::transformType):
(SVGAnimateTransformElement):
* svg/SVGAnimatedTransformList.cpp: Added.
(WebCore):
(WebCore::SVGAnimatedTransformListAnimator::SVGAnimatedTransformListAnimator):
(WebCore::SVGAnimatedTransformListAnimator::constructFromString):
(WebCore::SVGAnimatedTransformListAnimator::constructFromCopy):
(WebCore::SVGAnimatedTransformListAnimator::calculateFromAndToValues):
(WebCore::SVGAnimatedTransformListAnimator::calculateFromAndByValues):
(WebCore::SVGAnimatedTransformListAnimator::calculateAnimatedValue):
(WebCore::SVGAnimatedTransformListAnimator::calculateDistance):
* svg/SVGAnimatedTransformList.h:
(WebCore):
(SVGAnimatedTransformListAnimator):
(WebCore::SVGAnimatedTransformListAnimator::~SVGAnimatedTransformListAnimator):
* svg/SVGAnimatedType.cpp:
(WebCore::SVGAnimatedType::~SVGAnimatedType):
(WebCore::SVGAnimatedType::createTransformList):
(WebCore):
(WebCore::SVGAnimatedType::transformList):
(WebCore::SVGAnimatedType::valueAsString):
(WebCore::SVGAnimatedType::setValueAsString):
(WebCore::SVGAnimatedType::supportsAnimVal):
(WebCore::SVGAnimatedType::setVariantValue):
* svg/SVGAnimatedType.h:
(WebCore):
(SVGAnimatedType):
* svg/SVGAnimatorFactory.h:
(WebCore::SVGAnimatorFactory::create):
* svg/SVGGradientElement.cpp:
(WebCore::SVGGradientElement::parseAttribute):
* svg/SVGPatternElement.cpp:
(WebCore::SVGPatternElement::parseAttribute):
* svg/SVGStyledTransformableElement.cpp:
(WebCore::SVGStyledTransformableElement::parseAttribute):
* svg/SVGTextElement.cpp:
(WebCore::SVGTextElement::parseAttribute):
* svg/SVGTransform.cpp:
(WebCore::SVGTransform::transformTypePrefixForParsing):
(WebCore):
(WebCore::SVGTransform::valueAsString):
* svg/SVGTransform.h:
(SVGTransform):
* svg/SVGTransformList.cpp:
(WebCore::SVGTransformList::parse):
(WebCore):
* svg/SVGTransformList.h:
(SVGTransformList):
* svg/SVGTransformable.cpp:
(WebCore::SVGTransformable::parseTransformType):
* svg/SVGTransformable.h:
(WebCore):
* svg/SVGViewSpec.cpp:
(WebCore::SVGViewSpec::setTransform):

LayoutTests:

Rebaseline tests after enabling animVal support SVGAnimateTransformElement/SVGTransformList.

* svg/animations/animate-gradient-transform-expected.txt:
* svg/animations/animateTransform-pattern-transform-expected.txt:
* svg/animations/script-tests/animate-gradient-transform.js:
(sample1):
(sample2):
(sample3):
(executeTest):
* svg/animations/script-tests/animateTransform-pattern-transform.js:
(sample1):
(sample2):
(sample3):
(sample4):
(executeTest):

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@110838 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/LayoutTests/ChangeLog b/LayoutTests/ChangeLog
index ddad5db..ce29142 100644
--- a/LayoutTests/ChangeLog
+++ b/LayoutTests/ChangeLog
@@ -1,3 +1,26 @@
+2012-03-15  Nikolas Zimmermann  <nzimmermann@rim.com>
+
+        Enable animVal support for SVGTransformList
+        https://bugs.webkit.org/show_bug.cgi?id=80758
+
+        Reviewed by Antti Koivisto.
+
+        Rebaseline tests after enabling animVal support SVGAnimateTransformElement/SVGTransformList.
+
+        * svg/animations/animate-gradient-transform-expected.txt:
+        * svg/animations/animateTransform-pattern-transform-expected.txt:
+        * svg/animations/script-tests/animate-gradient-transform.js:
+        (sample1):
+        (sample2):
+        (sample3):
+        (executeTest):
+        * svg/animations/script-tests/animateTransform-pattern-transform.js:
+        (sample1):
+        (sample2):
+        (sample3):
+        (sample4):
+        (executeTest):
+
 2012-03-13  Nikolas Zimmermann  <nzimmermann@rim.com>
 
         Enable animVal support for SVGLengthList
diff --git a/LayoutTests/svg/animations/animate-gradient-transform-expected.txt b/LayoutTests/svg/animations/animate-gradient-transform-expected.txt
index eb62209..cd72814 100644
--- a/LayoutTests/svg/animations/animate-gradient-transform-expected.txt
+++ b/LayoutTests/svg/animations/animate-gradient-transform-expected.txt
@@ -5,12 +5,31 @@
 On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
 
 
-PASS gradient.gradientTransform.baseVal.consolidate().matrix.e is 0
-PASS gradient.gradientTransform.animVal.consolidate().matrix.e threw exception Error: NO_MODIFICATION_ALLOWED_ERR: DOM Exception 7.
-PASS gradient.gradientTransform.baseVal.consolidate().matrix.e is 100
-PASS gradient.gradientTransform.animVal.consolidate().matrix.e threw exception Error: NO_MODIFICATION_ALLOWED_ERR: DOM Exception 7.
-PASS gradient.gradientTransform.baseVal.consolidate().matrix.e is 200
-PASS gradient.gradientTransform.animVal.consolidate().matrix.e threw exception Error: NO_MODIFICATION_ALLOWED_ERR: DOM Exception 7.
+PASS gradient.gradientTransform.animVal.consolidate() threw exception Error: NO_MODIFICATION_ALLOWED_ERR: DOM Exception 7.
+PASS gradient.gradientTransform.animVal.numberOfItems is 1
+PASS gradient.gradientTransform.animVal.getItem(0).matrix.e is 0
+PASS gradient.gradientTransform.animVal.getItem(0).type is SVGTransform.SVG_TRANSFORM_TRANSLATE
+PASS gradient.gradientTransform.baseVal.numberOfItems is 1
+PASS gradient.gradientTransform.baseVal.getItem(0).type is SVGTransform.SVG_TRANSFORM_TRANSLATE
+PASS gradient.gradientTransform.baseVal.getItem(0).matrix.e is 0
+PASS gradient.gradientTransform.animVal.numberOfItems is 1
+PASS gradient.gradientTransform.animVal.getItem(0).type is SVGTransform.SVG_TRANSFORM_TRANSLATE
+PASS gradient.gradientTransform.animVal.getItem(0).matrix.e is 100
+PASS gradient.gradientTransform.baseVal.numberOfItems is 1
+PASS gradient.gradientTransform.baseVal.getItem(0).type is SVGTransform.SVG_TRANSFORM_TRANSLATE
+PASS gradient.gradientTransform.baseVal.getItem(0).matrix.e is 0
+PASS gradient.gradientTransform.animVal.numberOfItems is 1
+PASS gradient.gradientTransform.animVal.getItem(0).type is SVGTransform.SVG_TRANSFORM_TRANSLATE
+PASS gradient.gradientTransform.animVal.getItem(0).matrix.e is 200
+PASS gradient.gradientTransform.baseVal.numberOfItems is 1
+PASS gradient.gradientTransform.baseVal.getItem(0).type is SVGTransform.SVG_TRANSFORM_TRANSLATE
+PASS gradient.gradientTransform.baseVal.getItem(0).matrix.e is 0
+PASS gradient.gradientTransform.animVal.numberOfItems is 1
+PASS gradient.gradientTransform.animVal.getItem(0).type is SVGTransform.SVG_TRANSFORM_TRANSLATE
+PASS gradient.gradientTransform.animVal.getItem(0).matrix.e is 200
+PASS gradient.gradientTransform.baseVal.numberOfItems is 1
+PASS gradient.gradientTransform.baseVal.getItem(0).type is SVGTransform.SVG_TRANSFORM_TRANSLATE
+PASS gradient.gradientTransform.baseVal.getItem(0).matrix.e is 0
 PASS successfullyParsed is true
 
 TEST COMPLETE
diff --git a/LayoutTests/svg/animations/animateTransform-pattern-transform-expected.txt b/LayoutTests/svg/animations/animateTransform-pattern-transform-expected.txt
index fec4f0b..8094fac 100644
--- a/LayoutTests/svg/animations/animateTransform-pattern-transform-expected.txt
+++ b/LayoutTests/svg/animations/animateTransform-pattern-transform-expected.txt
@@ -5,14 +5,22 @@
 On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
 
 
+PASS pattern.patternTransform.animVal.numberOfItems is 0
+PASS pattern.patternTransform.baseVal.numberOfItems is 0
+PASS pattern.patternTransform.animVal.numberOfItems is 1
+PASS pattern.patternTransform.animVal.getItem(0).type is SVGTransform.SVG_TRANSFORM_SCALE
 PASS pattern.patternTransform.animVal.getItem(0).matrix.a is 1
-PASS pattern.patternTransform.baseVal.getItem(0).matrix.a is 1
+PASS pattern.patternTransform.baseVal.numberOfItems is 0
+PASS pattern.patternTransform.animVal.numberOfItems is 1
+PASS pattern.patternTransform.animVal.getItem(0).type is SVGTransform.SVG_TRANSFORM_SCALE
 PASS pattern.patternTransform.animVal.getItem(0).matrix.a is 1.5
-PASS pattern.patternTransform.baseVal.getItem(0).matrix.a is 1.5
+PASS pattern.patternTransform.baseVal.numberOfItems is 0
+PASS pattern.patternTransform.animVal.numberOfItems is 1
+PASS pattern.patternTransform.animVal.getItem(0).type is SVGTransform.SVG_TRANSFORM_SCALE
 PASS pattern.patternTransform.animVal.getItem(0).matrix.a is 2
-PASS pattern.patternTransform.baseVal.getItem(0).matrix.a is 2
-PASS pattern.patternTransform.animVal.getItem(0).matrix.a is 1
-PASS pattern.patternTransform.baseVal.getItem(0).matrix.a is 1
+PASS pattern.patternTransform.baseVal.numberOfItems is 0
+PASS pattern.patternTransform.animVal.numberOfItems is 0
+PASS pattern.patternTransform.baseVal.numberOfItems is 0
 PASS successfullyParsed is true
 
 TEST COMPLETE
diff --git a/LayoutTests/svg/animations/script-tests/animate-gradient-transform.js b/LayoutTests/svg/animations/script-tests/animate-gradient-transform.js
index 8f93abf..b62146b 100644
--- a/LayoutTests/svg/animations/script-tests/animate-gradient-transform.js
+++ b/LayoutTests/svg/animations/script-tests/animate-gradient-transform.js
@@ -44,20 +44,36 @@
 // Setup animation test
 function sample1() {
     // Check initial conditions
-    shouldBeCloseEnough("gradient.gradientTransform.baseVal.consolidate().matrix.e", "0");
-    shouldThrow("gradient.gradientTransform.animVal.consolidate().matrix.e");
+    shouldThrow("gradient.gradientTransform.animVal.consolidate()");
+    shouldBe("gradient.gradientTransform.animVal.numberOfItems", "1");
+    shouldBeCloseEnough("gradient.gradientTransform.animVal.getItem(0).matrix.e", "0");
+    shouldBe("gradient.gradientTransform.animVal.getItem(0).type", "SVGTransform.SVG_TRANSFORM_TRANSLATE");
+
+    shouldBe("gradient.gradientTransform.baseVal.numberOfItems", "1");
+    shouldBe("gradient.gradientTransform.baseVal.getItem(0).type", "SVGTransform.SVG_TRANSFORM_TRANSLATE");
+    shouldBe("gradient.gradientTransform.baseVal.getItem(0).matrix.e", "0");
 }
 
 function sample2() {
     // Check half-time conditions
-    shouldBeCloseEnough("gradient.gradientTransform.baseVal.consolidate().matrix.e", "100");
-    shouldThrow("gradient.gradientTransform.animVal.consolidate().matrix.e");
+    shouldBe("gradient.gradientTransform.animVal.numberOfItems", "1");
+    shouldBe("gradient.gradientTransform.animVal.getItem(0).type", "SVGTransform.SVG_TRANSFORM_TRANSLATE");
+    shouldBeCloseEnough("gradient.gradientTransform.animVal.getItem(0).matrix.e", "100");
+
+    shouldBe("gradient.gradientTransform.baseVal.numberOfItems", "1");
+    shouldBe("gradient.gradientTransform.baseVal.getItem(0).type", "SVGTransform.SVG_TRANSFORM_TRANSLATE");
+    shouldBe("gradient.gradientTransform.baseVal.getItem(0).matrix.e", "0");
 }
 
 function sample3() {
     // Check end conditions
-    shouldBeCloseEnough("gradient.gradientTransform.baseVal.consolidate().matrix.e", "200");
-    shouldThrow("gradient.gradientTransform.animVal.consolidate().matrix.e");
+    shouldBe("gradient.gradientTransform.animVal.numberOfItems", "1");
+    shouldBe("gradient.gradientTransform.animVal.getItem(0).type", "SVGTransform.SVG_TRANSFORM_TRANSLATE");
+    shouldBeCloseEnough("gradient.gradientTransform.animVal.getItem(0).matrix.e", "200");
+
+    shouldBe("gradient.gradientTransform.baseVal.numberOfItems", "1");
+    shouldBe("gradient.gradientTransform.baseVal.getItem(0).type", "SVGTransform.SVG_TRANSFORM_TRANSLATE");
+    shouldBe("gradient.gradientTransform.baseVal.getItem(0).matrix.e", "0");
 }
 
 function executeTest() {  
@@ -65,7 +81,8 @@
         // [animationId, time, sampleCallback]
         ["animation", 0.0, sample1],
         ["animation", 2.0, sample2],
-        ["animation", 4.0, sample3]
+        ["animation", 3.999, sample3],
+        ["animation", 4.001, sample3]
     ];
 
     runAnimationTest(expectedValues);
diff --git a/LayoutTests/svg/animations/script-tests/animateTransform-pattern-transform.js b/LayoutTests/svg/animations/script-tests/animateTransform-pattern-transform.js
index cf71f7a..3c2ce4d 100644
--- a/LayoutTests/svg/animations/script-tests/animateTransform-pattern-transform.js
+++ b/LayoutTests/svg/animations/script-tests/animateTransform-pattern-transform.js
@@ -41,28 +41,44 @@
 // Setup animation test
 function sample1() {
     // Check initial/end conditions
-    shouldBeCloseEnough("pattern.patternTransform.animVal.getItem(0).matrix.a", "1");
-    shouldBeCloseEnough("pattern.patternTransform.baseVal.getItem(0).matrix.a", "1");
+    shouldBe("pattern.patternTransform.animVal.numberOfItems", "0");
+    shouldBe("pattern.patternTransform.baseVal.numberOfItems", "0");
 }
 
 function sample2() {
-    // Check half-time conditions
-    shouldBeCloseEnough("pattern.patternTransform.animVal.getItem(0).matrix.a", "1.5");
-    shouldBeCloseEnough("pattern.patternTransform.baseVal.getItem(0).matrix.a", "1.5");
+    shouldBe("pattern.patternTransform.animVal.numberOfItems", "1");
+    shouldBe("pattern.patternTransform.animVal.getItem(0).type", "SVGTransform.SVG_TRANSFORM_SCALE");
+    shouldBeCloseEnough("pattern.patternTransform.animVal.getItem(0).matrix.a", "1");
+
+    shouldBe("pattern.patternTransform.baseVal.numberOfItems", "0");
 }
 
 function sample3() {
+    // Check half-time conditions
+    shouldBe("pattern.patternTransform.animVal.numberOfItems", "1");
+    shouldBe("pattern.patternTransform.animVal.getItem(0).type", "SVGTransform.SVG_TRANSFORM_SCALE");
+    shouldBeCloseEnough("pattern.patternTransform.animVal.getItem(0).matrix.a", "1.5");
+
+    shouldBe("pattern.patternTransform.baseVal.numberOfItems", "0");
+}
+
+function sample4() {
+    // Check half-time conditions
+    shouldBe("pattern.patternTransform.animVal.numberOfItems", "1");
+    shouldBe("pattern.patternTransform.animVal.getItem(0).type", "SVGTransform.SVG_TRANSFORM_SCALE");
     shouldBeCloseEnough("pattern.patternTransform.animVal.getItem(0).matrix.a", "2");
-    shouldBeCloseEnough("pattern.patternTransform.baseVal.getItem(0).matrix.a", "2");
+
+    shouldBe("pattern.patternTransform.baseVal.numberOfItems", "0");
 }
 
 function executeTest() {
     const expectedValues = [
         // [animationId, time, sampleCallback]
         ["animation", 0.0,   sample1],
-        ["animation", 2.0,   sample2],
-        ["animation", 3.999, sample3],
-        ["animation", 4.001, sample1]
+        ["animation", 0.001, sample2],
+        ["animation", 2.0,   sample3],
+        ["animation", 3.999, sample4],
+        ["animation", 4.0,   sample1]
     ];
 
     runAnimationTest(expectedValues);
diff --git a/Source/WebCore/CMakeLists.txt b/Source/WebCore/CMakeLists.txt
index da4c9c9..42fa002 100644
--- a/Source/WebCore/CMakeLists.txt
+++ b/Source/WebCore/CMakeLists.txt
@@ -1770,6 +1770,7 @@
         svg/SVGAnimatedPreserveAspectRatio.cpp
         svg/SVGAnimatedRect.cpp
         svg/SVGAnimatedString.cpp
+        svg/SVGAnimatedTransformList.cpp
         svg/SVGAnimatedType.cpp
         svg/SVGAnimateElement.cpp
         svg/SVGAnimateMotionElement.cpp
diff --git a/Source/WebCore/ChangeLog b/Source/WebCore/ChangeLog
index 37e9852..d2f9307 100644
--- a/Source/WebCore/ChangeLog
+++ b/Source/WebCore/ChangeLog
@@ -1,3 +1,96 @@
+2012-03-15  Nikolas Zimmermann  <nzimmermann@rim.com>
+
+        Enable animVal support for SVGTransformList
+        https://bugs.webkit.org/show_bug.cgi?id=80758
+
+        Reviewed by Antti Koivisto.
+
+        Enable animVal support for SVGTransformList. SVGTransformLists are only animatable
+        via <animateTransform>, not via <animate> directly. Still we can handle it in the
+        same framework as all other types used for <animate>, as we also need proper animVal
+        support for <animateTransform>.
+
+        This patch removes the special <animateTransform> implementation, and lets
+        SVGAnimateTransformElement inherit from SVGAnimateElement, just like its done
+        for SVGAnimateColorElement & SVGSetElement.
+
+        All existing code (calculateFromAndToValues/FromAndByValues/etc..) are moved from
+        SVGAnimateTransform right into the SVGAnimatedTransformListAnimator.
+
+        This doesn't change <animateTransform> behavior, it just simplies the code
+        and enables animVal support for SVGTransformLists - all covered by existing tests.
+
+        * CMakeLists.txt:
+        * GNUmakefile.list.am:
+        * Target.pri:
+        * WebCore.gypi:
+        * WebCore.xcodeproj/project.pbxproj:
+        * svg/SVGAllInOne.cpp:
+        * svg/SVGAnimateElement.cpp:
+        (WebCore::SVGAnimateElement::SVGAnimateElement):
+        (WebCore::SVGAnimateElement::determineAnimatedPropertyType):
+        (WebCore::SVGAnimateElement::calculateAnimatedValue):
+        (WebCore::SVGAnimateElement::applyResultsToTarget):
+        * svg/SVGAnimateTransformElement.cpp:
+        (WebCore::SVGAnimateTransformElement::SVGAnimateTransformElement):
+        (WebCore::SVGAnimateTransformElement::hasValidAttributeType):
+        (WebCore::SVGAnimateTransformElement::parseAttribute):
+        * svg/SVGAnimateTransformElement.h:
+        (WebCore::SVGAnimateTransformElement::transformType):
+        (SVGAnimateTransformElement):
+        * svg/SVGAnimatedTransformList.cpp: Added.
+        (WebCore):
+        (WebCore::SVGAnimatedTransformListAnimator::SVGAnimatedTransformListAnimator):
+        (WebCore::SVGAnimatedTransformListAnimator::constructFromString):
+        (WebCore::SVGAnimatedTransformListAnimator::constructFromCopy):
+        (WebCore::SVGAnimatedTransformListAnimator::calculateFromAndToValues):
+        (WebCore::SVGAnimatedTransformListAnimator::calculateFromAndByValues):
+        (WebCore::SVGAnimatedTransformListAnimator::calculateAnimatedValue):
+        (WebCore::SVGAnimatedTransformListAnimator::calculateDistance):
+        * svg/SVGAnimatedTransformList.h:
+        (WebCore):
+        (SVGAnimatedTransformListAnimator):
+        (WebCore::SVGAnimatedTransformListAnimator::~SVGAnimatedTransformListAnimator):
+        * svg/SVGAnimatedType.cpp:
+        (WebCore::SVGAnimatedType::~SVGAnimatedType):
+        (WebCore::SVGAnimatedType::createTransformList):
+        (WebCore):
+        (WebCore::SVGAnimatedType::transformList):
+        (WebCore::SVGAnimatedType::valueAsString):
+        (WebCore::SVGAnimatedType::setValueAsString):
+        (WebCore::SVGAnimatedType::supportsAnimVal):
+        (WebCore::SVGAnimatedType::setVariantValue):
+        * svg/SVGAnimatedType.h:
+        (WebCore):
+        (SVGAnimatedType):
+        * svg/SVGAnimatorFactory.h:
+        (WebCore::SVGAnimatorFactory::create):
+        * svg/SVGGradientElement.cpp:
+        (WebCore::SVGGradientElement::parseAttribute):
+        * svg/SVGPatternElement.cpp:
+        (WebCore::SVGPatternElement::parseAttribute):
+        * svg/SVGStyledTransformableElement.cpp:
+        (WebCore::SVGStyledTransformableElement::parseAttribute):
+        * svg/SVGTextElement.cpp:
+        (WebCore::SVGTextElement::parseAttribute):
+        * svg/SVGTransform.cpp:
+        (WebCore::SVGTransform::transformTypePrefixForParsing):
+        (WebCore):
+        (WebCore::SVGTransform::valueAsString):
+        * svg/SVGTransform.h:
+        (SVGTransform):
+        * svg/SVGTransformList.cpp:
+        (WebCore::SVGTransformList::parse):
+        (WebCore):
+        * svg/SVGTransformList.h:
+        (SVGTransformList):
+        * svg/SVGTransformable.cpp:
+        (WebCore::SVGTransformable::parseTransformType):
+        * svg/SVGTransformable.h:
+        (WebCore):
+        * svg/SVGViewSpec.cpp:
+        (WebCore::SVGViewSpec::setTransform):
+
 2012-03-13  Nikolas Zimmermann  <nzimmermann@rim.com>
 
         Enable animVal support for SVGLengthList
diff --git a/Source/WebCore/GNUmakefile.list.am b/Source/WebCore/GNUmakefile.list.am
index 9b58c95..a87ae1c 100644
--- a/Source/WebCore/GNUmakefile.list.am
+++ b/Source/WebCore/GNUmakefile.list.am
@@ -4100,6 +4100,7 @@
 	Source/WebCore/svg/SVGAnimatedRect.h \
 	Source/WebCore/svg/SVGAnimatedString.cpp \
 	Source/WebCore/svg/SVGAnimatedString.h \
+	Source/WebCore/svg/SVGAnimatedTransformList.cpp \
 	Source/WebCore/svg/SVGAnimatedTransformList.h \
 	Source/WebCore/svg/SVGAnimatedType.cpp \
 	Source/WebCore/svg/SVGAnimatedType.h \
diff --git a/Source/WebCore/Target.pri b/Source/WebCore/Target.pri
index ecfd647..063aa40 100644
--- a/Source/WebCore/Target.pri
+++ b/Source/WebCore/Target.pri
@@ -3501,6 +3501,7 @@
               svg/SVGAnimatedPreserveAspectRatio.cpp \
               svg/SVGAnimatedRect.cpp \
               svg/SVGAnimatedString.cpp \
+              svg/SVGAnimatedTransformList.cpp \
               svg/SVGAnimatedType.cpp \
               svg/SVGAnimateElement.cpp \
               svg/SVGAnimateMotionElement.cpp \
diff --git a/Source/WebCore/WebCore.gypi b/Source/WebCore/WebCore.gypi
index 75f0c8f..851b8b5 100644
--- a/Source/WebCore/WebCore.gypi
+++ b/Source/WebCore/WebCore.gypi
@@ -5813,6 +5813,7 @@
             'svg/SVGAnimatedPreserveAspectRatio.cpp',
             'svg/SVGAnimatedRect.cpp',
             'svg/SVGAnimatedString.cpp',
+            'svg/SVGAnimatedTransformList.cpp',
             'svg/SVGAnimatedType.cpp',
             'svg/SVGAnimateElement.cpp',
             'svg/SVGAnimateElement.h',
diff --git a/Source/WebCore/WebCore.xcodeproj/project.pbxproj b/Source/WebCore/WebCore.xcodeproj/project.pbxproj
index d8e57db..51fbf42 100644
--- a/Source/WebCore/WebCore.xcodeproj/project.pbxproj
+++ b/Source/WebCore/WebCore.xcodeproj/project.pbxproj
@@ -1788,6 +1788,7 @@
 		7134496D146941B300720312 /* SVGLengthContext.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7134496B146941B300720312 /* SVGLengthContext.cpp */; };
 		7134496E146941B300720312 /* SVGLengthContext.h in Headers */ = {isa = PBXBuildFile; fileRef = 7134496C146941B300720312 /* SVGLengthContext.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		71537A01146BD9D7008BD615 /* SVGPathData.h in Headers */ = {isa = PBXBuildFile; fileRef = 715379FF146BD9D6008BD615 /* SVGPathData.h */; };
+		7157F062150B6564006EAABD /* SVGAnimatedTransformList.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7157F061150B6564006EAABD /* SVGAnimatedTransformList.cpp */; };
 		71FB967B1383D64600AC8A4C /* SVGAnimatedEnumerationPropertyTearOff.h in Headers */ = {isa = PBXBuildFile; fileRef = 71FB967A1383D64600AC8A4C /* SVGAnimatedEnumerationPropertyTearOff.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		72626E020EF022FE00A07E20 /* FontFastPath.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 72626E010EF022FE00A07E20 /* FontFastPath.cpp */; };
 		750D029311D0E7F300BD1B27 /* RenderInputSpeech.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 750D029111D0E7F300BD1B27 /* RenderInputSpeech.cpp */; };
@@ -8739,6 +8740,7 @@
 		7134496C146941B300720312 /* SVGLengthContext.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SVGLengthContext.h; sourceTree = "<group>"; };
 		715379FE146BD9D6008BD615 /* SVGPathData.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SVGPathData.cpp; sourceTree = "<group>"; };
 		715379FF146BD9D6008BD615 /* SVGPathData.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SVGPathData.h; sourceTree = "<group>"; };
+		7157F061150B6564006EAABD /* SVGAnimatedTransformList.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SVGAnimatedTransformList.cpp; sourceTree = "<group>"; };
 		71FB967A1383D64600AC8A4C /* SVGAnimatedEnumerationPropertyTearOff.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SVGAnimatedEnumerationPropertyTearOff.h; sourceTree = "<group>"; };
 		72626E010EF022FE00A07E20 /* FontFastPath.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FontFastPath.cpp; sourceTree = "<group>"; };
 		750D029111D0E7F300BD1B27 /* RenderInputSpeech.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RenderInputSpeech.cpp; sourceTree = "<group>"; };
@@ -18589,6 +18591,7 @@
 				43A6266613B3D11000AC94B8 /* SVGAnimatedString.cpp */,
 				084DB59A128008CC002A6D64 /* SVGAnimatedString.h */,
 				B22277F60D00BF1F0071B782 /* SVGAnimatedString.idl */,
+				7157F061150B6564006EAABD /* SVGAnimatedTransformList.cpp */,
 				08250938128BD4D800E2ED8E /* SVGAnimatedTransformList.h */,
 				B22277F80D00BF1F0071B782 /* SVGAnimatedTransformList.idl */,
 				43A0F0B513ACCCFF00A5F0A7 /* SVGAnimatedType.cpp */,
@@ -27556,6 +27559,7 @@
 				450CEBF015073BBE002BB149 /* LabelableElement.cpp in Sources */,
 				C5B4C24E1509236C00A6EF37 /* WebCoreNSURLExtras.mm in Sources */,
 				9B2B7AC11509850A008932CC /* MicroDataItemValue.cpp in Sources */,
+				7157F062150B6564006EAABD /* SVGAnimatedTransformList.cpp in Sources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
diff --git a/Source/WebCore/svg/SVGAllInOne.cpp b/Source/WebCore/svg/SVGAllInOne.cpp
index e1a7417..4f09d5c 100644
--- a/Source/WebCore/svg/SVGAllInOne.cpp
+++ b/Source/WebCore/svg/SVGAllInOne.cpp
@@ -46,6 +46,7 @@
 #include "SVGAnimatedPreserveAspectRatio.cpp"
 #include "SVGAnimatedRect.cpp"
 #include "SVGAnimatedString.cpp"
+#include "SVGAnimatedTransformList.cpp"
 #include "SVGAnimatedType.cpp"
 #include "SVGAnimateElement.cpp"
 #include "SVGAnimateMotionElement.cpp"
diff --git a/Source/WebCore/svg/SVGAnimateElement.cpp b/Source/WebCore/svg/SVGAnimateElement.cpp
index 06e4c81..059ebc6 100644
--- a/Source/WebCore/svg/SVGAnimateElement.cpp
+++ b/Source/WebCore/svg/SVGAnimateElement.cpp
@@ -43,7 +43,7 @@
     , m_toPropertyValueType(RegularPropertyValue)
     , m_animatedProperty(0)
 {
-    ASSERT(hasTagName(SVGNames::animateTag) || hasTagName(SVGNames::setTag) || hasTagName(SVGNames::animateColorTag));
+    ASSERT(hasTagName(SVGNames::animateTag) || hasTagName(SVGNames::setTag) || hasTagName(SVGNames::animateColorTag) || hasTagName(SVGNames::animateTransformTag));
 }
 
 PassRefPtr<SVGAnimateElement> SVGAnimateElement::create(const QualifiedName& tagName, Document* document)
@@ -130,7 +130,7 @@
 
     // Animations of transform lists are not allowed for <animate> or <set>
     // http://www.w3.org/TR/SVG/animate.html#AnimationAttributesAndProperties
-    if (type == AnimatedTransformList)
+    if (type == AnimatedTransformList && !hasTagName(SVGNames::animateTransformTag))
         return AnimatedUnknown;
 
     return type;
@@ -166,7 +166,7 @@
 
     ASSERT(percentage >= 0 && percentage <= 1);
     ASSERT(m_animatedPropertyType != AnimatedEnumeration);
-    ASSERT(m_animatedPropertyType != AnimatedTransformList);
+    ASSERT(m_animatedPropertyType != AnimatedTransformList || hasTagName(SVGNames::animateTransformTag));
     ASSERT(m_animatedPropertyType != AnimatedUnknown);
     ASSERT(m_animator);
     ASSERT(m_animator->type() == m_animatedPropertyType);
@@ -176,6 +176,7 @@
 
     ASSERT(resultElement->hasTagName(SVGNames::animateTag)
         || resultElement->hasTagName(SVGNames::animateColorTag)
+        || resultElement->hasTagName(SVGNames::animateTransformTag)
         || resultElement->hasTagName(SVGNames::setTag));
 
     SVGAnimateElement* resultAnimationElement = static_cast<SVGAnimateElement*>(resultElement);
@@ -250,7 +251,7 @@
 void SVGAnimateElement::applyResultsToTarget()
 {
     ASSERT(m_animatedPropertyType != AnimatedEnumeration);
-    ASSERT(m_animatedPropertyType != AnimatedTransformList);
+    ASSERT(m_animatedPropertyType != AnimatedTransformList || hasTagName(SVGNames::animateTransformTag));
     ASSERT(m_animatedPropertyType != AnimatedUnknown);
     ASSERT(m_animatedType);
     setTargetAttributeAnimatedValue(m_animatedType.get());
diff --git a/Source/WebCore/svg/SVGAnimateTransformElement.cpp b/Source/WebCore/svg/SVGAnimateTransformElement.cpp
index c1bb199..faacd4e 100644
--- a/Source/WebCore/svg/SVGAnimateTransformElement.cpp
+++ b/Source/WebCore/svg/SVGAnimateTransformElement.cpp
@@ -25,32 +25,15 @@
 #if ENABLE(SVG)
 #include "SVGAnimateTransformElement.h"
 
-#include "AffineTransform.h"
 #include "Attribute.h"
-#include "RenderObject.h"
-#include "RenderSVGResource.h"
-#include "SVGAngle.h"
-#include "SVGElementInstance.h"
-#include "SVGGradientElement.h"
 #include "SVGNames.h"
-#include "SVGParserUtilities.h"
-#include "SVGPatternElement.h"
-#include "SVGSVGElement.h"
-#include "SVGStyledTransformableElement.h"
-#include "SVGTextElement.h"
-#include "SVGTransform.h"
-#include "SVGTransformList.h"
-#include "SVGUseElement.h"
-#include <wtf/MathExtras.h>
-
-using namespace std;
+#include "SVGTransformable.h"
 
 namespace WebCore {
 
 inline SVGAnimateTransformElement::SVGAnimateTransformElement(const QualifiedName& tagName, Document* document)
-    : SVGAnimationElement(tagName, document)
+    : SVGAnimateElement(tagName, document)
     , m_type(SVGTransform::SVG_TRANSFORM_UNKNOWN)
-    , m_baseIndexInTransformList(0)
 {
     ASSERT(hasTagName(SVGNames::animateTransformTag));
 }
@@ -62,26 +45,9 @@
 
 bool SVGAnimateTransformElement::hasValidAttributeType()
 {
-    SVGElement* targetElement = this->targetElement();
-    if (!targetElement)
-        return false;
-    
-    return determineAnimatedPropertyType(targetElement) == AnimatedTransformList;
-}
-
-AnimatedPropertyType SVGAnimateTransformElement::determineAnimatedPropertyType(SVGElement* targetElement) const
-{
-    ASSERT(targetElement);
-    
-    // Just transform lists can be animated with <animateTransform>
-    // http://www.w3.org/TR/SVG/animate.html#AnimationAttributesAndProperties
-    Vector<AnimatedPropertyType> propertyTypes;
-    targetElement->animatedPropertyTypeForAttribute(attributeName(), propertyTypes);
-    if (propertyTypes.isEmpty() || propertyTypes[0] != AnimatedTransformList)
-        return AnimatedUnknown;
-
-    ASSERT(propertyTypes.size() == 1);
-    return AnimatedTransformList;
+    if (SVGElement* targetElement = this->targetElement())
+        return determineAnimatedPropertyType(targetElement) == AnimatedTransformList;
+    return false;
 }
 
 bool SVGAnimateTransformElement::isSupportedAttribute(const QualifiedName& attrName)
@@ -95,194 +61,18 @@
 void SVGAnimateTransformElement::parseAttribute(Attribute* attr)
 {
     if (!isSupportedAttribute(attr->name())) {
-        SVGAnimationElement::parseAttribute(attr);
+        SVGAnimateElement::parseAttribute(attr);
         return;
     }
 
     if (attr->name() == SVGNames::typeAttr) {
-        const AtomicString& value = attr->value();
-        if (value == "translate")
-            m_type = SVGTransform::SVG_TRANSFORM_TRANSLATE;
-        else if (value == "scale")
-            m_type = SVGTransform::SVG_TRANSFORM_SCALE;
-        else if (value == "rotate")
-            m_type = SVGTransform::SVG_TRANSFORM_ROTATE;
-        else if (value == "skewX")
-            m_type = SVGTransform::SVG_TRANSFORM_SKEWX;
-        else if (value == "skewY")
-            m_type = SVGTransform::SVG_TRANSFORM_SKEWY;
+        m_type = SVGTransformable::parseTransformType(attr->value());
         return;
     }
 
     ASSERT_NOT_REACHED();
 }
 
-static PassRefPtr<SVGAnimatedTransformList> animatedTransformListFor(SVGElement* element)
-{
-    ASSERT(element);
-    if (element->isStyledTransformable())
-        return static_cast<SVGStyledTransformableElement*>(element)->transformAnimated();
-    if (element->hasTagName(SVGNames::textTag))
-        return static_cast<SVGTextElement*>(element)->transformAnimated();
-    if (element->hasTagName(SVGNames::linearGradientTag) || element->hasTagName(SVGNames::radialGradientTag))
-        return static_cast<SVGGradientElement*>(element)->gradientTransformAnimated();
-    if (element->hasTagName(SVGNames::patternTag))
-        return static_cast<SVGPatternElement*>(element)->patternTransformAnimated();
-    return 0;
-}
-    
-void SVGAnimateTransformElement::resetToBaseValue(const String& baseValue)
-{
-    // FIXME: Once we added SVGAnimatedTransformListAnimator, this whole class is unncessary.
-    // See bug https://bugs.webkit.org/show_bug.cgi?id=80758. Once this is fixed animVal support
-    // for <animateTransform> is finished, and this class is almost empty.
-    SVGElement* targetElement = this->targetElement();
-    if (!targetElement || determineAnimatedPropertyType(targetElement) == AnimatedUnknown)
-        return;
-
-    // FIXME: This might not be correct for accumulated sum. Needs checking.
-    if (targetElement->hasTagName(SVGNames::linearGradientTag) || targetElement->hasTagName(SVGNames::radialGradientTag)) {
-        targetElement->setAttribute(SVGNames::gradientTransformAttr, baseValue.isEmpty() ? "matrix(1 0 0 1 0 0)" : baseValue);
-        return;
-    }
-    if (targetElement->hasTagName(SVGNames::patternTag)) {
-        targetElement->setAttribute(SVGNames::patternTransformAttr, baseValue.isEmpty() ? "matrix(1 0 0 1 0 0)" : baseValue);
-        return;
-    }
-    
-    if (baseValue.isEmpty()) {
-        if (RefPtr<SVGAnimatedTransformList> list = animatedTransformListFor(targetElement)) {
-            SVGListProperty<SVGTransformList>* baseVal = static_cast<SVGListProperty<SVGTransformList>*>(list->baseVal());
-            baseVal->detachListWrappers(0);
-            baseVal->values().clear();
-        }
-    } else
-        targetElement->setAttribute(SVGNames::transformAttr, baseValue);
 }
 
-void SVGAnimateTransformElement::calculateAnimatedValue(float percentage, unsigned repeat, SVGSMILElement*)
-{
-    // FIXME: Once we added SVGAnimatedTransformListAnimator, this whole class is unncessary.
-    // See bug https://bugs.webkit.org/show_bug.cgi?id=80758. Once this is fixed animVal support
-    // for <animateTransform> is finished, and this class is almost empty.
-    SVGElement* targetElement = this->targetElement();
-    if (!targetElement || determineAnimatedPropertyType(targetElement) == AnimatedUnknown)
-        return;
-    RefPtr<SVGAnimatedTransformList> animatedList = animatedTransformListFor(targetElement);
-    ASSERT(animatedList);
-    SVGListProperty<SVGTransformList>* baseVal = static_cast<SVGListProperty<SVGTransformList>*>(animatedList->baseVal());
-    ASSERT(baseVal);
-
-    if (calcMode() == CalcModeDiscrete)
-        percentage = percentage < 0.5 ? 0 : 1;
-
-    if (!isAdditive()) {
-        baseVal->detachListWrappers(0);
-        baseVal->values().clear();
-    }
-    if (isAccumulated() && repeat)
-        percentage += repeat;
-    SVGTransform transform = SVGTransformDistance(m_fromTransform, m_toTransform).scaledDistance(percentage).addToSVGTransform(m_fromTransform);
-    baseVal->values().append(transform);
-    baseVal->wrappers().append(RefPtr<SVGPropertyTearOff<SVGTransform> >());
-}
-    
-bool SVGAnimateTransformElement::calculateFromAndToValues(const String& fromString, const String& toString)
-{
-    m_fromTransform = parseTransformValue(fromString);
-    if (!m_fromTransform.isValid())
-        return false;
-    m_toTransform = parseTransformValue(toString);
-    return m_toTransform.isValid();
-}
-
-bool SVGAnimateTransformElement::calculateFromAndByValues(const String& fromString, const String& byString)
-{
-    m_fromTransform = parseTransformValue(fromString);
-    if (!m_fromTransform.isValid())
-        return false;
-    m_toTransform = SVGTransformDistance::addSVGTransforms(m_fromTransform, parseTransformValue(byString));
-    return m_toTransform.isValid();
-}
-
-SVGTransform SVGAnimateTransformElement::parseTransformValue(const String& value) const
-{
-    if (value.isEmpty())
-        return SVGTransform(m_type);
-    SVGTransform result;
-    // FIXME: This is pretty dumb but parseTransformValue() wants those parenthesis.
-    String parseString("(" + value + ")");
-    const UChar* ptr = parseString.characters();
-    SVGTransformable::parseTransformValue(m_type, ptr, ptr + parseString.length(), result); // ignoring return value
-    return result;
-}
-    
-void SVGAnimateTransformElement::applyResultsToTarget()
-{
-    SVGElement* targetElement = this->targetElement();
-    if (!targetElement || determineAnimatedPropertyType(targetElement) == AnimatedUnknown)
-        return;
-
-    // We accumulate to the target element transform list so there is not much to do here.
-    if (RenderObject* renderer = targetElement->renderer()) {
-        renderer->setNeedsTransformUpdate();
-        RenderSVGResource::markForLayoutAndParentResourceInvalidation(renderer);
-    }
-
-    // ...except in case where we have additional instances in <use> trees.
-    RefPtr<SVGAnimatedTransformList> animatedList = animatedTransformListFor(targetElement);
-    if (!animatedList)
-        return;
-
-    // FIXME: Once we added SVGAnimatedTransformListAnimator, this whole class is unncessary.
-    // See bug https://bugs.webkit.org/show_bug.cgi?id=80758. Once this is fixed animVal support
-    // for <animateTransform> is finished, and this class is almost empty.
-    SVGListProperty<SVGTransformList>* baseVal = static_cast<SVGListProperty<SVGTransformList>*>(animatedList->baseVal());
-    ASSERT(baseVal);
-    SVGTransformList& transformList = baseVal->values();
-
-    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();
-        ASSERT(shadowTreeElement);
-        if (shadowTreeElement->isStyledTransformable())
-            static_cast<SVGStyledTransformableElement*>(shadowTreeElement)->setTransformBaseValue(transformList);
-        else if (shadowTreeElement->hasTagName(SVGNames::textTag))
-            static_cast<SVGTextElement*>(shadowTreeElement)->setTransformBaseValue(transformList);
-        else if (shadowTreeElement->hasTagName(SVGNames::linearGradientTag) || shadowTreeElement->hasTagName(SVGNames::radialGradientTag))
-            static_cast<SVGGradientElement*>(shadowTreeElement)->setGradientTransformBaseValue(transformList);
-        else if (shadowTreeElement->hasTagName(SVGNames::patternTag))
-            static_cast<SVGPatternElement*>(shadowTreeElement)->setPatternTransformBaseValue(transformList);
-        if (RenderObject* renderer = shadowTreeElement->renderer()) {
-            renderer->setNeedsTransformUpdate();
-            RenderSVGResource::markForLayoutAndParentResourceInvalidation(renderer);
-        }
-    }
-}
-    
-float SVGAnimateTransformElement::calculateDistance(const String& fromString, const String& toString)
-{
-    // FIXME: This is not correct in all cases. The spec demands that each component (translate x and y for example) 
-    // is paced separately. To implement this we need to treat each component as individual animation everywhere.
-    SVGTransform from = parseTransformValue(fromString);
-    if (!from.isValid())
-        return -1;
-    SVGTransform to = parseTransformValue(toString);
-    if (!to.isValid() || from.type() != to.type())
-        return -1;
-    if (to.type() == SVGTransform::SVG_TRANSFORM_TRANSLATE) {
-        FloatSize diff = to.translate() - from.translate();
-        return sqrtf(diff.width() * diff.width() + diff.height() * diff.height());
-    }
-    if (to.type() == SVGTransform::SVG_TRANSFORM_ROTATE)
-        return fabsf(to.angle() - from.angle());
-    if (to.type() == SVGTransform::SVG_TRANSFORM_SCALE) {
-        FloatSize diff = to.scale() - from.scale();
-        return sqrtf(diff.width() * diff.width() + diff.height() * diff.height());
-    }
-    return -1;
-}
-
-}
 #endif // ENABLE(SVG)
diff --git a/Source/WebCore/svg/SVGAnimateTransformElement.h b/Source/WebCore/svg/SVGAnimateTransformElement.h
index a3d7f79..d308e0b 100644
--- a/Source/WebCore/svg/SVGAnimateTransformElement.h
+++ b/Source/WebCore/svg/SVGAnimateTransformElement.h
@@ -22,44 +22,30 @@
 
 #ifndef SVGAnimateTransformElement_h
 #define SVGAnimateTransformElement_h
-#if ENABLE(SVG)
 
-#include "SVGAnimationElement.h"
+#if ENABLE(SVG)
+#include "SVGAnimateElement.h"
 #include "SVGTransform.h"
-#include "SVGTransformDistance.h"
 
 namespace WebCore {
 
 class AffineTransform;
 
-class SVGAnimateTransformElement : public SVGAnimationElement {
+class SVGAnimateTransformElement : public SVGAnimateElement {
 public:
     static PassRefPtr<SVGAnimateTransformElement> create(const QualifiedName&, Document*);
 
+    SVGTransform::SVGTransformType transformType() const { return m_type; }
+
 private:
     SVGAnimateTransformElement(const QualifiedName&, Document*);
     
     virtual bool hasValidAttributeType();
-    AnimatedPropertyType determineAnimatedPropertyType(SVGElement*) const;
 
     bool isSupportedAttribute(const QualifiedName&);
     virtual void parseAttribute(Attribute*) OVERRIDE;
 
-    virtual void resetToBaseValue(const String&);
-    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);
-    virtual void applyResultsToTarget();
-    virtual float calculateDistance(const String& fromString, const String& toString);
-
-    SVGTransform parseTransformValue(const String&) const;
-    
     SVGTransform::SVGTransformType m_type;
-    
-    unsigned m_baseIndexInTransformList;
-
-    SVGTransform m_toTransform;
-    SVGTransform m_fromTransform;
 };
 
 } // namespace WebCore
diff --git a/Source/WebCore/svg/SVGAnimatedTransformList.cpp b/Source/WebCore/svg/SVGAnimatedTransformList.cpp
new file mode 100644
index 0000000..6e3ed94
--- /dev/null
+++ b/Source/WebCore/svg/SVGAnimatedTransformList.cpp
@@ -0,0 +1,150 @@
+/*
+ * Copyright (C) Research In Motion Limited 2012. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+
+#if ENABLE(SVG)
+#include "SVGAnimatedTransformList.h"
+
+#include "SVGAnimateTransformElement.h"
+#include "SVGAnimatedNumber.h"
+#include "SVGNames.h"
+#include "SVGTransformDistance.h"
+
+namespace WebCore {
+
+SVGAnimatedTransformListAnimator::SVGAnimatedTransformListAnimator(SVGAnimationElement* animationElement, SVGElement* contextElement)
+    : SVGAnimatedTypeAnimator(AnimatedTransformList, animationElement, contextElement)
+{
+    // Only <animateTransform> uses this animator, as <animate> doesn't allow to animate transform lists directly.
+    ASSERT(animationElement->hasTagName(SVGNames::animateTransformTag));
+}
+
+PassOwnPtr<SVGAnimatedType> SVGAnimatedTransformListAnimator::constructFromString(const String& string)
+{
+    OwnPtr<SVGAnimatedType> animatedType = SVGAnimatedType::createTransformList(new SVGTransformList);
+    animatedType->transformList().parse(string);
+    ASSERT(animatedType->transformList().size() <= 1);
+    return animatedType.release();
+}
+
+PassOwnPtr<SVGAnimatedType> SVGAnimatedTransformListAnimator::constructFromCopy(SVGGenericAnimatedType* animatedType)
+{
+    ASSERT(animatedType);
+    return SVGAnimatedType::createTransformList(new SVGTransformList(*reinterpret_cast<SVGTransformList*>(animatedType)));
+}
+
+inline PassOwnPtr<SVGAnimatedType> SVGAnimatedTransformListAnimator::constructFromString(SVGAnimateTransformElement* animateTransformElement, const String& string)
+{
+    ASSERT(animateTransformElement);
+    return SVGAnimatedTransformListAnimator::constructFromString(SVGTransform::transformTypePrefixForParsing(animateTransformElement->transformType()) + string + ')');
+}
+
+void SVGAnimatedTransformListAnimator::calculateFromAndToValues(OwnPtr<SVGAnimatedType>& from, OwnPtr<SVGAnimatedType>& to, const String& fromString, const String& toString)
+{
+    ASSERT(m_animationElement);
+    SVGAnimateTransformElement* animateTransformElement = static_cast<SVGAnimateTransformElement*>(m_animationElement);
+
+    from = constructFromString(animateTransformElement, fromString);
+    to = constructFromString(animateTransformElement, toString);
+}
+
+void SVGAnimatedTransformListAnimator::calculateFromAndByValues(OwnPtr<SVGAnimatedType>& from, OwnPtr<SVGAnimatedType>& to, const String& fromString, const String& byString)
+{
+    ASSERT(m_animationElement);
+    SVGAnimateTransformElement* animateTransformElement = static_cast<SVGAnimateTransformElement*>(m_animationElement);
+
+    from = constructFromString(animateTransformElement, fromString);
+    to = constructFromString(animateTransformElement, byString);
+
+    SVGTransformList& fromTransformList = from->transformList();
+    SVGTransformList& toTransformList = to->transformList();
+    unsigned itemsCount = fromTransformList.size();
+    if (!itemsCount || itemsCount != toTransformList.size())
+        return;
+
+    ASSERT(itemsCount == 1);
+    toTransformList[0] = SVGTransformDistance::addSVGTransforms(fromTransformList[0], toTransformList[0]);
+}
+
+void SVGAnimatedTransformListAnimator::calculateAnimatedValue(float percentage, unsigned repeatCount,
+                                                       OwnPtr<SVGAnimatedType>& from, OwnPtr<SVGAnimatedType>& to, OwnPtr<SVGAnimatedType>& animated)
+{
+    ASSERT(m_animationElement);
+
+    // Spec: To animations provide specific functionality to get a smooth change from the underlying value to the
+    // ‘to’ attribute value, which conflicts mathematically with the requirement for additive transform animations
+    // to be post-multiplied. As a consequence, in SVG 1.1 the behavior of to animations for ‘animateTransform’ is undefined.
+    // FIXME: This is not taken into account yet.
+    SVGTransformList& fromTransformList = from->transformList();
+    SVGTransformList& toTransformList = to->transformList();
+    ASSERT(fromTransformList.size() <= 1);
+    ASSERT(toTransformList.size() <= 1);
+    ASSERT(fromTransformList[0].type() == toTransformList[0].type());
+
+    SVGTransform fromTransform;
+    SVGTransform toTransform;
+    if (!toTransformList.isEmpty() && !fromTransformList.isEmpty()) {
+        fromTransform = fromTransformList[0];
+        toTransform = toTransformList[0];
+        ASSERT(fromTransform.type() == toTransform.type());
+    }
+
+    if (m_animationElement->calcMode() == CalcModeDiscrete)
+        percentage = percentage < 0.5 ? 0 : 1;
+
+    if (m_animationElement->isAccumulated() && repeatCount)
+        percentage += repeatCount;
+
+    SVGTransformList& animatedTransformList = animated->transformList();
+    if (!m_animationElement->isAdditive())
+        animatedTransformList.clear();
+
+    animatedTransformList.append(SVGTransformDistance(fromTransform, toTransform).scaledDistance(percentage).addToSVGTransform(fromTransform));
+}
+
+float SVGAnimatedTransformListAnimator::calculateDistance(const String& fromString, const String& toString)
+{
+    ASSERT(m_animationElement);
+    SVGAnimateTransformElement* animateTransformElement = static_cast<SVGAnimateTransformElement*>(m_animationElement);
+
+    // FIXME: This is not correct in all cases. The spec demands that each component (translate x and y for example)
+    // is paced separately. To implement this we need to treat each component as individual animation everywhere.
+    OwnPtr<SVGAnimatedType> from = constructFromString(animateTransformElement, fromString);
+    OwnPtr<SVGAnimatedType> to = constructFromString(animateTransformElement, toString);
+
+    SVGTransformList& fromTransformList = from->transformList();
+    SVGTransformList& toTransformList = to->transformList();
+    unsigned itemsCount = fromTransformList.size();
+    if (!itemsCount || itemsCount != toTransformList.size())
+        return -1;
+
+    ASSERT(itemsCount == 1);
+    if (fromTransformList[0].type() != toTransformList[0].type())
+        return -1;
+
+    // Spec: http://www.w3.org/TR/SVG/animate.html#complexDistances
+    // Paced animations assume a notion of distance between the various animation values defined by the ‘to’, ‘from’, ‘by’ and ‘values’ attributes.
+    // Distance is defined only for scalar types (such as <length>), colors and the subset of transformation types that are supported by ‘animateTransform’.
+    return SVGTransformDistance(fromTransformList[0], toTransformList[0]).distance();
+}
+
+}
+
+#endif // ENABLE(SVG)
diff --git a/Source/WebCore/svg/SVGAnimatedTransformList.h b/Source/WebCore/svg/SVGAnimatedTransformList.h
index bf8038e..895a32f 100644
--- a/Source/WebCore/svg/SVGAnimatedTransformList.h
+++ b/Source/WebCore/svg/SVGAnimatedTransformList.h
@@ -22,6 +22,7 @@
 
 #if ENABLE(SVG)
 #include "SVGAnimatedTransformListPropertyTearOff.h"
+#include "SVGAnimatedTypeAnimator.h"
 
 namespace WebCore {
 
@@ -34,6 +35,28 @@
 #define DEFINE_ANIMATED_TRANSFORM_LIST(OwnerType, DOMAttribute, UpperProperty, LowerProperty) \
 DEFINE_ANIMATED_PROPERTY(AnimatedTransformList, OwnerType, DOMAttribute, DOMAttribute.localName(), UpperProperty, LowerProperty)
 
+class SVGAnimationElement;
+class SVGAnimateTransformElement;
+class SVGGenericAnimatedType;
+
+class SVGAnimatedTransformListAnimator : public SVGAnimatedTypeAnimator {
+public:
+    SVGAnimatedTransformListAnimator(SVGAnimationElement*, SVGElement*);
+    virtual ~SVGAnimatedTransformListAnimator() { }
+
+    virtual PassOwnPtr<SVGAnimatedType> constructFromString(const String&);
+    virtual PassOwnPtr<SVGAnimatedType> constructFromCopy(SVGGenericAnimatedType*);
+
+    virtual void calculateFromAndToValues(OwnPtr<SVGAnimatedType>& fromValue, OwnPtr<SVGAnimatedType>& toValue, const String& fromString, const String& toString);
+    virtual void calculateFromAndByValues(OwnPtr<SVGAnimatedType>& fromValue, OwnPtr<SVGAnimatedType>& toValue, const String& fromString, const String& byString);
+    virtual void calculateAnimatedValue(float percentage, unsigned repeatCount,
+                                        OwnPtr<SVGAnimatedType>& fromValue, OwnPtr<SVGAnimatedType>& toValue, OwnPtr<SVGAnimatedType>& animatedValue);
+    virtual float calculateDistance(const String& fromString, const String& toString);
+
+private:
+    PassOwnPtr<SVGAnimatedType> constructFromString(SVGAnimateTransformElement*, const String&);
+};
+
 } // namespace WebCore
 
 #endif // ENABLE(SVG)
diff --git a/Source/WebCore/svg/SVGAnimatedType.cpp b/Source/WebCore/svg/SVGAnimatedType.cpp
index 3abaab9..41e579c 100644
--- a/Source/WebCore/svg/SVGAnimatedType.cpp
+++ b/Source/WebCore/svg/SVGAnimatedType.cpp
@@ -32,6 +32,7 @@
 #include "SVGPathParserFactory.h"
 #include "SVGPointList.h"
 #include "SVGPreserveAspectRatio.h"
+#include "SVGTransformList.h"
 
 using namespace std;
 
@@ -87,6 +88,9 @@
     case AnimatedString:
         delete m_data.string;
         break;
+    case AnimatedTransformList:
+        delete m_data.transformList;
+        break;
     default:
         ASSERT_NOT_REACHED();
         break;
@@ -205,6 +209,14 @@
     return animatedType.release();
 }
 
+PassOwnPtr<SVGAnimatedType> SVGAnimatedType::createTransformList(SVGTransformList* transformList)
+{
+    ASSERT(transformList);
+    OwnPtr<SVGAnimatedType> animatedType = adoptPtr(new SVGAnimatedType(AnimatedTransformList));
+    animatedType->m_data.transformList = transformList;
+    return animatedType.release();
+}
+
 SVGAngle& SVGAnimatedType::angle()
 {
     ASSERT(m_type == AnimatedAngle);
@@ -289,6 +301,12 @@
     return *m_data.string;
 }
 
+SVGTransformList& SVGAnimatedType::transformList()
+{
+    ASSERT(m_type == AnimatedTransformList);
+    return *m_data.transformList;
+}
+
 String SVGAnimatedType::valueAsString()
 {
     switch (m_type) {
@@ -338,6 +356,9 @@
     case AnimatedString:
         ASSERT(m_data.string);
         return *m_data.string;
+     case AnimatedTransformList:
+        ASSERT(m_data.transformList);
+        return m_data.transformList->valueAsString();
     default:
         break;
     }
@@ -414,6 +435,7 @@
         ASSERT(m_data.string);
         *m_data.string = value;
         break;
+    case AnimatedTransformList:
     default:
         ASSERT_NOT_REACHED();
         break;
@@ -429,10 +451,11 @@
 
 bool SVGAnimatedType::supportsAnimVal(AnimatedPropertyType type)
 {
-    // FIXME: This lists the current state of our animVal support: only SVGLength is supported for now.
+    // FIXME: This lists the current state of our animVal support.
     switch (type) {
     case AnimatedLength:
     case AnimatedLengthList:
+    case AnimatedTransformList:
         return true;
     case AnimatedAngle:
     case AnimatedBoolean:
@@ -447,7 +470,6 @@
     case AnimatedPreserveAspectRatio:
     case AnimatedRect:
     case AnimatedString:
-    case AnimatedTransformList:
     case AnimatedUnknown:
         return false;
     }
@@ -458,7 +480,7 @@
 
 void SVGAnimatedType::setVariantValue(SVGGenericAnimatedType* type)
 {
-    // FIXME: This lists the current state of our animVal support: only SVGLength is supported for now.
+    // FIXME: This lists the current state of our animVal support.
     switch (m_type) {
     case AnimatedLength:
         *m_data.length = *reinterpret_cast<SVGLength*>(type);
@@ -466,6 +488,9 @@
     case AnimatedLengthList:
         *m_data.lengthList = *reinterpret_cast<SVGLengthList*>(type);
         return;
+    case AnimatedTransformList:
+        *m_data.transformList = *reinterpret_cast<SVGTransformList*>(type);
+        return;
     case AnimatedAngle:
     case AnimatedBoolean:
     case AnimatedColor:
@@ -479,7 +504,6 @@
     case AnimatedPreserveAspectRatio:
     case AnimatedRect:
     case AnimatedString:
-    case AnimatedTransformList:
     case AnimatedUnknown:
         break;
     }
diff --git a/Source/WebCore/svg/SVGAnimatedType.h b/Source/WebCore/svg/SVGAnimatedType.h
index 152e34f..77dc6e3 100644
--- a/Source/WebCore/svg/SVGAnimatedType.h
+++ b/Source/WebCore/svg/SVGAnimatedType.h
@@ -35,6 +35,7 @@
 class SVGPathByteStream;
 class SVGPointList;
 class SVGPreserveAspectRatio;
+class SVGTransformList;
 
 class SVGAnimatedType {
     WTF_MAKE_FAST_ALLOCATED;
@@ -55,6 +56,7 @@
     static PassOwnPtr<SVGAnimatedType> createPreserveAspectRatio(SVGPreserveAspectRatio*);
     static PassOwnPtr<SVGAnimatedType> createRect(FloatRect*);
     static PassOwnPtr<SVGAnimatedType> createString(String*);
+    static PassOwnPtr<SVGAnimatedType> createTransformList(SVGTransformList*);
     static bool supportsAnimVal(AnimatedPropertyType);
 
     AnimatedPropertyType type() const { return m_type; }
@@ -73,6 +75,7 @@
     SVGPreserveAspectRatio& preserveAspectRatio();
     FloatRect& rect();
     String& string();
+    SVGTransformList& transformList();
 
     // Use with care, the actual type of the generic animated object has to be equal to our type().
     void setVariantValue(SVGGenericAnimatedType*);
@@ -109,6 +112,7 @@
         SVGPointList* pointList;
         FloatRect* rect;
         String* string;
+        SVGTransformList* transformList;
         SVGGenericAnimatedType* variant;
     } m_data;
 };
diff --git a/Source/WebCore/svg/SVGAnimatorFactory.h b/Source/WebCore/svg/SVGAnimatorFactory.h
index fbc746f..028daf6 100644
--- a/Source/WebCore/svg/SVGAnimatorFactory.h
+++ b/Source/WebCore/svg/SVGAnimatorFactory.h
@@ -35,6 +35,7 @@
 #include "SVGAnimatedPreserveAspectRatio.h"
 #include "SVGAnimatedRect.h"
 #include "SVGAnimatedString.h"
+#include "SVGAnimatedTransformList.h"
 
 namespace WebCore {
 
@@ -76,8 +77,9 @@
             return adoptPtr(new SVGAnimatedRectAnimator(animationElement, contextElement));
         case AnimatedString:
             return adoptPtr(new SVGAnimatedStringAnimator(animationElement, contextElement));
+        case AnimatedTransformList:
+            return adoptPtr(new SVGAnimatedTransformListAnimator(animationElement, contextElement));
         case AnimatedEnumeration: // FIXME: Implementation needed.
-        case AnimatedTransformList: // FIXME: Implementation needed.
         case AnimatedUnknown:
             break;
         }
diff --git a/Source/WebCore/svg/SVGGradientElement.cpp b/Source/WebCore/svg/SVGGradientElement.cpp
index c959464..07a88ad 100644
--- a/Source/WebCore/svg/SVGGradientElement.cpp
+++ b/Source/WebCore/svg/SVGGradientElement.cpp
@@ -91,9 +91,7 @@
 
     if (attr->name() == SVGNames::gradientTransformAttr) {
         SVGTransformList newList;
-        if (!SVGTransformable::parseTransformAttribute(newList, attr->value()))
-            newList.clear();
-
+        newList.parse(attr->value());
         detachAnimatedGradientTransformListWrappers(newList.size());
         setGradientTransformBaseValue(newList);
         return;
diff --git a/Source/WebCore/svg/SVGPatternElement.cpp b/Source/WebCore/svg/SVGPatternElement.cpp
index 8bf97b3..780f57b 100644
--- a/Source/WebCore/svg/SVGPatternElement.cpp
+++ b/Source/WebCore/svg/SVGPatternElement.cpp
@@ -127,9 +127,7 @@
         return;
     } else if (attr->name() == SVGNames::patternTransformAttr) {
         SVGTransformList newList;
-        if (!SVGTransformable::parseTransformAttribute(newList, attr->value()))
-            newList.clear();
-
+        newList.parse(attr->value());
         detachAnimatedPatternTransformListWrappers(newList.size());
         setPatternTransformBaseValue(newList);
         return;
diff --git a/Source/WebCore/svg/SVGStyledTransformableElement.cpp b/Source/WebCore/svg/SVGStyledTransformableElement.cpp
index 02f35d3..7e6f1dd 100644
--- a/Source/WebCore/svg/SVGStyledTransformableElement.cpp
+++ b/Source/WebCore/svg/SVGStyledTransformableElement.cpp
@@ -107,8 +107,7 @@
 
     if (attr->name() == SVGNames::transformAttr) {
         SVGTransformList newList;
-        if (!SVGTransformable::parseTransformAttribute(newList, attr->value()))
-            newList.clear();
+        newList.parse(attr->value());
         detachAnimatedTransformListWrappers(newList.size());
         setTransformBaseValue(newList);
         return;
diff --git a/Source/WebCore/svg/SVGTextElement.cpp b/Source/WebCore/svg/SVGTextElement.cpp
index 54a64a5..cc8b674 100644
--- a/Source/WebCore/svg/SVGTextElement.cpp
+++ b/Source/WebCore/svg/SVGTextElement.cpp
@@ -73,9 +73,7 @@
 
     if (attr->name() == SVGNames::transformAttr) {
         SVGTransformList newList;
-        if (!SVGTransformable::parseTransformAttribute(newList, attr->value()))
-            newList.clear();
-
+        newList.parse(attr->value());
         detachAnimatedTransformListWrappers(newList.size());
         setTransformBaseValue(newList);
         return;
diff --git a/Source/WebCore/svg/SVGTransform.cpp b/Source/WebCore/svg/SVGTransform.cpp
index 70bdad7..4561d42 100644
--- a/Source/WebCore/svg/SVGTransform.cpp
+++ b/Source/WebCore/svg/SVGTransform.cpp
@@ -129,49 +129,75 @@
     m_matrix.skewY(angle);
 }
 
-String SVGTransform::valueAsString() const
+const String& SVGTransform::transformTypePrefixForParsing(SVGTransformType type)
 {
-    switch (m_type) {
+    switch (type) {
     case SVG_TRANSFORM_UNKNOWN:
-        return String();
+        return emptyString();
     case SVG_TRANSFORM_MATRIX: {
         DEFINE_STATIC_LOCAL(String, matrixString, ("matrix("));
-        StringBuilder builder;
-        builder.append(matrixString + String::number(m_matrix.a()) + ' ' + String::number(m_matrix.b()) + ' ' + String::number(m_matrix.c()) + ' ' +
-                       String::number(m_matrix.d()) + ' ' + String::number(m_matrix.e()) + ' ' + String::number(m_matrix.f()) + ')');
-        return builder.toString();
+        return matrixString;
     }
     case SVG_TRANSFORM_TRANSLATE: {
         DEFINE_STATIC_LOCAL(String, translateString, ("translate("));
-        return translateString + String::number(m_matrix.e()) + ' ' + String::number(m_matrix.f()) + ')';
+        return translateString;
     }
     case SVG_TRANSFORM_SCALE: {
         DEFINE_STATIC_LOCAL(String, scaleString, ("scale("));
-        return scaleString + String::number(m_matrix.xScale()) + ' ' + String::number(m_matrix.yScale()) + ')';
+        return scaleString;
     }
     case SVG_TRANSFORM_ROTATE: {
         DEFINE_STATIC_LOCAL(String, rotateString, ("rotate("));
+        return rotateString;
+    }    
+    case SVG_TRANSFORM_SKEWX: {
+        DEFINE_STATIC_LOCAL(String, skewXString, ("skewX("));
+        return skewXString;
+    }
+    case SVG_TRANSFORM_SKEWY: {
+        DEFINE_STATIC_LOCAL(String, skewYString, ("skewY("));
+        return skewYString;
+    }
+    }
+
+    ASSERT_NOT_REACHED();
+    return emptyString();
+}
+
+String SVGTransform::valueAsString() const
+{
+    const String& prefix = transformTypePrefixForParsing(m_type);
+    switch (m_type) {
+    case SVG_TRANSFORM_UNKNOWN:
+        return prefix;
+    case SVG_TRANSFORM_MATRIX: {
+        StringBuilder builder;
+        builder.append(prefix + String::number(m_matrix.a()) + ' ' + String::number(m_matrix.b()) + ' ' + String::number(m_matrix.c()) + ' ' +
+                       String::number(m_matrix.d()) + ' ' + String::number(m_matrix.e()) + ' ' + String::number(m_matrix.f()) + ')');
+        return builder.toString();
+    }
+    case SVG_TRANSFORM_TRANSLATE:
+        return prefix + String::number(m_matrix.e()) + ' ' + String::number(m_matrix.f()) + ')';
+    case SVG_TRANSFORM_SCALE:
+        return prefix + String::number(m_matrix.xScale()) + ' ' + String::number(m_matrix.yScale()) + ')';
+    case SVG_TRANSFORM_ROTATE: {
         double angleInRad = deg2rad(m_angle);
         double cosAngle = cos(angleInRad);
         double sinAngle = sin(angleInRad);
         float cx = narrowPrecisionToFloat(cosAngle != 1 ? (m_matrix.e() * (1 - cosAngle) - m_matrix.f() * sinAngle) / (1 - cosAngle) / 2 : 0);
         float cy = narrowPrecisionToFloat(cosAngle != 1 ? (m_matrix.e() * sinAngle / (1 - cosAngle) + m_matrix.f()) / 2 : 0);
         if (cx || cy)
-            return rotateString + String::number(m_angle) + ' ' + String::number(cx) + ' ' + String::number(cy) + ')';
-        return rotateString + String::number(m_angle) + ')';
-    }    
-    case SVG_TRANSFORM_SKEWX: {
-        DEFINE_STATIC_LOCAL(String, skewXString, ("skewX("));
-        return skewXString + String::number(m_angle) + ')';
+            return prefix + String::number(m_angle) + ' ' + String::number(cx) + ' ' + String::number(cy) + ')';
+        return prefix + String::number(m_angle) + ')';
     }
-    case SVG_TRANSFORM_SKEWY: {
-        DEFINE_STATIC_LOCAL(String, skewYString, ("skewY("));
-        return skewYString + String::number(m_angle) + ')';
-    }
+    case SVG_TRANSFORM_SKEWX:
+        return prefix + String::number(m_angle) + ')';
+    case SVG_TRANSFORM_SKEWY:
+        return prefix + String::number(m_angle) + ')';
     }
 
     ASSERT_NOT_REACHED();
-    return String();
+    return emptyString();
 }
 
 } // namespace WebCore
diff --git a/Source/WebCore/svg/SVGTransform.h b/Source/WebCore/svg/SVGTransform.h
index 14718ae..6a08b73 100644
--- a/Source/WebCore/svg/SVGTransform.h
+++ b/Source/WebCore/svg/SVGTransform.h
@@ -68,6 +68,8 @@
     bool isValid() const { return m_type != SVG_TRANSFORM_UNKNOWN; }
     String valueAsString() const;
 
+    static const String& transformTypePrefixForParsing(SVGTransformType);
+
 private:
     friend bool operator==(const SVGTransform& a, const SVGTransform& b);
 
diff --git a/Source/WebCore/svg/SVGTransformList.cpp b/Source/WebCore/svg/SVGTransformList.cpp
index 5cc8492..d97461d 100644
--- a/Source/WebCore/svg/SVGTransformList.cpp
+++ b/Source/WebCore/svg/SVGTransformList.cpp
@@ -26,6 +26,7 @@
 #include "AffineTransform.h"
 #include "SVGSVGElement.h"
 #include "SVGTransform.h"
+#include "SVGTransformable.h"
 #include <wtf/text/StringBuilder.h>
 
 namespace WebCore {
@@ -73,6 +74,13 @@
     return builder.toString();
 }
 
+void SVGTransformList::parse(const String& transform)
+{
+    const UChar* start = transform.characters();
+    if (!SVGTransformable::parseTransformAttribute(*this, start, start + transform.length()))
+        clear();
+}
+
 } // namespace WebCore
 
 #endif // ENABLE(SVG)
diff --git a/Source/WebCore/svg/SVGTransformList.h b/Source/WebCore/svg/SVGTransformList.h
index 0afc832..14aba3b 100644
--- a/Source/WebCore/svg/SVGTransformList.h
+++ b/Source/WebCore/svg/SVGTransformList.h
@@ -39,6 +39,7 @@
     bool concatenate(AffineTransform& result) const;
  
     String valueAsString() const;
+    void parse(const String&);
 };
 
 template<>
diff --git a/Source/WebCore/svg/SVGTransformable.cpp b/Source/WebCore/svg/SVGTransformable.cpp
index d4193bc..094ced9 100644
--- a/Source/WebCore/svg/SVGTransformable.cpp
+++ b/Source/WebCore/svg/SVGTransformable.cpp
@@ -170,10 +170,12 @@
     return true;
 }
 
-bool SVGTransformable::parseTransformAttribute(SVGTransformList& list, const AtomicString& transform)
+SVGTransform::SVGTransformType SVGTransformable::parseTransformType(const String& typeString)
 {
-    const UChar* start = transform.characters();
-    return parseTransformAttribute(list, start, start + transform.length());
+    unsigned short type = SVGTransform::SVG_TRANSFORM_UNKNOWN;
+    const UChar* characters = typeString.characters();
+    parseAndSkipType(characters, characters + typeString.length(), type);
+    return static_cast<SVGTransform::SVGTransformType>(type);
 }
 
 bool SVGTransformable::parseTransformAttribute(SVGTransformList& list, const UChar*& currTransform, const UChar* end, TransformParsingMode mode)
diff --git a/Source/WebCore/svg/SVGTransformable.h b/Source/WebCore/svg/SVGTransformable.h
index ffd9cee..7168ba3 100644
--- a/Source/WebCore/svg/SVGTransformable.h
+++ b/Source/WebCore/svg/SVGTransformable.h
@@ -22,16 +22,14 @@
 #define SVGTransformable_h
 
 #if ENABLE(SVG)
-#include "PlatformString.h"
 #include "SVGLocatable.h"
+#include "SVGTransform.h"
 #include "SVGTransformList.h"
-#include <wtf/Forward.h>
+#include <wtf/text/WTFString.h>
 
 namespace WebCore {
     
 class AffineTransform;
-class SVGTransform;
-class QualifiedName;
 
 class SVGTransformable : virtual public SVGLocatable {
 public:
@@ -42,9 +40,9 @@
 
     virtual ~SVGTransformable();
 
-    static bool parseTransformAttribute(SVGTransformList&, const AtomicString& transform);
     static bool parseTransformAttribute(SVGTransformList&, const UChar*& ptr, const UChar* end, TransformParsingMode mode = ClearList);
     static bool parseTransformValue(unsigned type, const UChar*& ptr, const UChar* end, SVGTransform&);
+    static SVGTransform::SVGTransformType parseTransformType(const String&);
 
     virtual AffineTransform localCoordinateSpaceTransform(SVGLocatable::CTMScope) const { return animatedLocalTransform(); }
     virtual AffineTransform animatedLocalTransform() const = 0;
diff --git a/Source/WebCore/svg/SVGViewSpec.cpp b/Source/WebCore/svg/SVGViewSpec.cpp
index ce7bd19..d09ea59 100644
--- a/Source/WebCore/svg/SVGViewSpec.cpp
+++ b/Source/WebCore/svg/SVGViewSpec.cpp
@@ -48,7 +48,7 @@
 
 void SVGViewSpec::setTransform(const String& transform)
 {
-    SVGTransformable::parseTransformAttribute(m_transform, transform);
+    m_transform.parse(transform);
 }
 
 void SVGViewSpec::setViewBoxString(const String& viewBoxStr)