Title: [134352] trunk
Revision
134352
Author
k...@webkit.org
Date
2012-11-12 20:51:53 -0800 (Mon, 12 Nov 2012)

Log Message

BasicShapes 'circle', 'rectangle', 'ellipse' should be animatable with themselves
https://bugs.webkit.org/show_bug.cgi?id=101854

Reviewed by Andreas Kling.

Source/WebCore:

The basic shapes BasicShapeCircle, BasicShapeEllipse and BasicShapeRectangle should
blend with themselves. This patch introduces simple interpolation of BasicShapes for
the -webkit-clip-path property.

Test: css3/masking/clip-path-animation.html

* page/animation/CSSPropertyAnimation.cpp:
(WebCore::blendFunc): Added a new function that blends between two BasicShape objects.
    It skips blending on <clipPath> references, polygons and if the shapes are not of
    the same type.
(WebCore):
(PropertyWrapperClipPath): Added new wrapper for ClipPathShapes.
(WebCore::PropertyWrapperClipPath::PropertyWrapperClipPath): Ditto.
(WebCore::CSSPropertyAnimation::ensurePropertyMap): Add -webkit-clip-path to animatable
    properties.
* rendering/style/BasicShapes.cpp:
    The blending is done by each shape itself. This is similar to FilterOperations or
    TransformOperations.
(WebCore::BasicShapeRectangle::blend):
(WebCore):
(WebCore::BasicShapeCircle::blend):
(WebCore::BasicShapeEllipse::blend):
(WebCore::BasicShapePolygon::blend):
* rendering/style/BasicShapes.h:
    Added new blending functions to header.
(BasicShape):
(BasicShapeRectangle):
(BasicShapeCircle):
(BasicShapeEllipse):
(BasicShapePolygon):

LayoutTests:

Added an animtation test for -webkit-clip-path and tested the basic shapes.

* animations/resources/animation-test-helpers.js:
(parseBasicShape):
(basicShapeParametersMatch):
(getPropertyValue):
(comparePropertyValue):
* css3/masking/clip-path-animation-expected.txt: Added.
* css3/masking/clip-path-animation.html: Added.

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (134351 => 134352)


--- trunk/LayoutTests/ChangeLog	2012-11-13 04:46:20 UTC (rev 134351)
+++ trunk/LayoutTests/ChangeLog	2012-11-13 04:51:53 UTC (rev 134352)
@@ -1,3 +1,20 @@
+2012-11-10  Dirk Schulze  <k...@webkit.org>
+
+        BasicShapes 'circle', 'rectangle', 'ellipse' should be animatable with themselves
+        https://bugs.webkit.org/show_bug.cgi?id=101854
+
+        Reviewed by Andreas Kling.
+
+        Added an animtation test for -webkit-clip-path and tested the basic shapes.
+
+        * animations/resources/animation-test-helpers.js:
+        (parseBasicShape):
+        (basicShapeParametersMatch):
+        (getPropertyValue):
+        (comparePropertyValue):
+        * css3/masking/clip-path-animation-expected.txt: Added.
+        * css3/masking/clip-path-animation.html: Added.
+
 2012-11-12  Erik Arvidsson  <a...@chromium.org>
 
         Replace DOMException TYPE_MISMATCH_ERR with TypeError

Modified: trunk/LayoutTests/animations/resources/animation-test-helpers.js (134351 => 134352)


--- trunk/LayoutTests/animations/resources/animation-test-helpers.js	2012-11-13 04:46:20 UTC (rev 134351)
+++ trunk/LayoutTests/animations/resources/animation-test-helpers.js	2012-11-13 04:51:53 UTC (rev 134352)
@@ -59,6 +59,58 @@
     return {"from": matches[1], "to": matches[2], "percent": parseFloat(matches[3])}
 }
 
