Encapsulate globals in CSSPropertyAnimation.cpp
[WebKit-https.git] / Source / WebCore / page / animation / CSSPropertyAnimation.cpp
1 /*
2  * Copyright (C) 2007, 2008, 2009, 2013 Apple Inc. All rights reserved.
3  * Copyright (C) 2012, 2013 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 "CSSPropertyAnimation.h"
32
33 #include "AnimationBase.h"
34 #include "CSSComputedStyleDeclaration.h"
35 #include "CSSCrossfadeValue.h"
36 #include "CSSFilterImageValue.h"
37 #include "CSSImageGeneratorValue.h"
38 #include "CSSImageValue.h"
39 #include "CSSPrimitiveValue.h"
40 #include "CSSPropertyNames.h"
41 #include "CachedImage.h"
42 #include "ClipPathOperation.h"
43 #include "FloatConversion.h"
44 #include "IdentityTransformOperation.h"
45 #include "Matrix3DTransformOperation.h"
46 #include "MatrixTransformOperation.h"
47 #include "RenderBox.h"
48 #include "RenderStyle.h"
49 #include "StyleCachedImage.h"
50 #include "StyleGeneratedImage.h"
51 #include "StylePropertyShorthand.h"
52 #include "StyleResolver.h"
53 #include <algorithm>
54 #include <wtf/MathExtras.h>
55 #include <wtf/Noncopyable.h>
56 #include <wtf/RefCounted.h>
57
58 namespace WebCore {
59
60 static inline int blendFunc(const AnimationBase*, int from, int to, double progress)
61 {
62     return blend(from, to, progress);
63 }
64
65 static inline unsigned blendFunc(const AnimationBase*, unsigned from, unsigned to, double progress)
66 {
67     return blend(from, to, progress);
68 }
69
70 static inline double blendFunc(const AnimationBase*, double from, double to, double progress)
71 {
72     return blend(from, to, progress);
73 }
74
75 static inline float blendFunc(const AnimationBase*, float from, float to, double progress)
76 {
77     return narrowPrecisionToFloat(from + (to - from) * progress);
78 }
79
80 static inline Color blendFunc(const AnimationBase*, const Color& from, const Color& to, double progress)
81 {
82     return blend(from, to, progress);
83 }
84
85 static inline Length blendFunc(const AnimationBase*, const Length& from, const Length& to, double progress)
86 {
87     return to.blend(from, narrowPrecisionToFloat(progress));
88 }
89
90 static inline LengthSize blendFunc(const AnimationBase* anim, const LengthSize& from, const LengthSize& to, double progress)
91 {
92     return LengthSize(blendFunc(anim, from.width(), to.width(), progress),
93                       blendFunc(anim, from.height(), to.height(), progress));
94 }
95
96 static inline IntSize blendFunc(const AnimationBase* anim, const IntSize& from, const IntSize& to, double progress)
97 {
98     return IntSize(blendFunc(anim, from.width(), to.width(), progress),
99                    blendFunc(anim, from.height(), to.height(), progress));
100 }
101
102 static inline ShadowStyle blendFunc(const AnimationBase* anim, ShadowStyle from, ShadowStyle to, double progress)
103 {
104     if (from == to)
105         return to;
106
107     double fromVal = from == Normal ? 1 : 0;
108     double toVal = to == Normal ? 1 : 0;
109     double result = blendFunc(anim, fromVal, toVal, progress);
110     return result > 0 ? Normal : Inset;
111 }
112
113 static inline PassOwnPtr<ShadowData> blendFunc(const AnimationBase* anim, const ShadowData* from, const ShadowData* to, double progress)
114 {
115     ASSERT(from && to);
116     if (from->style() != to->style())
117         return adoptPtr(new ShadowData(*to));
118
119     return adoptPtr(new ShadowData(blend(from->location(), to->location(), progress),
120                                    blend(from->radius(), to->radius(), progress),
121                                    blend(from->spread(), to->spread(), progress),
122                                    blendFunc(anim, from->style(), to->style(), progress),
123                                    from->isWebkitBoxShadow(),
124                                    blend(from->color(), to->color(), progress)));
125 }
126
127 static inline TransformOperations blendFunc(const AnimationBase* anim, const TransformOperations& from, const TransformOperations& to, double progress)
128 {
129     if (anim->isTransformFunctionListValid())
130         return to.blendByMatchingOperations(from, progress);
131     return to.blendByUsingMatrixInterpolation(from, progress, anim->renderer()->isBox() ? toRenderBox(anim->renderer())->borderBoxRect().size() : LayoutSize());
132 }
133
134 static inline PassRefPtr<ClipPathOperation> blendFunc(const AnimationBase*, ClipPathOperation* from, ClipPathOperation* to, double progress)
135 {
136     if (!from || !to)
137         return to;
138
139     // Other clip-path operations than BasicShapes can not be animated.
140     if (from->getOperationType() != ClipPathOperation::SHAPE || to->getOperationType() != ClipPathOperation::SHAPE)
141         return to;
142
143     const BasicShape* fromShape = static_cast<ShapeClipPathOperation*>(from)->basicShape();
144     const BasicShape* toShape = static_cast<ShapeClipPathOperation*>(to)->basicShape();
145
146     if (!fromShape->canBlend(toShape))
147         return to;
148
149     return ShapeClipPathOperation::create(toShape->blend(fromShape, progress));
150 }
151
152 #if ENABLE(CSS_SHAPES)
153 static inline PassRefPtr<ShapeValue> blendFunc(const AnimationBase*, ShapeValue* from, ShapeValue* to, double progress)
154 {
155     // FIXME Bug 102723: Shape-inside should be able to animate a value of 'outside-shape' when shape-outside is set to a BasicShape
156     if (from->type() != ShapeValue::Shape || to->type() != ShapeValue::Shape)
157         return to;
158
159     const BasicShape* fromShape = from->shape();
160     const BasicShape* toShape = to->shape();
161
162     if (!fromShape->canBlend(toShape))
163         return to;
164
165     return ShapeValue::createShapeValue(toShape->blend(fromShape, progress));
166 }
167 #endif
168
169 #if ENABLE(CSS_FILTERS)
170 static inline PassRefPtr<FilterOperation> blendFunc(const AnimationBase* anim, FilterOperation* fromOp, FilterOperation* toOp, double progress, bool blendToPassthrough = false)
171 {
172     ASSERT(toOp);
173     if (toOp->blendingNeedsRendererSize()) {
174         LayoutSize size = anim->renderer()->isBox() ? toRenderBox(anim->renderer())->borderBoxRect().size() : LayoutSize();
175         return toOp->blend(fromOp, progress, size, blendToPassthrough);
176     }
177     return toOp->blend(fromOp, progress, blendToPassthrough);
178 }
179
180 static inline FilterOperations blendFilterOperations(const AnimationBase* anim,  const FilterOperations& from, const FilterOperations& to, double progress)
181 {
182     FilterOperations result;
183     size_t fromSize = from.operations().size();
184     size_t toSize = to.operations().size();
185     size_t size = max(fromSize, toSize);
186     for (size_t i = 0; i < size; i++) {
187         RefPtr<FilterOperation> fromOp = (i < fromSize) ? from.operations()[i].get() : 0;
188         RefPtr<FilterOperation> toOp = (i < toSize) ? to.operations()[i].get() : 0;
189         RefPtr<FilterOperation> blendedOp = toOp ? blendFunc(anim, fromOp.get(), toOp.get(), progress) : (fromOp ? blendFunc(anim, 0, fromOp.get(), progress, true) : 0);
190         if (blendedOp)
191             result.operations().append(blendedOp);
192         else {
193             RefPtr<FilterOperation> identityOp = PassthroughFilterOperation::create();
194             if (progress > 0.5)
195                 result.operations().append(toOp ? toOp : identityOp);
196             else
197                 result.operations().append(fromOp ? fromOp : identityOp);
198         }
199     }
200     return result;
201 }
202
203 static inline FilterOperations blendFunc(const AnimationBase* anim, const FilterOperations& from, const FilterOperations& to, double progress)
204 {
205     FilterOperations result;
206
207     // If we have a filter function list, use that to do a per-function animation.
208     if (anim->filterFunctionListsMatch())
209         result = blendFilterOperations(anim, from, to, progress);
210     else {
211         // If the filter function lists don't match, we could try to cross-fade, but don't yet have a way to represent that in CSS.
212         // For now we'll just fail to animate.
213         result = to;
214     }
215
216     return result;
217 }
218
219 static inline PassRefPtr<StyleImage> blendFilter(const AnimationBase* anim, CachedImage* image, const FilterOperations& from, const FilterOperations& to, double progress)
220 {
221     ASSERT(image);
222     FilterOperations filterResult = blendFilterOperations(anim, from, to, progress);
223
224     RefPtr<StyleCachedImage> styledImage = StyleCachedImage::create(image);
225     RefPtr<CSSImageValue> imageValue = CSSImageValue::create(image->url(), styledImage.get());
226     RefPtr<CSSValue> filterValue = ComputedStyleExtractor::valueForFilter(anim->renderer(), anim->renderer()->style(), filterResult, DoNotAdjustPixelValues);
227     RefPtr<CSSFilterImageValue> result = CSSFilterImageValue::create(imageValue, filterValue);
228     result->setFilterOperations(filterResult);
229
230     return StyleGeneratedImage::create(result.get());
231 }
232 #endif // ENABLE(CSS_FILTERS)
233
234 static inline EVisibility blendFunc(const AnimationBase* anim, EVisibility from, EVisibility to, double progress)
235 {
236     // Any non-zero result means we consider the object to be visible. Only at 0 do we consider the object to be
237     // invisible. The invisible value we use (HIDDEN vs. COLLAPSE) depends on the specified from/to values.
238     double fromVal = from == VISIBLE ? 1. : 0.;
239     double toVal = to == VISIBLE ? 1. : 0.;
240     if (fromVal == toVal)
241         return to;
242     double result = blendFunc(anim, fromVal, toVal, progress);
243     return result > 0. ? VISIBLE : (to != VISIBLE ? to : from);
244 }
245
246 static inline LengthBox blendFunc(const AnimationBase* anim, const LengthBox& from, const LengthBox& to, double progress)
247 {
248     LengthBox result(blendFunc(anim, from.top(), to.top(), progress),
249                      blendFunc(anim, from.right(), to.right(), progress),
250                      blendFunc(anim, from.bottom(), to.bottom(), progress),
251                      blendFunc(anim, from.left(), to.left(), progress));
252     return result;
253 }
254
255 #if ENABLE(SVG)
256 static inline SVGLength blendFunc(const AnimationBase*, const SVGLength& from, const SVGLength& to, double progress)
257 {
258     return to.blend(from, narrowPrecisionToFloat(progress));
259 }
260 static inline Vector<SVGLength> blendFunc(const AnimationBase*, const Vector<SVGLength>& from, const Vector<SVGLength>& to, double progress)
261 {
262     size_t fromLength = from.size();
263     size_t toLength = to.size();
264     if (!fromLength)
265         return !progress ? from : to;
266     if (!toLength)
267         return progress == 1 ? from : to;
268     size_t resultLength = fromLength;
269     if (fromLength != toLength) {
270         if (!remainder(std::max(fromLength, toLength), std::min(fromLength, toLength)))
271             resultLength = std::max(fromLength, toLength);
272         else
273             resultLength = fromLength * toLength;
274     }
275     Vector<SVGLength> result(resultLength);
276     for (size_t i = 0; i < resultLength; ++i)
277         result[i] = to[i % toLength].blend(from[i % fromLength], narrowPrecisionToFloat(progress));
278     return result;
279 }
280 #endif
281
282 static inline PassRefPtr<StyleImage> crossfadeBlend(const AnimationBase*, StyleCachedImage* fromStyleImage, StyleCachedImage* toStyleImage, double progress)
283 {
284     // If progress is at one of the extremes, we want getComputedStyle to show the image,
285     // not a completed cross-fade, so we hand back one of the existing images.
286     if (!progress)
287         return fromStyleImage;
288     if (progress == 1)
289         return toStyleImage;
290
291     CachedImage* fromCachedImage = static_cast<CachedImage*>(fromStyleImage->data());
292     CachedImage* toCachedImage = static_cast<CachedImage*>(toStyleImage->data());
293
294     RefPtr<CSSImageValue> fromImageValue = CSSImageValue::create(fromCachedImage->url(), fromStyleImage);
295     RefPtr<CSSImageValue> toImageValue = CSSImageValue::create(toCachedImage->url(), toStyleImage);
296     RefPtr<CSSCrossfadeValue> crossfadeValue = CSSCrossfadeValue::create(fromImageValue, toImageValue);
297
298     crossfadeValue->setPercentage(CSSPrimitiveValue::create(progress, CSSPrimitiveValue::CSS_NUMBER));
299
300     return StyleGeneratedImage::create(crossfadeValue.get());
301 }
302
303 static inline PassRefPtr<StyleImage> blendFunc(const AnimationBase* anim, StyleImage* from, StyleImage* to, double progress)
304 {
305     if (!from || !to)
306         return to;
307
308     // Animation between two generated images. Cross fade for all other cases.
309     if (from->isGeneratedImage() && to->isGeneratedImage()) {
310         CSSImageGeneratorValue* fromGenerated = toStyleGeneratedImage(from)->imageValue();
311         CSSImageGeneratorValue* toGenerated = toStyleGeneratedImage(to)->imageValue();
312
313 #if ENABLE(CSS_FILTERS)
314         if (fromGenerated->isFilterImageValue() && toGenerated->isFilterImageValue()) {
315             // Animation of generated images just possible if input images are equal.
316             // Otherwise fall back to cross fade animation.
317             CSSFilterImageValue& fromFilter = *toCSSFilterImageValue(fromGenerated);
318             CSSFilterImageValue& toFilter = *toCSSFilterImageValue(toGenerated);
319             if (fromFilter.equalInputImages(toFilter) && fromFilter.cachedImage())
320                 return blendFilter(anim, fromFilter.cachedImage(), fromFilter.filterOperations(), toFilter.filterOperations(), progress);
321         }
322 #endif
323
324         if (fromGenerated->isCrossfadeValue() && toGenerated->isCrossfadeValue()) {
325             CSSCrossfadeValue& fromCrossfade = *toCSSCrossfadeValue(fromGenerated);
326             CSSCrossfadeValue& toCrossfade = *toCSSCrossfadeValue(toGenerated);
327             if (fromCrossfade.equalInputImages(toCrossfade))
328                 return StyleGeneratedImage::create(toCrossfade.blend(fromCrossfade, progress).get());
329         }
330
331         // FIXME: Add support for animation between two *gradient() functions.
332         // https://bugs.webkit.org/show_bug.cgi?id=119956
333 #if ENABLE(CSS_FILTERS)
334     } else if (from->isGeneratedImage() && to->isCachedImage()) {
335         CSSImageGeneratorValue* fromGenerated = toStyleGeneratedImage(from)->imageValue();
336         if (fromGenerated->isFilterImageValue()) {
337             CSSFilterImageValue& fromFilter = *toCSSFilterImageValue(fromGenerated);
338             if (fromFilter.cachedImage() && static_cast<StyleCachedImage*>(to)->cachedImage() == fromFilter.cachedImage())
339                 return blendFilter(anim, fromFilter.cachedImage(), fromFilter.filterOperations(), FilterOperations(), progress);
340         }
341         // FIXME: Add interpolation between cross-fade and image source.
342     } else if (from->isCachedImage() && to->isGeneratedImage()) {
343         CSSImageGeneratorValue* toGenerated = toStyleGeneratedImage(to)->imageValue();
344         if (toGenerated->isFilterImageValue()) {
345             CSSFilterImageValue& toFilter = *toCSSFilterImageValue(toGenerated);
346             if (toFilter.cachedImage() && static_cast<StyleCachedImage*>(from)->cachedImage() == toFilter.cachedImage())     
347                 return blendFilter(anim, toFilter.cachedImage(), FilterOperations(), toFilter.filterOperations(), progress);
348         }
349 #endif
350         // FIXME: Add interpolation between image source and cross-fade.
351     }
352
353     // FIXME: Add support cross fade between cached and generated images.
354     // https://bugs.webkit.org/show_bug.cgi?id=78293
355     if (from->isCachedImage() && to->isCachedImage())
356         return crossfadeBlend(anim, static_cast<StyleCachedImage*>(from), static_cast<StyleCachedImage*>(to), progress);
357
358     return to;
359 }
360
361 static inline NinePieceImage blendFunc(const AnimationBase* anim, const NinePieceImage& from, const NinePieceImage& to, double progress)
362 {
363     if (!from.hasImage() || !to.hasImage())
364         return to;
365
366     // FIXME (74112): Support transitioning between NinePieceImages that differ by more than image content.
367
368     if (from.imageSlices() != to.imageSlices() || from.borderSlices() != to.borderSlices() || from.outset() != to.outset() || from.fill() != to.fill() || from.horizontalRule() != to.horizontalRule() || from.verticalRule() != to.verticalRule())
369         return to;
370
371     if (from.image()->imageSize(anim->renderer(), 1.0) != to.image()->imageSize(anim->renderer(), 1.0))
372         return to;
373
374     RefPtr<StyleImage> newContentImage = blendFunc(anim, from.image(), to.image(), progress);
375
376     return NinePieceImage(newContentImage, from.imageSlices(), from.fill(), from.borderSlices(), from.outset(), from.horizontalRule(), from.verticalRule());
377 }
378
379 class AnimationPropertyWrapperBase {
380     WTF_MAKE_NONCOPYABLE(AnimationPropertyWrapperBase);
381     WTF_MAKE_FAST_ALLOCATED;
382 public:
383     AnimationPropertyWrapperBase(CSSPropertyID prop)
384         : m_prop(prop)
385     {
386     }
387
388     virtual ~AnimationPropertyWrapperBase() { }
389
390     virtual bool isShorthandWrapper() const { return false; }
391     virtual bool equals(const RenderStyle* a, const RenderStyle* b) const = 0;
392     virtual void blend(const AnimationBase*, RenderStyle*, const RenderStyle*, const RenderStyle*, double) const = 0;
393
394     CSSPropertyID property() const { return m_prop; }
395
396 #if USE(ACCELERATED_COMPOSITING)
397     virtual bool animationIsAccelerated() const { return false; }
398 #endif
399
400 private:
401     CSSPropertyID m_prop;
402 };
403
404 template <typename T>
405 class PropertyWrapperGetter : public AnimationPropertyWrapperBase {
406 public:
407     PropertyWrapperGetter(CSSPropertyID prop, T (RenderStyle::*getter)() const)
408         : AnimationPropertyWrapperBase(prop)
409         , m_getter(getter)
410     {
411     }
412
413     virtual bool equals(const RenderStyle* a, const RenderStyle* b) const
414     {
415         // If the style pointers are the same, don't bother doing the test.
416         // If either is null, return false. If both are null, return true.
417         if ((!a && !b) || a == b)
418             return true;
419         if (!a || !b)
420             return false;
421         return (a->*m_getter)() == (b->*m_getter)();
422     }
423
424 protected:
425     T (RenderStyle::*m_getter)() const;
426 };
427
428 template <typename T>
429 class PropertyWrapper : public PropertyWrapperGetter<T> {
430 public:
431     PropertyWrapper(CSSPropertyID prop, T (RenderStyle::*getter)() const, void (RenderStyle::*setter)(T))
432         : PropertyWrapperGetter<T>(prop, getter)
433         , m_setter(setter)
434     {
435     }
436
437     virtual void blend(const AnimationBase* anim, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress) const
438     {
439         (dst->*m_setter)(blendFunc(anim, (a->*PropertyWrapperGetter<T>::m_getter)(), (b->*PropertyWrapperGetter<T>::m_getter)(), progress));
440     }
441
442 protected:
443     void (RenderStyle::*m_setter)(T);
444 };
445
446 template <typename T>
447 class RefCountedPropertyWrapper : public PropertyWrapperGetter<T*> {
448 public:
449     RefCountedPropertyWrapper(CSSPropertyID prop, T* (RenderStyle::*getter)() const, void (RenderStyle::*setter)(PassRefPtr<T>))
450         : PropertyWrapperGetter<T*>(prop, getter)
451         , m_setter(setter)
452     {
453     }
454
455     virtual void blend(const AnimationBase* anim, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress) const
456     {
457         (dst->*m_setter)(blendFunc(anim, (a->*PropertyWrapperGetter<T*>::m_getter)(), (b->*PropertyWrapperGetter<T*>::m_getter)(), progress));
458     }
459
460 protected:
461     void (RenderStyle::*m_setter)(PassRefPtr<T>);
462 };
463
464
465 class PropertyWrapperClipPath : public RefCountedPropertyWrapper<ClipPathOperation> {
466 public:
467     PropertyWrapperClipPath(CSSPropertyID prop, ClipPathOperation* (RenderStyle::*getter)() const, void (RenderStyle::*setter)(PassRefPtr<ClipPathOperation>))
468         : RefCountedPropertyWrapper<ClipPathOperation>(prop, getter, setter)
469     {
470     }
471 };
472
473 #if ENABLE(CSS_SHAPES)
474 class PropertyWrapperShape : public RefCountedPropertyWrapper<ShapeValue> {
475 public:
476     PropertyWrapperShape(CSSPropertyID prop, ShapeValue* (RenderStyle::*getter)() const, void (RenderStyle::*setter)(PassRefPtr<ShapeValue>))
477         : RefCountedPropertyWrapper<ShapeValue>(prop, getter, setter)
478     {
479     }
480 };
481 #endif
482
483 class StyleImagePropertyWrapper : public RefCountedPropertyWrapper<StyleImage> {
484 public:
485     StyleImagePropertyWrapper(CSSPropertyID prop, StyleImage* (RenderStyle::*getter)() const, void (RenderStyle::*setter)(PassRefPtr<StyleImage>))
486         : RefCountedPropertyWrapper<StyleImage>(prop, getter, setter)
487     {
488     }
489
490     virtual bool equals(const RenderStyle* a, const RenderStyle* b) const
491     {
492        // If the style pointers are the same, don't bother doing the test.
493        // If either is null, return false. If both are null, return true.
494        if (a == b)
495            return true;
496        if (!a || !b)
497             return false;
498
499         StyleImage* imageA = (a->*m_getter)();
500         StyleImage* imageB = (b->*m_getter)();
501         return StyleImage::imagesEquivalent(imageA, imageB);
502     }
503 };
504
505 class PropertyWrapperColor : public PropertyWrapperGetter<Color> {
506 public:
507     PropertyWrapperColor(CSSPropertyID prop, Color (RenderStyle::*getter)() const, void (RenderStyle::*setter)(const Color&))
508         : PropertyWrapperGetter<Color>(prop, getter)
509         , m_setter(setter)
510     {
511     }
512
513     virtual void blend(const AnimationBase* anim, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress) const
514     {
515         (dst->*m_setter)(blendFunc(anim, (a->*PropertyWrapperGetter<Color>::m_getter)(), (b->*PropertyWrapperGetter<Color>::m_getter)(), progress));
516     }
517
518 protected:
519     void (RenderStyle::*m_setter)(const Color&);
520 };
521
522 #if USE(ACCELERATED_COMPOSITING)
523 class PropertyWrapperAcceleratedOpacity : public PropertyWrapper<float> {
524 public:
525     PropertyWrapperAcceleratedOpacity()
526         : PropertyWrapper<float>(CSSPropertyOpacity, &RenderStyle::opacity, &RenderStyle::setOpacity)
527     {
528     }
529
530     virtual bool animationIsAccelerated() const { return true; }
531
532     virtual void blend(const AnimationBase* anim, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress) const
533     {
534         float fromOpacity = a->opacity();
535
536         // This makes sure we put the object being animated into a RenderLayer during the animation
537         dst->setOpacity(blendFunc(anim, (fromOpacity == 1) ? 0.999999f : fromOpacity, b->opacity(), progress));
538     }
539 };
540
541 class PropertyWrapperAcceleratedTransform : public PropertyWrapper<const TransformOperations&> {
542 public:
543     PropertyWrapperAcceleratedTransform()
544         : PropertyWrapper<const TransformOperations&>(CSSPropertyWebkitTransform, &RenderStyle::transform, &RenderStyle::setTransform)
545     {
546     }
547
548     virtual bool animationIsAccelerated() const { return true; }
549
550     virtual void blend(const AnimationBase* anim, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress) const
551     {
552         dst->setTransform(blendFunc(anim, a->transform(), b->transform(), progress));
553     }
554 };
555
556 #if ENABLE(CSS_FILTERS)
557 class PropertyWrapperAcceleratedFilter : public PropertyWrapper<const FilterOperations&> {
558 public:
559     PropertyWrapperAcceleratedFilter()
560         : PropertyWrapper<const FilterOperations&>(CSSPropertyWebkitFilter, &RenderStyle::filter, &RenderStyle::setFilter)
561     {
562     }
563
564     virtual bool animationIsAccelerated() const { return true; }
565
566     virtual void blend(const AnimationBase* anim, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress) const
567     {
568         dst->setFilter(blendFunc(anim, a->filter(), b->filter(), progress));
569     }
570 };
571 #endif
572 #endif // USE(ACCELERATED_COMPOSITING)
573
574 static inline size_t shadowListLength(const ShadowData* shadow)
575 {
576     size_t count;
577     for (count = 0; shadow; shadow = shadow->next())
578         ++count;
579     return count;
580 }
581
582 static inline const ShadowData* shadowForBlending(const ShadowData* srcShadow, const ShadowData* otherShadow)
583 {
584     DEFINE_STATIC_LOCAL(ShadowData, defaultShadowData, (IntPoint(), 0, 0, Normal, false, Color::transparent));
585     DEFINE_STATIC_LOCAL(ShadowData, defaultInsetShadowData, (IntPoint(), 0, 0, Inset, false, Color::transparent));
586
587     DEFINE_STATIC_LOCAL(ShadowData, defaultWebKitBoxShadowData, (IntPoint(), 0, 0, Normal, true, Color::transparent));
588     DEFINE_STATIC_LOCAL(ShadowData, defaultInsetWebKitBoxShadowData, (IntPoint(), 0, 0, Inset, true, Color::transparent));
589
590     if (srcShadow)
591         return srcShadow;
592
593     if (otherShadow->style() == Inset)
594         return otherShadow->isWebkitBoxShadow() ? &defaultInsetWebKitBoxShadowData : &defaultInsetShadowData;
595
596     return otherShadow->isWebkitBoxShadow() ? &defaultWebKitBoxShadowData : &defaultShadowData;
597 }
598
599 class PropertyWrapperShadow : public AnimationPropertyWrapperBase {
600 public:
601     PropertyWrapperShadow(CSSPropertyID prop, const ShadowData* (RenderStyle::*getter)() const, void (RenderStyle::*setter)(PassOwnPtr<ShadowData>, bool))
602         : AnimationPropertyWrapperBase(prop)
603         , m_getter(getter)
604         , m_setter(setter)
605     {
606     }
607
608     virtual bool equals(const RenderStyle* a, const RenderStyle* b) const
609     {
610         const ShadowData* shadowA = (a->*m_getter)();
611         const ShadowData* shadowB = (b->*m_getter)();
612
613         while (true) {
614             // end of both lists
615             if (!shadowA && !shadowB)
616                 return true;
617
618             // end of just one of the lists
619             if (!shadowA || !shadowB)
620                 return false;
621
622             if (*shadowA != *shadowB)
623                 return false;
624
625             shadowA = shadowA->next();
626             shadowB = shadowB->next();
627         }
628
629         return true;
630     }
631
632     virtual void blend(const AnimationBase* anim, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress) const
633     {
634         const ShadowData* shadowA = (a->*m_getter)();
635         const ShadowData* shadowB = (b->*m_getter)();
636
637         int fromLength = shadowListLength(shadowA);
638         int toLength = shadowListLength(shadowB);
639
640         if (fromLength == toLength || (fromLength <= 1 && toLength <= 1)) {
641             (dst->*m_setter)(blendSimpleOrMatchedShadowLists(anim, progress, shadowA, shadowB), false);
642             return;
643         }
644
645         (dst->*m_setter)(blendMismatchedShadowLists(anim, progress, shadowA, shadowB, fromLength, toLength), false);
646     }
647
648 private:
649     PassOwnPtr<ShadowData> blendSimpleOrMatchedShadowLists(const AnimationBase* anim, double progress, const ShadowData* shadowA, const ShadowData* shadowB) const
650     {
651         OwnPtr<ShadowData> newShadowData;
652         ShadowData* lastShadow = 0;
653
654         while (shadowA || shadowB) {
655             const ShadowData* srcShadow = shadowForBlending(shadowA, shadowB);
656             const ShadowData* dstShadow = shadowForBlending(shadowB, shadowA);
657
658             OwnPtr<ShadowData> blendedShadow = blendFunc(anim, srcShadow, dstShadow, progress);
659             ShadowData* blendedShadowPtr = blendedShadow.get();
660
661             if (!lastShadow)
662                 newShadowData = blendedShadow.release();
663             else
664                 lastShadow->setNext(blendedShadow.release());
665
666             lastShadow = blendedShadowPtr;
667
668             shadowA = shadowA ? shadowA->next() : 0;
669             shadowB = shadowB ? shadowB->next() : 0;
670         }
671
672         return newShadowData.release();
673     }
674
675     PassOwnPtr<ShadowData> blendMismatchedShadowLists(const AnimationBase* anim, double progress, const ShadowData* shadowA, const ShadowData* shadowB, int fromLength, int toLength) const
676     {
677         // The shadows in ShadowData are stored in reverse order, so when animating mismatched lists,
678         // reverse them and match from the end.
679         Vector<const ShadowData*, 4> fromShadows(fromLength);
680         for (int i = fromLength - 1; i >= 0; --i) {
681             fromShadows[i] = shadowA;
682             shadowA = shadowA->next();
683         }
684
685         Vector<const ShadowData*, 4> toShadows(toLength);
686         for (int i = toLength - 1; i >= 0; --i) {
687             toShadows[i] = shadowB;
688             shadowB = shadowB->next();
689         }
690
691         OwnPtr<ShadowData> newShadowData;
692
693         int maxLength = max(fromLength, toLength);
694         for (int i = 0; i < maxLength; ++i) {
695             const ShadowData* fromShadow = i < fromLength ? fromShadows[i] : 0;
696             const ShadowData* toShadow = i < toLength ? toShadows[i] : 0;
697
698             const ShadowData* srcShadow = shadowForBlending(fromShadow, toShadow);
699             const ShadowData* dstShadow = shadowForBlending(toShadow, fromShadow);
700
701             OwnPtr<ShadowData> blendedShadow = blendFunc(anim, srcShadow, dstShadow, progress);
702             // Insert at the start of the list to preserve the order.
703             blendedShadow->setNext(newShadowData.release());
704             newShadowData = blendedShadow.release();
705         }
706
707         return newShadowData.release();
708     }
709
710     const ShadowData* (RenderStyle::*m_getter)() const;
711     void (RenderStyle::*m_setter)(PassOwnPtr<ShadowData>, bool);
712 };
713
714 class PropertyWrapperMaybeInvalidColor : public AnimationPropertyWrapperBase {
715 public:
716     PropertyWrapperMaybeInvalidColor(CSSPropertyID prop, Color (RenderStyle::*getter)() const, void (RenderStyle::*setter)(const Color&))
717         : AnimationPropertyWrapperBase(prop)
718         , m_getter(getter)
719         , m_setter(setter)
720     {
721     }
722
723     virtual bool equals(const RenderStyle* a, const RenderStyle* b) const
724     {
725         Color fromColor = (a->*m_getter)();
726         Color toColor = (b->*m_getter)();
727
728         if (!fromColor.isValid() && !toColor.isValid())
729             return true;
730
731         if (!fromColor.isValid())
732             fromColor = a->color();
733         if (!toColor.isValid())
734             toColor = b->color();
735
736         return fromColor == toColor;
737     }
738
739     virtual void blend(const AnimationBase* anim, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress) const
740     {
741         Color fromColor = (a->*m_getter)();
742         Color toColor = (b->*m_getter)();
743
744         if (!fromColor.isValid() && !toColor.isValid())
745             return;
746
747         if (!fromColor.isValid())
748             fromColor = a->color();
749         if (!toColor.isValid())
750             toColor = b->color();
751         (dst->*m_setter)(blendFunc(anim, fromColor, toColor, progress));
752     }
753
754 private:
755     Color (RenderStyle::*m_getter)() const;
756     void (RenderStyle::*m_setter)(const Color&);
757 };
758
759
760 enum MaybeInvalidColorTag { MaybeInvalidColor };
761 class PropertyWrapperVisitedAffectedColor : public AnimationPropertyWrapperBase {
762 public:
763     PropertyWrapperVisitedAffectedColor(CSSPropertyID prop, Color (RenderStyle::*getter)() const, void (RenderStyle::*setter)(const Color&),
764                                         Color (RenderStyle::*visitedGetter)() const, void (RenderStyle::*visitedSetter)(const Color&))
765         : AnimationPropertyWrapperBase(prop)
766         , m_wrapper(adoptPtr(new PropertyWrapperColor(prop, getter, setter)))
767         , m_visitedWrapper(adoptPtr(new PropertyWrapperColor(prop, visitedGetter, visitedSetter)))
768     {
769     }
770     PropertyWrapperVisitedAffectedColor(CSSPropertyID prop, MaybeInvalidColorTag, Color (RenderStyle::*getter)() const, void (RenderStyle::*setter)(const Color&),
771                                         Color (RenderStyle::*visitedGetter)() const, void (RenderStyle::*visitedSetter)(const Color&))
772         : AnimationPropertyWrapperBase(prop)
773         , m_wrapper(adoptPtr(new PropertyWrapperMaybeInvalidColor(prop, getter, setter)))
774         , m_visitedWrapper(adoptPtr(new PropertyWrapperMaybeInvalidColor(prop, visitedGetter, visitedSetter)))
775     {
776     }
777     virtual bool equals(const RenderStyle* a, const RenderStyle* b) const
778     {
779         return m_wrapper->equals(a, b) && m_visitedWrapper->equals(a, b);
780     }
781     virtual void blend(const AnimationBase* anim, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress) const
782     {
783         m_wrapper->blend(anim, dst, a, b, progress);
784         m_visitedWrapper->blend(anim, dst, a, b, progress);
785     }
786
787 private:
788     OwnPtr<AnimationPropertyWrapperBase> m_wrapper;
789     OwnPtr<AnimationPropertyWrapperBase> m_visitedWrapper;
790 };
791
792 // Wrapper base class for an animatable property in a FillLayer
793 class FillLayerAnimationPropertyWrapperBase {
794 public:
795     FillLayerAnimationPropertyWrapperBase()
796     {
797     }
798
799     virtual ~FillLayerAnimationPropertyWrapperBase() { }
800
801     virtual bool equals(const FillLayer*, const FillLayer*) const = 0;
802     virtual void blend(const AnimationBase*, FillLayer*, const FillLayer*, const FillLayer*, double) const = 0;
803 };
804
805 template <typename T>
806 class FillLayerPropertyWrapperGetter : public FillLayerAnimationPropertyWrapperBase {
807     WTF_MAKE_NONCOPYABLE(FillLayerPropertyWrapperGetter);
808 public:
809     FillLayerPropertyWrapperGetter(T (FillLayer::*getter)() const)
810         : m_getter(getter)
811     {
812     }
813
814     virtual bool equals(const FillLayer* a, const FillLayer* b) const
815     {
816        // If the style pointers are the same, don't bother doing the test.
817        // If either is null, return false. If both are null, return true.
818        if ((!a && !b) || a == b)
819            return true;
820        if (!a || !b)
821             return false;
822         return (a->*m_getter)() == (b->*m_getter)();
823     }
824
825 protected:
826     T (FillLayer::*m_getter)() const;
827 };
828
829 template <typename T>
830 class FillLayerPropertyWrapper : public FillLayerPropertyWrapperGetter<T> {
831 public:
832     FillLayerPropertyWrapper(T (FillLayer::*getter)() const, void (FillLayer::*setter)(T))
833         : FillLayerPropertyWrapperGetter<T>(getter)
834         , m_setter(setter)
835     {
836     }
837
838     virtual void blend(const AnimationBase* anim, FillLayer* dst, const FillLayer* a, const FillLayer* b, double progress) const
839     {
840         (dst->*m_setter)(blendFunc(anim, (a->*FillLayerPropertyWrapperGetter<T>::m_getter)(), (b->*FillLayerPropertyWrapperGetter<T>::m_getter)(), progress));
841     }
842
843 protected:
844     void (FillLayer::*m_setter)(T);
845 };
846
847 template <typename T>
848 class FillLayerRefCountedPropertyWrapper : public FillLayerPropertyWrapperGetter<T*> {
849 public:
850     FillLayerRefCountedPropertyWrapper(T* (FillLayer::*getter)() const, void (FillLayer::*setter)(PassRefPtr<T>))
851         : FillLayerPropertyWrapperGetter<T*>(getter)
852         , m_setter(setter)
853     {
854     }
855
856     virtual void blend(const AnimationBase* anim, FillLayer* dst, const FillLayer* a, const FillLayer* b, double progress) const
857     {
858         (dst->*m_setter)(blendFunc(anim, (a->*FillLayerPropertyWrapperGetter<T*>::m_getter)(), (b->*FillLayerPropertyWrapperGetter<T*>::m_getter)(), progress));
859     }
860
861 protected:
862     void (FillLayer::*m_setter)(PassRefPtr<T>);
863 };
864
865 class FillLayerStyleImagePropertyWrapper : public FillLayerRefCountedPropertyWrapper<StyleImage> {
866 public:
867     FillLayerStyleImagePropertyWrapper(StyleImage* (FillLayer::*getter)() const, void (FillLayer::*setter)(PassRefPtr<StyleImage>))
868         : FillLayerRefCountedPropertyWrapper<StyleImage>(getter, setter)
869     {
870     }
871
872     virtual bool equals(const FillLayer* a, const FillLayer* b) const
873     {
874        // If the style pointers are the same, don't bother doing the test.
875        // If either is null, return false. If both are null, return true.
876        if (a == b)
877            return true;
878        if (!a || !b)
879             return false;
880
881         StyleImage* imageA = (a->*m_getter)();
882         StyleImage* imageB = (b->*m_getter)();
883         return StyleImage::imagesEquivalent(imageA, imageB);
884     }
885 };
886
887
888 class FillLayersPropertyWrapper : public AnimationPropertyWrapperBase {
889 public:
890     typedef const FillLayer* (RenderStyle::*LayersGetter)() const;
891     typedef FillLayer* (RenderStyle::*LayersAccessor)();
892
893     FillLayersPropertyWrapper(CSSPropertyID prop, LayersGetter getter, LayersAccessor accessor)
894         : AnimationPropertyWrapperBase(prop)
895         , m_layersGetter(getter)
896         , m_layersAccessor(accessor)
897     {
898         switch (prop) {
899         case CSSPropertyBackgroundPositionX:
900         case CSSPropertyWebkitMaskPositionX:
901             m_fillLayerPropertyWrapper = new FillLayerPropertyWrapper<Length>(&FillLayer::xPosition, &FillLayer::setXPosition);
902             break;
903         case CSSPropertyBackgroundPositionY:
904         case CSSPropertyWebkitMaskPositionY:
905             m_fillLayerPropertyWrapper = new FillLayerPropertyWrapper<Length>(&FillLayer::yPosition, &FillLayer::setYPosition);
906             break;
907         case CSSPropertyBackgroundSize:
908         case CSSPropertyWebkitBackgroundSize:
909         case CSSPropertyWebkitMaskSize:
910             m_fillLayerPropertyWrapper = new FillLayerPropertyWrapper<LengthSize>(&FillLayer::sizeLength, &FillLayer::setSizeLength);
911             break;
912         case CSSPropertyBackgroundImage:
913             m_fillLayerPropertyWrapper = new FillLayerStyleImagePropertyWrapper(&FillLayer::image, &FillLayer::setImage);
914             break;
915         default:
916             break;
917         }
918     }
919
920     virtual bool equals(const RenderStyle* a, const RenderStyle* b) const
921     {
922         const FillLayer* fromLayer = (a->*m_layersGetter)();
923         const FillLayer* toLayer = (b->*m_layersGetter)();
924
925         while (fromLayer && toLayer) {
926             if (!m_fillLayerPropertyWrapper->equals(fromLayer, toLayer))
927                 return false;
928
929             fromLayer = fromLayer->next();
930             toLayer = toLayer->next();
931         }
932
933         return true;
934     }
935
936     virtual void blend(const AnimationBase* anim, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress) const
937     {
938         const FillLayer* aLayer = (a->*m_layersGetter)();
939         const FillLayer* bLayer = (b->*m_layersGetter)();
940         FillLayer* dstLayer = (dst->*m_layersAccessor)();
941
942         while (aLayer && bLayer && dstLayer) {
943             m_fillLayerPropertyWrapper->blend(anim, dstLayer, aLayer, bLayer, progress);
944             aLayer = aLayer->next();
945             bLayer = bLayer->next();
946             dstLayer = dstLayer->next();
947         }
948     }
949
950 private:
951     FillLayerAnimationPropertyWrapperBase* m_fillLayerPropertyWrapper;
952
953     LayersGetter m_layersGetter;
954     LayersAccessor m_layersAccessor;
955 };
956
957 class ShorthandPropertyWrapper : public AnimationPropertyWrapperBase {
958 public:
959     ShorthandPropertyWrapper(CSSPropertyID property, Vector<AnimationPropertyWrapperBase*> longhandWrappers)
960         : AnimationPropertyWrapperBase(property)
961     {
962         m_propertyWrappers.swap(longhandWrappers);
963     }
964
965     virtual bool isShorthandWrapper() const { return true; }
966
967     virtual bool equals(const RenderStyle* a, const RenderStyle* b) const
968     {
969         Vector<AnimationPropertyWrapperBase*>::const_iterator end = m_propertyWrappers.end();
970         for (Vector<AnimationPropertyWrapperBase*>::const_iterator it = m_propertyWrappers.begin(); it != end; ++it) {
971             if (!(*it)->equals(a, b))
972                 return false;
973         }
974         return true;
975     }
976
977     virtual void blend(const AnimationBase* anim, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress) const
978     {
979         Vector<AnimationPropertyWrapperBase*>::const_iterator end = m_propertyWrappers.end();
980         for (Vector<AnimationPropertyWrapperBase*>::const_iterator it = m_propertyWrappers.begin(); it != end; ++it)
981             (*it)->blend(anim, dst, a, b, progress);
982     }
983
984     const Vector<AnimationPropertyWrapperBase*> propertyWrappers() const { return m_propertyWrappers; }
985
986 private:
987     Vector<AnimationPropertyWrapperBase*> m_propertyWrappers;
988 };
989
990 class PropertyWrapperFlex : public AnimationPropertyWrapperBase {
991 public:
992     PropertyWrapperFlex() : AnimationPropertyWrapperBase(CSSPropertyWebkitFlex)
993     {
994     }
995
996     virtual bool equals(const RenderStyle* a, const RenderStyle* b) const
997     {
998         // If the style pointers are the same, don't bother doing the test.
999         // If either is null, return false. If both are null, return true.
1000         if ((!a && !b) || a == b)
1001             return true;
1002         if (!a || !b)
1003             return false;
1004
1005         return a->flexBasis() == b->flexBasis() && a->flexGrow() == b->flexGrow() && a->flexShrink() == b->flexShrink();
1006     }
1007
1008     virtual void blend(const AnimationBase* anim, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress) const
1009     {
1010         dst->setFlexBasis(blendFunc(anim, a->flexBasis(), b->flexBasis(), progress));
1011         dst->setFlexGrow(blendFunc(anim, a->flexGrow(), b->flexGrow(), progress));
1012         dst->setFlexShrink(blendFunc(anim, a->flexShrink(), b->flexShrink(), progress));
1013     }
1014 };
1015
1016 #if ENABLE(SVG)
1017 class PropertyWrapperSVGPaint : public AnimationPropertyWrapperBase {
1018 public:
1019     PropertyWrapperSVGPaint(CSSPropertyID prop, const SVGPaint::SVGPaintType& (RenderStyle::*paintTypeGetter)() const, Color (RenderStyle::*getter)() const, void (RenderStyle::*setter)(const Color&))
1020         : AnimationPropertyWrapperBase(prop)
1021         , m_paintTypeGetter(paintTypeGetter)
1022         , m_getter(getter)
1023         , m_setter(setter)
1024     {
1025     }
1026
1027     virtual bool equals(const RenderStyle* a, const RenderStyle* b) const
1028     {
1029         if ((a->*m_paintTypeGetter)() != (b->*m_paintTypeGetter)())
1030             return false;
1031
1032         // We only support animations between SVGPaints that are pure Color values.
1033         // For everything else we must return true for this method, otherwise
1034         // we will try to animate between values forever.
1035         if ((a->*m_paintTypeGetter)() == SVGPaint::SVG_PAINTTYPE_RGBCOLOR) {
1036             Color fromColor = (a->*m_getter)();
1037             Color toColor = (b->*m_getter)();
1038
1039             if (!fromColor.isValid() && !toColor.isValid())
1040                 return true;
1041
1042             if (!fromColor.isValid())
1043                 fromColor = Color();
1044             if (!toColor.isValid())
1045                 toColor = Color();
1046
1047             return fromColor == toColor;
1048         }
1049         return true;
1050     }
1051
1052     virtual void blend(const AnimationBase* anim, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress) const
1053     {
1054         if ((a->*m_paintTypeGetter)() != SVGPaint::SVG_PAINTTYPE_RGBCOLOR
1055             || (b->*m_paintTypeGetter)() != SVGPaint::SVG_PAINTTYPE_RGBCOLOR)
1056             return;
1057
1058         Color fromColor = (a->*m_getter)();
1059         Color toColor = (b->*m_getter)();
1060
1061         if (!fromColor.isValid() && !toColor.isValid())
1062             return;
1063
1064         if (!fromColor.isValid())
1065             fromColor = Color();
1066         if (!toColor.isValid())
1067             toColor = Color();
1068         (dst->*m_setter)(blendFunc(anim, fromColor, toColor, progress));
1069     }
1070
1071 private:
1072     const SVGPaint::SVGPaintType& (RenderStyle::*m_paintTypeGetter)() const;
1073     Color (RenderStyle::*m_getter)() const;
1074     void (RenderStyle::*m_setter)(const Color&);
1075 };
1076 #endif
1077
1078 class CSSPropertyAnimationWrapperMap {
1079 public:
1080     static CSSPropertyAnimationWrapperMap& instance()
1081     {
1082         // FIXME: This data is never destroyed. Maybe we should ref count it and toss it when the last AnimationController is destroyed?
1083         DEFINE_STATIC_LOCAL(OwnPtr<CSSPropertyAnimationWrapperMap>, map, ());
1084         if (!map) {
1085             map = adoptPtr(new CSSPropertyAnimationWrapperMap);
1086             map->ensurePropertyMap(); // FIXME: ensurePropertyMap() calls instance() inside addShorthandProperties().
1087         }
1088         return *map;
1089     }
1090
1091     AnimationPropertyWrapperBase* wrapperForProperty(CSSPropertyID propertyID)
1092     {
1093         int propIndex = propertyID - firstCSSProperty;
1094         if (propertyID < firstCSSProperty || propertyID > lastCSSProperty)
1095             return 0;
1096
1097         unsigned wrapperIndex = m_propertyToIdMap[propIndex];
1098         if (wrapperIndex == cInvalidPropertyWrapperIndex)
1099             return 0;
1100
1101         return m_propertyWrappers[wrapperIndex];
1102     }
1103
1104     AnimationPropertyWrapperBase* wrapperForIndex(unsigned index)
1105     {
1106         ASSERT(index < m_propertyWrappers.size());
1107         return m_propertyWrappers[index];
1108     }
1109
1110     unsigned size()
1111     {
1112         return m_propertyWrappers.size();
1113     }
1114
1115
1116 private:
1117     void addShorthandProperties();
1118     void ensurePropertyMap();
1119
1120     void addPropertyWrapper(CSSPropertyID propertyID, AnimationPropertyWrapperBase* wrapper)
1121     {
1122         int propIndex = propertyID - firstCSSProperty;
1123
1124         ASSERT(m_propertyToIdMap[propIndex] == cInvalidPropertyWrapperIndex);
1125
1126         unsigned wrapperIndex = m_propertyWrappers.size();
1127         m_propertyWrappers.append(wrapper);
1128         m_propertyToIdMap[propIndex] = wrapperIndex;
1129     }
1130
1131     Vector<AnimationPropertyWrapperBase*> m_propertyWrappers;
1132     unsigned m_propertyToIdMap[numCSSProperties];
1133
1134     const unsigned cInvalidPropertyWrapperIndex = UINT_MAX;
1135 };
1136
1137 void CSSPropertyAnimationWrapperMap::addShorthandProperties()
1138 {
1139     static const CSSPropertyID animatableShorthandProperties[] = {
1140         CSSPropertyBackground, // for background-color, background-position, background-image
1141         CSSPropertyBackgroundPosition,
1142         CSSPropertyFont, // for font-size, font-weight
1143         CSSPropertyWebkitMask, // for mask-position
1144         CSSPropertyWebkitMaskPosition,
1145         CSSPropertyBorderTop, CSSPropertyBorderRight, CSSPropertyBorderBottom, CSSPropertyBorderLeft,
1146         CSSPropertyBorderColor,
1147         CSSPropertyBorderRadius,
1148         CSSPropertyBorderWidth,
1149         CSSPropertyBorder,
1150         CSSPropertyBorderImage,
1151         CSSPropertyBorderSpacing,
1152         CSSPropertyListStyle, // for list-style-image
1153         CSSPropertyMargin,
1154         CSSPropertyOutline,
1155         CSSPropertyPadding,
1156         CSSPropertyWebkitTextStroke,
1157         CSSPropertyWebkitColumnRule,
1158         CSSPropertyWebkitBorderRadius,
1159         CSSPropertyWebkitTransformOrigin
1160     };
1161
1162     CSSPropertyAnimationWrapperMap& map = CSSPropertyAnimationWrapperMap::instance();
1163
1164     for (size_t i = 0; i < WTF_ARRAY_LENGTH(animatableShorthandProperties); ++i) {
1165         CSSPropertyID propertyID = animatableShorthandProperties[i];
1166         StylePropertyShorthand shorthand = shorthandForProperty(propertyID);
1167         if (!shorthand.length())
1168             continue;
1169
1170         Vector<AnimationPropertyWrapperBase*> longhandWrappers;
1171         for (unsigned i = 0; i < shorthand.length(); ++i) {
1172             if (AnimationPropertyWrapperBase* wrapper = map.wrapperForProperty(shorthand.properties()[i]))
1173                 longhandWrappers.append(wrapper);
1174         }
1175
1176         map.addPropertyWrapper(propertyID, new ShorthandPropertyWrapper(propertyID, longhandWrappers));
1177     }
1178 }
1179
1180 void CSSPropertyAnimationWrapperMap::ensurePropertyMap()
1181 {
1182     Vector<AnimationPropertyWrapperBase*>* gPropertyWrappers = &m_propertyWrappers; // FIXME: Remove this aliasing.
1183
1184     // build the list of property wrappers to do the comparisons and blends
1185     gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyLeft, &RenderStyle::left, &RenderStyle::setLeft));
1186     gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyRight, &RenderStyle::right, &RenderStyle::setRight));
1187     gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyTop, &RenderStyle::top, &RenderStyle::setTop));
1188     gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyBottom, &RenderStyle::bottom, &RenderStyle::setBottom));
1189
1190     gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyWidth, &RenderStyle::width, &RenderStyle::setWidth));
1191     gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyMinWidth, &RenderStyle::minWidth, &RenderStyle::setMinWidth));
1192     gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyMaxWidth, &RenderStyle::maxWidth, &RenderStyle::setMaxWidth));
1193
1194     gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyHeight, &RenderStyle::height, &RenderStyle::setHeight));
1195     gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyMinHeight, &RenderStyle::minHeight, &RenderStyle::setMinHeight));
1196     gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyMaxHeight, &RenderStyle::maxHeight, &RenderStyle::setMaxHeight));
1197
1198     gPropertyWrappers->append(new PropertyWrapperFlex());
1199
1200     gPropertyWrappers->append(new PropertyWrapper<unsigned>(CSSPropertyBorderLeftWidth, &RenderStyle::borderLeftWidth, &RenderStyle::setBorderLeftWidth));
1201     gPropertyWrappers->append(new PropertyWrapper<unsigned>(CSSPropertyBorderRightWidth, &RenderStyle::borderRightWidth, &RenderStyle::setBorderRightWidth));
1202     gPropertyWrappers->append(new PropertyWrapper<unsigned>(CSSPropertyBorderTopWidth, &RenderStyle::borderTopWidth, &RenderStyle::setBorderTopWidth));
1203     gPropertyWrappers->append(new PropertyWrapper<unsigned>(CSSPropertyBorderBottomWidth, &RenderStyle::borderBottomWidth, &RenderStyle::setBorderBottomWidth));
1204     gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyMarginLeft, &RenderStyle::marginLeft, &RenderStyle::setMarginLeft));
1205     gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyMarginRight, &RenderStyle::marginRight, &RenderStyle::setMarginRight));
1206     gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyMarginTop, &RenderStyle::marginTop, &RenderStyle::setMarginTop));
1207     gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyMarginBottom, &RenderStyle::marginBottom, &RenderStyle::setMarginBottom));
1208     gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyPaddingLeft, &RenderStyle::paddingLeft, &RenderStyle::setPaddingLeft));
1209     gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyPaddingRight, &RenderStyle::paddingRight, &RenderStyle::setPaddingRight));
1210     gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyPaddingTop, &RenderStyle::paddingTop, &RenderStyle::setPaddingTop));
1211     gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyPaddingBottom, &RenderStyle::paddingBottom, &RenderStyle::setPaddingBottom));
1212     gPropertyWrappers->append(new PropertyWrapperVisitedAffectedColor(CSSPropertyColor, &RenderStyle::color, &RenderStyle::setColor, &RenderStyle::visitedLinkColor, &RenderStyle::setVisitedLinkColor));
1213
1214     gPropertyWrappers->append(new PropertyWrapperVisitedAffectedColor(CSSPropertyBackgroundColor, &RenderStyle::backgroundColor, &RenderStyle::setBackgroundColor, &RenderStyle::visitedLinkBackgroundColor, &RenderStyle::setVisitedLinkBackgroundColor));
1215
1216     gPropertyWrappers->append(new FillLayersPropertyWrapper(CSSPropertyBackgroundImage, &RenderStyle::backgroundLayers, &RenderStyle::accessBackgroundLayers));
1217     gPropertyWrappers->append(new StyleImagePropertyWrapper(CSSPropertyListStyleImage, &RenderStyle::listStyleImage, &RenderStyle::setListStyleImage));
1218     gPropertyWrappers->append(new StyleImagePropertyWrapper(CSSPropertyWebkitMaskImage, &RenderStyle::maskImage, &RenderStyle::setMaskImage));
1219
1220     gPropertyWrappers->append(new StyleImagePropertyWrapper(CSSPropertyBorderImageSource, &RenderStyle::borderImageSource, &RenderStyle::setBorderImageSource));
1221     gPropertyWrappers->append(new PropertyWrapper<LengthBox>(CSSPropertyBorderImageSlice, &RenderStyle::borderImageSlices, &RenderStyle::setBorderImageSlices));
1222     gPropertyWrappers->append(new PropertyWrapper<LengthBox>(CSSPropertyBorderImageWidth, &RenderStyle::borderImageWidth, &RenderStyle::setBorderImageWidth));
1223     gPropertyWrappers->append(new PropertyWrapper<LengthBox>(CSSPropertyBorderImageOutset, &RenderStyle::borderImageOutset, &RenderStyle::setBorderImageOutset));
1224
1225     gPropertyWrappers->append(new StyleImagePropertyWrapper(CSSPropertyWebkitMaskBoxImageSource, &RenderStyle::maskBoxImageSource, &RenderStyle::setMaskBoxImageSource));
1226     gPropertyWrappers->append(new PropertyWrapper<const NinePieceImage&>(CSSPropertyWebkitMaskBoxImage, &RenderStyle::maskBoxImage, &RenderStyle::setMaskBoxImage));
1227
1228     gPropertyWrappers->append(new FillLayersPropertyWrapper(CSSPropertyBackgroundPositionX, &RenderStyle::backgroundLayers, &RenderStyle::accessBackgroundLayers));
1229     gPropertyWrappers->append(new FillLayersPropertyWrapper(CSSPropertyBackgroundPositionY, &RenderStyle::backgroundLayers, &RenderStyle::accessBackgroundLayers));
1230     gPropertyWrappers->append(new FillLayersPropertyWrapper(CSSPropertyBackgroundSize, &RenderStyle::backgroundLayers, &RenderStyle::accessBackgroundLayers));
1231     gPropertyWrappers->append(new FillLayersPropertyWrapper(CSSPropertyWebkitBackgroundSize, &RenderStyle::backgroundLayers, &RenderStyle::accessBackgroundLayers));
1232
1233     gPropertyWrappers->append(new FillLayersPropertyWrapper(CSSPropertyWebkitMaskPositionX, &RenderStyle::maskLayers, &RenderStyle::accessMaskLayers));
1234     gPropertyWrappers->append(new FillLayersPropertyWrapper(CSSPropertyWebkitMaskPositionY, &RenderStyle::maskLayers, &RenderStyle::accessMaskLayers));
1235     gPropertyWrappers->append(new FillLayersPropertyWrapper(CSSPropertyWebkitMaskSize, &RenderStyle::maskLayers, &RenderStyle::accessMaskLayers));
1236
1237     gPropertyWrappers->append(new PropertyWrapper<float>(CSSPropertyFontSize,
1238         // Must pass a specified size to setFontSize if Text Autosizing is enabled, but a computed size
1239         // if text zoom is enabled (if neither is enabled it's irrelevant as they're probably the same).
1240         // FIXME: Find some way to assert that text zoom isn't activated when Text Autosizing is compiled in.
1241 #if ENABLE(TEXT_AUTOSIZING)
1242         &RenderStyle::specifiedFontSize,
1243 #else
1244         &RenderStyle::computedFontSize,
1245 #endif
1246         &RenderStyle::setFontSize));
1247     gPropertyWrappers->append(new PropertyWrapper<unsigned short>(CSSPropertyWebkitColumnRuleWidth, &RenderStyle::columnRuleWidth, &RenderStyle::setColumnRuleWidth));
1248     gPropertyWrappers->append(new PropertyWrapper<float>(CSSPropertyWebkitColumnGap, &RenderStyle::columnGap, &RenderStyle::setColumnGap));
1249     gPropertyWrappers->append(new PropertyWrapper<unsigned short>(CSSPropertyWebkitColumnCount, &RenderStyle::columnCount, &RenderStyle::setColumnCount));
1250     gPropertyWrappers->append(new PropertyWrapper<float>(CSSPropertyWebkitColumnWidth, &RenderStyle::columnWidth, &RenderStyle::setColumnWidth));
1251     gPropertyWrappers->append(new PropertyWrapper<short>(CSSPropertyWebkitBorderHorizontalSpacing, &RenderStyle::horizontalBorderSpacing, &RenderStyle::setHorizontalBorderSpacing));
1252     gPropertyWrappers->append(new PropertyWrapper<short>(CSSPropertyWebkitBorderVerticalSpacing, &RenderStyle::verticalBorderSpacing, &RenderStyle::setVerticalBorderSpacing));
1253     gPropertyWrappers->append(new PropertyWrapper<int>(CSSPropertyZIndex, &RenderStyle::zIndex, &RenderStyle::setZIndex));
1254     gPropertyWrappers->append(new PropertyWrapper<short>(CSSPropertyOrphans, &RenderStyle::orphans, &RenderStyle::setOrphans));
1255     gPropertyWrappers->append(new PropertyWrapper<short>(CSSPropertyWidows, &RenderStyle::widows, &RenderStyle::setWidows));
1256     gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyLineHeight, &RenderStyle::specifiedLineHeight, &RenderStyle::setLineHeight));
1257     gPropertyWrappers->append(new PropertyWrapper<int>(CSSPropertyOutlineOffset, &RenderStyle::outlineOffset, &RenderStyle::setOutlineOffset));
1258     gPropertyWrappers->append(new PropertyWrapper<unsigned short>(CSSPropertyOutlineWidth, &RenderStyle::outlineWidth, &RenderStyle::setOutlineWidth));
1259     gPropertyWrappers->append(new PropertyWrapper<int>(CSSPropertyLetterSpacing, &RenderStyle::letterSpacing, &RenderStyle::setLetterSpacing));
1260     gPropertyWrappers->append(new PropertyWrapper<int>(CSSPropertyWordSpacing, &RenderStyle::wordSpacing, &RenderStyle::setWordSpacing));
1261     gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyTextIndent, &RenderStyle::textIndent, &RenderStyle::setTextIndent));
1262
1263     gPropertyWrappers->append(new PropertyWrapper<float>(CSSPropertyWebkitPerspective, &RenderStyle::perspective, &RenderStyle::setPerspective));
1264     gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyWebkitPerspectiveOriginX, &RenderStyle::perspectiveOriginX, &RenderStyle::setPerspectiveOriginX));
1265     gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyWebkitPerspectiveOriginY, &RenderStyle::perspectiveOriginY, &RenderStyle::setPerspectiveOriginY));
1266     gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyWebkitTransformOriginX, &RenderStyle::transformOriginX, &RenderStyle::setTransformOriginX));
1267     gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyWebkitTransformOriginY, &RenderStyle::transformOriginY, &RenderStyle::setTransformOriginY));
1268     gPropertyWrappers->append(new PropertyWrapper<float>(CSSPropertyWebkitTransformOriginZ, &RenderStyle::transformOriginZ, &RenderStyle::setTransformOriginZ));
1269     gPropertyWrappers->append(new PropertyWrapper<LengthSize>(CSSPropertyBorderTopLeftRadius, &RenderStyle::borderTopLeftRadius, &RenderStyle::setBorderTopLeftRadius));
1270     gPropertyWrappers->append(new PropertyWrapper<LengthSize>(CSSPropertyBorderTopRightRadius, &RenderStyle::borderTopRightRadius, &RenderStyle::setBorderTopRightRadius));
1271     gPropertyWrappers->append(new PropertyWrapper<LengthSize>(CSSPropertyBorderBottomLeftRadius, &RenderStyle::borderBottomLeftRadius, &RenderStyle::setBorderBottomLeftRadius));
1272     gPropertyWrappers->append(new PropertyWrapper<LengthSize>(CSSPropertyBorderBottomRightRadius, &RenderStyle::borderBottomRightRadius, &RenderStyle::setBorderBottomRightRadius));
1273     gPropertyWrappers->append(new PropertyWrapper<EVisibility>(CSSPropertyVisibility, &RenderStyle::visibility, &RenderStyle::setVisibility));
1274     gPropertyWrappers->append(new PropertyWrapper<float>(CSSPropertyZoom, &RenderStyle::zoom, &RenderStyle::setZoomWithoutReturnValue));
1275
1276     gPropertyWrappers->append(new PropertyWrapper<LengthBox>(CSSPropertyClip, &RenderStyle::clip, &RenderStyle::setClip));
1277
1278 #if USE(ACCELERATED_COMPOSITING)
1279     gPropertyWrappers->append(new PropertyWrapperAcceleratedOpacity());
1280     gPropertyWrappers->append(new PropertyWrapperAcceleratedTransform());
1281 #if ENABLE(CSS_FILTERS)
1282     gPropertyWrappers->append(new PropertyWrapperAcceleratedFilter());
1283 #endif
1284 #else
1285     gPropertyWrappers->append(new PropertyWrapper<float>(CSSPropertyOpacity, &RenderStyle::opacity, &RenderStyle::setOpacity));
1286     gPropertyWrappers->append(new PropertyWrapper<const TransformOperations&>(CSSPropertyWebkitTransform, &RenderStyle::transform, &RenderStyle::setTransform));
1287 #if ENABLE(CSS_FILTERS)
1288     gPropertyWrappers->append(new PropertyWrapper<const FilterOperations&>(CSSPropertyWebkitFilter, &RenderStyle::filter, &RenderStyle::setFilter));
1289 #endif
1290 #endif
1291
1292     gPropertyWrappers->append(new PropertyWrapperClipPath(CSSPropertyWebkitClipPath, &RenderStyle::clipPath, &RenderStyle::setClipPath));
1293
1294 #if ENABLE(CSS_SHAPES)
1295     gPropertyWrappers->append(new PropertyWrapperShape(CSSPropertyWebkitShapeInside, &RenderStyle::shapeInside, &RenderStyle::setShapeInside));
1296 #endif
1297
1298     gPropertyWrappers->append(new PropertyWrapperVisitedAffectedColor(CSSPropertyWebkitColumnRuleColor, MaybeInvalidColor, &RenderStyle::columnRuleColor, &RenderStyle::setColumnRuleColor, &RenderStyle::visitedLinkColumnRuleColor, &RenderStyle::setVisitedLinkColumnRuleColor));
1299     gPropertyWrappers->append(new PropertyWrapperVisitedAffectedColor(CSSPropertyWebkitTextStrokeColor, MaybeInvalidColor, &RenderStyle::textStrokeColor, &RenderStyle::setTextStrokeColor, &RenderStyle::visitedLinkTextStrokeColor, &RenderStyle::setVisitedLinkTextStrokeColor));
1300     gPropertyWrappers->append(new PropertyWrapperVisitedAffectedColor(CSSPropertyWebkitTextFillColor, MaybeInvalidColor, &RenderStyle::textFillColor, &RenderStyle::setTextFillColor, &RenderStyle::visitedLinkTextFillColor, &RenderStyle::setVisitedLinkTextFillColor));
1301     gPropertyWrappers->append(new PropertyWrapperVisitedAffectedColor(CSSPropertyBorderLeftColor, MaybeInvalidColor, &RenderStyle::borderLeftColor, &RenderStyle::setBorderLeftColor, &RenderStyle::visitedLinkBorderLeftColor, &RenderStyle::setVisitedLinkBorderLeftColor));
1302     gPropertyWrappers->append(new PropertyWrapperVisitedAffectedColor(CSSPropertyBorderRightColor, MaybeInvalidColor, &RenderStyle::borderRightColor, &RenderStyle::setBorderRightColor, &RenderStyle::visitedLinkBorderRightColor, &RenderStyle::setVisitedLinkBorderRightColor));
1303     gPropertyWrappers->append(new PropertyWrapperVisitedAffectedColor(CSSPropertyBorderTopColor, MaybeInvalidColor, &RenderStyle::borderTopColor, &RenderStyle::setBorderTopColor, &RenderStyle::visitedLinkBorderTopColor, &RenderStyle::setVisitedLinkBorderTopColor));
1304     gPropertyWrappers->append(new PropertyWrapperVisitedAffectedColor(CSSPropertyBorderBottomColor, MaybeInvalidColor, &RenderStyle::borderBottomColor, &RenderStyle::setBorderBottomColor, &RenderStyle::visitedLinkBorderBottomColor, &RenderStyle::setVisitedLinkBorderBottomColor));
1305     gPropertyWrappers->append(new PropertyWrapperVisitedAffectedColor(CSSPropertyOutlineColor, MaybeInvalidColor, &RenderStyle::outlineColor, &RenderStyle::setOutlineColor, &RenderStyle::visitedLinkOutlineColor, &RenderStyle::setVisitedLinkOutlineColor));
1306
1307     gPropertyWrappers->append(new PropertyWrapperShadow(CSSPropertyBoxShadow, &RenderStyle::boxShadow, &RenderStyle::setBoxShadow));
1308     gPropertyWrappers->append(new PropertyWrapperShadow(CSSPropertyWebkitBoxShadow, &RenderStyle::boxShadow, &RenderStyle::setBoxShadow));
1309     gPropertyWrappers->append(new PropertyWrapperShadow(CSSPropertyTextShadow, &RenderStyle::textShadow, &RenderStyle::setTextShadow));
1310
1311 #if ENABLE(SVG)
1312     gPropertyWrappers->append(new PropertyWrapperSVGPaint(CSSPropertyFill, &RenderStyle::fillPaintType, &RenderStyle::fillPaintColor, &RenderStyle::setFillPaintColor));
1313     gPropertyWrappers->append(new PropertyWrapper<float>(CSSPropertyFillOpacity, &RenderStyle::fillOpacity, &RenderStyle::setFillOpacity));
1314
1315     gPropertyWrappers->append(new PropertyWrapperSVGPaint(CSSPropertyStroke, &RenderStyle::strokePaintType, &RenderStyle::strokePaintColor, &RenderStyle::setStrokePaintColor));
1316     gPropertyWrappers->append(new PropertyWrapper<float>(CSSPropertyStrokeOpacity, &RenderStyle::strokeOpacity, &RenderStyle::setStrokeOpacity));
1317     gPropertyWrappers->append(new PropertyWrapper<SVGLength>(CSSPropertyStrokeWidth, &RenderStyle::strokeWidth, &RenderStyle::setStrokeWidth));
1318     gPropertyWrappers->append(new PropertyWrapper< Vector<SVGLength> >(CSSPropertyStrokeDasharray, &RenderStyle::strokeDashArray, &RenderStyle::setStrokeDashArray));
1319     gPropertyWrappers->append(new PropertyWrapper<SVGLength>(CSSPropertyStrokeDashoffset, &RenderStyle::strokeDashOffset, &RenderStyle::setStrokeDashOffset));
1320     gPropertyWrappers->append(new PropertyWrapper<float>(CSSPropertyStrokeMiterlimit, &RenderStyle::strokeMiterLimit, &RenderStyle::setStrokeMiterLimit));
1321
1322     gPropertyWrappers->append(new PropertyWrapper<float>(CSSPropertyFloodOpacity, &RenderStyle::floodOpacity, &RenderStyle::setFloodOpacity));
1323     gPropertyWrappers->append(new PropertyWrapperMaybeInvalidColor(CSSPropertyFloodColor, &RenderStyle::floodColor, &RenderStyle::setFloodColor));
1324
1325     gPropertyWrappers->append(new PropertyWrapper<float>(CSSPropertyStopOpacity, &RenderStyle::stopOpacity, &RenderStyle::setStopOpacity));
1326     gPropertyWrappers->append(new PropertyWrapperMaybeInvalidColor(CSSPropertyStopColor, &RenderStyle::stopColor, &RenderStyle::setStopColor));
1327
1328     gPropertyWrappers->append(new PropertyWrapperMaybeInvalidColor(CSSPropertyLightingColor, &RenderStyle::lightingColor, &RenderStyle::setLightingColor));
1329
1330     gPropertyWrappers->append(new PropertyWrapper<SVGLength>(CSSPropertyBaselineShift, &RenderStyle::baselineShiftValue, &RenderStyle::setBaselineShiftValue));
1331     gPropertyWrappers->append(new PropertyWrapper<SVGLength>(CSSPropertyKerning, &RenderStyle::kerning, &RenderStyle::setKerning));
1332 #endif
1333
1334     // TODO:
1335     //
1336     //  CSSPropertyVerticalAlign
1337     //
1338     // Compound properties that have components that should be animatable:
1339     //
1340     //  CSSPropertyWebkitColumns
1341     //  CSSPropertyWebkitBoxReflect
1342
1343     // Make sure unused slots have a value
1344     for (unsigned int i = 0; i < static_cast<unsigned int>(numCSSProperties); ++i)
1345         m_propertyToIdMap[i] = cInvalidPropertyWrapperIndex;
1346
1347     // First we put the non-shorthand property wrappers into the map, so the shorthand-building
1348     // code can find them.
1349     size_t n = gPropertyWrappers->size();
1350     for (unsigned int i = 0; i < n; ++i) {
1351         ASSERT(m_propertyWrappers[i]->property() - firstCSSProperty < numCSSProperties);
1352         m_propertyToIdMap[m_propertyWrappers[i]->property() - firstCSSProperty] = i;
1353     }
1354
1355     // Now add the shorthand wrappers.
1356     addShorthandProperties();
1357 }
1358
1359 static bool gatherEnclosingShorthandProperties(CSSPropertyID property, AnimationPropertyWrapperBase* wrapper, HashSet<CSSPropertyID>& propertySet)
1360 {
1361     if (!wrapper->isShorthandWrapper())
1362         return false;
1363
1364     ShorthandPropertyWrapper* shorthandWrapper = static_cast<ShorthandPropertyWrapper*>(wrapper);
1365
1366     bool contained = false;
1367     for (size_t i = 0; i < shorthandWrapper->propertyWrappers().size(); ++i) {
1368         AnimationPropertyWrapperBase* currWrapper = shorthandWrapper->propertyWrappers()[i];
1369
1370         if (gatherEnclosingShorthandProperties(property, currWrapper, propertySet) || currWrapper->property() == property)
1371             contained = true;
1372     }
1373
1374     if (contained)
1375         propertySet.add(wrapper->property());
1376
1377     return contained;
1378 }
1379
1380 // Returns true if we need to start animation timers
1381 bool CSSPropertyAnimation::blendProperties(const AnimationBase* anim, CSSPropertyID prop, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress)
1382 {
1383     ASSERT(prop != CSSPropertyInvalid);
1384
1385     AnimationPropertyWrapperBase* wrapper = CSSPropertyAnimationWrapperMap::instance().wrapperForProperty(prop);
1386     if (wrapper) {
1387         wrapper->blend(anim, dst, a, b, progress);
1388 #if USE(ACCELERATED_COMPOSITING)
1389         return !wrapper->animationIsAccelerated() || !anim->isAccelerated();
1390 #else
1391         return true;
1392 #endif
1393     }
1394
1395     return false;
1396 }
1397
1398 #if USE(ACCELERATED_COMPOSITING)
1399 bool CSSPropertyAnimation::animationOfPropertyIsAccelerated(CSSPropertyID prop)
1400 {
1401     AnimationPropertyWrapperBase* wrapper = CSSPropertyAnimationWrapperMap::instance().wrapperForProperty(prop);
1402     return wrapper ? wrapper->animationIsAccelerated() : false;
1403 }
1404 #endif
1405
1406 // Note: this is inefficient. It's only called from pauseTransitionAtTime().
1407 HashSet<CSSPropertyID> CSSPropertyAnimation::animatableShorthandsAffectingProperty(CSSPropertyID property)
1408 {
1409     CSSPropertyAnimationWrapperMap& map = CSSPropertyAnimationWrapperMap::instance();
1410
1411     HashSet<CSSPropertyID> foundProperties;
1412     for (unsigned i = 0; i < map.size(); ++i)
1413         gatherEnclosingShorthandProperties(property, map.wrapperForIndex(i), foundProperties);
1414
1415     return foundProperties;
1416 }
1417
1418 bool CSSPropertyAnimation::propertiesEqual(CSSPropertyID prop, const RenderStyle* a, const RenderStyle* b)
1419 {
1420     AnimationPropertyWrapperBase* wrapper = CSSPropertyAnimationWrapperMap::instance().wrapperForProperty(prop);
1421     if (wrapper)
1422         return wrapper->equals(a, b);
1423     return true;
1424 }
1425
1426 CSSPropertyID CSSPropertyAnimation::getPropertyAtIndex(int i, bool& isShorthand)
1427 {
1428     CSSPropertyAnimationWrapperMap& map = CSSPropertyAnimationWrapperMap::instance();
1429
1430     if (i < 0 || static_cast<unsigned>(i) >= map.size())
1431         return CSSPropertyInvalid;
1432
1433     AnimationPropertyWrapperBase* wrapper = map.wrapperForIndex(i);
1434     isShorthand = wrapper->isShorthandWrapper();
1435     return wrapper->property();
1436 }
1437
1438 int CSSPropertyAnimation::getNumProperties()
1439 {
1440     return CSSPropertyAnimationWrapperMap::instance().size();
1441 }
1442
1443 }