SVG should support transform-origin and relative values
authorcommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 13 Mar 2012 02:45:38 +0000 (02:45 +0000)
committercommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 13 Mar 2012 02:45:38 +0000 (02:45 +0000)
https://bugs.webkit.org/show_bug.cgi?id=79068

Patch by Hans Muller <hmuller@adobe.com> on 2012-03-12
Reviewed by Dirk Schulze.

Source/WebCore:

Added SVG support for the CSS 'transform-origin' property and for percentage
values in the transform translate function.  The changes conform to
http://dev.w3.org/csswg/css3-transforms/.

Tests: svg/transforms/percent-transform-values.xhtml
       svg/transforms/transform-origin-css-property.xhtml

* css/svg.css:
(*):
(html|* > svg):
Default transform-origin for SVG elements is 0 0.

* platform/Length.h:
(WebCore::Length::calcFloatValue):
Added a calcFloatValue overload whose max parameter (for percent lengths) is a float.
The original version will be obsolete when the sub-pixel layout support is completed.

* rendering/style/RenderStyle.cpp:
* rendering/style/RenderStyle.h:
(WebCore):
(WebCore::requireTransformOrigin):
Transforms that only include translations don't depend on the transform-origin.

(WebCore::RenderStyle::applyTransform):
SVG elements interpret non-percentage/keyword transform-origin values relative to their viewport,
unlike HTML which interprets all transform-origin values relative to the element's origin.
The new FloatRect applyTransform() function handles SVG semantics. Similarly, SVG elements interpret
percentage/keyword transform-origin values relative to the origin of their objectBoundingBox(), HTML
uses the borderBox.  All this per http://dev.w3.org/csswg/css3-transforms/.

* svg/SVGStyledTransformableElement.cpp:
(WebCore::SVGStyledTransformableElement::animatedLocalTransform):

LayoutTests:

Added tests for SVG CSS transform-origin property support and for
CSS translations specified with percentages and applied to an SVG element.

* svg/transforms/change-transform-origin-css-expected.xhtml: Added.
* svg/transforms/change-transform-origin-css.xhtml: Added.
* svg/transforms/change-transform-origin-presentation-attribute-expected.xhtml: Added.
* svg/transforms/change-transform-origin-presentation-attribute.xhtml: Added.
* svg/transforms/percent-transform-values-expected.txt: Added.
* svg/transforms/percent-transform-values.xhtml: Added.
* svg/transforms/transform-origin-css-property-expected.xhtml: Added.
* svg/transforms/transform-origin-css-property.xhtml: Added.

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

16 files changed:
LayoutTests/ChangeLog
LayoutTests/platform/chromium/test_expectations.txt
LayoutTests/svg/transforms/change-transform-origin-css-expected.xhtml [new file with mode: 0644]
LayoutTests/svg/transforms/change-transform-origin-css.xhtml [new file with mode: 0644]
LayoutTests/svg/transforms/change-transform-origin-presentation-attribute-expected.xhtml [new file with mode: 0644]
LayoutTests/svg/transforms/change-transform-origin-presentation-attribute.xhtml [new file with mode: 0644]
LayoutTests/svg/transforms/percent-transform-values-expected.txt [new file with mode: 0644]
LayoutTests/svg/transforms/percent-transform-values.xhtml [new file with mode: 0644]
LayoutTests/svg/transforms/transform-origin-css-property-expected.xhtml [new file with mode: 0644]
LayoutTests/svg/transforms/transform-origin-css-property.xhtml [new file with mode: 0644]
Source/WebCore/ChangeLog
Source/WebCore/css/svg.css
Source/WebCore/platform/Length.h
Source/WebCore/rendering/style/RenderStyle.cpp
Source/WebCore/rendering/style/RenderStyle.h
Source/WebCore/svg/SVGStyledTransformableElement.cpp