+function parseBasicShape(s)
+{
+    var shapeFunction = s.match(/(\w+)\((.+)\)/);
+    if (!shapeFunction)
+        return null;
+
+    var matches;
+    switch (shapeFunction[1]) {
+    case "rectangle":
+        matches = s.match("rectangle\\((.*)\\s*,\\s*(.*)\\s*,\\s*(.*)\\,\\s*(.*)\\)");
+        break;
+    case "circle":
+        matches = s.match("circle\\((.*)\\s*,\\s*(.*)\\s*,\\s*(.*)\\)");
+        break;
+    case "ellipse":
+        matches = s.match("ellipse\\((.*)\\s*,\\s*(.*)\\s*,\\s*(.*)\\,\\s*(.*)\\)");
+        break;
+    default:
+        return null;
+    }
+
+    if (!matches)
+        return null;
+
+    matches.shift();
+
+    // Normalize percentage values.
+    for (var i = 0; i < matches.length; ++i) {
+        var param = matches[i];
+        matches[i] = parseFloat(matches[i]);
+        if (param.indexOf('%') != -1)
+            matches[i] = matches[i] / 100;
+    }
+
+    return {"shape": shapeFunction[1], "params": matches};
+}
+
+function basicShapeParametersMatch(paramList1, paramList2, tolerance)
+{
+    if (paramList1.shape != paramList2.shape
+        || paramList1.params.length != paramList2.params.length)
+        return false;
+    for (var i = 0; i < paramList1.params.length; ++i) {
+        var param1 = paramList1.params[i], 
+            param2 = paramList2.params[i];
+        var match = isCloseEnough(param1, param2, tolerance);
+        if (!match)
+            return false;
+    }
+    return true;
+}
+
 // Return an array of numeric filter params in 0-1.
 function getFilterParameters(s)
 {
@@ -243,6 +295,7 @@
                || property == "webkitMaskImage"
                || property == "webkitMaskBoxImage"
                || property == "webkitFilter"
+               || property == "webkitClipPath"
                || !property.indexOf("webkitTransform")) {
         computedValue = window.getComputedStyle(element)[property.split(".")[0]];
     } else {
@@ -275,6 +328,12 @@
         var filterParameters = getFilterParameters(computedValue);
         var filter2Parameters = getFilterParameters(expectedValue);
         result = filterParametersMatch(filterParameters, filter2Parameters, tolerance);
+    } else if (property == "webkitClipPath") {
+        var clipPathParameters = parseBasicShape(computedValue);
+        var clipPathParameters2 = parseBasicShape(expectedValue);
+        if (!clipPathParameters || !clipPathParameters2)
+            result = false;
+        result = basicShapeParametersMatch(clipPathParameters, clipPathParameters2, tolerance);
     } else if (property == "backgroundImage"
                || property == "borderImageSource"
                || property == "listStyleImage"

Added: trunk/LayoutTests/css3/masking/clip-path-animation-expected.txt (0 => 134352)


--- trunk/LayoutTests/css3/masking/clip-path-animation-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/css3/masking/clip-path-animation-expected.txt	2012-11-13 04:51:53 UTC (rev 134352)
@@ -0,0 +1,5 @@
+  
+PASS - "webkitClipPath" property for "rectangle-box" element at 1s saw something close to: rectangle(10%, 10%, 80%, 80%)
+PASS - "webkitClipPath" property for "circle-box" element at 1s saw something close to: circle(35%, 35%, 35%)
+PASS - "webkitClipPath" property for "ellipse-box" element at 1s saw something close to: ellipse(35%, 35%, 35%, 30%)
+

Added: trunk/LayoutTests/css3/masking/clip-path-animation.html (0 => 134352)


--- trunk/LayoutTests/css3/masking/clip-path-animation.html	                        (rev 0)
+++ trunk/LayoutTests/css3/masking/clip-path-animation.html	2012-11-13 04:51:53 UTC (rev 134352)
@@ -0,0 +1,64 @@
+<!DOCTYPE html>
+
+<html>
+<head>
+  <style>
+    .box {
+        height: 100px;
+        width: 100px;
+        margin: 10px;
+        background-color: blue;
+        display: inline-block;
+    }
+
+    #rectangle-box {
+      -webkit-animation: rectangle-anim 2s linear
+    }
+
+    #circle-box {
+      -webkit-animation: circle-anim 2s linear
+    }
+
+    #ellipse-box {
+      -webkit-animation: ellipse-anim 2s linear
+    }
+
+
+    @-webkit-keyframes rectangle-anim {
+        from { -webkit-clip-path: rectangle(0%, 0%, 100%, 100%); }
+        to   { -webkit-clip-path: rectangle(20%, 20%, 60%, 60%); }
+    }
+
+    @-webkit-keyframes circle-anim {
+        from { -webkit-clip-path: circle(50%, 50%, 50%); }
+        to   { -webkit-clip-path: circle(20%, 20%, 20%); }
+    }
+
+    @-webkit-keyframes ellipse-anim {
+        from { -webkit-clip-path: ellipse(50%, 50%, 50%, 40%); }
+        to   { -webkit-clip-path: ellipse(20%, 20%, 20%, 20%); }
+    }
+
+  </style>
+  <script src=""
+  <script type="text/_javascript_">
+    const expectedValues = [
+      // [animation-name, time, element-id, property, expected-value, tolerance]
+      ["rectangle-anim",  1, "rectangle-box", "webkitClipPath", 'rectangle(10%, 10%, 80%, 80%)', 0.05],
+      ["circle-anim",  1, "circle-box", "webkitClipPath", 'circle(35%, 35%, 35%)', 0.05],
+      ["ellipse-anim",  1, "ellipse-box", "webkitClipPath", 'ellipse(35%, 35%, 35%, 30%)', 0.05],
+    ];
+    
+    runAnimationTest(expectedValues);
+  </script>
+</head>
+<body>
+
+<div class="box" id="rectangle-box"></div>
+<div class="box" id="circle-box"></div>
+<div class="box" id="ellipse-box"></div>
+
+<div id="result">
+</div>
+</body>
+</html>

