2013-12-18 Rob Buis <rob.buis@samsung.com>
authorrwlbuis@webkit.org <rwlbuis@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 18 Dec 2013 17:27:58 +0000 (17:27 +0000)
committerrwlbuis@webkit.org <rwlbuis@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 18 Dec 2013 17:27:58 +0000 (17:27 +0000)
        [CSS Shapes] Implement interpolation between keywords in basic shapes
        https://bugs.webkit.org/show_bug.cgi?id=125108

        Reviewed by Simon Fraser.

        Allow blending for all center coordinates since top/left and bottom/right default to correct
        Length values of 0% and 100%. For mixed keyword and value positions compute the length's used
        for blending to percentages. This is possible since we compute the reference box bounds given the
        renderer.

        * page/animation/CSSPropertyAnimation.cpp:
        (WebCore::blendFunc): Pass additional RenderBox parameter.
        * rendering/style/BasicShapes.cpp:
        (WebCore::BasicShape::canBlend): Don't check circle/ellipse center anymore, but do check that both
        shapes use the same reference box.
        (WebCore::BasicShape::referenceBoxSize): Compute box dimension depending on reference box.
        (WebCore::BasicShapeCenterCoordinate::lengthForBlending): Convert to percentage for Bottom/Right.
        (WebCore::BasicShapeRectangle::blend):
        (WebCore::DeprecatedBasicShapeCircle::blend):
        (WebCore::BasicShapeCircle::blend):
        (WebCore::DeprecatedBasicShapeEllipse::blend):
        (WebCore::BasicShapeEllipse::blend):
        (WebCore::BasicShapePolygon::blend):
        (WebCore::BasicShapeInsetRectangle::blend):
        (WebCore::BasicShapeInset::blend):
        * rendering/style/BasicShapes.h:
        (WebCore::BasicShapeCenterCoordinate::blend): Use new lengthForBlending.

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

LayoutTests/ChangeLog
LayoutTests/fast/shapes/parsing/parsing-shape-inside-expected.txt
LayoutTests/fast/shapes/parsing/parsing-shape-outside-expected.txt
LayoutTests/fast/shapes/parsing/parsing-test-utils.js
LayoutTests/fast/shapes/shape-outside-floats/shape-outside-animation-expected.txt
LayoutTests/fast/shapes/shape-outside-floats/shape-outside-animation.html
Source/WebCore/ChangeLog
Source/WebCore/page/animation/CSSPropertyAnimation.cpp
Source/WebCore/rendering/style/BasicShapes.cpp
Source/WebCore/rendering/style/BasicShapes.h

index 2f987d8..9983a06 100644 (file)
@@ -1,3 +1,19 @@
+2013-12-18  Rob Buis  <rob.buis@samsung.com>
+
+        [CSS Shapes] Implement interpolation between keywords in basic shapes
+        https://bugs.webkit.org/show_bug.cgi?id=125108
+
+        Reviewed by Simon Fraser.
+
+        Add tests to shape-outside-animation when animating using keywords for the circle/ellipse center positions.
+        Also add tests for invalid mixing of keyword and values in the center coordinate to parsing-test-utils.js.
+
+        * fast/shapes/parsing/parsing-shape-inside-expected.txt:
+        * fast/shapes/parsing/parsing-shape-outside-expected.txt:
+        * fast/shapes/parsing/parsing-test-utils.js:
+        * fast/shapes/shape-outside-floats/shape-outside-animation-expected.txt:
+        * fast/shapes/shape-outside-floats/shape-outside-animation.html:
+
 2013-12-18  Dániel Bátyai  <dbatyai.u-szeged@partner.samsung.com>
 
         CSS: Null-pointer dereference with negative 'orphans' value.
index 1d08b5e..d361406 100644 (file)
@@ -191,6 +191,8 @@ PASS getCSSText("-webkit-shape-inside", "circle(10px at 10px 10px at center)") i
 PASS getComputedStyleValue("-webkit-shape-inside", "circle(10px at 10px 10px at center)") is "auto"
 PASS getCSSText("-webkit-shape-inside", "circle(10px at center center 10px)") is ""
 PASS getComputedStyleValue("-webkit-shape-inside", "circle(10px at center center 10px)") is "auto"
