Make sure CSS transforms can be animated using the CSS transition property.
authorhyatt <hyatt@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 31 Oct 2007 02:30:40 +0000 (02:30 +0000)
committerhyatt <hyatt@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 31 Oct 2007 02:30:40 +0000 (02:30 +0000)
        Reviewed by Dan and Antti

        * css/CSSStyleSelector.cpp:
        (WebCore::CSSStyleSelector::applyProperty):
        * page/AnimationController.cpp:
        (WebCore::blendFunc):
        (WebCore::ImplicitAnimation::animate):
        * rendering/Length.h:
        (WebCore::Length::blend):
        * rendering/RenderStyle.cpp:
        (WebCore::StyleTransformData::operator==):
        (WebCore::TransformOperations::operator==):
        (WebCore::blendLengths):
        (WebCore::ScaleTransformOperation::blend):
        (WebCore::RotateTransformOperation::blend):
        (WebCore::SkewTransformOperation::blend):
        (WebCore::TranslateTransformOperation::blend):
        (WebCore::MatrixTransformOperation::blend):
        * rendering/RenderStyle.h:
        (WebCore::TransformOperations::operator!=):
        (WebCore::TransformOperations::isEmpty):
        (WebCore::TransformOperations::size):
        (WebCore::TransformOperations::operator[]):
        (WebCore::TransformOperations::append):
        (WebCore::RenderStyle::transform):
        (WebCore::RenderStyle::setTransform):
        (WebCore::RenderStyle::initialTransform):

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

WebCore/ChangeLog
WebCore/css/CSSStyleSelector.cpp
WebCore/page/AnimationController.cpp
WebCore/rendering/Length.h
WebCore/rendering/RenderStyle.cpp
WebCore/rendering/RenderStyle.h

index d3538a2..511a48d 100644 (file)
@@ -1,3 +1,35 @@
+2007-10-30  David Hyatt  <hyatt@apple.com>
+
+        Make sure CSS transforms can be animated using the CSS transition property.
+
+        Reviewed by Dan and Antti
+
+        * css/CSSStyleSelector.cpp:
+        (WebCore::CSSStyleSelector::applyProperty):
+        * page/AnimationController.cpp:
+        (WebCore::blendFunc):
+        (WebCore::ImplicitAnimation::animate):
+        * rendering/Length.h:
+        (WebCore::Length::blend):
+        * rendering/RenderStyle.cpp:
+        (WebCore::StyleTransformData::operator==):
+        (WebCore::TransformOperations::operator==):
+        (WebCore::blendLengths):
+        (WebCore::ScaleTransformOperation::blend):
+        (WebCore::RotateTransformOperation::blend):
+        (WebCore::SkewTransformOperation::blend):
+        (WebCore::TranslateTransformOperation::blend):
+        (WebCore::MatrixTransformOperation::blend):
+        * rendering/RenderStyle.h:
+        (WebCore::TransformOperations::operator!=):
+        (WebCore::TransformOperations::isEmpty):
+        (WebCore::TransformOperations::size):
+        (WebCore::TransformOperations::operator[]):
+        (WebCore::TransformOperations::append):
+        (WebCore::RenderStyle::transform):
+        (WebCore::RenderStyle::setTransform):
+        (WebCore::RenderStyle::initialTransform):
+
 2007-10-30  Antti Koivisto  <antti@apple.com>
 
         Another Qt/GTK build fix.