Modified: trunk/Source/WebCore/ChangeLog (134351 => 134352)


--- trunk/Source/WebCore/ChangeLog	2012-11-13 04:46:20 UTC (rev 134351)
+++ trunk/Source/WebCore/ChangeLog	2012-11-13 04:51:53 UTC (rev 134352)
@@ -1,3 +1,41 @@
+2012-11-10  Dirk Schulze  <k...@webkit.org>
+
+        BasicShapes 'circle', 'rectangle', 'ellipse' should be animatable with themselves
+        https://bugs.webkit.org/show_bug.cgi?id=101854
+
+        Reviewed by Andreas Kling.
+
+        The basic shapes BasicShapeCircle, BasicShapeEllipse and BasicShapeRectangle should
+        blend with themselves. This patch introduces simple interpolation of BasicShapes for
+        the -webkit-clip-path property.
+
+        Test: css3/masking/clip-path-animation.html
+
+        * page/animation/CSSPropertyAnimation.cpp:
+        (WebCore::blendFunc): Added a new function that blends between two BasicShape objects.
+            It skips blending on <clipPath> references, polygons and if the shapes are not of
+            the same type.
+        (WebCore):
+        (PropertyWrapperClipPath): Added new wrapper for ClipPathShapes.
+        (WebCore::PropertyWrapperClipPath::PropertyWrapperClipPath): Ditto.
+        (WebCore::CSSPropertyAnimation::ensurePropertyMap): Add -webkit-clip-path to animatable
+            properties.
+        * rendering/style/BasicShapes.cpp:
+            The blending is done by each shape itself. This is similar to FilterOperations or
+            TransformOperations.
+        (WebCore::BasicShapeRectangle::blend):
+        (WebCore):
+        (WebCore::BasicShapeCircle::blend):
+        (WebCore::BasicShapeEllipse::blend):
+        (WebCore::BasicShapePolygon::blend):
+        * rendering/style/BasicShapes.h:
+            Added new blending functions to header.
+        (BasicShape):
+        (BasicShapeRectangle):
+        (BasicShapeCircle):
+        (BasicShapeEllipse):
+        (BasicShapePolygon):
+
 2012-11-12  Adam Barth  <aba...@webkit.org>
 
         [V8] We should be able to get V8PerContextData from a v8::Context more quickly

