[WTF] Add makeUnique<T>, which ensures T is fast-allocated, makeUnique / makeUniqueWi...
[WebKit-https.git] / Source / WebCore / page / animation / CSSPropertyAnimation.cpp
1 /*
2  * Copyright (C) 2007, 2008, 2009, 2013, 2016 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 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 "CSSComputedStyleDeclaration.h"
34 #include "CSSCrossfadeValue.h"
35 #include "CSSFilterImageValue.h"
36 #include "CSSImageGeneratorValue.h"
37 #include "CSSImageValue.h"
38 #include "CSSPrimitiveValue.h"
39 #include "CSSPropertyBlendingClient.h"
40 #include "CSSPropertyNames.h"
41 #include "CachedImage.h"
42 #include "CalculationValue.h"
43 #include "ClipPathOperation.h"
44 #include "FloatConversion.h"
45 #include "FontCascade.h"
46 #include "FontSelectionAlgorithm.h"
47 #include "FontTaggedSettings.h"
48 #include "GapLength.h"
49 #include "IdentityTransformOperation.h"
50 #include "Logging.h"
51 #include "Matrix3DTransformOperation.h"
52 #include "MatrixTransformOperation.h"
53 #include "RenderBox.h"
54 #include "RenderStyle.h"
55 #include "StyleCachedImage.h"
56 #include "StyleGeneratedImage.h"
57 #include "StylePropertyShorthand.h"
58 #include "StyleResolver.h"
59 #include <algorithm>
60 #include <memory>
61 #include <wtf/MathExtras.h>
62 #include <wtf/NeverDestroyed.h>
63 #include <wtf/Noncopyable.h>
64 #include <wtf/PointerComparison.h>
65 #include <wtf/RefCounted.h>
66 #include <wtf/text/TextStream.h>
67
68 namespace WebCore {
69
70 static inline int blendFunc(const CSSPropertyBlendingClient*, int from, int to, double progress)
71 {
72     return blend(from, to, progress);
73 }
74
75 static inline double blendFunc(const CSSPropertyBlendingClient*, double from, double to, double progress)
76 {
77     return blend(from, to, progress);
78 }
79
80 static inline float blendFunc(const CSSPropertyBlendingClient*, float from, float to, double progress)
81 {
82     return narrowPrecisionToFloat(from + (to - from) * progress);
83 }
84
85 static inline Color blendFunc(const CSSPropertyBlendingClient*, const Color& from, const Color& to, double progress)
86 {
87     return blend(from, to, progress);
88 }
89
90 static inline Length blendFunc(const CSSPropertyBlendingClient*, const Length& from, const Length& to, double progress)
91 {
92     return blend(from, to, progress);
93 }
94
95 static inline GapLength blendFunc(const CSSPropertyBlendingClient*, const GapLength& from, const GapLength& to, double progress)
96 {
97     return (from.isNormal() || to.isNormal()) ? to : blend(from.length(), to.length(), progress);
98 }
99
100 static inline LengthSize blendFunc(const CSSPropertyBlendingClient* anim, const LengthSize& from, const LengthSize& to, double progress)
101 {
102     return { blendFunc(anim, from.width, to.width, progress), blendFunc(anim, from.height, to.height, progress) };
103 }
104
105 static inline ShadowStyle blendFunc(const CSSPropertyBlendingClient* anim, ShadowStyle from, ShadowStyle to, double progress)
106 {
107     if (from == to)
108         return to;
109
110     double fromVal = from == Normal ? 1 : 0;
111     double toVal = to == Normal ? 1 : 0;
112     double result = blendFunc(anim, fromVal, toVal, progress);
113     return result > 0 ? Normal : Inset;
114 }
115
116 static inline std::unique_ptr<ShadowData> blendFunc(const CSSPropertyBlendingClient* anim, const ShadowData* from, const ShadowData* to, double progress)
117 {
118     ASSERT(from && to);
119     if (from->style() != to->style())
120         return makeUnique<ShadowData>(*to);
121
122     return makeUnique<ShadowData>(blend(from->location(), to->location(), progress),
123         blend(from->radius(), to->radius(), progress),
124         blend(from->spread(), to->spread(), progress),
125         blendFunc(anim, from->style(), to->style(), progress),
126         from->isWebkitBoxShadow(),
127         blend(from->color(), to->color(), progress));
128 }
129
130 static inline TransformOperations blendFunc(const CSSPropertyBlendingClient* animation, const TransformOperations& from, const TransformOperations& to, double progress)
131 {
132     if (animation->transformFunctionListsMatch())
133         return to.blendByMatchingOperations(from, progress);
134     return to.blendByUsingMatrixInterpolation(from, progress, is<RenderBox>(animation->renderer()) ? downcast<RenderBox>(*animation->renderer()).borderBoxRect().size() : LayoutSize());
135 }
136
137 static inline RefPtr<ClipPathOperation> blendFunc(const CSSPropertyBlendingClient*, ClipPathOperation* from, ClipPathOperation* to, double progress)
138 {
139     if (!from || !to)
140         return to;
141
142     // Other clip-path operations than BasicShapes can not be animated.
143     if (from->type() != ClipPathOperation::Shape || to->type() != ClipPathOperation::Shape)
144         return to;
145
146     const BasicShape& fromShape = downcast<ShapeClipPathOperation>(*from).basicShape();
147     const BasicShape& toShape = downcast<ShapeClipPathOperation>(*to).basicShape();
148
149     if (!fromShape.canBlend(toShape))
150         return to;
151
152     return ShapeClipPathOperation::create(toShape.blend(fromShape, progress));
153 }
154
155 static inline RefPtr<ShapeValue> blendFunc(const CSSPropertyBlendingClient*, ShapeValue* from, ShapeValue* to, double progress)
156 {
157     if (!from || !to)
158         return to;
159
160     if (from->type() != ShapeValue::Type::Shape || to->type() != ShapeValue::Type::Shape)
161         return to;
162
163     if (from->cssBox() != to->cssBox())
164         return to;
165
166     const BasicShape& fromShape = *from->shape();
167     const BasicShape& toShape = *to->shape();
168
169     if (!fromShape.canBlend(toShape))
170         return to;
171
172     return ShapeValue::create(toShape.blend(fromShape, progress), to->cssBox());
173 }
174
175 static inline RefPtr<FilterOperation> blendFunc(const CSSPropertyBlendingClient*, FilterOperation* fromOp, FilterOperation* toOp, double progress, bool blendToPassthrough = false)
176 {
177     ASSERT(toOp);
178     return toOp->blend(fromOp, progress, blendToPassthrough);
179 }
180
181 static inline FilterOperations blendFilterOperations(const CSSPropertyBlendingClient* anim,  const FilterOperations& from, const FilterOperations& to, double progress)
182 {
183     FilterOperations result;
184     size_t fromSize = from.operations().size();
185     size_t toSize = to.operations().size();
186     size_t size = std::max(fromSize, toSize);
187     for (size_t i = 0; i < size; i++) {
188         RefPtr<FilterOperation> fromOp = (i < fromSize) ? from.operations()[i].get() : 0;
189         RefPtr<FilterOperation> toOp = (i < toSize) ? to.operations()[i].get() : 0;
190         RefPtr<FilterOperation> blendedOp = toOp ? blendFunc(anim, fromOp.get(), toOp.get(), progress) : (fromOp ? blendFunc(anim, 0, fromOp.get(), progress, true) : 0);
191         if (blendedOp)
192             result.operations().append(blendedOp);
193         else {
194             auto identityOp = PassthroughFilterOperation::create();
195             if (progress > 0.5)
196                 result.operations().append(toOp ? toOp : WTFMove(identityOp));
197             else
198                 result.operations().append(fromOp ? fromOp : WTFMove(identityOp));
199         }
200     }
201     return result;
202 }
203
204 static inline FilterOperations blendFunc(const CSSPropertyBlendingClient* anim, const FilterOperations& from, const FilterOperations& to, double progress, CSSPropertyID propertyID = CSSPropertyFilter)
205 {
206     FilterOperations result;
207
208     // If we have a filter function list, use that to do a per-function animation.
209     
210     bool listsMatch = false;
211     switch (propertyID) {
212     case CSSPropertyFilter:
213         listsMatch = anim->filterFunctionListsMatch();
214         break;
215 #if ENABLE(FILTERS_LEVEL_2)
216     case CSSPropertyWebkitBackdropFilter:
217         listsMatch = anim->backdropFilterFunctionListsMatch();
218         break;
219 #endif
220     case CSSPropertyAppleColorFilter:
221         listsMatch = anim->colorFilterFunctionListsMatch();
222         break;
223     default:
224         break;
225     }
226     
227     if (listsMatch)
228         result = blendFilterOperations(anim, from, to, progress);
229     else {
230         // 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.
231         // For now we'll just fail to animate.
232         result = to;
233     }
234
235     return result;
236 }
237
238 static inline RefPtr<StyleImage> blendFilter(const CSSPropertyBlendingClient* anim, CachedImage* image, const FilterOperations& from, const FilterOperations& to, double progress)
239 {
240     ASSERT(image);
241     FilterOperations filterResult = blendFilterOperations(anim, from, to, progress);
242
243     auto imageValue = CSSImageValue::create(*image);
244     auto filterValue = ComputedStyleExtractor::valueForFilter(anim->currentStyle(), filterResult, DoNotAdjustPixelValues);
245
246     auto result = CSSFilterImageValue::create(WTFMove(imageValue), WTFMove(filterValue));
247     result.get().setFilterOperations(filterResult);
248     return StyleGeneratedImage::create(WTFMove(result));
249 }
250
251 static inline Visibility blendFunc(const CSSPropertyBlendingClient* anim, Visibility from, Visibility to, double progress)
252 {
253     // Any non-zero result means we consider the object to be visible. Only at 0 do we consider the object to be
254     // invisible. The invisible value we use (Visibility::Hidden vs. Visibility::Collapse) depends on the specified from/to values.
255     double fromVal = from == Visibility::Visible ? 1. : 0.;
256     double toVal = to == Visibility::Visible ? 1. : 0.;
257     if (fromVal == toVal)
258         return to;
259     double result = blendFunc(anim, fromVal, toVal, progress);
260     return result > 0. ? Visibility::Visible : (to != Visibility::Visible ? to : from);
261 }
262
263 static inline TextUnderlineOffset blendFunc(const CSSPropertyBlendingClient* anim, const TextUnderlineOffset& from, const TextUnderlineOffset& to, double progress)
264 {
265     if (from.isLength() && to.isLength())
266         return TextUnderlineOffset::createWithLength(blendFunc(anim, from.lengthValue(), to.lengthValue(), progress));
267     return TextUnderlineOffset::createWithAuto();
268 }
269
270 static inline TextDecorationThickness blendFunc(const CSSPropertyBlendingClient* anim, const TextDecorationThickness& from, const TextDecorationThickness& to, double progress)
271 {
272     if (from.isLength() && to.isLength())
273         return TextDecorationThickness::createWithLength(blendFunc(anim, from.lengthValue(), to.lengthValue(), progress));
274     return TextDecorationThickness::createWithAuto();
275 }
276
277 static inline LengthBox blendFunc(const CSSPropertyBlendingClient* anim, const LengthBox& from, const LengthBox& to, double progress)
278 {
279     LengthBox result(blendFunc(anim, from.top(), to.top(), progress),
280                      blendFunc(anim, from.right(), to.right(), progress),
281                      blendFunc(anim, from.bottom(), to.bottom(), progress),
282                      blendFunc(anim, from.left(), to.left(), progress));
283     return result;
284 }
285
286 static inline SVGLengthValue blendFunc(const CSSPropertyBlendingClient*, const SVGLengthValue& from, const SVGLengthValue& to, double progress)
287 {
288     return to.blend(from, narrowPrecisionToFloat(progress));
289 }
290
291 static inline Vector<SVGLengthValue> blendFunc(const CSSPropertyBlendingClient*, const Vector<SVGLengthValue>& from, const Vector<SVGLengthValue>& to, double progress)
292 {
293     size_t fromLength = from.size();
294     size_t toLength = to.size();
295     if (!fromLength)
296         return !progress ? from : to;
297     if (!toLength)
298         return progress == 1 ? from : to;
299     size_t resultLength = fromLength;
300     if (fromLength != toLength) {
301         if (!remainder(std::max(fromLength, toLength), std::min(fromLength, toLength)))
302             resultLength = std::max(fromLength, toLength);
303         else
304             resultLength = fromLength * toLength;
305     }
306     Vector<SVGLengthValue> result(resultLength);
307     for (size_t i = 0; i < resultLength; ++i)
308         result[i] = to[i % toLength].blend(from[i % fromLength], narrowPrecisionToFloat(progress));
309     return result;
310 }
311
312 static inline RefPtr<StyleImage> crossfadeBlend(const CSSPropertyBlendingClient*, StyleCachedImage* fromStyleImage, StyleCachedImage* toStyleImage, double progress)
313 {
314     // If progress is at one of the extremes, we want getComputedStyle to show the image,
315     // not a completed cross-fade, so we hand back one of the existing images.
316     if (!progress)
317         return fromStyleImage;
318     if (progress == 1)
319         return toStyleImage;
320     if (!fromStyleImage->cachedImage() || !toStyleImage->cachedImage())
321         return toStyleImage;
322
323     auto fromImageValue = CSSImageValue::create(*fromStyleImage->cachedImage());
324     auto toImageValue = CSSImageValue::create(*toStyleImage->cachedImage());
325     auto percentageValue = CSSPrimitiveValue::create(progress, CSSPrimitiveValue::CSS_NUMBER);
326
327     auto crossfadeValue = CSSCrossfadeValue::create(WTFMove(fromImageValue), WTFMove(toImageValue), WTFMove(percentageValue));
328     return StyleGeneratedImage::create(WTFMove(crossfadeValue));
329 }
330
331 static inline RefPtr<StyleImage> blendFunc(const CSSPropertyBlendingClient* anim, StyleImage* from, StyleImage* to, double progress)
332 {
333     if (!from || !to)
334         return to;
335
336     // Animation between two generated images. Cross fade for all other cases.
337     if (is<StyleGeneratedImage>(*from) && is<StyleGeneratedImage>(*to)) {
338         CSSImageGeneratorValue& fromGenerated = downcast<StyleGeneratedImage>(*from).imageValue();
339         CSSImageGeneratorValue& toGenerated = downcast<StyleGeneratedImage>(*to).imageValue();
340
341         if (is<CSSFilterImageValue>(fromGenerated) && is<CSSFilterImageValue>(toGenerated)) {
342             // Animation of generated images just possible if input images are equal.
343             // Otherwise fall back to cross fade animation.
344             CSSFilterImageValue& fromFilter = downcast<CSSFilterImageValue>(fromGenerated);
345             CSSFilterImageValue& toFilter = downcast<CSSFilterImageValue>(toGenerated);
346             if (fromFilter.equalInputImages(toFilter) && fromFilter.cachedImage())
347                 return blendFilter(anim, fromFilter.cachedImage(), fromFilter.filterOperations(), toFilter.filterOperations(), progress);
348         }
349
350         if (is<CSSCrossfadeValue>(fromGenerated) && is<CSSCrossfadeValue>(toGenerated)) {
351             CSSCrossfadeValue& fromCrossfade = downcast<CSSCrossfadeValue>(fromGenerated);
352             CSSCrossfadeValue& toCrossfade = downcast<CSSCrossfadeValue>(toGenerated);
353             if (fromCrossfade.equalInputImages(toCrossfade)) {
354                 if (auto crossfadeBlend = toCrossfade.blend(fromCrossfade, progress))
355                     return StyleGeneratedImage::create(*crossfadeBlend);
356             }
357         }
358
359         // FIXME: Add support for animation between two *gradient() functions.
360         // https://bugs.webkit.org/show_bug.cgi?id=119956
361     } else if (is<StyleGeneratedImage>(*from) && is<StyleCachedImage>(*to)) {
362         CSSImageGeneratorValue& fromGenerated = downcast<StyleGeneratedImage>(*from).imageValue();
363         if (is<CSSFilterImageValue>(fromGenerated)) {
364             CSSFilterImageValue& fromFilter = downcast<CSSFilterImageValue>(fromGenerated);
365             if (fromFilter.cachedImage() && downcast<StyleCachedImage>(*to).cachedImage() == fromFilter.cachedImage())
366                 return blendFilter(anim, fromFilter.cachedImage(), fromFilter.filterOperations(), FilterOperations(), progress);
367         }
368         // FIXME: Add interpolation between cross-fade and image source.
369     } else if (is<StyleCachedImage>(*from) && is<StyleGeneratedImage>(*to)) {
370         CSSImageGeneratorValue& toGenerated = downcast<StyleGeneratedImage>(*to).imageValue();
371         if (is<CSSFilterImageValue>(toGenerated)) {
372             CSSFilterImageValue& toFilter = downcast<CSSFilterImageValue>(toGenerated);
373             if (toFilter.cachedImage() && downcast<StyleCachedImage>(*from).cachedImage() == toFilter.cachedImage())
374                 return blendFilter(anim, toFilter.cachedImage(), FilterOperations(), toFilter.filterOperations(), progress);
375         }
376         // FIXME: Add interpolation between image source and cross-fade.
377     }
378
379     // FIXME: Add support cross fade between cached and generated images.
380     // https://bugs.webkit.org/show_bug.cgi?id=78293
381     if (is<StyleCachedImage>(*from) && is<StyleCachedImage>(*to))
382         return crossfadeBlend(anim, downcast<StyleCachedImage>(from), downcast<StyleCachedImage>(to), progress);
383
384     return to;
385 }
386
387 static inline NinePieceImage blendFunc(const CSSPropertyBlendingClient* anim, const NinePieceImage& from, const NinePieceImage& to, double progress)
388 {
389     if (!from.hasImage() || !to.hasImage())
390         return to;
391
392     // FIXME (74112): Support transitioning between NinePieceImages that differ by more than image content.
393
394     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())
395         return to;
396
397     if (auto* renderer = anim->renderer()) {
398         if (from.image()->imageSize(renderer, 1.0) != to.image()->imageSize(renderer, 1.0))
399             return to;
400     }
401
402     return NinePieceImage(blendFunc(anim, from.image(), to.image(), progress),
403         from.imageSlices(), from.fill(), from.borderSlices(), from.outset(), from.horizontalRule(), from.verticalRule());
404 }
405
406 #if ENABLE(VARIATION_FONTS)
407
408 static inline FontVariationSettings blendFunc(const CSSPropertyBlendingClient* anim, const FontVariationSettings& from, const FontVariationSettings& to, double progress)
409 {
410     if (from.size() != to.size())
411         return FontVariationSettings();
412     FontVariationSettings result;
413     unsigned size = from.size();
414     for (unsigned i = 0; i < size; ++i) {
415         auto& fromItem = from.at(i);
416         auto& toItem = to.at(i);
417         if (fromItem.tag() != toItem.tag())
418             return FontVariationSettings();
419         float interpolated = blendFunc(anim, fromItem.value(), toItem.value(), progress);
420         result.insert({ fromItem.tag(), interpolated });
421     }
422     return result;
423 }
424
425 #endif
426
427 static inline FontSelectionValue blendFunc(const CSSPropertyBlendingClient* anim, FontSelectionValue from, FontSelectionValue to, double progress)
428 {
429     return FontSelectionValue(blendFunc(anim, static_cast<float>(from), static_cast<float>(to), progress));
430 }
431
432 static inline Optional<FontSelectionValue> blendFunc(const CSSPropertyBlendingClient* anim, Optional<FontSelectionValue> from, Optional<FontSelectionValue> to, double progress)
433 {
434     return FontSelectionValue(blendFunc(anim, static_cast<float>(from.value()), static_cast<float>(to.value()), progress));
435 }
436
437 class AnimationPropertyWrapperBase {
438     WTF_MAKE_NONCOPYABLE(AnimationPropertyWrapperBase);
439     WTF_MAKE_FAST_ALLOCATED;
440 public:
441     explicit AnimationPropertyWrapperBase(CSSPropertyID prop)
442         : m_prop(prop)
443     {
444     }
445     virtual ~AnimationPropertyWrapperBase() = default;
446
447     virtual bool isShorthandWrapper() const { return false; }
448     virtual bool equals(const RenderStyle* a, const RenderStyle* b) const = 0;
449     virtual bool canInterpolate(const RenderStyle*, const RenderStyle*) const { return true; }
450     virtual void blend(const CSSPropertyBlendingClient*, RenderStyle*, const RenderStyle*, const RenderStyle*, double) const = 0;
451     
452 #if !LOG_DISABLED
453     virtual void logBlend(const RenderStyle* a, const RenderStyle* b, const RenderStyle* result, double) const = 0;
454 #endif
455
456     CSSPropertyID property() const { return m_prop; }
457
458     virtual bool animationIsAccelerated() const { return false; }
459
460 private:
461     CSSPropertyID m_prop;
462 };
463
464 template <typename T>
465 class PropertyWrapperGetter : public AnimationPropertyWrapperBase {
466     WTF_MAKE_FAST_ALLOCATED;
467 public:
468     PropertyWrapperGetter(CSSPropertyID prop, T (RenderStyle::*getter)() const)
469         : AnimationPropertyWrapperBase(prop)
470         , m_getter(getter)
471     {
472     }
473
474     bool equals(const RenderStyle* a, const RenderStyle* b) const override
475     {
476         if (a == b)
477             return true;
478         if (!a || !b)
479             return false;
480         return (a->*m_getter)() == (b->*m_getter)();
481     }
482
483     T value(const RenderStyle* a) const
484     {
485         return (a->*m_getter)();
486     }
487
488 #if !LOG_DISABLED
489     void logBlend(const RenderStyle* a, const RenderStyle* b, const RenderStyle* result, double progress) const final
490     {
491         LOG_WITH_STREAM(Animations, stream << "  blending " << getPropertyName(property()) << " from " << value(a) << " to " << value(b) << " at " << TextStream::FormatNumberRespectingIntegers(progress) << " -> " << value(result));
492     }
493 #endif
494
495 protected:
496     T (RenderStyle::*m_getter)() const;
497 };
498
499 template <typename T>
500 class PropertyWrapper : public PropertyWrapperGetter<T> {
501     WTF_MAKE_FAST_ALLOCATED;
502 public:
503     PropertyWrapper(CSSPropertyID prop, T (RenderStyle::*getter)() const, void (RenderStyle::*setter)(T))
504         : PropertyWrapperGetter<T>(prop, getter)
505         , m_setter(setter)
506     {
507     }
508
509     void blend(const CSSPropertyBlendingClient* anim, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress) const override
510     {
511         (dst->*m_setter)(blendFunc(anim, (a->*PropertyWrapperGetter<T>::m_getter)(), (b->*PropertyWrapperGetter<T>::m_getter)(), progress));
512     }
513
514 protected:
515     void (RenderStyle::*m_setter)(T);
516 };
517
518 template <typename T>
519 class RefCountedPropertyWrapper : public PropertyWrapperGetter<T*> {
520     WTF_MAKE_FAST_ALLOCATED;
521 public:
522     RefCountedPropertyWrapper(CSSPropertyID prop, T* (RenderStyle::*getter)() const, void (RenderStyle::*setter)(RefPtr<T>&&))
523         : PropertyWrapperGetter<T*>(prop, getter)
524         , m_setter(setter)
525     {
526     }
527
528     void blend(const CSSPropertyBlendingClient* anim, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress) const override
529     {
530         (dst->*m_setter)(blendFunc(anim, (a->*PropertyWrapperGetter<T*>::m_getter)(), (b->*PropertyWrapperGetter<T*>::m_getter)(), progress));
531     }
532
533 protected:
534     void (RenderStyle::*m_setter)(RefPtr<T>&&);
535 };
536
537 class LengthPropertyWrapper : public PropertyWrapperGetter<const Length&> {
538     WTF_MAKE_FAST_ALLOCATED;
539 public:
540     LengthPropertyWrapper(CSSPropertyID prop, const Length& (RenderStyle::*getter)() const, void (RenderStyle::*setter)(Length&&))
541         : PropertyWrapperGetter<const Length&>(prop, getter)
542         , m_setter(setter)
543     {
544     }
545
546     bool canInterpolate(const RenderStyle* a, const RenderStyle* b) const override
547     {
548         return !(a->*PropertyWrapperGetter<const Length&>::m_getter)().isAuto() && !(b->*PropertyWrapperGetter<const Length&>::m_getter)().isAuto();
549     }
550
551     void blend(const CSSPropertyBlendingClient* anim, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress) const override
552     {
553         (dst->*m_setter)(blendFunc(anim, (a->*PropertyWrapperGetter<const Length&>::m_getter)(), (b->*PropertyWrapperGetter<const Length&>::m_getter)(), progress));
554     }
555
556 protected:
557     void (RenderStyle::*m_setter)(Length&&);
558 };
559
560 template <typename T>
561 class LengthVariantPropertyWrapper : public PropertyWrapperGetter<const T&> {
562     WTF_MAKE_FAST_ALLOCATED;
563 public:
564     LengthVariantPropertyWrapper(CSSPropertyID prop, const T& (RenderStyle::*getter)() const, void (RenderStyle::*setter)(T&&))
565         : PropertyWrapperGetter<const T&>(prop, getter)
566         , m_setter(setter)
567     {
568     }
569
570     void blend(const CSSPropertyBlendingClient* anim, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress) const override
571     {
572         (dst->*m_setter)(blendFunc(anim, (a->*PropertyWrapperGetter<const T&>::m_getter)(), (b->*PropertyWrapperGetter<const T&>::m_getter)(), progress));
573     }
574
575 protected:
576     void (RenderStyle::*m_setter)(T&&);
577 };
578
579 class PropertyWrapperClipPath : public RefCountedPropertyWrapper<ClipPathOperation> {
580     WTF_MAKE_FAST_ALLOCATED;
581 public:
582     PropertyWrapperClipPath(CSSPropertyID prop, ClipPathOperation* (RenderStyle::*getter)() const, void (RenderStyle::*setter)(RefPtr<ClipPathOperation>&&))
583         : RefCountedPropertyWrapper<ClipPathOperation>(prop, getter, setter)
584     {
585     }
586
587     bool equals(const RenderStyle* a, const RenderStyle* b) const override
588     {
589         // If the style pointers are the same, don't bother doing the test.
590         // If either is null, return false. If both are null, return true.
591         if (a == b)
592             return true;
593         if (!a || !b)
594             return false;
595
596         ClipPathOperation* clipPathA = (a->*m_getter)();
597         ClipPathOperation* clipPathB = (b->*m_getter)();
598         if (clipPathA == clipPathB)
599             return true;
600         if (!clipPathA || !clipPathB)
601             return false;
602         return *clipPathA == *clipPathB;
603     }
604 };
605
606 #if ENABLE(VARIATION_FONTS)
607 class PropertyWrapperFontVariationSettings : public PropertyWrapper<FontVariationSettings> {
608     WTF_MAKE_FAST_ALLOCATED;
609 public:
610     PropertyWrapperFontVariationSettings(CSSPropertyID prop, FontVariationSettings (RenderStyle::*getter)() const, void (RenderStyle::*setter)(FontVariationSettings))
611         : PropertyWrapper<FontVariationSettings>(prop, getter, setter)
612     {
613     }
614
615     bool equals(const RenderStyle* a, const RenderStyle* b) const override
616     {
617         // If the style pointers are the same, don't bother doing the test.
618         // If either is null, return false. If both are null, return true.
619         if (a == b)
620             return true;
621         if (!a || !b)
622             return false;
623
624         const FontVariationSettings& variationSettingsA = (a->*m_getter)();
625         const FontVariationSettings& variationSettingsB = (b->*m_getter)();
626         return variationSettingsA == variationSettingsB;
627     }
628 };
629 #endif
630
631 class PropertyWrapperShape : public RefCountedPropertyWrapper<ShapeValue> {
632     WTF_MAKE_FAST_ALLOCATED;
633 public:
634     PropertyWrapperShape(CSSPropertyID prop, ShapeValue* (RenderStyle::*getter)() const, void (RenderStyle::*setter)(RefPtr<ShapeValue>&&))
635         : RefCountedPropertyWrapper<ShapeValue>(prop, getter, setter)
636     {
637     }
638
639     bool equals(const RenderStyle* a, const RenderStyle* b) const override
640     {
641         // If the style pointers are the same, don't bother doing the test.
642         // If either is null, return false. If both are null, return true.
643         if (a == b)
644             return true;
645         if (!a || !b)
646             return false;
647
648         ShapeValue* shapeA = (a->*m_getter)();
649         ShapeValue* shapeB = (b->*m_getter)();
650         if (shapeA == shapeB)
651             return true;
652         if (!shapeA || !shapeB)
653             return false;
654         return *shapeA == *shapeB;
655     }
656 };
657
658 class StyleImagePropertyWrapper : public RefCountedPropertyWrapper<StyleImage> {
659     WTF_MAKE_FAST_ALLOCATED;
660 public:
661     StyleImagePropertyWrapper(CSSPropertyID prop, StyleImage* (RenderStyle::*getter)() const, void (RenderStyle::*setter)(RefPtr<StyleImage>&&))
662         : RefCountedPropertyWrapper<StyleImage>(prop, getter, setter)
663     {
664     }
665
666     bool equals(const RenderStyle* a, const RenderStyle* b) const override
667     {
668        if (a == b)
669            return true;
670        if (!a || !b)
671             return false;
672
673         StyleImage* imageA = (a->*m_getter)();
674         StyleImage* imageB = (b->*m_getter)();
675         return arePointingToEqualData(imageA, imageB);
676     }
677 };
678
679 class PropertyWrapperColor : public PropertyWrapperGetter<const Color&> {
680     WTF_MAKE_FAST_ALLOCATED;
681 public:
682     PropertyWrapperColor(CSSPropertyID prop, const Color& (RenderStyle::*getter)() const, void (RenderStyle::*setter)(const Color&))
683         : PropertyWrapperGetter<const Color&>(prop, getter)
684         , m_setter(setter)
685     {
686     }
687
688     void blend(const CSSPropertyBlendingClient* anim, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress) const override
689     {
690         (dst->*m_setter)(blendFunc(anim, (a->*PropertyWrapperGetter<const Color&>::m_getter)(), (b->*PropertyWrapperGetter<const Color&>::m_getter)(), progress));
691     }
692
693 protected:
694     void (RenderStyle::*m_setter)(const Color&);
695 };
696
697 class PropertyWrapperAcceleratedOpacity : public PropertyWrapper<float> {
698     WTF_MAKE_FAST_ALLOCATED;
699 public:
700     PropertyWrapperAcceleratedOpacity()
701         : PropertyWrapper<float>(CSSPropertyOpacity, &RenderStyle::opacity, &RenderStyle::setOpacity)
702     {
703     }
704
705     bool animationIsAccelerated() const override { return true; }
706
707     void blend(const CSSPropertyBlendingClient* anim, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress) const override
708     {
709         dst->setOpacity(blendFunc(anim, a->opacity(), b->opacity(), progress));
710     }
711 };
712
713 class PropertyWrapperAcceleratedTransform : public PropertyWrapper<const TransformOperations&> {
714     WTF_MAKE_FAST_ALLOCATED;
715 public:
716     PropertyWrapperAcceleratedTransform()
717         : PropertyWrapper<const TransformOperations&>(CSSPropertyTransform, &RenderStyle::transform, &RenderStyle::setTransform)
718     {
719     }
720
721     bool animationIsAccelerated() const override { return true; }
722
723     void blend(const CSSPropertyBlendingClient* anim, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress) const override
724     {
725         dst->setTransform(blendFunc(anim, a->transform(), b->transform(), progress));
726     }
727 };
728
729 class PropertyWrapperFilter : public PropertyWrapper<const FilterOperations&> {
730     WTF_MAKE_FAST_ALLOCATED;
731 public:
732     PropertyWrapperFilter(CSSPropertyID propertyID, const FilterOperations& (RenderStyle::*getter)() const, void (RenderStyle::*setter)(const FilterOperations&))
733         : PropertyWrapper<const FilterOperations&>(propertyID, getter, setter)
734     {
735     }
736
737     bool animationIsAccelerated() const override
738     {
739         return property() == CSSPropertyFilter
740 #if ENABLE(FILTERS_LEVEL_2)
741             || property() == CSSPropertyWebkitBackdropFilter
742 #endif
743             ;
744     }
745
746     void blend(const CSSPropertyBlendingClient* anim, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress) const override
747     {
748         (dst->*m_setter)(blendFunc(anim, (a->*PropertyWrapperGetter<const FilterOperations&>::m_getter)(), (b->*PropertyWrapperGetter<const FilterOperations&>::m_getter)(), progress, property()));
749     }
750 };
751
752 static inline size_t shadowListLength(const ShadowData* shadow)
753 {
754     size_t count;
755     for (count = 0; shadow; shadow = shadow->next())
756         ++count;
757     return count;
758 }
759
760 static inline const ShadowData* shadowForBlending(const ShadowData* srcShadow, const ShadowData* otherShadow)
761 {
762     static NeverDestroyed<ShadowData> defaultShadowData(IntPoint(), 0, 0, Normal, false, Color::transparent);
763     static NeverDestroyed<ShadowData> defaultInsetShadowData(IntPoint(), 0, 0, Inset, false, Color::transparent);
764     static NeverDestroyed<ShadowData> defaultWebKitBoxShadowData(IntPoint(), 0, 0, Normal, true, Color::transparent);
765     static NeverDestroyed<ShadowData> defaultInsetWebKitBoxShadowData(IntPoint(), 0, 0, Inset, true, Color::transparent);
766
767     if (srcShadow)
768         return srcShadow;
769
770     if (otherShadow->style() == Inset)
771         return otherShadow->isWebkitBoxShadow() ? &defaultInsetWebKitBoxShadowData.get() : &defaultInsetShadowData.get();
772
773     return otherShadow->isWebkitBoxShadow() ? &defaultWebKitBoxShadowData.get() : &defaultShadowData.get();
774 }
775
776 class PropertyWrapperShadow : public AnimationPropertyWrapperBase {
777     WTF_MAKE_FAST_ALLOCATED;
778 public:
779     PropertyWrapperShadow(CSSPropertyID prop, const ShadowData* (RenderStyle::*getter)() const, void (RenderStyle::*setter)(std::unique_ptr<ShadowData>, bool))
780         : AnimationPropertyWrapperBase(prop)
781         , m_getter(getter)
782         , m_setter(setter)
783     {
784     }
785
786     bool equals(const RenderStyle* a, const RenderStyle* b) const override
787     {
788         if (a == b)
789             return true;
790         if (!a || !b)
791             return false;
792
793         const ShadowData* shadowA = (a->*m_getter)();
794         const ShadowData* shadowB = (b->*m_getter)();
795
796         while (true) {
797             // end of both lists
798             if (!shadowA && !shadowB)
799                 return true;
800
801             // end of just one of the lists
802             if (!shadowA || !shadowB)
803                 return false;
804
805             if (*shadowA != *shadowB)
806                 return false;
807
808             shadowA = shadowA->next();
809             shadowB = shadowB->next();
810         }
811
812         return true;
813     }
814
815     void blend(const CSSPropertyBlendingClient* anim, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress) const override
816     {
817         const ShadowData* shadowA = (a->*m_getter)();
818         const ShadowData* shadowB = (b->*m_getter)();
819
820         int fromLength = shadowListLength(shadowA);
821         int toLength = shadowListLength(shadowB);
822
823         if (fromLength == toLength || (fromLength <= 1 && toLength <= 1)) {
824             (dst->*m_setter)(blendSimpleOrMatchedShadowLists(anim, progress, shadowA, shadowB), false);
825             return;
826         }
827
828         (dst->*m_setter)(blendMismatchedShadowLists(anim, progress, shadowA, shadowB, fromLength, toLength), false);
829     }
830
831 #if !LOG_DISABLED
832     void logBlend(const RenderStyle*, const RenderStyle*, const RenderStyle*, double progress) const final
833     {
834         // FIXME: better logging.
835         LOG_WITH_STREAM(Animations, stream << "  blending ShadowData at " << TextStream::FormatNumberRespectingIntegers(progress));
836     }
837 #endif
838
839 private:
840     std::unique_ptr<ShadowData> blendSimpleOrMatchedShadowLists(const CSSPropertyBlendingClient* anim, double progress, const ShadowData* shadowA, const ShadowData* shadowB) const
841     {
842         std::unique_ptr<ShadowData> newShadowData;
843         ShadowData* lastShadow = 0;
844
845         while (shadowA || shadowB) {
846             const ShadowData* srcShadow = shadowForBlending(shadowA, shadowB);
847             const ShadowData* dstShadow = shadowForBlending(shadowB, shadowA);
848
849             std::unique_ptr<ShadowData> blendedShadow = blendFunc(anim, srcShadow, dstShadow, progress);
850             ShadowData* blendedShadowPtr = blendedShadow.get();
851
852             if (!lastShadow)
853                 newShadowData = WTFMove(blendedShadow);
854             else
855                 lastShadow->setNext(WTFMove(blendedShadow));
856
857             lastShadow = blendedShadowPtr;
858
859             shadowA = shadowA ? shadowA->next() : 0;
860             shadowB = shadowB ? shadowB->next() : 0;
861         }
862
863         return newShadowData;
864     }
865
866     std::unique_ptr<ShadowData> blendMismatchedShadowLists(const CSSPropertyBlendingClient* anim, double progress, const ShadowData* shadowA, const ShadowData* shadowB, int fromLength, int toLength) const
867     {
868         // The shadows in ShadowData are stored in reverse order, so when animating mismatched lists,
869         // reverse them and match from the end.
870         Vector<const ShadowData*, 4> fromShadows(fromLength);
871         for (int i = fromLength - 1; i >= 0; --i) {
872             fromShadows[i] = shadowA;
873             shadowA = shadowA->next();
874         }
875
876         Vector<const ShadowData*, 4> toShadows(toLength);
877         for (int i = toLength - 1; i >= 0; --i) {
878             toShadows[i] = shadowB;
879             shadowB = shadowB->next();
880         }
881
882         std::unique_ptr<ShadowData> newShadowData;
883
884         int maxLength = std::max(fromLength, toLength);
885         for (int i = 0; i < maxLength; ++i) {
886             const ShadowData* fromShadow = i < fromLength ? fromShadows[i] : 0;
887             const ShadowData* toShadow = i < toLength ? toShadows[i] : 0;
888
889             const ShadowData* srcShadow = shadowForBlending(fromShadow, toShadow);
890             const ShadowData* dstShadow = shadowForBlending(toShadow, fromShadow);
891
892             std::unique_ptr<ShadowData> blendedShadow = blendFunc(anim, srcShadow, dstShadow, progress);
893             // Insert at the start of the list to preserve the order.
894             blendedShadow->setNext(WTFMove(newShadowData));
895             newShadowData = WTFMove(blendedShadow);
896         }
897
898         return newShadowData;
899     }
900
901     const ShadowData* (RenderStyle::*m_getter)() const;
902     void (RenderStyle::*m_setter)(std::unique_ptr<ShadowData>, bool);
903 };
904
905 class PropertyWrapperMaybeInvalidColor : public AnimationPropertyWrapperBase {
906     WTF_MAKE_FAST_ALLOCATED;
907 public:
908     PropertyWrapperMaybeInvalidColor(CSSPropertyID prop, const Color& (RenderStyle::*getter)() const, void (RenderStyle::*setter)(const Color&))
909         : AnimationPropertyWrapperBase(prop)
910         , m_getter(getter)
911         , m_setter(setter)
912     {
913     }
914
915     bool equals(const RenderStyle* a, const RenderStyle* b) const override
916     {
917         if (a == b)
918             return true;
919         if (!a || !b)
920             return false;
921
922         Color fromColor = value(a);
923         Color toColor = value(b);
924
925         if (!fromColor.isValid() && !toColor.isValid())
926             return true;
927
928         if (!fromColor.isValid())
929             fromColor = a->color();
930         if (!toColor.isValid())
931             toColor = b->color();
932
933         return fromColor == toColor;
934     }
935
936     void blend(const CSSPropertyBlendingClient* anim, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress) const override
937     {
938         Color fromColor = value(a);
939         Color toColor = value(b);
940
941         if (!fromColor.isValid() && !toColor.isValid())
942             return;
943
944         if (!fromColor.isValid())
945             fromColor = a->color();
946         if (!toColor.isValid())
947             toColor = b->color();
948         (dst->*m_setter)(blendFunc(anim, fromColor, toColor, progress));
949     }
950
951     Color value(const RenderStyle* a) const
952     {
953         return (a->*m_getter)();
954     }
955
956 #if !LOG_DISABLED
957     void logBlend(const RenderStyle* a, const RenderStyle* b, const RenderStyle* result, double progress) const final
958     {
959         // FIXME: better logging.
960         LOG_WITH_STREAM(Animations, stream << "  blending " << getPropertyName(property()) << " from " << value(a) << " to " << value(b) << " at " << TextStream::FormatNumberRespectingIntegers(progress) << " -> " << value(result));
961     }
962 #endif
963
964 private:
965     const Color& (RenderStyle::*m_getter)() const;
966     void (RenderStyle::*m_setter)(const Color&);
967 };
968
969
970 enum MaybeInvalidColorTag { MaybeInvalidColor };
971 class PropertyWrapperVisitedAffectedColor : public AnimationPropertyWrapperBase {
972     WTF_MAKE_FAST_ALLOCATED;
973 public:
974     PropertyWrapperVisitedAffectedColor(CSSPropertyID prop, const Color& (RenderStyle::*getter)() const, void (RenderStyle::*setter)(const Color&),
975         const Color& (RenderStyle::*visitedGetter)() const, void (RenderStyle::*visitedSetter)(const Color&))
976         : AnimationPropertyWrapperBase(prop)
977         , m_wrapper(makeUnique<PropertyWrapperColor>(prop, getter, setter))
978         , m_visitedWrapper(makeUnique<PropertyWrapperColor>(prop, visitedGetter, visitedSetter))
979     {
980     }
981     PropertyWrapperVisitedAffectedColor(CSSPropertyID prop, MaybeInvalidColorTag, const Color& (RenderStyle::*getter)() const, void (RenderStyle::*setter)(const Color&),
982         const Color& (RenderStyle::*visitedGetter)() const, void (RenderStyle::*visitedSetter)(const Color&))
983         : AnimationPropertyWrapperBase(prop)
984         , m_wrapper(makeUnique<PropertyWrapperMaybeInvalidColor>(prop, getter, setter))
985         , m_visitedWrapper(makeUnique<PropertyWrapperMaybeInvalidColor>(prop, visitedGetter, visitedSetter))
986     {
987     }
988     bool equals(const RenderStyle* a, const RenderStyle* b) const override
989     {
990         return m_wrapper->equals(a, b) && m_visitedWrapper->equals(a, b);
991     }
992     void blend(const CSSPropertyBlendingClient* anim, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress) const override
993     {
994         m_wrapper->blend(anim, dst, a, b, progress);
995         m_visitedWrapper->blend(anim, dst, a, b, progress);
996     }
997
998 #if !LOG_DISABLED
999     void logBlend(const RenderStyle* a, const RenderStyle* b, const RenderStyle* result, double progress) const final
1000     {
1001         m_wrapper->logBlend(a, b, result, progress);
1002         m_visitedWrapper->logBlend(a, b, result, progress);
1003     }
1004 #endif
1005
1006 private:
1007     std::unique_ptr<AnimationPropertyWrapperBase> m_wrapper;
1008     std::unique_ptr<AnimationPropertyWrapperBase> m_visitedWrapper;
1009 };
1010
1011 // Wrapper base class for an animatable property in a FillLayer
1012 class FillLayerAnimationPropertyWrapperBase {
1013     WTF_MAKE_FAST_ALLOCATED;
1014 public:
1015     FillLayerAnimationPropertyWrapperBase(CSSPropertyID property)
1016         : m_property(property)
1017     {
1018     }
1019     virtual ~FillLayerAnimationPropertyWrapperBase() = default;
1020
1021     CSSPropertyID property() const { return m_property; }
1022
1023     virtual bool equals(const FillLayer*, const FillLayer*) const = 0;
1024     virtual void blend(const CSSPropertyBlendingClient*, FillLayer*, const FillLayer*, const FillLayer*, double) const = 0;
1025
1026 #if !LOG_DISABLED
1027     virtual void logBlend(const FillLayer* result, const FillLayer*, const FillLayer*, double) const = 0;
1028 #endif
1029 private:
1030     CSSPropertyID m_property;
1031 };
1032
1033 template <typename T>
1034 class FillLayerPropertyWrapperGetter : public FillLayerAnimationPropertyWrapperBase {
1035     WTF_MAKE_FAST_ALLOCATED;
1036     WTF_MAKE_NONCOPYABLE(FillLayerPropertyWrapperGetter);
1037 public:
1038     FillLayerPropertyWrapperGetter(CSSPropertyID property, T (FillLayer::*getter)() const)
1039         : FillLayerAnimationPropertyWrapperBase(property)
1040         , m_getter(getter)
1041     {
1042     }
1043
1044     bool equals(const FillLayer* a, const FillLayer* b) const override
1045     {
1046         if (a == b)
1047             return true;
1048         if (!a || !b)
1049             return false;
1050         return (a->*m_getter)() == (b->*m_getter)();
1051     }
1052
1053     T value(const FillLayer* layer) const
1054     {
1055         return (layer->*m_getter)();
1056     }
1057
1058 #if !LOG_DISABLED
1059     void logBlend(const FillLayer* result, const FillLayer* a, const FillLayer* b, double progress) const override
1060     {
1061         LOG_WITH_STREAM(Animations, stream << "  blending " << getPropertyName(property()) << " from " << value(a) << " to " << value(b) << " at " << TextStream::FormatNumberRespectingIntegers(progress) << " -> " << value(result));
1062     }
1063 #endif
1064
1065 protected:
1066     T (FillLayer::*m_getter)() const;
1067 };
1068
1069 template <typename T>
1070 class FillLayerPropertyWrapper : public FillLayerPropertyWrapperGetter<const T&> {
1071     WTF_MAKE_FAST_ALLOCATED;
1072 public:
1073     FillLayerPropertyWrapper(CSSPropertyID property, const T& (FillLayer::*getter)() const, void (FillLayer::*setter)(T))
1074         : FillLayerPropertyWrapperGetter<const T&>(property, getter)
1075         , m_setter(setter)
1076     {
1077     }
1078
1079     void blend(const CSSPropertyBlendingClient* anim, FillLayer* dst, const FillLayer* a, const FillLayer* b, double progress) const override
1080     {
1081         (dst->*m_setter)(blendFunc(anim, (a->*FillLayerPropertyWrapperGetter<const T&>::m_getter)(), (b->*FillLayerPropertyWrapperGetter<const T&>::m_getter)(), progress));
1082     }
1083
1084 #if !LOG_DISABLED
1085     void logBlend(const FillLayer* result, const FillLayer* a, const FillLayer* b, double progress) const override
1086     {
1087         LOG_WITH_STREAM(Animations, stream << "  blending " << getPropertyName(FillLayerPropertyWrapperGetter<const T&>::property())
1088             << " from " << FillLayerPropertyWrapperGetter<const T&>::value(a)
1089             << " to " << FillLayerPropertyWrapperGetter<const T&>::value(b)
1090             << " at " << TextStream::FormatNumberRespectingIntegers(progress) << " -> " << FillLayerPropertyWrapperGetter<const T&>::value(result));
1091     }
1092 #endif
1093
1094 protected:
1095     void (FillLayer::*m_setter)(T);
1096 };
1097
1098 class FillLayerPositionPropertyWrapper : public FillLayerPropertyWrapperGetter<const Length&> {
1099     WTF_MAKE_FAST_ALLOCATED;
1100 public:
1101     FillLayerPositionPropertyWrapper(CSSPropertyID property, const Length& (FillLayer::*lengthGetter)() const, void (FillLayer::*lengthSetter)(Length), Edge (FillLayer::*originGetter)() const, void (FillLayer::*originSetter)(Edge), Edge farEdge)
1102         : FillLayerPropertyWrapperGetter<const Length&>(property, lengthGetter)
1103         , m_lengthSetter(lengthSetter)
1104         , m_originGetter(originGetter)
1105         , m_originSetter(originSetter)
1106         , m_farEdge(farEdge)
1107     {
1108     }
1109
1110     bool equals(const FillLayer* a, const FillLayer* b) const override
1111     {
1112         if (a == b)
1113             return true;
1114         if (!a || !b)
1115             return false;
1116
1117         Length fromLength = (a->*FillLayerPropertyWrapperGetter<const Length&>::m_getter)();
1118         Length toLength = (b->*FillLayerPropertyWrapperGetter<const Length&>::m_getter)();
1119         
1120         Edge fromEdge = (a->*m_originGetter)();
1121         Edge toEdge = (b->*m_originGetter)();
1122         
1123         return fromLength == toLength && fromEdge == toEdge;
1124     }
1125
1126     void blend(const CSSPropertyBlendingClient* anim, FillLayer* dst, const FillLayer* a, const FillLayer* b, double progress) const override
1127     {
1128         Length fromLength = (a->*FillLayerPropertyWrapperGetter<const Length&>::m_getter)();
1129         Length toLength = (b->*FillLayerPropertyWrapperGetter<const Length&>::m_getter)();
1130         
1131         Edge fromEdge = (a->*m_originGetter)();
1132         Edge toEdge = (b->*m_originGetter)();
1133         
1134         if (fromEdge != toEdge) {
1135             // Convert the right/bottom into a calc expression,
1136             if (fromEdge == m_farEdge)
1137                 fromLength = convertTo100PercentMinusLength(fromLength);
1138             else if (toEdge == m_farEdge) {
1139                 toLength = convertTo100PercentMinusLength(toLength);
1140                 (dst->*m_originSetter)(fromEdge); // Now we have a calc(100% - l), it's relative to the left/top edge.
1141             }
1142         }
1143
1144         (dst->*m_lengthSetter)(blendFunc(anim, fromLength, toLength, progress));
1145     }
1146
1147 #if !LOG_DISABLED
1148     void logBlend(const FillLayer* result, const FillLayer* a, const FillLayer* b, double progress) const override
1149     {
1150         LOG_WITH_STREAM(Animations, stream << "  blending " << getPropertyName(property()) << " from " << value(a) << " to " << value(b) << " at " << TextStream::FormatNumberRespectingIntegers(progress) << " -> " << value(result));
1151     }
1152 #endif
1153
1154 protected:
1155     void (FillLayer::*m_lengthSetter)(Length);
1156     Edge (FillLayer::*m_originGetter)() const;
1157     void (FillLayer::*m_originSetter)(Edge);
1158     Edge m_farEdge;
1159 };
1160
1161 template <typename T>
1162 class FillLayerRefCountedPropertyWrapper : public FillLayerPropertyWrapperGetter<T*> {
1163     WTF_MAKE_FAST_ALLOCATED;
1164 public:
1165     FillLayerRefCountedPropertyWrapper(CSSPropertyID property, T* (FillLayer::*getter)() const, void (FillLayer::*setter)(RefPtr<T>&&))
1166         : FillLayerPropertyWrapperGetter<T*>(property, getter)
1167         , m_setter(setter)
1168     {
1169     }
1170
1171     void blend(const CSSPropertyBlendingClient* anim, FillLayer* dst, const FillLayer* a, const FillLayer* b, double progress) const override
1172     {
1173         (dst->*m_setter)(blendFunc(anim, (a->*FillLayerPropertyWrapperGetter<T*>::m_getter)(), (b->*FillLayerPropertyWrapperGetter<T*>::m_getter)(), progress));
1174     }
1175
1176 #if !LOG_DISABLED
1177     void logBlend(const FillLayer* result, const FillLayer* a, const FillLayer* b, double progress) const override
1178     {
1179         LOG_WITH_STREAM(Animations, stream << "  blending " << getPropertyName(FillLayerPropertyWrapperGetter<T*>::property())
1180             << " from " << FillLayerPropertyWrapperGetter<T*>::value(a)
1181             << " to " << FillLayerPropertyWrapperGetter<T*>::value(b)
1182             << " at " << TextStream::FormatNumberRespectingIntegers(progress) << " -> " << FillLayerPropertyWrapperGetter<T*>::value(result));
1183     }
1184 #endif
1185
1186 protected:
1187     void (FillLayer::*m_setter)(RefPtr<T>&&);
1188 };
1189
1190 class FillLayerStyleImagePropertyWrapper : public FillLayerRefCountedPropertyWrapper<StyleImage> {
1191     WTF_MAKE_FAST_ALLOCATED;
1192 public:
1193     FillLayerStyleImagePropertyWrapper(CSSPropertyID property, StyleImage* (FillLayer::*getter)() const, void (FillLayer::*setter)(RefPtr<StyleImage>&&))
1194         : FillLayerRefCountedPropertyWrapper<StyleImage>(property, getter, setter)
1195     {
1196     }
1197
1198     bool equals(const FillLayer* a, const FillLayer* b) const override
1199     {
1200        if (a == b)
1201            return true;
1202        if (!a || !b)
1203             return false;
1204
1205         StyleImage* imageA = (a->*m_getter)();
1206         StyleImage* imageB = (b->*m_getter)();
1207         return arePointingToEqualData(imageA, imageB);
1208     }
1209
1210 #if !LOG_DISABLED
1211     void logBlend(const FillLayer* result, const FillLayer* a, const FillLayer* b, double progress) const override
1212     {
1213         LOG_WITH_STREAM(Animations, stream << "  blending " << getPropertyName(property()) << " from " << value(a) << " to " << value(b) << " at " << TextStream::FormatNumberRespectingIntegers(progress) << " -> " << value(result));
1214     }
1215 #endif
1216 };
1217
1218 class FillLayersPropertyWrapper : public AnimationPropertyWrapperBase {
1219     WTF_MAKE_FAST_ALLOCATED;
1220 public:
1221     typedef const FillLayer& (RenderStyle::*LayersGetter)() const;
1222     typedef FillLayer& (RenderStyle::*LayersAccessor)();
1223
1224     FillLayersPropertyWrapper(CSSPropertyID property, LayersGetter getter, LayersAccessor accessor)
1225         : AnimationPropertyWrapperBase(property)
1226         , m_layersGetter(getter)
1227         , m_layersAccessor(accessor)
1228     {
1229         switch (property) {
1230         case CSSPropertyBackgroundPositionX:
1231         case CSSPropertyWebkitMaskPositionX:
1232             m_fillLayerPropertyWrapper = makeUnique<FillLayerPositionPropertyWrapper>(property, &FillLayer::xPosition, &FillLayer::setXPosition, &FillLayer::backgroundXOrigin, &FillLayer::setBackgroundXOrigin, Edge::Right);
1233             break;
1234         case CSSPropertyBackgroundPositionY:
1235         case CSSPropertyWebkitMaskPositionY:
1236             m_fillLayerPropertyWrapper = makeUnique<FillLayerPositionPropertyWrapper>(property, &FillLayer::yPosition, &FillLayer::setYPosition, &FillLayer::backgroundYOrigin, &FillLayer::setBackgroundYOrigin, Edge::Bottom);
1237             break;
1238         case CSSPropertyBackgroundSize:
1239         case CSSPropertyWebkitBackgroundSize:
1240         case CSSPropertyWebkitMaskSize:
1241             m_fillLayerPropertyWrapper = makeUnique<FillLayerPropertyWrapper<LengthSize>>(property, &FillLayer::sizeLength, &FillLayer::setSizeLength);
1242             break;
1243         case CSSPropertyBackgroundImage:
1244             m_fillLayerPropertyWrapper = makeUnique<FillLayerStyleImagePropertyWrapper>(property, &FillLayer::image, &FillLayer::setImage);
1245             break;
1246         default:
1247             break;
1248         }
1249     }
1250
1251     bool equals(const RenderStyle* a, const RenderStyle* b) const override
1252     {
1253         if (a == b)
1254             return true;
1255         if (!a || !b)
1256             return false;
1257
1258         auto* fromLayer = &(a->*m_layersGetter)();
1259         auto* toLayer = &(b->*m_layersGetter)();
1260
1261         while (fromLayer && toLayer) {
1262             if (!m_fillLayerPropertyWrapper->equals(fromLayer, toLayer))
1263                 return false;
1264
1265             fromLayer = fromLayer->next();
1266             toLayer = toLayer->next();
1267         }
1268
1269         return true;
1270     }
1271
1272     void blend(const CSSPropertyBlendingClient* anim, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress) const override
1273     {
1274         auto* aLayer = &(a->*m_layersGetter)();
1275         auto* bLayer = &(b->*m_layersGetter)();
1276         auto* dstLayer = &(dst->*m_layersAccessor)();
1277
1278         while (aLayer && bLayer && dstLayer) {
1279             m_fillLayerPropertyWrapper->blend(anim, dstLayer, aLayer, bLayer, progress);
1280             aLayer = aLayer->next();
1281             bLayer = bLayer->next();
1282             dstLayer = dstLayer->next();
1283         }
1284     }
1285
1286 #if !LOG_DISABLED
1287     void logBlend(const RenderStyle* from, const RenderStyle* to, const RenderStyle* result, double progress) const final
1288     {
1289         auto* aLayer = &(from->*m_layersGetter)();
1290         auto* bLayer = &(to->*m_layersGetter)();
1291         auto* dstLayer = &(result->*m_layersGetter)();
1292
1293         while (aLayer && bLayer && dstLayer) {
1294             m_fillLayerPropertyWrapper->logBlend(dstLayer, aLayer, bLayer, progress);
1295             aLayer = aLayer->next();
1296             bLayer = bLayer->next();
1297             dstLayer = dstLayer->next();
1298         }
1299     }
1300 #endif
1301
1302 private:
1303     std::unique_ptr<FillLayerAnimationPropertyWrapperBase> m_fillLayerPropertyWrapper;
1304
1305     LayersGetter m_layersGetter;
1306     LayersAccessor m_layersAccessor;
1307 };
1308
1309 class ShorthandPropertyWrapper : public AnimationPropertyWrapperBase {
1310     WTF_MAKE_FAST_ALLOCATED;
1311 public:
1312     ShorthandPropertyWrapper(CSSPropertyID property, Vector<AnimationPropertyWrapperBase*> longhandWrappers)
1313         : AnimationPropertyWrapperBase(property)
1314         , m_propertyWrappers(WTFMove(longhandWrappers))
1315     {
1316     }
1317
1318     bool isShorthandWrapper() const override { return true; }
1319
1320     bool equals(const RenderStyle* a, const RenderStyle* b) const override
1321     {
1322         if (a == b)
1323             return true;
1324         if (!a || !b)
1325             return false;
1326
1327         for (auto& wrapper : m_propertyWrappers) {
1328             if (!wrapper->equals(a, b))
1329                 return false;
1330         }
1331         return true;
1332     }
1333
1334     void blend(const CSSPropertyBlendingClient* anim, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress) const override
1335     {
1336         for (auto& wrapper : m_propertyWrappers)
1337             wrapper->blend(anim, dst, a, b, progress);
1338     }
1339
1340 #if !LOG_DISABLED
1341     void logBlend(const RenderStyle* a, const RenderStyle* b, const RenderStyle* dst, double progress) const final
1342     {
1343         for (auto& wrapper : m_propertyWrappers)
1344             wrapper->logBlend(a, b, dst, progress);
1345     }
1346 #endif
1347
1348     const Vector<AnimationPropertyWrapperBase*>& propertyWrappers() const { return m_propertyWrappers; }
1349
1350 private:
1351     Vector<AnimationPropertyWrapperBase*> m_propertyWrappers;
1352 };
1353
1354 class PropertyWrapperFlex : public AnimationPropertyWrapperBase {
1355     WTF_MAKE_FAST_ALLOCATED;
1356 public:
1357     PropertyWrapperFlex()
1358         : AnimationPropertyWrapperBase(CSSPropertyFlex)
1359     {
1360     }
1361
1362     bool equals(const RenderStyle* a, const RenderStyle* b) const override
1363     {
1364         if (a == b)
1365             return true;
1366         if (!a || !b)
1367             return false;
1368
1369         return a->flexBasis() == b->flexBasis() && a->flexGrow() == b->flexGrow() && a->flexShrink() == b->flexShrink();
1370     }
1371
1372     void blend(const CSSPropertyBlendingClient* anim, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress) const override
1373     {
1374         dst->setFlexBasis(blendFunc(anim, a->flexBasis(), b->flexBasis(), progress));
1375         dst->setFlexGrow(blendFunc(anim, a->flexGrow(), b->flexGrow(), progress));
1376         dst->setFlexShrink(blendFunc(anim, a->flexShrink(), b->flexShrink(), progress));
1377     }
1378
1379 #if !LOG_DISABLED
1380     void logBlend(const RenderStyle*, const RenderStyle*, const RenderStyle*, double progress) const final
1381     {
1382         // FIXME: better logging.
1383         LOG_WITH_STREAM(Animations, stream << "  blending flex at " << TextStream::FormatNumberRespectingIntegers(progress));
1384     }
1385 #endif
1386 };
1387
1388 class PropertyWrapperSVGPaint : public AnimationPropertyWrapperBase {
1389     WTF_MAKE_FAST_ALLOCATED;
1390 public:
1391     PropertyWrapperSVGPaint(CSSPropertyID prop, SVGPaintType (RenderStyle::*paintTypeGetter)() const, Color (RenderStyle::*getter)() const, void (RenderStyle::*setter)(const Color&))
1392         : AnimationPropertyWrapperBase(prop)
1393         , m_paintTypeGetter(paintTypeGetter)
1394         , m_getter(getter)
1395         , m_setter(setter)
1396     {
1397     }
1398
1399     bool equals(const RenderStyle* a, const RenderStyle* b) const override
1400     {
1401         if (a == b)
1402             return true;
1403         if (!a || !b)
1404             return false;
1405
1406         if ((a->*m_paintTypeGetter)() != (b->*m_paintTypeGetter)())
1407             return false;
1408
1409         // We only support animations between SVGPaints that are pure Color values.
1410         // For everything else we must return true for this method, otherwise
1411         // we will try to animate between values forever.
1412         if ((a->*m_paintTypeGetter)() == SVGPaintType::RGBColor) {
1413             Color fromColor = (a->*m_getter)();
1414             Color toColor = (b->*m_getter)();
1415
1416             if (!fromColor.isValid() && !toColor.isValid())
1417                 return true;
1418
1419             if (!fromColor.isValid())
1420                 fromColor = Color();
1421             if (!toColor.isValid())
1422                 toColor = Color();
1423
1424             return fromColor == toColor;
1425         }
1426         return true;
1427     }
1428
1429     void blend(const CSSPropertyBlendingClient* anim, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress) const override
1430     {
1431         if ((a->*m_paintTypeGetter)() != SVGPaintType::RGBColor
1432             || (b->*m_paintTypeGetter)() != SVGPaintType::RGBColor)
1433             return;
1434
1435         Color fromColor = (a->*m_getter)();
1436         Color toColor = (b->*m_getter)();
1437
1438         if (!fromColor.isValid() && !toColor.isValid())
1439             return;
1440
1441         if (!fromColor.isValid())
1442             fromColor = Color();
1443         if (!toColor.isValid())
1444             toColor = Color();
1445         (dst->*m_setter)(blendFunc(anim, fromColor, toColor, progress));
1446     }
1447
1448 #if !LOG_DISABLED
1449     void logBlend(const RenderStyle*, const RenderStyle*, const RenderStyle*, double progress) const final
1450     {
1451         // FIXME: better logging.
1452         LOG_WITH_STREAM(Animations, stream << "  blending SVGPaint at " << TextStream::FormatNumberRespectingIntegers(progress));
1453     }
1454 #endif
1455
1456 private:
1457     SVGPaintType (RenderStyle::*m_paintTypeGetter)() const;
1458     Color (RenderStyle::*m_getter)() const;
1459     void (RenderStyle::*m_setter)(const Color&);
1460 };
1461
1462 class PropertyWrapperFontStyle : public PropertyWrapper<Optional<FontSelectionValue>> {
1463     WTF_MAKE_FAST_ALLOCATED;
1464 public:
1465     PropertyWrapperFontStyle()
1466         : PropertyWrapper<Optional<FontSelectionValue>>(CSSPropertyFontStyle, &RenderStyle::fontItalic, &RenderStyle::setFontItalic)
1467     {
1468     }
1469
1470     bool canInterpolate(const RenderStyle* from, const RenderStyle* to) const override
1471     {
1472         return from->fontItalic() && to->fontItalic() && from->fontDescription().fontStyleAxis() == FontStyleAxis::slnt && to->fontDescription().fontStyleAxis() == FontStyleAxis::slnt;
1473     }
1474
1475     void blend(const CSSPropertyBlendingClient* anim, RenderStyle* dst, const RenderStyle* from, const RenderStyle* to, double progress) const override
1476     {
1477         auto discrete = !canInterpolate(from, to);
1478
1479         auto blendedStyleAxis = FontStyleAxis::slnt;
1480         if (discrete)
1481             blendedStyleAxis = (progress < 0.5 ? from : to)->fontDescription().fontStyleAxis();
1482
1483         auto fromFontItalic = from->fontItalic();
1484         auto toFontItalic = to->fontItalic();
1485         auto blendedFontItalic = progress < 0.5 ? fromFontItalic : toFontItalic;
1486         if (!discrete)
1487             blendedFontItalic = blendFunc(anim, fromFontItalic, toFontItalic, progress);
1488
1489         FontSelector* currentFontSelector = dst->fontCascade().fontSelector();
1490         auto description = dst->fontDescription();
1491         description.setItalic(blendedFontItalic);
1492         description.setFontStyleAxis(blendedStyleAxis);
1493         dst->setFontDescription(WTFMove(description));
1494         dst->fontCascade().update(currentFontSelector);
1495     }
1496 };
1497
1498 class CSSPropertyAnimationWrapperMap {
1499     WTF_MAKE_FAST_ALLOCATED;
1500 public:
1501     static CSSPropertyAnimationWrapperMap& singleton()
1502     {
1503         // FIXME: This data is never destroyed. Maybe we should ref count it and toss it when the last CSSAnimationController is destroyed?
1504         static NeverDestroyed<CSSPropertyAnimationWrapperMap> map;
1505         return map;
1506     }
1507
1508     AnimationPropertyWrapperBase* wrapperForProperty(CSSPropertyID propertyID)
1509     {
1510         if (propertyID < firstCSSProperty || propertyID > lastCSSProperty)
1511             return nullptr;
1512
1513         unsigned wrapperIndex = indexFromPropertyID(propertyID);
1514         if (wrapperIndex == cInvalidPropertyWrapperIndex)
1515             return nullptr;
1516
1517         return m_propertyWrappers[wrapperIndex].get();
1518     }
1519
1520     AnimationPropertyWrapperBase* wrapperForIndex(unsigned index)
1521     {
1522         ASSERT(index < m_propertyWrappers.size());
1523         return m_propertyWrappers[index].get();
1524     }
1525
1526     unsigned size()
1527     {
1528         return m_propertyWrappers.size();
1529     }
1530
1531 private:
1532     CSSPropertyAnimationWrapperMap();
1533     ~CSSPropertyAnimationWrapperMap() = delete;
1534
1535     unsigned char& indexFromPropertyID(CSSPropertyID propertyID)
1536     {
1537         return m_propertyToIdMap[propertyID - firstCSSProperty];
1538     }
1539
1540     Vector<std::unique_ptr<AnimationPropertyWrapperBase>> m_propertyWrappers;
1541     unsigned char m_propertyToIdMap[numCSSProperties];
1542
1543     static const unsigned char cInvalidPropertyWrapperIndex = UCHAR_MAX;
1544
1545     friend class WTF::NeverDestroyed<CSSPropertyAnimationWrapperMap>;
1546 };
1547
1548 CSSPropertyAnimationWrapperMap::CSSPropertyAnimationWrapperMap()
1549 {
1550     // build the list of property wrappers to do the comparisons and blends
1551     AnimationPropertyWrapperBase* animatableLonghandPropertyWrappers[] = {
1552         new LengthPropertyWrapper(CSSPropertyLeft, &RenderStyle::left, &RenderStyle::setLeft),
1553         new LengthPropertyWrapper(CSSPropertyRight, &RenderStyle::right, &RenderStyle::setRight),
1554         new LengthPropertyWrapper(CSSPropertyTop, &RenderStyle::top, &RenderStyle::setTop),
1555         new LengthPropertyWrapper(CSSPropertyBottom, &RenderStyle::bottom, &RenderStyle::setBottom),
1556
1557         new LengthPropertyWrapper(CSSPropertyWidth, &RenderStyle::width, &RenderStyle::setWidth),
1558         new LengthPropertyWrapper(CSSPropertyMinWidth, &RenderStyle::minWidth, &RenderStyle::setMinWidth),
1559         new LengthPropertyWrapper(CSSPropertyMaxWidth, &RenderStyle::maxWidth, &RenderStyle::setMaxWidth),
1560
1561         new LengthPropertyWrapper(CSSPropertyHeight, &RenderStyle::height, &RenderStyle::setHeight),
1562         new LengthPropertyWrapper(CSSPropertyMinHeight, &RenderStyle::minHeight, &RenderStyle::setMinHeight),
1563         new LengthPropertyWrapper(CSSPropertyMaxHeight, &RenderStyle::maxHeight, &RenderStyle::setMaxHeight),
1564
1565         new PropertyWrapperFlex(),
1566
1567         new PropertyWrapper<float>(CSSPropertyBorderLeftWidth, &RenderStyle::borderLeftWidth, &RenderStyle::setBorderLeftWidth),
1568         new PropertyWrapper<float>(CSSPropertyBorderRightWidth, &RenderStyle::borderRightWidth, &RenderStyle::setBorderRightWidth),
1569         new PropertyWrapper<float>(CSSPropertyBorderTopWidth, &RenderStyle::borderTopWidth, &RenderStyle::setBorderTopWidth),
1570         new PropertyWrapper<float>(CSSPropertyBorderBottomWidth, &RenderStyle::borderBottomWidth, &RenderStyle::setBorderBottomWidth),
1571         new LengthPropertyWrapper(CSSPropertyMarginLeft, &RenderStyle::marginLeft, &RenderStyle::setMarginLeft),
1572         new LengthPropertyWrapper(CSSPropertyMarginRight, &RenderStyle::marginRight, &RenderStyle::setMarginRight),
1573         new LengthPropertyWrapper(CSSPropertyMarginTop, &RenderStyle::marginTop, &RenderStyle::setMarginTop),
1574         new LengthPropertyWrapper(CSSPropertyMarginBottom, &RenderStyle::marginBottom, &RenderStyle::setMarginBottom),
1575         new LengthPropertyWrapper(CSSPropertyPaddingLeft, &RenderStyle::paddingLeft, &RenderStyle::setPaddingLeft),
1576         new LengthPropertyWrapper(CSSPropertyPaddingRight, &RenderStyle::paddingRight, &RenderStyle::setPaddingRight),
1577         new LengthPropertyWrapper(CSSPropertyPaddingTop, &RenderStyle::paddingTop, &RenderStyle::setPaddingTop),
1578         new LengthPropertyWrapper(CSSPropertyPaddingBottom, &RenderStyle::paddingBottom, &RenderStyle::setPaddingBottom),
1579
1580         new PropertyWrapperVisitedAffectedColor(CSSPropertyCaretColor, &RenderStyle::caretColor, &RenderStyle::setCaretColor, &RenderStyle::visitedLinkCaretColor, &RenderStyle::setVisitedLinkCaretColor),
1581
1582         new PropertyWrapperVisitedAffectedColor(CSSPropertyColor, &RenderStyle::color, &RenderStyle::setColor, &RenderStyle::visitedLinkColor, &RenderStyle::setVisitedLinkColor),
1583
1584         new PropertyWrapperVisitedAffectedColor(CSSPropertyBackgroundColor, &RenderStyle::backgroundColor, &RenderStyle::setBackgroundColor, &RenderStyle::visitedLinkBackgroundColor, &RenderStyle::setVisitedLinkBackgroundColor),
1585
1586         new FillLayersPropertyWrapper(CSSPropertyBackgroundImage, &RenderStyle::backgroundLayers, &RenderStyle::ensureBackgroundLayers),
1587         new StyleImagePropertyWrapper(CSSPropertyListStyleImage, &RenderStyle::listStyleImage, &RenderStyle::setListStyleImage),
1588         new StyleImagePropertyWrapper(CSSPropertyWebkitMaskImage, &RenderStyle::maskImage, &RenderStyle::setMaskImage),
1589
1590         new StyleImagePropertyWrapper(CSSPropertyBorderImageSource, &RenderStyle::borderImageSource, &RenderStyle::setBorderImageSource),
1591         new LengthVariantPropertyWrapper<LengthBox>(CSSPropertyBorderImageSlice, &RenderStyle::borderImageSlices, &RenderStyle::setBorderImageSlices),
1592         new LengthVariantPropertyWrapper<LengthBox>(CSSPropertyBorderImageWidth, &RenderStyle::borderImageWidth, &RenderStyle::setBorderImageWidth),
1593         new LengthVariantPropertyWrapper<LengthBox>(CSSPropertyBorderImageOutset, &RenderStyle::borderImageOutset, &RenderStyle::setBorderImageOutset),
1594
1595         new StyleImagePropertyWrapper(CSSPropertyWebkitMaskBoxImageSource, &RenderStyle::maskBoxImageSource, &RenderStyle::setMaskBoxImageSource),
1596         new PropertyWrapper<const NinePieceImage&>(CSSPropertyWebkitMaskBoxImage, &RenderStyle::maskBoxImage, &RenderStyle::setMaskBoxImage),
1597
1598         new FillLayersPropertyWrapper(CSSPropertyBackgroundPositionX, &RenderStyle::backgroundLayers, &RenderStyle::ensureBackgroundLayers),
1599         new FillLayersPropertyWrapper(CSSPropertyBackgroundPositionY, &RenderStyle::backgroundLayers, &RenderStyle::ensureBackgroundLayers),
1600         new FillLayersPropertyWrapper(CSSPropertyBackgroundSize, &RenderStyle::backgroundLayers, &RenderStyle::ensureBackgroundLayers),
1601         new FillLayersPropertyWrapper(CSSPropertyWebkitBackgroundSize, &RenderStyle::backgroundLayers, &RenderStyle::ensureBackgroundLayers),
1602
1603         new FillLayersPropertyWrapper(CSSPropertyWebkitMaskPositionX, &RenderStyle::maskLayers, &RenderStyle::ensureMaskLayers),
1604         new FillLayersPropertyWrapper(CSSPropertyWebkitMaskPositionY, &RenderStyle::maskLayers, &RenderStyle::ensureMaskLayers),
1605         new FillLayersPropertyWrapper(CSSPropertyWebkitMaskSize, &RenderStyle::maskLayers, &RenderStyle::ensureMaskLayers),
1606
1607         new PropertyWrapper<float>(CSSPropertyFontSize, &RenderStyle::computedFontSize, &RenderStyle::setFontSize),
1608         new PropertyWrapper<unsigned short>(CSSPropertyColumnRuleWidth, &RenderStyle::columnRuleWidth, &RenderStyle::setColumnRuleWidth),
1609         new LengthVariantPropertyWrapper<GapLength>(CSSPropertyColumnGap, &RenderStyle::columnGap, &RenderStyle::setColumnGap),
1610         new LengthVariantPropertyWrapper<GapLength>(CSSPropertyRowGap, &RenderStyle::rowGap, &RenderStyle::setRowGap),
1611         new PropertyWrapper<unsigned short>(CSSPropertyColumnCount, &RenderStyle::columnCount, &RenderStyle::setColumnCount),
1612         new PropertyWrapper<float>(CSSPropertyColumnWidth, &RenderStyle::columnWidth, &RenderStyle::setColumnWidth),
1613         new PropertyWrapper<float>(CSSPropertyWebkitBorderHorizontalSpacing, &RenderStyle::horizontalBorderSpacing, &RenderStyle::setHorizontalBorderSpacing),
1614         new PropertyWrapper<float>(CSSPropertyWebkitBorderVerticalSpacing, &RenderStyle::verticalBorderSpacing, &RenderStyle::setVerticalBorderSpacing),
1615         new PropertyWrapper<int>(CSSPropertyZIndex, &RenderStyle::zIndex, &RenderStyle::setZIndex),
1616         new PropertyWrapper<short>(CSSPropertyOrphans, &RenderStyle::orphans, &RenderStyle::setOrphans),
1617         new PropertyWrapper<short>(CSSPropertyWidows, &RenderStyle::widows, &RenderStyle::setWidows),
1618         new LengthPropertyWrapper(CSSPropertyLineHeight, &RenderStyle::specifiedLineHeight, &RenderStyle::setLineHeight),
1619         new PropertyWrapper<float>(CSSPropertyOutlineOffset, &RenderStyle::outlineOffset, &RenderStyle::setOutlineOffset),
1620         new PropertyWrapper<float>(CSSPropertyOutlineWidth, &RenderStyle::outlineWidth, &RenderStyle::setOutlineWidth),
1621         new PropertyWrapper<float>(CSSPropertyLetterSpacing, &RenderStyle::letterSpacing, &RenderStyle::setLetterSpacing),
1622         new LengthPropertyWrapper(CSSPropertyWordSpacing, &RenderStyle::wordSpacing, &RenderStyle::setWordSpacing),
1623         new LengthPropertyWrapper(CSSPropertyTextIndent, &RenderStyle::textIndent, &RenderStyle::setTextIndent),
1624
1625         new PropertyWrapper<float>(CSSPropertyPerspective, &RenderStyle::perspective, &RenderStyle::setPerspective),
1626         new LengthPropertyWrapper(CSSPropertyPerspectiveOriginX, &RenderStyle::perspectiveOriginX, &RenderStyle::setPerspectiveOriginX),
1627         new LengthPropertyWrapper(CSSPropertyPerspectiveOriginY, &RenderStyle::perspectiveOriginY, &RenderStyle::setPerspectiveOriginY),
1628         new LengthPropertyWrapper(CSSPropertyTransformOriginX, &RenderStyle::transformOriginX, &RenderStyle::setTransformOriginX),
1629         new LengthPropertyWrapper(CSSPropertyTransformOriginY, &RenderStyle::transformOriginY, &RenderStyle::setTransformOriginY),
1630         new PropertyWrapper<float>(CSSPropertyTransformOriginZ, &RenderStyle::transformOriginZ, &RenderStyle::setTransformOriginZ),
1631         new LengthVariantPropertyWrapper<LengthSize>(CSSPropertyBorderTopLeftRadius, &RenderStyle::borderTopLeftRadius, &RenderStyle::setBorderTopLeftRadius),
1632         new LengthVariantPropertyWrapper<LengthSize>(CSSPropertyBorderTopRightRadius, &RenderStyle::borderTopRightRadius, &RenderStyle::setBorderTopRightRadius),
1633         new LengthVariantPropertyWrapper<LengthSize>(CSSPropertyBorderBottomLeftRadius, &RenderStyle::borderBottomLeftRadius, &RenderStyle::setBorderBottomLeftRadius),
1634         new LengthVariantPropertyWrapper<LengthSize>(CSSPropertyBorderBottomRightRadius, &RenderStyle::borderBottomRightRadius, &RenderStyle::setBorderBottomRightRadius),
1635         new PropertyWrapper<Visibility>(CSSPropertyVisibility, &RenderStyle::visibility, &RenderStyle::setVisibility),
1636         new PropertyWrapper<float>(CSSPropertyZoom, &RenderStyle::zoom, &RenderStyle::setZoomWithoutReturnValue),
1637
1638         new LengthVariantPropertyWrapper<LengthBox>(CSSPropertyClip, &RenderStyle::clip, &RenderStyle::setClip),
1639
1640         new PropertyWrapperAcceleratedOpacity(),
1641         new PropertyWrapperAcceleratedTransform(),
1642         
1643         new PropertyWrapperFilter(CSSPropertyFilter, &RenderStyle::filter, &RenderStyle::setFilter),
1644 #if ENABLE(FILTERS_LEVEL_2)
1645         new PropertyWrapperFilter(CSSPropertyWebkitBackdropFilter, &RenderStyle::backdropFilter, &RenderStyle::setBackdropFilter),
1646 #endif
1647         new PropertyWrapperFilter(CSSPropertyAppleColorFilter, &RenderStyle::appleColorFilter, &RenderStyle::setAppleColorFilter),
1648
1649         new PropertyWrapperClipPath(CSSPropertyWebkitClipPath, &RenderStyle::clipPath, &RenderStyle::setClipPath),
1650
1651         new PropertyWrapperShape(CSSPropertyShapeOutside, &RenderStyle::shapeOutside, &RenderStyle::setShapeOutside),
1652         new LengthPropertyWrapper(CSSPropertyShapeMargin, &RenderStyle::shapeMargin, &RenderStyle::setShapeMargin),
1653         new PropertyWrapper<float>(CSSPropertyShapeImageThreshold, &RenderStyle::shapeImageThreshold, &RenderStyle::setShapeImageThreshold),
1654
1655         new PropertyWrapperVisitedAffectedColor(CSSPropertyColumnRuleColor, MaybeInvalidColor, &RenderStyle::columnRuleColor, &RenderStyle::setColumnRuleColor, &RenderStyle::visitedLinkColumnRuleColor, &RenderStyle::setVisitedLinkColumnRuleColor),
1656         new PropertyWrapperVisitedAffectedColor(CSSPropertyWebkitTextStrokeColor, MaybeInvalidColor, &RenderStyle::textStrokeColor, &RenderStyle::setTextStrokeColor, &RenderStyle::visitedLinkTextStrokeColor, &RenderStyle::setVisitedLinkTextStrokeColor),
1657         new PropertyWrapperVisitedAffectedColor(CSSPropertyWebkitTextFillColor, MaybeInvalidColor, &RenderStyle::textFillColor, &RenderStyle::setTextFillColor, &RenderStyle::visitedLinkTextFillColor, &RenderStyle::setVisitedLinkTextFillColor),
1658         new PropertyWrapperVisitedAffectedColor(CSSPropertyBorderLeftColor, MaybeInvalidColor, &RenderStyle::borderLeftColor, &RenderStyle::setBorderLeftColor, &RenderStyle::visitedLinkBorderLeftColor, &RenderStyle::setVisitedLinkBorderLeftColor),
1659         new PropertyWrapperVisitedAffectedColor(CSSPropertyBorderRightColor, MaybeInvalidColor, &RenderStyle::borderRightColor, &RenderStyle::setBorderRightColor, &RenderStyle::visitedLinkBorderRightColor, &RenderStyle::setVisitedLinkBorderRightColor),
1660         new PropertyWrapperVisitedAffectedColor(CSSPropertyBorderTopColor, MaybeInvalidColor, &RenderStyle::borderTopColor, &RenderStyle::setBorderTopColor, &RenderStyle::visitedLinkBorderTopColor, &RenderStyle::setVisitedLinkBorderTopColor),
1661         new PropertyWrapperVisitedAffectedColor(CSSPropertyBorderBottomColor, MaybeInvalidColor, &RenderStyle::borderBottomColor, &RenderStyle::setBorderBottomColor, &RenderStyle::visitedLinkBorderBottomColor, &RenderStyle::setVisitedLinkBorderBottomColor),
1662         new PropertyWrapperVisitedAffectedColor(CSSPropertyOutlineColor, MaybeInvalidColor, &RenderStyle::outlineColor, &RenderStyle::setOutlineColor, &RenderStyle::visitedLinkOutlineColor, &RenderStyle::setVisitedLinkOutlineColor),
1663
1664         new PropertyWrapperShadow(CSSPropertyBoxShadow, &RenderStyle::boxShadow, &RenderStyle::setBoxShadow),
1665         new PropertyWrapperShadow(CSSPropertyWebkitBoxShadow, &RenderStyle::boxShadow, &RenderStyle::setBoxShadow),
1666         new PropertyWrapperShadow(CSSPropertyTextShadow, &RenderStyle::textShadow, &RenderStyle::setTextShadow),
1667
1668         new PropertyWrapperSVGPaint(CSSPropertyFill, &RenderStyle::fillPaintType, &RenderStyle::fillPaintColor, &RenderStyle::setFillPaintColor),
1669         new PropertyWrapper<float>(CSSPropertyFillOpacity, &RenderStyle::fillOpacity, &RenderStyle::setFillOpacity),
1670
1671         new PropertyWrapperSVGPaint(CSSPropertyStroke, &RenderStyle::strokePaintType, &RenderStyle::strokePaintColor, &RenderStyle::setStrokePaintColor),
1672         new PropertyWrapper<float>(CSSPropertyStrokeOpacity, &RenderStyle::strokeOpacity, &RenderStyle::setStrokeOpacity),
1673         new PropertyWrapper<Vector<SVGLengthValue>>(CSSPropertyStrokeDasharray, &RenderStyle::strokeDashArray, &RenderStyle::setStrokeDashArray),
1674         new PropertyWrapper<float>(CSSPropertyStrokeMiterlimit, &RenderStyle::strokeMiterLimit, &RenderStyle::setStrokeMiterLimit),
1675
1676         new LengthPropertyWrapper(CSSPropertyCx, &RenderStyle::cx, &RenderStyle::setCx),
1677         new LengthPropertyWrapper(CSSPropertyCy, &RenderStyle::cy, &RenderStyle::setCy),
1678         new LengthPropertyWrapper(CSSPropertyR, &RenderStyle::r, &RenderStyle::setR),
1679         new LengthPropertyWrapper(CSSPropertyRx, &RenderStyle::rx, &RenderStyle::setRx),
1680         new LengthPropertyWrapper(CSSPropertyRy, &RenderStyle::ry, &RenderStyle::setRy),
1681         new LengthPropertyWrapper(CSSPropertyStrokeDashoffset, &RenderStyle::strokeDashOffset, &RenderStyle::setStrokeDashOffset),
1682         new LengthPropertyWrapper(CSSPropertyStrokeWidth, &RenderStyle::strokeWidth, &RenderStyle::setStrokeWidth),
1683         new LengthPropertyWrapper(CSSPropertyX, &RenderStyle::x, &RenderStyle::setX),
1684         new LengthPropertyWrapper(CSSPropertyY, &RenderStyle::y, &RenderStyle::setY),
1685
1686         new PropertyWrapper<float>(CSSPropertyFloodOpacity, &RenderStyle::floodOpacity, &RenderStyle::setFloodOpacity),
1687         new PropertyWrapperMaybeInvalidColor(CSSPropertyFloodColor, &RenderStyle::floodColor, &RenderStyle::setFloodColor),
1688
1689         new PropertyWrapper<float>(CSSPropertyStopOpacity, &RenderStyle::stopOpacity, &RenderStyle::setStopOpacity),
1690         new PropertyWrapperMaybeInvalidColor(CSSPropertyStopColor, &RenderStyle::stopColor, &RenderStyle::setStopColor),
1691
1692         new PropertyWrapperMaybeInvalidColor(CSSPropertyLightingColor, &RenderStyle::lightingColor, &RenderStyle::setLightingColor),
1693
1694         new PropertyWrapper<SVGLengthValue>(CSSPropertyBaselineShift, &RenderStyle::baselineShiftValue, &RenderStyle::setBaselineShiftValue),
1695         new PropertyWrapper<SVGLengthValue>(CSSPropertyKerning, &RenderStyle::kerning, &RenderStyle::setKerning),
1696 #if ENABLE(VARIATION_FONTS)
1697         new PropertyWrapperFontVariationSettings(CSSPropertyFontVariationSettings, &RenderStyle::fontVariationSettings, &RenderStyle::setFontVariationSettings),
1698 #endif
1699         new PropertyWrapper<FontSelectionValue>(CSSPropertyFontWeight, &RenderStyle::fontWeight, &RenderStyle::setFontWeight),
1700         new PropertyWrapper<FontSelectionValue>(CSSPropertyFontStretch, &RenderStyle::fontStretch, &RenderStyle::setFontStretch),
1701         new PropertyWrapperFontStyle(),
1702         new PropertyWrapper<TextDecorationThickness>(CSSPropertyTextDecorationThickness, &RenderStyle::textDecorationThickness, &RenderStyle::setTextDecorationThickness),
1703         new PropertyWrapper<TextUnderlineOffset>(CSSPropertyTextUnderlineOffset, &RenderStyle::textUnderlineOffset, &RenderStyle::setTextUnderlineOffset),
1704     };
1705     const unsigned animatableLonghandPropertiesCount = WTF_ARRAY_LENGTH(animatableLonghandPropertyWrappers);
1706
1707     static const CSSPropertyID animatableShorthandProperties[] = {
1708         CSSPropertyBackground, // for background-color, background-position, background-image
1709         CSSPropertyBackgroundPosition,
1710         CSSPropertyFont, // for font-size, font-weight
1711         CSSPropertyWebkitMask, // for mask-position
1712         CSSPropertyWebkitMaskPosition,
1713         CSSPropertyBorderTop, CSSPropertyBorderRight, CSSPropertyBorderBottom, CSSPropertyBorderLeft,
1714         CSSPropertyBorderColor,
1715         CSSPropertyBorderRadius,
1716         CSSPropertyBorderWidth,
1717         CSSPropertyBorder,
1718         CSSPropertyBorderImage,
1719         CSSPropertyBorderSpacing,
1720         CSSPropertyListStyle, // for list-style-image
1721         CSSPropertyMargin,
1722         CSSPropertyOutline,
1723         CSSPropertyPadding,
1724         CSSPropertyWebkitTextStroke,
1725         CSSPropertyColumnRule,
1726         CSSPropertyWebkitBorderRadius,
1727         CSSPropertyTransformOrigin
1728     };
1729     const unsigned animatableShorthandPropertiesCount = WTF_ARRAY_LENGTH(animatableShorthandProperties);
1730
1731     // TODO:
1732     //
1733     //  CSSPropertyVerticalAlign
1734     //
1735     // Compound properties that have components that should be animatable:
1736     //
1737     //  CSSPropertyColumns
1738     //  CSSPropertyWebkitBoxReflect
1739
1740     // Make sure unused slots have a value
1741     for (int i = 0; i < numCSSProperties; ++i)
1742         m_propertyToIdMap[i] = cInvalidPropertyWrapperIndex;
1743
1744     COMPILE_ASSERT(animatableLonghandPropertiesCount + animatableShorthandPropertiesCount < UCHAR_MAX, numberOfAnimatablePropertiesMustBeLessThanUCharMax);
1745     m_propertyWrappers.reserveInitialCapacity(animatableLonghandPropertiesCount + animatableShorthandPropertiesCount);
1746
1747     // First we put the non-shorthand property wrappers into the map, so the shorthand-building
1748     // code can find them.
1749
1750     for (unsigned i = 0; i < animatableLonghandPropertiesCount; ++i) {
1751         AnimationPropertyWrapperBase* wrapper = animatableLonghandPropertyWrappers[i];
1752         m_propertyWrappers.uncheckedAppend(std::unique_ptr<AnimationPropertyWrapperBase>(wrapper));
1753         indexFromPropertyID(wrapper->property()) = i;
1754     }
1755
1756     for (size_t i = 0; i < animatableShorthandPropertiesCount; ++i) {
1757         CSSPropertyID propertyID = animatableShorthandProperties[i];
1758         StylePropertyShorthand shorthand = shorthandForProperty(propertyID);
1759         if (!shorthand.length())
1760             continue;
1761
1762         Vector<AnimationPropertyWrapperBase*> longhandWrappers;
1763         longhandWrappers.reserveInitialCapacity(shorthand.length());
1764         const CSSPropertyID* properties = shorthand.properties();
1765         for (unsigned j = 0; j < shorthand.length(); ++j) {
1766             unsigned wrapperIndex = indexFromPropertyID(properties[j]);
1767             if (wrapperIndex == cInvalidPropertyWrapperIndex)
1768                 continue;
1769             ASSERT(m_propertyWrappers[wrapperIndex]);
1770             longhandWrappers.uncheckedAppend(m_propertyWrappers[wrapperIndex].get());
1771         }
1772
1773         m_propertyWrappers.uncheckedAppend(makeUnique<ShorthandPropertyWrapper>(propertyID, WTFMove(longhandWrappers)));
1774         indexFromPropertyID(propertyID) = animatableLonghandPropertiesCount + i;
1775     }
1776 }
1777
1778 static bool gatherEnclosingShorthandProperties(CSSPropertyID property, AnimationPropertyWrapperBase* wrapper, HashSet<CSSPropertyID>& propertySet)
1779 {
1780     if (!wrapper->isShorthandWrapper())
1781         return false;
1782
1783     ShorthandPropertyWrapper* shorthandWrapper = static_cast<ShorthandPropertyWrapper*>(wrapper);
1784     bool contained = false;
1785     for (auto& currWrapper : shorthandWrapper->propertyWrappers()) {
1786         if (gatherEnclosingShorthandProperties(property, currWrapper, propertySet) || currWrapper->property() == property)
1787             contained = true;
1788     }
1789
1790     if (contained)
1791         propertySet.add(wrapper->property());
1792
1793     return contained;
1794 }
1795
1796 // Returns true if we need to start animation timers
1797 bool CSSPropertyAnimation::blendProperties(const CSSPropertyBlendingClient* anim, CSSPropertyID prop, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress)
1798 {
1799     ASSERT(prop != CSSPropertyInvalid);
1800
1801     AnimationPropertyWrapperBase* wrapper = CSSPropertyAnimationWrapperMap::singleton().wrapperForProperty(prop);
1802     if (wrapper) {
1803         wrapper->blend(anim, dst, a, b, progress);
1804 #if !LOG_DISABLED
1805         wrapper->logBlend(a, b, dst, progress);
1806 #endif
1807         return !wrapper->animationIsAccelerated() || !anim->isAccelerated();
1808     }
1809     return false;
1810 }
1811
1812 bool CSSPropertyAnimation::isPropertyAnimatable(CSSPropertyID prop)
1813 {
1814     return CSSPropertyAnimationWrapperMap::singleton().wrapperForProperty(prop);
1815 }
1816
1817 bool CSSPropertyAnimation::animationOfPropertyIsAccelerated(CSSPropertyID prop)
1818 {
1819     AnimationPropertyWrapperBase* wrapper = CSSPropertyAnimationWrapperMap::singleton().wrapperForProperty(prop);
1820     return wrapper ? wrapper->animationIsAccelerated() : false;
1821 }
1822
1823 // Note: this is inefficient. It's only called from pauseTransitionAtTime().
1824 HashSet<CSSPropertyID> CSSPropertyAnimation::animatableShorthandsAffectingProperty(CSSPropertyID property)
1825 {
1826     CSSPropertyAnimationWrapperMap& map = CSSPropertyAnimationWrapperMap::singleton();
1827
1828     HashSet<CSSPropertyID> foundProperties;
1829     for (unsigned i = 0; i < map.size(); ++i)
1830         gatherEnclosingShorthandProperties(property, map.wrapperForIndex(i), foundProperties);
1831
1832     return foundProperties;
1833 }
1834
1835 bool CSSPropertyAnimation::propertiesEqual(CSSPropertyID prop, const RenderStyle* a, const RenderStyle* b)
1836 {
1837     AnimationPropertyWrapperBase* wrapper = CSSPropertyAnimationWrapperMap::singleton().wrapperForProperty(prop);
1838     if (wrapper)
1839         return wrapper->equals(a, b);
1840     return true;
1841 }
1842
1843 bool CSSPropertyAnimation::canPropertyBeInterpolated(CSSPropertyID prop, const RenderStyle* a, const RenderStyle* b)
1844 {
1845     AnimationPropertyWrapperBase* wrapper = CSSPropertyAnimationWrapperMap::singleton().wrapperForProperty(prop);
1846     if (wrapper)
1847         return wrapper->canInterpolate(a, b);
1848     return false;
1849 }
1850
1851 CSSPropertyID CSSPropertyAnimation::getPropertyAtIndex(int i, Optional<bool>& isShorthand)
1852 {
1853     CSSPropertyAnimationWrapperMap& map = CSSPropertyAnimationWrapperMap::singleton();
1854
1855     if (i < 0 || static_cast<unsigned>(i) >= map.size())
1856         return CSSPropertyInvalid;
1857
1858     AnimationPropertyWrapperBase* wrapper = map.wrapperForIndex(i);
1859     isShorthand = wrapper->isShorthandWrapper();
1860     return wrapper->property();
1861 }
1862
1863 int CSSPropertyAnimation::getNumProperties()
1864 {
1865     return CSSPropertyAnimationWrapperMap::singleton().size();
1866 }
1867
1868 }