+PASS getCSSText("-webkit-shape-inside", "circle(10px at 10% left)") is ""
+PASS getComputedStyleValue("-webkit-shape-inside", "circle(10px at 10% left)") is "auto"
 PASS getCSSText("-webkit-shape-inside", "circle(at 10px 10px 10px)") is ""
 PASS getComputedStyleValue("-webkit-shape-inside", "circle(at 10px 10px 10px)") is "auto"
 PASS getCSSText("-webkit-shape-inside", "circle(at 10px 10px at center)") is ""
@@ -211,6 +213,8 @@ PASS getCSSText("-webkit-shape-inside", "ellipse(10px at 10px 10px at center)")
 PASS getComputedStyleValue("-webkit-shape-inside", "ellipse(10px at 10px 10px at center)") is "auto"
 PASS getCSSText("-webkit-shape-inside", "ellipse(10px at center center 10px)") is ""
 PASS getComputedStyleValue("-webkit-shape-inside", "ellipse(10px at center center 10px)") is "auto"
+PASS getCSSText("-webkit-shape-inside", "ellipse(10px 10px at 10% left)") is ""
+PASS getComputedStyleValue("-webkit-shape-inside", "ellipse(10px 10px at 10% left)") is "auto"
 PASS getCSSText("-webkit-shape-inside", "ellipse(10px 20px 30px at center center 10px)") is ""
 PASS getComputedStyleValue("-webkit-shape-inside", "ellipse(10px 20px 30px at center center 10px)") is "auto"
 PASS getCSSText("-webkit-shape-inside", "ellipse(at 10px 10px 10px)") is ""
index a89805e..edfb985 100644 (file)
@@ -189,6 +189,8 @@ PASS getCSSText("-webkit-shape-outside", "circle(10px at 10px 10px at center)")
 PASS getComputedStyleValue("-webkit-shape-outside", "circle(10px at 10px 10px at center)") is "auto"
 PASS getCSSText("-webkit-shape-outside", "circle(10px at center center 10px)") is ""
 PASS getComputedStyleValue("-webkit-shape-outside", "circle(10px at center center 10px)") is "auto"
+PASS getCSSText("-webkit-shape-outside", "circle(10px at 10% left)") is ""
+PASS getComputedStyleValue("-webkit-shape-outside", "circle(10px at 10% left)") is "auto"
 PASS getCSSText("-webkit-shape-outside", "circle(at 10px 10px 10px)") is ""
 PASS getComputedStyleValue("-webkit-shape-outside", "circle(at 10px 10px 10px)") is "auto"
 PASS getCSSText("-webkit-shape-outside", "circle(at 10px 10px at center)") is ""
@@ -209,6 +211,8 @@ PASS getCSSText("-webkit-shape-outside", "ellipse(10px at 10px 10px at center)")
 PASS getComputedStyleValue("-webkit-shape-outside", "ellipse(10px at 10px 10px at center)") is "auto"
 PASS getCSSText("-webkit-shape-outside", "ellipse(10px at center center 10px)") is ""
 PASS getComputedStyleValue("-webkit-shape-outside", "ellipse(10px at center center 10px)") is "auto"
+PASS getCSSText("-webkit-shape-outside", "ellipse(10px 10px at 10% left)") is ""
+PASS getComputedStyleValue("-webkit-shape-outside", "ellipse(10px 10px at 10% left)") is "auto"
 PASS getCSSText("-webkit-shape-outside", "ellipse(10px 20px 30px at center center 10px)") is ""
 PASS getComputedStyleValue("-webkit-shape-outside", "ellipse(10px 20px 30px at center center 10px)") is "auto"
 PASS getCSSText("-webkit-shape-outside", "ellipse(at 10px 10px 10px)") is ""
