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