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