getComputedStyle returns wrong value for CSS3 2D transformations
authorcommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 23 Aug 2012 17:23:20 +0000 (17:23 +0000)
committercommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 23 Aug 2012 17:23:20 +0000 (17:23 +0000)
https://bugs.webkit.org/show_bug.cgi?id=94211

Patch by Alexander Shalamov <alexander.shalamov@intel.com> on 2012-08-23
Reviewed by Simon Fraser.

Source/WebCore:

When computed style is calculated for CSS3 2D transformation, content
box size is used. According to W3C specification, object's bounding
box should be used. This patch fixes transformation matrix calculation.

Layout tests getComputedStyle-transform.html and computed-style-origin.html
were modified to test changes.

* css/CSSComputedStyleDeclaration.cpp:
(WebCore::computedTransform):
(WebCore::CSSComputedStyleDeclaration::getPropertyCSSValue):
(WebCore::pixelSnappedSizingBox): Removed unused method

LayoutTests:

This change fixes getComputedStyle-transform.html test.
Before this change, the test doesn't do anything.
When new transformation value is set, it immediately read
back as an old value, thus computed style is equal to
an old style. Moreover, expected result is never checked.
Added new test case to computed-style-origin.html layout test.

* fast/css/getComputedStyle/getComputedStyle-transform-expected.txt:
* fast/css/getComputedStyle/getComputedStyle-transform.html:
* transforms/2d/computed-style-origin-expected.txt:
* transforms/2d/computed-style-origin.html:

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

LayoutTests/ChangeLog
LayoutTests/fast/css/getComputedStyle/getComputedStyle-transform-expected.txt
LayoutTests/fast/css/getComputedStyle/getComputedStyle-transform.html
LayoutTests/transforms/2d/computed-style-origin-expected.txt
LayoutTests/transforms/2d/computed-style-origin.html
Source/WebCore/ChangeLog
Source/WebCore/css/CSSComputedStyleDeclaration.cpp

index 0efc92f..d864313 100644 (file)
@@ -1,3 +1,22 @@
+2012-08-23  Alexander Shalamov  <alexander.shalamov@intel.com>
+
+        getComputedStyle returns wrong value for CSS3 2D transformations
+        https://bugs.webkit.org/show_bug.cgi?id=94211
+
+        Reviewed by Simon Fraser.
+
+        This change fixes getComputedStyle-transform.html test.
+        Before this change, the test doesn't do anything.
+        When new transformation value is set, it immediately read
+        back as an old value, thus computed style is equal to
+        an old style. Moreover, expected result is never checked.
+        Added new test case to computed-style-origin.html layout test.
+
+        * fast/css/getComputedStyle/getComputedStyle-transform-expected.txt:
+        * fast/css/getComputedStyle/getComputedStyle-transform.html:
+        * transforms/2d/computed-style-origin-expected.txt:
+        * transforms/2d/computed-style-origin.html:
+
 2012-08-23  Takashi Sakamoto  <tasak@google.com>
 
         Distributed nodes should not share styles.
index e3a93eb..7aa07b4 100644 (file)
@@ -1,4 +1,5 @@
 translate(80px, 90px) expected matrix(1, 0, 0, 1, 80, 90) : PASS
+translate(10px, 50%) expected matrix(1, 0, 0, 1, 10, 60) : PASS
 scale(1.2, 0.8) expected matrix(1.2, 0, 0, 0.8, 0, 0) : PASS
 skew(-0.7rad, 20deg) expected matrix(1, 0.36397, -0.842288, 1, 0, 0) : PASS
 rotate(45deg) expected matrix(0.707107, 0.707107, -0.707107, 0.707107, 0, 0) : PASS
index f74bfc6..447edfe 100644 (file)
     .box {
       height: 100%;
       width: 100%;
+      padding: 5px;
+      margin: 5px;
+      border: 5px solid gray;
       background-color: green;
       -webkit-transform-origin: 20% 50%;
     }
     #results {
