2011-01-24 Simon Fraser <simon.fraser@apple.com>
authorsimon.fraser@apple.com <simon.fraser@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 25 Jan 2011 05:15:56 +0000 (05:15 +0000)
committersimon.fraser@apple.com <simon.fraser@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 25 Jan 2011 05:15:56 +0000 (05:15 +0000)
        Reviewed by Chris Marrin.

        perspective() transform function should take lengths
        https://bugs.webkit.org/show_bug.cgi?id=52683

        The argument to the perspective() transform function should
        be a Length, rather than a bare number. Bare numbers are still
        accepted (and treated as px), but this behavior is deprecated.

        Test: animations/3d/transform-perspective.html
              transforms/3d/general/3dtransform-values.html

        * css/CSSParser.cpp:
        (WebCore::CSSParser::parseTransform): Check the units for the perspective()
        function. Allow bare numbers for backwards compatibility.
        * css/CSSStyleSelector.cpp:
        (WebCore::CSSStyleSelector::createTransformOperations): Convert
        value to Length.
        * platform/graphics/transforms/PerspectiveTransformOperation.cpp:
        (WebCore::clampToPostiveInteger): Helper.
        (WebCore::PerspectiveTransformOperation::blend): Blend via Lengths.
        * platform/graphics/transforms/PerspectiveTransformOperation.h:
        (WebCore::PerspectiveTransformOperation::create): double -> Length.
        (WebCore::PerspectiveTransformOperation::perspective): Ditto.
        (WebCore::PerspectiveTransformOperation::isIdentity): Ditto.
        (WebCore::PerspectiveTransformOperation::apply): Ditto.
        (WebCore::PerspectiveTransformOperation::PerspectiveTransformOperation): Assert
        that the Length is a fixed type.

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

LayoutTests/ChangeLog
LayoutTests/animations/3d/transform-perspective-expected.txt [new file with mode: 0644]
LayoutTests/animations/3d/transform-perspective.html [new file with mode: 0644]
LayoutTests/transforms/3d/general/3dtransform-values-expected.txt
LayoutTests/transforms/3d/general/3dtransform-values.html
Source/WebCore/ChangeLog
Source/WebCore/css/CSSParser.cpp
Source/WebCore/css/CSSStyleSelector.cpp
Source/WebCore/platform/graphics/transforms/PerspectiveTransformOperation.cpp
Source/WebCore/platform/graphics/transforms/PerspectiveTransformOperation.h

index 24d478d..8e40430 100644 (file)
@@ -1,3 +1,17 @@
+2011-01-24  Simon Fraser  <simon.fraser@apple.com>
+
+        Reviewed by Chris Marrin.
+
+        perspective() transform function should take lengths
+        https://bugs.webkit.org/show_bug.cgi?id=52683
+        
+        Add tests for perspective() handling, and interpolation for animation.
+
+        * animations/3d/transform-perspective-expected.txt: Added.
+        * animations/3d/transform-perspective.html: Added.
+        * transforms/3d/general/3dtransform-values-expected.txt:
+        * transforms/3d/general/3dtransform-values.html:
+
 2011-01-24  Kent Tamura  <tkent@chromium.org>
 
         Reviewed by Dimitri Glazkov.
diff --git a/LayoutTests/animations/3d/transform-perspective-expected.txt b/LayoutTests/animations/3d/transform-perspective-expected.txt
new file mode 100644 (file)
index 0000000..be68229
--- /dev/null
@@ -0,0 +1,3 @@
+PASS - "webkitTransform" property for "box" element at 0.5s saw something close to: 1,0,0,0,0,1,0,0,0,0,1,-0.0075,0,0,0,1
+PASS - "webkitTransform" property for "box2" element at 0.5s saw something close to: 1,0,0,0,0,1,0,0,0,0,1,-0.00199,0,0,0,1
+
diff --git a/LayoutTests/animations/3d/transform-perspective.html b/LayoutTests/animations/3d/transform-perspective.html
new file mode 100644 (file)
index 0000000..1c0ac44
--- /dev/null
@@ -0,0 +1,54 @@
+<!DOCTYPE html>
+
+<html>
+<head>
+  <style type="text/css">
+    .box {
+      height: 100px;
+      width: 100px;
+      background-color: blue;
+    }
+    
+    #box {
+      -webkit-animation: anim 2s linear;
+    }
+    
+    #box2 {
+      -webkit-animation: anim2 2s linear;
+    }
+
+    @-webkit-keyframes anim {
+        from { -webkit-transform: perspective(100px); }
+        to   { -webkit-transform: perspective(200px); }
+    }
+
+    @-webkit-keyframes anim2 {
+        from { -webkit-transform: perspective(1000px); }
+        to   { -webkit-transform: none; }
+    }
+  </style>
+  <script src="../animation-test-helpers.js" type="text/javascript"></script>
+  <script type="text/javascript">
+    const expectedValues = [
+      // [time, element-id, property, expected-value, tolerance]
+      ["anim",  0.5, "box",  "webkitTransform", [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, -0.0075, 0, 0, 0, 1], 0.002],
+      ["anim2", 0.5, "box2", "webkitTransform", [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, -0.00199, 0, 0, 0, 1], 0.002],
+    ];
+    
+    function setupTest()
+    {
+      var box = document.getElementById('box');
+      box.style.webkitTransform = 'perspective(1000px) rotateX(90deg)';
+    }
+    
+    runAnimationTest(expectedValues);
+  </script>
+</head>
+<body>
+
+<div class="box" id="box"></div>
+<div class="box" id="box2"></div>
+<div id="result"></div>
+
+</body>
+</html>
index 353d3f8..b2c9698 100644 (file)
@@ -9,4 +9,12 @@ transform "translateZ(10)" expected "none" : PASS
 transform "rotate3d(0, 1, 0, 180)" expected "none" : PASS
 transform "rotate3d(0, 1, 0, 180px)" expected "none" : PASS
 transform "rotate3d(0, 1, 0, 180px)" expected "none" : PASS