index 4231d28..cc32904 100644 (file)
@@ -117,6 +117,7 @@ var invalidShapeValues = [
     "circle(10px at 10px 10px 10px)",
     "circle(10px at 10px 10px at center)",
     "circle(10px at center center 10px)",
+    "circle(10px at 10% left)",
     "circle(at 10px 10px 10px)",
     "circle(at 10px 10px at center)",
     "circle(at center center 10px)",
@@ -129,6 +130,7 @@ var invalidShapeValues = [
     "ellipse(10px at 10px 10px 10px)",
     "ellipse(10px at 10px 10px at center)",
     "ellipse(10px at center center 10px)",
+    "ellipse(10px 10px at 10% left)",
     "ellipse(10px 20px 30px at center center 10px)",
     "ellipse(at 10px 10px 10px)",
     "ellipse(at 10px 10px at center)",
index 6870685..a3eee94 100644 (file)
@@ -4,10 +4,24 @@ Moving Text
 Moving Text
 Moving Text
 Moving Text
+Moving Text
+Moving Text
+Moving Text
+Moving Text
+Moving Text
+Moving Text
+Moving Text
 PASS - "webkitShapeOutside" property for "rectangle-box" element at 1s saw something close to: rectangle(10%, 10%, 80%, 80%, 0px, 0px)
 PASS - "webkitShapeOutside" property for "circle-box" element at 1s saw something close to: circle(35% at 35% 35%)
 PASS - "webkitShapeOutside" property for "ellipse-box" element at 1s saw something close to: ellipse(35% 30% at 35% 35%)
 PASS - "webkitShapeOutside" property for "polygon-box" element at 1s saw something close to: polygon(nonzero, 10% 10%, 90% 10%, 90% 90%, 10% 90%)
 PASS - "webkitShapeOutside" property for "polygon2-box" element at 1s saw something close to: polygon(nonzero, 20% 20%, 80% 20%, 80% 80%, 20% 80%)
 PASS - "webkitShapeOutside" property for "circle-auto-box" element at 1s saw something close to: circle(50% at 50% 50%)
+PASS - "webkitShapeOutside" property for "circle-to-topleft-box" element at 1s saw something close to: circle(35% at 25% 25%)
+PASS - "webkitShapeOutside" property for "circle-to-topleft-box" element at 1s saw something close to: circle(35% at 25% 25%)
+PASS - "webkitShapeOutside" property for "circle-to-bottomright-using-keyword-box" element at 1s saw something close to: circle(35% at 75% 75%)
+PASS - "webkitShapeOutside" property for "circle-to-bottomright-using-keyword-box" element at 1s saw something close to: circle(35% at 75% 75%)
+PASS - "webkitShapeOutside" property for "circle-to-bottomright-extended-box" element at 1s saw something close to: circle(35% at 75% 75%)
+PASS - "webkitShapeOutside" property for "circle-to-bottomright-extended-using-keyword-box" element at 1s saw something close to: circle(35% at 70% 70%)
+PASS - "webkitShapeOutside" property for "circle-to-bottomright-extended-using-keyword-2-box" element at 1s saw something close to: circle(35% at 70% 70%)
 
index d24f367..b9c33e4 100644 (file)
@@ -10,7 +10,7 @@
     .box {
         height: 100px;
         width: 100px;
-        margin: 10px;
+        margin: 50px;
         float: left;
     }
 
       -webkit-animation: circle-auto-anim 2s linear
     }
 
+    #circle-to-topleft-box {
+      -webkit-animation: circle-to-topleft-anim 2s linear
+    }
+
+    #circle-to-topleft-using-keyword-box {
+      -webkit-animation: circle-to-topleft-using-keyword-anim 2s linear
+    }
+
+    #circle-to-bottomright-box {
+      -webkit-animation: circle-to-bottomright-anim 2s linear
+    }
+
+    #circle-to-bottomright-using-keyword-box {
+      -webkit-animation: circle-to-bottomright-using-keyword-anim 2s linear
+    }
+
+    #circle-to-bottomright-extended-box {
+      -webkit-animation: circle-to-bottomright-extended-anim 2s linear
+    }
+
+    #circle-to-bottomright-extended-using-keyword-box {
+      -webkit-animation: circle-to-bottomright-extended-using-keyword-anim 2s linear
+    }
+
+    #circle-to-bottomright-extended-using-keyword-2-box {
+      -webkit-animation: circle-to-bottomright-extended-using-keyword-2-anim 2s linear
+    }
+
     @-webkit-keyframes rectangle-anim {
         from { -webkit-shape-outside: rectangle(0%, 0%, 100%, 100%); }
         to   { -webkit-shape-outside: rectangle(20%, 20%, 60%, 60%); }
         to   { -webkit-shape-outside: circle(50% at 50% 50%); }
     }
 
