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