+transform "perspective(400)" expected "matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, -0.0025, 0, 0, 0, 1)" : PASS
+transform "perspective(400px)" expected "matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, -0.0025, 0, 0, 0, 1)" : PASS
+transform "perspective(400em)" expected "matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, -0.00015625, 0, 0, 0, 1)" : PASS
+transform "perspective(50%)" expected "none" : PASS
+transform "perspective(-400)" expected "none" : PASS
+transform "perspective(0)" expected "matrix(1, 0, 0, 1, 0, 0)" : PASS
+transform "perspective(400deg)" expected "none" : PASS
+transform "perspective(banana)" expected "none" : PASS
 
index f6a1ea9..6039326 100644 (file)
       { 'transform' : 'rotate3d(0, 1, 0, 180)', 'result' : 'none' }, // last value must be an angle
       { 'transform' : 'rotate3d(0, 1, 0, 180px)', 'result' : 'none' }, // last value must be an angle
       { 'transform' : 'rotate3d(0, 1, 0, 180px)', 'result' : 'none' }, // last value must be an angle
+      { 'transform' : 'perspective(400)', 'result' : 'matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, -0.0025, 0, 0, 0, 1)' }, // legacy
+      { 'transform' : 'perspective(400px)', 'result' : 'matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, -0.0025, 0, 0, 0, 1)' },
+      { 'transform' : 'perspective(400em)', 'result' : 'matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, -0.00015625, 0, 0, 0, 1)' },
+      { 'transform' : 'perspective(50%)', 'result' : 'none' },
+      { 'transform' : 'perspective(-400)', 'result' : 'none' },
+      { 'transform' : 'perspective(0)', 'result' : 'matrix(1, 0, 0, 1, 0, 0)' },
+      { 'transform' : 'perspective(400deg)', 'result' : 'none' }, // unit must be length
+      { 'transform' : 'perspective(banana)', 'result' : 'none' }, // unit must be length
     ];
     
     function runTests()
index 6f16628..6104938 100644 (file)
@@ -1,3 +1,34 @@
+2011-01-24  Simon Fraser  <simon.fraser@apple.com>
+
+        Reviewed by Chris Marrin.
+
+        perspective() transform function should take lengths
+        https://bugs.webkit.org/show_bug.cgi?id=52683
+        
+        The argument to the perspective() transform function should
+        be a Length, rather than a bare number. Bare numbers are still
+        accepted (and treated as px), but this behavior is deprecated.
+
+        Test: animations/3d/transform-perspective.html
+              transforms/3d/general/3dtransform-values.html
+
+        * css/CSSParser.cpp:
+        (WebCore::CSSParser::parseTransform): Check the units for the perspective()
+        function. Allow bare numbers for backwards compatibility.
+        * css/CSSStyleSelector.cpp:
+        (WebCore::CSSStyleSelector::createTransformOperations): Convert
+        value to Length.
+        * platform/graphics/transforms/PerspectiveTransformOperation.cpp:
+        (WebCore::clampToPostiveInteger): Helper.
+        (WebCore::PerspectiveTransformOperation::blend): Blend via Lengths.
+        * platform/graphics/transforms/PerspectiveTransformOperation.h:
+        (WebCore::PerspectiveTransformOperation::create): double -> Length.
+        (WebCore::PerspectiveTransformOperation::perspective): Ditto.
+        (WebCore::PerspectiveTransformOperation::isIdentity): Ditto.
+        (WebCore::PerspectiveTransformOperation::apply): Ditto.
+        (WebCore::PerspectiveTransformOperation::PerspectiveTransformOperation): Assert
+        that the Length is a fixed type.
+
 2011-01-24  Kent Tamura  <tkent@chromium.org>
 
         Reviewed by Dimitri Glazkov.
index a4ded65..89220cd 100644 (file)
@@ -5316,6 +5316,10 @@ PassRefPtr<CSSValueList> CSSParser::parseTransform()
                 // 1st param of translateZ() cannot be a percentage
                 if (!validUnit(a, FLength, true))
                     return 0;
+            } else if (info.type() == WebKitCSSTransformValue::PerspectiveTransformOperation && argNumber == 0) {
+                // 1st param of perspective() must be a non-negative number (deprecated) or length.
+                if (!validUnit(a, FNumber | FLength | FNonNeg, true))
+                    return 0;
             } else if (!validUnit(a, unit, true))
                 return 0;
 