+    @-webkit-keyframes circle-to-topleft-anim {
+        from { -webkit-shape-outside: circle(50% at 50% 50%); }
+        to   { -webkit-shape-outside: circle(20% at 0% 0%); }
+    }
+
+    @-webkit-keyframes circle-to-topleft-using-keyword-anim {
+        from { -webkit-shape-outside: circle(50% at 50% 50%); }
+        to   { -webkit-shape-outside: circle(20% at left top); }
+    }
+
+    @-webkit-keyframes circle-to-bottomright-anim {
+        from { -webkit-shape-outside: circle(50% at 50% 50%); }
+        to   { -webkit-shape-outside: circle(20% at 100% 100%); }
+    }
+
+    @-webkit-keyframes circle-to-bottomright-using-keyword-anim {
+        from { -webkit-shape-outside: circle(50% at 50% 50%); }
+        to   { -webkit-shape-outside: circle(20% at right bottom); }
+    }
+
+    @-webkit-keyframes circle-to-bottomright-extended-anim {
+        from { -webkit-shape-outside: circle(50% at 50% 50%); }
+        to   { -webkit-shape-outside: circle(20% at 100% 100%); }
+    }
+
+    @-webkit-keyframes circle-to-bottomright-extended-using-keyword-anim {
+        from { -webkit-shape-outside: circle(50% at 50% 50%); }
+        to   { -webkit-shape-outside: circle(20% at right 10% bottom 20px); }
+    }
+
+    @-webkit-keyframes circle-to-bottomright-extended-using-keyword-2-anim {
+        from { -webkit-shape-outside: circle(50% at 50% 50%) border-box; }
+        to   { -webkit-shape-outside: circle(20% at right 10% bottom 10px) border-box; }
+    }
   </style>
   <script src="../../../animations/resources/animation-test-helpers.js"></script>
   <script type="text/javascript">
       ["polygon-anim",  1, "polygon-box", "webkitShapeOutside", "polygon(nonzero, 10% 10%, 90% 10%, 90% 90%, 10% 90%)", 0.05],
       ["polygon2-anim",  1, "polygon2-box", "webkitShapeOutside", "polygon(nonzero, 20% 20%, 80% 20%, 80% 80%, 20% 80%)", 0.05],
       ["circle-auto-anim",  1, "circle-auto-box", "webkitShapeOutside", "circle(50% at 50% 50%)", 0.05],
+      ["circle-to-topleft-anim",  1, "circle-to-topleft-box", "webkitShapeOutside", "circle(35% at 25% 25%)", 0.05],
+      ["circle-to-topleft-anim",  1, "circle-to-topleft-box", "webkitShapeOutside", "circle(35% at 25% 25%)", 0.05],
+      ["circle-to-bottomright-using-keyword-anim",  1, "circle-to-bottomright-using-keyword-box", "webkitShapeOutside", "circle(35% at 75% 75%)", 0.05],
+      ["circle-to-bottomright-using-keyword-anim",  1, "circle-to-bottomright-using-keyword-box", "webkitShapeOutside", "circle(35% at 75% 75%)", 0.05],
+      ["circle-to-bottomright-extended-anim",  1, "circle-to-bottomright-extended-box", "webkitShapeOutside", "circle(35% at 75% 75%)", 0.05],
+      ["circle-to-bottomright-extended-using-keyword-anim",  1, "circle-to-bottomright-extended-using-keyword-box", "webkitShapeOutside", "circle(35% at 70% 70%)", 0.01],
+      ["circle-to-bottomright-extended-using-keyword-2-anim",  1, "circle-to-bottomright-extended-using-keyword-2-box", "webkitShapeOutside", "circle(35% at 70% 70%)", 0.01],
     ];
     
     runAnimationTest(expectedValues);
   <div class="box" id="circle-auto-box"></div>
   Moving Text
 </div>
+<div class='container'>
+  <div class="box" id="circle-to-topleft-box"></div>
+  Moving Text
+</div>
+<div class='container'>
+  <div class="box" id="circle-to-topleft-using-keyword-box"></div>
+  Moving Text
+</div>
+<div class='container'>
+  <div class="box" id="circle-to-bottomright-box"></div>
+  Moving Text
+</div>
+<div class='container'>
+  <div class="box" id="circle-to-bottomright-using-keyword-box"></div>
+  Moving Text
+</div>
+<div class='container'>
+  <div class="box" id="circle-to-bottomright-extended-box"></div>
+  Moving Text
+</div>
+<div class='container'>
+  <div class="box" id="circle-to-bottomright-extended-using-keyword-box"></div>
+  Moving Text
+</div>
+<div class='container'>
+  <div class="box" id="circle-to-bottomright-extended-using-keyword-2-box"></div>
+  Moving Text
+</div>
 
 <div id="result">
 </div>