Modified: trunk/Source/WebCore/page/animation/CSSPropertyAnimation.cpp (134351 => 134352)


--- trunk/Source/WebCore/page/animation/CSSPropertyAnimation.cpp	2012-11-13 04:46:20 UTC (rev 134351)
+++ trunk/Source/WebCore/page/animation/CSSPropertyAnimation.cpp	2012-11-13 04:51:53 UTC (rev 134352)
@@ -35,6 +35,7 @@
 #include "CSSImageValue.h"
 #include "CSSPrimitiveValue.h"
 #include "CSSPropertyNames.h"
+#include "ClipPathOperation.h"
 #include "FloatConversion.h"
 #include "IdentityTransformOperation.h"
 #include "Matrix3DTransformOperation.h"
@@ -125,6 +126,26 @@
     return to.blendByUsingMatrixInterpolation(from, progress, anim->renderer()->isBox() ? toRenderBox(anim->renderer())->borderBoxRect().size() : LayoutSize());
 }
 
+static inline PassRefPtr<ClipPathOperation> blendFunc(const AnimationBase*, ClipPathOperation* from, ClipPathOperation* to, double progress)
+{
+    // Other clip-path operations than BasicShapes can not be animated.
+    if (from->getOperationType() != ClipPathOperation::SHAPE || to->getOperationType() != ClipPathOperation::SHAPE)
+        return to;
+
+    const BasicShape* fromShape = static_cast<ShapeClipPathOperation*>(from)->basicShape();
+    const BasicShape* toShape = static_cast<ShapeClipPathOperation*>(to)->basicShape();
+
+    // FIXME: Support animations between different shapes in the future.
+    if (fromShape->type() != toShape->type())
+        return to;
+
+    // FIXME: Support animations between polygons in the future.
+    if (fromShape->type() == BasicShape::BASIC_SHAPE_POLYGON)
+        return to;
+
+    return ShapeClipPathOperation::create(toShape->blend(fromShape, progress));
+}
+
 #if ENABLE(CSS_FILTERS)
 static inline PassRefPtr<FilterOperation> blendFunc(const AnimationBase* anim, FilterOperation* fromOp, FilterOperation* toOp, double progress, bool blendToPassthrough = false)
 {
@@ -368,6 +389,14 @@
 };
 
 
