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