index c0b4d25..e32b8d1 100644 (file)
@@ -1,3 +1,22 @@
+2012-03-12  Hans Muller  <hmuller@adobe.com>
+
+        SVG should support transform-origin and relative values
+        https://bugs.webkit.org/show_bug.cgi?id=79068
+
+        Reviewed by Dirk Schulze.
+
+        Added tests for SVG CSS transform-origin property support and for
+        CSS translations specified with percentages and applied to an SVG element.
+
+        * svg/transforms/change-transform-origin-css-expected.xhtml: Added.
+        * svg/transforms/change-transform-origin-css.xhtml: Added.
+        * svg/transforms/change-transform-origin-presentation-attribute-expected.xhtml: Added.
+        * svg/transforms/change-transform-origin-presentation-attribute.xhtml: Added.
+        * svg/transforms/percent-transform-values-expected.txt: Added.
+        * svg/transforms/percent-transform-values.xhtml: Added.
+        * svg/transforms/transform-origin-css-property-expected.xhtml: Added.
+        * svg/transforms/transform-origin-css-property.xhtml: Added.
+
 2012-03-12  Sam Weinig  <sam@webkit.org>
 
         Fix assert seen in DRT due to not calling EventSender.mouseUp in a previous test
index 258989e..626690e 100644 (file)
@@ -930,6 +930,9 @@ BUGCR62433 WIN : fast/images/gif-loop-count.html = IMAGE
 // SVG TESTS
 // -----------------------------------------------------------------
 
+// Chromium failure needs investigation
+BUGWK79068 : svg/transforms/transform-origin-css-property.xhtml = FAIL
+
 // New test requires rebaseline
 BUGWK77535 : svg/repaint/inner-svg-change-viewPort-relative.svg = IMAGE IMAGE+TEXT
 