index 63090cf..58d1473 100644 (file)
@@ -7052,9 +7052,21 @@ bool CSSStyleSelector::createTransformOperations(CSSValue* inValue, RenderStyle*
                 break;
             }   
             case WebKitCSSTransformValue::PerspectiveTransformOperation: {
-                double p = firstValue->getDoubleValue();
-                if (p < 0.0)
+                bool ok = true;
+                Length p = Length(0, Fixed);
+                if (CSSPrimitiveValue::isUnitTypeLength(firstValue->primitiveType()))
+                    p = convertToLength(firstValue, style, rootStyle, zoomFactor, &ok);
+                else {
+                    // This is a quirk that should go away when 3d transforms are finalized.
+                    double val = firstValue->getDoubleValue();
+                    ok = val >= 0;
+                    val = min<double>(val, numeric_limits<int>::max());
+                    p = Length(static_cast<int>(val), Fixed);
+                }
+                
+                if (!ok)
                     return false;
+
                 operations.operations().append(PerspectiveTransformOperation::create(p));
                 break;
             }
index 9fd03a1..258cfbe 100644 (file)
 #include "PerspectiveTransformOperation.h"
 
 #include <algorithm>
+#include <limits>
 
 using namespace std;
 
 namespace WebCore {
 
+static int clampToPostiveInteger(double val)
+{
+    return static_cast<int>(max<double>(min<double>(val, numeric_limits<int>::max()), 0));
+}
+
 PassRefPtr<TransformOperation> PerspectiveTransformOperation::blend(const TransformOperation* from, double progress, bool blendToIdentity)
 {
     if (from && !from->isSameType(*this))
         return this;
     
-    if (blendToIdentity)
-        return PerspectiveTransformOperation::create(m_p + (1. - m_p) * progress);
+    if (blendToIdentity) {
+        double p = m_p.calcFloatValue(1);
+        p = p + (1. - p) * progress; // FIXME: this seems wrong. https://bugs.webkit.org/show_bug.cgi?id=52700
+        return PerspectiveTransformOperation::create(Length(clampToPostiveInteger(p), Fixed));
+    }
     
     const PerspectiveTransformOperation* fromOp = static_cast<const PerspectiveTransformOperation*>(from);
-    double fromP = fromOp ? fromOp->m_p : 0;
-    double toP = m_p;
+    Length fromP = fromOp ? fromOp->m_p : Length(m_p.type());
+    Length toP = m_p;
 
     TransformationMatrix fromT;
     TransformationMatrix toT;
-    fromT.applyPerspective(fromP);
-    toT.applyPerspective(toP);
+    fromT.applyPerspective(fromP.calcFloatValue(1));
+    toT.applyPerspective(toP.calcFloatValue(1));
     toT.blend(fromT, progress);
     TransformationMatrix::DecomposedType decomp;
     toT.decompose(decomp);
-    
-    return PerspectiveTransformOperation::create(decomp.perspectiveZ ? -1.0 / decomp.perspectiveZ : 0.0);
+
+    if (decomp.perspectiveZ) {
+        double val = -1.0 / decomp.perspectiveZ;
+        return PerspectiveTransformOperation::create(Length(clampToPostiveInteger(val), Fixed));
+    }
+    return PerspectiveTransformOperation::create(Length(0, Fixed));
 }
 
 } // namespace WebCore
index 834cc83..886d3dc 100644 (file)
 #ifndef PerspectiveTransformOperation_h
 #define PerspectiveTransformOperation_h
 
+#include "Length.h"
 #include "TransformOperation.h"
 
 namespace WebCore {
 
 class PerspectiveTransformOperation : public TransformOperation {
 public:
-    static PassRefPtr<PerspectiveTransformOperation> create(double p)
+    static PassRefPtr<PerspectiveTransformOperation> create(const Length& p)
     {
         return adoptRef(new PerspectiveTransformOperation(p));
     }
 
-    double perspective() const { return m_p; }
+    Length perspective() const { return m_p; }
     
 private:
-    virtual bool isIdentity() const { return m_p == 0; }
+    virtual bool isIdentity() const { return m_p.calcFloatValue(1) == 0; }
     virtual OperationType getOperationType() const { return PERSPECTIVE; }
     virtual bool isSameType(const TransformOperation& o) const { return o.getOperationType() == PERSPECTIVE; }
 
@@ -54,18 +55,19 @@ private:
 
     virtual bool apply(TransformationMatrix& transform, const IntSize&) const
     {
-        transform.applyPerspective(m_p);
+        transform.applyPerspective(m_p.calcFloatValue(1));
         return false;
     }
 
     virtual PassRefPtr<TransformOperation> blend(const TransformOperation* from, double progress, bool blendToIdentity = false);
 
-    PerspectiveTransformOperation(double p)
+    PerspectiveTransformOperation(const Length& p)
         : m_p(p)
     {
+        ASSERT(p.isFixed());
     }
 
-    double m_p;
+    Length m_p;
 };
 
 } // namespace WebCore