2009-08-15 Simon Fraser <simon.fraser@apple.com>
authorsimon.fraser@apple.com <simon.fraser@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sun, 16 Aug 2009 01:32:17 +0000 (01:32 +0000)
committersimon.fraser@apple.com <simon.fraser@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sun, 16 Aug 2009 01:32:17 +0000 (01:32 +0000)
        Reviewed by Anders Carlsson.

        Make transitions work for position and size of multiple backgrounds and masks.
        https://bugs.webkit.org/show_bug.cgi?id=28266

        Make background-position, background-size, -webkit-mask-position and -webkit-mask-size
        properties animatable with multiple backgrounds, rather than just animating the first one.

        Tests: transitions/multiple-background-size-transitions.html
               transitions/multiple-background-transitions.html
               transitions/multiple-mask-transitions.html

        * page/animation/AnimationBase.cpp:
        (WebCore::FillLayerPropertyWrapperBase::FillLayerPropertyWrapperBase):
        (WebCore::FillLayerPropertyWrapperBase::~FillLayerPropertyWrapperBase):
        (WebCore::FillLayerPropertyWrapperGetter::FillLayerPropertyWrapperGetter):
        (WebCore::FillLayerPropertyWrapperGetter::equals):
        (WebCore::FillLayerPropertyWrapper::FillLayerPropertyWrapper):
        (WebCore::FillLayerPropertyWrapper::blend):
        (WebCore::FillLayersPropertyWrapper::FillLayersPropertyWrapper):
        (WebCore::FillLayersPropertyWrapper::equals):
        (WebCore::FillLayersPropertyWrapper::blend):
        (WebCore::ensurePropertyMap):
        * rendering/style/FillLayer.h:
        (WebCore::FillLayer::setXPosition):
        (WebCore::FillLayer::setYPosition):
        (WebCore::FillLayer::setSize):

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

LayoutTests/ChangeLog
LayoutTests/transitions/multiple-background-size-transitions-expected.txt [new file with mode: 0644]
LayoutTests/transitions/multiple-background-size-transitions.html [new file with mode: 0644]
LayoutTests/transitions/multiple-background-transitions-expected.txt [new file with mode: 0644]
LayoutTests/transitions/multiple-background-transitions.html [new file with mode: 0644]
LayoutTests/transitions/multiple-mask-transitions-expected.txt [new file with mode: 0644]
LayoutTests/transitions/multiple-mask-transitions.html [new file with mode: 0644]
WebCore/ChangeLog
WebCore/page/animation/AnimationBase.cpp
WebCore/rendering/style/FillLayer.h

index 9fc5975..f2b66b3 100644 (file)
@@ -1,3 +1,17 @@
+2009-08-15  Simon Fraser  <simon.fraser@apple.com>
+
+        Reviewed by Anders Carlsson.
+
+        Make transitions work for position and size of multiple backgrounds and masks.
+        https://bugs.webkit.org/show_bug.cgi?id=28266
+
+        * transitions/multiple-background-size-transitions-expected.txt: Added.
+        * transitions/multiple-background-size-transitions.html: Added.
+        * transitions/multiple-background-transitions-expected.txt: Added.
+        * transitions/multiple-background-transitions.html: Added.
+        * transitions/multiple-mask-transitions-expected.txt: Added.
+        * transitions/multiple-mask-transitions.html: Added.
+
 2009-08-15  George Staikos  <george.staikos@torchmobile.com>
 
         Reviewed by Jan Alonzo.