diff --git a/LayoutTests/svg/transforms/change-transform-origin-css-expected.xhtml b/LayoutTests/svg/transforms/change-transform-origin-css-expected.xhtml
new file mode 100644 (file)
index 0000000..d2fdf38
--- /dev/null
@@ -0,0 +1,5 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<body>
+    <div style="position: absolute; left: 25px; top: 25px; width: 100px; height: 100px; background: green;"></div>
+</body>
+</html>
diff --git a/LayoutTests/svg/transforms/change-transform-origin-css.xhtml b/LayoutTests/svg/transforms/change-transform-origin-css.xhtml
new file mode 100644 (file)
index 0000000..38f94ce
--- /dev/null
@@ -0,0 +1,19 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+
+<!--
+Verify that changing the SVG transform-origin CSS property attribute works correctly.  Note that
+the default transform-origin for an SVG element is 0 0.
+
+The green 100x100 rectangle should appear at 25,25.
+-->
+
+<body>
+  <svg xmlns="http://www.w3.org/2000/svg" style="position: absolute; top: 0px; left: 0px;">
+      <rect id="rect" width="50px" height="50px" x="50" y="50" fill="green" style="-webkit-transform: scale(2, 2);"/>
+  </svg>
+
+  <script><![CDATA[
+      document.getElementById('rect').style.webkitTransformOrigin = "50% 50%";
+  ]]></script>
+</body>
+</html>
diff --git a/LayoutTests/svg/transforms/change-transform-origin-presentation-attribute-expected.xhtml b/LayoutTests/svg/transforms/change-transform-origin-presentation-attribute-expected.xhtml
new file mode 100644 (file)
index 0000000..d2fdf38
--- /dev/null
@@ -0,0 +1,5 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<body>
+    <div style="position: absolute; left: 25px; top: 25px; width: 100px; height: 100px; background: green;"></div>
+</body>
+</html>
diff --git a/LayoutTests/svg/transforms/change-transform-origin-presentation-attribute.xhtml b/LayoutTests/svg/transforms/change-transform-origin-presentation-attribute.xhtml
new file mode 100644 (file)
index 0000000..c03ee2b
--- /dev/null
@@ -0,0 +1,20 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+
+<!--
+Verify that changing the SVG transform-origin presentation attribute works correctly.
+
+The green 100x100 rectangle should appear at 25,25.
+-->
+
+<body>
+  <svg xmlns="http://www.w3.org/2000/svg" style="position: absolute; top: 0px; left: 0px;">
+      <rect id="rect" width="50px" height="50px" x="50" y="50" fill="green" transform-origin="0 0" style="-webkit-transform: scale(2, 2);"/>
+  </svg>
+
+  <script><![CDATA[
+
+      document.getElementById('rect').setAttribute("transform-origin", "50% 50%")
+
+  ]]></script>
+</body>
+</html>
diff --git a/LayoutTests/svg/transforms/percent-transform-values-expected.txt b/LayoutTests/svg/transforms/percent-transform-values-expected.txt
new file mode 100644 (file)
index 0000000..bf32734
--- /dev/null
@@ -0,0 +1,7 @@
+Test for bug 79068 - SVG should support transform-origin and relative values Verify that CSS transform translate values can be specified with percentages.
+
+You should see a series of "PASS" messages and one 80x60 green rectangle. The green rectangle obscures two red rectangles of the same size which have been translated to the same location.
+PASS  rect "r1" [50,200 80x60] expected [50,200 80x60]
+PASS  rect "r2" [50,200 80x60] expected [50,200 80x60]
+PASS  rect "r3" [50,200 80x60] expected [50,200 80x60]
+
diff --git a/LayoutTests/svg/transforms/percent-transform-values.xhtml b/LayoutTests/svg/transforms/percent-transform-values.xhtml
new file mode 100644 (file)
index 0000000..aa2cf51
--- /dev/null
@@ -0,0 +1,35 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<body>
+  <p>Test for bug <a href="">79068</a> - SVG should support transform-origin and relative values
+  Verify that CSS transform translate values can be specified with percentages.
+  </p>
+  You should see a series of "PASS" messages and one 80x60 green rectangle.   The green rectangle obscures two
+  red rectangles of the same size which have been translated to the same location.
+  <p>
+  </p>
+  <svg style="position:absolute; left:0px; top:0px;" xmlns="http://www.w3.org/2000/svg">
+    <rect id="r1" x="10" y="200" width="80" height="60" fill="red" style="-webkit-transform: translate(50%)"/>
+    <rect id="r2" x="90" y="260" width="80" height="60" fill="red" style="-webkit-transform: translate(-50%, -100%)"/>
+    <rect id="r3" x="10" y="200" width="80" height="60" fill="green" style="-webkit-transform: translate(50%, 0%)"/>
+  </svg>
+  <pre id="log"></pre>
+</body>
+<script><![CDATA[
+
+    var resultString = "";
+
+    function checkClientRect(rectID) {
+        var cr = document.getElementById(rectID).getBoundingClientRect();
+        var crString = "[" + cr.left + "," + cr.top + " " + cr.width + "x" + cr.height + "]";
+        var expected = "[50,200 80x60]";
+        resultString += ((crString == expected) ? "PASS " : "FAIL ") + " rect \"" + rectID + "\" " + crString + " expected " + expected + "\n";
+    }
+
+    ["r1", "r2", "r3"].map(checkClientRect);
+    document.getElementById("log").innerHTML = resultString;
+
+    if (window.layoutTestController)
+        layoutTestController.dumpAsText();
+
+ ]]></script>
+</html>
diff --git a/LayoutTests/svg/transforms/transform-origin-css-property-expected.xhtml b/LayoutTests/svg/transforms/transform-origin-css-property-expected.xhtml
new file mode 100644 (file)
index 0000000..41f4068
--- /dev/null
@@ -0,0 +1,45 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<style>
+#transformOriginDiv {
+   position: absolute;
+   width: 30px;
+   height: 30px;
+   background: green;
+   -webkit-transform: rotate(90deg);
+}
+</style>
+
+<body>
+  <div id="divRoot"></div>
+
+  <script><![CDATA[
+
+    function addTransformOriginDiv(x, y, transformOrigin)
+    {
+       var div = document.createElement("div");
+       div.setAttribute("id", "transformOriginDiv");
+       div.setAttribute("style", "top: " + y + "px; left: "+ x + "px; -webkit-transform-origin: " + transformOrigin + ";");
+       document.getElementById("divRoot").appendChild(div);
+    }
+
+    var transformOrigins = [
+         "50% 50%",
+         "0% 0%",
+         "0% 50%",
+         "100% 0%",
+         "0% 50%",
+         "100% 50%",
+         "0% 100%",
+         "50% 100%",
+         "100% 100%",
+     ];
+
+     for (var i = 0; i < transformOrigins.length; i++)  {
+         var x = 60 + (i %  4) * 60;
+         var y = 60 + Math.floor(i / 4) * 60;
+         addTransformOriginDiv(x, y, transformOrigins[i]);
+     }
+
+  ]]></script>
+</body>
+</html>
diff --git a/LayoutTests/svg/transforms/transform-origin-css-property.xhtml b/LayoutTests/svg/transforms/transform-origin-css-property.xhtml
new file mode 100644 (file)
index 0000000..19630bc
--- /dev/null
@@ -0,0 +1,61 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<style>
+#svgRoot {
+    position: absolute;
+    top: 0;
+    left: 0;
+}
+
+#transformOriginRect {
+    fill: green;
+    -webkit-transform: rotate(90deg);
+}
+</style>
+
+<!--
+  Test for bug 79068 - SVG should support transform-origin and relative values.
+
+  You should see 9 green 20x20 rectangles.  Each green rectangle is actually one of a set of about 6, each one
+  with a different but equivalent value for the CSS transform-origin property.
+-->
+
+<body>
+  <svg id="svgRoot" xmlns="http://www.w3.org/2000/svg"></svg>
+
+  <script><![CDATA[
+    var svgNS = "http://www.w3.org/2000/svg";
+
+    function addTransformOriginRect(x, y, s)
+    {
+       var rect = document.createElementNS(svgNS, "rect");
+       var transformOrigin = (typeof(s) == "string") ? s :  (x + s[0]) + " " + (y + s[1]);
+       rect.setAttribute("id", "transformOriginRect");
+       rect.setAttribute("x", x);
+       rect.setAttribute("y", y);
+       rect.setAttribute("width", 30);
+       rect.setAttribute("height", 30);
+       rect.setAttribute("style", "-webkit-transform-origin: " + transformOrigin + ";");
+       document.getElementById("svgRoot").appendChild(rect);
+    }
+
+    var equivalentTransformOrigins = [
+         ["50% 50%", "center 50%", "50% center", "center", "center center", [15, 15]],
+         ["0% 0%", "left 0%", "0% top", "left top", "top left", [0, 0]],
+         ["0% 50%", "left 50%", "0% center", "left", "left center", "center left", [0, 15]],
+         ["100% 0%", "right 0%", "100% top", "right top", "top right", [30, 0]],
+         ["0% 50%", "left 50%", "0% center", "left center", "center left", [0, 15]],
+         ["100% 50%", "right 50%", "100% center", "right center", "center right", [30, 15]],
+         ["0% 100%", "left 100%", "0% bottom", "left bottom", "left bottom", [0, 30]],
+         ["50% 100%", "center 100%", "50% bottom", "bottom", "center bottom", "bottom center", [15, 30]],
+         ["100% 100%", "right 100%", "100% bottom", "right bottom", "bottom right", [30, 30]]
+     ];
+
+     for (var i = 0; i < equivalentTransformOrigins.length; i++)  {
+         var x = 60 + (i %  4) * 60;
+         var y = 60 + Math.floor(i / 4) * 60;
+         equivalentTransformOrigins[i].map( function(s) { addTransformOriginRect(x, y, s); } );
+     }
+
+  ]]></script>
+</body>
+</html>
index bc66391..2c2db71 100644 (file)
@@ -1,3 +1,43 @@
+2012-03-12  Hans Muller  <hmuller@adobe.com>
+
+        SVG should support transform-origin and relative values
+        https://bugs.webkit.org/show_bug.cgi?id=79068
+
+        Reviewed by Dirk Schulze.
+
+        Added SVG support for the CSS 'transform-origin' property and for percentage
+        values in the transform translate function.  The changes conform to
+        http://dev.w3.org/csswg/css3-transforms/.
+
+        Tests: svg/transforms/percent-transform-values.xhtml
+               svg/transforms/transform-origin-css-property.xhtml
+
+        * css/svg.css:
+        (*):
+        (html|* > svg):
+        Default transform-origin for SVG elements is 0 0.
+
+        * platform/Length.h:
+        (WebCore::Length::calcFloatValue):
+        Added a calcFloatValue overload whose max parameter (for percent lengths) is a float.
+        The original version will be obsolete when the sub-pixel layout support is completed.
+
+        * rendering/style/RenderStyle.cpp:
+        * rendering/style/RenderStyle.h:
+        (WebCore):
+        (WebCore::requireTransformOrigin):
+        Transforms that only include translations don't depend on the transform-origin.
+
+        (WebCore::RenderStyle::applyTransform):
+        SVG elements interpret non-percentage/keyword transform-origin values relative to their viewport,
+        unlike HTML which interprets all transform-origin values relative to the element's origin.
+        The new FloatRect applyTransform() function handles SVG semantics. Similarly, SVG elements interpret
+        percentage/keyword transform-origin values relative to the origin of their objectBoundingBox(), HTML
+        uses the borderBox.  All this per http://dev.w3.org/csswg/css3-transforms/.
+
+        * svg/SVGStyledTransformableElement.cpp:
+        (WebCore::SVGStyledTransformableElement::animatedLocalTransform):
+
 2012-03-12  Dana Jansens  <danakj@chromium.org>
 
         [chromium] Use projectQuad to apply inverse mapRect