+class PropertyWrapperClipPath : public RefCountedPropertyWrapper<ClipPathOperation> {
+public:
+    PropertyWrapperClipPath(CSSPropertyID prop, ClipPathOperation* (RenderStyle::*getter)() const, void (RenderStyle::*setter)(PassRefPtr<ClipPathOperation>))
+        : RefCountedPropertyWrapper<ClipPathOperation>(prop, getter, setter)
+    {
+    }
+};
+
 class StyleImagePropertyWrapper : public RefCountedPropertyWrapper<StyleImage> {
 public:
     StyleImagePropertyWrapper(CSSPropertyID prop, StyleImage* (RenderStyle::*getter)() const, void (RenderStyle::*setter)(PassRefPtr<StyleImage>))
@@ -1114,6 +1143,8 @@
 #endif
 #endif
 
+    gPropertyWrappers->append(new PropertyWrapperClipPath(CSSPropertyWebkitClipPath, &RenderStyle::clipPath, &RenderStyle::setClipPath));
+
     gPropertyWrappers->append(new PropertyWrapperVisitedAffectedColor(CSSPropertyWebkitColumnRuleColor, MaybeInvalidColor, &RenderStyle::columnRuleColor, &RenderStyle::setColumnRuleColor, &RenderStyle::visitedLinkColumnRuleColor, &RenderStyle::setVisitedLinkColumnRuleColor));
     gPropertyWrappers->append(new PropertyWrapperVisitedAffectedColor(CSSPropertyWebkitTextStrokeColor, MaybeInvalidColor, &RenderStyle::textStrokeColor, &RenderStyle::setTextStrokeColor, &RenderStyle::visitedLinkTextStrokeColor, &RenderStyle::setVisitedLinkTextStrokeColor));
     gPropertyWrappers->append(new PropertyWrapperVisitedAffectedColor(CSSPropertyWebkitTextFillColor, MaybeInvalidColor, &RenderStyle::textFillColor, &RenderStyle::setTextFillColor, &RenderStyle::visitedLinkTextFillColor, &RenderStyle::setVisitedLinkTextFillColor));

Modified: trunk/Source/WebCore/rendering/style/BasicShapes.cpp (134351 => 134352)


--- trunk/Source/WebCore/rendering/style/BasicShapes.cpp	2012-11-13 04:46:20 UTC (rev 134351)
+++ trunk/Source/WebCore/rendering/style/BasicShapes.cpp	2012-11-13 04:51:53 UTC (rev 134352)
@@ -32,6 +32,7 @@
 #include "BasicShapes.h"
 #include "FloatRect.h"
 #include "LengthFunctions.h"
+#include "NotImplemented.h"
 #include "Path.h"
 
 namespace WebCore {
@@ -47,6 +48,23 @@
                                   m_cornerRadiusY.isUndefined() ? 0 : floatValueForLength(m_cornerRadiusY, boundingBox.height())));
 }
 
+PassRefPtr<BasicShape> BasicShapeRectangle::blend(const BasicShape* other, double progress) const
+{
+    ASSERT(type() == other->type());
+
+    const BasicShapeRectangle* o = static_cast<const BasicShapeRectangle*>(other);
+    RefPtr<BasicShapeRectangle> result =  BasicShapeRectangle::create();
+    result->setX(m_x.blend(o->x(), progress));
+    result->setY(m_y.blend(o->y(), progress));
+    result->setWidth(m_width.blend(o->width(), progress));
+    result->setHeight(m_height.blend(o->height(), progress));
+    if (!m_cornerRadiusX.isUndefined() && !o->cornerRadiusX().isUndefined())
+        result->setCornerRadiusX(m_cornerRadiusX.blend(o->cornerRadiusX(), progress));
+    if (!m_cornerRadiusY.isUndefined() && !o->cornerRadiusY().isUndefined())
+        result->setCornerRadiusY(m_cornerRadiusY.blend(o->cornerRadiusY(), progress));
+    return result.release();
+}
+
 void BasicShapeCircle::path(Path& path, const FloatRect& boundingBox)
 {
     ASSERT(path.isEmpty());
@@ -60,6 +78,18 @@
                               radius * 2));
 }
 
+PassRefPtr<BasicShape> BasicShapeCircle::blend(const BasicShape* other, double progress) const
+{
+    ASSERT(type() == other->type());
+
+    const BasicShapeCircle* o = static_cast<const BasicShapeCircle*>(other);
+    RefPtr<BasicShapeCircle> result =  BasicShapeCircle::create();
+    result->setCenterX(m_centerX.blend(o->centerX(), progress));
+    result->setCenterY(m_centerY.blend(o->centerY(), progress));
+    result->setRadius(m_radius.blend(o->radius(), progress));
+    return result.release();
+}
+
 void BasicShapeEllipse::path(Path& path, const FloatRect& boundingBox)
 {
     ASSERT(path.isEmpty());
@@ -73,6 +103,19 @@
                               radiusY * 2));
 }
 