index 4f3611c..974b372 100644 (file)
@@ -1,3 +1,33 @@
+2013-12-18  Rob Buis  <rob.buis@samsung.com>
+
+        [CSS Shapes] Implement interpolation between keywords in basic shapes
+        https://bugs.webkit.org/show_bug.cgi?id=125108
+
+        Reviewed by Simon Fraser.
+
+        Allow blending for all center coordinates since top/left and bottom/right default to correct
+        Length values of 0% and 100%. For mixed keyword and value positions compute the length's used
+        for blending to percentages. This is possible since we compute the reference box bounds given the
+        renderer.
+
+        * page/animation/CSSPropertyAnimation.cpp:
+        (WebCore::blendFunc): Pass additional RenderBox parameter.
+        * rendering/style/BasicShapes.cpp:
+        (WebCore::BasicShape::canBlend): Don't check circle/ellipse center anymore, but do check that both
+        shapes use the same reference box.
+        (WebCore::BasicShape::referenceBoxSize): Compute box dimension depending on reference box.
+        (WebCore::BasicShapeCenterCoordinate::lengthForBlending): Convert to percentage for Bottom/Right.
+        (WebCore::BasicShapeRectangle::blend):
+        (WebCore::DeprecatedBasicShapeCircle::blend):
+        (WebCore::BasicShapeCircle::blend):
+        (WebCore::DeprecatedBasicShapeEllipse::blend):
+        (WebCore::BasicShapeEllipse::blend):
+        (WebCore::BasicShapePolygon::blend):
+        (WebCore::BasicShapeInsetRectangle::blend):
+        (WebCore::BasicShapeInset::blend):
+        * rendering/style/BasicShapes.h:
+        (WebCore::BasicShapeCenterCoordinate::blend): Use new lengthForBlending.
+
 2013-12-18  Dániel Bátyai  <dbatyai.u-szeged@partner.samsung.com>
 
         CSS: Null-pointer dereference with negative 'orphans' value.
index 6d12419..801eaa3 100644 (file)
@@ -125,7 +125,7 @@ static inline TransformOperations blendFunc(const AnimationBase* anim, const Tra
     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)