index bc31269..6ec4b23 100644 (file)
@@ -26,6 +26,7 @@
  */
 
 @namespace "http://www.w3.org/2000/svg";
+@namespace html "http://www.w3.org/1999/xhtml";
 
 /*
     When an outermost SVG 'svg' element is stand-alone or embedded inline within a parent XML grammar 
@@ -63,3 +64,13 @@ text, tspan, tref {
 :focus {
     outline: auto 5px -webkit-focus-ring-color
 }
+
+/* CSS transform specification: "transform-origin 0 0 for SVG elements without associated CSS layout box, 50% 50% for all other elements". */
+* {
+    -webkit-transform-origin: 0 0;
+}
+
+html|* > svg {
+    -webkit-transform-origin: 50% 50%;
+}
index 2bcf932..5e74742 100644 (file)
@@ -2,6 +2,7 @@
     Copyright (C) 1999 Lars Knoll (knoll@kde.org)
     Copyright (C) 2006, 2008 Apple Inc. All rights reserved.
     Copyright (C) 2011 Rik Cabanier (cabanier@adobe.com)
+    Copyright (C) 2011 Adobe Systems Incorporated. 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
@@ -203,6 +204,7 @@ public:
         return 0;
     }
 
+    // FIXME: when subpixel layout is supported this copy of calcFloatValue() can be removed. See bug 71143.
     float calcFloatValue(int maxValue) const
     {
         switch (type()) {
@@ -225,6 +227,28 @@ public:
         return 0;
     }
 
+    float calcFloatValue(float maxValue) const
+    {
+        switch (type()) {
+        case Fixed:
+            return getFloatValue();
+        case Percent:
+            return static_cast<float>(maxValue * percent() / 100.0f);
+        case Auto:
+            return static_cast<float>(maxValue);
+        case Calculated:
+            return nonNanCalculatedValue(maxValue);
+        case Relative:
+        case Intrinsic:
+        case MinIntrinsic:
+        case Undefined:
+            ASSERT_NOT_REACHED();
+            return 0;
+        }
+        ASSERT_NOT_REACHED();
+        return 0;
+    }
+
     bool isUndefined() const { return type() == Undefined; }
 
     // FIXME calc: https://bugs.webkit.org/show_bug.cgi?id=80357. A calculated Length 
index 8f31e0f..8c1a3ad 100644 (file)
@@ -1,6 +1,7 @@
 /*
  * Copyright (C) 1999 Antti Koivisto (koivisto@kde.org)
  * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010 Apple Inc. All rights reserved.
+ * Copyright (C) 2011 Adobe Systems Incorporated. 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
@@ -769,39 +770,70 @@ void RenderStyle::setContent(QuoteType quote, bool add)
 
     rareNonInheritedData.access()->m_content = ContentData::create(quote);
 }
-
-void RenderStyle::applyTransform(TransformationMatrix& transform, const LayoutSize& borderBoxSize, ApplyTransformOrigin applyOrigin) const
+    
+inline bool requireTransformOrigin(const Vector<RefPtr<TransformOperation> >& transformOperations, RenderStyle::ApplyTransformOrigin applyOrigin)
 {
     // transform-origin brackets the transform with translate operations.
     // Optimize for the case where the only transform is a translation, since the transform-origin is irrelevant
     // in that case.
-    bool applyTransformOrigin = false;
-    unsigned s = rareNonInheritedData->m_transform->m_operations.operations().size();
-    unsigned i;
-    if (applyOrigin == IncludeTransformOrigin) {
-        for (i = 0; i < s; i++) {
-            TransformOperation::OperationType type = rareNonInheritedData->m_transform->m_operations.operations()[i]->getOperationType();
-            if (type != TransformOperation::TRANSLATE_X
-                    && type != TransformOperation::TRANSLATE_Y
-                    && type != TransformOperation::TRANSLATE 
-                    && type != TransformOperation::TRANSLATE_Z
-                    && type != TransformOperation::TRANSLATE_3D
-                    ) {
-                applyTransformOrigin = true;
-                break;
-            }
-        }
+    if (applyOrigin != RenderStyle::IncludeTransformOrigin)
+        return false;
+
+    unsigned size = transformOperations.size();
+    for (unsigned i = 0; i < size; ++i) {
+        TransformOperation::OperationType type = transformOperations[i]->getOperationType();
+        if (type != TransformOperation::TRANSLATE_X
+            && type != TransformOperation::TRANSLATE_Y
+            && type != TransformOperation::TRANSLATE 
+            && type != TransformOperation::TRANSLATE_Z
+            && type != TransformOperation::TRANSLATE_3D)
+            return true;
     }
+    
+    return false;
+}
 
-    if (applyTransformOrigin) {
+void RenderStyle::applyTransform(TransformationMatrix& transform, const LayoutSize& borderBoxSize, ApplyTransformOrigin applyOrigin) const
+{
+    // FIXME: when subpixel layout is supported (bug 71143) the body of this function could be replaced by
+    // applyTransform(transform, FloatRect(FloatPoint(), borderBoxSize), applyOrigin);
+    
+    const Vector<RefPtr<TransformOperation> >& transformOperations = rareNonInheritedData->m_transform->m_operations.operations();
+    bool applyTransformOrigin = requireTransformOrigin(transformOperations, applyOrigin);
+
+    if (applyTransformOrigin)
         transform.translate3d(transformOriginX().calcFloatValue(borderBoxSize.width()), transformOriginY().calcFloatValue(borderBoxSize.height()), transformOriginZ());
-    }
 
-    for (i = 0; i < s; i++)
-        rareNonInheritedData->m_transform->m_operations.operations()[i]->apply(transform, borderBoxSize);
+    unsigned size = transformOperations.size();
+    for (unsigned i = 0; i < size; ++i)
+        transformOperations[i]->apply(transform, borderBoxSize);
 
+    if (applyTransformOrigin)
+        transform.translate3d(-transformOriginX().calcFloatValue(borderBoxSize.width()), -transformOriginY().calcFloatValue(borderBoxSize.height()), -transformOriginZ()); 
+}
+
+void RenderStyle::applyTransform(TransformationMatrix& transform, const FloatRect& boundingBox, ApplyTransformOrigin applyOrigin) const
+{
+    const Vector<RefPtr<TransformOperation> >& transformOperations = rareNonInheritedData->m_transform->m_operations.operations();
+    bool applyTransformOrigin = requireTransformOrigin(transformOperations, applyOrigin);
+    
+    float offsetX = transformOriginX().type() == Percent ? boundingBox.x() : 0;
+    float offsetY = transformOriginY().type() == Percent ? boundingBox.y() : 0;
+    
+    if (applyTransformOrigin) {
+        transform.translate3d(transformOriginX().calcFloatValue(boundingBox.width()) + offsetX,
+                              transformOriginY().calcFloatValue(boundingBox.height()) + offsetY,
+                              transformOriginZ());
+    }
+    
+    unsigned size = transformOperations.size();
+    for (unsigned i = 0; i < size; ++i)
+        transformOperations[i]->apply(transform, boundingBox.size());
+    
     if (applyTransformOrigin) {
-        transform.translate3d(-transformOriginX().calcFloatValue(borderBoxSize.width()), -transformOriginY().calcFloatValue(borderBoxSize.height()), -transformOriginZ());
+        transform.translate3d(-transformOriginX().calcFloatValue(boundingBox.width()) - offsetX,
+                              -transformOriginY().calcFloatValue(boundingBox.height()) - offsetY,
+                              -transformOriginZ());
     }
 }
 
index 55151d3..34b57ee 100644 (file)
@@ -894,6 +894,7 @@ public:
 
     enum ApplyTransformOrigin { IncludeTransformOrigin, ExcludeTransformOrigin };
     void applyTransform(TransformationMatrix&, const LayoutSize& borderBoxSize, ApplyTransformOrigin = IncludeTransformOrigin) const;
+    void applyTransform(TransformationMatrix&, const FloatRect& boundingBox, ApplyTransformOrigin = IncludeTransformOrigin) const;
     void setPageScaleTransform(float);
 
     bool hasMask() const { return rareNonInheritedData->m_mask.hasImage() || rareNonInheritedData->m_maskBoxImage.hasImage(); }
index 99c1781..02f35d3 100644 (file)
@@ -66,14 +66,15 @@ AffineTransform SVGStyledTransformableElement::animatedLocalTransform() const
     AffineTransform matrix;
     RenderStyle* style = renderer() ? renderer()->style() : 0;
 
-    // if CSS property was set, use that, otherwise fallback to attribute (if set)
+    // If CSS property was set, use that, otherwise fallback to attribute (if set).
     if (style && style->hasTransform()) {
-        TransformationMatrix t;
-        // For now, the transform-origin is not taken into account
-        // Also, any percentage values will not be taken into account
-        style->applyTransform(t, IntSize(0, 0), RenderStyle::ExcludeTransformOrigin);
-        // Flatten any 3D transform
-        matrix = t.toAffineTransform();
+        // Note: objectBoundingBox is an emptyRect for elements like pattern or clipPath.
+        // See the "Object bounding box units" section of http://dev.w3.org/csswg/css3-transforms/
+        TransformationMatrix transform;
+        style->applyTransform(transform, renderer()->objectBoundingBox());
+
+        // Flatten any 3D transform.
+        matrix = transform.toAffineTransform();
     } else
         transform().concatenate(matrix);