WebCore/page/animation/AnimationBase.cpp
changeset 0 4f2f89ce4247
equal deleted inserted replaced
-1:000000000000 0:4f2f89ce4247
       
     1 /*
       
     2  * Copyright (C) 2007, 2008, 2009 Apple Inc. All rights reserved.
       
     3  *
       
     4  * Redistribution and use in source and binary forms, with or without
       
     5  * modification, are permitted provided that the following conditions
       
     6  * are met:
       
     7  *
       
     8  * 1.  Redistributions of source code must retain the above copyright
       
     9  *     notice, this list of conditions and the following disclaimer. 
       
    10  * 2.  Redistributions in binary form must reproduce the above copyright
       
    11  *     notice, this list of conditions and the following disclaimer in the
       
    12  *     documentation and/or other materials provided with the distribution. 
       
    13  * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
       
    14  *     its contributors may be used to endorse or promote products derived
       
    15  *     from this software without specific prior written permission. 
       
    16  *
       
    17  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
       
    18  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
       
    19  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
       
    20  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
       
    21  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
       
    22  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
       
    23  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
       
    24  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
       
    25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
       
    26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
       
    27  */
       
    28 
       
    29 #include "config.h"
       
    30 #include "AnimationBase.h"
       
    31 
       
    32 #include "AnimationControllerPrivate.h"
       
    33 #include "CSSMutableStyleDeclaration.h"
       
    34 #include "CSSPropertyLonghand.h"
       
    35 #include "CSSPropertyNames.h"
       
    36 #include "CompositeAnimation.h"
       
    37 #include "Document.h"
       
    38 #include "EventNames.h"
       
    39 #include "FloatConversion.h"
       
    40 #include "Frame.h"
       
    41 #include "IdentityTransformOperation.h"
       
    42 #include "ImplicitAnimation.h"
       
    43 #include "KeyframeAnimation.h"
       
    44 #include "MatrixTransformOperation.h"
       
    45 #include "Matrix3DTransformOperation.h"
       
    46 #include "RenderBox.h"
       
    47 #include "RenderLayer.h"
       
    48 #include "RenderLayerBacking.h"
       
    49 #include "RenderStyle.h"
       
    50 #include "UnitBezier.h"
       
    51 
       
    52 #include <algorithm>
       
    53 
       
    54 using namespace std;
       
    55 
       
    56 namespace WebCore {
       
    57 
       
    58 // The epsilon value we pass to UnitBezier::solve given that the animation is going to run over |dur| seconds. The longer the
       
    59 // animation, the more precision we need in the timing function result to avoid ugly discontinuities.
       
    60 static inline double solveEpsilon(double duration)
       
    61 {
       
    62     return 1.0 / (200.0 * duration);
       
    63 }
       
    64 
       
    65 static inline double solveCubicBezierFunction(double p1x, double p1y, double p2x, double p2y, double t, double duration)
       
    66 {
       
    67     // Convert from input time to parametric value in curve, then from
       
    68     // that to output time.
       
    69     UnitBezier bezier(p1x, p1y, p2x, p2y);
       
    70     return bezier.solve(t, solveEpsilon(duration));
       
    71 }
       
    72 
       
    73 static inline int blendFunc(const AnimationBase*, int from, int to, double progress)
       
    74 {  
       
    75     return int(from + (to - from) * progress);
       
    76 }
       
    77 
       
    78 static inline double blendFunc(const AnimationBase*, double from, double to, double progress)
       
    79 {  
       
    80     return from + (to - from) * progress;
       
    81 }
       
    82 
       
    83 static inline float blendFunc(const AnimationBase*, float from, float to, double progress)
       
    84 {  
       
    85     return narrowPrecisionToFloat(from + (to - from) * progress);
       
    86 }
       
    87 
       
    88 static inline Color blendFunc(const AnimationBase* anim, const Color& from, const Color& to, double progress)
       
    89 {
       
    90     // We need to preserve the state of the valid flag at the end of the animation
       
    91     if (progress == 1 && !to.isValid())
       
    92         return Color();
       
    93 
       
    94     // Contrary to the name, RGBA32 actually stores ARGB, so we can initialize Color directly from premultipliedARGBFromColor().
       
    95     // Also, premultipliedARGBFromColor() bails on zero alpha, so special-case that.
       
    96     Color premultFrom = from.alpha() ? premultipliedARGBFromColor(from) : 0;
       
    97     Color premultTo = to.alpha() ? premultipliedARGBFromColor(to) : 0;
       
    98 
       
    99     Color premultBlended(blendFunc(anim, premultFrom.red(), premultTo.red(), progress),
       
   100                  blendFunc(anim, premultFrom.green(), premultTo.green(), progress),
       
   101                  blendFunc(anim, premultFrom.blue(), premultTo.blue(), progress),
       
   102                  blendFunc(anim, premultFrom.alpha(), premultTo.alpha(), progress));
       
   103 
       
   104     return Color(colorFromPremultipliedARGB(premultBlended.rgb()));
       
   105 }
       
   106 
       
   107 static inline Length blendFunc(const AnimationBase*, const Length& from, const Length& to, double progress)
       
   108 {  
       
   109     return to.blend(from, progress);
       
   110 }
       
   111 
       
   112 static inline LengthSize blendFunc(const AnimationBase* anim, const LengthSize& from, const LengthSize& to, double progress)
       
   113 {  
       
   114     return LengthSize(blendFunc(anim, from.width(), to.width(), progress),
       
   115                       blendFunc(anim, from.height(), to.height(), progress));
       
   116 }
       
   117 
       
   118 static inline IntSize blendFunc(const AnimationBase* anim, const IntSize& from, const IntSize& to, double progress)
       
   119 {  
       
   120     return IntSize(blendFunc(anim, from.width(), to.width(), progress),
       
   121                    blendFunc(anim, from.height(), to.height(), progress));
       
   122 }
       
   123 
       
   124 static inline ShadowStyle blendFunc(const AnimationBase* anim, ShadowStyle from, ShadowStyle to, double progress)
       
   125 {
       
   126     if (from == to)
       
   127         return to;
       
   128 
       
   129     double fromVal = from == Normal ? 1 : 0;
       
   130     double toVal = to == Normal ? 1 : 0;
       
   131     double result = blendFunc(anim, fromVal, toVal, progress);
       
   132     return result > 0 ? Normal : Inset;
       
   133 }
       
   134 
       
   135 static inline ShadowData* blendFunc(const AnimationBase* anim, const ShadowData* from, const ShadowData* to, double progress)
       
   136 {  
       
   137     ASSERT(from && to);
       
   138     return new ShadowData(blendFunc(anim, from->x(), to->x(), progress), blendFunc(anim, from->y(), to->y(), progress), 
       
   139                           blendFunc(anim, from->blur(), to->blur(), progress), blendFunc(anim, from->spread(), to->spread(), progress),
       
   140                           blendFunc(anim, from->style(), to->style(), progress), blendFunc(anim, from->color(), to->color(), progress));
       
   141 }
       
   142 
       
   143 static inline TransformOperations blendFunc(const AnimationBase* anim, const TransformOperations& from, const TransformOperations& to, double progress)
       
   144 {    
       
   145     TransformOperations result;
       
   146 
       
   147     // If we have a transform function list, use that to do a per-function animation. Otherwise do a Matrix animation
       
   148     if (anim->isTransformFunctionListValid()) {
       
   149         unsigned fromSize = from.operations().size();
       
   150         unsigned toSize = to.operations().size();
       
   151         unsigned size = max(fromSize, toSize);
       
   152         for (unsigned i = 0; i < size; i++) {
       
   153             RefPtr<TransformOperation> fromOp = (i < fromSize) ? from.operations()[i].get() : 0;
       
   154             RefPtr<TransformOperation> toOp = (i < toSize) ? to.operations()[i].get() : 0;
       
   155             RefPtr<TransformOperation> blendedOp = toOp ? toOp->blend(fromOp.get(), progress) : (fromOp ? fromOp->blend(0, progress, true) : 0);
       
   156             if (blendedOp)
       
   157                 result.operations().append(blendedOp);
       
   158             else {
       
   159                 RefPtr<TransformOperation> identityOp = IdentityTransformOperation::create();
       
   160                 if (progress > 0.5)
       
   161                     result.operations().append(toOp ? toOp : identityOp);
       
   162                 else
       
   163                     result.operations().append(fromOp ? fromOp : identityOp);
       
   164             }
       
   165         }
       
   166     } else {
       
   167         // Convert the TransformOperations into matrices
       
   168         IntSize size = anim->renderer()->isBox() ? toRenderBox(anim->renderer())->borderBoxRect().size() : IntSize();
       
   169         TransformationMatrix fromT;
       
   170         TransformationMatrix toT;
       
   171         from.apply(size, fromT);
       
   172         to.apply(size, toT);
       
   173         
       
   174         toT.blend(fromT, progress);
       
   175         
       
   176         // Append the result
       
   177         result.operations().append(Matrix3DTransformOperation::create(toT));
       
   178     }
       
   179     return result;
       
   180 }
       
   181 
       
   182 static inline EVisibility blendFunc(const AnimationBase* anim, EVisibility from, EVisibility to, double progress)
       
   183 {
       
   184     // Any non-zero result means we consider the object to be visible.  Only at 0 do we consider the object to be
       
   185     // invisible.   The invisible value we use (HIDDEN vs. COLLAPSE) depends on the specified from/to values.
       
   186     double fromVal = from == VISIBLE ? 1. : 0.;
       
   187     double toVal = to == VISIBLE ? 1. : 0.;
       
   188     if (fromVal == toVal)
       
   189         return to;
       
   190     double result = blendFunc(anim, fromVal, toVal, progress);
       
   191     return result > 0. ? VISIBLE : (to != VISIBLE ? to : from);
       
   192 }
       
   193 
       
   194 static inline LengthBox blendFunc(const AnimationBase* anim, const LengthBox& from, const LengthBox& to, double progress)
       
   195 {
       
   196     // Length types have to match to animate
       
   197     if (from.top().type() != to.top().type()
       
   198         || from.right().type() != to.right().type()
       
   199         || from.bottom().type() != to.bottom().type()
       
   200         || from.left().type() != to.left().type())
       
   201         return to;
       
   202     
       
   203     LengthBox result(blendFunc(anim, from.top(), to.top(), progress),
       
   204                      blendFunc(anim, from.right(), to.right(), progress),
       
   205                      blendFunc(anim, from.bottom(), to.bottom(), progress),
       
   206                      blendFunc(anim, from.left(), to.left(), progress));
       
   207     return result;
       
   208 }
       
   209 
       
   210 class PropertyWrapperBase;
       
   211 
       
   212 static void addShorthandProperties();
       
   213 static PropertyWrapperBase* wrapperForProperty(int propertyID);
       
   214 
       
   215 class PropertyWrapperBase : public Noncopyable {
       
   216 public:
       
   217     PropertyWrapperBase(int prop)
       
   218         : m_prop(prop)
       
   219     {
       
   220     }
       
   221 
       
   222     virtual ~PropertyWrapperBase() { }
       
   223     
       
   224     virtual bool isShorthandWrapper() const { return false; }
       
   225     virtual bool equals(const RenderStyle* a, const RenderStyle* b) const = 0;
       
   226     virtual void blend(const AnimationBase* anim, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress) const = 0;
       
   227 
       
   228     int property() const { return m_prop; }
       
   229 
       
   230 #if USE(ACCELERATED_COMPOSITING)
       
   231     virtual bool animationIsAccelerated() const { return false; }
       
   232 #endif
       
   233 
       
   234 private:
       
   235     int m_prop;
       
   236 };
       
   237 
       
   238 template <typename T>
       
   239 class PropertyWrapperGetter : public PropertyWrapperBase {
       
   240 public:
       
   241     PropertyWrapperGetter(int prop, T (RenderStyle::*getter)() const)
       
   242         : PropertyWrapperBase(prop)
       
   243         , m_getter(getter)
       
   244     {
       
   245     }
       
   246 
       
   247     virtual bool equals(const RenderStyle* a, const RenderStyle* b) const
       
   248     {
       
   249        // If the style pointers are the same, don't bother doing the test.
       
   250        // If either is null, return false. If both are null, return true.
       
   251        if ((!a && !b) || a == b)
       
   252            return true;
       
   253        if (!a || !b)
       
   254             return false;
       
   255         return (a->*m_getter)() == (b->*m_getter)();
       
   256     }
       
   257 
       
   258 protected:
       
   259     T (RenderStyle::*m_getter)() const;
       
   260 };
       
   261 
       
   262 template <typename T>
       
   263 class PropertyWrapper : public PropertyWrapperGetter<T> {
       
   264 public:
       
   265     PropertyWrapper(int prop, T (RenderStyle::*getter)() const, void (RenderStyle::*setter)(T))
       
   266         : PropertyWrapperGetter<T>(prop, getter)
       
   267         , m_setter(setter)
       
   268     {
       
   269     }
       
   270     
       
   271     virtual void blend(const AnimationBase* anim, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress) const
       
   272     {
       
   273         (dst->*m_setter)(blendFunc(anim, (a->*PropertyWrapperGetter<T>::m_getter)(), (b->*PropertyWrapperGetter<T>::m_getter)(), progress));
       
   274     }
       
   275 
       
   276 protected:
       
   277     void (RenderStyle::*m_setter)(T);
       
   278 };
       
   279 
       
   280 #if USE(ACCELERATED_COMPOSITING)
       
   281 class PropertyWrapperAcceleratedOpacity : public PropertyWrapper<float> {
       
   282 public:
       
   283     PropertyWrapperAcceleratedOpacity()
       
   284         : PropertyWrapper<float>(CSSPropertyOpacity, &RenderStyle::opacity, &RenderStyle::setOpacity)
       
   285     {
       
   286     }
       
   287 
       
   288     virtual bool animationIsAccelerated() const { return true; }
       
   289 
       
   290     virtual void blend(const AnimationBase* anim, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress) const
       
   291     {
       
   292         float fromOpacity = a->opacity();
       
   293         
       
   294         // This makes sure we put the object being animated into a RenderLayer during the animation
       
   295         dst->setOpacity(blendFunc(anim, (fromOpacity == 1) ? 0.999999f : fromOpacity, b->opacity(), progress));
       
   296     }
       
   297 };
       
   298 
       
   299 class PropertyWrapperAcceleratedTransform : public PropertyWrapper<const TransformOperations&> {
       
   300 public:
       
   301     PropertyWrapperAcceleratedTransform()
       
   302         : PropertyWrapper<const TransformOperations&>(CSSPropertyWebkitTransform, &RenderStyle::transform, &RenderStyle::setTransform)
       
   303     {
       
   304     }
       
   305     
       
   306     virtual bool animationIsAccelerated() const { return true; }
       
   307 
       
   308     virtual void blend(const AnimationBase* anim, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress) const
       
   309     {
       
   310         dst->setTransform(blendFunc(anim, a->transform(), b->transform(), progress));
       
   311     }
       
   312 };
       
   313 #endif // USE(ACCELERATED_COMPOSITING)
       
   314 
       
   315 class PropertyWrapperShadow : public PropertyWrapperBase {
       
   316 public:
       
   317     PropertyWrapperShadow(int prop, const ShadowData* (RenderStyle::*getter)() const, void (RenderStyle::*setter)(ShadowData*, bool))
       
   318         : PropertyWrapperBase(prop)
       
   319         , m_getter(getter)
       
   320         , m_setter(setter)
       
   321     {
       
   322     }
       
   323 
       
   324     virtual bool equals(const RenderStyle* a, const RenderStyle* b) const
       
   325     {
       
   326         const ShadowData* shadowA = (a->*m_getter)();
       
   327         const ShadowData* shadowB = (b->*m_getter)();
       
   328         
       
   329         while (true) {
       
   330             if (!shadowA && !shadowB)   // end of both lists
       
   331                 return true;
       
   332 
       
   333             if (!shadowA || !shadowB)   // end of just one of the lists
       
   334                 return false;
       
   335 
       
   336             if (*shadowA != *shadowB)
       
   337                 return false;
       
   338         
       
   339             shadowA = shadowA->next();
       
   340             shadowB = shadowB->next();
       
   341         }
       
   342 
       
   343         return true;
       
   344     }
       
   345 
       
   346     virtual void blend(const AnimationBase* anim, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress) const
       
   347     {
       
   348         const ShadowData* shadowA = (a->*m_getter)();
       
   349         const ShadowData* shadowB = (b->*m_getter)();
       
   350         ShadowData defaultShadowData(0, 0, 0, 0, Normal, Color::transparent);
       
   351 
       
   352         ShadowData* newShadowData = 0;
       
   353         
       
   354         while (shadowA || shadowB) {
       
   355             const ShadowData* srcShadow = shadowA ? shadowA : &defaultShadowData;
       
   356             const ShadowData* dstShadow = shadowB ? shadowB : &defaultShadowData;
       
   357             
       
   358             if (!newShadowData)
       
   359                 newShadowData = blendFunc(anim, srcShadow, dstShadow, progress);
       
   360             else
       
   361                 newShadowData->setNext(blendFunc(anim, srcShadow, dstShadow, progress));
       
   362 
       
   363             shadowA = shadowA ? shadowA->next() : 0;
       
   364             shadowB = shadowB ? shadowB->next() : 0;
       
   365         }
       
   366         
       
   367         (dst->*m_setter)(newShadowData, false);
       
   368     }
       
   369 
       
   370 private:
       
   371     const ShadowData* (RenderStyle::*m_getter)() const;
       
   372     void (RenderStyle::*m_setter)(ShadowData*, bool);
       
   373 };
       
   374 
       
   375 class PropertyWrapperMaybeInvalidColor : public PropertyWrapperBase {
       
   376 public:
       
   377     PropertyWrapperMaybeInvalidColor(int prop, const Color& (RenderStyle::*getter)() const, void (RenderStyle::*setter)(const Color&))
       
   378         : PropertyWrapperBase(prop)
       
   379         , m_getter(getter)
       
   380         , m_setter(setter)
       
   381     {
       
   382     }
       
   383 
       
   384     virtual bool equals(const RenderStyle* a, const RenderStyle* b) const
       
   385     {
       
   386         Color fromColor = (a->*m_getter)();
       
   387         Color toColor = (b->*m_getter)();
       
   388 
       
   389         if (!fromColor.isValid() && !toColor.isValid())
       
   390             return true;
       
   391 
       
   392         if (!fromColor.isValid())
       
   393             fromColor = a->color();
       
   394         if (!toColor.isValid())
       
   395             toColor = b->color();
       
   396 
       
   397         return fromColor == toColor;
       
   398     }
       
   399 
       
   400     virtual void blend(const AnimationBase* anim, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress) const
       
   401     {
       
   402         Color fromColor = (a->*m_getter)();
       
   403         Color toColor = (b->*m_getter)();
       
   404 
       
   405         if (!fromColor.isValid() && !toColor.isValid())
       
   406             return;
       
   407 
       
   408         if (!fromColor.isValid())
       
   409             fromColor = a->color();
       
   410         if (!toColor.isValid())
       
   411             toColor = b->color();
       
   412         (dst->*m_setter)(blendFunc(anim, fromColor, toColor, progress));
       
   413     }
       
   414 
       
   415 private:
       
   416     const Color& (RenderStyle::*m_getter)() const;
       
   417     void (RenderStyle::*m_setter)(const Color&);
       
   418 };
       
   419 
       
   420 // Wrapper base class for an animatable property in a FillLayer
       
   421 class FillLayerPropertyWrapperBase {
       
   422 public:
       
   423     FillLayerPropertyWrapperBase()
       
   424     {
       
   425     }
       
   426 
       
   427     virtual ~FillLayerPropertyWrapperBase() { }
       
   428     
       
   429     virtual bool equals(const FillLayer* a, const FillLayer* b) const = 0;
       
   430     virtual void blend(const AnimationBase* anim, FillLayer* dst, const FillLayer* a, const FillLayer* b, double progress) const = 0;
       
   431 };
       
   432 
       
   433 template <typename T>
       
   434 class FillLayerPropertyWrapperGetter : public FillLayerPropertyWrapperBase, public Noncopyable {
       
   435 public:
       
   436     FillLayerPropertyWrapperGetter(T (FillLayer::*getter)() const)
       
   437         : m_getter(getter)
       
   438     {
       
   439     }
       
   440 
       
   441     virtual bool equals(const FillLayer* a, const FillLayer* b) const
       
   442     {
       
   443        // If the style pointers are the same, don't bother doing the test.
       
   444        // If either is null, return false. If both are null, return true.
       
   445        if ((!a && !b) || a == b)
       
   446            return true;
       
   447        if (!a || !b)
       
   448             return false;
       
   449         return (a->*m_getter)() == (b->*m_getter)();
       
   450     }
       
   451 
       
   452 protected:
       
   453     T (FillLayer::*m_getter)() const;
       
   454 };
       
   455 
       
   456 template <typename T>
       
   457 class FillLayerPropertyWrapper : public FillLayerPropertyWrapperGetter<T> {
       
   458 public:
       
   459     FillLayerPropertyWrapper(T (FillLayer::*getter)() const, void (FillLayer::*setter)(T))
       
   460         : FillLayerPropertyWrapperGetter<T>(getter)
       
   461         , m_setter(setter)
       
   462     {
       
   463     }
       
   464     
       
   465     virtual void blend(const AnimationBase* anim, FillLayer* dst, const FillLayer* a, const FillLayer* b, double progress) const
       
   466     {
       
   467         (dst->*m_setter)(blendFunc(anim, (a->*FillLayerPropertyWrapperGetter<T>::m_getter)(), (b->*FillLayerPropertyWrapperGetter<T>::m_getter)(), progress));
       
   468     }
       
   469 
       
   470 protected:
       
   471     void (FillLayer::*m_setter)(T);
       
   472 };
       
   473 
       
   474 
       
   475 class FillLayersPropertyWrapper : public PropertyWrapperBase {
       
   476 public:
       
   477     typedef const FillLayer* (RenderStyle::*LayersGetter)() const;
       
   478     typedef FillLayer* (RenderStyle::*LayersAccessor)();
       
   479     
       
   480     FillLayersPropertyWrapper(int prop, LayersGetter getter, LayersAccessor accessor)
       
   481         : PropertyWrapperBase(prop)
       
   482         , m_layersGetter(getter)
       
   483         , m_layersAccessor(accessor)
       
   484     {
       
   485         switch (prop) {
       
   486             case CSSPropertyBackgroundPositionX:
       
   487             case CSSPropertyWebkitMaskPositionX:
       
   488                 m_fillLayerPropertyWrapper = new FillLayerPropertyWrapper<Length>(&FillLayer::xPosition, &FillLayer::setXPosition);
       
   489                 break;
       
   490             case CSSPropertyBackgroundPositionY:
       
   491             case CSSPropertyWebkitMaskPositionY:
       
   492                 m_fillLayerPropertyWrapper = new FillLayerPropertyWrapper<Length>(&FillLayer::yPosition, &FillLayer::setYPosition);
       
   493                 break;
       
   494             case CSSPropertyBackgroundSize:
       
   495             case CSSPropertyWebkitBackgroundSize:
       
   496             case CSSPropertyWebkitMaskSize:
       
   497                 m_fillLayerPropertyWrapper = new FillLayerPropertyWrapper<LengthSize>(&FillLayer::sizeLength, &FillLayer::setSizeLength);
       
   498                 break;
       
   499         }
       
   500     }
       
   501 
       
   502     virtual bool equals(const RenderStyle* a, const RenderStyle* b) const
       
   503     {
       
   504         const FillLayer* fromLayer = (a->*m_layersGetter)();
       
   505         const FillLayer* toLayer = (b->*m_layersGetter)();
       
   506 
       
   507         while (fromLayer && toLayer) {
       
   508             if (!m_fillLayerPropertyWrapper->equals(fromLayer, toLayer))
       
   509                 return false;
       
   510             
       
   511             fromLayer = fromLayer->next();
       
   512             toLayer = toLayer->next();
       
   513         }
       
   514 
       
   515         return true;
       
   516     }
       
   517 
       
   518     virtual void blend(const AnimationBase* anim, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress) const
       
   519     {
       
   520         const FillLayer* aLayer = (a->*m_layersGetter)();
       
   521         const FillLayer* bLayer = (b->*m_layersGetter)();
       
   522         FillLayer* dstLayer = (dst->*m_layersAccessor)();
       
   523 
       
   524         while (aLayer && bLayer && dstLayer) {
       
   525             m_fillLayerPropertyWrapper->blend(anim, dstLayer, aLayer, bLayer, progress);
       
   526             aLayer = aLayer->next();
       
   527             bLayer = bLayer->next();
       
   528             dstLayer = dstLayer->next();
       
   529         }
       
   530     }
       
   531 
       
   532 private:
       
   533     FillLayerPropertyWrapperBase* m_fillLayerPropertyWrapper;
       
   534     
       
   535     LayersGetter m_layersGetter;
       
   536     LayersAccessor m_layersAccessor;
       
   537 };
       
   538 
       
   539 class ShorthandPropertyWrapper : public PropertyWrapperBase {
       
   540 public:
       
   541     ShorthandPropertyWrapper(int property, const CSSPropertyLonghand& longhand)
       
   542         : PropertyWrapperBase(property)
       
   543     {
       
   544         for (unsigned i = 0; i < longhand.length(); ++i) {
       
   545             PropertyWrapperBase* wrapper = wrapperForProperty(longhand.properties()[i]);
       
   546             if (wrapper)
       
   547                 m_propertyWrappers.append(wrapper);
       
   548         }
       
   549     }
       
   550 
       
   551     virtual bool isShorthandWrapper() const { return true; }
       
   552 
       
   553     virtual bool equals(const RenderStyle* a, const RenderStyle* b) const
       
   554     {
       
   555         Vector<PropertyWrapperBase*>::const_iterator end = m_propertyWrappers.end();
       
   556         for (Vector<PropertyWrapperBase*>::const_iterator it = m_propertyWrappers.begin(); it != end; ++it) {
       
   557             if (!(*it)->equals(a, b))
       
   558                 return false;
       
   559         }
       
   560         return true;
       
   561     }
       
   562 
       
   563     virtual void blend(const AnimationBase* anim, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress) const
       
   564     {
       
   565         Vector<PropertyWrapperBase*>::const_iterator end = m_propertyWrappers.end();
       
   566         for (Vector<PropertyWrapperBase*>::const_iterator it = m_propertyWrappers.begin(); it != end; ++it)
       
   567             (*it)->blend(anim, dst, a, b, progress);
       
   568     }
       
   569 
       
   570 private:
       
   571     Vector<PropertyWrapperBase*> m_propertyWrappers;
       
   572 };
       
   573 
       
   574 
       
   575 static Vector<PropertyWrapperBase*>* gPropertyWrappers = 0;
       
   576 static int gPropertyWrapperMap[numCSSProperties];
       
   577 
       
   578 static const int cInvalidPropertyWrapperIndex = -1;
       
   579 
       
   580 
       
   581 void AnimationBase::ensurePropertyMap()
       
   582 {
       
   583     // FIXME: This data is never destroyed. Maybe we should ref count it and toss it when the last AnimationController is destroyed?
       
   584     if (gPropertyWrappers == 0) {
       
   585         gPropertyWrappers = new Vector<PropertyWrapperBase*>();
       
   586 
       
   587         // build the list of property wrappers to do the comparisons and blends
       
   588         gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyLeft, &RenderStyle::left, &RenderStyle::setLeft));
       
   589         gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyRight, &RenderStyle::right, &RenderStyle::setRight));
       
   590         gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyTop, &RenderStyle::top, &RenderStyle::setTop));
       
   591         gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyBottom, &RenderStyle::bottom, &RenderStyle::setBottom));
       
   592 
       
   593         gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyWidth, &RenderStyle::width, &RenderStyle::setWidth));
       
   594         gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyMinWidth, &RenderStyle::minWidth, &RenderStyle::setMinWidth));
       
   595         gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyMaxWidth, &RenderStyle::maxWidth, &RenderStyle::setMaxWidth));
       
   596 
       
   597         gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyHeight, &RenderStyle::height, &RenderStyle::setHeight));
       
   598         gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyMinHeight, &RenderStyle::minHeight, &RenderStyle::setMinHeight));
       
   599         gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyMaxHeight, &RenderStyle::maxHeight, &RenderStyle::setMaxHeight));
       
   600 
       
   601         gPropertyWrappers->append(new PropertyWrapper<unsigned short>(CSSPropertyBorderLeftWidth, &RenderStyle::borderLeftWidth, &RenderStyle::setBorderLeftWidth));
       
   602         gPropertyWrappers->append(new PropertyWrapper<unsigned short>(CSSPropertyBorderRightWidth, &RenderStyle::borderRightWidth, &RenderStyle::setBorderRightWidth));
       
   603         gPropertyWrappers->append(new PropertyWrapper<unsigned short>(CSSPropertyBorderTopWidth, &RenderStyle::borderTopWidth, &RenderStyle::setBorderTopWidth));
       
   604         gPropertyWrappers->append(new PropertyWrapper<unsigned short>(CSSPropertyBorderBottomWidth, &RenderStyle::borderBottomWidth, &RenderStyle::setBorderBottomWidth));
       
   605         gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyMarginLeft, &RenderStyle::marginLeft, &RenderStyle::setMarginLeft));
       
   606         gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyMarginRight, &RenderStyle::marginRight, &RenderStyle::setMarginRight));
       
   607         gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyMarginTop, &RenderStyle::marginTop, &RenderStyle::setMarginTop));
       
   608         gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyMarginBottom, &RenderStyle::marginBottom, &RenderStyle::setMarginBottom));
       
   609         gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyPaddingLeft, &RenderStyle::paddingLeft, &RenderStyle::setPaddingLeft));
       
   610         gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyPaddingRight, &RenderStyle::paddingRight, &RenderStyle::setPaddingRight));
       
   611         gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyPaddingTop, &RenderStyle::paddingTop, &RenderStyle::setPaddingTop));
       
   612         gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyPaddingBottom, &RenderStyle::paddingBottom, &RenderStyle::setPaddingBottom));
       
   613         gPropertyWrappers->append(new PropertyWrapper<const Color&>(CSSPropertyColor, &RenderStyle::color, &RenderStyle::setColor));
       
   614 
       
   615         gPropertyWrappers->append(new PropertyWrapper<const Color&>(CSSPropertyBackgroundColor, &RenderStyle::backgroundColor, &RenderStyle::setBackgroundColor));
       
   616 
       
   617         gPropertyWrappers->append(new FillLayersPropertyWrapper(CSSPropertyBackgroundPositionX, &RenderStyle::backgroundLayers, &RenderStyle::accessBackgroundLayers));
       
   618         gPropertyWrappers->append(new FillLayersPropertyWrapper(CSSPropertyBackgroundPositionY, &RenderStyle::backgroundLayers, &RenderStyle::accessBackgroundLayers));
       
   619         gPropertyWrappers->append(new FillLayersPropertyWrapper(CSSPropertyBackgroundSize, &RenderStyle::backgroundLayers, &RenderStyle::accessBackgroundLayers));
       
   620         gPropertyWrappers->append(new FillLayersPropertyWrapper(CSSPropertyWebkitBackgroundSize, &RenderStyle::backgroundLayers, &RenderStyle::accessBackgroundLayers));
       
   621 
       
   622         gPropertyWrappers->append(new FillLayersPropertyWrapper(CSSPropertyWebkitMaskPositionX, &RenderStyle::maskLayers, &RenderStyle::accessMaskLayers));
       
   623         gPropertyWrappers->append(new FillLayersPropertyWrapper(CSSPropertyWebkitMaskPositionY, &RenderStyle::maskLayers, &RenderStyle::accessMaskLayers));
       
   624         gPropertyWrappers->append(new FillLayersPropertyWrapper(CSSPropertyWebkitMaskSize, &RenderStyle::maskLayers, &RenderStyle::accessMaskLayers));
       
   625 
       
   626         gPropertyWrappers->append(new PropertyWrapper<int>(CSSPropertyFontSize, &RenderStyle::fontSize, &RenderStyle::setBlendedFontSize));
       
   627         gPropertyWrappers->append(new PropertyWrapper<unsigned short>(CSSPropertyWebkitColumnRuleWidth, &RenderStyle::columnRuleWidth, &RenderStyle::setColumnRuleWidth));
       
   628         gPropertyWrappers->append(new PropertyWrapper<float>(CSSPropertyWebkitColumnGap, &RenderStyle::columnGap, &RenderStyle::setColumnGap));
       
   629         gPropertyWrappers->append(new PropertyWrapper<unsigned short>(CSSPropertyWebkitColumnCount, &RenderStyle::columnCount, &RenderStyle::setColumnCount));
       
   630         gPropertyWrappers->append(new PropertyWrapper<float>(CSSPropertyWebkitColumnWidth, &RenderStyle::columnWidth, &RenderStyle::setColumnWidth));
       
   631         gPropertyWrappers->append(new PropertyWrapper<short>(CSSPropertyWebkitBorderHorizontalSpacing, &RenderStyle::horizontalBorderSpacing, &RenderStyle::setHorizontalBorderSpacing));
       
   632         gPropertyWrappers->append(new PropertyWrapper<short>(CSSPropertyWebkitBorderVerticalSpacing, &RenderStyle::verticalBorderSpacing, &RenderStyle::setVerticalBorderSpacing));
       
   633         gPropertyWrappers->append(new PropertyWrapper<int>(CSSPropertyZIndex, &RenderStyle::zIndex, &RenderStyle::setZIndex));
       
   634         gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyLineHeight, &RenderStyle::lineHeight, &RenderStyle::setLineHeight));
       
   635         gPropertyWrappers->append(new PropertyWrapper<int>(CSSPropertyOutlineOffset, &RenderStyle::outlineOffset, &RenderStyle::setOutlineOffset));
       
   636         gPropertyWrappers->append(new PropertyWrapper<unsigned short>(CSSPropertyOutlineWidth, &RenderStyle::outlineWidth, &RenderStyle::setOutlineWidth));
       
   637         gPropertyWrappers->append(new PropertyWrapper<int>(CSSPropertyLetterSpacing, &RenderStyle::letterSpacing, &RenderStyle::setLetterSpacing));
       
   638         gPropertyWrappers->append(new PropertyWrapper<int>(CSSPropertyWordSpacing, &RenderStyle::wordSpacing, &RenderStyle::setWordSpacing));
       
   639         gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyTextIndent, &RenderStyle::textIndent, &RenderStyle::setTextIndent));
       
   640 
       
   641         gPropertyWrappers->append(new PropertyWrapper<float>(CSSPropertyWebkitPerspective, &RenderStyle::perspective, &RenderStyle::setPerspective));
       
   642         gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyWebkitPerspectiveOriginX, &RenderStyle::perspectiveOriginX, &RenderStyle::setPerspectiveOriginX));
       
   643         gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyWebkitPerspectiveOriginY, &RenderStyle::perspectiveOriginY, &RenderStyle::setPerspectiveOriginY));
       
   644         gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyWebkitTransformOriginX, &RenderStyle::transformOriginX, &RenderStyle::setTransformOriginX));
       
   645         gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyWebkitTransformOriginY, &RenderStyle::transformOriginY, &RenderStyle::setTransformOriginY));
       
   646         gPropertyWrappers->append(new PropertyWrapper<float>(CSSPropertyWebkitTransformOriginZ, &RenderStyle::transformOriginZ, &RenderStyle::setTransformOriginZ));
       
   647         gPropertyWrappers->append(new PropertyWrapper<const IntSize&>(CSSPropertyBorderTopLeftRadius, &RenderStyle::borderTopLeftRadius, &RenderStyle::setBorderTopLeftRadius));
       
   648         gPropertyWrappers->append(new PropertyWrapper<const IntSize&>(CSSPropertyBorderTopRightRadius, &RenderStyle::borderTopRightRadius, &RenderStyle::setBorderTopRightRadius));
       
   649         gPropertyWrappers->append(new PropertyWrapper<const IntSize&>(CSSPropertyBorderBottomLeftRadius, &RenderStyle::borderBottomLeftRadius, &RenderStyle::setBorderBottomLeftRadius));
       
   650         gPropertyWrappers->append(new PropertyWrapper<const IntSize&>(CSSPropertyBorderBottomRightRadius, &RenderStyle::borderBottomRightRadius, &RenderStyle::setBorderBottomRightRadius));
       
   651         gPropertyWrappers->append(new PropertyWrapper<EVisibility>(CSSPropertyVisibility, &RenderStyle::visibility, &RenderStyle::setVisibility));
       
   652         gPropertyWrappers->append(new PropertyWrapper<float>(CSSPropertyZoom, &RenderStyle::zoom, &RenderStyle::setZoom));
       
   653 
       
   654         gPropertyWrappers->append(new PropertyWrapper<LengthBox>(CSSPropertyClip, &RenderStyle::clip, &RenderStyle::setClip));
       
   655         
       
   656 #if USE(ACCELERATED_COMPOSITING)
       
   657         gPropertyWrappers->append(new PropertyWrapperAcceleratedOpacity());
       
   658         gPropertyWrappers->append(new PropertyWrapperAcceleratedTransform());
       
   659 #else
       
   660         gPropertyWrappers->append(new PropertyWrapper<float>(CSSPropertyOpacity, &RenderStyle::opacity, &RenderStyle::setOpacity));
       
   661         gPropertyWrappers->append(new PropertyWrapper<const TransformOperations&>(CSSPropertyWebkitTransform, &RenderStyle::transform, &RenderStyle::setTransform));
       
   662 #endif
       
   663 
       
   664         gPropertyWrappers->append(new PropertyWrapperMaybeInvalidColor(CSSPropertyWebkitColumnRuleColor, &RenderStyle::columnRuleColor, &RenderStyle::setColumnRuleColor));
       
   665         gPropertyWrappers->append(new PropertyWrapperMaybeInvalidColor(CSSPropertyWebkitTextStrokeColor, &RenderStyle::textStrokeColor, &RenderStyle::setTextStrokeColor));
       
   666         gPropertyWrappers->append(new PropertyWrapperMaybeInvalidColor(CSSPropertyWebkitTextFillColor, &RenderStyle::textFillColor, &RenderStyle::setTextFillColor));
       
   667         gPropertyWrappers->append(new PropertyWrapperMaybeInvalidColor(CSSPropertyBorderLeftColor, &RenderStyle::borderLeftColor, &RenderStyle::setBorderLeftColor));
       
   668         gPropertyWrappers->append(new PropertyWrapperMaybeInvalidColor(CSSPropertyBorderRightColor, &RenderStyle::borderRightColor, &RenderStyle::setBorderRightColor));
       
   669         gPropertyWrappers->append(new PropertyWrapperMaybeInvalidColor(CSSPropertyBorderTopColor, &RenderStyle::borderTopColor, &RenderStyle::setBorderTopColor));
       
   670         gPropertyWrappers->append(new PropertyWrapperMaybeInvalidColor(CSSPropertyBorderBottomColor, &RenderStyle::borderBottomColor, &RenderStyle::setBorderBottomColor));
       
   671         gPropertyWrappers->append(new PropertyWrapperMaybeInvalidColor(CSSPropertyOutlineColor, &RenderStyle::outlineColor, &RenderStyle::setOutlineColor));
       
   672 
       
   673         gPropertyWrappers->append(new PropertyWrapperShadow(CSSPropertyWebkitBoxShadow, &RenderStyle::boxShadow, &RenderStyle::setBoxShadow));
       
   674         gPropertyWrappers->append(new PropertyWrapperShadow(CSSPropertyTextShadow, &RenderStyle::textShadow, &RenderStyle::setTextShadow));
       
   675 
       
   676 #if ENABLE(SVG)
       
   677         gPropertyWrappers->append(new PropertyWrapper<float>(CSSPropertyFillOpacity, &RenderStyle::fillOpacity, &RenderStyle::setFillOpacity));
       
   678         gPropertyWrappers->append(new PropertyWrapper<float>(CSSPropertyFloodOpacity, &RenderStyle::floodOpacity, &RenderStyle::setFloodOpacity));
       
   679         gPropertyWrappers->append(new PropertyWrapper<float>(CSSPropertyStrokeOpacity, &RenderStyle::strokeOpacity, &RenderStyle::setStrokeOpacity));
       
   680 #endif
       
   681 
       
   682         // TODO:
       
   683         // 
       
   684         //  CSSPropertyVerticalAlign
       
   685         // 
       
   686         // Compound properties that have components that should be animatable:
       
   687         // 
       
   688         //  CSSPropertyWebkitColumns
       
   689         //  CSSPropertyWebkitBoxReflect
       
   690 
       
   691         // Make sure unused slots have a value
       
   692         for (unsigned int i = 0; i < static_cast<unsigned int>(numCSSProperties); ++i)
       
   693             gPropertyWrapperMap[i] = cInvalidPropertyWrapperIndex;
       
   694 
       
   695         // First we put the non-shorthand property wrappers into the map, so the shorthand-building
       
   696         // code can find them.
       
   697         size_t n = gPropertyWrappers->size();
       
   698         for (unsigned int i = 0; i < n; ++i) {
       
   699             ASSERT((*gPropertyWrappers)[i]->property() - firstCSSProperty < numCSSProperties);
       
   700             gPropertyWrapperMap[(*gPropertyWrappers)[i]->property() - firstCSSProperty] = i;
       
   701         }
       
   702         
       
   703         // Now add the shorthand wrappers.
       
   704         addShorthandProperties();
       
   705     }
       
   706 }
       
   707 
       
   708 static void addPropertyWrapper(int propertyID, PropertyWrapperBase* wrapper)
       
   709 {
       
   710     int propIndex = propertyID - firstCSSProperty;
       
   711 
       
   712     ASSERT(gPropertyWrapperMap[propIndex] == cInvalidPropertyWrapperIndex);
       
   713 
       
   714     unsigned wrapperIndex = gPropertyWrappers->size();
       
   715     gPropertyWrappers->append(wrapper);
       
   716     gPropertyWrapperMap[propIndex] = wrapperIndex;
       
   717 }
       
   718 
       
   719 static void addShorthandProperties()
       
   720 {
       
   721     static const int animatableShorthandProperties[] = {
       
   722         CSSPropertyBackground,      // for background-color, background-position
       
   723         CSSPropertyBackgroundPosition,
       
   724         CSSPropertyWebkitMask,      // for mask-position
       
   725         CSSPropertyWebkitMaskPosition,
       
   726         CSSPropertyBorderTop, CSSPropertyBorderRight, CSSPropertyBorderBottom, CSSPropertyBorderLeft,
       
   727         CSSPropertyBorderColor, 
       
   728         CSSPropertyBorderWidth,
       
   729         CSSPropertyBorder,
       
   730         CSSPropertyBorderSpacing,
       
   731         CSSPropertyMargin,
       
   732         CSSPropertyOutline,
       
   733         CSSPropertyPadding,
       
   734         CSSPropertyWebkitTextStroke,
       
   735         CSSPropertyWebkitColumnRule,
       
   736         CSSPropertyWebkitBorderRadius,
       
   737         CSSPropertyWebkitTransformOrigin
       
   738     };
       
   739 
       
   740     for (unsigned i = 0; i < sizeof(animatableShorthandProperties) / sizeof(animatableShorthandProperties[0]); ++i) {
       
   741         int propertyID = animatableShorthandProperties[i];
       
   742         CSSPropertyLonghand longhand = longhandForProperty(propertyID);
       
   743         if (longhand.length() > 0)
       
   744             addPropertyWrapper(propertyID, new ShorthandPropertyWrapper(propertyID, longhand));
       
   745     }
       
   746 
       
   747     // 'font' is not in the shorthand map.
       
   748     static const int animatableFontProperties[] = {
       
   749         CSSPropertyFontSize,
       
   750         CSSPropertyFontWeight
       
   751     };
       
   752 
       
   753     CSSPropertyLonghand fontLonghand(animatableFontProperties, sizeof(animatableFontProperties) / sizeof(animatableFontProperties[0]));
       
   754     addPropertyWrapper(CSSPropertyFont, new ShorthandPropertyWrapper(CSSPropertyFont, fontLonghand));
       
   755 }
       
   756 
       
   757 static PropertyWrapperBase* wrapperForProperty(int propertyID)
       
   758 {
       
   759     int propIndex = propertyID - firstCSSProperty;
       
   760     if (propIndex >= 0 && propIndex < numCSSProperties) {
       
   761         int wrapperIndex = gPropertyWrapperMap[propIndex];
       
   762         if (wrapperIndex >= 0)
       
   763             return (*gPropertyWrappers)[wrapperIndex];
       
   764     }
       
   765     return 0;
       
   766 }
       
   767 
       
   768 AnimationBase::AnimationBase(const Animation* transition, RenderObject* renderer, CompositeAnimation* compAnim)
       
   769     : m_animState(AnimationStateNew)
       
   770     , m_isAnimating(false)
       
   771     , m_startTime(0)
       
   772     , m_pauseTime(-1)
       
   773     , m_requestedStartTime(0)
       
   774     , m_object(renderer)
       
   775     , m_animation(const_cast<Animation*>(transition))
       
   776     , m_compAnim(compAnim)
       
   777     , m_isAccelerated(false)
       
   778     , m_transformFunctionListValid(false)
       
   779     , m_nextIterationDuration(-1)
       
   780     , m_next(0)
       
   781 {
       
   782     // Compute the total duration
       
   783     m_totalDuration = -1;
       
   784     if (m_animation->iterationCount() > 0)
       
   785         m_totalDuration = m_animation->duration() * m_animation->iterationCount();
       
   786 }
       
   787 
       
   788 AnimationBase::~AnimationBase()
       
   789 {
       
   790     m_compAnim->animationController()->removeFromStyleAvailableWaitList(this);
       
   791     m_compAnim->animationController()->removeFromStartTimeResponseWaitList(this);
       
   792 }
       
   793 
       
   794 bool AnimationBase::propertiesEqual(int prop, const RenderStyle* a, const RenderStyle* b)
       
   795 {
       
   796     ensurePropertyMap();
       
   797     if (prop == cAnimateAll) {
       
   798         size_t n = gPropertyWrappers->size();
       
   799         for (unsigned int i = 0; i < n; ++i) {
       
   800             PropertyWrapperBase* wrapper = (*gPropertyWrappers)[i];
       
   801             // No point comparing shorthand wrappers for 'all'.
       
   802             if (!wrapper->isShorthandWrapper() && !wrapper->equals(a, b))
       
   803                 return false;
       
   804         }
       
   805     } else {
       
   806         PropertyWrapperBase* wrapper = wrapperForProperty(prop);
       
   807         if (wrapper)
       
   808             return wrapper->equals(a, b);
       
   809     }
       
   810     return true;
       
   811 }
       
   812 
       
   813 int AnimationBase::getPropertyAtIndex(int i, bool& isShorthand)
       
   814 {
       
   815     ensurePropertyMap();
       
   816     if (i < 0 || i >= static_cast<int>(gPropertyWrappers->size()))
       
   817         return CSSPropertyInvalid;
       
   818 
       
   819     PropertyWrapperBase* wrapper = (*gPropertyWrappers)[i];
       
   820     isShorthand = wrapper->isShorthandWrapper();
       
   821     return wrapper->property();
       
   822 }
       
   823 
       
   824 int AnimationBase::getNumProperties()
       
   825 {
       
   826     ensurePropertyMap();
       
   827     return gPropertyWrappers->size();
       
   828 }
       
   829 
       
   830 // Returns true if we need to start animation timers
       
   831 bool AnimationBase::blendProperties(const AnimationBase* anim, int prop, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress)
       
   832 {
       
   833     ASSERT(prop != cAnimateAll);
       
   834 
       
   835     ensurePropertyMap();
       
   836     PropertyWrapperBase* wrapper = wrapperForProperty(prop);
       
   837     if (wrapper) {
       
   838         wrapper->blend(anim, dst, a, b, progress);
       
   839 #if USE(ACCELERATED_COMPOSITING)
       
   840         return !wrapper->animationIsAccelerated() || !anim->isAccelerated();
       
   841 #else
       
   842         return true;
       
   843 #endif
       
   844     }
       
   845 
       
   846     return false;
       
   847 }
       
   848 
       
   849 #if USE(ACCELERATED_COMPOSITING)
       
   850 bool AnimationBase::animationOfPropertyIsAccelerated(int prop)
       
   851 {
       
   852     ensurePropertyMap();
       
   853     PropertyWrapperBase* wrapper = wrapperForProperty(prop);
       
   854     return wrapper ? wrapper->animationIsAccelerated() : false;
       
   855 }
       
   856 #endif
       
   857 
       
   858 void AnimationBase::setNeedsStyleRecalc(Node* node)
       
   859 {
       
   860     ASSERT(!node || (node->document() && !node->document()->inPageCache()));
       
   861     if (node)
       
   862         node->setNeedsStyleRecalc(SyntheticStyleChange);
       
   863 }
       
   864 
       
   865 double AnimationBase::duration() const
       
   866 {
       
   867     return m_animation->duration();
       
   868 }
       
   869 
       
   870 bool AnimationBase::playStatePlaying() const
       
   871 {
       
   872     return m_animation->playState() == AnimPlayStatePlaying;
       
   873 }
       
   874 
       
   875 bool AnimationBase::animationsMatch(const Animation* anim) const
       
   876 {
       
   877     return m_animation->animationsMatch(anim);
       
   878 }
       
   879 
       
   880 void AnimationBase::updateStateMachine(AnimStateInput input, double param)
       
   881 {
       
   882     // If we get AnimationStateInputRestartAnimation then we force a new animation, regardless of state.
       
   883     if (input == AnimationStateInputMakeNew) {
       
   884         if (m_animState == AnimationStateStartWaitStyleAvailable)
       
   885             m_compAnim->animationController()->removeFromStyleAvailableWaitList(this);
       
   886         m_animState = AnimationStateNew;
       
   887         m_startTime = 0;
       
   888         m_pauseTime = -1;
       
   889         m_requestedStartTime = 0;
       
   890         m_nextIterationDuration = -1;
       
   891         endAnimation();
       
   892         return;
       
   893     }
       
   894 
       
   895     if (input == AnimationStateInputRestartAnimation) {
       
   896         if (m_animState == AnimationStateStartWaitStyleAvailable)
       
   897             m_compAnim->animationController()->removeFromStyleAvailableWaitList(this);
       
   898         m_animState = AnimationStateNew;
       
   899         m_startTime = 0;
       
   900         m_pauseTime = -1;
       
   901         m_requestedStartTime = 0;
       
   902         m_nextIterationDuration = -1;
       
   903         endAnimation();
       
   904 
       
   905         if (!paused())
       
   906             updateStateMachine(AnimationStateInputStartAnimation, -1);
       
   907         return;
       
   908     }
       
   909 
       
   910     if (input == AnimationStateInputEndAnimation) {
       
   911         if (m_animState == AnimationStateStartWaitStyleAvailable)
       
   912             m_compAnim->animationController()->removeFromStyleAvailableWaitList(this);
       
   913         m_animState = AnimationStateDone;
       
   914         endAnimation();
       
   915         return;
       
   916     }
       
   917 
       
   918     if (input == AnimationStateInputPauseOverride) {
       
   919         if (m_animState == AnimationStateStartWaitResponse) {
       
   920             // If we are in AnimationStateStartWaitResponse, the animation will get canceled before 
       
   921             // we get a response, so move to the next state.
       
   922             endAnimation();
       
   923             updateStateMachine(AnimationStateInputStartTimeSet, beginAnimationUpdateTime());
       
   924         }
       
   925         return;
       
   926     }
       
   927 
       
   928     if (input == AnimationStateInputResumeOverride) {
       
   929         if (m_animState == AnimationStateLooping || m_animState == AnimationStateEnding) {
       
   930             // Start the animation
       
   931             startAnimation(beginAnimationUpdateTime() - m_startTime);
       
   932         }
       
   933         return;
       
   934     }
       
   935 
       
   936     // Execute state machine
       
   937     switch (m_animState) {
       
   938         case AnimationStateNew:
       
   939             ASSERT(input == AnimationStateInputStartAnimation || input == AnimationStateInputPlayStateRunning || input == AnimationStateInputPlayStatePaused);
       
   940             if (input == AnimationStateInputStartAnimation || input == AnimationStateInputPlayStateRunning) {
       
   941                 m_requestedStartTime = beginAnimationUpdateTime();
       
   942                 m_animState = AnimationStateStartWaitTimer;
       
   943             }
       
   944             break;
       
   945         case AnimationStateStartWaitTimer:
       
   946             ASSERT(input == AnimationStateInputStartTimerFired || input == AnimationStateInputPlayStatePaused);
       
   947 
       
   948             if (input == AnimationStateInputStartTimerFired) {
       
   949                 ASSERT(param >= 0);
       
   950                 // Start timer has fired, tell the animation to start and wait for it to respond with start time
       
   951                 m_animState = AnimationStateStartWaitStyleAvailable;
       
   952                 m_compAnim->animationController()->addToStyleAvailableWaitList(this);
       
   953 
       
   954                 // Trigger a render so we can start the animation
       
   955                 if (m_object)
       
   956                     m_compAnim->animationController()->addNodeChangeToDispatch(m_object->node());
       
   957             } else {
       
   958                 ASSERT(!paused());
       
   959                 // We're waiting for the start timer to fire and we got a pause. Cancel the timer, pause and wait
       
   960                 m_pauseTime = beginAnimationUpdateTime();
       
   961                 m_animState = AnimationStatePausedWaitTimer;
       
   962             }
       
   963             break;
       
   964         case AnimationStateStartWaitStyleAvailable:
       
   965             ASSERT(input == AnimationStateInputStyleAvailable || input == AnimationStateInputPlayStatePaused);
       
   966 
       
   967             if (input == AnimationStateInputStyleAvailable) {
       
   968                 // Start timer has fired, tell the animation to start and wait for it to respond with start time
       
   969                 m_animState = AnimationStateStartWaitResponse;
       
   970 
       
   971                 overrideAnimations();
       
   972 
       
   973                 // Start the animation
       
   974                 if (overridden()) {
       
   975                     // We won't try to start accelerated animations if we are overridden and
       
   976                     // just move on to the next state.
       
   977                     m_animState = AnimationStateStartWaitResponse;
       
   978                     m_isAccelerated = false;
       
   979                     updateStateMachine(AnimationStateInputStartTimeSet, beginAnimationUpdateTime());
       
   980                 } else {
       
   981                     double timeOffset = 0;
       
   982                     // If the value for 'animation-delay' is negative then the animation appears to have started in the past.
       
   983                     if (m_animation->delay() < 0)
       
   984                         timeOffset = -m_animation->delay();
       
   985                     bool started = startAnimation(timeOffset);
       
   986 
       
   987                     m_compAnim->animationController()->addToStartTimeResponseWaitList(this, started);
       
   988                     m_isAccelerated = started;
       
   989                 }
       
   990             } else {
       
   991                 // We're waiting for the style to be available and we got a pause. Pause and wait
       
   992                 m_pauseTime = beginAnimationUpdateTime();
       
   993                 m_animState = AnimationStatePausedWaitStyleAvailable;
       
   994             }
       
   995             break;
       
   996         case AnimationStateStartWaitResponse:
       
   997             ASSERT(input == AnimationStateInputStartTimeSet || input == AnimationStateInputPlayStatePaused);
       
   998 
       
   999             if (input == AnimationStateInputStartTimeSet) {
       
  1000                 ASSERT(param >= 0);
       
  1001                 // We have a start time, set it, unless the startTime is already set
       
  1002                 if (m_startTime <= 0) {
       
  1003                     m_startTime = param;
       
  1004                     // If the value for 'animation-delay' is negative then the animation appears to have started in the past.
       
  1005                     if (m_animation->delay() < 0)
       
  1006                         m_startTime += m_animation->delay();
       
  1007                 }
       
  1008 
       
  1009                 // Now that we know the start time, fire the start event.
       
  1010                 onAnimationStart(0); // The elapsedTime is 0.
       
  1011 
       
  1012                 // Decide whether to go into looping or ending state
       
  1013                 goIntoEndingOrLoopingState();
       
  1014 
       
  1015                 // Dispatch updateStyleIfNeeded so we can start the animation
       
  1016                 if (m_object)
       
  1017                     m_compAnim->animationController()->addNodeChangeToDispatch(m_object->node());
       
  1018             } else {
       
  1019                 // We are pausing while waiting for a start response. Cancel the animation and wait. When 
       
  1020                 // we unpause, we will act as though the start timer just fired
       
  1021                 m_pauseTime = -1;
       
  1022                 pauseAnimation(beginAnimationUpdateTime() - m_startTime);
       
  1023                 m_animState = AnimationStatePausedWaitResponse;
       
  1024             }
       
  1025             break;
       
  1026         case AnimationStateLooping:
       
  1027             ASSERT(input == AnimationStateInputLoopTimerFired || input == AnimationStateInputPlayStatePaused);
       
  1028 
       
  1029             if (input == AnimationStateInputLoopTimerFired) {
       
  1030                 ASSERT(param >= 0);
       
  1031                 // Loop timer fired, loop again or end.
       
  1032                 onAnimationIteration(param);
       
  1033 
       
  1034                 // Decide whether to go into looping or ending state
       
  1035                 goIntoEndingOrLoopingState();
       
  1036             } else {
       
  1037                 // We are pausing while running. Cancel the animation and wait
       
  1038                 m_pauseTime = beginAnimationUpdateTime();
       
  1039                 pauseAnimation(beginAnimationUpdateTime() - m_startTime);
       
  1040                 m_animState = AnimationStatePausedRun;
       
  1041             }
       
  1042             break;
       
  1043         case AnimationStateEnding:
       
  1044             ASSERT(input == AnimationStateInputEndTimerFired || input == AnimationStateInputPlayStatePaused);
       
  1045 
       
  1046             if (input == AnimationStateInputEndTimerFired) {
       
  1047 
       
  1048                 ASSERT(param >= 0);
       
  1049                 // End timer fired, finish up
       
  1050                 onAnimationEnd(param);
       
  1051 
       
  1052                 m_animState = AnimationStateDone;
       
  1053                 
       
  1054                 if (m_object) {
       
  1055                     if (m_animation->fillsForwards())
       
  1056                         m_animState = AnimationStateFillingForwards;
       
  1057                     else
       
  1058                         resumeOverriddenAnimations();
       
  1059 
       
  1060                     // Fire off another style change so we can set the final value
       
  1061                     m_compAnim->animationController()->addNodeChangeToDispatch(m_object->node());
       
  1062                 }
       
  1063             } else {
       
  1064                 // We are pausing while running. Cancel the animation and wait
       
  1065                 m_pauseTime = beginAnimationUpdateTime();
       
  1066                 pauseAnimation(beginAnimationUpdateTime() - m_startTime);
       
  1067                 m_animState = AnimationStatePausedRun;
       
  1068             }
       
  1069             // |this| may be deleted here
       
  1070             break;
       
  1071         case AnimationStatePausedWaitTimer:
       
  1072             ASSERT(input == AnimationStateInputPlayStateRunning);
       
  1073             ASSERT(paused());
       
  1074             // Update the times
       
  1075             m_startTime += beginAnimationUpdateTime() - m_pauseTime;
       
  1076             m_pauseTime = -1;
       
  1077 
       
  1078             // we were waiting for the start timer to fire, go back and wait again
       
  1079             m_animState = AnimationStateNew;
       
  1080             updateStateMachine(AnimationStateInputStartAnimation, 0);
       
  1081             break;
       
  1082         case AnimationStatePausedWaitResponse:
       
  1083         case AnimationStatePausedWaitStyleAvailable:
       
  1084         case AnimationStatePausedRun:
       
  1085             // We treat these two cases the same. The only difference is that, when we are in
       
  1086             // AnimationStatePausedWaitResponse, we don't yet have a valid startTime, so we send 0 to startAnimation.
       
  1087             // When the AnimationStateInputStartTimeSet comes in and we were in AnimationStatePausedRun, we will notice
       
  1088             // that we have already set the startTime and will ignore it.
       
  1089             ASSERT(input == AnimationStateInputPlayStateRunning || input == AnimationStateInputStartTimeSet || input == AnimationStateInputStyleAvailable);
       
  1090             ASSERT(paused());
       
  1091             
       
  1092             if (input == AnimationStateInputPlayStateRunning) {
       
  1093                 // Update the times
       
  1094                 if (m_animState == AnimationStatePausedRun)
       
  1095                     m_startTime += beginAnimationUpdateTime() - m_pauseTime;
       
  1096                 else
       
  1097                     m_startTime = 0;
       
  1098                 m_pauseTime = -1;
       
  1099 
       
  1100                 if (m_animState == AnimationStatePausedWaitStyleAvailable)
       
  1101                     m_animState = AnimationStateStartWaitStyleAvailable;
       
  1102                 else {
       
  1103                     // We were either running or waiting for a begin time response from the animation.
       
  1104                     // Either way we need to restart the animation (possibly with an offset if we
       
  1105                     // had already been running) and wait for it to start.
       
  1106                     m_animState = AnimationStateStartWaitResponse;
       
  1107 
       
  1108                     // Start the animation
       
  1109                     if (overridden()) {
       
  1110                         // We won't try to start accelerated animations if we are overridden and
       
  1111                         // just move on to the next state.
       
  1112                         updateStateMachine(AnimationStateInputStartTimeSet, beginAnimationUpdateTime());
       
  1113                         m_isAccelerated = true;
       
  1114                     } else {
       
  1115                         bool started = startAnimation(beginAnimationUpdateTime() - m_startTime);
       
  1116                         m_compAnim->animationController()->addToStartTimeResponseWaitList(this, started);
       
  1117                         m_isAccelerated = !started;
       
  1118                     }
       
  1119                 }
       
  1120                 break;
       
  1121             }
       
  1122             
       
  1123             if (input == AnimationStateInputStartTimeSet) {
       
  1124                 ASSERT(m_animState == AnimationStatePausedWaitResponse);
       
  1125                 
       
  1126                 // We are paused but we got the callback that notifies us that an accelerated animation started.
       
  1127                 // We ignore the start time and just move into the paused-run state.
       
  1128                 m_animState = AnimationStatePausedRun;
       
  1129                 ASSERT(m_startTime == 0);
       
  1130                 m_startTime = param;
       
  1131                 m_pauseTime += m_startTime;
       
  1132                 break;
       
  1133             }
       
  1134             
       
  1135             ASSERT(m_animState == AnimationStatePausedWaitStyleAvailable);
       
  1136             // We are paused but we got the callback that notifies us that style has been updated.
       
  1137             // We move to the AnimationStatePausedWaitResponse state
       
  1138             m_animState = AnimationStatePausedWaitResponse;
       
  1139             overrideAnimations();
       
  1140             break;
       
  1141         case AnimationStateFillingForwards:
       
  1142         case AnimationStateDone:
       
  1143             // We're done. Stay in this state until we are deleted
       
  1144             break;
       
  1145     }
       
  1146 }
       
  1147     
       
  1148 void AnimationBase::fireAnimationEventsIfNeeded()
       
  1149 {
       
  1150     // If we are waiting for the delay time to expire and it has, go to the next state
       
  1151     if (m_animState != AnimationStateStartWaitTimer && m_animState != AnimationStateLooping && m_animState != AnimationStateEnding)
       
  1152         return;
       
  1153 
       
  1154     // We have to make sure to keep a ref to the this pointer, because it could get destroyed
       
  1155     // during an animation callback that might get called. Since the owner is a CompositeAnimation
       
  1156     // and it ref counts this object, we will keep a ref to that instead. That way the AnimationBase
       
  1157     // can still access the resources of its CompositeAnimation as needed.
       
  1158     RefPtr<AnimationBase> protector(this);
       
  1159     RefPtr<CompositeAnimation> compProtector(m_compAnim);
       
  1160     
       
  1161     // Check for start timeout
       
  1162     if (m_animState == AnimationStateStartWaitTimer) {
       
  1163         if (beginAnimationUpdateTime() - m_requestedStartTime >= m_animation->delay())
       
  1164             updateStateMachine(AnimationStateInputStartTimerFired, 0);
       
  1165         return;
       
  1166     }
       
  1167     
       
  1168     double elapsedDuration = beginAnimationUpdateTime() - m_startTime;
       
  1169     // FIXME: we need to ensure that elapsedDuration is never < 0. If it is, this suggests that
       
  1170     // we had a recalcStyle() outside of beginAnimationUpdate()/endAnimationUpdate().
       
  1171     // Also check in getTimeToNextEvent().
       
  1172     elapsedDuration = max(elapsedDuration, 0.0);
       
  1173     
       
  1174     // Check for end timeout
       
  1175     if (m_totalDuration >= 0 && elapsedDuration >= m_totalDuration) {
       
  1176         // Fire an end event
       
  1177         updateStateMachine(AnimationStateInputEndTimerFired, m_totalDuration);
       
  1178     } else {
       
  1179         // Check for iteration timeout
       
  1180         if (m_nextIterationDuration < 0) {
       
  1181             // Hasn't been set yet, set it
       
  1182             double durationLeft = m_animation->duration() - fmod(elapsedDuration, m_animation->duration());
       
  1183             m_nextIterationDuration = elapsedDuration + durationLeft;
       
  1184         }
       
  1185         
       
  1186         if (elapsedDuration >= m_nextIterationDuration) {
       
  1187             // Set to the next iteration
       
  1188             double previous = m_nextIterationDuration;
       
  1189             double durationLeft = m_animation->duration() - fmod(elapsedDuration, m_animation->duration());
       
  1190             m_nextIterationDuration = elapsedDuration + durationLeft;
       
  1191             
       
  1192             // Send the event
       
  1193             updateStateMachine(AnimationStateInputLoopTimerFired, previous);
       
  1194         }
       
  1195     }
       
  1196 }
       
  1197 
       
  1198 void AnimationBase::updatePlayState(bool run)
       
  1199 {
       
  1200     if (paused() == run || isNew())
       
  1201         updateStateMachine(run ? AnimationStateInputPlayStateRunning : AnimationStateInputPlayStatePaused, -1);
       
  1202 }
       
  1203 
       
  1204 double AnimationBase::timeToNextService()
       
  1205 {
       
  1206     // Returns the time at which next service is required. -1 means no service is required. 0 means 
       
  1207     // service is required now, and > 0 means service is required that many seconds in the future.
       
  1208     if (paused() || isNew() || m_animState == AnimationStateFillingForwards)
       
  1209         return -1;
       
  1210     
       
  1211     if (m_animState == AnimationStateStartWaitTimer) {
       
  1212         double timeFromNow = m_animation->delay() - (beginAnimationUpdateTime() - m_requestedStartTime);
       
  1213         return max(timeFromNow, 0.0);
       
  1214     }
       
  1215     
       
  1216     fireAnimationEventsIfNeeded();
       
  1217         
       
  1218     // In all other cases, we need service right away.
       
  1219     return 0;
       
  1220 }
       
  1221 
       
  1222 double AnimationBase::progress(double scale, double offset, const TimingFunction* tf) const
       
  1223 {
       
  1224     if (preActive())
       
  1225         return 0;
       
  1226 
       
  1227     double elapsedTime = getElapsedTime();
       
  1228 
       
  1229     double dur = m_animation->duration();
       
  1230     if (m_animation->iterationCount() > 0)
       
  1231         dur *= m_animation->iterationCount();
       
  1232 
       
  1233     if (postActive() || !m_animation->duration())
       
  1234         return 1.0;
       
  1235     if (m_animation->iterationCount() > 0 && elapsedTime >= dur)
       
  1236         return (m_animation->iterationCount() % 2) ? 1.0 : 0.0;
       
  1237 
       
  1238     // Compute the fractional time, taking into account direction.
       
  1239     // There is no need to worry about iterations, we assume that we would have
       
  1240     // short circuited above if we were done.
       
  1241     double fractionalTime = elapsedTime / m_animation->duration();
       
  1242     int integralTime = static_cast<int>(fractionalTime);
       
  1243     fractionalTime -= integralTime;
       
  1244 
       
  1245     if (m_animation->direction() && (integralTime & 1))
       
  1246         fractionalTime = 1 - fractionalTime;
       
  1247 
       
  1248     if (scale != 1 || offset)
       
  1249         fractionalTime = (fractionalTime - offset) * scale;
       
  1250         
       
  1251     if (!tf)
       
  1252         tf = &m_animation->timingFunction();
       
  1253 
       
  1254     if (tf->type() == LinearTimingFunction)
       
  1255         return fractionalTime;
       
  1256 
       
  1257     // Cubic bezier.
       
  1258     double result = solveCubicBezierFunction(tf->x1(),
       
  1259                                             tf->y1(),
       
  1260                                             tf->x2(),
       
  1261                                             tf->y2(),
       
  1262                                             fractionalTime, m_animation->duration());
       
  1263     return result;
       
  1264 }
       
  1265 
       
  1266 void AnimationBase::getTimeToNextEvent(double& time, bool& isLooping) const
       
  1267 {
       
  1268     // Decide when the end or loop event needs to fire
       
  1269     const double elapsedDuration = max(beginAnimationUpdateTime() - m_startTime, 0.0);
       
  1270     double durationLeft = 0;
       
  1271     double nextIterationTime = m_totalDuration;
       
  1272 
       
  1273     if (m_totalDuration < 0 || elapsedDuration < m_totalDuration) {
       
  1274         durationLeft = m_animation->duration() > 0 ? (m_animation->duration() - fmod(elapsedDuration, m_animation->duration())) : 0;
       
  1275         nextIterationTime = elapsedDuration + durationLeft;
       
  1276     }
       
  1277     
       
  1278     if (m_totalDuration < 0 || nextIterationTime < m_totalDuration) {
       
  1279         // We are not at the end yet
       
  1280         ASSERT(nextIterationTime > 0);
       
  1281         isLooping = true;
       
  1282     } else {
       
  1283         // We are at the end
       
  1284         isLooping = false;
       
  1285     }
       
  1286     
       
  1287     time = durationLeft;
       
  1288 }
       
  1289 
       
  1290 void AnimationBase::goIntoEndingOrLoopingState()
       
  1291 {
       
  1292     double t;
       
  1293     bool isLooping;
       
  1294     getTimeToNextEvent(t, isLooping);
       
  1295     m_animState = isLooping ? AnimationStateLooping : AnimationStateEnding;
       
  1296 }
       
  1297   
       
  1298 void AnimationBase::freezeAtTime(double t)
       
  1299 {
       
  1300     ASSERT(m_startTime);        // if m_startTime is zero, we haven't started yet, so we'll get a bad pause time.
       
  1301     m_pauseTime = m_startTime + t - m_animation->delay();
       
  1302 
       
  1303 #if USE(ACCELERATED_COMPOSITING)
       
  1304     if (m_object && m_object->hasLayer()) {
       
  1305         RenderLayer* layer = toRenderBoxModelObject(m_object)->layer();
       
  1306         if (layer->isComposited())
       
  1307             layer->backing()->suspendAnimations(m_pauseTime);
       
  1308     }
       
  1309 #endif
       
  1310 }
       
  1311 
       
  1312 double AnimationBase::beginAnimationUpdateTime() const
       
  1313 {
       
  1314     return m_compAnim->animationController()->beginAnimationUpdateTime();
       
  1315 }
       
  1316 
       
  1317 double AnimationBase::getElapsedTime() const
       
  1318 {
       
  1319     if (paused())    
       
  1320         return m_pauseTime - m_startTime;
       
  1321     if (m_startTime <= 0)
       
  1322         return 0;
       
  1323     if (postActive())
       
  1324         return 1;
       
  1325     return beginAnimationUpdateTime() - m_startTime;
       
  1326 }
       
  1327     
       
  1328 } // namespace WebCore