Fix the ACCELERATED_COMPOSITING code to not expose RenderLayer outside rendering
[WebKit.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 "CSSCrossfadeValue.h"
34 #include "CSSImageGeneratorValue.h"
35 #include "CSSImageValue.h"
36 #include "CSSPrimitiveValue.h"
37 #include "CompositeAnimation.h"
38 #include "Document.h"
39 #include "EventNames.h"
40 #include "FloatConversion.h"
41 #include "IdentityTransformOperation.h"
42 #include "MatrixTransformOperation.h"
43 #include "Matrix3DTransformOperation.h"
44 #include "RenderBox.h"
45 #include "RenderStyle.h"
46 #include "StyleCachedImage.h"
47 #include "StyleGeneratedImage.h"
48 #include "StylePropertyShorthand.h"
49 #include "UnitBezier.h"
50 #include <algorithm>
51 #include <wtf/CurrentTime.h>
52
53 using namespace std;
54
55 namespace WebCore {
56
57 // The epsilon value we pass to UnitBezier::solve given that the animation is going to run over |dur| seconds. The longer the
58 // animation, the more precision we need in the timing function result to avoid ugly discontinuities.
59 static inline double solveEpsilon(double duration)
60 {
61     return 1.0 / (200.0 * duration);
62 }
63
64 static inline double solveCubicBezierFunction(double p1x, double p1y, double p2x, double p2y, double t, double duration)
65 {
66     // Convert from input time to parametric value in curve, then from
67     // that to output time.
68     UnitBezier bezier(p1x, p1y, p2x, p2y);
69     return bezier.solve(t, solveEpsilon(duration));
70 }
71
72 static inline double solveStepsFunction(int numSteps, bool stepAtStart, double t)
73 {
74     if (stepAtStart)
75         return min(1.0, (floor(numSteps * t) + 1) / numSteps);
76     return floor(numSteps * t) / numSteps;
77 }
78
79 static inline int blendFunc(const AnimationBase*, int from, int to, double progress)
80 {  
81     return blend(from, to, progress);
82 }
83
84 static inline unsigned blendFunc(const AnimationBase*, unsigned from, unsigned to, double progress)
85 {
86     return blend(from, to, progress);
87 }
88
89 static inline double blendFunc(const AnimationBase*, double from, double to, double progress)
90 {  
91     return blend(from, to, progress);
92 }
93
94 static inline float blendFunc(const AnimationBase*, float from, float to, double progress)
95 {  
96     return narrowPrecisionToFloat(from + (to - from) * progress);
97 }
98
99 static inline Color blendFunc(const AnimationBase*, const Color& from, const Color& to, double progress)
100 {
101     return blend(from, to, progress);
102 }
103
104 static inline Length blendFunc(const AnimationBase*, const Length& from, const Length& to, double progress)
105 {  
106     return to.blend(from, narrowPrecisionToFloat(progress));
107 }
108
109 static inline LengthSize blendFunc(const AnimationBase* anim, const LengthSize& from, const LengthSize& to, double progress)
110 {  
111     return LengthSize(blendFunc(anim, from.width(), to.width(), progress),
112                       blendFunc(anim, from.height(), to.height(), progress));
113 }
114
115 static inline IntSize blendFunc(const AnimationBase* anim, const IntSize& from, const IntSize& to, double progress)
116 {  
117     return IntSize(blendFunc(anim, from.width(), to.width(), progress),
118                    blendFunc(anim, from.height(), to.height(), progress));
119 }
120
121 static inline ShadowStyle blendFunc(const AnimationBase* anim, ShadowStyle from, ShadowStyle to, double progress)
122 {
123     if (from == to)
124         return to;
125
126     double fromVal = from == Normal ? 1 : 0;
127     double toVal = to == Normal ? 1 : 0;
128     double result = blendFunc(anim, fromVal, toVal, progress);
129     return result > 0 ? Normal : Inset;
130 }
131
132 static inline PassOwnPtr<ShadowData> blendFunc(const AnimationBase* anim, const ShadowData* from, const ShadowData* to, double progress)
133 {  
134     ASSERT(from && to);
135     if (from->style() != to->style())
136         return adoptPtr(new ShadowData(*to));
137
138     return adoptPtr(new ShadowData(blend(from->x(), to->x(), progress),
139                                    blend(from->y(), to->y(), progress), 
140                                    blend(from->blur(), to->blur(), progress),
141                                    blend(from->spread(), to->spread(), progress),
142                                    blendFunc(anim, from->style(), to->style(), progress),
143                                    from->isWebkitBoxShadow(),
144                                    blend(from->color(), to->color(), progress)));
145 }
146
147 static inline TransformOperations blendFunc(const AnimationBase* anim, const TransformOperations& from, const TransformOperations& to, double progress)
148 {    
149     TransformOperations result;
150
151     // If we have a transform function list, use that to do a per-function animation. Otherwise do a Matrix animation
152     if (anim->isTransformFunctionListValid()) {
153         unsigned fromSize = from.operations().size();
154         unsigned toSize = to.operations().size();
155         unsigned size = max(fromSize, toSize);
156         for (unsigned i = 0; i < size; i++) {
157             RefPtr<TransformOperation> fromOp = (i < fromSize) ? from.operations()[i].get() : 0;
158             RefPtr<TransformOperation> toOp = (i < toSize) ? to.operations()[i].get() : 0;
159             RefPtr<TransformOperation> blendedOp = toOp ? toOp->blend(fromOp.get(), progress) : (fromOp ? fromOp->blend(0, progress, true) : PassRefPtr<TransformOperation>(0));
160             if (blendedOp)
161                 result.operations().append(blendedOp);
162             else {
163                 RefPtr<TransformOperation> identityOp = IdentityTransformOperation::create();
164                 if (progress > 0.5)
165                     result.operations().append(toOp ? toOp : identityOp);
166                 else
167                     result.operations().append(fromOp ? fromOp : identityOp);
168             }
169         }
170     } else {
171         // Convert the TransformOperations into matrices
172         LayoutSize size = anim->renderer()->isBox() ? toRenderBox(anim->renderer())->borderBoxRect().size() : LayoutSize();
173         TransformationMatrix fromT;
174         TransformationMatrix toT;
175         from.apply(size, fromT);
176         to.apply(size, toT);
177         
178         toT.blend(fromT, progress);
179         
180         // Append the result
181         result.operations().append(Matrix3DTransformOperation::create(toT));
182     }
183     return result;
184 }
185
186 #if ENABLE(CSS_FILTERS)
187 static inline FilterOperations blendFunc(const AnimationBase* anim, const FilterOperations& from, const FilterOperations& to, double progress)
188 {    
189     FilterOperations result;
190
191     // If we have a filter function list, use that to do a per-function animation.
192     if (anim->filterFunctionListsMatch()) {
193         size_t fromSize = from.operations().size();
194         size_t toSize = to.operations().size();
195         size_t size = max(fromSize, toSize);
196         for (size_t i = 0; i < size; i++) {
197             RefPtr<FilterOperation> fromOp = (i < fromSize) ? from.operations()[i].get() : 0;
198             RefPtr<FilterOperation> toOp = (i < toSize) ? to.operations()[i].get() : 0;
199             RefPtr<FilterOperation> blendedOp = toOp ? toOp->blend(fromOp.get(), progress) : (fromOp ? fromOp->blend(0, progress, true) : PassRefPtr<FilterOperation>(0));
200             if (blendedOp)
201                 result.operations().append(blendedOp);
202             else {
203                 RefPtr<FilterOperation> identityOp = PassthroughFilterOperation::create();
204                 if (progress > 0.5)
205                     result.operations().append(toOp ? toOp : identityOp);
206                 else
207                     result.operations().append(fromOp ? fromOp : identityOp);
208             }
209         }
210     } else {
211         // If the filter function lists don't match, we could try to cross-fade, but don't yet have a way to represent that in CSS.
212         // For now we'll just fail to animate.
213         result = to;
214     }
215
216     return result;
217 }
218 #endif // ENABLE(CSS_FILTERS)
219
220 static inline EVisibility blendFunc(const AnimationBase* anim, EVisibility from, EVisibility to, double progress)
221 {
222     // Any non-zero result means we consider the object to be visible.  Only at 0 do we consider the object to be
223     // invisible.   The invisible value we use (HIDDEN vs. COLLAPSE) depends on the specified from/to values.
224     double fromVal = from == VISIBLE ? 1. : 0.;
225     double toVal = to == VISIBLE ? 1. : 0.;
226     if (fromVal == toVal)
227         return to;
228     double result = blendFunc(anim, fromVal, toVal, progress);
229     return result > 0. ? VISIBLE : (to != VISIBLE ? to : from);
230 }
231
232 static inline LengthBox blendFunc(const AnimationBase* anim, const LengthBox& from, const LengthBox& to, double progress)
233 {
234     // Length types have to match to animate
235     if (from.top().type() != to.top().type()
236         || from.right().type() != to.right().type()
237         || from.bottom().type() != to.bottom().type()
238         || from.left().type() != to.left().type())
239         return to;
240     
241     LengthBox result(blendFunc(anim, from.top(), to.top(), progress),
242                      blendFunc(anim, from.right(), to.right(), progress),
243                      blendFunc(anim, from.bottom(), to.bottom(), progress),
244                      blendFunc(anim, from.left(), to.left(), progress));
245     return result;
246 }
247
248 #if ENABLE(SVG)
249 static inline SVGLength blendFunc(const AnimationBase*, const SVGLength& from, const SVGLength& to, double progress)
250 {  
251     return to.blend(from, narrowPrecisionToFloat(progress));
252 }
253 #endif
254
255 static inline PassRefPtr<StyleImage> crossfadeBlend(const AnimationBase*, StyleCachedImage* fromStyleImage, StyleCachedImage* toStyleImage, double progress)
256 {
257     // If progress is at one of the extremes, we want getComputedStyle to show the image,
258     // not a completed cross-fade, so we hand back one of the existing images.
259     if (!progress)
260         return fromStyleImage;
261     if (progress == 1)
262         return toStyleImage;
263
264     CachedImage* fromCachedImage = static_cast<CachedImage*>(fromStyleImage->data());
265     CachedImage* toCachedImage = static_cast<CachedImage*>(toStyleImage->data());
266
267     RefPtr<CSSImageValue> fromImageValue = CSSImageValue::create(fromCachedImage->url(), fromStyleImage);
268     RefPtr<CSSImageValue> toImageValue = CSSImageValue::create(toCachedImage->url(), toStyleImage);
269     RefPtr<CSSCrossfadeValue> crossfadeValue = CSSCrossfadeValue::create(fromImageValue, toImageValue);
270
271     crossfadeValue->setPercentage(CSSPrimitiveValue::create(progress, CSSPrimitiveValue::CSS_NUMBER));
272
273     return StyleGeneratedImage::create(crossfadeValue.get());
274 }
275
276 static inline PassRefPtr<StyleImage> blendFunc(const AnimationBase* anim, StyleImage* from, StyleImage* to, double progress)
277 {
278     if (!from || !to)
279         return to;
280
281     if (from->isCachedImage() && to->isCachedImage())
282         return crossfadeBlend(anim, static_cast<StyleCachedImage*>(from), static_cast<StyleCachedImage*>(to), progress);
283
284     // FIXME: Support transitioning generated images as well. (gradients, etc.)
285
286     return to;
287 }
288
289 static inline NinePieceImage blendFunc(const AnimationBase* anim, const NinePieceImage& from, const NinePieceImage& to, double progress)
290 {
291     if (!from.hasImage() || !to.hasImage())
292         return to;
293
294     // FIXME (74112): Support transitioning between NinePieceImages that differ by more than image content.
295
296     if (from.imageSlices() != to.imageSlices() || from.borderSlices() != to.borderSlices() || from.outset() != to.outset() || from.fill() != to.fill() || from.horizontalRule() != to.horizontalRule() || from.verticalRule() != to.verticalRule())
297         return to;
298
299     if (from.image()->imageSize(anim->renderer(), 1.0) != to.image()->imageSize(anim->renderer(), 1.0))
300         return to;
301
302     RefPtr<StyleImage> newContentImage = blendFunc(anim, from.image(), to.image(), progress);
303
304     return NinePieceImage(newContentImage, from.imageSlices(), from.fill(), from.borderSlices(), from.outset(), from.horizontalRule(), from.verticalRule());
305 }
306
307 class PropertyWrapperBase;
308
309 static void addShorthandProperties();
310 static PropertyWrapperBase* wrapperForProperty(CSSPropertyID);
311
312 class PropertyWrapperBase {
313     WTF_MAKE_NONCOPYABLE(PropertyWrapperBase); WTF_MAKE_FAST_ALLOCATED;
314 public:
315     PropertyWrapperBase(CSSPropertyID prop)
316         : m_prop(prop)
317     {
318     }
319
320     virtual ~PropertyWrapperBase() { }
321     
322     virtual bool isShorthandWrapper() const { return false; }
323     virtual bool equals(const RenderStyle* a, const RenderStyle* b) const = 0;
324     virtual void blend(const AnimationBase* anim, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress) const = 0;
325
326     CSSPropertyID property() const { return m_prop; }
327
328 #if USE(ACCELERATED_COMPOSITING)
329     virtual bool animationIsAccelerated() const { return false; }
330 #endif
331
332 private:
333     CSSPropertyID m_prop;
334 };
335
336 template <typename T>
337 class PropertyWrapperGetter : public PropertyWrapperBase {
338 public:
339     PropertyWrapperGetter(CSSPropertyID prop, T (RenderStyle::*getter)() const)
340         : PropertyWrapperBase(prop)
341         , m_getter(getter)
342     {
343     }
344
345     virtual bool equals(const RenderStyle* a, const RenderStyle* b) const
346     {
347         // If the style pointers are the same, don't bother doing the test.
348         // If either is null, return false. If both are null, return true.
349         if ((!a && !b) || a == b)
350             return true;
351         if (!a || !b)
352             return false;
353         return (a->*m_getter)() == (b->*m_getter)();
354     }
355
356 protected:
357     T (RenderStyle::*m_getter)() const;
358 };
359
360 template <typename T>
361 class PropertyWrapper : public PropertyWrapperGetter<T> {
362 public:
363     PropertyWrapper(CSSPropertyID prop, T (RenderStyle::*getter)() const, void (RenderStyle::*setter)(T))
364         : PropertyWrapperGetter<T>(prop, getter)
365         , m_setter(setter)
366     {
367     }
368     
369     virtual void blend(const AnimationBase* anim, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress) const
370     {
371         (dst->*m_setter)(blendFunc(anim, (a->*PropertyWrapperGetter<T>::m_getter)(), (b->*PropertyWrapperGetter<T>::m_getter)(), progress));
372     }
373
374 protected:
375     void (RenderStyle::*m_setter)(T);
376 };
377
378 template <typename T>
379 class RefCountedPropertyWrapper : public PropertyWrapperGetter<T*> {
380 public:
381     RefCountedPropertyWrapper(CSSPropertyID prop, T* (RenderStyle::*getter)() const, void (RenderStyle::*setter)(PassRefPtr<T>))
382         : PropertyWrapperGetter<T*>(prop, getter)
383         , m_setter(setter)
384     {
385     }
386
387     virtual void blend(const AnimationBase* anim, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress) const
388     {
389         (dst->*m_setter)(blendFunc(anim, (a->*PropertyWrapperGetter<T*>::m_getter)(), (b->*PropertyWrapperGetter<T*>::m_getter)(), progress));
390     }
391
392 protected:
393     void (RenderStyle::*m_setter)(PassRefPtr<T>);
394 };
395
396 class StyleImagePropertyWrapper : public RefCountedPropertyWrapper<StyleImage> {
397 public:
398     StyleImagePropertyWrapper(CSSPropertyID prop, StyleImage* (RenderStyle::*getter)() const, void (RenderStyle::*setter)(PassRefPtr<StyleImage>))
399         : RefCountedPropertyWrapper<StyleImage>(prop, getter, setter)
400     {
401     }
402
403     virtual bool equals(const RenderStyle* a, const RenderStyle* b) const
404     {
405        // If the style pointers are the same, don't bother doing the test.
406        // If either is null, return false. If both are null, return true.
407        if (a == b)
408            return true;
409        if (!a || !b)
410             return false;
411             
412         StyleImage* imageA = (a->*m_getter)();
413         StyleImage* imageB = (b->*m_getter)();
414         return StyleImage::imagesEquivalent(imageA, imageB);
415     }
416 };
417
418 class PropertyWrapperColor : public PropertyWrapperGetter<Color> {
419 public:
420     PropertyWrapperColor(CSSPropertyID prop, Color (RenderStyle::*getter)() const, void (RenderStyle::*setter)(const Color&))
421         : PropertyWrapperGetter<Color>(prop, getter)
422         , m_setter(setter)
423     {
424     }
425
426     virtual void blend(const AnimationBase* anim, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress) const
427     {
428         (dst->*m_setter)(blendFunc(anim, (a->*PropertyWrapperGetter<Color>::m_getter)(), (b->*PropertyWrapperGetter<Color>::m_getter)(), progress));
429     }
430
431 protected:
432     void (RenderStyle::*m_setter)(const Color&);
433 };
434
435 #if USE(ACCELERATED_COMPOSITING)
436 class PropertyWrapperAcceleratedOpacity : public PropertyWrapper<float> {
437 public:
438     PropertyWrapperAcceleratedOpacity()
439         : PropertyWrapper<float>(CSSPropertyOpacity, &RenderStyle::opacity, &RenderStyle::setOpacity)
440     {
441     }
442
443     virtual bool animationIsAccelerated() const { return true; }
444
445     virtual void blend(const AnimationBase* anim, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress) const
446     {
447         float fromOpacity = a->opacity();
448         
449         // This makes sure we put the object being animated into a RenderLayer during the animation
450         dst->setOpacity(blendFunc(anim, (fromOpacity == 1) ? 0.999999f : fromOpacity, b->opacity(), progress));
451     }
452 };
453
454 class PropertyWrapperAcceleratedTransform : public PropertyWrapper<const TransformOperations&> {
455 public:
456     PropertyWrapperAcceleratedTransform()
457         : PropertyWrapper<const TransformOperations&>(CSSPropertyWebkitTransform, &RenderStyle::transform, &RenderStyle::setTransform)
458     {
459     }
460     
461     virtual bool animationIsAccelerated() const { return true; }
462
463     virtual void blend(const AnimationBase* anim, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress) const
464     {
465         dst->setTransform(blendFunc(anim, a->transform(), b->transform(), progress));
466     }
467 };
468
469 #if ENABLE(CSS_FILTERS)
470 class PropertyWrapperAcceleratedFilter : public PropertyWrapper<const FilterOperations&> {
471 public:
472     PropertyWrapperAcceleratedFilter()
473         : PropertyWrapper<const FilterOperations&>(CSSPropertyWebkitFilter, &RenderStyle::filter, &RenderStyle::setFilter)
474     {
475     }
476     
477     virtual bool animationIsAccelerated() const { return true; }
478
479     virtual void blend(const AnimationBase* anim, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress) const
480     {
481         dst->setFilter(blendFunc(anim, a->filter(), b->filter(), progress));
482     }
483 };
484 #endif
485 #endif // USE(ACCELERATED_COMPOSITING)
486
487 static inline size_t shadowListLength(const ShadowData* shadow)
488 {
489     size_t count;
490     for (count = 0; shadow; shadow = shadow->next())
491         ++count;
492     return count;
493 }
494
495 static inline const ShadowData* shadowForBlending(const ShadowData* srcShadow, const ShadowData* otherShadow)
496 {
497     DEFINE_STATIC_LOCAL(ShadowData, defaultShadowData, (0, 0, 0, 0, Normal, false, Color::transparent));
498     DEFINE_STATIC_LOCAL(ShadowData, defaultInsetShadowData, (0, 0, 0, 0, Inset, false, Color::transparent));
499
500     DEFINE_STATIC_LOCAL(ShadowData, defaultWebKitBoxShadowData, (0, 0, 0, 0, Normal, true, Color::transparent));
501     DEFINE_STATIC_LOCAL(ShadowData, defaultInsetWebKitBoxShadowData, (0, 0, 0, 0, Inset, true, Color::transparent));
502
503     if (srcShadow)
504         return srcShadow;
505
506     if (otherShadow->style() == Inset)
507         return otherShadow->isWebkitBoxShadow() ? &defaultInsetWebKitBoxShadowData : &defaultInsetShadowData;
508     
509     return otherShadow->isWebkitBoxShadow() ? &defaultWebKitBoxShadowData : &defaultShadowData;
510 }
511
512 class PropertyWrapperShadow : public PropertyWrapperBase {
513 public:
514     PropertyWrapperShadow(CSSPropertyID prop, const ShadowData* (RenderStyle::*getter)() const, void (RenderStyle::*setter)(PassOwnPtr<ShadowData>, bool))
515         : PropertyWrapperBase(prop)
516         , m_getter(getter)
517         , m_setter(setter)
518     {
519     }
520
521     virtual bool equals(const RenderStyle* a, const RenderStyle* b) const
522     {
523         const ShadowData* shadowA = (a->*m_getter)();
524         const ShadowData* shadowB = (b->*m_getter)();
525         
526         while (true) {
527             if (!shadowA && !shadowB)   // end of both lists
528                 return true;
529
530             if (!shadowA || !shadowB)   // end of just one of the lists
531                 return false;
532
533             if (*shadowA != *shadowB)
534                 return false;
535         
536             shadowA = shadowA->next();
537             shadowB = shadowB->next();
538         }
539
540         return true;
541     }
542
543     virtual void blend(const AnimationBase* anim, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress) const
544     {
545         const ShadowData* shadowA = (a->*m_getter)();
546         const ShadowData* shadowB = (b->*m_getter)();
547
548         int fromLength = shadowListLength(shadowA);
549         int toLength = shadowListLength(shadowB);
550
551         if (fromLength == toLength || (fromLength <= 1 && toLength <= 1)) {
552             (dst->*m_setter)(blendSimpleOrMatchedShadowLists(anim, progress, shadowA, shadowB), false);
553             return;
554         }
555
556         (dst->*m_setter)(blendMismatchedShadowLists(anim, progress, shadowA, shadowB, fromLength, toLength), false);
557     }
558
559 private:
560     PassOwnPtr<ShadowData*> blendSimpleOrMatchedShadowLists(const AnimationBase* anim, double progress, const ShadowData* shadowA, const ShadowData* shadowB) const
561     {
562         OwnPtr<ShadowData> newShadowData;
563         ShadowData* lastShadow = 0;
564         
565         while (shadowA || shadowB) {
566             const ShadowData* srcShadow = shadowForBlending(shadowA, shadowB);
567             const ShadowData* dstShadow = shadowForBlending(shadowB, shadowA);
568
569             OwnPtr<ShadowData> blendedShadow = blendFunc(anim, srcShadow, dstShadow, progress);
570             ShadowData* blendedShadowPtr = blendedShadow.get();
571
572             if (!lastShadow)
573                 newShadowData = blendedShadow.release();
574             else
575                 lastShadow->setNext(blendedShadow.release());
576             
577             lastShadow = blendedShadowPtr;
578
579             shadowA = shadowA ? shadowA->next() : 0;
580             shadowB = shadowB ? shadowB->next() : 0;
581         }
582         
583         return newShadowData.release();
584     }
585
586     PassOwnPtr<ShadowData*> blendMismatchedShadowLists(const AnimationBase* anim, double progress, const ShadowData* shadowA, const ShadowData* shadowB, int fromLength, int toLength) const
587     {
588         // The shadows in ShadowData are stored in reverse order, so when animating mismatched lists,
589         // reverse them and match from the end.
590         Vector<const ShadowData*, 4> fromShadows(fromLength);
591         for (int i = fromLength - 1; i >= 0; --i) {
592             fromShadows[i] = shadowA;
593             shadowA = shadowA->next();
594         }
595
596         Vector<const ShadowData*, 4> toShadows(toLength);
597         for (int i = toLength - 1; i >= 0; --i) {
598             toShadows[i] = shadowB;
599             shadowB = shadowB->next();
600         }
601
602         OwnPtr<ShadowData> newShadowData;
603         
604         int maxLength = max(fromLength, toLength);
605         for (int i = 0; i < maxLength; ++i) {
606             const ShadowData* fromShadow = i < fromLength ? fromShadows[i] : 0;
607             const ShadowData* toShadow = i < toLength ? toShadows[i] : 0;
608             
609             const ShadowData* srcShadow = shadowForBlending(fromShadow, toShadow);
610             const ShadowData* dstShadow = shadowForBlending(toShadow, fromShadow);
611
612             OwnPtr<ShadowData> blendedShadow = blendFunc(anim, srcShadow, dstShadow, progress);
613             // Insert at the start of the list to preserve the order.
614             blendedShadow->setNext(newShadowData.release());
615             newShadowData = blendedShadow.release();
616         }
617
618         return newShadowData.release();
619     }
620
621     const ShadowData* (RenderStyle::*m_getter)() const;
622     void (RenderStyle::*m_setter)(PassOwnPtr<ShadowData>, bool);
623 };
624
625 class PropertyWrapperMaybeInvalidColor : public PropertyWrapperBase {
626 public:
627     PropertyWrapperMaybeInvalidColor(CSSPropertyID prop, Color (RenderStyle::*getter)() const, void (RenderStyle::*setter)(const Color&))
628         : PropertyWrapperBase(prop)
629         , m_getter(getter)
630         , m_setter(setter)
631     {
632     }
633
634     virtual bool equals(const RenderStyle* a, const RenderStyle* b) const
635     {
636         Color fromColor = (a->*m_getter)();
637         Color toColor = (b->*m_getter)();
638
639         if (!fromColor.isValid() && !toColor.isValid())
640             return true;
641
642         if (!fromColor.isValid())
643             fromColor = a->color();
644         if (!toColor.isValid())
645             toColor = b->color();
646
647         return fromColor == toColor;
648     }
649
650     virtual void blend(const AnimationBase* anim, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress) const
651     {
652         Color fromColor = (a->*m_getter)();
653         Color toColor = (b->*m_getter)();
654
655         if (!fromColor.isValid() && !toColor.isValid())
656             return;
657
658         if (!fromColor.isValid())
659             fromColor = a->color();
660         if (!toColor.isValid())
661             toColor = b->color();
662         (dst->*m_setter)(blendFunc(anim, fromColor, toColor, progress));
663     }
664
665 private:
666     Color (RenderStyle::*m_getter)() const;
667     void (RenderStyle::*m_setter)(const Color&);
668 };
669
670 enum MaybeInvalidColorTag { MaybeInvalidColor };
671 class PropertyWrapperVisitedAffectedColor : public PropertyWrapperBase {
672 public:
673     PropertyWrapperVisitedAffectedColor(CSSPropertyID prop, Color (RenderStyle::*getter)() const, void (RenderStyle::*setter)(const Color&),
674                                         Color (RenderStyle::*visitedGetter)() const, void (RenderStyle::*visitedSetter)(const Color&))
675         : PropertyWrapperBase(prop)
676         , m_wrapper(adoptPtr(new PropertyWrapperColor(prop, getter, setter)))
677         , m_visitedWrapper(adoptPtr(new PropertyWrapperColor(prop, visitedGetter, visitedSetter)))
678     {
679     }
680     PropertyWrapperVisitedAffectedColor(CSSPropertyID prop, MaybeInvalidColorTag, Color (RenderStyle::*getter)() const, void (RenderStyle::*setter)(const Color&),
681                                         Color (RenderStyle::*visitedGetter)() const, void (RenderStyle::*visitedSetter)(const Color&))
682         : PropertyWrapperBase(prop)
683         , m_wrapper(adoptPtr(new PropertyWrapperMaybeInvalidColor(prop, getter, setter)))
684         , m_visitedWrapper(adoptPtr(new PropertyWrapperMaybeInvalidColor(prop, visitedGetter, visitedSetter)))
685     {
686     }
687     virtual bool equals(const RenderStyle* a, const RenderStyle* b) const
688     {
689         return m_wrapper->equals(a, b) && m_visitedWrapper->equals(a, b);
690     }
691     virtual void blend(const AnimationBase* anim, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress) const
692     {
693         m_wrapper->blend(anim, dst, a, b, progress);
694         m_visitedWrapper->blend(anim, dst, a, b, progress);
695     }
696     
697 private:
698     OwnPtr<PropertyWrapperBase> m_wrapper;
699     OwnPtr<PropertyWrapperBase> m_visitedWrapper;
700 };
701
702 // Wrapper base class for an animatable property in a FillLayer
703 class FillLayerPropertyWrapperBase {
704 public:
705     FillLayerPropertyWrapperBase()
706     {
707     }
708
709     virtual ~FillLayerPropertyWrapperBase() { }
710     
711     virtual bool equals(const FillLayer* a, const FillLayer* b) const = 0;
712     virtual void blend(const AnimationBase* anim, FillLayer* dst, const FillLayer* a, const FillLayer* b, double progress) const = 0;
713 };
714
715 template <typename T>
716 class FillLayerPropertyWrapperGetter : public FillLayerPropertyWrapperBase {
717     WTF_MAKE_NONCOPYABLE(FillLayerPropertyWrapperGetter);
718 public:
719     FillLayerPropertyWrapperGetter(T (FillLayer::*getter)() const)
720         : m_getter(getter)
721     {
722     }
723
724     virtual bool equals(const FillLayer* a, const FillLayer* b) const
725     {
726        // If the style pointers are the same, don't bother doing the test.
727        // If either is null, return false. If both are null, return true.
728        if ((!a && !b) || a == b)
729            return true;
730        if (!a || !b)
731             return false;
732         return (a->*m_getter)() == (b->*m_getter)();
733     }
734
735 protected:
736     T (FillLayer::*m_getter)() const;
737 };
738
739 template <typename T>
740 class FillLayerPropertyWrapper : public FillLayerPropertyWrapperGetter<T> {
741 public:
742     FillLayerPropertyWrapper(T (FillLayer::*getter)() const, void (FillLayer::*setter)(T))
743         : FillLayerPropertyWrapperGetter<T>(getter)
744         , m_setter(setter)
745     {
746     }
747     
748     virtual void blend(const AnimationBase* anim, FillLayer* dst, const FillLayer* a, const FillLayer* b, double progress) const
749     {
750         (dst->*m_setter)(blendFunc(anim, (a->*FillLayerPropertyWrapperGetter<T>::m_getter)(), (b->*FillLayerPropertyWrapperGetter<T>::m_getter)(), progress));
751     }
752
753 protected:
754     void (FillLayer::*m_setter)(T);
755 };
756
757 template <typename T>
758 class FillLayerRefCountedPropertyWrapper : public FillLayerPropertyWrapperGetter<T*> {
759 public:
760     FillLayerRefCountedPropertyWrapper(T* (FillLayer::*getter)() const, void (FillLayer::*setter)(PassRefPtr<T>))
761         : FillLayerPropertyWrapperGetter<T*>(getter)
762         , m_setter(setter)
763     {
764     }
765
766     virtual void blend(const AnimationBase* anim, FillLayer* dst, const FillLayer* a, const FillLayer* b, double progress) const
767     {
768         (dst->*m_setter)(blendFunc(anim, (a->*FillLayerPropertyWrapperGetter<T*>::m_getter)(), (b->*FillLayerPropertyWrapperGetter<T*>::m_getter)(), progress));
769     }
770
771 protected:
772     void (FillLayer::*m_setter)(PassRefPtr<T>);
773 };
774
775 class FillLayerStyleImagePropertyWrapper : public FillLayerRefCountedPropertyWrapper<StyleImage> {
776 public:
777     FillLayerStyleImagePropertyWrapper(StyleImage* (FillLayer::*getter)() const, void (FillLayer::*setter)(PassRefPtr<StyleImage>))
778         : FillLayerRefCountedPropertyWrapper<StyleImage>(getter, setter)
779     {
780     }
781
782     virtual bool equals(const FillLayer* a, const FillLayer* b) const
783     {
784        // If the style pointers are the same, don't bother doing the test.
785        // If either is null, return false. If both are null, return true.
786        if (a == b)
787            return true;
788        if (!a || !b)
789             return false;
790
791         StyleImage* imageA = (a->*m_getter)();
792         StyleImage* imageB = (b->*m_getter)();
793         return StyleImage::imagesEquivalent(imageA, imageB);
794     }
795 };
796
797 class FillLayersPropertyWrapper : public PropertyWrapperBase {
798 public:
799     typedef const FillLayer* (RenderStyle::*LayersGetter)() const;
800     typedef FillLayer* (RenderStyle::*LayersAccessor)();
801     
802     FillLayersPropertyWrapper(CSSPropertyID prop, LayersGetter getter, LayersAccessor accessor)
803         : PropertyWrapperBase(prop)
804         , m_layersGetter(getter)
805         , m_layersAccessor(accessor)
806     {
807         switch (prop) {
808             case CSSPropertyBackgroundPositionX:
809             case CSSPropertyWebkitMaskPositionX:
810                 m_fillLayerPropertyWrapper = new FillLayerPropertyWrapper<Length>(&FillLayer::xPosition, &FillLayer::setXPosition);
811                 break;
812             case CSSPropertyBackgroundPositionY:
813             case CSSPropertyWebkitMaskPositionY:
814                 m_fillLayerPropertyWrapper = new FillLayerPropertyWrapper<Length>(&FillLayer::yPosition, &FillLayer::setYPosition);
815                 break;
816             case CSSPropertyBackgroundSize:
817             case CSSPropertyWebkitBackgroundSize:
818             case CSSPropertyWebkitMaskSize:
819                 m_fillLayerPropertyWrapper = new FillLayerPropertyWrapper<LengthSize>(&FillLayer::sizeLength, &FillLayer::setSizeLength);
820                 break;
821             case CSSPropertyBackgroundImage:
822                 m_fillLayerPropertyWrapper = new FillLayerStyleImagePropertyWrapper(&FillLayer::image, &FillLayer::setImage);
823                 break;
824              default:
825                 break;
826         }
827     }
828
829     virtual bool equals(const RenderStyle* a, const RenderStyle* b) const
830     {
831         const FillLayer* fromLayer = (a->*m_layersGetter)();
832         const FillLayer* toLayer = (b->*m_layersGetter)();
833
834         while (fromLayer && toLayer) {
835             if (!m_fillLayerPropertyWrapper->equals(fromLayer, toLayer))
836                 return false;
837             
838             fromLayer = fromLayer->next();
839             toLayer = toLayer->next();
840         }
841
842         return true;
843     }
844
845     virtual void blend(const AnimationBase* anim, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress) const
846     {
847         const FillLayer* aLayer = (a->*m_layersGetter)();
848         const FillLayer* bLayer = (b->*m_layersGetter)();
849         FillLayer* dstLayer = (dst->*m_layersAccessor)();
850
851         while (aLayer && bLayer && dstLayer) {
852             m_fillLayerPropertyWrapper->blend(anim, dstLayer, aLayer, bLayer, progress);
853             aLayer = aLayer->next();
854             bLayer = bLayer->next();
855             dstLayer = dstLayer->next();
856         }
857     }
858
859 private:
860     FillLayerPropertyWrapperBase* m_fillLayerPropertyWrapper;
861     
862     LayersGetter m_layersGetter;
863     LayersAccessor m_layersAccessor;
864 };
865
866 class PropertyWrapperFlex : public PropertyWrapperBase {
867 public:
868     PropertyWrapperFlex() : PropertyWrapperBase(CSSPropertyWebkitFlex)
869     {
870     }
871
872     virtual bool equals(const RenderStyle* a, const RenderStyle* b) const
873     {
874         // If the style pointers are the same, don't bother doing the test.
875         // If either is null, return false. If both are null, return true.
876         if ((!a && !b) || a == b)
877             return true;
878         if (!a || !b)
879             return false;
880
881         return a->flexPreferredSize() == b->flexPreferredSize() && a->positiveFlex() == b->positiveFlex() && a->negativeFlex() == b->negativeFlex();
882     }
883
884     virtual void blend(const AnimationBase* anim, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress) const
885     {
886         dst->setFlexPreferredSize(blendFunc(anim, a->flexPreferredSize(), b->flexPreferredSize(), progress));
887         dst->setPositiveFlex(blendFunc(anim, a->positiveFlex(), b->positiveFlex(), progress));
888         dst->setNegativeFlex(blendFunc(anim, a->negativeFlex(), b->negativeFlex(), progress));
889     }
890 };
891
892 class ShorthandPropertyWrapper : public PropertyWrapperBase {
893 public:
894     ShorthandPropertyWrapper(CSSPropertyID property, const StylePropertyShorthand& shorthand)
895         : PropertyWrapperBase(property)
896     {
897         for (unsigned i = 0; i < shorthand.length(); ++i) {
898             PropertyWrapperBase* wrapper = wrapperForProperty(shorthand.properties()[i]);
899             if (wrapper)
900                 m_propertyWrappers.append(wrapper);
901         }
902     }
903
904     virtual bool isShorthandWrapper() const { return true; }
905
906     virtual bool equals(const RenderStyle* a, const RenderStyle* b) const
907     {
908         Vector<PropertyWrapperBase*>::const_iterator end = m_propertyWrappers.end();
909         for (Vector<PropertyWrapperBase*>::const_iterator it = m_propertyWrappers.begin(); it != end; ++it) {
910             if (!(*it)->equals(a, b))
911                 return false;
912         }
913         return true;
914     }
915
916     virtual void blend(const AnimationBase* anim, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress) const
917     {
918         Vector<PropertyWrapperBase*>::const_iterator end = m_propertyWrappers.end();
919         for (Vector<PropertyWrapperBase*>::const_iterator it = m_propertyWrappers.begin(); it != end; ++it)
920             (*it)->blend(anim, dst, a, b, progress);
921     }
922
923     const Vector<PropertyWrapperBase*> propertyWrappers() const { return m_propertyWrappers; }
924
925 private:
926     Vector<PropertyWrapperBase*> m_propertyWrappers;
927 };
928
929 #if ENABLE(SVG)
930 class PropertyWrapperSVGPaint : public PropertyWrapperBase {
931 public:
932     PropertyWrapperSVGPaint(CSSPropertyID prop, const SVGPaint::SVGPaintType& (RenderStyle::*paintTypeGetter)() const, Color (RenderStyle::*getter)() const, void (RenderStyle::*setter)(const Color&))
933         : PropertyWrapperBase(prop)
934         , m_paintTypeGetter(paintTypeGetter)
935         , m_getter(getter)
936         , m_setter(setter)
937     {
938     }
939
940     virtual bool equals(const RenderStyle* a, const RenderStyle* b) const
941     {
942         if ((a->*m_paintTypeGetter)() != (b->*m_paintTypeGetter)())
943             return false;
944         
945         // We only support animations between SVGPaints that are pure Color values.
946         // For everything else we must return true for this method, otherwise
947         // we will try to animate between values forever.
948         if ((a->*m_paintTypeGetter)() == SVGPaint::SVG_PAINTTYPE_RGBCOLOR) {
949             Color fromColor = (a->*m_getter)();
950             Color toColor = (b->*m_getter)();
951
952             if (!fromColor.isValid() && !toColor.isValid())
953                 return true;
954
955             if (!fromColor.isValid())
956                 fromColor = Color();
957             if (!toColor.isValid())
958                 toColor = Color();
959
960             return fromColor == toColor;
961         }
962         return true;
963     }
964
965     virtual void blend(const AnimationBase* anim, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress) const
966     {
967         if ((a->*m_paintTypeGetter)() != SVGPaint::SVG_PAINTTYPE_RGBCOLOR
968             || (b->*m_paintTypeGetter)() != SVGPaint::SVG_PAINTTYPE_RGBCOLOR)
969             return;
970
971         Color fromColor = (a->*m_getter)();
972         Color toColor = (b->*m_getter)();
973
974         if (!fromColor.isValid() && !toColor.isValid())
975             return;
976
977         if (!fromColor.isValid())
978             fromColor = Color();
979         if (!toColor.isValid())
980             toColor = Color();
981         (dst->*m_setter)(blendFunc(anim, fromColor, toColor, progress));
982     }
983
984 private:
985     const SVGPaint::SVGPaintType& (RenderStyle::*m_paintTypeGetter)() const;
986     Color (RenderStyle::*m_getter)() const;
987     void (RenderStyle::*m_setter)(const Color&);
988 };
989 #endif
990
991 static Vector<PropertyWrapperBase*>* gPropertyWrappers = 0;
992 static int gPropertyWrapperMap[numCSSProperties];
993
994 static const int cInvalidPropertyWrapperIndex = -1;
995
996
997 void AnimationBase::ensurePropertyMap()
998 {
999     // FIXME: This data is never destroyed. Maybe we should ref count it and toss it when the last AnimationController is destroyed?
1000     if (gPropertyWrappers == 0) {
1001         gPropertyWrappers = new Vector<PropertyWrapperBase*>();
1002
1003         // build the list of property wrappers to do the comparisons and blends
1004         gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyLeft, &RenderStyle::left, &RenderStyle::setLeft));
1005         gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyRight, &RenderStyle::right, &RenderStyle::setRight));
1006         gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyTop, &RenderStyle::top, &RenderStyle::setTop));
1007         gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyBottom, &RenderStyle::bottom, &RenderStyle::setBottom));
1008
1009         gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyWidth, &RenderStyle::width, &RenderStyle::setWidth));
1010         gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyMinWidth, &RenderStyle::minWidth, &RenderStyle::setMinWidth));
1011         gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyMaxWidth, &RenderStyle::maxWidth, &RenderStyle::setMaxWidth));
1012
1013         gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyHeight, &RenderStyle::height, &RenderStyle::setHeight));
1014         gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyMinHeight, &RenderStyle::minHeight, &RenderStyle::setMinHeight));
1015         gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyMaxHeight, &RenderStyle::maxHeight, &RenderStyle::setMaxHeight));
1016
1017         gPropertyWrappers->append(new PropertyWrapperFlex());
1018
1019         gPropertyWrappers->append(new PropertyWrapper<unsigned>(CSSPropertyBorderLeftWidth, &RenderStyle::borderLeftWidth, &RenderStyle::setBorderLeftWidth));
1020         gPropertyWrappers->append(new PropertyWrapper<unsigned>(CSSPropertyBorderRightWidth, &RenderStyle::borderRightWidth, &RenderStyle::setBorderRightWidth));
1021         gPropertyWrappers->append(new PropertyWrapper<unsigned>(CSSPropertyBorderTopWidth, &RenderStyle::borderTopWidth, &RenderStyle::setBorderTopWidth));
1022         gPropertyWrappers->append(new PropertyWrapper<unsigned>(CSSPropertyBorderBottomWidth, &RenderStyle::borderBottomWidth, &RenderStyle::setBorderBottomWidth));
1023         gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyMarginLeft, &RenderStyle::marginLeft, &RenderStyle::setMarginLeft));
1024         gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyMarginRight, &RenderStyle::marginRight, &RenderStyle::setMarginRight));
1025         gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyMarginTop, &RenderStyle::marginTop, &RenderStyle::setMarginTop));
1026         gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyMarginBottom, &RenderStyle::marginBottom, &RenderStyle::setMarginBottom));
1027         gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyPaddingLeft, &RenderStyle::paddingLeft, &RenderStyle::setPaddingLeft));
1028         gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyPaddingRight, &RenderStyle::paddingRight, &RenderStyle::setPaddingRight));
1029         gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyPaddingTop, &RenderStyle::paddingTop, &RenderStyle::setPaddingTop));
1030         gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyPaddingBottom, &RenderStyle::paddingBottom, &RenderStyle::setPaddingBottom));
1031         gPropertyWrappers->append(new PropertyWrapperVisitedAffectedColor(CSSPropertyColor, &RenderStyle::color, &RenderStyle::setColor, &RenderStyle::visitedLinkColor, &RenderStyle::setVisitedLinkColor));
1032
1033         gPropertyWrappers->append(new PropertyWrapperVisitedAffectedColor(CSSPropertyBackgroundColor, &RenderStyle::backgroundColor, &RenderStyle::setBackgroundColor, &RenderStyle::visitedLinkBackgroundColor, &RenderStyle::setVisitedLinkBackgroundColor));
1034
1035         gPropertyWrappers->append(new FillLayersPropertyWrapper(CSSPropertyBackgroundImage, &RenderStyle::backgroundLayers, &RenderStyle::accessBackgroundLayers));
1036         gPropertyWrappers->append(new StyleImagePropertyWrapper(CSSPropertyListStyleImage, &RenderStyle::listStyleImage, &RenderStyle::setListStyleImage));
1037         gPropertyWrappers->append(new StyleImagePropertyWrapper(CSSPropertyWebkitMaskImage, &RenderStyle::maskImage, &RenderStyle::setMaskImage));
1038
1039         gPropertyWrappers->append(new StyleImagePropertyWrapper(CSSPropertyBorderImageSource, &RenderStyle::borderImageSource, &RenderStyle::setBorderImageSource));
1040         gPropertyWrappers->append(new PropertyWrapper<LengthBox>(CSSPropertyBorderImageSlice, &RenderStyle::borderImageSlices, &RenderStyle::setBorderImageSlices));
1041         gPropertyWrappers->append(new PropertyWrapper<LengthBox>(CSSPropertyBorderImageWidth, &RenderStyle::borderImageWidth, &RenderStyle::setBorderImageWidth));
1042         gPropertyWrappers->append(new PropertyWrapper<LengthBox>(CSSPropertyBorderImageOutset, &RenderStyle::borderImageOutset, &RenderStyle::setBorderImageOutset));
1043
1044         gPropertyWrappers->append(new StyleImagePropertyWrapper(CSSPropertyWebkitMaskBoxImageSource, &RenderStyle::maskBoxImageSource, &RenderStyle::setMaskBoxImageSource));
1045         gPropertyWrappers->append(new PropertyWrapper<const NinePieceImage&>(CSSPropertyWebkitMaskBoxImage, &RenderStyle::maskBoxImage, &RenderStyle::setMaskBoxImage));
1046
1047         gPropertyWrappers->append(new FillLayersPropertyWrapper(CSSPropertyBackgroundPositionX, &RenderStyle::backgroundLayers, &RenderStyle::accessBackgroundLayers));
1048         gPropertyWrappers->append(new FillLayersPropertyWrapper(CSSPropertyBackgroundPositionY, &RenderStyle::backgroundLayers, &RenderStyle::accessBackgroundLayers));
1049         gPropertyWrappers->append(new FillLayersPropertyWrapper(CSSPropertyBackgroundSize, &RenderStyle::backgroundLayers, &RenderStyle::accessBackgroundLayers));
1050         gPropertyWrappers->append(new FillLayersPropertyWrapper(CSSPropertyWebkitBackgroundSize, &RenderStyle::backgroundLayers, &RenderStyle::accessBackgroundLayers));
1051
1052         gPropertyWrappers->append(new FillLayersPropertyWrapper(CSSPropertyWebkitMaskPositionX, &RenderStyle::maskLayers, &RenderStyle::accessMaskLayers));
1053         gPropertyWrappers->append(new FillLayersPropertyWrapper(CSSPropertyWebkitMaskPositionY, &RenderStyle::maskLayers, &RenderStyle::accessMaskLayers));
1054         gPropertyWrappers->append(new FillLayersPropertyWrapper(CSSPropertyWebkitMaskSize, &RenderStyle::maskLayers, &RenderStyle::accessMaskLayers));
1055
1056         gPropertyWrappers->append(new PropertyWrapper<int>(CSSPropertyFontSize, &RenderStyle::fontSize, &RenderStyle::setBlendedFontSize));
1057         gPropertyWrappers->append(new PropertyWrapper<unsigned short>(CSSPropertyWebkitColumnRuleWidth, &RenderStyle::columnRuleWidth, &RenderStyle::setColumnRuleWidth));
1058         gPropertyWrappers->append(new PropertyWrapper<float>(CSSPropertyWebkitColumnGap, &RenderStyle::columnGap, &RenderStyle::setColumnGap));
1059         gPropertyWrappers->append(new PropertyWrapper<unsigned short>(CSSPropertyWebkitColumnCount, &RenderStyle::columnCount, &RenderStyle::setColumnCount));
1060         gPropertyWrappers->append(new PropertyWrapper<float>(CSSPropertyWebkitColumnWidth, &RenderStyle::columnWidth, &RenderStyle::setColumnWidth));
1061         gPropertyWrappers->append(new PropertyWrapper<short>(CSSPropertyWebkitBorderHorizontalSpacing, &RenderStyle::horizontalBorderSpacing, &RenderStyle::setHorizontalBorderSpacing));
1062         gPropertyWrappers->append(new PropertyWrapper<short>(CSSPropertyWebkitBorderVerticalSpacing, &RenderStyle::verticalBorderSpacing, &RenderStyle::setVerticalBorderSpacing));
1063         gPropertyWrappers->append(new PropertyWrapper<int>(CSSPropertyZIndex, &RenderStyle::zIndex, &RenderStyle::setZIndex));
1064         gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyLineHeight, &RenderStyle::lineHeight, &RenderStyle::setLineHeight));
1065         gPropertyWrappers->append(new PropertyWrapper<int>(CSSPropertyOutlineOffset, &RenderStyle::outlineOffset, &RenderStyle::setOutlineOffset));
1066         gPropertyWrappers->append(new PropertyWrapper<unsigned short>(CSSPropertyOutlineWidth, &RenderStyle::outlineWidth, &RenderStyle::setOutlineWidth));
1067         gPropertyWrappers->append(new PropertyWrapper<int>(CSSPropertyLetterSpacing, &RenderStyle::letterSpacing, &RenderStyle::setLetterSpacing));
1068         gPropertyWrappers->append(new PropertyWrapper<int>(CSSPropertyWordSpacing, &RenderStyle::wordSpacing, &RenderStyle::setWordSpacing));
1069         gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyTextIndent, &RenderStyle::textIndent, &RenderStyle::setTextIndent));
1070
1071         gPropertyWrappers->append(new PropertyWrapper<float>(CSSPropertyWebkitPerspective, &RenderStyle::perspective, &RenderStyle::setPerspective));
1072         gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyWebkitPerspectiveOriginX, &RenderStyle::perspectiveOriginX, &RenderStyle::setPerspectiveOriginX));
1073         gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyWebkitPerspectiveOriginY, &RenderStyle::perspectiveOriginY, &RenderStyle::setPerspectiveOriginY));
1074         gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyWebkitTransformOriginX, &RenderStyle::transformOriginX, &RenderStyle::setTransformOriginX));
1075         gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyWebkitTransformOriginY, &RenderStyle::transformOriginY, &RenderStyle::setTransformOriginY));
1076         gPropertyWrappers->append(new PropertyWrapper<float>(CSSPropertyWebkitTransformOriginZ, &RenderStyle::transformOriginZ, &RenderStyle::setTransformOriginZ));
1077         gPropertyWrappers->append(new PropertyWrapper<LengthSize>(CSSPropertyBorderTopLeftRadius, &RenderStyle::borderTopLeftRadius, &RenderStyle::setBorderTopLeftRadius));
1078         gPropertyWrappers->append(new PropertyWrapper<LengthSize>(CSSPropertyBorderTopRightRadius, &RenderStyle::borderTopRightRadius, &RenderStyle::setBorderTopRightRadius));
1079         gPropertyWrappers->append(new PropertyWrapper<LengthSize>(CSSPropertyBorderBottomLeftRadius, &RenderStyle::borderBottomLeftRadius, &RenderStyle::setBorderBottomLeftRadius));
1080         gPropertyWrappers->append(new PropertyWrapper<LengthSize>(CSSPropertyBorderBottomRightRadius, &RenderStyle::borderBottomRightRadius, &RenderStyle::setBorderBottomRightRadius));
1081         gPropertyWrappers->append(new PropertyWrapper<EVisibility>(CSSPropertyVisibility, &RenderStyle::visibility, &RenderStyle::setVisibility));
1082         gPropertyWrappers->append(new PropertyWrapper<float>(CSSPropertyZoom, &RenderStyle::zoom, &RenderStyle::setZoomWithoutReturnValue));
1083
1084         gPropertyWrappers->append(new PropertyWrapper<LengthBox>(CSSPropertyClip, &RenderStyle::clip, &RenderStyle::setClip));
1085         
1086 #if USE(ACCELERATED_COMPOSITING)
1087         gPropertyWrappers->append(new PropertyWrapperAcceleratedOpacity());
1088         gPropertyWrappers->append(new PropertyWrapperAcceleratedTransform());
1089 #if ENABLE(CSS_FILTERS)
1090         gPropertyWrappers->append(new PropertyWrapperAcceleratedFilter());
1091 #endif
1092 #else
1093         gPropertyWrappers->append(new PropertyWrapper<float>(CSSPropertyOpacity, &RenderStyle::opacity, &RenderStyle::setOpacity));
1094         gPropertyWrappers->append(new PropertyWrapper<const TransformOperations&>(CSSPropertyWebkitTransform, &RenderStyle::transform, &RenderStyle::setTransform));
1095 #if ENABLE(CSS_FILTERS)
1096         gPropertyWrappers->append(new PropertyWrapper<const FilterOperations&>(CSSPropertyWebkitFilter, &RenderStyle::filter, &RenderStyle::setFilter));
1097 #endif
1098 #endif
1099
1100         gPropertyWrappers->append(new PropertyWrapperVisitedAffectedColor(CSSPropertyWebkitColumnRuleColor, MaybeInvalidColor, &RenderStyle::columnRuleColor, &RenderStyle::setColumnRuleColor, &RenderStyle::visitedLinkColumnRuleColor, &RenderStyle::setVisitedLinkColumnRuleColor));
1101         gPropertyWrappers->append(new PropertyWrapperVisitedAffectedColor(CSSPropertyWebkitTextStrokeColor, MaybeInvalidColor, &RenderStyle::textStrokeColor, &RenderStyle::setTextStrokeColor, &RenderStyle::visitedLinkTextStrokeColor, &RenderStyle::setVisitedLinkTextStrokeColor));
1102         gPropertyWrappers->append(new PropertyWrapperVisitedAffectedColor(CSSPropertyWebkitTextFillColor, MaybeInvalidColor, &RenderStyle::textFillColor, &RenderStyle::setTextFillColor, &RenderStyle::visitedLinkTextFillColor, &RenderStyle::setVisitedLinkTextFillColor));
1103         gPropertyWrappers->append(new PropertyWrapperVisitedAffectedColor(CSSPropertyBorderLeftColor, MaybeInvalidColor, &RenderStyle::borderLeftColor, &RenderStyle::setBorderLeftColor, &RenderStyle::visitedLinkBorderLeftColor, &RenderStyle::setVisitedLinkBorderLeftColor));
1104         gPropertyWrappers->append(new PropertyWrapperVisitedAffectedColor(CSSPropertyBorderRightColor, MaybeInvalidColor, &RenderStyle::borderRightColor, &RenderStyle::setBorderRightColor, &RenderStyle::visitedLinkBorderRightColor, &RenderStyle::setVisitedLinkBorderRightColor));
1105         gPropertyWrappers->append(new PropertyWrapperVisitedAffectedColor(CSSPropertyBorderTopColor, MaybeInvalidColor, &RenderStyle::borderTopColor, &RenderStyle::setBorderTopColor, &RenderStyle::visitedLinkBorderTopColor, &RenderStyle::setVisitedLinkBorderTopColor));
1106         gPropertyWrappers->append(new PropertyWrapperVisitedAffectedColor(CSSPropertyBorderBottomColor, MaybeInvalidColor, &RenderStyle::borderBottomColor, &RenderStyle::setBorderBottomColor, &RenderStyle::visitedLinkBorderBottomColor, &RenderStyle::setVisitedLinkBorderBottomColor));
1107         gPropertyWrappers->append(new PropertyWrapperVisitedAffectedColor(CSSPropertyOutlineColor, MaybeInvalidColor, &RenderStyle::outlineColor, &RenderStyle::setOutlineColor, &RenderStyle::visitedLinkOutlineColor, &RenderStyle::setVisitedLinkOutlineColor));
1108
1109         gPropertyWrappers->append(new PropertyWrapperShadow(CSSPropertyBoxShadow, &RenderStyle::boxShadow, &RenderStyle::setBoxShadow));
1110         gPropertyWrappers->append(new PropertyWrapperShadow(CSSPropertyWebkitBoxShadow, &RenderStyle::boxShadow, &RenderStyle::setBoxShadow));
1111         gPropertyWrappers->append(new PropertyWrapperShadow(CSSPropertyTextShadow, &RenderStyle::textShadow, &RenderStyle::setTextShadow));
1112
1113 #if ENABLE(SVG)
1114         gPropertyWrappers->append(new PropertyWrapperSVGPaint(CSSPropertyFill, &RenderStyle::fillPaintType, &RenderStyle::fillPaintColor, &RenderStyle::setFillPaintColor));
1115         gPropertyWrappers->append(new PropertyWrapper<float>(CSSPropertyFillOpacity, &RenderStyle::fillOpacity, &RenderStyle::setFillOpacity));
1116
1117         gPropertyWrappers->append(new PropertyWrapperSVGPaint(CSSPropertyStroke, &RenderStyle::strokePaintType, &RenderStyle::strokePaintColor, &RenderStyle::setStrokePaintColor));
1118         gPropertyWrappers->append(new PropertyWrapper<float>(CSSPropertyStrokeOpacity, &RenderStyle::strokeOpacity, &RenderStyle::setStrokeOpacity));
1119         gPropertyWrappers->append(new PropertyWrapper<SVGLength>(CSSPropertyStrokeWidth, &RenderStyle::strokeWidth, &RenderStyle::setStrokeWidth));
1120         gPropertyWrappers->append(new PropertyWrapper<SVGLength>(CSSPropertyStrokeDashoffset, &RenderStyle::strokeDashOffset, &RenderStyle::setStrokeDashOffset));
1121         gPropertyWrappers->append(new PropertyWrapper<float>(CSSPropertyStrokeMiterlimit, &RenderStyle::strokeMiterLimit, &RenderStyle::setStrokeMiterLimit));
1122
1123         gPropertyWrappers->append(new PropertyWrapper<float>(CSSPropertyFloodOpacity, &RenderStyle::floodOpacity, &RenderStyle::setFloodOpacity));
1124         gPropertyWrappers->append(new PropertyWrapperMaybeInvalidColor(CSSPropertyFloodColor, &RenderStyle::floodColor, &RenderStyle::setFloodColor));
1125
1126         gPropertyWrappers->append(new PropertyWrapper<float>(CSSPropertyStopOpacity, &RenderStyle::stopOpacity, &RenderStyle::setStopOpacity));
1127         gPropertyWrappers->append(new PropertyWrapperMaybeInvalidColor(CSSPropertyStopColor, &RenderStyle::stopColor, &RenderStyle::setStopColor));
1128
1129         gPropertyWrappers->append(new PropertyWrapperMaybeInvalidColor(CSSPropertyLightingColor, &RenderStyle::lightingColor, &RenderStyle::setLightingColor));
1130
1131         gPropertyWrappers->append(new PropertyWrapper<SVGLength>(CSSPropertyBaselineShift, &RenderStyle::baselineShiftValue, &RenderStyle::setBaselineShiftValue));
1132         gPropertyWrappers->append(new PropertyWrapper<SVGLength>(CSSPropertyKerning, &RenderStyle::kerning, &RenderStyle::setKerning));
1133 #endif
1134
1135         // TODO:
1136         // 
1137         //  CSSPropertyVerticalAlign
1138         // 
1139         // Compound properties that have components that should be animatable:
1140         // 
1141         //  CSSPropertyWebkitColumns
1142         //  CSSPropertyWebkitBoxReflect
1143
1144         // Make sure unused slots have a value
1145         for (unsigned int i = 0; i < static_cast<unsigned int>(numCSSProperties); ++i)
1146             gPropertyWrapperMap[i] = cInvalidPropertyWrapperIndex;
1147
1148         // First we put the non-shorthand property wrappers into the map, so the shorthand-building
1149         // code can find them.
1150         size_t n = gPropertyWrappers->size();
1151         for (unsigned int i = 0; i < n; ++i) {
1152             ASSERT((*gPropertyWrappers)[i]->property() - firstCSSProperty < numCSSProperties);
1153             gPropertyWrapperMap[(*gPropertyWrappers)[i]->property() - firstCSSProperty] = i;
1154         }
1155         
1156         // Now add the shorthand wrappers.
1157         addShorthandProperties();
1158     }
1159 }
1160
1161 static void addPropertyWrapper(CSSPropertyID propertyID, PropertyWrapperBase* wrapper)
1162 {
1163     int propIndex = propertyID - firstCSSProperty;
1164
1165     ASSERT(gPropertyWrapperMap[propIndex] == cInvalidPropertyWrapperIndex);
1166
1167     unsigned wrapperIndex = gPropertyWrappers->size();
1168     gPropertyWrappers->append(wrapper);
1169     gPropertyWrapperMap[propIndex] = wrapperIndex;
1170 }
1171
1172 static void addShorthandProperties()
1173 {
1174     static const CSSPropertyID animatableShorthandProperties[] = {
1175         CSSPropertyBackground, // for background-color, background-position, background-image
1176         CSSPropertyBackgroundPosition,
1177         CSSPropertyFont, // for font-size, font-weight
1178         CSSPropertyWebkitMask, // for mask-position
1179         CSSPropertyWebkitMaskPosition,
1180         CSSPropertyBorderTop, CSSPropertyBorderRight, CSSPropertyBorderBottom, CSSPropertyBorderLeft,
1181         CSSPropertyBorderColor,
1182         CSSPropertyBorderRadius,
1183         CSSPropertyBorderWidth,
1184         CSSPropertyBorder,
1185         CSSPropertyBorderImage,
1186         CSSPropertyBorderSpacing,
1187         CSSPropertyListStyle, // for list-style-image
1188         CSSPropertyMargin,
1189         CSSPropertyOutline,
1190         CSSPropertyPadding,
1191         CSSPropertyWebkitTextStroke,
1192         CSSPropertyWebkitColumnRule,
1193         CSSPropertyWebkitBorderRadius,
1194         CSSPropertyWebkitTransformOrigin
1195     };
1196
1197     for (size_t i = 0; i < WTF_ARRAY_LENGTH(animatableShorthandProperties); ++i) {
1198         CSSPropertyID propertyID = animatableShorthandProperties[i];
1199         StylePropertyShorthand shorthand = shorthandForProperty(propertyID);
1200         if (shorthand.length() > 0)
1201             addPropertyWrapper(propertyID, new ShorthandPropertyWrapper(propertyID, shorthand));
1202     }
1203 }
1204
1205 static PropertyWrapperBase* wrapperForProperty(CSSPropertyID propertyID)
1206 {
1207     int propIndex = propertyID - firstCSSProperty;
1208     if (propIndex >= 0 && propIndex < numCSSProperties) {
1209         int wrapperIndex = gPropertyWrapperMap[propIndex];
1210         if (wrapperIndex >= 0)
1211             return (*gPropertyWrappers)[wrapperIndex];
1212     }
1213     return 0;
1214 }
1215
1216 AnimationBase::AnimationBase(const Animation* transition, RenderObject* renderer, CompositeAnimation* compAnim)
1217     : m_animState(AnimationStateNew)
1218     , m_isAnimating(false)
1219     , m_isAccelerated(false)
1220     , m_transformFunctionListValid(false)
1221 #if ENABLE(CSS_FILTERS)
1222     , m_filterFunctionListsMatch(false)
1223 #endif
1224     , m_startTime(0)
1225     , m_pauseTime(-1)
1226     , m_requestedStartTime(0)
1227     , m_totalDuration(-1)
1228     , m_nextIterationDuration(-1)
1229     , m_object(renderer)
1230     , m_animation(const_cast<Animation*>(transition))
1231     , m_compAnim(compAnim)
1232 {
1233     // Compute the total duration
1234     if (m_animation->iterationCount() > 0)
1235         m_totalDuration = m_animation->duration() * m_animation->iterationCount();
1236 }
1237
1238 bool AnimationBase::propertiesEqual(CSSPropertyID prop, const RenderStyle* a, const RenderStyle* b)
1239 {
1240     ensurePropertyMap();
1241     PropertyWrapperBase* wrapper = wrapperForProperty(prop);
1242     if (wrapper)
1243         return wrapper->equals(a, b);
1244     return true;
1245 }
1246
1247 CSSPropertyID AnimationBase::getPropertyAtIndex(int i, bool& isShorthand)
1248 {
1249     ensurePropertyMap();
1250     if (i < 0 || i >= static_cast<int>(gPropertyWrappers->size()))
1251         return CSSPropertyInvalid;
1252
1253     PropertyWrapperBase* wrapper = (*gPropertyWrappers)[i];
1254     isShorthand = wrapper->isShorthandWrapper();
1255     return wrapper->property();
1256 }
1257
1258 int AnimationBase::getNumProperties()
1259 {
1260     ensurePropertyMap();
1261     return gPropertyWrappers->size();
1262 }
1263
1264 // Returns true if we need to start animation timers
1265 bool AnimationBase::blendProperties(const AnimationBase* anim, CSSPropertyID prop, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress)
1266 {
1267     ASSERT(prop != CSSPropertyInvalid);
1268
1269     ensurePropertyMap();
1270     PropertyWrapperBase* wrapper = wrapperForProperty(prop);
1271     if (wrapper) {
1272         wrapper->blend(anim, dst, a, b, progress);
1273 #if USE(ACCELERATED_COMPOSITING)
1274         return !wrapper->animationIsAccelerated() || !anim->isAccelerated();
1275 #else
1276         return true;
1277 #endif
1278     }
1279
1280     return false;
1281 }
1282
1283 #if USE(ACCELERATED_COMPOSITING)
1284 bool AnimationBase::animationOfPropertyIsAccelerated(CSSPropertyID prop)
1285 {
1286     ensurePropertyMap();
1287     PropertyWrapperBase* wrapper = wrapperForProperty(prop);
1288     return wrapper ? wrapper->animationIsAccelerated() : false;
1289 }
1290 #endif
1291
1292 static bool gatherEnclosingShorthandProperties(CSSPropertyID property, PropertyWrapperBase* wrapper, HashSet<CSSPropertyID>& propertySet)
1293 {
1294     if (!wrapper->isShorthandWrapper())
1295         return false;
1296
1297     ShorthandPropertyWrapper* shorthandWrapper = static_cast<ShorthandPropertyWrapper*>(wrapper);
1298     
1299     bool contained = false;
1300     for (size_t i = 0; i < shorthandWrapper->propertyWrappers().size(); ++i) {
1301         PropertyWrapperBase* currWrapper = shorthandWrapper->propertyWrappers()[i];
1302
1303         if (gatherEnclosingShorthandProperties(property, currWrapper, propertySet) || currWrapper->property() == property)
1304             contained = true;
1305     }
1306     
1307     if (contained)
1308         propertySet.add(wrapper->property());
1309
1310     return contained;
1311 }
1312
1313 // Note: this is inefficient. It's only called from pauseTransitionAtTime().
1314 HashSet<CSSPropertyID> AnimationBase::animatableShorthandsAffectingProperty(CSSPropertyID property)
1315 {
1316     ensurePropertyMap();
1317
1318     HashSet<CSSPropertyID> foundProperties;
1319     for (int i = 0; i < getNumProperties(); ++i)
1320         gatherEnclosingShorthandProperties(property, (*gPropertyWrappers)[i], foundProperties);
1321
1322     return foundProperties;
1323 }
1324
1325 void AnimationBase::setNeedsStyleRecalc(Node* node)
1326 {
1327     ASSERT(!node || (node->document() && !node->document()->inPageCache()));
1328     if (node)
1329         node->setNeedsStyleRecalc(SyntheticStyleChange);
1330 }
1331
1332 double AnimationBase::duration() const
1333 {
1334     return m_animation->duration();
1335 }
1336
1337 bool AnimationBase::playStatePlaying() const
1338 {
1339     return m_animation->playState() == AnimPlayStatePlaying;
1340 }
1341
1342 bool AnimationBase::animationsMatch(const Animation* anim) const
1343 {
1344     return m_animation->animationsMatch(anim);
1345 }
1346
1347 void AnimationBase::updateStateMachine(AnimStateInput input, double param)
1348 {
1349     if (!m_compAnim)
1350         return;
1351
1352     // If we get AnimationStateInputRestartAnimation then we force a new animation, regardless of state.
1353     if (input == AnimationStateInputMakeNew) {
1354         if (m_animState == AnimationStateStartWaitStyleAvailable)
1355             m_compAnim->animationController()->removeFromAnimationsWaitingForStyle(this);
1356         m_animState = AnimationStateNew;
1357         m_startTime = 0;
1358         m_pauseTime = -1;
1359         m_requestedStartTime = 0;
1360         m_nextIterationDuration = -1;
1361         endAnimation();
1362         return;
1363     }
1364
1365     if (input == AnimationStateInputRestartAnimation) {
1366         if (m_animState == AnimationStateStartWaitStyleAvailable)
1367             m_compAnim->animationController()->removeFromAnimationsWaitingForStyle(this);
1368         m_animState = AnimationStateNew;
1369         m_startTime = 0;
1370         m_pauseTime = -1;
1371         m_requestedStartTime = 0;
1372         m_nextIterationDuration = -1;
1373         endAnimation();
1374
1375         if (!paused())
1376             updateStateMachine(AnimationStateInputStartAnimation, -1);
1377         return;
1378     }
1379
1380     if (input == AnimationStateInputEndAnimation) {
1381         if (m_animState == AnimationStateStartWaitStyleAvailable)
1382             m_compAnim->animationController()->removeFromAnimationsWaitingForStyle(this);
1383         m_animState = AnimationStateDone;
1384         endAnimation();
1385         return;
1386     }
1387
1388     if (input == AnimationStateInputPauseOverride) {
1389         if (m_animState == AnimationStateStartWaitResponse) {
1390             // If we are in AnimationStateStartWaitResponse, the animation will get canceled before 
1391             // we get a response, so move to the next state.
1392             endAnimation();
1393             updateStateMachine(AnimationStateInputStartTimeSet, beginAnimationUpdateTime());
1394         }
1395         return;
1396     }
1397
1398     if (input == AnimationStateInputResumeOverride) {
1399         if (m_animState == AnimationStateLooping || m_animState == AnimationStateEnding) {
1400             // Start the animation
1401             startAnimation(beginAnimationUpdateTime() - m_startTime);
1402         }
1403         return;
1404     }
1405
1406     // Execute state machine
1407     switch (m_animState) {
1408         case AnimationStateNew:
1409             ASSERT(input == AnimationStateInputStartAnimation || input == AnimationStateInputPlayStateRunning || input == AnimationStateInputPlayStatePaused);
1410             if (input == AnimationStateInputStartAnimation || input == AnimationStateInputPlayStateRunning) {
1411                 m_requestedStartTime = beginAnimationUpdateTime();
1412                 m_animState = AnimationStateStartWaitTimer;
1413             }
1414             break;
1415         case AnimationStateStartWaitTimer:
1416             ASSERT(input == AnimationStateInputStartTimerFired || input == AnimationStateInputPlayStatePaused);
1417
1418             if (input == AnimationStateInputStartTimerFired) {
1419                 ASSERT(param >= 0);
1420                 // Start timer has fired, tell the animation to start and wait for it to respond with start time
1421                 m_animState = AnimationStateStartWaitStyleAvailable;
1422                 m_compAnim->animationController()->addToAnimationsWaitingForStyle(this);
1423
1424                 // Trigger a render so we can start the animation
1425                 if (m_object)
1426                     m_compAnim->animationController()->addNodeChangeToDispatch(m_object->node());
1427             } else {
1428                 ASSERT(!paused());
1429                 // We're waiting for the start timer to fire and we got a pause. Cancel the timer, pause and wait
1430                 m_pauseTime = beginAnimationUpdateTime();
1431                 m_animState = AnimationStatePausedWaitTimer;
1432             }
1433             break;
1434         case AnimationStateStartWaitStyleAvailable:
1435             ASSERT(input == AnimationStateInputStyleAvailable || input == AnimationStateInputPlayStatePaused);
1436
1437             if (input == AnimationStateInputStyleAvailable) {
1438                 // Start timer has fired, tell the animation to start and wait for it to respond with start time
1439                 m_animState = AnimationStateStartWaitResponse;
1440
1441                 overrideAnimations();
1442
1443                 // Start the animation
1444                 if (overridden()) {
1445                     // We won't try to start accelerated animations if we are overridden and
1446                     // just move on to the next state.
1447                     m_animState = AnimationStateStartWaitResponse;
1448                     m_isAccelerated = false;
1449                     updateStateMachine(AnimationStateInputStartTimeSet, beginAnimationUpdateTime());
1450                 } else {
1451                     double timeOffset = 0;
1452                     // If the value for 'animation-delay' is negative then the animation appears to have started in the past.
1453                     if (m_animation->delay() < 0)
1454                         timeOffset = -m_animation->delay();
1455                     bool started = startAnimation(timeOffset);
1456
1457                     m_compAnim->animationController()->addToAnimationsWaitingForStartTimeResponse(this, started);
1458                     m_isAccelerated = started;
1459                 }
1460             } else {
1461                 // We're waiting for the style to be available and we got a pause. Pause and wait
1462                 m_pauseTime = beginAnimationUpdateTime();
1463                 m_animState = AnimationStatePausedWaitStyleAvailable;
1464             }
1465             break;
1466         case AnimationStateStartWaitResponse:
1467             ASSERT(input == AnimationStateInputStartTimeSet || input == AnimationStateInputPlayStatePaused);
1468
1469             if (input == AnimationStateInputStartTimeSet) {
1470                 ASSERT(param >= 0);
1471                 // We have a start time, set it, unless the startTime is already set
1472                 if (m_startTime <= 0) {
1473                     m_startTime = param;
1474                     // If the value for 'animation-delay' is negative then the animation appears to have started in the past.
1475                     if (m_animation->delay() < 0)
1476                         m_startTime += m_animation->delay();
1477                 }
1478
1479                 // Now that we know the start time, fire the start event.
1480                 onAnimationStart(0); // The elapsedTime is 0.
1481
1482                 // Decide whether to go into looping or ending state
1483                 goIntoEndingOrLoopingState();
1484
1485                 // Dispatch updateStyleIfNeeded so we can start the animation
1486                 if (m_object)
1487                     m_compAnim->animationController()->addNodeChangeToDispatch(m_object->node());
1488             } else {
1489                 // We are pausing while waiting for a start response. Cancel the animation and wait. When 
1490                 // we unpause, we will act as though the start timer just fired
1491                 m_pauseTime = beginAnimationUpdateTime();
1492                 pauseAnimation(beginAnimationUpdateTime() - m_startTime);
1493                 m_animState = AnimationStatePausedWaitResponse;
1494             }
1495             break;
1496         case AnimationStateLooping:
1497             ASSERT(input == AnimationStateInputLoopTimerFired || input == AnimationStateInputPlayStatePaused);
1498
1499             if (input == AnimationStateInputLoopTimerFired) {
1500                 ASSERT(param >= 0);
1501                 // Loop timer fired, loop again or end.
1502                 onAnimationIteration(param);
1503
1504                 // Decide whether to go into looping or ending state
1505                 goIntoEndingOrLoopingState();
1506             } else {
1507                 // We are pausing while running. Cancel the animation and wait
1508                 m_pauseTime = beginAnimationUpdateTime();
1509                 pauseAnimation(beginAnimationUpdateTime() - m_startTime);
1510                 m_animState = AnimationStatePausedRun;
1511             }
1512             break;
1513         case AnimationStateEnding:
1514 #if !LOG_DISABLED
1515             if (input != AnimationStateInputEndTimerFired && input != AnimationStateInputPlayStatePaused)
1516                 LOG_ERROR("State is AnimationStateEnding, but input is not AnimationStateInputEndTimerFired or AnimationStateInputPlayStatePaused. It is %d.", input);
1517 #endif
1518             if (input == AnimationStateInputEndTimerFired) {
1519
1520                 ASSERT(param >= 0);
1521                 // End timer fired, finish up
1522                 onAnimationEnd(param);
1523
1524                 m_animState = AnimationStateDone;
1525                 
1526                 if (m_object) {
1527                     if (m_animation->fillsForwards())
1528                         m_animState = AnimationStateFillingForwards;
1529                     else
1530                         resumeOverriddenAnimations();
1531
1532                     // Fire off another style change so we can set the final value
1533                     m_compAnim->animationController()->addNodeChangeToDispatch(m_object->node());
1534                 }
1535             } else {
1536                 // We are pausing while running. Cancel the animation and wait
1537                 m_pauseTime = beginAnimationUpdateTime();
1538                 pauseAnimation(beginAnimationUpdateTime() - m_startTime);
1539                 m_animState = AnimationStatePausedRun;
1540             }
1541             // |this| may be deleted here
1542             break;
1543         case AnimationStatePausedWaitTimer:
1544             ASSERT(input == AnimationStateInputPlayStateRunning);
1545             ASSERT(paused());
1546             // Update the times
1547             m_startTime += beginAnimationUpdateTime() - m_pauseTime;
1548             m_pauseTime = -1;
1549
1550             // we were waiting for the start timer to fire, go back and wait again
1551             m_animState = AnimationStateNew;
1552             updateStateMachine(AnimationStateInputStartAnimation, 0);
1553             break;
1554         case AnimationStatePausedWaitResponse:
1555         case AnimationStatePausedWaitStyleAvailable:
1556         case AnimationStatePausedRun:
1557             // We treat these two cases the same. The only difference is that, when we are in
1558             // AnimationStatePausedWaitResponse, we don't yet have a valid startTime, so we send 0 to startAnimation.
1559             // When the AnimationStateInputStartTimeSet comes in and we were in AnimationStatePausedRun, we will notice
1560             // that we have already set the startTime and will ignore it.
1561             ASSERT(input == AnimationStateInputPlayStateRunning || input == AnimationStateInputStartTimeSet || input == AnimationStateInputStyleAvailable);
1562             ASSERT(paused());
1563             
1564             if (input == AnimationStateInputPlayStateRunning) {
1565                 // Update the times
1566                 if (m_animState == AnimationStatePausedRun)
1567                     m_startTime += beginAnimationUpdateTime() - m_pauseTime;
1568                 else
1569                     m_startTime = 0;
1570                 m_pauseTime = -1;
1571
1572                 if (m_animState == AnimationStatePausedWaitStyleAvailable)
1573                     m_animState = AnimationStateStartWaitStyleAvailable;
1574                 else {
1575                     // We were either running or waiting for a begin time response from the animation.
1576                     // Either way we need to restart the animation (possibly with an offset if we
1577                     // had already been running) and wait for it to start.
1578                     m_animState = AnimationStateStartWaitResponse;
1579
1580                     // Start the animation
1581                     if (overridden()) {
1582                         // We won't try to start accelerated animations if we are overridden and
1583                         // just move on to the next state.
1584                         updateStateMachine(AnimationStateInputStartTimeSet, beginAnimationUpdateTime());
1585                         m_isAccelerated = true;
1586                     } else {
1587                         bool started = startAnimation(beginAnimationUpdateTime() - m_startTime);
1588                         m_compAnim->animationController()->addToAnimationsWaitingForStartTimeResponse(this, started);
1589                         m_isAccelerated = started;
1590                     }
1591                 }
1592                 break;
1593             }
1594             
1595             if (input == AnimationStateInputStartTimeSet) {
1596                 ASSERT(m_animState == AnimationStatePausedWaitResponse);
1597                 
1598                 // We are paused but we got the callback that notifies us that an accelerated animation started.
1599                 // We ignore the start time and just move into the paused-run state.
1600                 m_animState = AnimationStatePausedRun;
1601                 ASSERT(m_startTime == 0);
1602                 m_startTime = param;
1603                 m_pauseTime += m_startTime;
1604                 break;
1605             }
1606             
1607             ASSERT(m_animState == AnimationStatePausedWaitStyleAvailable);
1608             // We are paused but we got the callback that notifies us that style has been updated.
1609             // We move to the AnimationStatePausedWaitResponse state
1610             m_animState = AnimationStatePausedWaitResponse;
1611             overrideAnimations();
1612             break;
1613         case AnimationStateFillingForwards:
1614         case AnimationStateDone:
1615             // We're done. Stay in this state until we are deleted
1616             break;
1617     }
1618 }
1619     
1620 void AnimationBase::fireAnimationEventsIfNeeded()
1621 {
1622     if (!m_compAnim)
1623         return;
1624
1625     // If we are waiting for the delay time to expire and it has, go to the next state
1626     if (m_animState != AnimationStateStartWaitTimer && m_animState != AnimationStateLooping && m_animState != AnimationStateEnding)
1627         return;
1628
1629     // We have to make sure to keep a ref to the this pointer, because it could get destroyed
1630     // during an animation callback that might get called. Since the owner is a CompositeAnimation
1631     // and it ref counts this object, we will keep a ref to that instead. That way the AnimationBase
1632     // can still access the resources of its CompositeAnimation as needed.
1633     RefPtr<AnimationBase> protector(this);
1634     RefPtr<CompositeAnimation> compProtector(m_compAnim);
1635     
1636     // Check for start timeout
1637     if (m_animState == AnimationStateStartWaitTimer) {
1638         if (beginAnimationUpdateTime() - m_requestedStartTime >= m_animation->delay())
1639             updateStateMachine(AnimationStateInputStartTimerFired, 0);
1640         return;
1641     }
1642     
1643     double elapsedDuration = beginAnimationUpdateTime() - m_startTime;
1644     // FIXME: we need to ensure that elapsedDuration is never < 0. If it is, this suggests that
1645     // we had a recalcStyle() outside of beginAnimationUpdate()/endAnimationUpdate().
1646     // Also check in getTimeToNextEvent().
1647     elapsedDuration = max(elapsedDuration, 0.0);
1648     
1649     // Check for end timeout
1650     if (m_totalDuration >= 0 && elapsedDuration >= m_totalDuration) {
1651         // We may still be in AnimationStateLooping if we've managed to skip a
1652         // whole iteration, in which case we should jump to the end state.
1653         m_animState = AnimationStateEnding;
1654
1655         // Fire an end event
1656         updateStateMachine(AnimationStateInputEndTimerFired, m_totalDuration);
1657     } else {
1658         // Check for iteration timeout
1659         if (m_nextIterationDuration < 0) {
1660             // Hasn't been set yet, set it
1661             double durationLeft = m_animation->duration() - fmod(elapsedDuration, m_animation->duration());
1662             m_nextIterationDuration = elapsedDuration + durationLeft;
1663         }
1664         
1665         if (elapsedDuration >= m_nextIterationDuration) {
1666             // Set to the next iteration
1667             double previous = m_nextIterationDuration;
1668             double durationLeft = m_animation->duration() - fmod(elapsedDuration, m_animation->duration());
1669             m_nextIterationDuration = elapsedDuration + durationLeft;
1670             
1671             // Send the event
1672             updateStateMachine(AnimationStateInputLoopTimerFired, previous);
1673         }
1674     }
1675 }
1676
1677 void AnimationBase::updatePlayState(EAnimPlayState playState)
1678 {
1679     if (!m_compAnim)
1680         return;
1681
1682     // When we get here, we can have one of 4 desired states: running, paused, suspended, paused & suspended.
1683     // The state machine can be in one of two states: running, paused.
1684     // Set the state machine to the desired state.
1685     bool pause = playState == AnimPlayStatePaused || m_compAnim->suspended();
1686     
1687     if (pause == paused() && !isNew())
1688         return;
1689     
1690     updateStateMachine(pause ?  AnimationStateInputPlayStatePaused : AnimationStateInputPlayStateRunning, -1);
1691 }
1692
1693 double AnimationBase::timeToNextService()
1694 {
1695     // Returns the time at which next service is required. -1 means no service is required. 0 means 
1696     // service is required now, and > 0 means service is required that many seconds in the future.
1697     if (paused() || isNew() || m_animState == AnimationStateFillingForwards)
1698         return -1;
1699     
1700     if (m_animState == AnimationStateStartWaitTimer) {
1701         double timeFromNow = m_animation->delay() - (beginAnimationUpdateTime() - m_requestedStartTime);
1702         return max(timeFromNow, 0.0);
1703     }
1704     
1705     fireAnimationEventsIfNeeded();
1706         
1707     // In all other cases, we need service right away.
1708     return 0;
1709 }
1710
1711 // Compute the fractional time, taking into account direction.
1712 // There is no need to worry about iterations, we assume that we would have
1713 // short circuited above if we were done.
1714
1715 double AnimationBase::fractionalTime(double scale, double elapsedTime, double offset) const
1716 {
1717     double fractionalTime = m_animation->duration() ? (elapsedTime / m_animation->duration()) : 1;
1718     // FIXME: startTime can be before the current animation "frame" time. This is to sync with the frame time
1719     // concept in AnimationTimeController. So we need to somehow sync the two. Until then, the possible
1720     // error is small and will probably not be noticeable. Until we fix this, remove the assert.
1721     // https://bugs.webkit.org/show_bug.cgi?id=52037
1722     // ASSERT(fractionalTime >= 0);
1723     if (fractionalTime < 0)
1724         fractionalTime = 0;
1725
1726     int integralTime = static_cast<int>(fractionalTime);
1727     const int integralIterationCount = static_cast<int>(m_animation->iterationCount());
1728     const bool iterationCountHasFractional = m_animation->iterationCount() - integralIterationCount;
1729     if (m_animation->iterationCount() != Animation::IterationCountInfinite && !iterationCountHasFractional)
1730         integralTime = min(integralTime, integralIterationCount - 1);
1731
1732     fractionalTime -= integralTime;
1733
1734     if (((m_animation->direction() == Animation::AnimationDirectionAlternate) && (integralTime & 1))
1735         || ((m_animation->direction() == Animation::AnimationDirectionAlternateReverse) && !(integralTime & 1))
1736         || m_animation->direction() == Animation::AnimationDirectionReverse)
1737         fractionalTime = 1 - fractionalTime;
1738
1739     if (scale != 1 || offset)
1740         fractionalTime = (fractionalTime - offset) * scale;
1741
1742     return fractionalTime;
1743 }
1744
1745 double AnimationBase::progress(double scale, double offset, const TimingFunction* tf) const
1746 {
1747     if (preActive())
1748         return 0;
1749
1750     double elapsedTime = getElapsedTime();
1751
1752     double dur = m_animation->duration();
1753     if (m_animation->iterationCount() > 0)
1754         dur *= m_animation->iterationCount();
1755
1756     if (postActive() || !m_animation->duration())
1757         return 1.0;
1758     if (m_animation->iterationCount() > 0 && elapsedTime >= dur) {
1759         const int integralIterationCount = static_cast<int>(m_animation->iterationCount());
1760         const bool iterationCountHasFractional = m_animation->iterationCount() - integralIterationCount;
1761         return (integralIterationCount % 2 || iterationCountHasFractional) ? 1.0 : 0.0;
1762     }
1763
1764     const double fractionalTime = this->fractionalTime(scale, elapsedTime, offset);
1765
1766     if (!tf)
1767         tf = m_animation->timingFunction().get();
1768
1769     if (tf->isCubicBezierTimingFunction()) {
1770         const CubicBezierTimingFunction* ctf = static_cast<const CubicBezierTimingFunction*>(tf);
1771         return solveCubicBezierFunction(ctf->x1(),
1772                                         ctf->y1(),
1773                                         ctf->x2(),
1774                                         ctf->y2(),
1775                                         fractionalTime, m_animation->duration());
1776     } else if (tf->isStepsTimingFunction()) {
1777         const StepsTimingFunction* stf = static_cast<const StepsTimingFunction*>(tf);
1778         return solveStepsFunction(stf->numberOfSteps(), stf->stepAtStart(), fractionalTime);
1779     } else
1780         return fractionalTime;
1781 }
1782
1783 void AnimationBase::getTimeToNextEvent(double& time, bool& isLooping) const
1784 {
1785     // Decide when the end or loop event needs to fire
1786     const double elapsedDuration = max(beginAnimationUpdateTime() - m_startTime, 0.0);
1787     double durationLeft = 0;
1788     double nextIterationTime = m_totalDuration;
1789
1790     if (m_totalDuration < 0 || elapsedDuration < m_totalDuration) {
1791         durationLeft = m_animation->duration() > 0 ? (m_animation->duration() - fmod(elapsedDuration, m_animation->duration())) : 0;
1792         nextIterationTime = elapsedDuration + durationLeft;
1793     }
1794     
1795     if (m_totalDuration < 0 || nextIterationTime < m_totalDuration) {
1796         // We are not at the end yet
1797         ASSERT(nextIterationTime > 0);
1798         isLooping = true;
1799     } else {
1800         // We are at the end
1801         isLooping = false;
1802     }
1803     
1804     time = durationLeft;
1805 }
1806
1807 void AnimationBase::goIntoEndingOrLoopingState()
1808 {
1809     double t;
1810     bool isLooping;
1811     getTimeToNextEvent(t, isLooping);
1812     m_animState = isLooping ? AnimationStateLooping : AnimationStateEnding;
1813 }
1814   
1815 void AnimationBase::freezeAtTime(double t)
1816 {
1817     if (!m_compAnim)
1818         return;
1819
1820     if (!m_startTime) {
1821         // If we haven't started yet, make it as if we started.
1822         m_animState = AnimationStateStartWaitResponse;
1823         onAnimationStartResponse(currentTime());
1824     }
1825
1826     ASSERT(m_startTime);        // if m_startTime is zero, we haven't started yet, so we'll get a bad pause time.
1827     if (t <= m_animation->delay())
1828         m_pauseTime = m_startTime;
1829     else
1830         m_pauseTime = m_startTime + t - m_animation->delay();
1831
1832 #if USE(ACCELERATED_COMPOSITING)
1833     if (m_object && m_object->isComposited())
1834         toRenderBoxModelObject(m_object)->suspendAnimations(m_pauseTime);
1835 #endif
1836 }
1837
1838 double AnimationBase::beginAnimationUpdateTime() const
1839 {
1840     if (!m_compAnim)
1841         return 0;
1842
1843     return m_compAnim->animationController()->beginAnimationUpdateTime();
1844 }
1845
1846 double AnimationBase::getElapsedTime() const
1847 {
1848     if (paused())    
1849         return m_pauseTime - m_startTime;
1850     if (m_startTime <= 0)
1851         return 0;
1852     if (postActive())
1853         return 1;
1854
1855     return beginAnimationUpdateTime() - m_startTime;
1856 }
1857
1858 void AnimationBase::setElapsedTime(double time)
1859 {
1860     // FIXME: implement this method
1861     UNUSED_PARAM(time);
1862 }
1863
1864 void AnimationBase::play()
1865 {
1866     // FIXME: implement this method
1867 }
1868
1869 void AnimationBase::pause()
1870 {
1871     // FIXME: implement this method
1872 }
1873
1874 } // namespace WebCore