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