index 6ca2818..17a8eb2 100644 (file)
@@ -3868,7 +3868,7 @@ void CSSStyleSelector::applyProperty(int id, CSSValue *value)
     }
     case CSS_PROP__WEBKIT_TRANSFORM: {
         HANDLE_INHERIT_AND_INITIAL(transform, Transform);
-        Vector<RefPtr<TransformOperation> > operations;
+        TransformOperations operations;
         if (!value->isPrimitiveValue()) {
             CSSValueList* list = static_cast<CSSValueList*>(value);
             unsigned size = list->length();
index 1eae8da..09b2d8b 100644 (file)
@@ -269,10 +269,7 @@ static inline Color blendFunc(const Color& from, const Color& to, double progres
 
 static inline Length blendFunc(const Length& from, const Length& to, double progress)
 {  
-    if (from.type() != to.type())
-        return to;
-    return from.type() == Percent ? Length(blendFunc(from.percent(), to.percent(), progress), Percent)
-                                  : Length(blendFunc(from.value(), to.value(), progress), from.type());
+    return to.blend(from, progress);
 }
 
 static inline ShadowData* blendFunc(const ShadowData* from, const ShadowData* to, double progress)
@@ -281,6 +278,22 @@ static inline ShadowData* blendFunc(const ShadowData* from, const ShadowData* to
     return new ShadowData(blendFunc(from->x, to->x, progress), blendFunc(from->y, to->y, progress), blendFunc(from->blur, to->blur, progress), blendFunc(from->color, to->color, progress));
 }
 
+static inline TransformOperations blendFunc(const TransformOperations& from, const TransformOperations& to, double progress)
+{    
+    // Blend any operations whose types actually match up.  Otherwise don't bother.
+    unsigned fromSize = from.size();
+    unsigned toSize = to.size();
+    unsigned size = max(fromSize, toSize);
+    TransformOperations result;
+    for (unsigned i = 0; i < size; i++) {
+        TransformOperation* fromOp = i < fromSize ? from[i].get() : 0;
+        TransformOperation* toOp = i < toSize ? to[i].get() : 0;
+        TransformOperation* blendedOp = toOp ? toOp->blend(fromOp, progress) : fromOp->blend(0, progress, true);
+        result.append(blendedOp);
+    }
+    return result;
+}
+
 #define BLEND(prop, getter, setter) \
     if (m_property == prop && m_toStyle->getter() != targetStyle->getter()) \
         reset(renderer, currentStyle, targetStyle); \
@@ -364,6 +377,9 @@ void ImplicitAnimation::animate(CompositeImplicitAnimation* animation, RenderObj
     BLEND(CSS_PROP_WORD_SPACING, wordSpacing, setWordSpacing);
     BLEND_SHADOW(CSS_PROP__WEBKIT_BOX_SHADOW, boxShadow, setBoxShadow);
     BLEND_SHADOW(CSS_PROP_TEXT_SHADOW, textShadow, setTextShadow);
+    BLEND(CSS_PROP__WEBKIT_TRANSFORM, transform, setTransform);
+    BLEND(CSS_PROP__WEBKIT_TRANSFORM_ORIGIN_X, transformOriginX, setTransformOriginX);
+    BLEND(CSS_PROP__WEBKIT_TRANSFORM_ORIGIN_Y, transformOriginY, setTransformOriginY);
 }
 
 RenderStyle* CompositeImplicitAnimation::animate(RenderObject* renderer, RenderStyle* currentStyle, RenderStyle* targetStyle)
index ca26ea3..6bb023a 100644 (file)
@@ -142,6 +142,30 @@ namespace WebCore {
         bool isStatic() const { return type() == Static; }
         bool isIntrinsicOrAuto() const { return type() == Auto || type() == MinIntrinsic || type() == Intrinsic; }
 
+        Length blend(const Length& from, double progress) const
+        {
+            // Blend two lengths to produce a new length that is in between them.  Used for animation.
+            if (!from.isZero() && !isZero() && from.type() != type())
+                return *this;
+    
+            if (from.isZero() && isZero())
+                return *this;
+            
+            LengthType resultType = type();
+            if (isZero())
+                resultType = from.type();
+            
+            if (resultType == Percent) {
+                double fromPercent = from.isZero() ? 0. : from.percent();
+                double toPercent = isZero() ? 0. : percent();
+                return Length(fromPercent + (fromPercent - toPercent) * progress, Percent);
+            } 
+                
+            double fromValue = from.isZero() ? 0 : from.value();
+            double toValue = isZero() ? 0 : value();
+            return Length(fromValue + (fromValue - toValue) * progress, resultType);
+        }
+        
     private:
         int m_value;
     };
index b81d253..b48e602 100644 (file)
@@ -435,10 +435,10 @@ StyleTransformData::StyleTransformData(const StyleTransformData& o)
 
 bool StyleTransformData::operator==(const StyleTransformData& o) const
 {
-    return m_x == o.m_x && m_y == o.m_y && transformDataEquivalent(o);
+    return m_x == o.m_x && m_y == o.m_y && m_operations == o.m_operations;
 }
 
-bool StyleTransformData::transformDataEquivalent(const StyleTransformData& o) const
+bool TransformOperations::operator==(const TransformOperations& o) const
 {
     if (m_operations.size() != o.m_operations.size())
         return false;
@@ -452,6 +452,98 @@ bool StyleTransformData::transformDataEquivalent(const StyleTransformData& o) co
     return true;
 }
 
+static inline Length blendLengths(const Length& from, const Length& to, double progress)
+{  
+    if (from.type() != to.type())
+        return to;
+    return from.type() == Percent ? Length(from.percent() + (to.percent() - from.percent()) * progress, Percent)
+                                  : Length(from.value() + (to.value() - from.value()) * progress, from.type());
+}
+
+TransformOperation* ScaleTransformOperation::blend(const TransformOperation* from, double progress, bool blendToIdentity)
+{
+    if (from && !from->isScaleOperation())
+        return this;
+    
+    if (blendToIdentity)
+        return new ScaleTransformOperation(m_x + (1. - m_x) * progress, m_y + (1. - m_y) * progress);
+    
+    const ScaleTransformOperation* fromOp = static_cast<const ScaleTransformOperation*>(from);
+    double fromX = fromOp ? fromOp->m_x : 1.;
+    double fromY = fromOp ? fromOp->m_y : 1.;
+    return new ScaleTransformOperation(fromX + (m_x - fromX) * progress, fromY + (m_y - fromY) * progress);
+}
+
+TransformOperation* RotateTransformOperation::blend(const TransformOperation* from, double progress, bool blendToIdentity)
+{
+    if (from && !from->isRotateOperation())
+        return this;
+    
+    if (blendToIdentity)
+        return new RotateTransformOperation(m_angle - m_angle * progress);
+    
+    const RotateTransformOperation* fromOp = static_cast<const RotateTransformOperation*>(from);
+    double fromAngle = fromOp ? fromOp->m_angle : 0;
+    return new RotateTransformOperation(fromAngle + (m_angle - fromAngle) * progress);
+}
+
+TransformOperation* SkewTransformOperation::blend(const TransformOperation* from, double progress, bool blendToIdentity)
+{
+    if (from && !from->isSkewOperation())
+        return this;
+    
+    if (blendToIdentity)
+        return new SkewTransformOperation(m_angleX - m_angleX * progress, m_angleY - m_angleY * progress);
+    
+    const SkewTransformOperation* fromOp = static_cast<const SkewTransformOperation*>(from);
+    double fromAngleX = fromOp ? fromOp->m_angleX : 0;
+    double fromAngleY = fromOp ? fromOp->m_angleY : 0;
+    return new SkewTransformOperation(fromAngleX + (m_angleX - fromAngleX) * progress, fromAngleY + (m_angleY - fromAngleY) * progress);
+}
+
+TransformOperation* TranslateTransformOperation::blend(const TransformOperation* from, double progress, bool blendToIdentity)
+{
+    if (from && !from->isTranslateOperation())
+        return this;
+    
+    if (blendToIdentity)
+        return new TranslateTransformOperation(Length(0, m_x.type()).blend(m_x, progress), Length(0, m_y.type()).blend(m_y, progress));
+
+    const TranslateTransformOperation* fromOp = static_cast<const TranslateTransformOperation*>(from);
+    Length fromX = fromOp ? fromOp->m_x : Length(0, m_x.type());
+    Length fromY = fromOp ? fromOp->m_y : Length(0, m_y.type());
+    return new TranslateTransformOperation(m_x.blend(fromX, progress), m_y.blend(fromY, progress));
+}
+
+TransformOperation* MatrixTransformOperation::blend(const TransformOperation* from, double progress, bool blendToIdentity)
+{
+    if (from && !from->isMatrixOperation())
+        return this;
+    
+    if (blendToIdentity)
+        return new MatrixTransformOperation(Length(1, m_a.type()).blend(m_a, progress),
+                                            Length(0, m_b.type()).blend(m_b, progress),
+                                            Length(0, m_c.type()).blend(m_c, progress),
+                                            Length(1, m_d.type()).blend(m_d, progress),
+                                            Length(0, m_e.type()).blend(m_e, progress),
+                                            Length(0, m_f.type()).blend(m_f, progress));
+
+    const MatrixTransformOperation* fromOp = static_cast<const MatrixTransformOperation*>(from);
+    Length fromA = fromOp ? fromOp->m_a : Length(1, m_a.type());
+    Length fromB = fromOp ? fromOp->m_b : Length(0, m_b.type());
+    Length fromC = fromOp ? fromOp->m_c : Length(0, m_c.type());
+    Length fromD = fromOp ? fromOp->m_d : Length(1, m_d.type());
+    Length fromE = fromOp ? fromOp->m_e : Length(0, m_e.type());
+    Length fromF = fromOp ? fromOp->m_f : Length(0, m_f.type());
+    
+    return new MatrixTransformOperation(m_a.blend(fromA, progress),
+                                        m_b.blend(fromB, progress),
+                                        m_c.blend(fromC, progress),
+                                        m_d.blend(fromD, progress),
+                                        m_e.blend(fromE, progress),
+                                        m_f.blend(fromF, progress));
+}
+
 Transition::Transition()
     : m_duration(RenderStyle::initialTransitionDuration())
     , m_repeatCount(RenderStyle::initialTransitionRepeatCount())
index 4696e31..57ef1bf 100644 (file)
@@ -637,6 +637,8 @@ public:
 
     virtual void apply(AffineTransform&, const IntSize& borderBoxSize) = 0;
     
+    virtual TransformOperation* blend(const TransformOperation* from, double progress, bool blendToIdentity = false) = 0;
+    
     virtual bool isScaleOperation() const { return false; }
     virtual bool isRotateOperation() const { return false; }
     virtual bool isSkewOperation() const { return false; }
@@ -667,6 +669,8 @@ public:
         transform.scale(m_x, m_y);
     }
 
+    virtual TransformOperation* blend(const TransformOperation* from, double progress, bool blendToIdentity = false);
+
 private:
     double m_x;
     double m_y;
@@ -695,6 +699,7 @@ public:
         transform.rotate(m_angle);
     }
 
+    virtual TransformOperation* blend(const TransformOperation* from, double progress, bool blendToIdentity = false);
     
 private:
     double m_angle;
@@ -723,7 +728,8 @@ public:
         transform.skew(m_angleX, m_angleY);
     }
 