+static inline PassRefPtr<ClipPathOperation> blendFunc(const AnimationBase* anim, ClipPathOperation* from, ClipPathOperation* to, double progress)
 {
     if (!from || !to)
         return to;
@@ -140,11 +140,12 @@ static inline PassRefPtr<ClipPathOperation> blendFunc(const AnimationBase*, Clip
     if (!fromShape->canBlend(toShape))
         return to;
 
-    return ShapeClipPathOperation::create(toShape->blend(fromShape, progress));
+    ASSERT(anim->renderer()->isBox());
+    return ShapeClipPathOperation::create(toShape->blend(fromShape, progress, *toRenderBox(anim->renderer())));
 }
 
 #if ENABLE(CSS_SHAPES)
-static inline PassRefPtr<ShapeValue> blendFunc(const AnimationBase*, ShapeValue* from, ShapeValue* to, double progress)
+static inline PassRefPtr<ShapeValue> blendFunc(const AnimationBase* anim, ShapeValue* from, ShapeValue* to, double progress)
 {
     if (!from || !to)
         return to;
@@ -159,7 +160,8 @@ static inline PassRefPtr<ShapeValue> blendFunc(const AnimationBase*, ShapeValue*
     if (!fromShape->canBlend(toShape))
         return to;
 
-    return ShapeValue::createShapeValue(toShape->blend(fromShape, progress));
+    ASSERT(anim->renderer()->isBox());
+    return ShapeValue::createShapeValue(toShape->blend(fromShape, progress, *toRenderBox(anim->renderer())));
 }
 #endif
 
index 02eba07..8850b5a 100644 (file)
@@ -35,6 +35,7 @@
 #include "FloatRect.h"
 #include "LengthFunctions.h"
 #include "Path.h"
+#include "RenderBox.h"
 
 namespace WebCore {
 
@@ -44,32 +45,61 @@ bool BasicShape::canBlend(const BasicShape* other) const
     if (type() != other->type())
         return false;
 
+    // Both shapes must use the same reference box.
+    if (box() != other->box())
+        return false;
+
     // Just polygons with same number of vertices can be animated.
     if (type() == BasicShape::BasicShapePolygonType
         && (static_cast<const BasicShapePolygon*>(this)->values().size() != static_cast<const BasicShapePolygon*>(other)->values().size()
         || static_cast<const BasicShapePolygon*>(this)->windRule() != static_cast<const BasicShapePolygon*>(other)->windRule()))
         return false;
 
-    // Circles with keywords for radii or center coordinates cannot be animated.
+    // Circles with keywords for radii coordinates cannot be animated.
     if (type() == BasicShape::BasicShapeCircleType) {
         const BasicShapeCircle* thisCircle = static_cast<const BasicShapeCircle*>(this);
         const BasicShapeCircle* otherCircle = static_cast<const BasicShapeCircle*>(other);
-        if (!thisCircle->radius().canBlend(otherCircle->radius())
-            || !thisCircle->centerX().canBlend(otherCircle->centerX())
-            || !thisCircle->centerY().canBlend(otherCircle->centerY()))
+        if (!thisCircle->radius().canBlend(otherCircle->radius()))
             return false;
     }
 
-    // Ellipses with keywords for radii or center coordinates cannot be animated.
+    // Ellipses with keywords for radii coordinates cannot be animated.
     if (type() != BasicShape::BasicShapeEllipseType)
         return true;
 
     const BasicShapeEllipse* thisEllipse = static_cast<const BasicShapeEllipse*>(this);
     const BasicShapeEllipse* otherEllipse = static_cast<const BasicShapeEllipse*>(other);
     return (thisEllipse->radiusX().canBlend(otherEllipse->radiusX())
-        && thisEllipse->radiusY().canBlend(otherEllipse->radiusY())
-        && thisEllipse->centerX().canBlend(otherEllipse->centerX())
-        && thisEllipse->centerY().canBlend(otherEllipse->centerY()));
+        && thisEllipse->radiusY().canBlend(otherEllipse->radiusY()));
+}
+
+FloatSize BasicShape::referenceBoxSize(const RenderBox& renderer) const
+{
+    switch (box()) {
+    case ContentBox:
+        return renderer.contentBoxRect().size();
+    case PaddingBox:
+        return renderer.paddingBoxRect().size();
+    case BorderBox:
+        return renderer.size();
+    case None: // If <box> is not supplied, then the reference box defaults to margin-box.
+    case MarginBox:
+        return FloatSize(renderer.marginLeft() + renderer.width() + renderer.marginRight(),
+            renderer.marginTop() + renderer.height() + renderer.marginBottom());
+    }
+
+    ASSERT_NOT_REACHED();
+    return FloatSize();
+}
+
+Length BasicShapeCenterCoordinate::lengthForBlending(const FloatSize& boxSize) const
+{
+    Length length = this->length();
+    if (keyword() == Right)
+        return Length(100 - (length.isPercent() ? length.percent() : 100.f * (length.value() / boxSize.width())), Percent);
+    if (keyword() == Bottom)
+        return Length(100 - (length.isPercent() ? length.percent() : 100.f * (length.value() / boxSize.height())), Percent);
+    return length;
 }
 
 void BasicShapeRectangle::path(Path& path, const FloatRect& boundingBox)
@@ -89,7 +119,7 @@ void BasicShapeRectangle::path(Path& path, const FloatRect& boundingBox)
     );
 }
 
-PassRefPtr<BasicShape> BasicShapeRectangle::blend(const BasicShape* other, double progress) const
+PassRefPtr<BasicShape> BasicShapeRectangle::blend(const BasicShape* other, double progress, const RenderBox&) const
 {
     ASSERT(type() == other->type());
 
@@ -119,7 +149,7 @@ void DeprecatedBasicShapeCircle::path(Path& path, const FloatRect& boundingBox)
     ));
 }
 
-PassRefPtr<BasicShape> DeprecatedBasicShapeCircle::blend(const BasicShape* other, double progress) const
+PassRefPtr<BasicShape> DeprecatedBasicShapeCircle::blend(const BasicShape* other, double progress, const RenderBox&) const
 {
     ASSERT(type() == other->type());
 
@@ -161,14 +191,15 @@ void BasicShapeCircle::path(Path& path, const FloatRect& boundingBox)
     ));
 }
 
-PassRefPtr<BasicShape> BasicShapeCircle::blend(const BasicShape* other, double progress) const
+PassRefPtr<BasicShape> BasicShapeCircle::blend(const BasicShape* other, double progress, const RenderBox& renderer) 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));
+    FloatSize boxSize = referenceBoxSize(renderer);
+    result->setCenterX(m_centerX.blend(o->centerX(), progress, boxSize));
+    result->setCenterY(m_centerY.blend(o->centerY(), progress, boxSize));
     result->setRadius(m_radius.blend(o->radius(), progress));
     return result.release();
 }
@@ -188,7 +219,7 @@ void DeprecatedBasicShapeEllipse::path(Path& path, const FloatRect& boundingBox)
     ));
 }
 