+PassRefPtr<BasicShape> BasicShapeEllipse::blend(const BasicShape* other, double progress) const
+{
+    ASSERT(type() == other->type());
+
+    const BasicShapeEllipse* o = static_cast<const BasicShapeEllipse*>(other);
+    RefPtr<BasicShapeEllipse> result =  BasicShapeEllipse::create();
+    result->setCenterX(m_centerX.blend(o->centerX(), progress));
+    result->setCenterY(m_centerY.blend(o->centerY(), progress));
+    result->setRadiusX(m_radiusX.blend(o->radiusX(), progress));
+    result->setRadiusY(m_radiusY.blend(o->radiusY(), progress));
+    return result.release();
+}
+
 void BasicShapePolygon::path(Path& path, const FloatRect& boundingBox)
 {
     ASSERT(path.isEmpty());
@@ -90,4 +133,10 @@
     }
     path.closeSubpath();
 }
+
+PassRefPtr<BasicShape> BasicShapePolygon::blend(const BasicShape*, double) const
+{
+    notImplemented();
+    return BasicShapePolygon::create();
 }
+}

Modified: trunk/Source/WebCore/rendering/style/BasicShapes.h (134351 => 134352)


--- trunk/Source/WebCore/rendering/style/BasicShapes.h	2012-11-13 04:46:20 UTC (rev 134351)
+++ trunk/Source/WebCore/rendering/style/BasicShapes.h	2012-11-13 04:51:53 UTC (rev 134352)
@@ -54,6 +54,7 @@
 
     virtual void path(Path&, const FloatRect&) = 0;
     virtual WindRule windRule() const { return RULE_NONZERO; }
+    virtual PassRefPtr<BasicShape> blend(const BasicShape*, double) const = 0;
 
     virtual Type type() const = 0;
 protected:
@@ -78,7 +79,8 @@
     void setCornerRadiusX(Length radiusX) { m_cornerRadiusX = radiusX; }
     void setCornerRadiusY(Length radiusY) { m_cornerRadiusY = radiusY; }
 
-    virtual void path(Path&, const FloatRect&);
+    virtual void path(Path&, const FloatRect&) OVERRIDE;
+    virtual PassRefPtr<BasicShape> blend(const BasicShape*, double) const OVERRIDE;
 
     virtual Type type() const { return BASIC_SHAPE_RECTANGLE; }
 private:
@@ -107,7 +109,8 @@
     void setCenterY(Length centerY) { m_centerY = centerY; }
     void setRadius(Length radius) { m_radius = radius; }
 
-    virtual void path(Path&, const FloatRect&);
+    virtual void path(Path&, const FloatRect&) OVERRIDE;
+    virtual PassRefPtr<BasicShape> blend(const BasicShape*, double) const OVERRIDE;
 
     virtual Type type() const { return BASIC_SHAPE_CIRCLE; }
 private:
@@ -132,7 +135,8 @@
     void setRadiusX(Length radiusX) { m_radiusX = radiusX; }
     void setRadiusY(Length radiusY) { m_radiusY = radiusY; }
 
-    virtual void path(Path&, const FloatRect&);
+    virtual void path(Path&, const FloatRect&) OVERRIDE;
+    virtual PassRefPtr<BasicShape> blend(const BasicShape*, double) const OVERRIDE;
 
     virtual Type type() const { return BASIC_SHAPE_ELLIPSE; } 
 private:
@@ -155,7 +159,9 @@
     void setWindRule(WindRule windRule) { m_windRule = windRule; }
     void appendPoint(Length x, Length y) { m_values.append(x); m_values.append(y); }
 
-    virtual void path(Path&, const FloatRect&);
+    virtual void path(Path&, const FloatRect&) OVERRIDE;
+    virtual PassRefPtr<BasicShape> blend(const BasicShape*, double) const OVERRIDE;
+
     virtual WindRule windRule() const { return m_windRule; }
 
     virtual Type type() const { return BASIC_SHAPE_POLYGON; }
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
http://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to