-
+    virtual TransformOperation* blend(const TransformOperation* from, double progress, bool blendToIdentity = false);
+    
 private:
     double m_angleX;
     double m_angleY;
@@ -752,6 +758,8 @@ public:
         transform.translate(m_x.calcValue(borderBoxSize.width()), m_y.calcValue(borderBoxSize.height()));
     }
 
+    virtual TransformOperation* blend(const TransformOperation* from, double progress, bool blendToIdentity = false);
+
 private:
     Length m_x;
     Length m_y;
@@ -780,7 +788,9 @@ public:
         AffineTransform matrix(m_a.value(), m_b.value(), m_c.value(), m_d.value(), m_e.calcValue(borderBoxSize.width()), m_f.calcValue(borderBoxSize.height()));
         transform.multiply(matrix);
     }
-   
+
+    virtual TransformOperation* blend(const TransformOperation* from, double progress, bool blendToIdentity = false);
+    
 private:
     Length m_a;
     Length m_b;
@@ -790,6 +800,24 @@ private:
     Length m_f;
 };
 
+class TransformOperations
+{
+public:
+    bool operator==(const TransformOperations&) const;
+    bool operator!=(const TransformOperations& o) const {
+        return !(*this == o);
+    }
+    
+    bool isEmpty() const { return m_operations.isEmpty(); }
+    unsigned size() const { return m_operations.size(); }
+    const RefPtr<TransformOperation>& operator[](size_t i) const { return m_operations.at(i); }
+
+    void append(const RefPtr<TransformOperation>& op) { return m_operations.append(op); }
+
+private:
+    Vector<RefPtr<TransformOperation> > m_operations;
+};
+
 class StyleTransformData : public Shared<StyleTransformData> {
 public:
     StyleTransformData();
@@ -800,9 +828,7 @@ public:
         return !(*this == o);
     }
 