-      margin-top: 100px;
+      margin-top: 150px;
     }
   </style>
   <script type="text/javascript" charset="utf-8">
 
     var gTests = [
       { 'transform' : 'translate(80px, 90px)',  'result' : 'matrix(1, 0, 0, 1, 80, 90)' },
+      { 'transform' : 'translate(10px, 50%)',   'result' : 'matrix(1, 0, 0, 1, 10, 60)' },
       { 'transform' : 'scale(1.2, 0.8)',        'result' : 'matrix(1.2, 0, 0, 0.8, 0, 0)' },
       { 'transform' : 'skew(-0.7rad, 20deg)',   'result' : 'matrix(1, 0.36397, -0.842288, 1, 0, 0)' },
       { 'transform' : 'rotate(45deg)',          'result' : 'matrix(0.707107, 0.707107, -0.707107, 0.707107, 0, 0)' },
     ];
+
+    function compareTransform(expected, computed)
+    {
+      var re = /^matrix\(([^,]+), ([^,]+), ([^,]+), ([^,]+), ([^,]+?)(?:px)?, ([^,]+?)(?:px)?\)$/;
+      var parsedExpected = re.exec(expected);
+      var parsedComputed = re.exec(computed);
+      for(var i = 1; i < 7; i++) {
+         // use +/- 0.05 to avoid problems with rounding
+         if (!(Math.abs(parsedComputed[i] - parsedExpected[i]) < 0.05))
+            return false;
+      }
+      return true;
+    }
     
     function runTests()
     {
       var testBox = document.getElementById('test-box');
+      var testSpan = document.getElementById('test-span');
       var resultsBox = document.getElementById('results');
 
       gTests.forEach(function(curTest) {
         // set one of our test transforms
         testBox.style.webkitTransform = curTest.transform;
-        // read back computed style
-        var oldTransform = window.getComputedStyle(testBox).webkitTransform;
-        // set that matrix() back on the element
-        testBox.style.webkitTransform = oldTransform;
+        testSpan.style.webkitTransform = curTest.transform;
         // read back computed style
         var computedTransform = window.getComputedStyle(testBox).webkitTransform;
-        
-        var success = (oldTransform == computedTransform);
+        var computedSpanTransform = window.getComputedStyle(testSpan).webkitTransform;
+        // compare expected result to computed transformation matrix
+        var success = compareTransform(curTest.result, computedTransform);
         var result;
         if (success)
           result = curTest.transform + ' expected <code>' + curTest.result + '</code> : PASS';
         else
-          result = curTest.transform + ' expected <code>' + oldTransform + '</code>, got <code>' + computedTransform + '</code> : FAIL';
+          result = curTest.transform + ' expected <code>' + curTest.result + '</code>, got <code>' + computedTransform + '</code> : FAIL';
         resultsBox.innerHTML += result + '<br>';
+
+        if (computedSpanTransform !== 'none') {
+          result = curTest.transform + ' applied to a non-box element: ' + ' expected <code>none</code> got <code>' + computedSpanTransform + '</code> : FAIL';
+          resultsBox.innerHTML += result + '<br>';
+        }
       });
       
       if (window.testRunner)
@@ -70,6 +91,8 @@
     <div id="test-box" class="box"></div>
   </div>
 
+  <span id="test-span" class="box"></span>
+
   <div id="results">
   </div>
 </body>
index 516699f..e85f3d3 100644 (file)
@@ -7,6 +7,7 @@ PASS test1Style.webkitTransformOrigin is '10px 10px'
 PASS test2Style.webkitTransformOrigin is '10px 10px'
 PASS test3Style.webkitTransformOrigin is '0px 20px'
 PASS test4Style.webkitTransformOrigin is '5px 7px'
+PASS test5Style.webkitTransformOrigin is '15px 15px'
 
 PASS successfullyParsed is true
 
index 5f3444c..73d9dd3 100644 (file)
         -webkit-transform: translate(0);
         -webkit-transform-origin: 5px 7px;
     }
+    #test5 {
+        width: 10px;
+        height: 10px;
+        padding: 5px;
+        margin: 5px;
+        border: 5px solid green;
+        background-color: blue;
+        position: relative;
+        -webkit-transform: translate(0);
+        -webkit-transform-origin: 50% 50%;
+    }
+
 </style>
 <script src="../../fast/js/resources/js-test-pre.js"></script>
 </head>
@@ -41,6 +53,7 @@
 <p id="test2"></p>
 <p id="test3"></p>
 <p id="test4"></p>
+<p id="test5"></p>
 <p id="description"></p>
 <div id="console"></div>
 <script>
