2011-04-11 Simon Fraser <simon.fraser@apple.com>
[WebKit-https.git] / Source / WebCore / page / animation / AnimationBase.cpp
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