diff --git a/LayoutTests/transitions/multiple-background-size-transitions-expected.txt b/LayoutTests/transitions/multiple-background-size-transitions-expected.txt
new file mode 100644 (file)
index 0000000..bce1dab
--- /dev/null
@@ -0,0 +1,3 @@
+PASS - "-webkit-background-size" property for "box" element at 0.5s saw something close to: 25,25
+PASS - "-webkit-mask-size" property for "box1" element at 0.5s saw something close to: 25,25
+
diff --git a/LayoutTests/transitions/multiple-background-size-transitions.html b/LayoutTests/transitions/multiple-background-size-transitions.html
new file mode 100644 (file)
index 0000000..54cc943
--- /dev/null
@@ -0,0 +1,69 @@
+<!DOCTYPE>
+
+<html lang="en">
+<head>
+  <title>background-size and mask-size transitions on multiple backgrounds/masks</title>
+  <style type="text/css" media="screen">
+    .box {
+      height: 100px;
+      width: 100px;
+      margin: 10px;
+      border: 1px solid black;
+      background-repeat: no-repeat;
+      -webkit-mask-repeat: no-repeat;
+      -webkit-transition-duration: 1s;
+      -webkit-transition-timing-function: linear;
+      -webkit-transition-property: background-size, -webkit-mask-size;
+    }
+    
+    #box {
+      background-image: url('../fast/backgrounds/repeat/resources/gradient.gif'), url('../fast/backgrounds/repeat/resources/gradient.gif');
+      background-position: 0 0, 50px 50px;
+      -webkit-background-size: 0% 0%, 50% 50%;
+    }
+    
+    #box.final {
+      -webkit-background-size: 50% 50%, 0% 0%;
+    }
+    
+    #box1 {
+      background-color: gray;
+      -webkit-mask-image: url('../fast/backgrounds/repeat/resources/gradient.gif'), url('../fast/backgrounds/repeat/resources/gradient.gif');
+      -webkit-mask-position: 0 0, 50px 50px;
+      -webkit-mask-size: 0% 0%, 50% 50%;
+    }
+
+    #box1.final {
+      -webkit-mask-size: 50% 50%, 0% 0%;
+    }
+
+  </style>
+  <script src="transition-test-helpers.js" type="text/javascript" charset="utf-8"></script>
+  <script type="text/javascript" charset="utf-8">
+
+    const expectedValues = [
+      // [time, element-id, property, expected-value, tolerance]
+      [0.5, 'box', '-webkit-background-size', [25, 25], 4],
+      [0.5, 'box1', '-webkit-mask-size', [25, 25], 4],
+    ];
+  
+    function setupTest()
+    {
+      document.getElementById('box').className = 'box final';
+      document.getElementById('box1').className = 'box final';
+    }
+  
+    runTransitionTest(expectedValues, setupTest, true);
+    
+  </script>
+</head>
+<body>
+
+  <div id="box" class="box"></div>
+  <div id="box1" class="box"></div>
+
+  <div id="result">
+  </div>
+
+</body>
+</html>
diff --git a/LayoutTests/transitions/multiple-background-transitions-expected.txt b/LayoutTests/transitions/multiple-background-transitions-expected.txt
new file mode 100644 (file)
index 0000000..80a4420
--- /dev/null
@@ -0,0 +1,4 @@
+PASS - "background-position" property for "box" element at 0.5s saw something close to: 40,40
+PASS - "background-position" property for "box2" element at 0.5s saw something close to: 40,40
+PASS - "background-position" property for "box3" element at 0.5s saw something close to: 40,40
+
diff --git a/LayoutTests/transitions/multiple-background-transitions.html b/LayoutTests/transitions/multiple-background-transitions.html
new file mode 100644 (file)
index 0000000..2c0e268
--- /dev/null
@@ -0,0 +1,80 @@
+<!DOCTYPE>
+
+<html lang="en">
+<head>
+  <title>background-position and size transitions</title>
+  <style type="text/css" media="screen">
+    .box {
+      height: 100px;
+      width: 100px;
+      margin: 10px;
+      border: 1px solid black;
+      background-repeat: no-repeat;
+      -webkit-transition-duration: 1s;
+      -webkit-transition-timing-function: linear;
+      -webkit-transition-property: background-position;
+    }
+    
+    #box {
+      background-image: url('../fast/backgrounds/repeat/resources/gradient.gif'), url('../fast/backgrounds/repeat/resources/gradient.gif');
+      background-position: 0 0, 0 80px;
+    }
+    
+    #box.final {
+      background-position: 80px 80px, 80px 0;
+    }
+
+    /* Mismatched layers */
+    #box2 {
+      background-image: url('../fast/backgrounds/repeat/resources/gradient.gif'), url('../fast/backgrounds/repeat/resources/gradient.gif');
+      background-position: 0 0, 0 80px;
+    }
+    
+    #box2.final {
+      background-image: url('../fast/backgrounds/repeat/resources/gradient.gif');
+      background-position: 80px 80px;
+    }
+
+    #box3 {
+      background-image: url('../fast/backgrounds/repeat/resources/gradient.gif');
+      background-position: 80px 80px;
+    }
+    
+    #box3.final {
+      background-image: url('../fast/backgrounds/repeat/resources/gradient.gif'), url('../fast/backgrounds/repeat/resources/gradient.gif');
+      background-position: 0 0, 0 80px;
+    }
+
+  </style>
+  <script src="transition-test-helpers.js" type="text/javascript" charset="utf-8"></script>
+  <script type="text/javascript" charset="utf-8">
+
+    const expectedValues = [
+      // [time, element-id, property, expected-value, tolerance]
+      [0.5, 'box', 'background-position', [40, 40], 2],
+      [0.5, 'box2', 'background-position', [40, 40], 2],
+      [0.5, 'box3', 'background-position', [40, 40], 2],
+    ];
+  
+    function setupTest()
+    {
+      document.getElementById('box').className = 'box final';
+      document.getElementById('box2').className = 'box final';
+      document.getElementById('box3').className = 'box final';
+    }
+  
+    runTransitionTest(expectedValues, setupTest, true);
+    
+  </script>
+</head>
+<body>
+
+  <div id="box" class="box"></div>
+  <div id="box2" class="box"></div>
+  <div id="box3" class="box"></div>
+
+  <div id="result">
+  </div>
+
+</body>
+</html>
diff --git a/LayoutTests/transitions/multiple-mask-transitions-expected.txt b/LayoutTests/transitions/multiple-mask-transitions-expected.txt
new file mode 100644 (file)
index 0000000..f50cf7b
--- /dev/null
@@ -0,0 +1,4 @@
+PASS - "-webkit-mask-position" property for "box" element at 0.5s saw something close to: 40,40
+PASS - "-webkit-mask-position" property for "box2" element at 0.5s saw something close to: 40,40
+PASS - "-webkit-mask-position" property for "box3" element at 0.5s saw something close to: 40,40
+
diff --git a/LayoutTests/transitions/multiple-mask-transitions.html b/LayoutTests/transitions/multiple-mask-transitions.html
new file mode 100644 (file)
index 0000000..beee8da
--- /dev/null
@@ -0,0 +1,80 @@
+<!DOCTYPE>
+
+<html lang="en">
+<head>
+  <title>mask-position and size transitions</title>
+  <style type="text/css" media="screen">
+    .box {
+      height: 100px;
+      width: 100px;
+      margin: 10px;
+      background-color: gray;
+      -webkit-mask-repeat: no-repeat;
+      -webkit-transition-duration: 1s;
+      -webkit-transition-timing-function: linear;
+      -webkit-transition-property: -webkit-mask-position;
+    }
+    
+    #box {
+      -webkit-mask-image: url('../fast/backgrounds/repeat/resources/gradient.gif'), url('../fast/backgrounds/repeat/resources/gradient.gif');
+      -webkit-mask-position: 0 0, 0 80px;
+    }
+    
+    #box.final {
+      -webkit-mask-position: 80px 80px, 80px 0;
+    }
+
+    /* Mismatched layers */
+    #box2 {
+      -webkit-mask-image: url('../fast/backgrounds/repeat/resources/gradient.gif'), url('../fast/backgrounds/repeat/resources/gradient.gif');
+      -webkit-mask-position: 0 0, 0 80px;
+    }
+    
+    #box2.final {
+      -webkit-mask-image: url('../fast/backgrounds/repeat/resources/gradient.gif');
+      -webkit-mask-position: 80px 80px;
+    }
+
+    #box3 {
+      -webkit-mask-image: url('../fast/backgrounds/repeat/resources/gradient.gif');
+      -webkit-mask-position: 80px 80px;
+    }
+    
+    #box3.final {
+      -webkit-mask-image: url('../fast/backgrounds/repeat/resources/gradient.gif'), url('../fast/backgrounds/repeat/resources/gradient.gif');
+      -webkit-mask-position: 0 0, 0 80px;
+    }
+
+  </style>
+  <script src="transition-test-helpers.js" type="text/javascript" charset="utf-8"></script>
+  <script type="text/javascript" charset="utf-8">
+
+    const expectedValues = [
+      // [time, element-id, property, expected-value, tolerance]
+      [0.5, 'box', '-webkit-mask-position', [40, 40], 5],
+      [0.5, 'box2', '-webkit-mask-position', [40, 40], 5],
+      [0.5, 'box3', '-webkit-mask-position', [40, 40], 5],
+    ];
+  
+    function setupTest()
+    {
+      document.getElementById('box').className = 'box final';
+      document.getElementById('box2').className = 'box final';
+      document.getElementById('box3').className = 'box final';
+    }
+  
+    runTransitionTest(expectedValues, setupTest, true);
+    
+  </script>
+</head>
+<body>
+
+  <div id="box" class="box"></div>
+  <div id="box2" class="box"></div>
+  <div id="box3" class="box"></div>
+
+  <div id="result">
+  </div>
+
+</body>
+</html>
index 7f1e2c1..b6f2b9f 100644 (file)
@@ -1,3 +1,33 @@
+2009-08-15  Simon Fraser  <simon.fraser@apple.com>
+
+        Reviewed by Anders Carlsson.
+
+        Make transitions work for position and size of multiple backgrounds and masks.
+        https://bugs.webkit.org/show_bug.cgi?id=28266
+        
+        Make background-position, background-size, -webkit-mask-position and -webkit-mask-size
+        properties animatable with multiple backgrounds, rather than just animating the first one.
+
+        Tests: transitions/multiple-background-size-transitions.html
+               transitions/multiple-background-transitions.html
+               transitions/multiple-mask-transitions.html
+
+        * page/animation/AnimationBase.cpp:
+        (WebCore::FillLayerPropertyWrapperBase::FillLayerPropertyWrapperBase):
+        (WebCore::FillLayerPropertyWrapperBase::~FillLayerPropertyWrapperBase):
+        (WebCore::FillLayerPropertyWrapperGetter::FillLayerPropertyWrapperGetter):
+        (WebCore::FillLayerPropertyWrapperGetter::equals):
+        (WebCore::FillLayerPropertyWrapper::FillLayerPropertyWrapper):
+        (WebCore::FillLayerPropertyWrapper::blend):
+        (WebCore::FillLayersPropertyWrapper::FillLayersPropertyWrapper):
+        (WebCore::FillLayersPropertyWrapper::equals):
+        (WebCore::FillLayersPropertyWrapper::blend):
+        (WebCore::ensurePropertyMap):
+        * rendering/style/FillLayer.h:
+        (WebCore::FillLayer::setXPosition):
+        (WebCore::FillLayer::setYPosition):
+        (WebCore::FillLayer::setSize):
+
 2009-08-15  George Staikos  <george.staikos@torchmobile.com>
 
         Reviewed by Jan Alonzo.