-    bool transformDataEquivalent(const StyleTransformData&) const;
-
-    Vector<RefPtr<TransformOperation> > m_operations;
+    TransformOperations m_operations;
     Length m_x;
     Length m_y;
 };
@@ -1770,7 +1796,7 @@ public:
     EPageBreak columnBreakBefore() const { return static_cast<EPageBreak>(rareNonInheritedData->m_multiCol->m_breakBefore); }
     EPageBreak columnBreakInside() const { return static_cast<EPageBreak>(rareNonInheritedData->m_multiCol->m_breakInside); }
     EPageBreak columnBreakAfter() const { return static_cast<EPageBreak>(rareNonInheritedData->m_multiCol->m_breakAfter); }
-    const Vector<RefPtr<TransformOperation> >& transform() const { return rareNonInheritedData->m_transform->m_operations; }
+    const TransformOperations& transform() const { return rareNonInheritedData->m_transform->m_operations; }
     Length transformOriginX() const { return rareNonInheritedData->m_transform->m_x; }
     Length transformOriginY() const { return rareNonInheritedData->m_transform->m_y; }
     bool hasTransform() const { return !rareNonInheritedData->m_transform->m_operations.isEmpty(); }
@@ -2019,7 +2045,7 @@ public:
     void setColumnBreakBefore(EPageBreak p) { SET_VAR(rareNonInheritedData.access()->m_multiCol, m_breakBefore, p); }
     void setColumnBreakInside(EPageBreak p) { SET_VAR(rareNonInheritedData.access()->m_multiCol, m_breakInside, p); }
     void setColumnBreakAfter(EPageBreak p) { SET_VAR(rareNonInheritedData.access()->m_multiCol, m_breakAfter, p); }
-    void setTransform(const Vector<RefPtr<TransformOperation> >& ops) { SET_VAR(rareNonInheritedData.access()->m_transform, m_operations, ops); }
+    void setTransform(const TransformOperations& ops) { SET_VAR(rareNonInheritedData.access()->m_transform, m_operations, ops); }
     void setTransformOriginX(Length l) { SET_VAR(rareNonInheritedData.access()->m_transform, m_x, l); }
     void setTransformOriginY(Length l) { SET_VAR(rareNonInheritedData.access()->m_transform, m_y, l); }
     // End CSS3 Setters
@@ -2164,7 +2190,7 @@ public:
     static bool initialVisuallyOrdered() { return false; }
     static float initialTextStrokeWidth() { return 0; }
     static unsigned short initialColumnCount() { return 1; }
-    static const Vector<RefPtr<TransformOperation> >& initialTransform() { static Vector<RefPtr<TransformOperation> > ops; return ops; }
+    static const TransformOperations& initialTransform() { static TransformOperations ops; return ops; }
     static Length initialTransformOriginX() { return Length(50.0, Percent); }
     static Length initialTransformOriginY() { return Length(50.0, Percent); }