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