@@ -51,16 +64,19 @@ var test1 = document.getElementById("test1");
 var test2 = document.getElementById("test2");
 var test3 = document.getElementById("test3");
 var test4 = document.getElementById("test4");
+var test5 = document.getElementById("test5");
 
 var test1Style = window.getComputedStyle(test1);
 var test2Style = window.getComputedStyle(test2);
 var test3Style = window.getComputedStyle(test3);
 var test4Style = window.getComputedStyle(test4);
+var test5Style = window.getComputedStyle(test5);
 
 shouldBe("test1Style.webkitTransformOrigin", "'10px 10px'");
 shouldBe("test2Style.webkitTransformOrigin", "'10px 10px'");
 shouldBe("test3Style.webkitTransformOrigin", "'0px 20px'");
 shouldBe("test4Style.webkitTransformOrigin", "'5px 7px'");
+shouldBe("test5Style.webkitTransformOrigin", "'15px 15px'");
 
 debug("");
 
index 8955e0c..a030d30 100644 (file)
@@ -1,3 +1,22 @@
+2012-08-23  Alexander Shalamov  <alexander.shalamov@intel.com>
+
+        getComputedStyle returns wrong value for CSS3 2D transformations
+        https://bugs.webkit.org/show_bug.cgi?id=94211
+
+        Reviewed by Simon Fraser.
+
+        When computed style is calculated for CSS3 2D transformation, content
+        box size is used. According to W3C specification, object's bounding
+        box should be used. This patch fixes transformation matrix calculation.
+
+        Layout tests getComputedStyle-transform.html and computed-style-origin.html
+        were modified to test changes.
+
+        * css/CSSComputedStyleDeclaration.cpp:
+        (WebCore::computedTransform):
+        (WebCore::CSSComputedStyleDeclaration::getPropertyCSSValue):
+        (WebCore::pixelSnappedSizingBox): Removed unused method
+
 2012-08-23  Takashi Sakamoto  <tasak@google.com>
 
         Distributed nodes should not share styles.
index fe10eb0..d7c344c 100644 (file)
@@ -715,21 +715,14 @@ static LayoutRect sizingBox(RenderObject* renderer)
     return box->style()->boxSizing() == BORDER_BOX ? box->borderBoxRect() : box->computedCSSContentBoxRect();
 }
 
-static IntRect pixelSnappedSizingBox(RenderObject* renderer)
-{
-    if (!renderer->isBox())
-        return IntRect();
-
-    RenderBox* box = toRenderBox(renderer);
-    return box->style()->boxSizing() == BORDER_BOX ? box->pixelSnappedBorderBoxRect() : pixelSnappedIntRect(box->computedCSSContentBoxRect());
-}
-
 static PassRefPtr<CSSValue> computedTransform(RenderObject* renderer, const RenderStyle* style)
 {
-    if (!renderer || style->transform().operations().isEmpty())
+    if (!renderer || !renderer->hasTransform() || !style->hasTransform())
         return cssValuePool().createIdentifierValue(CSSValueNone);
 
-    IntRect box = pixelSnappedSizingBox(renderer);
+    IntRect box;
+    if (renderer->isBox())
+        box = pixelSnappedIntRect(toRenderBox(renderer)->borderBoxRect());
 
     TransformationMatrix transform;
     style->applyTransform(transform, box.size(), RenderStyle::ExcludeTransformOrigin);
@@ -2327,7 +2320,10 @@ PassRefPtr<CSSValue> CSSComputedStyleDeclaration::getPropertyCSSValue(CSSPropert
         case CSSPropertyWebkitTransformOrigin: {
             RefPtr<CSSValueList> list = CSSValueList::createSpaceSeparated();
             if (renderer) {
-                LayoutRect box = sizingBox(renderer);
+                LayoutRect box;
+                if (renderer->isBox())
+                    box = toRenderBox(renderer)->borderBoxRect();
+
                 RenderView* renderView = m_node->document()->renderView();
                 list->append(zoomAdjustedPixelValue(minimumValueForLength(style->transformOriginX(), box.width(), renderView), style.get()));
                 list->append(zoomAdjustedPixelValue(minimumValueForLength(style->transformOriginY(), box.height(), renderView), style.get()));