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