index 7503f0a..b2e54f7 100644 (file)
@@ -365,6 +365,124 @@ private:
     void (RenderStyle::*m_setter)(const Color&);
 };
 
+// Wrapper base class for an animatable property in a FillLayer
+class FillLayerPropertyWrapperBase {
+public:
+    FillLayerPropertyWrapperBase()
+    {
+    }
+
+    virtual ~FillLayerPropertyWrapperBase() { }
+    
+    virtual bool equals(const FillLayer* a, const FillLayer* b) const = 0;
+    virtual void blend(const AnimationBase* anim, FillLayer* dst, const FillLayer* a, const FillLayer* b, double progress) const = 0;
+};
+
+template <typename T>
+class FillLayerPropertyWrapperGetter : public FillLayerPropertyWrapperBase {
+public:
+    FillLayerPropertyWrapperGetter(T (FillLayer::*getter)() const)
+        : m_getter(getter)
+    {
+    }
+
+    virtual bool equals(const FillLayer* a, const FillLayer* b) const
+    {
+       // If the style pointers are the same, don't bother doing the test.
+       // If either is null, return false. If both are null, return true.
+       if ((!a && !b) || a == b)
+           return true;
+       if (!a || !b)
+            return false;
+        return (a->*m_getter)() == (b->*m_getter)();
+    }
+
+protected:
+    T (FillLayer::*m_getter)() const;
+};
+
+template <typename T>
+class FillLayerPropertyWrapper : public FillLayerPropertyWrapperGetter<T> {
+public:
+    FillLayerPropertyWrapper(T (FillLayer::*getter)() const, void (FillLayer::*setter)(T))
+        : FillLayerPropertyWrapperGetter<T>(getter)
+        , m_setter(setter)
+    {
+    }
+    
+    virtual void blend(const AnimationBase* anim, FillLayer* dst, const FillLayer* a, const FillLayer* b, double progress) const
+    {
+        (dst->*m_setter)(blendFunc(anim, (a->*FillLayerPropertyWrapperGetter<T>::m_getter)(), (b->*FillLayerPropertyWrapperGetter<T>::m_getter)(), progress));
+    }
+
+protected:
+    void (FillLayer::*m_setter)(T);
+};
+
+
+class FillLayersPropertyWrapper : public PropertyWrapperBase {
+public:
+    typedef const FillLayer* (RenderStyle::*LayersGetter)() const;
+    typedef FillLayer* (RenderStyle::*LayersAccessor)();
+    
+    FillLayersPropertyWrapper(int prop, LayersGetter getter, LayersAccessor accessor)
+        : PropertyWrapperBase(prop)
+        , m_layersGetter(getter)
+        , m_layersAccessor(accessor)
+    {
+        switch (prop) {
+            case CSSPropertyBackgroundPositionX:
+            case CSSPropertyWebkitMaskPositionX:
+                m_fillLayerPropertyWrapper = new FillLayerPropertyWrapper<Length>(&FillLayer::xPosition, &FillLayer::setXPosition);
+                break;
+            case CSSPropertyBackgroundPositionY:
+            case CSSPropertyWebkitMaskPositionY:
+                m_fillLayerPropertyWrapper = new FillLayerPropertyWrapper<Length>(&FillLayer::yPosition, &FillLayer::setYPosition);
+                break;
+            case CSSPropertyWebkitBackgroundSize:
+            case CSSPropertyWebkitMaskSize:
+                m_fillLayerPropertyWrapper = new FillLayerPropertyWrapper<LengthSize>(&FillLayer::size, &FillLayer::setSize);
+                break;
+        }
+    }
+
+    virtual bool equals(const RenderStyle* a, const RenderStyle* b) const
+    {
+        const FillLayer* fromLayer = (a->*m_layersGetter)();
+        const FillLayer* toLayer = (b->*m_layersGetter)();
+
+        while (fromLayer && toLayer) {
+            if (!m_fillLayerPropertyWrapper->equals(fromLayer, toLayer))
+                return false;
+            
+            fromLayer = fromLayer->next();
+            toLayer = toLayer->next();
+        }
+
+        return true;
+    }
+
+    virtual void blend(const AnimationBase* anim, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress) const
+    {
+        const FillLayer* aLayer = (a->*m_layersGetter)();
+        const FillLayer* bLayer = (b->*m_layersGetter)();
+        FillLayer* dstLayer = (dst->*m_layersAccessor)();
+
+        while (aLayer && bLayer && dstLayer) {
+            m_fillLayerPropertyWrapper->blend(anim, dstLayer, aLayer, bLayer, progress);
+            aLayer = aLayer->next();
+            bLayer = bLayer->next();
+            dstLayer = dstLayer->next();
+        }
+    }
+
+private:
+    FillLayerPropertyWrapperBase* m_fillLayerPropertyWrapper;
+    
+    LayersGetter m_layersGetter;
+    LayersAccessor m_layersAccessor;
+};
+
 class ShorthandPropertyWrapper : public PropertyWrapperBase {
 public:
     ShorthandPropertyWrapper(int property, const CSSPropertyLonghand& longhand)
@@ -442,13 +560,14 @@ static void ensurePropertyMap()
         gPropertyWrappers->append(new PropertyWrapper<const Color&>(CSSPropertyColor, &RenderStyle::color, &RenderStyle::setColor));
 
         gPropertyWrappers->append(new PropertyWrapper<const Color&>(CSSPropertyBackgroundColor, &RenderStyle::backgroundColor, &RenderStyle::setBackgroundColor));
-        gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyBackgroundPositionX, &RenderStyle::backgroundXPosition, &RenderStyle::setBackgroundXPosition));
-        gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyBackgroundPositionY, &RenderStyle::backgroundYPosition, &RenderStyle::setBackgroundYPosition));
-        gPropertyWrappers->append(new PropertyWrapper<LengthSize>(CSSPropertyWebkitBackgroundSize, &RenderStyle::backgroundSize, &RenderStyle::setBackgroundSize));
 