-PassRefPtr<BasicShape> DeprecatedBasicShapeEllipse::blend(const BasicShape* other, double progress) const
+PassRefPtr<BasicShape> DeprecatedBasicShapeEllipse::blend(const BasicShape* other, double progress, const RenderBox&) const
 {
     ASSERT(type() == other->type());
 
@@ -228,7 +259,7 @@ void BasicShapeEllipse::path(Path& path, const FloatRect& boundingBox)
         radiusY * 2));
 }
 
-PassRefPtr<BasicShape> BasicShapeEllipse::blend(const BasicShape* other, double progress) const
+PassRefPtr<BasicShape> BasicShapeEllipse::blend(const BasicShape* other, double progress, const RenderBox& renderer) const
 {
     ASSERT(type() == other->type());
     const BasicShapeEllipse* o = static_cast<const BasicShapeEllipse*>(other);
@@ -243,8 +274,9 @@ PassRefPtr<BasicShape> BasicShapeEllipse::blend(const BasicShape* other, double
         return result;
     }
 
-    result->setCenterX(m_centerX.blend(o->centerX(), progress));
-    result->setCenterY(m_centerY.blend(o->centerY(), progress));
+    FloatSize boxSize = referenceBoxSize(renderer);
+    result->setCenterX(m_centerX.blend(o->centerX(), progress, boxSize));
+    result->setCenterY(m_centerY.blend(o->centerY(), progress, boxSize));
     result->setRadiusX(m_radiusX.blend(o->radiusX(), progress));
     result->setRadiusY(m_radiusY.blend(o->radiusY(), progress));
     return result.release();
@@ -268,7 +300,7 @@ void BasicShapePolygon::path(Path& path, const FloatRect& boundingBox)
     path.closeSubpath();
 }
 
-PassRefPtr<BasicShape> BasicShapePolygon::blend(const BasicShape* other, double progress) const
+PassRefPtr<BasicShape> BasicShapePolygon::blend(const BasicShape* other, double progress, const RenderBox&) const
 {
     ASSERT(type() == other->type());
 
@@ -310,7 +342,7 @@ void BasicShapeInsetRectangle::path(Path& path, const FloatRect& boundingBox)
     );
 }
 
-PassRefPtr<BasicShape> BasicShapeInsetRectangle::blend(const BasicShape* other, double progress) const
+PassRefPtr<BasicShape> BasicShapeInsetRectangle::blend(const BasicShape* other, double progress, const RenderBox&) const
 {
     ASSERT(type() == other->type());
 
@@ -356,7 +388,7 @@ void BasicShapeInset::path(Path& path, const FloatRect& boundingBox)
     );
 }
 
