Upstream version 5.34.92.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / core / frame / animation / CSSPropertyAnimation.cpp
1 /*
2  * Copyright (C) 2007, 2008, 2009 Apple Inc. All rights reserved.
3  * Copyright (C) 2012 Adobe Systems Incorporated. All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * 1.  Redistributions of source code must retain the above copyright
10  *     notice, this list of conditions and the following disclaimer.
11  * 2.  Redistributions in binary form must reproduce the above copyright
12  *     notice, this list of conditions and the following disclaimer in the
13  *     documentation and/or other materials provided with the distribution.
14  * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
15  *     its contributors may be used to endorse or promote products derived
16  *     from this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
19  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
22  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29
30 #include "config.h"
31 #include "core/frame/animation/CSSPropertyAnimation.h"
32
33 #include <algorithm>
34 #include "StylePropertyShorthand.h"
35 #include "core/animation/css/CSSAnimations.h"
36 #include "core/css/CSSCrossfadeValue.h"
37 #include "core/css/CSSImageValue.h"
38 #include "core/css/CSSPrimitiveValue.h"
39 #include "core/fetch/ImageResource.h"
40 #include "core/frame/animation/AnimationBase.h"
41 #include "core/rendering/ClipPathOperation.h"
42 #include "core/rendering/RenderBox.h"
43 #include "core/rendering/style/RenderStyle.h"
44 #include "core/rendering/style/ShadowList.h"
45 #include "core/rendering/style/StyleFetchedImage.h"
46 #include "core/rendering/style/StyleGeneratedImage.h"
47 #include "platform/FloatConversion.h"
48 #include "wtf/Noncopyable.h"
49
50 namespace WebCore {
51
52 template <typename T>
53 static inline T blendFunc(const AnimationBase*, T from, T to, double progress)
54 {
55     return blend(from, to, progress);
56 }
57
58 static inline float blendFunc(const AnimationBase*, float from, float to, double progress)
59 {
60     return narrowPrecisionToFloat(from + (to - from) * progress);
61 }
62
63 static inline Color blendFunc(const AnimationBase*, const Color& from, const Color& to, double progress)
64 {
65     return blend(from, to, progress);
66 }
67
68 static inline Length blendFunc(const AnimationBase*, const Length& from, const Length& to, double progress)
69 {
70     return to.blend(from, progress, ValueRangeAll);
71 }
72
73 static inline BorderImageLength blendFunc(const AnimationBase* anim, const BorderImageLength& from, const BorderImageLength& to, double progress)
74 {
75     if (from.isNumber() && to.isNumber())
76         return BorderImageLength(blendFunc(anim, from.number(), to.number(), progress));
77
78     if (from.isLength() && to.isLength())
79         return BorderImageLength(blendFunc(anim, from.length(), to.length(), progress));
80
81     // FIXME: Converting numbers to lengths using the computed border
82     // width would make it possible to interpolate between numbers and
83     // lengths.
84     // https://code.google.com/p/chromium/issues/detail?id=316164
85     return to;
86 }
87
88 static inline BorderImageLengthBox blendFunc(const AnimationBase* anim, const BorderImageLengthBox& from,
89     const BorderImageLengthBox& to, double progress)
90 {
91     return BorderImageLengthBox(blendFunc(anim, from.top(), to.top(), progress),
92         blendFunc(anim, from.right(), to.right(), progress),
93         blendFunc(anim, from.bottom(), to.bottom(), progress),
94         blendFunc(anim, from.left(), to.left(), progress));
95 }
96
97 static inline LengthSize blendFunc(const AnimationBase* anim, const LengthSize& from, const LengthSize& to, double progress)
98 {
99     return LengthSize(blendFunc(anim, from.width(), to.width(), progress),
100         blendFunc(anim, from.height(), to.height(), progress));
101 }
102
103 static inline LengthPoint blendFunc(const AnimationBase* anim, const LengthPoint& from, const LengthPoint& to, double progress)
104 {
105     return LengthPoint(blendFunc(anim, from.x(), to.x(), progress), blendFunc(anim, from.y(), to.y(), progress));
106 }
107
108 static inline TransformOperations blendFunc(const AnimationBase* anim, const TransformOperations& from, const TransformOperations& to, double progress)
109 {
110     if (anim->isTransformFunctionListValid())
111         return to.blendByMatchingOperations(from, progress);
112     return to.blendByUsingMatrixInterpolation(from, progress);
113 }
114
115 static inline PassRefPtr<ClipPathOperation> blendFunc(const AnimationBase*, ClipPathOperation* from, ClipPathOperation* to, double progress)
116 {
117     // Other clip-path operations than BasicShapes can not be animated.
118     if (!from || !to || from->type() != ClipPathOperation::SHAPE || to->type() != ClipPathOperation::SHAPE)
119         return to;
120
121     const BasicShape* fromShape = toShapeClipPathOperation(from)->basicShape();
122     const BasicShape* toShape = toShapeClipPathOperation(to)->basicShape();
123
124     if (!fromShape->canBlend(toShape))
125         return to;
126
127     return ShapeClipPathOperation::create(toShape->blend(fromShape, progress));
128 }
129
130 static inline PassRefPtr<ShapeValue> blendFunc(const AnimationBase*, ShapeValue* from, ShapeValue* to, double progress)
131 {
132     // FIXME Bug 102723: Shape-inside should be able to animate a value of 'outside-shape' when shape-outside is set to a BasicShape
133     if (!from || !to || from->type() != ShapeValue::Shape || to->type() != ShapeValue::Shape)
134         return to;
135
136     const BasicShape* fromShape = from->shape();
137     const BasicShape* toShape = to->shape();
138
139     if (!fromShape->canBlend(toShape))
140         return to;
141
142     return ShapeValue::createShapeValue(toShape->blend(fromShape, progress));
143 }
144
145 static inline FilterOperations blendFunc(const AnimationBase* anim, const FilterOperations& from, const FilterOperations& to, double progress)
146 {
147     FilterOperations result;
148
149     // If we have a filter function list, use that to do a per-function animation.
150     if (anim->filterFunctionListsMatch()) {
151         size_t fromSize = from.operations().size();
152         size_t toSize = to.operations().size();
153         size_t size = max(fromSize, toSize);
154         for (size_t i = 0; i < size; i++) {
155             const FilterOperation* fromOp = (i < fromSize) ? from.operations()[i].get() : 0;
156             const FilterOperation* toOp = (i < toSize) ? to.operations()[i].get() : 0;
157             RefPtr<FilterOperation> blendedOp = FilterOperation::blend(fromOp, toOp, progress);
158             if (blendedOp)
159                 result.operations().append(blendedOp);
160             else
161                 ASSERT_NOT_REACHED();
162         }
163     } else {
164         // If the filter function lists don't match, we could try to cross-fade, but don't yet have a way to represent that in CSS.
165         // For now we'll just fail to animate.
166         result = to;
167     }
168
169     return result;
170 }
171
172 static inline EVisibility blendFunc(const AnimationBase* anim, EVisibility from, EVisibility to, double progress)
173 {
174     // Any non-zero result means we consider the object to be visible. Only at 0 do we consider the object to be
175     // invisible. The invisible value we use (HIDDEN vs. COLLAPSE) depends on the specified from/to values.
176     double fromVal = from == VISIBLE ? 1. : 0.;
177     double toVal = to == VISIBLE ? 1. : 0.;
178     if (fromVal == toVal)
179         return to;
180     double result = blendFunc(anim, fromVal, toVal, progress);
181     return result > 0. ? VISIBLE : (to != VISIBLE ? to : from);
182 }
183
184 static inline LengthBox blendFunc(const AnimationBase* anim, const LengthBox& from, const LengthBox& to, double progress)
185 {
186     // Length types have to match to animate
187     if (from.top().type() != to.top().type()
188         || from.right().type() != to.right().type()
189         || from.bottom().type() != to.bottom().type()
190         || from.left().type() != to.left().type())
191         return to;
192
193     LengthBox result(blendFunc(anim, from.top(), to.top(), progress),
194                      blendFunc(anim, from.right(), to.right(), progress),
195                      blendFunc(anim, from.bottom(), to.bottom(), progress),
196                      blendFunc(anim, from.left(), to.left(), progress));
197     return result;
198 }
199
200 static inline PassRefPtr<SVGLength> blendFunc(const AnimationBase*, PassRefPtr<SVGLength> from, PassRefPtr<SVGLength> to, double progress)
201 {
202     return to->blend(from, narrowPrecisionToFloat(progress));
203 }
204
205 static inline PassRefPtr<SVGLengthList> blendFunc(const AnimationBase*, PassRefPtr<SVGLengthList> passFrom, PassRefPtr<SVGLengthList> passTo, double progress)
206 {
207     RefPtr<SVGLengthList> from = passFrom;
208     RefPtr<SVGLengthList> to = passTo;
209
210     size_t fromLength = from->numberOfItems();
211     size_t toLength = to->numberOfItems();
212     if (!fromLength)
213         return !progress ? from->clone() : to->clone();
214     if (!toLength)
215         return progress == 1 ? from->clone() : to->clone();
216
217     size_t resultLength = fromLength;
218     if (fromLength != toLength) {
219         if (!(fromLength % toLength))
220             resultLength = fromLength;
221         else if (!(toLength % fromLength))
222             resultLength = toLength;
223         else
224             resultLength = fromLength * toLength;
225     }
226     RefPtr<SVGLengthList> result = SVGLengthList::create();
227     for (size_t i = 0; i < resultLength; ++i)
228         result->append(to->at(i % toLength)->blend(from->at(i % fromLength), narrowPrecisionToFloat(progress)));
229     return result;
230 }
231
232 static inline PassRefPtr<StyleImage> crossfadeBlend(const AnimationBase*, StyleFetchedImage* fromStyleImage, StyleFetchedImage* toStyleImage, double progress)
233 {
234     // If progress is at one of the extremes, we want getComputedStyle to show the image,
235     // not a completed cross-fade, so we hand back one of the existing images.
236     if (!progress)
237         return fromStyleImage;
238     if (progress == 1)
239         return toStyleImage;
240
241     ImageResource* fromImageResource = static_cast<ImageResource*>(fromStyleImage->data());
242     ImageResource* toImageResource = static_cast<ImageResource*>(toStyleImage->data());
243
244     RefPtr<CSSImageValue> fromImageValue = CSSImageValue::create(fromImageResource->url(), fromStyleImage);
245     RefPtr<CSSImageValue> toImageValue = CSSImageValue::create(toImageResource->url(), toStyleImage);
246     RefPtr<CSSCrossfadeValue> crossfadeValue = CSSCrossfadeValue::create(fromImageValue, toImageValue);
247
248     crossfadeValue->setPercentage(CSSPrimitiveValue::create(progress, CSSPrimitiveValue::CSS_NUMBER));
249
250     return StyleGeneratedImage::create(crossfadeValue.get());
251 }
252
253 static inline PassRefPtr<StyleImage> blendFunc(const AnimationBase* anim, StyleImage* from, StyleImage* to, double progress)
254 {
255     if (!from || !to)
256         return to;
257
258     if (from->isImageResource() && to->isImageResource())
259         return crossfadeBlend(anim, toStyleFetchedImage(from), toStyleFetchedImage(to), progress);
260
261     // FIXME: Support transitioning generated images as well. (gradients, etc.)
262
263     return to;
264 }
265
266 class AnimationPropertyWrapperBase {
267     WTF_MAKE_NONCOPYABLE(AnimationPropertyWrapperBase);
268     WTF_MAKE_FAST_ALLOCATED;
269 public:
270     AnimationPropertyWrapperBase(CSSPropertyID prop)
271         : m_prop(prop)
272     {
273     }
274
275     virtual ~AnimationPropertyWrapperBase() { }
276
277     virtual bool isShorthandWrapper() const { return false; }
278     virtual bool equals(const RenderStyle* a, const RenderStyle* b) const = 0;
279     virtual void blend(const AnimationBase*, RenderStyle*, const RenderStyle*, const RenderStyle*, double) const = 0;
280
281     CSSPropertyID property() const { return m_prop; }
282
283     virtual bool animationIsAccelerated() const { return false; }
284
285 private:
286     CSSPropertyID m_prop;
287 };
288
289 static int gPropertyWrapperMap[numCSSProperties];
290 static const int cInvalidPropertyWrapperIndex = -1;
291 static Vector<AnimationPropertyWrapperBase*>* gPropertyWrappers = 0;
292
293 static void addPropertyWrapper(CSSPropertyID propertyID, AnimationPropertyWrapperBase* wrapper)
294 {
295     int propIndex = propertyID - firstCSSProperty;
296
297     ASSERT(gPropertyWrapperMap[propIndex] == cInvalidPropertyWrapperIndex);
298
299     unsigned wrapperIndex = gPropertyWrappers->size();
300     gPropertyWrappers->append(wrapper);
301     gPropertyWrapperMap[propIndex] = wrapperIndex;
302 }
303
304 static AnimationPropertyWrapperBase* wrapperForProperty(CSSPropertyID propertyID)
305 {
306     int propIndex = propertyID - firstCSSProperty;
307     if (propIndex >= 0 && propIndex < numCSSProperties) {
308         int wrapperIndex = gPropertyWrapperMap[propIndex];
309         if (wrapperIndex >= 0)
310             return (*gPropertyWrappers)[wrapperIndex];
311     }
312     return 0;
313 }
314
315 template <typename T>
316 class PropertyWrapperGetter : public AnimationPropertyWrapperBase {
317 public:
318     PropertyWrapperGetter(CSSPropertyID prop, T (RenderStyle::*getter)() const)
319         : AnimationPropertyWrapperBase(prop)
320         , m_getter(getter)
321     {
322     }
323
324     virtual bool equals(const RenderStyle* a, const RenderStyle* b) const
325     {
326         // If the style pointers are the same, don't bother doing the test.
327         // If either is null, return false. If both are null, return true.
328         if ((!a && !b) || a == b)
329             return true;
330         if (!a || !b)
331             return false;
332         return (a->*m_getter)() == (b->*m_getter)();
333     }
334
335 protected:
336     T (RenderStyle::*m_getter)() const;
337 };
338
339 template <typename T>
340 class PropertyWrapper : public PropertyWrapperGetter<T> {
341 public:
342     PropertyWrapper(CSSPropertyID prop, T (RenderStyle::*getter)() const, void (RenderStyle::*setter)(T))
343         : PropertyWrapperGetter<T>(prop, getter)
344         , m_setter(setter)
345     {
346     }
347
348     virtual void blend(const AnimationBase* anim, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress) const
349     {
350         (dst->*m_setter)(blendFunc(anim, (a->*PropertyWrapperGetter<T>::m_getter)(), (b->*PropertyWrapperGetter<T>::m_getter)(), progress));
351     }
352
353 protected:
354     void (RenderStyle::*m_setter)(T);
355 };
356
357 class NonNegativeLengthWrapper FINAL : public PropertyWrapper<Length> {
358 public:
359     NonNegativeLengthWrapper(CSSPropertyID prop, Length (RenderStyle::*getter)() const, void (RenderStyle::*setter)(Length))
360     : PropertyWrapper<Length>(prop, getter, setter)
361     {
362     }
363
364     virtual void blend(const AnimationBase* anim, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress) const OVERRIDE
365     {
366         Length from = (a->*PropertyWrapperGetter<Length>::m_getter)();
367         Length to = (b->*PropertyWrapperGetter<Length>::m_getter)();
368         (dst->*PropertyWrapper<Length>::m_setter)(to.blend(from, progress, ValueRangeNonNegative));
369     }
370 };
371
372 template <typename T>
373 class RefCountedPropertyWrapper : public PropertyWrapperGetter<T*> {
374 public:
375     RefCountedPropertyWrapper(CSSPropertyID prop, T* (RenderStyle::*getter)() const, void (RenderStyle::*setter)(PassRefPtr<T>))
376         : PropertyWrapperGetter<T*>(prop, getter)
377         , m_setter(setter)
378     {
379     }
380
381     virtual void blend(const AnimationBase* anim, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress) const
382     {
383         (dst->*m_setter)(blendFunc(anim, (a->*PropertyWrapperGetter<T*>::m_getter)(), (b->*PropertyWrapperGetter<T*>::m_getter)(), progress));
384     }
385
386     virtual bool equals(const RenderStyle* a, const RenderStyle* b) const OVERRIDE
387     {
388         if (a == b)
389             return true;
390         if (!a || !b)
391             return false;
392         const T* aValue = (a->*this->m_getter)();
393         const T* bValue = (b->*this->m_getter)();
394         if (aValue == bValue)
395             return true;
396         if (!aValue || !bValue)
397             return false;
398         return *aValue == *bValue;
399     }
400
401 protected:
402     void (RenderStyle::*m_setter)(PassRefPtr<T>);
403 };
404
405
406 class PropertyWrapperClipPath : public RefCountedPropertyWrapper<ClipPathOperation> {
407 public:
408     PropertyWrapperClipPath(CSSPropertyID prop, ClipPathOperation* (RenderStyle::*getter)() const, void (RenderStyle::*setter)(PassRefPtr<ClipPathOperation>))
409         : RefCountedPropertyWrapper<ClipPathOperation>(prop, getter, setter)
410     {
411     }
412 };
413
414 class PropertyWrapperShape : public RefCountedPropertyWrapper<ShapeValue> {
415 public:
416     PropertyWrapperShape(CSSPropertyID prop, ShapeValue* (RenderStyle::*getter)() const, void (RenderStyle::*setter)(PassRefPtr<ShapeValue>))
417         : RefCountedPropertyWrapper<ShapeValue>(prop, getter, setter)
418     {
419     }
420 };
421
422 class StyleImagePropertyWrapper FINAL : public RefCountedPropertyWrapper<StyleImage> {
423 public:
424     StyleImagePropertyWrapper(CSSPropertyID prop, StyleImage* (RenderStyle::*getter)() const, void (RenderStyle::*setter)(PassRefPtr<StyleImage>))
425         : RefCountedPropertyWrapper<StyleImage>(prop, getter, setter)
426     {
427     }
428
429     virtual bool equals(const RenderStyle* a, const RenderStyle* b) const OVERRIDE
430     {
431        // If the style pointers are the same, don't bother doing the test.
432        // If either is null, return false. If both are null, return true.
433        if (a == b)
434            return true;
435        if (!a || !b)
436             return false;
437
438         StyleImage* imageA = (a->*m_getter)();
439         StyleImage* imageB = (b->*m_getter)();
440         return StyleImage::imagesEquivalent(imageA, imageB);
441     }
442 };
443
444 class PropertyWrapperColor FINAL : public PropertyWrapperGetter<Color> {
445 public:
446     PropertyWrapperColor(CSSPropertyID prop, Color (RenderStyle::*getter)() const, void (RenderStyle::*setter)(const Color&))
447         : PropertyWrapperGetter<Color>(prop, getter)
448         , m_setter(setter)
449     {
450     }
451
452     virtual void blend(const AnimationBase* anim, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress) const OVERRIDE
453     {
454         (dst->*m_setter)(blendFunc(anim, (a->*PropertyWrapperGetter<Color>::m_getter)(), (b->*PropertyWrapperGetter<Color>::m_getter)(), progress));
455     }
456
457 protected:
458     void (RenderStyle::*m_setter)(const Color&);
459 };
460
461 class PropertyWrapperAcceleratedOpacity FINAL : public PropertyWrapper<float> {
462 public:
463     PropertyWrapperAcceleratedOpacity()
464         : PropertyWrapper<float>(CSSPropertyOpacity, &RenderStyle::opacity, &RenderStyle::setOpacity)
465     {
466     }
467
468     virtual bool animationIsAccelerated() const OVERRIDE { return true; }
469
470     virtual void blend(const AnimationBase* anim, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress) const OVERRIDE
471     {
472         float fromOpacity = a->opacity();
473
474         // This makes sure we put the object being animated into a RenderLayer during the animation
475         dst->setOpacity(blendFunc(anim, (fromOpacity == 1) ? 0.999999f : fromOpacity, b->opacity(), progress));
476     }
477 };
478
479 class PropertyWrapperAcceleratedTransform FINAL : public PropertyWrapper<const TransformOperations&> {
480 public:
481     PropertyWrapperAcceleratedTransform()
482         : PropertyWrapper<const TransformOperations&>(CSSPropertyWebkitTransform, &RenderStyle::transform, &RenderStyle::setTransform)
483     {
484     }
485
486     virtual bool animationIsAccelerated() const OVERRIDE { return true; }
487
488     virtual void blend(const AnimationBase* anim, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress) const OVERRIDE
489     {
490         dst->setTransform(blendFunc(anim, a->transform(), b->transform(), progress));
491     }
492 };
493
494 class PropertyWrapperAcceleratedFilter FINAL : public PropertyWrapper<const FilterOperations&> {
495 public:
496     PropertyWrapperAcceleratedFilter()
497         : PropertyWrapper<const FilterOperations&>(CSSPropertyWebkitFilter, &RenderStyle::filter, &RenderStyle::setFilter)
498     {
499     }
500
501     virtual bool animationIsAccelerated() const OVERRIDE { return true; }
502
503     virtual void blend(const AnimationBase* anim, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress) const OVERRIDE
504     {
505         dst->setFilter(blendFunc(anim, a->filter(), b->filter(), progress));
506     }
507 };
508
509 class PropertyWrapperShadow FINAL : public AnimationPropertyWrapperBase {
510 public:
511     PropertyWrapperShadow(CSSPropertyID prop, ShadowList* (RenderStyle::*getter)() const, void (RenderStyle::*setter)(PassRefPtr<ShadowList>))
512         : AnimationPropertyWrapperBase(prop)
513         , m_getter(getter)
514         , m_setter(setter)
515     {
516     }
517
518     virtual bool equals(const RenderStyle* a, const RenderStyle* b) const OVERRIDE
519     {
520         const ShadowList* shadowA = (a->*m_getter)();
521         const ShadowList* shadowB = (b->*m_getter)();
522         if (shadowA == shadowB)
523             return true;
524         if (shadowA && shadowB)
525             return *shadowA == *shadowB;
526         return false;
527     }
528
529     virtual void blend(const AnimationBase* anim, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress) const OVERRIDE
530     {
531         (dst->*m_setter)(ShadowList::blend((a->*m_getter)(), (b->*m_getter)(), progress));
532     }
533
534     ShadowList* (RenderStyle::*m_getter)() const;
535     void (RenderStyle::*m_setter)(PassRefPtr<ShadowList>);
536 };
537
538 class PropertyWrapperMaybeInvalidStyleColor FINAL : public AnimationPropertyWrapperBase {
539 public:
540     PropertyWrapperMaybeInvalidStyleColor(CSSPropertyID prop, StyleColor (RenderStyle::*getter)() const, void (RenderStyle::*setter)(const StyleColor&))
541         : AnimationPropertyWrapperBase(prop)
542         , m_getter(getter)
543         , m_setter(setter)
544     {
545     }
546
547     virtual bool equals(const RenderStyle* a, const RenderStyle* b) const OVERRIDE
548     {
549         StyleColor fromColor = (a->*m_getter)();
550         StyleColor toColor = (b->*m_getter)();
551
552         if (fromColor.isCurrentColor() && toColor.isCurrentColor())
553             return true;
554
555         return fromColor.resolve(a->color()) == toColor.resolve(b->color());
556     }
557
558     virtual void blend(const AnimationBase* anim, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress) const OVERRIDE
559     {
560         StyleColor fromColor = (a->*m_getter)();
561         StyleColor toColor = (b->*m_getter)();
562
563         if (fromColor.isCurrentColor() && toColor.isCurrentColor())
564             return;
565
566         (dst->*m_setter)(blendFunc(anim, fromColor.resolve(a->color()), toColor.resolve(b->color()), progress));
567     }
568
569 private:
570     StyleColor (RenderStyle::*m_getter)() const;
571     void (RenderStyle::*m_setter)(const StyleColor&);
572 };
573
574
575 class PropertyWrapperVisitedAffectedColor FINAL : public AnimationPropertyWrapperBase {
576 public:
577     PropertyWrapperVisitedAffectedColor(CSSPropertyID prop, Color (RenderStyle::*getter)() const, void (RenderStyle::*setter)(const Color&),
578         Color (RenderStyle::*visitedGetter)() const, void (RenderStyle::*visitedSetter)(const Color&))
579         : AnimationPropertyWrapperBase(prop)
580         , m_wrapper(adoptPtr(new PropertyWrapperColor(prop, getter, setter)))
581         , m_visitedWrapper(adoptPtr(new PropertyWrapperColor(prop, visitedGetter, visitedSetter)))
582     {
583     }
584     virtual bool equals(const RenderStyle* a, const RenderStyle* b) const
585     {
586         return m_wrapper->equals(a, b) && m_visitedWrapper->equals(a, b);
587     }
588     virtual void blend(const AnimationBase* anim, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress) const
589     {
590         m_wrapper->blend(anim, dst, a, b, progress);
591         m_visitedWrapper->blend(anim, dst, a, b, progress);
592     }
593
594 private:
595     OwnPtr<AnimationPropertyWrapperBase> m_wrapper;
596     OwnPtr<AnimationPropertyWrapperBase> m_visitedWrapper;
597 };
598
599 class PropertyWrapperVisitedAffectedStyleColor FINAL : public AnimationPropertyWrapperBase {
600 public:
601     PropertyWrapperVisitedAffectedStyleColor(CSSPropertyID prop, StyleColor (RenderStyle::*getter)() const, void (RenderStyle::*setter)(const StyleColor&),
602         StyleColor (RenderStyle::*visitedGetter)() const, void (RenderStyle::*visitedSetter)(const StyleColor&))
603         : AnimationPropertyWrapperBase(prop)
604         , m_wrapper(adoptPtr(new PropertyWrapperMaybeInvalidStyleColor(prop, getter, setter)))
605         , m_visitedWrapper(adoptPtr(new PropertyWrapperMaybeInvalidStyleColor(prop, visitedGetter, visitedSetter)))
606     {
607     }
608     virtual bool equals(const RenderStyle* a, const RenderStyle* b) const OVERRIDE
609     {
610         return m_wrapper->equals(a, b) && m_visitedWrapper->equals(a, b);
611     }
612     virtual void blend(const AnimationBase* anim, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress) const OVERRIDE
613     {
614         m_wrapper->blend(anim, dst, a, b, progress);
615         m_visitedWrapper->blend(anim, dst, a, b, progress);
616     }
617
618 private:
619     OwnPtr<AnimationPropertyWrapperBase> m_wrapper;
620     OwnPtr<AnimationPropertyWrapperBase> m_visitedWrapper;
621 };
622
623 // Wrapper base class for an animatable property in a FillLayer
624 class FillLayerAnimationPropertyWrapperBase {
625 public:
626     FillLayerAnimationPropertyWrapperBase()
627     {
628     }
629
630     virtual ~FillLayerAnimationPropertyWrapperBase() { }
631
632     virtual bool equals(const FillLayer*, const FillLayer*) const = 0;
633     virtual void blend(const AnimationBase*, FillLayer*, const FillLayer*, const FillLayer*, double) const = 0;
634 };
635
636 template <typename T>
637 class FillLayerPropertyWrapperGetter : public FillLayerAnimationPropertyWrapperBase {
638     WTF_MAKE_NONCOPYABLE(FillLayerPropertyWrapperGetter);
639 public:
640     FillLayerPropertyWrapperGetter(T (FillLayer::*getter)() const)
641         : m_getter(getter)
642     {
643     }
644
645     virtual bool equals(const FillLayer* a, const FillLayer* b) const
646     {
647        // If the style pointers are the same, don't bother doing the test.
648        // If either is null, return false. If both are null, return true.
649        if ((!a && !b) || a == b)
650            return true;
651        if (!a || !b)
652             return false;
653         return (a->*m_getter)() == (b->*m_getter)();
654     }
655
656 protected:
657     T (FillLayer::*m_getter)() const;
658 };
659
660 template <typename T>
661 class FillLayerPropertyWrapper FINAL : public FillLayerPropertyWrapperGetter<T> {
662 public:
663     FillLayerPropertyWrapper(T (FillLayer::*getter)() const, void (FillLayer::*setter)(T))
664         : FillLayerPropertyWrapperGetter<T>(getter)
665         , m_setter(setter)
666     {
667     }
668
669     virtual void blend(const AnimationBase* anim, FillLayer* dst, const FillLayer* a, const FillLayer* b, double progress) const OVERRIDE
670     {
671         (dst->*m_setter)(blendFunc(anim, (a->*FillLayerPropertyWrapperGetter<T>::m_getter)(), (b->*FillLayerPropertyWrapperGetter<T>::m_getter)(), progress));
672     }
673
674 protected:
675     void (FillLayer::*m_setter)(T);
676 };
677
678 template <typename T>
679 class FillLayerRefCountedPropertyWrapper : public FillLayerPropertyWrapperGetter<T*> {
680 public:
681     FillLayerRefCountedPropertyWrapper(T* (FillLayer::*getter)() const, void (FillLayer::*setter)(PassRefPtr<T>))
682         : FillLayerPropertyWrapperGetter<T*>(getter)
683         , m_setter(setter)
684     {
685     }
686
687     virtual void blend(const AnimationBase* anim, FillLayer* dst, const FillLayer* a, const FillLayer* b, double progress) const
688     {
689         (dst->*m_setter)(blendFunc(anim, (a->*FillLayerPropertyWrapperGetter<T*>::m_getter)(), (b->*FillLayerPropertyWrapperGetter<T*>::m_getter)(), progress));
690     }
691
692 protected:
693     void (FillLayer::*m_setter)(PassRefPtr<T>);
694 };
695
696 class FillLayerStyleImagePropertyWrapper FINAL : public FillLayerRefCountedPropertyWrapper<StyleImage> {
697 public:
698     FillLayerStyleImagePropertyWrapper(StyleImage* (FillLayer::*getter)() const, void (FillLayer::*setter)(PassRefPtr<StyleImage>))
699         : FillLayerRefCountedPropertyWrapper<StyleImage>(getter, setter)
700     {
701     }
702
703     virtual bool equals(const FillLayer* a, const FillLayer* b) const OVERRIDE
704     {
705        // If the style pointers are the same, don't bother doing the test.
706        // If either is null, return false. If both are null, return true.
707        if (a == b)
708            return true;
709        if (!a || !b)
710             return false;
711
712         StyleImage* imageA = (a->*m_getter)();
713         StyleImage* imageB = (b->*m_getter)();
714         return StyleImage::imagesEquivalent(imageA, imageB);
715     }
716 };
717
718
719 class FillLayersPropertyWrapper FINAL : public AnimationPropertyWrapperBase {
720 public:
721     typedef const FillLayer* (RenderStyle::*LayersGetter)() const;
722     typedef FillLayer* (RenderStyle::*LayersAccessor)();
723
724     FillLayersPropertyWrapper(CSSPropertyID prop, LayersGetter getter, LayersAccessor accessor)
725         : AnimationPropertyWrapperBase(prop)
726         , m_layersGetter(getter)
727         , m_layersAccessor(accessor)
728     {
729         switch (prop) {
730         case CSSPropertyBackgroundPositionX:
731         case CSSPropertyWebkitMaskPositionX:
732             m_fillLayerPropertyWrapper = new FillLayerPropertyWrapper<Length>(&FillLayer::xPosition, &FillLayer::setXPosition);
733             break;
734         case CSSPropertyBackgroundPositionY:
735         case CSSPropertyWebkitMaskPositionY:
736             m_fillLayerPropertyWrapper = new FillLayerPropertyWrapper<Length>(&FillLayer::yPosition, &FillLayer::setYPosition);
737             break;
738         case CSSPropertyBackgroundSize:
739         case CSSPropertyWebkitBackgroundSize:
740         case CSSPropertyWebkitMaskSize:
741             m_fillLayerPropertyWrapper = new FillLayerPropertyWrapper<LengthSize>(&FillLayer::sizeLength, &FillLayer::setSizeLength);
742             break;
743         case CSSPropertyBackgroundImage:
744             m_fillLayerPropertyWrapper = new FillLayerStyleImagePropertyWrapper(&FillLayer::image, &FillLayer::setImage);
745             break;
746         default:
747             break;
748         }
749     }
750
751     virtual bool equals(const RenderStyle* a, const RenderStyle* b) const OVERRIDE
752     {
753         const FillLayer* fromLayer = (a->*m_layersGetter)();
754         const FillLayer* toLayer = (b->*m_layersGetter)();
755
756         while (fromLayer && toLayer) {
757             if (!m_fillLayerPropertyWrapper->equals(fromLayer, toLayer))
758                 return false;
759
760             fromLayer = fromLayer->next();
761             toLayer = toLayer->next();
762         }
763
764         return true;
765     }
766
767     virtual void blend(const AnimationBase* anim, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress) const OVERRIDE
768     {
769         const FillLayer* aLayer = (a->*m_layersGetter)();
770         const FillLayer* bLayer = (b->*m_layersGetter)();
771         FillLayer* dstLayer = (dst->*m_layersAccessor)();
772
773         while (aLayer && bLayer && dstLayer) {
774             m_fillLayerPropertyWrapper->blend(anim, dstLayer, aLayer, bLayer, progress);
775             aLayer = aLayer->next();
776             bLayer = bLayer->next();
777             dstLayer = dstLayer->next();
778         }
779     }
780
781 private:
782     FillLayerAnimationPropertyWrapperBase* m_fillLayerPropertyWrapper;
783
784     LayersGetter m_layersGetter;
785     LayersAccessor m_layersAccessor;
786 };
787
788 class ShorthandPropertyWrapper FINAL : public AnimationPropertyWrapperBase {
789 public:
790     ShorthandPropertyWrapper(CSSPropertyID property, const StylePropertyShorthand& shorthand)
791         : AnimationPropertyWrapperBase(property)
792     {
793         for (unsigned i = 0; i < shorthand.length(); ++i) {
794             AnimationPropertyWrapperBase* wrapper = wrapperForProperty(shorthand.properties()[i]);
795             if (wrapper)
796                 m_propertyWrappers.append(wrapper);
797         }
798     }
799
800     virtual bool isShorthandWrapper() const OVERRIDE { return true; }
801
802     virtual bool equals(const RenderStyle* a, const RenderStyle* b) const OVERRIDE
803     {
804         Vector<AnimationPropertyWrapperBase*>::const_iterator end = m_propertyWrappers.end();
805         for (Vector<AnimationPropertyWrapperBase*>::const_iterator it = m_propertyWrappers.begin(); it != end; ++it) {
806             if (!(*it)->equals(a, b))
807                 return false;
808         }
809         return true;
810     }
811
812     virtual void blend(const AnimationBase* anim, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress) const OVERRIDE
813     {
814         Vector<AnimationPropertyWrapperBase*>::const_iterator end = m_propertyWrappers.end();
815         for (Vector<AnimationPropertyWrapperBase*>::const_iterator it = m_propertyWrappers.begin(); it != end; ++it)
816             (*it)->blend(anim, dst, a, b, progress);
817     }
818
819     const Vector<AnimationPropertyWrapperBase*> propertyWrappers() const { return m_propertyWrappers; }
820
821 private:
822     Vector<AnimationPropertyWrapperBase*> m_propertyWrappers;
823 };
824
825 class PropertyWrapperFlex FINAL : public AnimationPropertyWrapperBase {
826 public:
827     PropertyWrapperFlex()
828         : AnimationPropertyWrapperBase(CSSPropertyFlex)
829     {
830     }
831
832     virtual bool equals(const RenderStyle* a, const RenderStyle* b) const OVERRIDE
833     {
834         // If the style pointers are the same, don't bother doing the test.
835         // If either is null, return false. If both are null, return true.
836         if ((!a && !b) || a == b)
837             return true;
838         if (!a || !b)
839             return false;
840
841         return a->flexBasis() == b->flexBasis() && a->flexGrow() == b->flexGrow() && a->flexShrink() == b->flexShrink();
842     }
843
844     virtual void blend(const AnimationBase* anim, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress) const OVERRIDE
845     {
846         dst->setFlexBasis(blendFunc(anim, a->flexBasis(), b->flexBasis(), progress));
847         dst->setFlexGrow(blendFunc(anim, a->flexGrow(), b->flexGrow(), progress));
848         dst->setFlexShrink(blendFunc(anim, a->flexShrink(), b->flexShrink(), progress));
849     }
850 };
851
852 class PropertyWrapperSVGPaint FINAL : public AnimationPropertyWrapperBase {
853 public:
854     PropertyWrapperSVGPaint(CSSPropertyID prop, const SVGPaint::SVGPaintType& (RenderStyle::*paintTypeGetter)() const, Color (RenderStyle::*getter)() const, void (RenderStyle::*setter)(const Color&))
855         : AnimationPropertyWrapperBase(prop)
856         , m_paintTypeGetter(paintTypeGetter)
857         , m_getter(getter)
858         , m_setter(setter)
859     {
860     }
861
862     virtual bool equals(const RenderStyle* a, const RenderStyle* b) const OVERRIDE
863     {
864         if ((a->*m_paintTypeGetter)() != (b->*m_paintTypeGetter)())
865             return false;
866
867         // We only support animations between SVGPaints that are pure Color values.
868         // For everything else we must return true for this method, otherwise
869         // we will try to animate between values forever.
870         if ((a->*m_paintTypeGetter)() == SVGPaint::SVG_PAINTTYPE_RGBCOLOR) {
871             Color fromColor = (a->*m_getter)();
872             Color toColor = (b->*m_getter)();
873             return fromColor == toColor;
874         }
875         return true;
876     }
877
878     virtual void blend(const AnimationBase* anim, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress) const OVERRIDE
879     {
880         if ((a->*m_paintTypeGetter)() != SVGPaint::SVG_PAINTTYPE_RGBCOLOR
881             || (b->*m_paintTypeGetter)() != SVGPaint::SVG_PAINTTYPE_RGBCOLOR)
882             return;
883
884         Color fromColor = (a->*m_getter)();
885         Color toColor = (b->*m_getter)();
886
887         (dst->*m_setter)(blendFunc(anim, fromColor, toColor, progress));
888     }
889
890 private:
891     const SVGPaint::SVGPaintType& (RenderStyle::*m_paintTypeGetter)() const;
892     Color (RenderStyle::*m_getter)() const;
893     void (RenderStyle::*m_setter)(const Color&);
894 };
895
896 template <typename T>
897 class RefCountedSVGPropertyWrapper : public AnimationPropertyWrapperBase {
898 public:
899     RefCountedSVGPropertyWrapper(CSSPropertyID prop, PassRefPtr<T> (RenderStyle::*getter)() const, void (RenderStyle::*setter)(PassRefPtr<T>))
900         : AnimationPropertyWrapperBase(prop)
901         , m_getter(getter)
902         , m_setter(setter)
903     {
904     }
905
906     virtual void blend(const AnimationBase* anim, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress) const
907     {
908         (dst->*m_setter)(blendFunc(anim, (a->*m_getter)(), (b->*m_getter)(), progress));
909     }
910
911     virtual bool equals(const RenderStyle* a, const RenderStyle* b) const OVERRIDE
912     {
913         if (a == b)
914             return true;
915         if (!a || !b)
916             return false;
917         RefPtr<T> aValue = (a->*this->m_getter)();
918         RefPtr<T> bValue = (b->*this->m_getter)();
919         if (aValue == bValue)
920             return true;
921         if (!aValue || !bValue)
922             return false;
923         return *aValue == *bValue;
924     }
925
926 protected:
927     PassRefPtr<T> (RenderStyle::*m_getter)() const;
928     void (RenderStyle::*m_setter)(PassRefPtr<T>);
929 };
930
931 static void addShorthandProperties()
932 {
933     static const CSSPropertyID animatableShorthandProperties[] = {
934         CSSPropertyBackground, // for background-color, background-position, background-image
935         CSSPropertyBackgroundPosition,
936         CSSPropertyFont, // for font-size, font-weight
937         CSSPropertyWebkitMask, // for mask-position
938         CSSPropertyWebkitMaskPosition,
939         CSSPropertyBorderTop, CSSPropertyBorderRight, CSSPropertyBorderBottom, CSSPropertyBorderLeft,
940         CSSPropertyBorderColor,
941         CSSPropertyBorderRadius,
942         CSSPropertyBorderWidth,
943         CSSPropertyBorder,
944         CSSPropertyBorderImage,
945         CSSPropertyBorderSpacing,
946         CSSPropertyListStyle, // for list-style-image
947         CSSPropertyMargin,
948         CSSPropertyOutline,
949         CSSPropertyPadding,
950         CSSPropertyWebkitTextStroke,
951         CSSPropertyWebkitColumnRule,
952         CSSPropertyWebkitBorderRadius,
953         CSSPropertyWebkitTransformOrigin
954     };
955
956     for (size_t i = 0; i < WTF_ARRAY_LENGTH(animatableShorthandProperties); ++i) {
957         CSSPropertyID propertyID = animatableShorthandProperties[i];
958         StylePropertyShorthand shorthand = shorthandForProperty(propertyID);
959         if (shorthand.length() > 0)
960             addPropertyWrapper(propertyID, new ShorthandPropertyWrapper(propertyID, shorthand));
961     }
962 }
963
964 void CSSPropertyAnimation::ensurePropertyMap()
965 {
966     // FIXME: This data is never destroyed. Maybe we should ref count it and toss it when the last AnimationController is destroyed?
967     if (gPropertyWrappers)
968         return;
969
970     gPropertyWrappers = new Vector<AnimationPropertyWrapperBase*>();
971
972     // build the list of property wrappers to do the comparisons and blends
973     gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyLeft, &RenderStyle::left, &RenderStyle::setLeft));
974     gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyRight, &RenderStyle::right, &RenderStyle::setRight));
975     gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyTop, &RenderStyle::top, &RenderStyle::setTop));
976     gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyBottom, &RenderStyle::bottom, &RenderStyle::setBottom));
977
978     gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyWidth, &RenderStyle::width, &RenderStyle::setWidth));
979     gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyMinWidth, &RenderStyle::minWidth, &RenderStyle::setMinWidth));
980     gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyMaxWidth, &RenderStyle::maxWidth, &RenderStyle::setMaxWidth));
981
982     gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyHeight, &RenderStyle::height, &RenderStyle::setHeight));
983     gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyMinHeight, &RenderStyle::minHeight, &RenderStyle::setMinHeight));
984     gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyMaxHeight, &RenderStyle::maxHeight, &RenderStyle::setMaxHeight));
985
986     if (!RuntimeEnabledFeatures::webAnimationsCSSEnabled())
987         gPropertyWrappers->append(new PropertyWrapperFlex());
988
989     gPropertyWrappers->append(new PropertyWrapper<unsigned>(CSSPropertyBorderLeftWidth, &RenderStyle::borderLeftWidth, &RenderStyle::setBorderLeftWidth));
990     gPropertyWrappers->append(new PropertyWrapper<unsigned>(CSSPropertyBorderRightWidth, &RenderStyle::borderRightWidth, &RenderStyle::setBorderRightWidth));
991     gPropertyWrappers->append(new PropertyWrapper<unsigned>(CSSPropertyBorderTopWidth, &RenderStyle::borderTopWidth, &RenderStyle::setBorderTopWidth));
992     gPropertyWrappers->append(new PropertyWrapper<unsigned>(CSSPropertyBorderBottomWidth, &RenderStyle::borderBottomWidth, &RenderStyle::setBorderBottomWidth));
993     gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyMarginLeft, &RenderStyle::marginLeft, &RenderStyle::setMarginLeft));
994     gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyMarginRight, &RenderStyle::marginRight, &RenderStyle::setMarginRight));
995     gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyMarginTop, &RenderStyle::marginTop, &RenderStyle::setMarginTop));
996     gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyMarginBottom, &RenderStyle::marginBottom, &RenderStyle::setMarginBottom));
997     gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyPaddingLeft, &RenderStyle::paddingLeft, &RenderStyle::setPaddingLeft));
998     gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyPaddingRight, &RenderStyle::paddingRight, &RenderStyle::setPaddingRight));
999     gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyPaddingTop, &RenderStyle::paddingTop, &RenderStyle::setPaddingTop));
1000     gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyPaddingBottom, &RenderStyle::paddingBottom, &RenderStyle::setPaddingBottom));
1001     gPropertyWrappers->append(new PropertyWrapperVisitedAffectedColor(CSSPropertyColor, &RenderStyle::color, &RenderStyle::setColor, &RenderStyle::visitedLinkColor, &RenderStyle::setVisitedLinkColor));
1002
1003     gPropertyWrappers->append(new PropertyWrapperVisitedAffectedStyleColor(CSSPropertyBackgroundColor, &RenderStyle::backgroundColor, &RenderStyle::setBackgroundColor, &RenderStyle::visitedLinkBackgroundColor, &RenderStyle::setVisitedLinkBackgroundColor));
1004
1005     gPropertyWrappers->append(new FillLayersPropertyWrapper(CSSPropertyBackgroundImage, &RenderStyle::backgroundLayers, &RenderStyle::accessBackgroundLayers));
1006     gPropertyWrappers->append(new StyleImagePropertyWrapper(CSSPropertyListStyleImage, &RenderStyle::listStyleImage, &RenderStyle::setListStyleImage));
1007     gPropertyWrappers->append(new StyleImagePropertyWrapper(CSSPropertyWebkitMaskImage, &RenderStyle::maskImage, &RenderStyle::setMaskImage));
1008
1009     gPropertyWrappers->append(new StyleImagePropertyWrapper(CSSPropertyBorderImageSource, &RenderStyle::borderImageSource, &RenderStyle::setBorderImageSource));
1010     gPropertyWrappers->append(new PropertyWrapper<LengthBox>(CSSPropertyBorderImageSlice, &RenderStyle::borderImageSlices, &RenderStyle::setBorderImageSlices));
1011     gPropertyWrappers->append(new PropertyWrapper<const BorderImageLengthBox&>(CSSPropertyBorderImageWidth, &RenderStyle::borderImageWidth, &RenderStyle::setBorderImageWidth));
1012     gPropertyWrappers->append(new PropertyWrapper<const BorderImageLengthBox&>(CSSPropertyBorderImageOutset, &RenderStyle::borderImageOutset, &RenderStyle::setBorderImageOutset));
1013
1014     gPropertyWrappers->append(new StyleImagePropertyWrapper(CSSPropertyWebkitMaskBoxImageSource, &RenderStyle::maskBoxImageSource, &RenderStyle::setMaskBoxImageSource));
1015     gPropertyWrappers->append(new PropertyWrapper<LengthBox>(CSSPropertyWebkitMaskBoxImageSlice, &RenderStyle::maskBoxImageSlices, &RenderStyle::setMaskBoxImageSlices));
1016     gPropertyWrappers->append(new PropertyWrapper<const BorderImageLengthBox&>(CSSPropertyWebkitMaskBoxImageWidth, &RenderStyle::maskBoxImageWidth, &RenderStyle::setMaskBoxImageWidth));
1017     gPropertyWrappers->append(new PropertyWrapper<const BorderImageLengthBox&>(CSSPropertyWebkitMaskBoxImageOutset, &RenderStyle::maskBoxImageOutset, &RenderStyle::setMaskBoxImageOutset));
1018
1019     gPropertyWrappers->append(new FillLayersPropertyWrapper(CSSPropertyBackgroundPositionX, &RenderStyle::backgroundLayers, &RenderStyle::accessBackgroundLayers));
1020     gPropertyWrappers->append(new FillLayersPropertyWrapper(CSSPropertyBackgroundPositionY, &RenderStyle::backgroundLayers, &RenderStyle::accessBackgroundLayers));
1021     gPropertyWrappers->append(new FillLayersPropertyWrapper(CSSPropertyBackgroundSize, &RenderStyle::backgroundLayers, &RenderStyle::accessBackgroundLayers));
1022     gPropertyWrappers->append(new FillLayersPropertyWrapper(CSSPropertyWebkitBackgroundSize, &RenderStyle::backgroundLayers, &RenderStyle::accessBackgroundLayers));
1023
1024     gPropertyWrappers->append(new FillLayersPropertyWrapper(CSSPropertyWebkitMaskPositionX, &RenderStyle::maskLayers, &RenderStyle::accessMaskLayers));
1025     gPropertyWrappers->append(new FillLayersPropertyWrapper(CSSPropertyWebkitMaskPositionY, &RenderStyle::maskLayers, &RenderStyle::accessMaskLayers));
1026     gPropertyWrappers->append(new FillLayersPropertyWrapper(CSSPropertyWebkitMaskSize, &RenderStyle::maskLayers, &RenderStyle::accessMaskLayers));
1027
1028     gPropertyWrappers->append(new PropertyWrapper<LengthPoint>(CSSPropertyObjectPosition, &RenderStyle::objectPosition, &RenderStyle::setObjectPosition));
1029
1030     gPropertyWrappers->append(new PropertyWrapper<float>(CSSPropertyFontSize,
1031         // Must pass a specified size to setFontSize if Text Autosizing is enabled, but a computed size
1032         // if text zoom is enabled (if neither is enabled it's irrelevant as they're probably the same).
1033         // FIXME: Should we introduce an option to pass the computed font size here, allowing consumers to
1034         // enable text zoom rather than Text Autosizing? See http://crbug.com/227545.
1035         &RenderStyle::specifiedFontSize,
1036         &RenderStyle::setFontSize));
1037     gPropertyWrappers->append(new PropertyWrapper<unsigned short>(CSSPropertyWebkitColumnRuleWidth, &RenderStyle::columnRuleWidth, &RenderStyle::setColumnRuleWidth));
1038     gPropertyWrappers->append(new PropertyWrapper<float>(CSSPropertyWebkitColumnGap, &RenderStyle::columnGap, &RenderStyle::setColumnGap));
1039     gPropertyWrappers->append(new PropertyWrapper<unsigned short>(CSSPropertyWebkitColumnCount, &RenderStyle::columnCount, &RenderStyle::setColumnCount));
1040     gPropertyWrappers->append(new PropertyWrapper<float>(CSSPropertyWebkitColumnWidth, &RenderStyle::columnWidth, &RenderStyle::setColumnWidth));
1041     gPropertyWrappers->append(new PropertyWrapper<short>(CSSPropertyWebkitBorderHorizontalSpacing, &RenderStyle::horizontalBorderSpacing, &RenderStyle::setHorizontalBorderSpacing));
1042     gPropertyWrappers->append(new PropertyWrapper<short>(CSSPropertyWebkitBorderVerticalSpacing, &RenderStyle::verticalBorderSpacing, &RenderStyle::setVerticalBorderSpacing));
1043     gPropertyWrappers->append(new PropertyWrapper<int>(CSSPropertyZIndex, &RenderStyle::zIndex, &RenderStyle::setZIndex));
1044     gPropertyWrappers->append(new PropertyWrapper<short>(CSSPropertyOrphans, &RenderStyle::orphans, &RenderStyle::setOrphans));
1045     gPropertyWrappers->append(new PropertyWrapper<short>(CSSPropertyWidows, &RenderStyle::widows, &RenderStyle::setWidows));
1046     gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyLineHeight, &RenderStyle::specifiedLineHeight, &RenderStyle::setLineHeight));
1047     gPropertyWrappers->append(new PropertyWrapper<int>(CSSPropertyOutlineOffset, &RenderStyle::outlineOffset, &RenderStyle::setOutlineOffset));
1048     gPropertyWrappers->append(new PropertyWrapper<unsigned short>(CSSPropertyOutlineWidth, &RenderStyle::outlineWidth, &RenderStyle::setOutlineWidth));
1049     gPropertyWrappers->append(new PropertyWrapper<float>(CSSPropertyLetterSpacing, &RenderStyle::letterSpacing, &RenderStyle::setLetterSpacing));
1050     gPropertyWrappers->append(new PropertyWrapper<float>(CSSPropertyWordSpacing, &RenderStyle::wordSpacing, &RenderStyle::setWordSpacing));
1051     gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyTextIndent, &RenderStyle::textIndent, &RenderStyle::setTextIndent));
1052
1053     gPropertyWrappers->append(new PropertyWrapper<float>(CSSPropertyWebkitPerspective, &RenderStyle::perspective, &RenderStyle::setPerspective));
1054     gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyWebkitPerspectiveOriginX, &RenderStyle::perspectiveOriginX, &RenderStyle::setPerspectiveOriginX));
1055     gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyWebkitPerspectiveOriginY, &RenderStyle::perspectiveOriginY, &RenderStyle::setPerspectiveOriginY));
1056     gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyWebkitTransformOriginX, &RenderStyle::transformOriginX, &RenderStyle::setTransformOriginX));
1057     gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyWebkitTransformOriginY, &RenderStyle::transformOriginY, &RenderStyle::setTransformOriginY));
1058     gPropertyWrappers->append(new PropertyWrapper<float>(CSSPropertyWebkitTransformOriginZ, &RenderStyle::transformOriginZ, &RenderStyle::setTransformOriginZ));
1059     gPropertyWrappers->append(new PropertyWrapper<LengthSize>(CSSPropertyBorderTopLeftRadius, &RenderStyle::borderTopLeftRadius, &RenderStyle::setBorderTopLeftRadius));
1060     gPropertyWrappers->append(new PropertyWrapper<LengthSize>(CSSPropertyBorderTopRightRadius, &RenderStyle::borderTopRightRadius, &RenderStyle::setBorderTopRightRadius));
1061     gPropertyWrappers->append(new PropertyWrapper<LengthSize>(CSSPropertyBorderBottomLeftRadius, &RenderStyle::borderBottomLeftRadius, &RenderStyle::setBorderBottomLeftRadius));
1062     gPropertyWrappers->append(new PropertyWrapper<LengthSize>(CSSPropertyBorderBottomRightRadius, &RenderStyle::borderBottomRightRadius, &RenderStyle::setBorderBottomRightRadius));
1063     gPropertyWrappers->append(new PropertyWrapper<EVisibility>(CSSPropertyVisibility, &RenderStyle::visibility, &RenderStyle::setVisibility));
1064     gPropertyWrappers->append(new PropertyWrapper<float>(CSSPropertyZoom, &RenderStyle::zoom, &RenderStyle::setZoomWithoutReturnValue));
1065
1066     gPropertyWrappers->append(new PropertyWrapper<LengthBox>(CSSPropertyClip, &RenderStyle::clip, &RenderStyle::setClip));
1067
1068     gPropertyWrappers->append(new PropertyWrapperAcceleratedOpacity());
1069     gPropertyWrappers->append(new PropertyWrapperAcceleratedTransform());
1070     gPropertyWrappers->append(new PropertyWrapperAcceleratedFilter());
1071
1072     gPropertyWrappers->append(new PropertyWrapperClipPath(CSSPropertyWebkitClipPath, &RenderStyle::clipPath, &RenderStyle::setClipPath));
1073
1074     gPropertyWrappers->append(new PropertyWrapperShape(CSSPropertyShapeInside, &RenderStyle::shapeInside, &RenderStyle::setShapeInside));
1075     gPropertyWrappers->append(new PropertyWrapperShape(CSSPropertyShapeOutside, &RenderStyle::shapeOutside, &RenderStyle::setShapeOutside));
1076     gPropertyWrappers->append(new NonNegativeLengthWrapper(CSSPropertyShapeMargin, &RenderStyle::shapeMargin, &RenderStyle::setShapeMargin));
1077     gPropertyWrappers->append(new PropertyWrapper<float>(CSSPropertyShapeImageThreshold, &RenderStyle::shapeImageThreshold, &RenderStyle::setShapeImageThreshold));
1078
1079     gPropertyWrappers->append(new PropertyWrapperVisitedAffectedStyleColor(CSSPropertyWebkitColumnRuleColor, &RenderStyle::columnRuleColor, &RenderStyle::setColumnRuleColor, &RenderStyle::visitedLinkColumnRuleColor, &RenderStyle::setVisitedLinkColumnRuleColor));
1080     gPropertyWrappers->append(new PropertyWrapperVisitedAffectedStyleColor(CSSPropertyWebkitTextStrokeColor, &RenderStyle::textStrokeColor, &RenderStyle::setTextStrokeColor, &RenderStyle::visitedLinkTextStrokeColor, &RenderStyle::setVisitedLinkTextStrokeColor));
1081     gPropertyWrappers->append(new PropertyWrapperVisitedAffectedStyleColor(CSSPropertyBorderLeftColor, &RenderStyle::borderLeftColor, &RenderStyle::setBorderLeftColor, &RenderStyle::visitedLinkBorderLeftColor, &RenderStyle::setVisitedLinkBorderLeftColor));
1082     gPropertyWrappers->append(new PropertyWrapperVisitedAffectedStyleColor(CSSPropertyBorderRightColor, &RenderStyle::borderRightColor, &RenderStyle::setBorderRightColor, &RenderStyle::visitedLinkBorderRightColor, &RenderStyle::setVisitedLinkBorderRightColor));
1083     gPropertyWrappers->append(new PropertyWrapperVisitedAffectedStyleColor(CSSPropertyBorderTopColor, &RenderStyle::borderTopColor, &RenderStyle::setBorderTopColor, &RenderStyle::visitedLinkBorderTopColor, &RenderStyle::setVisitedLinkBorderTopColor));
1084     gPropertyWrappers->append(new PropertyWrapperVisitedAffectedStyleColor(CSSPropertyBorderBottomColor, &RenderStyle::borderBottomColor, &RenderStyle::setBorderBottomColor, &RenderStyle::visitedLinkBorderBottomColor, &RenderStyle::setVisitedLinkBorderBottomColor));
1085     gPropertyWrappers->append(new PropertyWrapperVisitedAffectedStyleColor(CSSPropertyOutlineColor, &RenderStyle::outlineColor, &RenderStyle::setOutlineColor, &RenderStyle::visitedLinkOutlineColor, &RenderStyle::setVisitedLinkOutlineColor));
1086
1087     gPropertyWrappers->append(new PropertyWrapperShadow(CSSPropertyBoxShadow, &RenderStyle::boxShadow, &RenderStyle::setBoxShadow));
1088     gPropertyWrappers->append(new PropertyWrapperShadow(CSSPropertyWebkitBoxShadow, &RenderStyle::boxShadow, &RenderStyle::setBoxShadow));
1089     gPropertyWrappers->append(new PropertyWrapperShadow(CSSPropertyTextShadow, &RenderStyle::textShadow, &RenderStyle::setTextShadow));
1090
1091     gPropertyWrappers->append(new PropertyWrapperSVGPaint(CSSPropertyFill, &RenderStyle::fillPaintType, &RenderStyle::fillPaintColor, &RenderStyle::setFillPaintColor));
1092     gPropertyWrappers->append(new PropertyWrapper<float>(CSSPropertyFillOpacity, &RenderStyle::fillOpacity, &RenderStyle::setFillOpacity));
1093
1094     gPropertyWrappers->append(new PropertyWrapperSVGPaint(CSSPropertyStroke, &RenderStyle::strokePaintType, &RenderStyle::strokePaintColor, &RenderStyle::setStrokePaintColor));
1095     gPropertyWrappers->append(new PropertyWrapper<float>(CSSPropertyStrokeOpacity, &RenderStyle::strokeOpacity, &RenderStyle::setStrokeOpacity));
1096     gPropertyWrappers->append(new RefCountedSVGPropertyWrapper<SVGLength>(CSSPropertyStrokeWidth, &RenderStyle::strokeWidth, &RenderStyle::setStrokeWidth));
1097     gPropertyWrappers->append(new RefCountedSVGPropertyWrapper<SVGLengthList>(CSSPropertyStrokeDasharray, &RenderStyle::strokeDashArray, &RenderStyle::setStrokeDashArray));
1098     gPropertyWrappers->append(new RefCountedSVGPropertyWrapper<SVGLength>(CSSPropertyStrokeDashoffset, &RenderStyle::strokeDashOffset, &RenderStyle::setStrokeDashOffset));
1099     gPropertyWrappers->append(new PropertyWrapper<float>(CSSPropertyStrokeMiterlimit, &RenderStyle::strokeMiterLimit, &RenderStyle::setStrokeMiterLimit));
1100
1101     gPropertyWrappers->append(new PropertyWrapper<float>(CSSPropertyFloodOpacity, &RenderStyle::floodOpacity, &RenderStyle::setFloodOpacity));
1102     gPropertyWrappers->append(new PropertyWrapperColor(CSSPropertyFloodColor, &RenderStyle::floodColor, &RenderStyle::setFloodColor));
1103
1104     gPropertyWrappers->append(new PropertyWrapper<float>(CSSPropertyStopOpacity, &RenderStyle::stopOpacity, &RenderStyle::setStopOpacity));
1105     gPropertyWrappers->append(new PropertyWrapperColor(CSSPropertyStopColor, &RenderStyle::stopColor, &RenderStyle::setStopColor));
1106
1107     gPropertyWrappers->append(new PropertyWrapperColor(CSSPropertyLightingColor, &RenderStyle::lightingColor, &RenderStyle::setLightingColor));
1108
1109     gPropertyWrappers->append(new RefCountedSVGPropertyWrapper<SVGLength>(CSSPropertyBaselineShift, &RenderStyle::baselineShiftValue, &RenderStyle::setBaselineShiftValue));
1110     gPropertyWrappers->append(new RefCountedSVGPropertyWrapper<SVGLength>(CSSPropertyKerning, &RenderStyle::kerning, &RenderStyle::setKerning));
1111
1112     if (RuntimeEnabledFeatures::webAnimationsCSSEnabled()) {
1113         gPropertyWrappers->append(new PropertyWrapper<float>(CSSPropertyFlexGrow, &RenderStyle::flexGrow, &RenderStyle::setFlexGrow));
1114         gPropertyWrappers->append(new PropertyWrapper<float>(CSSPropertyFlexShrink, &RenderStyle::flexShrink, &RenderStyle::setFlexShrink));
1115         gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyFlexBasis, &RenderStyle::flexBasis, &RenderStyle::setFlexBasis));
1116     }
1117
1118     // TODO:
1119     //
1120     //  CSSPropertyVerticalAlign
1121     //
1122     // Compound properties that have components that should be animatable:
1123     //
1124     //  CSSPropertyWebkitColumns
1125     //  CSSPropertyWebkitBoxReflect
1126
1127     // Make sure unused slots have a value
1128     for (unsigned int i = 0; i < static_cast<unsigned int>(numCSSProperties); ++i)
1129         gPropertyWrapperMap[i] = cInvalidPropertyWrapperIndex;
1130
1131     // First we put the non-shorthand property wrappers into the map, so the shorthand-building
1132     // code can find them.
1133     size_t n = gPropertyWrappers->size();
1134     for (unsigned int i = 0; i < n; ++i) {
1135         CSSPropertyID property = (*gPropertyWrappers)[i]->property();
1136         ASSERT_WITH_MESSAGE(RuntimeEnabledFeatures::webAnimationsCSSEnabled() || CSSAnimations::isAnimatableProperty(property), "%s is not whitelisted for animation", getPropertyNameString(property).utf8().data());
1137         ASSERT(property - firstCSSProperty < numCSSProperties);
1138         gPropertyWrapperMap[property - firstCSSProperty] = i;
1139     }
1140
1141     // Now add the shorthand wrappers.
1142     addShorthandProperties();
1143 }
1144
1145 // Returns true if we need to start animation timers
1146 bool CSSPropertyAnimation::blendProperties(const AnimationBase* anim, CSSPropertyID prop, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress)
1147 {
1148     ASSERT(prop != CSSPropertyInvalid);
1149
1150     ensurePropertyMap();
1151
1152     AnimationPropertyWrapperBase* wrapper = wrapperForProperty(prop);
1153     if (wrapper) {
1154         wrapper->blend(anim, dst, a, b, progress);
1155         return !wrapper->animationIsAccelerated() || !anim->isAccelerated();
1156     }
1157
1158     return false;
1159 }
1160
1161 bool CSSPropertyAnimation::animationOfPropertyIsAccelerated(CSSPropertyID prop)
1162 {
1163     ensurePropertyMap();
1164     AnimationPropertyWrapperBase* wrapper = wrapperForProperty(prop);
1165     return wrapper ? wrapper->animationIsAccelerated() : false;
1166 }
1167
1168 bool CSSPropertyAnimation::propertiesEqual(CSSPropertyID prop, const RenderStyle* a, const RenderStyle* b)
1169 {
1170     ensurePropertyMap();
1171
1172     AnimationPropertyWrapperBase* wrapper = wrapperForProperty(prop);
1173     if (wrapper)
1174         return wrapper->equals(a, b);
1175     return true;
1176 }
1177
1178 CSSPropertyID CSSPropertyAnimation::getPropertyAtIndex(int i, bool& isShorthand)
1179 {
1180     ensurePropertyMap();
1181
1182     if (i < 0 || i >= getNumProperties())
1183         return CSSPropertyInvalid;
1184
1185     AnimationPropertyWrapperBase* wrapper = (*gPropertyWrappers)[i];
1186     isShorthand = wrapper->isShorthandWrapper();
1187     return wrapper->property();
1188 }
1189
1190 int CSSPropertyAnimation::getNumProperties()
1191 {
1192     ensurePropertyMap();
1193
1194     return gPropertyWrappers->size();
1195 }
1196
1197 }