-        gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyWebkitMaskPositionX, &RenderStyle::maskXPosition, &RenderStyle::setMaskXPosition));
-        gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyWebkitMaskPositionY, &RenderStyle::maskYPosition, &RenderStyle::setMaskYPosition));
-        gPropertyWrappers->append(new PropertyWrapper<LengthSize>(CSSPropertyWebkitMaskSize, &RenderStyle::maskSize, &RenderStyle::setMaskSize));
+        gPropertyWrappers->append(new FillLayersPropertyWrapper(CSSPropertyBackgroundPositionX, &RenderStyle::backgroundLayers, &RenderStyle::accessBackgroundLayers));
+        gPropertyWrappers->append(new FillLayersPropertyWrapper(CSSPropertyBackgroundPositionY, &RenderStyle::backgroundLayers, &RenderStyle::accessBackgroundLayers));
+        gPropertyWrappers->append(new FillLayersPropertyWrapper(CSSPropertyWebkitBackgroundSize, &RenderStyle::backgroundLayers, &RenderStyle::accessBackgroundLayers));
+
+        gPropertyWrappers->append(new FillLayersPropertyWrapper(CSSPropertyWebkitMaskPositionX, &RenderStyle::maskLayers, &RenderStyle::accessMaskLayers));
+        gPropertyWrappers->append(new FillLayersPropertyWrapper(CSSPropertyWebkitMaskPositionY, &RenderStyle::maskLayers, &RenderStyle::accessMaskLayers));
+        gPropertyWrappers->append(new FillLayersPropertyWrapper(CSSPropertyWebkitMaskSize, &RenderStyle::maskLayers, &RenderStyle::accessMaskLayers));
 
         gPropertyWrappers->append(new PropertyWrapper<int>(CSSPropertyFontSize, &RenderStyle::fontSize, &RenderStyle::setBlendedFontSize));
         gPropertyWrappers->append(new PropertyWrapper<unsigned short>(CSSPropertyWebkitColumnRuleWidth, &RenderStyle::columnRuleWidth, &RenderStyle::setColumnRuleWidth));
