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