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