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