index c3944ad..aad7900 100644 (file)
@@ -63,14 +63,14 @@ public:
     bool isSizeSet() const { return m_sizeSet; }
     
     void setImage(StyleImage* i) { m_image = i; m_imageSet = true; }
-    void setXPosition(const Length& l) { m_xPosition = l; m_xPosSet = true; }
-    void setYPosition(const Length& l) { m_yPosition = l; m_yPosSet = true; }
+    void setXPosition(Length l) { m_xPosition = l; m_xPosSet = true; }
+    void setYPosition(Length l) { m_yPosition = l; m_yPosSet = true; }
     void setAttachment(EFillAttachment attachment) { m_attachment = attachment; m_attachmentSet = true; }
     void setClip(EFillBox b) { m_clip = b; m_clipSet = true; }
     void setOrigin(EFillBox b) { m_origin = b; m_originSet = true; }
     void setRepeat(EFillRepeat r) { m_repeat = r; m_repeatSet = true; }
     void setComposite(CompositeOperator c) { m_composite = c; m_compositeSet = true; }
-    void setSize(const LengthSize& b) { m_size = b; m_sizeSet = true; }
+    void setSize(LengthSize b) { m_size = b; m_sizeSet = true; }
     
     void clearImage() { m_imageSet = false; }
     void clearXPosition() { m_xPosSet = false; }