-PassRefPtr<BasicShape> BasicShapeInset::blend(const BasicShape* other, double progress) const
+PassRefPtr<BasicShape> BasicShapeInset::blend(const BasicShape* other, double progress, const RenderBox&) const
 {
     ASSERT(type() == other->type());
 
index 9255f7b..f9ddf16 100644 (file)
@@ -41,6 +41,7 @@ namespace WebCore {
 
 class FloatRect;
 class Path;
+class RenderBox;
 
 class BasicShape : public RefCounted<BasicShape> {
 public:
@@ -69,7 +70,7 @@ public:
 
     virtual void path(Path&, const FloatRect&) = 0;
     virtual WindRule windRule() const { return RULE_NONZERO; }
-    virtual PassRefPtr<BasicShape> blend(const BasicShape*, double) const = 0;
+    virtual PassRefPtr<BasicShape> blend(const BasicShape*, double, const RenderBox&) const = 0;
 
     virtual Type type() const = 0;
 
@@ -82,6 +83,8 @@ protected:
     {
     }
 
+    FloatSize referenceBoxSize(const RenderBox&) const;
+
 private:
     ReferenceBox m_box;
 };
@@ -113,7 +116,7 @@ public:
     }
 
     virtual void path(Path&, const FloatRect&) OVERRIDE;
-    virtual PassRefPtr<BasicShape> blend(const BasicShape*, double) const OVERRIDE;
+    virtual PassRefPtr<BasicShape> blend(const BasicShape*, double, const RenderBox&) const OVERRIDE;
 
     virtual Type type() const OVERRIDE { return BasicShapeRectangleType; }
 private:
@@ -143,19 +146,11 @@ public:
 
     Keyword keyword() const { return m_keyword; }
     const Length& length() const { return m_length; }
+    Length lengthForBlending(const FloatSize&) const;
 
-    bool canBlend(const BasicShapeCenterCoordinate& other) const
-    {
-        // FIXME determine how to interpolate between keywords. See bug 125108.
-        return m_keyword == None && other.keyword() == None;
-    }
-
-    BasicShapeCenterCoordinate blend(const BasicShapeCenterCoordinate& other, double progress) const
+    BasicShapeCenterCoordinate blend(const BasicShapeCenterCoordinate& other, double progress, const FloatSize& boxSize) const
     {
-        if (m_keyword != None || other.keyword() != None)
-            return BasicShapeCenterCoordinate(other);
-
-        return BasicShapeCenterCoordinate(m_length.blend(other.length(), progress));
+        return BasicShapeCenterCoordinate(lengthForBlending(boxSize).blend(other.lengthForBlending(boxSize), progress));
     }
 
 private:
@@ -212,7 +207,7 @@ public:
     void setRadius(BasicShapeRadius radius) { m_radius = std::move(radius); }
 
     virtual void path(Path&, const FloatRect&) OVERRIDE;
-    virtual PassRefPtr<BasicShape> blend(const BasicShape*, double) const OVERRIDE;
+    virtual PassRefPtr<BasicShape> blend(const BasicShape*, double, const RenderBox&) const OVERRIDE;
 
     virtual Type type() const OVERRIDE { return BasicShapeCircleType; }
 private:
@@ -236,7 +231,7 @@ public:
     void setRadius(Length radius) { m_radius = std::move(radius); }
 
     virtual void path(Path&, const FloatRect&) OVERRIDE;
-    virtual PassRefPtr<BasicShape> blend(const BasicShape*, double) const OVERRIDE;
+    virtual PassRefPtr<BasicShape> blend(const BasicShape*, double, const RenderBox&) const OVERRIDE;
 
     virtual Type type() const OVERRIDE { return DeprecatedBasicShapeCircleType; }
 private:
@@ -263,7 +258,7 @@ public:
     void setRadiusY(BasicShapeRadius radiusY) { m_radiusY = std::move(radiusY); }
 
     virtual void path(Path&, const FloatRect&) OVERRIDE;
-    virtual PassRefPtr<BasicShape> blend(const BasicShape*, double) const OVERRIDE;
+    virtual PassRefPtr<BasicShape> blend(const BasicShape*, double, const RenderBox&) const OVERRIDE;
 
     virtual Type type() const OVERRIDE { return BasicShapeEllipseType; }
 private:
@@ -290,7 +285,7 @@ public:
     void setRadiusY(Length radiusY) { m_radiusY = std::move(radiusY); }
 
     virtual void path(Path&, const FloatRect&) OVERRIDE;
-    virtual PassRefPtr<BasicShape> blend(const BasicShape*, double) const OVERRIDE;
+    virtual PassRefPtr<BasicShape> blend(const BasicShape*, double, const RenderBox&) const OVERRIDE;
 
     virtual Type type() const OVERRIDE { return DeprecatedBasicShapeEllipseType; }
 private:
@@ -314,7 +309,7 @@ public:
     void appendPoint(Length x, Length y) { m_values.append(std::move(x)); m_values.append(std::move(y)); }
 
     virtual void path(Path&, const FloatRect&) OVERRIDE;
-    virtual PassRefPtr<BasicShape> blend(const BasicShape*, double) const OVERRIDE;
+    virtual PassRefPtr<BasicShape> blend(const BasicShape*, double, const RenderBox&) const OVERRIDE;
 
     virtual WindRule windRule() const OVERRIDE { return m_windRule; }
 
@@ -355,7 +350,7 @@ public:
     }
 
     virtual void path(Path&, const FloatRect&) OVERRIDE;
-    virtual PassRefPtr<BasicShape> blend(const BasicShape*, double) const OVERRIDE;
+    virtual PassRefPtr<BasicShape> blend(const BasicShape*, double, const RenderBox&) const OVERRIDE;
 
     virtual Type type() const OVERRIDE { return BasicShapeInsetRectangleType; }
 private:
@@ -394,7 +389,7 @@ public:
     void setBottomLeftRadius(LengthSize radius) { m_bottomLeftRadius = std::move(radius); }
 
     virtual void path(Path&, const FloatRect&) OVERRIDE;
-    virtual PassRefPtr<BasicShape> blend(const BasicShape*, double) const OVERRIDE;
+    virtual PassRefPtr<BasicShape> blend(const BasicShape*, double, const RenderBox&) const OVERRIDE;
 
     virtual Type type() const OVERRIDE { return BasicShapeInsetType; }
 private: