• 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     return Color(blendFunc(anim, from.red(), to.red(), progress),
96                  blendFunc(anim, from.green(), to.green(), progress),
97                  blendFunc(anim, from.blue(), to.blue(), progress),
98                  blendFunc(anim, from.alpha(), to.alpha(), progress));
99 }
100 
blendFunc(const AnimationBase *,const Length & from,const Length & to,double progress)101 static inline Length blendFunc(const AnimationBase*, const Length& from, const Length& to, double progress)
102 {
103     return to.blend(from, progress);
104 }
105 
blendFunc(const AnimationBase * anim,const LengthSize & from,const LengthSize & to,double progress)106 static inline LengthSize blendFunc(const AnimationBase* anim, const LengthSize& from, const LengthSize& to, double progress)
107 {
108     return LengthSize(blendFunc(anim, from.width(), to.width(), progress),
109                       blendFunc(anim, from.height(), to.height(), progress));
110 }
111 
blendFunc(const AnimationBase * anim,const IntSize & from,const IntSize & to,double progress)112 static inline IntSize blendFunc(const AnimationBase* anim, const IntSize& from, const IntSize& to, double progress)
113 {
114     return IntSize(blendFunc(anim, from.width(), to.width(), progress),
115                    blendFunc(anim, from.height(), to.height(), progress));
116 }
117 
blendFunc(const AnimationBase * anim,ShadowStyle from,ShadowStyle to,double progress)118 static inline ShadowStyle blendFunc(const AnimationBase* anim, ShadowStyle from, ShadowStyle to, double progress)
119 {
120     if (from == to)
121         return to;
122 
123     double fromVal = from == Normal ? 1 : 0;
124     double toVal = to == Normal ? 1 : 0;
125     double result = blendFunc(anim, fromVal, toVal, progress);
126     return result > 0 ? Normal : Inset;
127 }
128 
blendFunc(const AnimationBase * anim,const ShadowData * from,const ShadowData * to,double progress)129 static inline ShadowData* blendFunc(const AnimationBase* anim, const ShadowData* from, const ShadowData* to, double progress)
130 {
131     ASSERT(from && to);
132     return new ShadowData(blendFunc(anim, from->x, to->x, progress), blendFunc(anim, from->y, to->y, progress),
133                           blendFunc(anim, from->blur, to->blur, progress), blendFunc(anim, from->spread, to->spread, progress),
134                           blendFunc(anim, from->style, to->style, progress), blendFunc(anim, from->color, to->color, progress));
135 }
136 
blendFunc(const AnimationBase * anim,const TransformOperations & from,const TransformOperations & to,double progress)137 static inline TransformOperations blendFunc(const AnimationBase* anim, const TransformOperations& from, const TransformOperations& to, double progress)
138 {
139     TransformOperations result;
140 
141     // If we have a transform function list, use that to do a per-function animation. Otherwise do a Matrix animation
142     if (anim->isTransformFunctionListValid()) {
143         unsigned fromSize = from.operations().size();
144         unsigned toSize = to.operations().size();
145         unsigned size = max(fromSize, toSize);
146         for (unsigned i = 0; i < size; i++) {
147             RefPtr<TransformOperation> fromOp = (i < fromSize) ? from.operations()[i].get() : 0;
148             RefPtr<TransformOperation> toOp = (i < toSize) ? to.operations()[i].get() : 0;
149             RefPtr<TransformOperation> blendedOp = toOp ? toOp->blend(fromOp.get(), progress) : (fromOp ? fromOp->blend(0, progress, true) : 0);
150             if (blendedOp)
151                 result.operations().append(blendedOp);
152             else {
153                 RefPtr<TransformOperation> identityOp = IdentityTransformOperation::create();
154                 if (progress > 0.5)
155                     result.operations().append(toOp ? toOp : identityOp);
156                 else
157                     result.operations().append(fromOp ? fromOp : identityOp);
158             }
159         }
160     } else {
161         // Convert the TransformOperations into matrices
162         IntSize size = anim->renderer()->isBox() ? toRenderBox(anim->renderer())->borderBoxRect().size() : IntSize();
163         TransformationMatrix fromT;
164         TransformationMatrix toT;
165         from.apply(size, fromT);
166         to.apply(size, toT);
167 
168         toT.blend(fromT, progress);
169 
170         // Append the result
171         result.operations().append(Matrix3DTransformOperation::create(toT));
172     }
173     return result;
174 }
175 
blendFunc(const AnimationBase * anim,EVisibility from,EVisibility to,double progress)176 static inline EVisibility blendFunc(const AnimationBase* anim, EVisibility from, EVisibility to, double progress)
177 {
178     // Any non-zero result means we consider the object to be visible.  Only at 0 do we consider the object to be
179     // invisible.   The invisible value we use (HIDDEN vs. COLLAPSE) depends on the specified from/to values.
180     double fromVal = from == VISIBLE ? 1. : 0.;
181     double toVal = to == VISIBLE ? 1. : 0.;
182     if (fromVal == toVal)
183         return to;
184     double result = blendFunc(anim, fromVal, toVal, progress);
185     return result > 0. ? VISIBLE : (to != VISIBLE ? to : from);
186 }
187 
188 class PropertyWrapperBase;
189 
190 static void addShorthandProperties();
191 static PropertyWrapperBase* wrapperForProperty(int propertyID);
192 
193 class PropertyWrapperBase {
194 public:
PropertyWrapperBase(int prop)195     PropertyWrapperBase(int prop)
196         : m_prop(prop)
197     {
198     }
199 
~PropertyWrapperBase()200     virtual ~PropertyWrapperBase() { }
201 
isShorthandWrapper() const202     virtual bool isShorthandWrapper() const { return false; }
203     virtual bool equals(const RenderStyle* a, const RenderStyle* b) const = 0;
204     virtual void blend(const AnimationBase* anim, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress) const = 0;
205 
property() const206     int property() const { return m_prop; }
207 
208 #if USE(ACCELERATED_COMPOSITING)
animationIsAccelerated() const209     virtual bool animationIsAccelerated() const { return false; }
210 #endif
211 
212 private:
213     int m_prop;
214 };
215 
216 template <typename T>
217 class PropertyWrapperGetter : public PropertyWrapperBase {
218 public:
PropertyWrapperGetter(int prop,T (RenderStyle::* getter)()const)219     PropertyWrapperGetter(int prop, T (RenderStyle::*getter)() const)
220         : PropertyWrapperBase(prop)
221         , m_getter(getter)
222     {
223     }
224 
equals(const RenderStyle * a,const RenderStyle * b) const225     virtual bool equals(const RenderStyle* a, const RenderStyle* b) const
226     {
227        // If the style pointers are the same, don't bother doing the test.
228        // If either is null, return false. If both are null, return true.
229        if ((!a && !b) || a == b)
230            return true;
231        if (!a || !b)
232             return false;
233         return (a->*m_getter)() == (b->*m_getter)();
234     }
235 
236 protected:
237     T (RenderStyle::*m_getter)() const;
238 };
239 
240 template <typename T>
241 class PropertyWrapper : public PropertyWrapperGetter<T> {
242 public:
PropertyWrapper(int prop,T (RenderStyle::* getter)()const,void (RenderStyle::* setter)(T))243     PropertyWrapper(int prop, T (RenderStyle::*getter)() const, void (RenderStyle::*setter)(T))
244         : PropertyWrapperGetter<T>(prop, getter)
245         , m_setter(setter)
246     {
247     }
248 
blend(const AnimationBase * anim,RenderStyle * dst,const RenderStyle * a,const RenderStyle * b,double progress) const249     virtual void blend(const AnimationBase* anim, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress) const
250     {
251         (dst->*m_setter)(blendFunc(anim, (a->*PropertyWrapperGetter<T>::m_getter)(), (b->*PropertyWrapperGetter<T>::m_getter)(), progress));
252     }
253 
254 protected:
255     void (RenderStyle::*m_setter)(T);
256 };
257 
258 #if USE(ACCELERATED_COMPOSITING)
259 class PropertyWrapperAcceleratedOpacity : public PropertyWrapper<float> {
260 public:
PropertyWrapperAcceleratedOpacity()261     PropertyWrapperAcceleratedOpacity()
262         : PropertyWrapper<float>(CSSPropertyOpacity, &RenderStyle::opacity, &RenderStyle::setOpacity)
263     {
264     }
265 
animationIsAccelerated() const266     virtual bool animationIsAccelerated() const { return true; }
267 
blend(const AnimationBase * anim,RenderStyle * dst,const RenderStyle * a,const RenderStyle * b,double progress) const268     virtual void blend(const AnimationBase* anim, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress) const
269     {
270         float fromOpacity = a->opacity();
271 
272         // This makes sure we put the object being animated into a RenderLayer during the animation
273         dst->setOpacity(blendFunc(anim, (fromOpacity == 1) ? 0.999999f : fromOpacity, b->opacity(), progress));
274     }
275 };
276 
277 class PropertyWrapperAcceleratedTransform : public PropertyWrapper<const TransformOperations&> {
278 public:
PropertyWrapperAcceleratedTransform()279     PropertyWrapperAcceleratedTransform()
280         : PropertyWrapper<const TransformOperations&>(CSSPropertyWebkitTransform, &RenderStyle::transform, &RenderStyle::setTransform)
281     {
282     }
283 
animationIsAccelerated() const284     virtual bool animationIsAccelerated() const { return true; }
285 
blend(const AnimationBase * anim,RenderStyle * dst,const RenderStyle * a,const RenderStyle * b,double progress) const286     virtual void blend(const AnimationBase* anim, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress) const
287     {
288         dst->setTransform(blendFunc(anim, a->transform(), b->transform(), progress));
289     }
290 };
291 #endif // USE(ACCELERATED_COMPOSITING)
292 
293 class PropertyWrapperShadow : public PropertyWrapperGetter<ShadowData*> {
294 public:
PropertyWrapperShadow(int prop,ShadowData * (RenderStyle::* getter)()const,void (RenderStyle::* setter)(ShadowData *,bool))295     PropertyWrapperShadow(int prop, ShadowData* (RenderStyle::*getter)() const, void (RenderStyle::*setter)(ShadowData*, bool))
296         : PropertyWrapperGetter<ShadowData*>(prop, getter)
297         , m_setter(setter)
298     {
299     }
300 
equals(const RenderStyle * a,const RenderStyle * b) const301     virtual bool equals(const RenderStyle* a, const RenderStyle* b) const
302     {
303         ShadowData* shadowA = (a->*m_getter)();
304         ShadowData* shadowB = (b->*m_getter)();
305 
306         if ((!shadowA && shadowB) || (shadowA && !shadowB))
307             return false;
308         if (shadowA && shadowB && (*shadowA != *shadowB))
309             return false;
310         return true;
311     }
312 
blend(const AnimationBase * anim,RenderStyle * dst,const RenderStyle * a,const RenderStyle * b,double progress) const313     virtual void blend(const AnimationBase* anim, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress) const
314     {
315         ShadowData* shadowA = (a->*m_getter)();
316         ShadowData* shadowB = (b->*m_getter)();
317         ShadowData defaultShadowData(0, 0, 0, 0, Normal, Color::transparent);
318 
319         if (!shadowA)
320             shadowA = &defaultShadowData;
321         if (!shadowB)
322             shadowB = &defaultShadowData;
323 
324         (dst->*m_setter)(blendFunc(anim, shadowA, shadowB, progress), false);
325     }
326 
327 private:
328     void (RenderStyle::*m_setter)(ShadowData*, bool);
329 };
330 
331 class PropertyWrapperMaybeInvalidColor : public PropertyWrapperBase {
332 public:
PropertyWrapperMaybeInvalidColor(int prop,const Color & (RenderStyle::* getter)()const,void (RenderStyle::* setter)(const Color &))333     PropertyWrapperMaybeInvalidColor(int prop, const Color& (RenderStyle::*getter)() const, void (RenderStyle::*setter)(const Color&))
334         : PropertyWrapperBase(prop)
335         , m_getter(getter)
336         , m_setter(setter)
337     {
338     }
339 
equals(const RenderStyle * a,const RenderStyle * b) const340     virtual bool equals(const RenderStyle* a, const RenderStyle* b) const
341     {
342         Color fromColor = (a->*m_getter)();
343         Color toColor = (b->*m_getter)();
344         if (!fromColor.isValid())
345             fromColor = a->color();
346         if (!toColor.isValid())
347             toColor = b->color();
348 
349         return fromColor == toColor;
350     }
351 
blend(const AnimationBase * anim,RenderStyle * dst,const RenderStyle * a,const RenderStyle * b,double progress) const352     virtual void blend(const AnimationBase* anim, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress) const
353     {
354         Color fromColor = (a->*m_getter)();
355         Color toColor = (b->*m_getter)();
356         if (!fromColor.isValid())
357             fromColor = a->color();
358         if (!toColor.isValid())
359             toColor = b->color();
360         (dst->*m_setter)(blendFunc(anim, fromColor, toColor, progress));
361     }
362 
363 private:
364     const Color& (RenderStyle::*m_getter)() const;
365     void (RenderStyle::*m_setter)(const Color&);
366 };
367 
368 class ShorthandPropertyWrapper : public PropertyWrapperBase {
369 public:
ShorthandPropertyWrapper(int property,const CSSPropertyLonghand & longhand)370     ShorthandPropertyWrapper(int property, const CSSPropertyLonghand& longhand)
371         : PropertyWrapperBase(property)
372     {
373         for (unsigned i = 0; i < longhand.length(); ++i) {
374             PropertyWrapperBase* wrapper = wrapperForProperty(longhand.properties()[i]);
375             if (wrapper)
376                 m_propertyWrappers.append(wrapper);
377         }
378     }
379 
isShorthandWrapper() const380     virtual bool isShorthandWrapper() const { return true; }
381 
equals(const RenderStyle * a,const RenderStyle * b) const382     virtual bool equals(const RenderStyle* a, const RenderStyle* b) const
383     {
384         Vector<PropertyWrapperBase*>::const_iterator end = m_propertyWrappers.end();
385         for (Vector<PropertyWrapperBase*>::const_iterator it = m_propertyWrappers.begin(); it != end; ++it) {
386             if (!(*it)->equals(a, b))
387                 return false;
388         }
389         return true;
390     }
391 
blend(const AnimationBase * anim,RenderStyle * dst,const RenderStyle * a,const RenderStyle * b,double progress) const392     virtual void blend(const AnimationBase* anim, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress) const
393     {
394         Vector<PropertyWrapperBase*>::const_iterator end = m_propertyWrappers.end();
395         for (Vector<PropertyWrapperBase*>::const_iterator it = m_propertyWrappers.begin(); it != end; ++it)
396             (*it)->blend(anim, dst, a, b, progress);
397     }
398 
399 private:
400     Vector<PropertyWrapperBase*> m_propertyWrappers;
401 };
402 
403 
404 static Vector<PropertyWrapperBase*>* gPropertyWrappers = 0;
405 static int gPropertyWrapperMap[numCSSProperties];
406 
407 static const int cInvalidPropertyWrapperIndex = -1;
408 
409 
ensurePropertyMap()410 static void ensurePropertyMap()
411 {
412     // FIXME: This data is never destroyed. Maybe we should ref count it and toss it when the last AnimationController is destroyed?
413     if (gPropertyWrappers == 0) {
414         gPropertyWrappers = new Vector<PropertyWrapperBase*>();
415 
416         // build the list of property wrappers to do the comparisons and blends
417         gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyLeft, &RenderStyle::left, &RenderStyle::setLeft));
418         gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyRight, &RenderStyle::right, &RenderStyle::setRight));
419         gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyTop, &RenderStyle::top, &RenderStyle::setTop));
420         gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyBottom, &RenderStyle::bottom, &RenderStyle::setBottom));
421 
422         gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyWidth, &RenderStyle::width, &RenderStyle::setWidth));
423         gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyMinWidth, &RenderStyle::minWidth, &RenderStyle::setMinWidth));
424         gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyMaxWidth, &RenderStyle::maxWidth, &RenderStyle::setMaxWidth));
425 
426         gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyHeight, &RenderStyle::height, &RenderStyle::setHeight));
427         gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyMinHeight, &RenderStyle::minHeight, &RenderStyle::setMinHeight));
428         gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyMaxHeight, &RenderStyle::maxHeight, &RenderStyle::setMaxHeight));
429 
430         gPropertyWrappers->append(new PropertyWrapper<unsigned short>(CSSPropertyBorderLeftWidth, &RenderStyle::borderLeftWidth, &RenderStyle::setBorderLeftWidth));
431         gPropertyWrappers->append(new PropertyWrapper<unsigned short>(CSSPropertyBorderRightWidth, &RenderStyle::borderRightWidth, &RenderStyle::setBorderRightWidth));
432         gPropertyWrappers->append(new PropertyWrapper<unsigned short>(CSSPropertyBorderTopWidth, &RenderStyle::borderTopWidth, &RenderStyle::setBorderTopWidth));
433         gPropertyWrappers->append(new PropertyWrapper<unsigned short>(CSSPropertyBorderBottomWidth, &RenderStyle::borderBottomWidth, &RenderStyle::setBorderBottomWidth));
434         gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyMarginLeft, &RenderStyle::marginLeft, &RenderStyle::setMarginLeft));
435         gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyMarginRight, &RenderStyle::marginRight, &RenderStyle::setMarginRight));
436         gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyMarginTop, &RenderStyle::marginTop, &RenderStyle::setMarginTop));
437         gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyMarginBottom, &RenderStyle::marginBottom, &RenderStyle::setMarginBottom));
438         gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyPaddingLeft, &RenderStyle::paddingLeft, &RenderStyle::setPaddingLeft));
439         gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyPaddingRight, &RenderStyle::paddingRight, &RenderStyle::setPaddingRight));
440         gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyPaddingTop, &RenderStyle::paddingTop, &RenderStyle::setPaddingTop));
441         gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyPaddingBottom, &RenderStyle::paddingBottom, &RenderStyle::setPaddingBottom));
442         gPropertyWrappers->append(new PropertyWrapper<const Color&>(CSSPropertyColor, &RenderStyle::color, &RenderStyle::setColor));
443 
444         gPropertyWrappers->append(new PropertyWrapper<const Color&>(CSSPropertyBackgroundColor, &RenderStyle::backgroundColor, &RenderStyle::setBackgroundColor));
445         gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyBackgroundPositionX, &RenderStyle::backgroundXPosition, &RenderStyle::setBackgroundXPosition));
446         gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyBackgroundPositionY, &RenderStyle::backgroundYPosition, &RenderStyle::setBackgroundYPosition));
447         gPropertyWrappers->append(new PropertyWrapper<LengthSize>(CSSPropertyWebkitBackgroundSize, &RenderStyle::backgroundSize, &RenderStyle::setBackgroundSize));
448 
449         gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyWebkitMaskPositionX, &RenderStyle::maskXPosition, &RenderStyle::setMaskXPosition));
450         gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyWebkitMaskPositionY, &RenderStyle::maskYPosition, &RenderStyle::setMaskYPosition));
451         gPropertyWrappers->append(new PropertyWrapper<LengthSize>(CSSPropertyWebkitMaskSize, &RenderStyle::maskSize, &RenderStyle::setMaskSize));
452 
453         gPropertyWrappers->append(new PropertyWrapper<int>(CSSPropertyFontSize, &RenderStyle::fontSize, &RenderStyle::setBlendedFontSize));
454         gPropertyWrappers->append(new PropertyWrapper<unsigned short>(CSSPropertyWebkitColumnRuleWidth, &RenderStyle::columnRuleWidth, &RenderStyle::setColumnRuleWidth));
455         gPropertyWrappers->append(new PropertyWrapper<float>(CSSPropertyWebkitColumnGap, &RenderStyle::columnGap, &RenderStyle::setColumnGap));
456         gPropertyWrappers->append(new PropertyWrapper<unsigned short>(CSSPropertyWebkitColumnCount, &RenderStyle::columnCount, &RenderStyle::setColumnCount));
457         gPropertyWrappers->append(new PropertyWrapper<float>(CSSPropertyWebkitColumnWidth, &RenderStyle::columnWidth, &RenderStyle::setColumnWidth));
458         gPropertyWrappers->append(new PropertyWrapper<short>(CSSPropertyWebkitBorderHorizontalSpacing, &RenderStyle::horizontalBorderSpacing, &RenderStyle::setHorizontalBorderSpacing));
459         gPropertyWrappers->append(new PropertyWrapper<short>(CSSPropertyWebkitBorderVerticalSpacing, &RenderStyle::verticalBorderSpacing, &RenderStyle::setVerticalBorderSpacing));
460         gPropertyWrappers->append(new PropertyWrapper<int>(CSSPropertyZIndex, &RenderStyle::zIndex, &RenderStyle::setZIndex));
461         gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyLineHeight, &RenderStyle::lineHeight, &RenderStyle::setLineHeight));
462         gPropertyWrappers->append(new PropertyWrapper<int>(CSSPropertyOutlineOffset, &RenderStyle::outlineOffset, &RenderStyle::setOutlineOffset));
463         gPropertyWrappers->append(new PropertyWrapper<unsigned short>(CSSPropertyOutlineWidth, &RenderStyle::outlineWidth, &RenderStyle::setOutlineWidth));
464         gPropertyWrappers->append(new PropertyWrapper<int>(CSSPropertyLetterSpacing, &RenderStyle::letterSpacing, &RenderStyle::setLetterSpacing));
465         gPropertyWrappers->append(new PropertyWrapper<int>(CSSPropertyWordSpacing, &RenderStyle::wordSpacing, &RenderStyle::setWordSpacing));
466         gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyTextIndent, &RenderStyle::textIndent, &RenderStyle::setTextIndent));
467 
468         gPropertyWrappers->append(new PropertyWrapper<float>(CSSPropertyWebkitPerspective, &RenderStyle::perspective, &RenderStyle::setPerspective));
469         gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyWebkitPerspectiveOriginX, &RenderStyle::perspectiveOriginX, &RenderStyle::setPerspectiveOriginX));
470         gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyWebkitPerspectiveOriginY, &RenderStyle::perspectiveOriginY, &RenderStyle::setPerspectiveOriginY));
471         gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyWebkitTransformOriginX, &RenderStyle::transformOriginX, &RenderStyle::setTransformOriginX));
472         gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyWebkitTransformOriginY, &RenderStyle::transformOriginY, &RenderStyle::setTransformOriginY));
473         gPropertyWrappers->append(new PropertyWrapper<float>(CSSPropertyWebkitTransformOriginZ, &RenderStyle::transformOriginZ, &RenderStyle::setTransformOriginZ));
474         gPropertyWrappers->append(new PropertyWrapper<const IntSize&>(CSSPropertyBorderTopLeftRadius, &RenderStyle::borderTopLeftRadius, &RenderStyle::setBorderTopLeftRadius));
475         gPropertyWrappers->append(new PropertyWrapper<const IntSize&>(CSSPropertyBorderTopRightRadius, &RenderStyle::borderTopRightRadius, &RenderStyle::setBorderTopRightRadius));
476         gPropertyWrappers->append(new PropertyWrapper<const IntSize&>(CSSPropertyBorderBottomLeftRadius, &RenderStyle::borderBottomLeftRadius, &RenderStyle::setBorderBottomLeftRadius));
477         gPropertyWrappers->append(new PropertyWrapper<const IntSize&>(CSSPropertyBorderBottomRightRadius, &RenderStyle::borderBottomRightRadius, &RenderStyle::setBorderBottomRightRadius));
478         gPropertyWrappers->append(new PropertyWrapper<EVisibility>(CSSPropertyVisibility, &RenderStyle::visibility, &RenderStyle::setVisibility));
479         gPropertyWrappers->append(new PropertyWrapper<float>(CSSPropertyZoom, &RenderStyle::zoom, &RenderStyle::setZoom));
480 
481 #if USE(ACCELERATED_COMPOSITING)
482         gPropertyWrappers->append(new PropertyWrapperAcceleratedOpacity());
483         gPropertyWrappers->append(new PropertyWrapperAcceleratedTransform());
484 #else
485         gPropertyWrappers->append(new PropertyWrapper<float>(CSSPropertyOpacity, &RenderStyle::opacity, &RenderStyle::setOpacity));
486         gPropertyWrappers->append(new PropertyWrapper<const TransformOperations&>(CSSPropertyWebkitTransform, &RenderStyle::transform, &RenderStyle::setTransform));
487 #endif
488 
489         gPropertyWrappers->append(new PropertyWrapperMaybeInvalidColor(CSSPropertyWebkitColumnRuleColor, &RenderStyle::columnRuleColor, &RenderStyle::setColumnRuleColor));
490         gPropertyWrappers->append(new PropertyWrapperMaybeInvalidColor(CSSPropertyWebkitTextStrokeColor, &RenderStyle::textStrokeColor, &RenderStyle::setTextStrokeColor));
491         gPropertyWrappers->append(new PropertyWrapperMaybeInvalidColor(CSSPropertyWebkitTextFillColor, &RenderStyle::textFillColor, &RenderStyle::setTextFillColor));
492         gPropertyWrappers->append(new PropertyWrapperMaybeInvalidColor(CSSPropertyBorderLeftColor, &RenderStyle::borderLeftColor, &RenderStyle::setBorderLeftColor));
493         gPropertyWrappers->append(new PropertyWrapperMaybeInvalidColor(CSSPropertyBorderRightColor, &RenderStyle::borderRightColor, &RenderStyle::setBorderRightColor));
494         gPropertyWrappers->append(new PropertyWrapperMaybeInvalidColor(CSSPropertyBorderTopColor, &RenderStyle::borderTopColor, &RenderStyle::setBorderTopColor));
495         gPropertyWrappers->append(new PropertyWrapperMaybeInvalidColor(CSSPropertyBorderBottomColor, &RenderStyle::borderBottomColor, &RenderStyle::setBorderBottomColor));
496         gPropertyWrappers->append(new PropertyWrapperMaybeInvalidColor(CSSPropertyOutlineColor, &RenderStyle::outlineColor, &RenderStyle::setOutlineColor));
497 
498         // These are for shadows
499         gPropertyWrappers->append(new PropertyWrapperShadow(CSSPropertyBoxShadow, &RenderStyle::boxShadow, &RenderStyle::setBoxShadow));
500         gPropertyWrappers->append(new PropertyWrapperShadow(CSSPropertyTextShadow, &RenderStyle::textShadow, &RenderStyle::setTextShadow));
501 
502 #if ENABLE(SVG)
503         gPropertyWrappers->append(new PropertyWrapper<float>(CSSPropertyFillOpacity, &RenderStyle::fillOpacity, &RenderStyle::setFillOpacity));
504         gPropertyWrappers->append(new PropertyWrapper<float>(CSSPropertyFloodOpacity, &RenderStyle::floodOpacity, &RenderStyle::setFloodOpacity));
505         gPropertyWrappers->append(new PropertyWrapper<float>(CSSPropertyStrokeOpacity, &RenderStyle::strokeOpacity, &RenderStyle::setStrokeOpacity));
506 #endif
507 
508         // TODO:
509         //
510         //  CSSPropertyVerticalAlign
511         //
512         // Compound properties that have components that should be animatable:
513         //
514         //  CSSPropertyWebkitColumns
515         //  CSSPropertyWebkitBoxReflect
516 
517         // Make sure unused slots have a value
518         for (unsigned int i = 0; i < static_cast<unsigned int>(numCSSProperties); ++i)
519             gPropertyWrapperMap[i] = cInvalidPropertyWrapperIndex;
520 
521         // First we put the non-shorthand property wrappers into the map, so the shorthand-building
522         // code can find them.
523         size_t n = gPropertyWrappers->size();
524         for (unsigned int i = 0; i < n; ++i) {
525             ASSERT((*gPropertyWrappers)[i]->property() - firstCSSProperty < numCSSProperties);
526             gPropertyWrapperMap[(*gPropertyWrappers)[i]->property() - firstCSSProperty] = i;
527         }
528 
529         // Now add the shorthand wrappers.
530         addShorthandProperties();
531     }
532 }
533 
addPropertyWrapper(int propertyID,PropertyWrapperBase * wrapper)534 static void addPropertyWrapper(int propertyID, PropertyWrapperBase* wrapper)
535 {
536     int propIndex = propertyID - firstCSSProperty;
537 
538     ASSERT(gPropertyWrapperMap[propIndex] == cInvalidPropertyWrapperIndex);
539 
540     unsigned wrapperIndex = gPropertyWrappers->size();
541     gPropertyWrappers->append(wrapper);
542     gPropertyWrapperMap[propIndex] = wrapperIndex;
543 }
544 
addShorthandProperties()545 static void addShorthandProperties()
546 {
547     static const int animatableShorthandProperties[] = {
548         CSSPropertyBackground,      // for background-color, background-position
549         CSSPropertyBackgroundPosition,
550         CSSPropertyWebkitMask,      // for mask-position
551         CSSPropertyWebkitMaskPosition,
552         CSSPropertyBorderTop, CSSPropertyBorderRight, CSSPropertyBorderBottom, CSSPropertyBorderLeft,
553         CSSPropertyBorderColor,
554         CSSPropertyBorderWidth,
555         CSSPropertyBorder,
556         CSSPropertyBorderSpacing,
557         CSSPropertyMargin,
558         CSSPropertyOutline,
559         CSSPropertyPadding,
560         CSSPropertyWebkitTextStroke,
561         CSSPropertyWebkitColumnRule,
562         CSSPropertyWebkitBorderRadius,
563         CSSPropertyWebkitTransformOrigin
564     };
565 
566     for (unsigned i = 0; i < sizeof(animatableShorthandProperties) / sizeof(animatableShorthandProperties[0]); ++i) {
567         int propertyID = animatableShorthandProperties[i];
568         CSSPropertyLonghand longhand = longhandForProperty(propertyID);
569         if (longhand.length() > 0)
570             addPropertyWrapper(propertyID, new ShorthandPropertyWrapper(propertyID, longhand));
571     }
572 
573     // 'font' is not in the shorthand map.
574     static const int animatableFontProperties[] = {
575         CSSPropertyFontSize,
576         CSSPropertyFontWeight
577     };
578 
579     CSSPropertyLonghand fontLonghand(animatableFontProperties, sizeof(animatableFontProperties) / sizeof(animatableFontProperties[0]));
580     addPropertyWrapper(CSSPropertyFont, new ShorthandPropertyWrapper(CSSPropertyFont, fontLonghand));
581 }
582 
wrapperForProperty(int propertyID)583 static PropertyWrapperBase* wrapperForProperty(int propertyID)
584 {
585     int propIndex = propertyID - firstCSSProperty;
586     if (propIndex >= 0 && propIndex < numCSSProperties) {
587         int wrapperIndex = gPropertyWrapperMap[propIndex];
588         if (wrapperIndex >= 0)
589             return (*gPropertyWrappers)[wrapperIndex];
590     }
591     return 0;
592 }
593 
AnimationBase(const Animation * transition,RenderObject * renderer,CompositeAnimation * compAnim)594 AnimationBase::AnimationBase(const Animation* transition, RenderObject* renderer, CompositeAnimation* compAnim)
595     : m_animState(AnimationStateNew)
596     , m_isAnimating(false)
597     , m_startTime(0)
598     , m_pauseTime(-1)
599     , m_requestedStartTime(0)
600     , m_object(renderer)
601     , m_animation(const_cast<Animation*>(transition))
602     , m_compAnim(compAnim)
603     , m_fallbackAnimating(false)
604     , m_transformFunctionListValid(false)
605     , m_nextIterationDuration(-1)
606     , m_next(0)
607 {
608     // Compute the total duration
609     m_totalDuration = -1;
610     if (m_animation->iterationCount() > 0)
611         m_totalDuration = m_animation->duration() * m_animation->iterationCount();
612 }
613 
~AnimationBase()614 AnimationBase::~AnimationBase()
615 {
616     m_compAnim->animationController()->removeFromStyleAvailableWaitList(this);
617     m_compAnim->animationController()->removeFromStartTimeResponseWaitList(this);
618 }
619 
propertiesEqual(int prop,const RenderStyle * a,const RenderStyle * b)620 bool AnimationBase::propertiesEqual(int prop, const RenderStyle* a, const RenderStyle* b)
621 {
622     ensurePropertyMap();
623     if (prop == cAnimateAll) {
624         size_t n = gPropertyWrappers->size();
625         for (unsigned int i = 0; i < n; ++i) {
626             PropertyWrapperBase* wrapper = (*gPropertyWrappers)[i];
627             // No point comparing shorthand wrappers for 'all'.
628             if (!wrapper->isShorthandWrapper() && !wrapper->equals(a, b))
629                 return false;
630         }
631     } else {
632         PropertyWrapperBase* wrapper = wrapperForProperty(prop);
633         if (wrapper)
634             return wrapper->equals(a, b);
635     }
636     return true;
637 }
638 
getPropertyAtIndex(int i,bool & isShorthand)639 int AnimationBase::getPropertyAtIndex(int i, bool& isShorthand)
640 {
641     ensurePropertyMap();
642     if (i < 0 || i >= static_cast<int>(gPropertyWrappers->size()))
643         return CSSPropertyInvalid;
644 
645     PropertyWrapperBase* wrapper = (*gPropertyWrappers)[i];
646     isShorthand = wrapper->isShorthandWrapper();
647     return wrapper->property();
648 }
649 
getNumProperties()650 int AnimationBase::getNumProperties()
651 {
652     ensurePropertyMap();
653     return gPropertyWrappers->size();
654 }
655 
656 // 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)657 bool AnimationBase::blendProperties(const AnimationBase* anim, int prop, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress)
658 {
659     ASSERT(prop != cAnimateAll);
660 
661     ensurePropertyMap();
662     PropertyWrapperBase* wrapper = wrapperForProperty(prop);
663     if (wrapper) {
664         wrapper->blend(anim, dst, a, b, progress);
665 #if USE(ACCELERATED_COMPOSITING)
666         return !wrapper->animationIsAccelerated() || anim->isFallbackAnimating();
667 #else
668         return true;
669 #endif
670     }
671 
672     return false;
673 }
674 
675 #if USE(ACCELERATED_COMPOSITING)
animationOfPropertyIsAccelerated(int prop)676 bool AnimationBase::animationOfPropertyIsAccelerated(int prop)
677 {
678     ensurePropertyMap();
679     PropertyWrapperBase* wrapper = wrapperForProperty(prop);
680     return wrapper ? wrapper->animationIsAccelerated() : false;
681 }
682 #endif
683 
setNeedsStyleRecalc(Node * node)684 void AnimationBase::setNeedsStyleRecalc(Node* node)
685 {
686     ASSERT(!node || (node->document() && !node->document()->inPageCache()));
687     if (node)
688         node->setNeedsStyleRecalc(AnimationStyleChange);
689 }
690 
duration() const691 double AnimationBase::duration() const
692 {
693     return m_animation->duration();
694 }
695 
playStatePlaying() const696 bool AnimationBase::playStatePlaying() const
697 {
698     return m_animation->playState() == AnimPlayStatePlaying;
699 }
700 
animationsMatch(const Animation * anim) const701 bool AnimationBase::animationsMatch(const Animation* anim) const
702 {
703     return m_animation->animationsMatch(anim);
704 }
705 
updateStateMachine(AnimStateInput input,double param)706 void AnimationBase::updateStateMachine(AnimStateInput input, double param)
707 {
708     // If we get AnimationStateInputRestartAnimation then we force a new animation, regardless of state.
709     if (input == AnimationStateInputMakeNew) {
710         if (m_animState == AnimationStateStartWaitStyleAvailable)
711             m_compAnim->animationController()->removeFromStyleAvailableWaitList(this);
712         m_animState = AnimationStateNew;
713         m_startTime = 0;
714         m_pauseTime = -1;
715         m_requestedStartTime = 0;
716         m_nextIterationDuration = -1;
717         endAnimation(false);
718         return;
719     }
720 
721     if (input == AnimationStateInputRestartAnimation) {
722         if (m_animState == AnimationStateStartWaitStyleAvailable)
723             m_compAnim->animationController()->removeFromStyleAvailableWaitList(this);
724         m_animState = AnimationStateNew;
725         m_startTime = 0;
726         m_pauseTime = -1;
727         m_requestedStartTime = 0;
728         m_nextIterationDuration = -1;
729         endAnimation(false);
730 
731         if (!paused())
732             updateStateMachine(AnimationStateInputStartAnimation, -1);
733         return;
734     }
735 
736     if (input == AnimationStateInputEndAnimation) {
737         if (m_animState == AnimationStateStartWaitStyleAvailable)
738             m_compAnim->animationController()->removeFromStyleAvailableWaitList(this);
739         m_animState = AnimationStateDone;
740         endAnimation(true);
741         return;
742     }
743 
744     if (input == AnimationStateInputPauseOverride) {
745         if (m_animState == AnimationStateStartWaitResponse) {
746             // If we are in AnimationStateStartWaitResponse, the animation will get canceled before
747             // we get a response, so move to the next state.
748             endAnimation(false);
749             updateStateMachine(AnimationStateInputStartTimeSet, beginAnimationUpdateTime());
750         }
751         return;
752     }
753 
754     if (input == AnimationStateInputResumeOverride) {
755         if (m_animState == AnimationStateLooping || m_animState == AnimationStateEnding) {
756             // Start the animation
757             startAnimation(m_startTime);
758         }
759         return;
760     }
761 
762     // Execute state machine
763     switch (m_animState) {
764         case AnimationStateNew:
765             ASSERT(input == AnimationStateInputStartAnimation || input == AnimationStateInputPlayStateRunnning || input == AnimationStateInputPlayStatePaused);
766             if (input == AnimationStateInputStartAnimation || input == AnimationStateInputPlayStateRunnning) {
767                 m_requestedStartTime = beginAnimationUpdateTime();
768                 m_animState = AnimationStateStartWaitTimer;
769             }
770             break;
771         case AnimationStateStartWaitTimer:
772             ASSERT(input == AnimationStateInputStartTimerFired || input == AnimationStateInputPlayStatePaused);
773 
774             if (input == AnimationStateInputStartTimerFired) {
775                 ASSERT(param >= 0);
776                 // Start timer has fired, tell the animation to start and wait for it to respond with start time
777                 m_animState = AnimationStateStartWaitStyleAvailable;
778                 m_compAnim->animationController()->addToStyleAvailableWaitList(this);
779 
780                 // Trigger a render so we can start the animation
781                 if (m_object)
782                     m_compAnim->animationController()->addNodeChangeToDispatch(m_object->node());
783             } else {
784                 ASSERT(!paused());
785                 // We're waiting for the start timer to fire and we got a pause. Cancel the timer, pause and wait
786                 m_pauseTime = beginAnimationUpdateTime();
787                 m_animState = AnimationStatePausedWaitTimer;
788             }
789             break;
790         case AnimationStateStartWaitStyleAvailable:
791             ASSERT(input == AnimationStateInputStyleAvailable || input == AnimationStateInputPlayStatePaused);
792 
793             // Start timer has fired, tell the animation to start and wait for it to respond with start time
794             m_animState = AnimationStateStartWaitResponse;
795 
796             overrideAnimations();
797 
798             // Send start event, if needed
799             onAnimationStart(0); // The elapsedTime is always 0 here
800 
801             // Start the animation
802             if (overridden()) {
803                 // We won't try to start accelerated animations if we are overridden and
804                 // just move on to the next state.
805                 m_animState = AnimationStateStartWaitResponse;
806                 m_fallbackAnimating = true;
807                 updateStateMachine(AnimationStateInputStartTimeSet, beginAnimationUpdateTime());
808             }
809             else {
810                 bool started = startAnimation(0);
811                 m_compAnim->animationController()->addToStartTimeResponseWaitList(this, started);
812                 m_fallbackAnimating = !started;
813             }
814             break;
815         case AnimationStateStartWaitResponse:
816             ASSERT(input == AnimationStateInputStartTimeSet || input == AnimationStateInputPlayStatePaused);
817 
818             if (input == AnimationStateInputStartTimeSet) {
819                 ASSERT(param >= 0);
820                 // We have a start time, set it, unless the startTime is already set
821                 if (m_startTime <= 0)
822                     m_startTime = param;
823 
824                 // Decide whether to go into looping or ending state
825                 goIntoEndingOrLoopingState();
826 
827                 // Dispatch updateStyleIfNeeded so we can start the animation
828                 if (m_object)
829                     m_compAnim->animationController()->addNodeChangeToDispatch(m_object->node());
830             } else {
831                 // We are pausing while waiting for a start response. Cancel the animation and wait. When
832                 // we unpause, we will act as though the start timer just fired
833                 m_pauseTime = -1;
834                 endAnimation(false);
835                 m_animState = AnimationStatePausedWaitResponse;
836             }
837             break;
838         case AnimationStateLooping:
839             ASSERT(input == AnimationStateInputLoopTimerFired || input == AnimationStateInputPlayStatePaused);
840 
841             if (input == AnimationStateInputLoopTimerFired) {
842                 ASSERT(param >= 0);
843                 // Loop timer fired, loop again or end.
844                 onAnimationIteration(param);
845 
846                 // Decide whether to go into looping or ending state
847                 goIntoEndingOrLoopingState();
848             } else {
849                 // We are pausing while running. Cancel the animation and wait
850                 m_pauseTime = beginAnimationUpdateTime();
851                 endAnimation(false);
852                 m_animState = AnimationStatePausedRun;
853             }
854             break;
855         case AnimationStateEnding:
856             ASSERT(input == AnimationStateInputEndTimerFired || input == AnimationStateInputPlayStatePaused);
857 
858             if (input == AnimationStateInputEndTimerFired) {
859                 ASSERT(param >= 0);
860                 // End timer fired, finish up
861                 onAnimationEnd(param);
862 
863                 m_animState = AnimationStateDone;
864 
865                 if (m_object) {
866                     resumeOverriddenAnimations();
867 
868                     // Fire off another style change so we can set the final value
869                     m_compAnim->animationController()->addNodeChangeToDispatch(m_object->node());
870                 }
871             } else {
872                 // We are pausing while running. Cancel the animation and wait
873                 m_pauseTime = beginAnimationUpdateTime();
874                 endAnimation(false);
875                 m_animState = AnimationStatePausedRun;
876             }
877             // |this| may be deleted here
878             break;
879         case AnimationStatePausedWaitTimer:
880             ASSERT(input == AnimationStateInputPlayStateRunnning);
881             ASSERT(paused());
882             // Update the times
883             m_startTime += beginAnimationUpdateTime() - m_pauseTime;
884             m_pauseTime = -1;
885 
886             // we were waiting for the start timer to fire, go back and wait again
887             m_animState = AnimationStateNew;
888             updateStateMachine(AnimationStateInputStartAnimation, 0);
889             break;
890         case AnimationStatePausedWaitResponse:
891         case AnimationStatePausedRun:
892             // We treat these two cases the same. The only difference is that, when we are in
893             // AnimationStatePausedWaitResponse, we don't yet have a valid startTime, so we send 0 to startAnimation.
894             // When the AnimationStateInputStartTimeSet comes in and we were in AnimationStatePausedRun, we will notice
895             // that we have already set the startTime and will ignore it.
896             ASSERT(input == AnimationStateInputPlayStateRunnning || input == AnimationStateInputStartTimeSet);
897             ASSERT(paused());
898 
899             // If we are paused, but we get the callback that notifies us that an accelerated animation started,
900             // then we ignore the start time and just move into the paused-run state.
901             if (m_animState == AnimationStatePausedWaitResponse && input == AnimationStateInputStartTimeSet) {
902                 m_animState = AnimationStatePausedRun;
903                 ASSERT(m_startTime == 0);
904                 m_startTime = param;
905                 m_pauseTime += m_startTime;
906                 break;
907             }
908 
909             // Update the times
910             if (m_animState == AnimationStatePausedRun)
911                 m_startTime += beginAnimationUpdateTime() - m_pauseTime;
912             else
913                 m_startTime = 0;
914             m_pauseTime = -1;
915 
916             // We were waiting for a begin time response from the animation, go back and wait again
917             m_animState = AnimationStateStartWaitResponse;
918 
919             // Start the animation
920             if (overridden()) {
921                 // We won't try to start accelerated animations if we are overridden and
922                 // just move on to the next state.
923                 updateStateMachine(AnimationStateInputStartTimeSet, beginAnimationUpdateTime());
924                 m_fallbackAnimating = true;
925             } else {
926                 bool started = startAnimation(m_startTime);
927                 m_compAnim->animationController()->addToStartTimeResponseWaitList(this, started);
928                 m_fallbackAnimating = !started;
929             }
930             break;
931         case AnimationStateDone:
932             // We're done. Stay in this state until we are deleted
933             break;
934     }
935 }
936 
fireAnimationEventsIfNeeded()937 void AnimationBase::fireAnimationEventsIfNeeded()
938 {
939     // If we are waiting for the delay time to expire and it has, go to the next state
940     if (m_animState != AnimationStateStartWaitTimer && m_animState != AnimationStateLooping && m_animState != AnimationStateEnding)
941         return;
942 
943     // We have to make sure to keep a ref to the this pointer, because it could get destroyed
944     // during an animation callback that might get called. Since the owner is a CompositeAnimation
945     // and it ref counts this object, we will keep a ref to that instead. That way the AnimationBase
946     // can still access the resources of its CompositeAnimation as needed.
947     RefPtr<AnimationBase> protector(this);
948     RefPtr<CompositeAnimation> compProtector(m_compAnim);
949 
950     // Check for start timeout
951     if (m_animState == AnimationStateStartWaitTimer) {
952         if (beginAnimationUpdateTime() - m_requestedStartTime >= m_animation->delay())
953             updateStateMachine(AnimationStateInputStartTimerFired, 0);
954         return;
955     }
956 
957     double elapsedDuration = beginAnimationUpdateTime() - m_startTime;
958     // FIXME: we need to ensure that elapsedDuration is never < 0. If it is, this suggests that
959     // we had a recalcStyle() outside of beginAnimationUpdate()/endAnimationUpdate().
960     // Also check in getTimeToNextEvent().
961     elapsedDuration = max(elapsedDuration, 0.0);
962 
963     // Check for end timeout
964     if (m_totalDuration >= 0 && elapsedDuration >= m_totalDuration) {
965         // Fire an end event
966         updateStateMachine(AnimationStateInputEndTimerFired, m_totalDuration);
967     } else {
968         // Check for iteration timeout
969         if (m_nextIterationDuration < 0) {
970             // Hasn't been set yet, set it
971             double durationLeft = m_animation->duration() - fmod(elapsedDuration, m_animation->duration());
972             m_nextIterationDuration = elapsedDuration + durationLeft;
973         }
974 
975         if (elapsedDuration >= m_nextIterationDuration) {
976             // Set to the next iteration
977             double previous = m_nextIterationDuration;
978             double durationLeft = m_animation->duration() - fmod(elapsedDuration, m_animation->duration());
979             m_nextIterationDuration = elapsedDuration + durationLeft;
980 
981             // Send the event
982             updateStateMachine(AnimationStateInputLoopTimerFired, previous);
983         }
984     }
985 }
986 
updatePlayState(bool run)987 void AnimationBase::updatePlayState(bool run)
988 {
989     if (paused() == run || isNew())
990         updateStateMachine(run ? AnimationStateInputPlayStateRunnning : AnimationStateInputPlayStatePaused, -1);
991 }
992 
timeToNextService()993 double AnimationBase::timeToNextService()
994 {
995     // Returns the time at which next service is required. -1 means no service is required. 0 means
996     // service is required now, and > 0 means service is required that many seconds in the future.
997     if (paused() || isNew())
998         return -1;
999 
1000     if (m_animState == AnimationStateStartWaitTimer) {
1001         double timeFromNow = m_animation->delay() - (beginAnimationUpdateTime() - m_requestedStartTime);
1002         return max(timeFromNow, 0.0);
1003     }
1004 
1005     fireAnimationEventsIfNeeded();
1006 
1007     // In all other cases, we need service right away.
1008     return 0;
1009 }
1010 
progress(double scale,double offset,const TimingFunction * tf) const1011 double AnimationBase::progress(double scale, double offset, const TimingFunction* tf) const
1012 {
1013     if (preActive())
1014         return 0;
1015 
1016     double elapsedTime = getElapsedTime();
1017 
1018     double dur = m_animation->duration();
1019     if (m_animation->iterationCount() > 0)
1020         dur *= m_animation->iterationCount();
1021 
1022     if (postActive() || !m_animation->duration() || (m_animation->iterationCount() > 0 && elapsedTime >= dur))
1023         return 1.0;
1024 
1025     // Compute the fractional time, taking into account direction.
1026     // There is no need to worry about iterations, we assume that we would have
1027     // short circuited above if we were done.
1028     double fractionalTime = elapsedTime / m_animation->duration();
1029     int integralTime = static_cast<int>(fractionalTime);
1030     fractionalTime -= integralTime;
1031 
1032     if (m_animation->direction() && (integralTime & 1))
1033         fractionalTime = 1 - fractionalTime;
1034 
1035     if (scale != 1 || offset)
1036         fractionalTime = (fractionalTime - offset) * scale;
1037 
1038     if (!tf)
1039         tf = &m_animation->timingFunction();
1040 
1041     if (tf->type() == LinearTimingFunction)
1042         return fractionalTime;
1043 
1044     // Cubic bezier.
1045     double result = solveCubicBezierFunction(tf->x1(),
1046                                             tf->y1(),
1047                                             tf->x2(),
1048                                             tf->y2(),
1049                                             fractionalTime, m_animation->duration());
1050     return result;
1051 }
1052 
getTimeToNextEvent(double & time,bool & isLooping) const1053 void AnimationBase::getTimeToNextEvent(double& time, bool& isLooping) const
1054 {
1055     // Decide when the end or loop event needs to fire
1056     double totalDuration = -1;
1057     if (m_animation->iterationCount() > 0)
1058         totalDuration = m_animation->duration() * m_animation->iterationCount();
1059 
1060     const double elapsedDuration = max(beginAnimationUpdateTime() - m_startTime, 0.0);
1061     double durationLeft = 0;
1062     double nextIterationTime = m_totalDuration;
1063 
1064     if (m_totalDuration < 0 || elapsedDuration < m_totalDuration) {
1065         durationLeft = m_animation->duration() > 0 ? (m_animation->duration() - fmod(elapsedDuration, m_animation->duration())) : 0;
1066         nextIterationTime = elapsedDuration + durationLeft;
1067     }
1068 
1069     if (m_totalDuration < 0 || nextIterationTime < m_totalDuration) {
1070         // We are not at the end yet
1071         ASSERT(nextIterationTime > 0);
1072         isLooping = true;
1073     } else {
1074         // We are at the end
1075         isLooping = false;
1076     }
1077 
1078     time = durationLeft;
1079 }
1080 
goIntoEndingOrLoopingState()1081 void AnimationBase::goIntoEndingOrLoopingState()
1082 {
1083     double t;
1084     bool isLooping;
1085     getTimeToNextEvent(t, isLooping);
1086     m_animState = isLooping ? AnimationStateLooping : AnimationStateEnding;
1087 }
1088 
freezeAtTime(double t)1089 void AnimationBase::freezeAtTime(double t)
1090 {
1091     ASSERT(m_startTime);        // if m_startTime is zero, we haven't started yet, so we'll get a bad pause time.
1092     m_pauseTime = m_startTime + t - m_animation->delay();
1093 
1094 #if USE(ACCELERATED_COMPOSITING)
1095     if (m_object && m_object->hasLayer()) {
1096         RenderLayer* layer = toRenderBoxModelObject(m_object)->layer();
1097         if (layer->isComposited())
1098             layer->backing()->suspendAnimations(m_pauseTime);
1099     }
1100 #endif
1101 }
1102 
beginAnimationUpdateTime() const1103 double AnimationBase::beginAnimationUpdateTime() const
1104 {
1105     return m_compAnim->animationController()->beginAnimationUpdateTime();
1106 }
1107 
getElapsedTime() const1108 double AnimationBase::getElapsedTime() const
1109 {
1110     if (paused())
1111         return m_pauseTime - m_startTime;
1112     if (m_startTime <= 0)
1113         return 0;
1114     if (postActive())
1115         return 1;
1116     return beginAnimationUpdateTime() - m_startTime;
1117 }
1118 
1119 } // namespace WebCore
1120