1/* 2 * Copyright (C) 2007, 2008, 2009, 2013 Apple Inc. All rights reserved. 3 * Copyright (C) 2012, 2013 Adobe Systems Incorporated. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. Neither the name of Apple Inc. ("Apple") nor the names of 15 * its contributors may be used to endorse or promote products derived 16 * from this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY 19 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY 22 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 23 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 24 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 25 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 */ 29 30#include "config.h" 31#include "CSSPropertyAnimation.h" 32 33#include "AnimationBase.h" 34#include "CSSComputedStyleDeclaration.h" 35#include "CSSCrossfadeValue.h" 36#include "CSSFilterImageValue.h" 37#include "CSSImageGeneratorValue.h" 38#include "CSSImageValue.h" 39#include "CSSPrimitiveValue.h" 40#include "CSSPropertyNames.h" 41#include "CachedImage.h" 42#include "ClipPathOperation.h" 43#include "FloatConversion.h" 44#include "IdentityTransformOperation.h" 45#include "Matrix3DTransformOperation.h" 46#include "MatrixTransformOperation.h" 47#include "RenderBox.h" 48#include "RenderStyle.h" 49#include "StyleCachedImage.h" 50#include "StyleGeneratedImage.h" 51#include "StylePropertyShorthand.h" 52#include "StyleResolver.h" 53#include <algorithm> 54#include <memory> 55#include <wtf/MathExtras.h> 56#include <wtf/Noncopyable.h> 57#include <wtf/RefCounted.h> 58 59namespace WebCore { 60 61static inline int blendFunc(const AnimationBase*, int from, int to, double progress) 62{ 63 return blend(from, to, progress); 64} 65 66static inline double blendFunc(const AnimationBase*, double from, double to, double progress) 67{ 68 return blend(from, to, progress); 69} 70 71static inline float blendFunc(const AnimationBase*, float from, float to, double progress) 72{ 73 return narrowPrecisionToFloat(from + (to - from) * progress); 74} 75 76static inline Color blendFunc(const AnimationBase*, const Color& from, const Color& to, double progress) 77{ 78 return blend(from, to, progress); 79} 80 81static inline Length blendFunc(const AnimationBase*, const Length& from, const Length& to, double progress) 82{ 83 return to.blend(from, narrowPrecisionToFloat(progress)); 84} 85 86static inline LengthSize blendFunc(const AnimationBase* anim, const LengthSize& from, const LengthSize& to, double progress) 87{ 88 return LengthSize(blendFunc(anim, from.width(), to.width(), progress), 89 blendFunc(anim, from.height(), to.height(), progress)); 90} 91 92static inline ShadowStyle blendFunc(const AnimationBase* anim, ShadowStyle from, ShadowStyle to, double progress) 93{ 94 if (from == to) 95 return to; 96 97 double fromVal = from == Normal ? 1 : 0; 98 double toVal = to == Normal ? 1 : 0; 99 double result = blendFunc(anim, fromVal, toVal, progress); 100 return result > 0 ? Normal : Inset; 101} 102 103static inline std::unique_ptr<ShadowData> blendFunc(const AnimationBase* anim, const ShadowData* from, const ShadowData* to, double progress) 104{ 105 ASSERT(from && to); 106 if (from->style() != to->style()) 107 return std::make_unique<ShadowData>(*to); 108 109 return std::make_unique<ShadowData>(blend(from->location(), to->location(), progress), 110 blend(from->radius(), to->radius(), progress), 111 blend(from->spread(), to->spread(), progress), 112 blendFunc(anim, from->style(), to->style(), progress), 113 from->isWebkitBoxShadow(), 114 blend(from->color(), to->color(), progress)); 115} 116 117static inline TransformOperations blendFunc(const AnimationBase* anim, const TransformOperations& from, const TransformOperations& to, double progress) 118{ 119 if (anim->isTransformFunctionListValid()) 120 return to.blendByMatchingOperations(from, progress); 121 return to.blendByUsingMatrixInterpolation(from, progress, anim->renderer()->isBox() ? toRenderBox(anim->renderer())->borderBoxRect().size() : LayoutSize()); 122} 123 124static inline PassRefPtr<ClipPathOperation> blendFunc(const AnimationBase*, ClipPathOperation* from, ClipPathOperation* to, double progress) 125{ 126 if (!from || !to) 127 return to; 128 129 // Other clip-path operations than BasicShapes can not be animated. 130 if (from->type() != ClipPathOperation::Shape || to->type() != ClipPathOperation::Shape) 131 return to; 132 133 const BasicShape* fromShape = static_cast<ShapeClipPathOperation*>(from)->basicShape(); 134 const BasicShape* toShape = static_cast<ShapeClipPathOperation*>(to)->basicShape(); 135 136 if (!fromShape->canBlend(toShape)) 137 return to; 138 139 return ShapeClipPathOperation::create(toShape->blend(fromShape, progress)); 140} 141 142#if ENABLE(CSS_SHAPES) 143static inline PassRefPtr<ShapeValue> blendFunc(const AnimationBase*, ShapeValue* from, ShapeValue* to, double progress) 144{ 145 if (!from || !to) 146 return to; 147 148 if (from->type() != ShapeValue::Type::Shape || to->type() != ShapeValue::Type::Shape) 149 return to; 150 151 if (from->cssBox() != to->cssBox()) 152 return to; 153 154 const BasicShape* fromShape = from->shape(); 155 const BasicShape* toShape = to->shape(); 156 157 if (!fromShape->canBlend(toShape)) 158 return to; 159 160 return ShapeValue::createShapeValue(toShape->blend(fromShape, progress), to->cssBox()); 161} 162#endif 163 164#if ENABLE(CSS_FILTERS) 165static inline PassRefPtr<FilterOperation> blendFunc(const AnimationBase* anim, FilterOperation* fromOp, FilterOperation* toOp, double progress, bool blendToPassthrough = false) 166{ 167 ASSERT(toOp); 168 if (toOp->blendingNeedsRendererSize()) { 169 LayoutSize size = anim->renderer()->isBox() ? toRenderBox(anim->renderer())->borderBoxRect().size() : LayoutSize(); 170 return toOp->blend(fromOp, progress, size, blendToPassthrough); 171 } 172 return toOp->blend(fromOp, progress, blendToPassthrough); 173} 174 175static inline FilterOperations blendFilterOperations(const AnimationBase* anim, const FilterOperations& from, const FilterOperations& to, double progress) 176{ 177 FilterOperations result; 178 size_t fromSize = from.operations().size(); 179 size_t toSize = to.operations().size(); 180 size_t size = std::max(fromSize, toSize); 181 for (size_t i = 0; i < size; i++) { 182 RefPtr<FilterOperation> fromOp = (i < fromSize) ? from.operations()[i].get() : 0; 183 RefPtr<FilterOperation> toOp = (i < toSize) ? to.operations()[i].get() : 0; 184 RefPtr<FilterOperation> blendedOp = toOp ? blendFunc(anim, fromOp.get(), toOp.get(), progress) : (fromOp ? blendFunc(anim, 0, fromOp.get(), progress, true) : 0); 185 if (blendedOp) 186 result.operations().append(blendedOp); 187 else { 188 RefPtr<FilterOperation> identityOp = PassthroughFilterOperation::create(); 189 if (progress > 0.5) 190 result.operations().append(toOp ? toOp : identityOp); 191 else 192 result.operations().append(fromOp ? fromOp : identityOp); 193 } 194 } 195 return result; 196} 197 198static inline FilterOperations blendFunc(const AnimationBase* anim, const FilterOperations& from, const FilterOperations& to, double progress) 199{ 200 FilterOperations result; 201 202 // If we have a filter function list, use that to do a per-function animation. 203 if (anim->filterFunctionListsMatch()) 204 result = blendFilterOperations(anim, from, to, progress); 205 else { 206 // 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. 207 // For now we'll just fail to animate. 208 result = to; 209 } 210 211 return result; 212} 213 214static inline PassRefPtr<StyleImage> blendFilter(const AnimationBase* anim, CachedImage* image, const FilterOperations& from, const FilterOperations& to, double progress) 215{ 216 ASSERT(image); 217 FilterOperations filterResult = blendFilterOperations(anim, from, to, progress); 218 219 RefPtr<StyleCachedImage> styledImage = StyleCachedImage::create(image); 220 auto imageValue = CSSImageValue::create(image->url(), styledImage.get()); 221 auto filterValue = ComputedStyleExtractor::valueForFilter(&anim->renderer()->style(), filterResult, DoNotAdjustPixelValues); 222 223 auto result = CSSFilterImageValue::create(WTF::move(imageValue), WTF::move(filterValue)); 224 result.get().setFilterOperations(filterResult); 225 return StyleGeneratedImage::create(WTF::move(result)); 226} 227#endif // ENABLE(CSS_FILTERS) 228 229static inline EVisibility blendFunc(const AnimationBase* anim, EVisibility from, EVisibility to, double progress) 230{ 231 // Any non-zero result means we consider the object to be visible. Only at 0 do we consider the object to be 232 // invisible. The invisible value we use (HIDDEN vs. COLLAPSE) depends on the specified from/to values. 233 double fromVal = from == VISIBLE ? 1. : 0.; 234 double toVal = to == VISIBLE ? 1. : 0.; 235 if (fromVal == toVal) 236 return to; 237 double result = blendFunc(anim, fromVal, toVal, progress); 238 return result > 0. ? VISIBLE : (to != VISIBLE ? to : from); 239} 240 241static inline LengthBox blendFunc(const AnimationBase* anim, const LengthBox& from, const LengthBox& to, double progress) 242{ 243 LengthBox result(blendFunc(anim, from.top(), to.top(), progress), 244 blendFunc(anim, from.right(), to.right(), progress), 245 blendFunc(anim, from.bottom(), to.bottom(), progress), 246 blendFunc(anim, from.left(), to.left(), progress)); 247 return result; 248} 249 250static inline SVGLength blendFunc(const AnimationBase*, const SVGLength& from, const SVGLength& to, double progress) 251{ 252 return to.blend(from, narrowPrecisionToFloat(progress)); 253} 254static inline Vector<SVGLength> blendFunc(const AnimationBase*, const Vector<SVGLength>& from, const Vector<SVGLength>& to, double progress) 255{ 256 size_t fromLength = from.size(); 257 size_t toLength = to.size(); 258 if (!fromLength) 259 return !progress ? from : to; 260 if (!toLength) 261 return progress == 1 ? from : to; 262 size_t resultLength = fromLength; 263 if (fromLength != toLength) { 264 if (!remainder(std::max(fromLength, toLength), std::min(fromLength, toLength))) 265 resultLength = std::max(fromLength, toLength); 266 else 267 resultLength = fromLength * toLength; 268 } 269 Vector<SVGLength> result(resultLength); 270 for (size_t i = 0; i < resultLength; ++i) 271 result[i] = to[i % toLength].blend(from[i % fromLength], narrowPrecisionToFloat(progress)); 272 return result; 273} 274 275static inline PassRefPtr<StyleImage> crossfadeBlend(const AnimationBase*, StyleCachedImage* fromStyleImage, StyleCachedImage* toStyleImage, double progress) 276{ 277 // If progress is at one of the extremes, we want getComputedStyle to show the image, 278 // not a completed cross-fade, so we hand back one of the existing images. 279 if (!progress) 280 return fromStyleImage; 281 if (progress == 1) 282 return toStyleImage; 283 284 auto fromImageValue = CSSImageValue::create(fromStyleImage->cachedImage()->url(), fromStyleImage); 285 auto toImageValue = CSSImageValue::create(toStyleImage->cachedImage()->url(), toStyleImage); 286 287 auto crossfadeValue = CSSCrossfadeValue::create(WTF::move(fromImageValue), WTF::move(toImageValue)); 288 crossfadeValue.get().setPercentage(CSSPrimitiveValue::create(progress, CSSPrimitiveValue::CSS_NUMBER)); 289 return StyleGeneratedImage::create(WTF::move(crossfadeValue)); 290} 291 292static inline PassRefPtr<StyleImage> blendFunc(const AnimationBase* anim, StyleImage* from, StyleImage* to, double progress) 293{ 294 if (!from || !to) 295 return to; 296 297 // Animation between two generated images. Cross fade for all other cases. 298 if (from->isGeneratedImage() && to->isGeneratedImage()) { 299 CSSImageGeneratorValue& fromGenerated = toStyleGeneratedImage(from)->imageValue(); 300 CSSImageGeneratorValue& toGenerated = toStyleGeneratedImage(to)->imageValue(); 301 302#if ENABLE(CSS_FILTERS) 303 if (fromGenerated.isFilterImageValue() && toGenerated.isFilterImageValue()) { 304 // Animation of generated images just possible if input images are equal. 305 // Otherwise fall back to cross fade animation. 306 CSSFilterImageValue& fromFilter = toCSSFilterImageValue(fromGenerated); 307 CSSFilterImageValue& toFilter = toCSSFilterImageValue(toGenerated); 308 if (fromFilter.equalInputImages(toFilter) && fromFilter.cachedImage()) 309 return blendFilter(anim, fromFilter.cachedImage(), fromFilter.filterOperations(), toFilter.filterOperations(), progress); 310 } 311#endif 312 313 if (fromGenerated.isCrossfadeValue() && toGenerated.isCrossfadeValue()) { 314 CSSCrossfadeValue& fromCrossfade = toCSSCrossfadeValue(fromGenerated); 315 CSSCrossfadeValue& toCrossfade = toCSSCrossfadeValue(toGenerated); 316 if (fromCrossfade.equalInputImages(toCrossfade)) 317 return StyleGeneratedImage::create(*toCrossfade.blend(fromCrossfade, progress)); 318 } 319 320 // FIXME: Add support for animation between two *gradient() functions. 321 // https://bugs.webkit.org/show_bug.cgi?id=119956 322#if ENABLE(CSS_FILTERS) 323 } else if (from->isGeneratedImage() && to->isCachedImage()) { 324 CSSImageGeneratorValue& fromGenerated = toStyleGeneratedImage(from)->imageValue(); 325 if (fromGenerated.isFilterImageValue()) { 326 CSSFilterImageValue& fromFilter = toCSSFilterImageValue(fromGenerated); 327 if (fromFilter.cachedImage() && toStyleCachedImage(to)->cachedImage() == fromFilter.cachedImage()) 328 return blendFilter(anim, fromFilter.cachedImage(), fromFilter.filterOperations(), FilterOperations(), progress); 329 } 330 // FIXME: Add interpolation between cross-fade and image source. 331 } else if (from->isCachedImage() && to->isGeneratedImage()) { 332 CSSImageGeneratorValue& toGenerated = toStyleGeneratedImage(to)->imageValue(); 333 if (toGenerated.isFilterImageValue()) { 334 CSSFilterImageValue& toFilter = toCSSFilterImageValue(toGenerated); 335 if (toFilter.cachedImage() && toStyleCachedImage(from)->cachedImage() == toFilter.cachedImage()) 336 return blendFilter(anim, toFilter.cachedImage(), FilterOperations(), toFilter.filterOperations(), progress); 337 } 338#endif 339 // FIXME: Add interpolation between image source and cross-fade. 340 } 341 342 // FIXME: Add support cross fade between cached and generated images. 343 // https://bugs.webkit.org/show_bug.cgi?id=78293 344 if (from->isCachedImage() && to->isCachedImage()) 345 return crossfadeBlend(anim, toStyleCachedImage(from), toStyleCachedImage(to), progress); 346 347 return to; 348} 349 350static inline NinePieceImage blendFunc(const AnimationBase* anim, const NinePieceImage& from, const NinePieceImage& to, double progress) 351{ 352 if (!from.hasImage() || !to.hasImage()) 353 return to; 354 355 // FIXME (74112): Support transitioning between NinePieceImages that differ by more than image content. 356 357 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()) 358 return to; 359 360 if (from.image()->imageSize(anim->renderer(), 1.0) != to.image()->imageSize(anim->renderer(), 1.0)) 361 return to; 362 363 RefPtr<StyleImage> newContentImage = blendFunc(anim, from.image(), to.image(), progress); 364 365 return NinePieceImage(newContentImage, from.imageSlices(), from.fill(), from.borderSlices(), from.outset(), from.horizontalRule(), from.verticalRule()); 366} 367 368class AnimationPropertyWrapperBase { 369 WTF_MAKE_NONCOPYABLE(AnimationPropertyWrapperBase); 370 WTF_MAKE_FAST_ALLOCATED; 371public: 372 AnimationPropertyWrapperBase(CSSPropertyID prop) 373 : m_prop(prop) 374 { 375 } 376 377 virtual ~AnimationPropertyWrapperBase() { } 378 379 virtual bool isShorthandWrapper() const { return false; } 380 virtual bool equals(const RenderStyle* a, const RenderStyle* b) const = 0; 381 virtual void blend(const AnimationBase*, RenderStyle*, const RenderStyle*, const RenderStyle*, double) const = 0; 382 383 CSSPropertyID property() const { return m_prop; } 384 385 virtual bool animationIsAccelerated() const { return false; } 386 387private: 388 CSSPropertyID m_prop; 389}; 390 391template <typename T> 392class PropertyWrapperGetter : public AnimationPropertyWrapperBase { 393public: 394 PropertyWrapperGetter(CSSPropertyID prop, T (RenderStyle::*getter)() const) 395 : AnimationPropertyWrapperBase(prop) 396 , m_getter(getter) 397 { 398 } 399 400 virtual bool equals(const RenderStyle* a, const RenderStyle* b) const 401 { 402 // If the style pointers are the same, don't bother doing the test. 403 // If either is null, return false. If both are null, return true. 404 if ((!a && !b) || a == b) 405 return true; 406 if (!a || !b) 407 return false; 408 return (a->*m_getter)() == (b->*m_getter)(); 409 } 410 411protected: 412 T (RenderStyle::*m_getter)() const; 413}; 414 415template <typename T> 416class PropertyWrapper : public PropertyWrapperGetter<T> { 417public: 418 PropertyWrapper(CSSPropertyID prop, T (RenderStyle::*getter)() const, void (RenderStyle::*setter)(T)) 419 : PropertyWrapperGetter<T>(prop, getter) 420 , m_setter(setter) 421 { 422 } 423 424 virtual void blend(const AnimationBase* anim, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress) const 425 { 426 (dst->*m_setter)(blendFunc(anim, (a->*PropertyWrapperGetter<T>::m_getter)(), (b->*PropertyWrapperGetter<T>::m_getter)(), progress)); 427 } 428 429protected: 430 void (RenderStyle::*m_setter)(T); 431}; 432 433template <typename T> 434class RefCountedPropertyWrapper : public PropertyWrapperGetter<T*> { 435public: 436 RefCountedPropertyWrapper(CSSPropertyID prop, T* (RenderStyle::*getter)() const, void (RenderStyle::*setter)(PassRefPtr<T>)) 437 : PropertyWrapperGetter<T*>(prop, getter) 438 , m_setter(setter) 439 { 440 } 441 442 virtual void blend(const AnimationBase* anim, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress) const 443 { 444 (dst->*m_setter)(blendFunc(anim, (a->*PropertyWrapperGetter<T*>::m_getter)(), (b->*PropertyWrapperGetter<T*>::m_getter)(), progress)); 445 } 446 447protected: 448 void (RenderStyle::*m_setter)(PassRefPtr<T>); 449}; 450 451template <typename T> 452class LengthPropertyWrapper : public PropertyWrapperGetter<const T&> { 453public: 454 LengthPropertyWrapper(CSSPropertyID prop, const T& (RenderStyle::*getter)() const, void (RenderStyle::*setter)(T)) 455 : PropertyWrapperGetter<const T&>(prop, getter) 456 , m_setter(setter) 457 { 458 } 459 460 virtual void blend(const AnimationBase* anim, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress) const 461 { 462 (dst->*m_setter)(blendFunc(anim, (a->*PropertyWrapperGetter<const T&>::m_getter)(), (b->*PropertyWrapperGetter<const T&>::m_getter)(), progress)); 463 } 464 465protected: 466 void (RenderStyle::*m_setter)(T); 467}; 468 469class PropertyWrapperClipPath : public RefCountedPropertyWrapper<ClipPathOperation> { 470public: 471 PropertyWrapperClipPath(CSSPropertyID prop, ClipPathOperation* (RenderStyle::*getter)() const, void (RenderStyle::*setter)(PassRefPtr<ClipPathOperation>)) 472 : RefCountedPropertyWrapper<ClipPathOperation>(prop, getter, setter) 473 { 474 } 475}; 476 477#if ENABLE(CSS_SHAPES) 478class PropertyWrapperShape : public RefCountedPropertyWrapper<ShapeValue> { 479public: 480 PropertyWrapperShape(CSSPropertyID prop, ShapeValue* (RenderStyle::*getter)() const, void (RenderStyle::*setter)(PassRefPtr<ShapeValue>)) 481 : RefCountedPropertyWrapper<ShapeValue>(prop, getter, setter) 482 { 483 } 484}; 485#endif 486 487class StyleImagePropertyWrapper : public RefCountedPropertyWrapper<StyleImage> { 488public: 489 StyleImagePropertyWrapper(CSSPropertyID prop, StyleImage* (RenderStyle::*getter)() const, void (RenderStyle::*setter)(PassRefPtr<StyleImage>)) 490 : RefCountedPropertyWrapper<StyleImage>(prop, getter, setter) 491 { 492 } 493 494 virtual bool equals(const RenderStyle* a, const RenderStyle* b) const 495 { 496 // If the style pointers are the same, don't bother doing the test. 497 // If either is null, return false. If both are null, return true. 498 if (a == b) 499 return true; 500 if (!a || !b) 501 return false; 502 503 StyleImage* imageA = (a->*m_getter)(); 504 StyleImage* imageB = (b->*m_getter)(); 505 return StyleImage::imagesEquivalent(imageA, imageB); 506 } 507}; 508 509class PropertyWrapperColor : public PropertyWrapperGetter<Color> { 510public: 511 PropertyWrapperColor(CSSPropertyID prop, Color (RenderStyle::*getter)() const, void (RenderStyle::*setter)(const Color&)) 512 : PropertyWrapperGetter<Color>(prop, getter) 513 , m_setter(setter) 514 { 515 } 516 517 virtual void blend(const AnimationBase* anim, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress) const 518 { 519 (dst->*m_setter)(blendFunc(anim, (a->*PropertyWrapperGetter<Color>::m_getter)(), (b->*PropertyWrapperGetter<Color>::m_getter)(), progress)); 520 } 521 522protected: 523 void (RenderStyle::*m_setter)(const Color&); 524}; 525 526 527class PropertyWrapperAcceleratedOpacity : public PropertyWrapper<float> { 528public: 529 PropertyWrapperAcceleratedOpacity() 530 : PropertyWrapper<float>(CSSPropertyOpacity, &RenderStyle::opacity, &RenderStyle::setOpacity) 531 { 532 } 533 534 virtual bool animationIsAccelerated() const { return true; } 535 536 virtual void blend(const AnimationBase* anim, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress) const 537 { 538 float fromOpacity = a->opacity(); 539 540 // This makes sure we put the object being animated into a RenderLayer during the animation 541 dst->setOpacity(blendFunc(anim, (fromOpacity == 1) ? 0.999999f : fromOpacity, b->opacity(), progress)); 542 } 543}; 544 545class PropertyWrapperAcceleratedTransform : public PropertyWrapper<const TransformOperations&> { 546public: 547 PropertyWrapperAcceleratedTransform() 548 : PropertyWrapper<const TransformOperations&>(CSSPropertyWebkitTransform, &RenderStyle::transform, &RenderStyle::setTransform) 549 { 550 } 551 552 virtual bool animationIsAccelerated() const { return true; } 553 554 virtual void blend(const AnimationBase* anim, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress) const 555 { 556 dst->setTransform(blendFunc(anim, a->transform(), b->transform(), progress)); 557 } 558}; 559 560#if ENABLE(CSS_FILTERS) 561class PropertyWrapperAcceleratedFilter : public PropertyWrapper<const FilterOperations&> { 562public: 563 PropertyWrapperAcceleratedFilter() 564 : PropertyWrapper<const FilterOperations&>(CSSPropertyWebkitFilter, &RenderStyle::filter, &RenderStyle::setFilter) 565 { 566 } 567 568 virtual bool animationIsAccelerated() const { return true; } 569 570 virtual void blend(const AnimationBase* anim, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress) const 571 { 572 dst->setFilter(blendFunc(anim, a->filter(), b->filter(), progress)); 573 } 574}; 575#endif 576 577static inline size_t shadowListLength(const ShadowData* shadow) 578{ 579 size_t count; 580 for (count = 0; shadow; shadow = shadow->next()) 581 ++count; 582 return count; 583} 584 585static inline const ShadowData* shadowForBlending(const ShadowData* srcShadow, const ShadowData* otherShadow) 586{ 587 DEPRECATED_DEFINE_STATIC_LOCAL(ShadowData, defaultShadowData, (IntPoint(), 0, 0, Normal, false, Color::transparent)); 588 DEPRECATED_DEFINE_STATIC_LOCAL(ShadowData, defaultInsetShadowData, (IntPoint(), 0, 0, Inset, false, Color::transparent)); 589 590 DEPRECATED_DEFINE_STATIC_LOCAL(ShadowData, defaultWebKitBoxShadowData, (IntPoint(), 0, 0, Normal, true, Color::transparent)); 591 DEPRECATED_DEFINE_STATIC_LOCAL(ShadowData, defaultInsetWebKitBoxShadowData, (IntPoint(), 0, 0, Inset, true, Color::transparent)); 592 593 if (srcShadow) 594 return srcShadow; 595 596 if (otherShadow->style() == Inset) 597 return otherShadow->isWebkitBoxShadow() ? &defaultInsetWebKitBoxShadowData : &defaultInsetShadowData; 598 599 return otherShadow->isWebkitBoxShadow() ? &defaultWebKitBoxShadowData : &defaultShadowData; 600} 601 602class PropertyWrapperShadow : public AnimationPropertyWrapperBase { 603public: 604 PropertyWrapperShadow(CSSPropertyID prop, const ShadowData* (RenderStyle::*getter)() const, void (RenderStyle::*setter)(std::unique_ptr<ShadowData>, bool)) 605 : AnimationPropertyWrapperBase(prop) 606 , m_getter(getter) 607 , m_setter(setter) 608 { 609 } 610 611 virtual bool equals(const RenderStyle* a, const RenderStyle* b) const 612 { 613 const ShadowData* shadowA = (a->*m_getter)(); 614 const ShadowData* shadowB = (b->*m_getter)(); 615 616 while (true) { 617 // end of both lists 618 if (!shadowA && !shadowB) 619 return true; 620 621 // end of just one of the lists 622 if (!shadowA || !shadowB) 623 return false; 624 625 if (*shadowA != *shadowB) 626 return false; 627 628 shadowA = shadowA->next(); 629 shadowB = shadowB->next(); 630 } 631 632 return true; 633 } 634 635 virtual void blend(const AnimationBase* anim, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress) const 636 { 637 const ShadowData* shadowA = (a->*m_getter)(); 638 const ShadowData* shadowB = (b->*m_getter)(); 639 640 int fromLength = shadowListLength(shadowA); 641 int toLength = shadowListLength(shadowB); 642 643 if (fromLength == toLength || (fromLength <= 1 && toLength <= 1)) { 644 (dst->*m_setter)(blendSimpleOrMatchedShadowLists(anim, progress, shadowA, shadowB), false); 645 return; 646 } 647 648 (dst->*m_setter)(blendMismatchedShadowLists(anim, progress, shadowA, shadowB, fromLength, toLength), false); 649 } 650 651private: 652 std::unique_ptr<ShadowData> blendSimpleOrMatchedShadowLists(const AnimationBase* anim, double progress, const ShadowData* shadowA, const ShadowData* shadowB) const 653 { 654 std::unique_ptr<ShadowData> newShadowData; 655 ShadowData* lastShadow = 0; 656 657 while (shadowA || shadowB) { 658 const ShadowData* srcShadow = shadowForBlending(shadowA, shadowB); 659 const ShadowData* dstShadow = shadowForBlending(shadowB, shadowA); 660 661 std::unique_ptr<ShadowData> blendedShadow = blendFunc(anim, srcShadow, dstShadow, progress); 662 ShadowData* blendedShadowPtr = blendedShadow.get(); 663 664 if (!lastShadow) 665 newShadowData = WTF::move(blendedShadow); 666 else 667 lastShadow->setNext(WTF::move(blendedShadow)); 668 669 lastShadow = blendedShadowPtr; 670 671 shadowA = shadowA ? shadowA->next() : 0; 672 shadowB = shadowB ? shadowB->next() : 0; 673 } 674 675 return newShadowData; 676 } 677 678 std::unique_ptr<ShadowData> blendMismatchedShadowLists(const AnimationBase* anim, double progress, const ShadowData* shadowA, const ShadowData* shadowB, int fromLength, int toLength) const 679 { 680 // The shadows in ShadowData are stored in reverse order, so when animating mismatched lists, 681 // reverse them and match from the end. 682 Vector<const ShadowData*, 4> fromShadows(fromLength); 683 for (int i = fromLength - 1; i >= 0; --i) { 684 fromShadows[i] = shadowA; 685 shadowA = shadowA->next(); 686 } 687 688 Vector<const ShadowData*, 4> toShadows(toLength); 689 for (int i = toLength - 1; i >= 0; --i) { 690 toShadows[i] = shadowB; 691 shadowB = shadowB->next(); 692 } 693 694 std::unique_ptr<ShadowData> newShadowData; 695 696 int maxLength = std::max(fromLength, toLength); 697 for (int i = 0; i < maxLength; ++i) { 698 const ShadowData* fromShadow = i < fromLength ? fromShadows[i] : 0; 699 const ShadowData* toShadow = i < toLength ? toShadows[i] : 0; 700 701 const ShadowData* srcShadow = shadowForBlending(fromShadow, toShadow); 702 const ShadowData* dstShadow = shadowForBlending(toShadow, fromShadow); 703 704 std::unique_ptr<ShadowData> blendedShadow = blendFunc(anim, srcShadow, dstShadow, progress); 705 // Insert at the start of the list to preserve the order. 706 blendedShadow->setNext(WTF::move(newShadowData)); 707 newShadowData = WTF::move(blendedShadow); 708 } 709 710 return newShadowData; 711 } 712 713 const ShadowData* (RenderStyle::*m_getter)() const; 714 void (RenderStyle::*m_setter)(std::unique_ptr<ShadowData>, bool); 715}; 716 717class PropertyWrapperMaybeInvalidColor : public AnimationPropertyWrapperBase { 718public: 719 PropertyWrapperMaybeInvalidColor(CSSPropertyID prop, Color (RenderStyle::*getter)() const, void (RenderStyle::*setter)(const Color&)) 720 : AnimationPropertyWrapperBase(prop) 721 , m_getter(getter) 722 , m_setter(setter) 723 { 724 } 725 726 virtual bool equals(const RenderStyle* a, const RenderStyle* b) const 727 { 728 Color fromColor = (a->*m_getter)(); 729 Color toColor = (b->*m_getter)(); 730 731 if (!fromColor.isValid() && !toColor.isValid()) 732 return true; 733 734 if (!fromColor.isValid()) 735 fromColor = a->color(); 736 if (!toColor.isValid()) 737 toColor = b->color(); 738 739 return fromColor == toColor; 740 } 741 742 virtual void blend(const AnimationBase* anim, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress) const 743 { 744 Color fromColor = (a->*m_getter)(); 745 Color toColor = (b->*m_getter)(); 746 747 if (!fromColor.isValid() && !toColor.isValid()) 748 return; 749 750 if (!fromColor.isValid()) 751 fromColor = a->color(); 752 if (!toColor.isValid()) 753 toColor = b->color(); 754 (dst->*m_setter)(blendFunc(anim, fromColor, toColor, progress)); 755 } 756 757private: 758 Color (RenderStyle::*m_getter)() const; 759 void (RenderStyle::*m_setter)(const Color&); 760}; 761 762 763enum MaybeInvalidColorTag { MaybeInvalidColor }; 764class PropertyWrapperVisitedAffectedColor : public AnimationPropertyWrapperBase { 765public: 766 PropertyWrapperVisitedAffectedColor(CSSPropertyID prop, Color (RenderStyle::*getter)() const, void (RenderStyle::*setter)(const Color&), 767 Color (RenderStyle::*visitedGetter)() const, void (RenderStyle::*visitedSetter)(const Color&)) 768 : AnimationPropertyWrapperBase(prop) 769 , m_wrapper(std::make_unique<PropertyWrapperColor>(prop, getter, setter)) 770 , m_visitedWrapper(std::make_unique<PropertyWrapperColor>(prop, visitedGetter, visitedSetter)) 771 { 772 } 773 PropertyWrapperVisitedAffectedColor(CSSPropertyID prop, MaybeInvalidColorTag, Color (RenderStyle::*getter)() const, void (RenderStyle::*setter)(const Color&), 774 Color (RenderStyle::*visitedGetter)() const, void (RenderStyle::*visitedSetter)(const Color&)) 775 : AnimationPropertyWrapperBase(prop) 776 , m_wrapper(std::make_unique<PropertyWrapperMaybeInvalidColor>(prop, getter, setter)) 777 , m_visitedWrapper(std::make_unique<PropertyWrapperMaybeInvalidColor>(prop, visitedGetter, visitedSetter)) 778 { 779 } 780 virtual bool equals(const RenderStyle* a, const RenderStyle* b) const 781 { 782 return m_wrapper->equals(a, b) && m_visitedWrapper->equals(a, b); 783 } 784 virtual void blend(const AnimationBase* anim, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress) const 785 { 786 m_wrapper->blend(anim, dst, a, b, progress); 787 m_visitedWrapper->blend(anim, dst, a, b, progress); 788 } 789 790private: 791 std::unique_ptr<AnimationPropertyWrapperBase> m_wrapper; 792 std::unique_ptr<AnimationPropertyWrapperBase> m_visitedWrapper; 793}; 794 795// Wrapper base class for an animatable property in a FillLayer 796class FillLayerAnimationPropertyWrapperBase { 797public: 798 FillLayerAnimationPropertyWrapperBase() 799 { 800 } 801 802 virtual ~FillLayerAnimationPropertyWrapperBase() { } 803 804 virtual bool equals(const FillLayer*, const FillLayer*) const = 0; 805 virtual void blend(const AnimationBase*, FillLayer*, const FillLayer*, const FillLayer*, double) const = 0; 806}; 807 808template <typename T> 809class FillLayerPropertyWrapperGetter : public FillLayerAnimationPropertyWrapperBase { 810 WTF_MAKE_NONCOPYABLE(FillLayerPropertyWrapperGetter); 811public: 812 FillLayerPropertyWrapperGetter(T (FillLayer::*getter)() const) 813 : m_getter(getter) 814 { 815 } 816 817 virtual bool equals(const FillLayer* a, const FillLayer* b) const 818 { 819 // If the style pointers are the same, don't bother doing the test. 820 // If either is null, return false. If both are null, return true. 821 if ((!a && !b) || a == b) 822 return true; 823 if (!a || !b) 824 return false; 825 return (a->*m_getter)() == (b->*m_getter)(); 826 } 827 828protected: 829 T (FillLayer::*m_getter)() const; 830}; 831 832template <typename T> 833class FillLayerPropertyWrapper : public FillLayerPropertyWrapperGetter<const T&> { 834public: 835 FillLayerPropertyWrapper(const T& (FillLayer::*getter)() const, void (FillLayer::*setter)(T)) 836 : FillLayerPropertyWrapperGetter<const T&>(getter) 837 , m_setter(setter) 838 { 839 } 840 841 virtual void blend(const AnimationBase* anim, FillLayer* dst, const FillLayer* a, const FillLayer* b, double progress) const 842 { 843 (dst->*m_setter)(blendFunc(anim, (a->*FillLayerPropertyWrapperGetter<const T&>::m_getter)(), (b->*FillLayerPropertyWrapperGetter<const T&>::m_getter)(), progress)); 844 } 845 846protected: 847 void (FillLayer::*m_setter)(T); 848}; 849 850template <typename T> 851class FillLayerRefCountedPropertyWrapper : public FillLayerPropertyWrapperGetter<T*> { 852public: 853 FillLayerRefCountedPropertyWrapper(T* (FillLayer::*getter)() const, void (FillLayer::*setter)(PassRefPtr<T>)) 854 : FillLayerPropertyWrapperGetter<T*>(getter) 855 , m_setter(setter) 856 { 857 } 858 859 virtual void blend(const AnimationBase* anim, FillLayer* dst, const FillLayer* a, const FillLayer* b, double progress) const 860 { 861 (dst->*m_setter)(blendFunc(anim, (a->*FillLayerPropertyWrapperGetter<T*>::m_getter)(), (b->*FillLayerPropertyWrapperGetter<T*>::m_getter)(), progress)); 862 } 863 864protected: 865 void (FillLayer::*m_setter)(PassRefPtr<T>); 866}; 867 868class FillLayerStyleImagePropertyWrapper : public FillLayerRefCountedPropertyWrapper<StyleImage> { 869public: 870 FillLayerStyleImagePropertyWrapper(StyleImage* (FillLayer::*getter)() const, void (FillLayer::*setter)(PassRefPtr<StyleImage>)) 871 : FillLayerRefCountedPropertyWrapper<StyleImage>(getter, setter) 872 { 873 } 874 875 virtual bool equals(const FillLayer* a, const FillLayer* b) const 876 { 877 // If the style pointers are the same, don't bother doing the test. 878 // If either is null, return false. If both are null, return true. 879 if (a == b) 880 return true; 881 if (!a || !b) 882 return false; 883 884 StyleImage* imageA = (a->*m_getter)(); 885 StyleImage* imageB = (b->*m_getter)(); 886 return StyleImage::imagesEquivalent(imageA, imageB); 887 } 888}; 889 890class FillLayersPropertyWrapper : public AnimationPropertyWrapperBase { 891public: 892 typedef const FillLayer* (RenderStyle::*LayersGetter)() const; 893 typedef FillLayer* (RenderStyle::*LayersAccessor)(); 894 895 FillLayersPropertyWrapper(CSSPropertyID prop, LayersGetter getter, LayersAccessor accessor) 896 : AnimationPropertyWrapperBase(prop) 897 , m_layersGetter(getter) 898 , m_layersAccessor(accessor) 899 { 900 switch (prop) { 901 case CSSPropertyBackgroundPositionX: 902 case CSSPropertyWebkitMaskPositionX: 903 m_fillLayerPropertyWrapper = new FillLayerPropertyWrapper<Length>(&FillLayer::xPosition, &FillLayer::setXPosition); 904 break; 905 case CSSPropertyBackgroundPositionY: 906 case CSSPropertyWebkitMaskPositionY: 907 m_fillLayerPropertyWrapper = new FillLayerPropertyWrapper<Length>(&FillLayer::yPosition, &FillLayer::setYPosition); 908 break; 909 case CSSPropertyBackgroundSize: 910 case CSSPropertyWebkitBackgroundSize: 911 case CSSPropertyWebkitMaskSize: 912 m_fillLayerPropertyWrapper = new FillLayerPropertyWrapper<LengthSize>(&FillLayer::sizeLength, &FillLayer::setSizeLength); 913 break; 914 case CSSPropertyBackgroundImage: 915 m_fillLayerPropertyWrapper = new FillLayerStyleImagePropertyWrapper(&FillLayer::image, &FillLayer::setImage); 916 break; 917 default: 918 break; 919 } 920 } 921 922 virtual bool equals(const RenderStyle* a, const RenderStyle* b) const 923 { 924 const FillLayer* fromLayer = (a->*m_layersGetter)(); 925 const FillLayer* toLayer = (b->*m_layersGetter)(); 926 927 while (fromLayer && toLayer) { 928 if (!m_fillLayerPropertyWrapper->equals(fromLayer, toLayer)) 929 return false; 930 931 fromLayer = fromLayer->next(); 932 toLayer = toLayer->next(); 933 } 934 935 return true; 936 } 937 938 virtual void blend(const AnimationBase* anim, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress) const 939 { 940 const FillLayer* aLayer = (a->*m_layersGetter)(); 941 const FillLayer* bLayer = (b->*m_layersGetter)(); 942 FillLayer* dstLayer = (dst->*m_layersAccessor)(); 943 944 while (aLayer && bLayer && dstLayer) { 945 m_fillLayerPropertyWrapper->blend(anim, dstLayer, aLayer, bLayer, progress); 946 aLayer = aLayer->next(); 947 bLayer = bLayer->next(); 948 dstLayer = dstLayer->next(); 949 } 950 } 951 952private: 953 FillLayerAnimationPropertyWrapperBase* m_fillLayerPropertyWrapper; 954 955 LayersGetter m_layersGetter; 956 LayersAccessor m_layersAccessor; 957}; 958 959class ShorthandPropertyWrapper : public AnimationPropertyWrapperBase { 960public: 961 ShorthandPropertyWrapper(CSSPropertyID property, Vector<AnimationPropertyWrapperBase*> longhandWrappers) 962 : AnimationPropertyWrapperBase(property) 963 , m_propertyWrappers(WTF::move(longhandWrappers)) 964 { 965 } 966 967 virtual bool isShorthandWrapper() const { return true; } 968 969 virtual bool equals(const RenderStyle* a, const RenderStyle* b) const 970 { 971 Vector<AnimationPropertyWrapperBase*>::const_iterator end = m_propertyWrappers.end(); 972 for (Vector<AnimationPropertyWrapperBase*>::const_iterator it = m_propertyWrappers.begin(); it != end; ++it) { 973 if (!(*it)->equals(a, b)) 974 return false; 975 } 976 return true; 977 } 978 979 virtual void blend(const AnimationBase* anim, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress) const 980 { 981 Vector<AnimationPropertyWrapperBase*>::const_iterator end = m_propertyWrappers.end(); 982 for (Vector<AnimationPropertyWrapperBase*>::const_iterator it = m_propertyWrappers.begin(); it != end; ++it) 983 (*it)->blend(anim, dst, a, b, progress); 984 } 985 986 const Vector<AnimationPropertyWrapperBase*>& propertyWrappers() const { return m_propertyWrappers; } 987 988private: 989 Vector<AnimationPropertyWrapperBase*> m_propertyWrappers; 990}; 991 992class PropertyWrapperFlex : public AnimationPropertyWrapperBase { 993public: 994 PropertyWrapperFlex() : AnimationPropertyWrapperBase(CSSPropertyWebkitFlex) 995 { 996 } 997 998 virtual bool equals(const RenderStyle* a, const RenderStyle* b) const 999 { 1000 // If the style pointers are the same, don't bother doing the test. 1001 // If either is null, return false. If both are null, return true. 1002 if ((!a && !b) || a == b) 1003 return true; 1004 if (!a || !b) 1005 return false; 1006 1007 return a->flexBasis() == b->flexBasis() && a->flexGrow() == b->flexGrow() && a->flexShrink() == b->flexShrink(); 1008 } 1009 1010 virtual void blend(const AnimationBase* anim, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress) const 1011 { 1012 dst->setFlexBasis(blendFunc(anim, a->flexBasis(), b->flexBasis(), progress)); 1013 dst->setFlexGrow(blendFunc(anim, a->flexGrow(), b->flexGrow(), progress)); 1014 dst->setFlexShrink(blendFunc(anim, a->flexShrink(), b->flexShrink(), progress)); 1015 } 1016}; 1017 1018class PropertyWrapperSVGPaint : public AnimationPropertyWrapperBase { 1019public: 1020 PropertyWrapperSVGPaint(CSSPropertyID prop, const SVGPaint::SVGPaintType& (RenderStyle::*paintTypeGetter)() const, Color (RenderStyle::*getter)() const, void (RenderStyle::*setter)(const Color&)) 1021 : AnimationPropertyWrapperBase(prop) 1022 , m_paintTypeGetter(paintTypeGetter) 1023 , m_getter(getter) 1024 , m_setter(setter) 1025 { 1026 } 1027 1028 virtual bool equals(const RenderStyle* a, const RenderStyle* b) const 1029 { 1030 if ((a->*m_paintTypeGetter)() != (b->*m_paintTypeGetter)()) 1031 return false; 1032 1033 // We only support animations between SVGPaints that are pure Color values. 1034 // For everything else we must return true for this method, otherwise 1035 // we will try to animate between values forever. 1036 if ((a->*m_paintTypeGetter)() == SVGPaint::SVG_PAINTTYPE_RGBCOLOR) { 1037 Color fromColor = (a->*m_getter)(); 1038 Color toColor = (b->*m_getter)(); 1039 1040 if (!fromColor.isValid() && !toColor.isValid()) 1041 return true; 1042 1043 if (!fromColor.isValid()) 1044 fromColor = Color(); 1045 if (!toColor.isValid()) 1046 toColor = Color(); 1047 1048 return fromColor == toColor; 1049 } 1050 return true; 1051 } 1052 1053 virtual void blend(const AnimationBase* anim, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress) const 1054 { 1055 if ((a->*m_paintTypeGetter)() != SVGPaint::SVG_PAINTTYPE_RGBCOLOR 1056 || (b->*m_paintTypeGetter)() != SVGPaint::SVG_PAINTTYPE_RGBCOLOR) 1057 return; 1058 1059 Color fromColor = (a->*m_getter)(); 1060 Color toColor = (b->*m_getter)(); 1061 1062 if (!fromColor.isValid() && !toColor.isValid()) 1063 return; 1064 1065 if (!fromColor.isValid()) 1066 fromColor = Color(); 1067 if (!toColor.isValid()) 1068 toColor = Color(); 1069 (dst->*m_setter)(blendFunc(anim, fromColor, toColor, progress)); 1070 } 1071 1072private: 1073 const SVGPaint::SVGPaintType& (RenderStyle::*m_paintTypeGetter)() const; 1074 Color (RenderStyle::*m_getter)() const; 1075 void (RenderStyle::*m_setter)(const Color&); 1076}; 1077 1078class CSSPropertyAnimationWrapperMap { 1079public: 1080 static CSSPropertyAnimationWrapperMap& instance() 1081 { 1082 // FIXME: This data is never destroyed. Maybe we should ref count it and toss it when the last AnimationController is destroyed? 1083 static NeverDestroyed<CSSPropertyAnimationWrapperMap> map; 1084 return map; 1085 } 1086 1087 AnimationPropertyWrapperBase* wrapperForProperty(CSSPropertyID propertyID) 1088 { 1089 if (propertyID < firstCSSProperty || propertyID > lastCSSProperty) 1090 return 0; 1091 1092 unsigned wrapperIndex = indexFromPropertyID(propertyID); 1093 if (wrapperIndex == cInvalidPropertyWrapperIndex) 1094 return 0; 1095 1096 return m_propertyWrappers[wrapperIndex].get(); 1097 } 1098 1099 AnimationPropertyWrapperBase* wrapperForIndex(unsigned index) 1100 { 1101 ASSERT(index < m_propertyWrappers.size()); 1102 return m_propertyWrappers[index].get(); 1103 } 1104 1105 unsigned size() 1106 { 1107 return m_propertyWrappers.size(); 1108 } 1109 1110private: 1111 CSSPropertyAnimationWrapperMap(); 1112 unsigned char& indexFromPropertyID(CSSPropertyID propertyID) 1113 { 1114 return m_propertyToIdMap[propertyID - firstCSSProperty]; 1115 } 1116 1117 Vector<std::unique_ptr<AnimationPropertyWrapperBase>> m_propertyWrappers; 1118 unsigned char m_propertyToIdMap[numCSSProperties]; 1119 1120 static const unsigned char cInvalidPropertyWrapperIndex = UCHAR_MAX; 1121 1122 friend class WTF::NeverDestroyed<CSSPropertyAnimationWrapperMap>; 1123}; 1124 1125CSSPropertyAnimationWrapperMap::CSSPropertyAnimationWrapperMap() 1126{ 1127 // build the list of property wrappers to do the comparisons and blends 1128 AnimationPropertyWrapperBase* animatableLonghandPropertyWrappers[] = { 1129 new LengthPropertyWrapper<Length>(CSSPropertyLeft, &RenderStyle::left, &RenderStyle::setLeft), 1130 new LengthPropertyWrapper<Length>(CSSPropertyRight, &RenderStyle::right, &RenderStyle::setRight), 1131 new LengthPropertyWrapper<Length>(CSSPropertyTop, &RenderStyle::top, &RenderStyle::setTop), 1132 new LengthPropertyWrapper<Length>(CSSPropertyBottom, &RenderStyle::bottom, &RenderStyle::setBottom), 1133 1134 new LengthPropertyWrapper<Length>(CSSPropertyWidth, &RenderStyle::width, &RenderStyle::setWidth), 1135 new LengthPropertyWrapper<Length>(CSSPropertyMinWidth, &RenderStyle::minWidth, &RenderStyle::setMinWidth), 1136 new LengthPropertyWrapper<Length>(CSSPropertyMaxWidth, &RenderStyle::maxWidth, &RenderStyle::setMaxWidth), 1137 1138 new LengthPropertyWrapper<Length>(CSSPropertyHeight, &RenderStyle::height, &RenderStyle::setHeight), 1139 new LengthPropertyWrapper<Length>(CSSPropertyMinHeight, &RenderStyle::minHeight, &RenderStyle::setMinHeight), 1140 new LengthPropertyWrapper<Length>(CSSPropertyMaxHeight, &RenderStyle::maxHeight, &RenderStyle::setMaxHeight), 1141 1142 new PropertyWrapperFlex(), 1143 1144 new PropertyWrapper<float>(CSSPropertyBorderLeftWidth, &RenderStyle::borderLeftWidth, &RenderStyle::setBorderLeftWidth), 1145 new PropertyWrapper<float>(CSSPropertyBorderRightWidth, &RenderStyle::borderRightWidth, &RenderStyle::setBorderRightWidth), 1146 new PropertyWrapper<float>(CSSPropertyBorderTopWidth, &RenderStyle::borderTopWidth, &RenderStyle::setBorderTopWidth), 1147 new PropertyWrapper<float>(CSSPropertyBorderBottomWidth, &RenderStyle::borderBottomWidth, &RenderStyle::setBorderBottomWidth), 1148 new LengthPropertyWrapper<Length>(CSSPropertyMarginLeft, &RenderStyle::marginLeft, &RenderStyle::setMarginLeft), 1149 new LengthPropertyWrapper<Length>(CSSPropertyMarginRight, &RenderStyle::marginRight, &RenderStyle::setMarginRight), 1150 new LengthPropertyWrapper<Length>(CSSPropertyMarginTop, &RenderStyle::marginTop, &RenderStyle::setMarginTop), 1151 new LengthPropertyWrapper<Length>(CSSPropertyMarginBottom, &RenderStyle::marginBottom, &RenderStyle::setMarginBottom), 1152 new LengthPropertyWrapper<Length>(CSSPropertyPaddingLeft, &RenderStyle::paddingLeft, &RenderStyle::setPaddingLeft), 1153 new LengthPropertyWrapper<Length>(CSSPropertyPaddingRight, &RenderStyle::paddingRight, &RenderStyle::setPaddingRight), 1154 new LengthPropertyWrapper<Length>(CSSPropertyPaddingTop, &RenderStyle::paddingTop, &RenderStyle::setPaddingTop), 1155 new LengthPropertyWrapper<Length>(CSSPropertyPaddingBottom, &RenderStyle::paddingBottom, &RenderStyle::setPaddingBottom), 1156 new PropertyWrapperVisitedAffectedColor(CSSPropertyColor, &RenderStyle::color, &RenderStyle::setColor, &RenderStyle::visitedLinkColor, &RenderStyle::setVisitedLinkColor), 1157 1158 new PropertyWrapperVisitedAffectedColor(CSSPropertyBackgroundColor, &RenderStyle::backgroundColor, &RenderStyle::setBackgroundColor, &RenderStyle::visitedLinkBackgroundColor, &RenderStyle::setVisitedLinkBackgroundColor), 1159 1160 new FillLayersPropertyWrapper(CSSPropertyBackgroundImage, &RenderStyle::backgroundLayers, &RenderStyle::accessBackgroundLayers), 1161 new StyleImagePropertyWrapper(CSSPropertyListStyleImage, &RenderStyle::listStyleImage, &RenderStyle::setListStyleImage), 1162 new StyleImagePropertyWrapper(CSSPropertyWebkitMaskImage, &RenderStyle::maskImage, &RenderStyle::setMaskImage), 1163 1164 new StyleImagePropertyWrapper(CSSPropertyBorderImageSource, &RenderStyle::borderImageSource, &RenderStyle::setBorderImageSource), 1165 new LengthPropertyWrapper<LengthBox>(CSSPropertyBorderImageSlice, &RenderStyle::borderImageSlices, &RenderStyle::setBorderImageSlices), 1166 new LengthPropertyWrapper<LengthBox>(CSSPropertyBorderImageWidth, &RenderStyle::borderImageWidth, &RenderStyle::setBorderImageWidth), 1167 new LengthPropertyWrapper<LengthBox>(CSSPropertyBorderImageOutset, &RenderStyle::borderImageOutset, &RenderStyle::setBorderImageOutset), 1168 1169 new StyleImagePropertyWrapper(CSSPropertyWebkitMaskBoxImageSource, &RenderStyle::maskBoxImageSource, &RenderStyle::setMaskBoxImageSource), 1170 new PropertyWrapper<const NinePieceImage&>(CSSPropertyWebkitMaskBoxImage, &RenderStyle::maskBoxImage, &RenderStyle::setMaskBoxImage), 1171 1172 new FillLayersPropertyWrapper(CSSPropertyBackgroundPositionX, &RenderStyle::backgroundLayers, &RenderStyle::accessBackgroundLayers), 1173 new FillLayersPropertyWrapper(CSSPropertyBackgroundPositionY, &RenderStyle::backgroundLayers, &RenderStyle::accessBackgroundLayers), 1174 new FillLayersPropertyWrapper(CSSPropertyBackgroundSize, &RenderStyle::backgroundLayers, &RenderStyle::accessBackgroundLayers), 1175 new FillLayersPropertyWrapper(CSSPropertyWebkitBackgroundSize, &RenderStyle::backgroundLayers, &RenderStyle::accessBackgroundLayers), 1176 1177 new FillLayersPropertyWrapper(CSSPropertyWebkitMaskPositionX, &RenderStyle::maskLayers, &RenderStyle::accessMaskLayers), 1178 new FillLayersPropertyWrapper(CSSPropertyWebkitMaskPositionY, &RenderStyle::maskLayers, &RenderStyle::accessMaskLayers), 1179 new FillLayersPropertyWrapper(CSSPropertyWebkitMaskSize, &RenderStyle::maskLayers, &RenderStyle::accessMaskLayers), 1180 1181 new PropertyWrapper<float>(CSSPropertyFontSize, 1182 // Must pass a specified size to setFontSize if Text Autosizing is enabled, but a computed size 1183 // if text zoom is enabled (if neither is enabled it's irrelevant as they're probably the same). 1184 // FIXME: Find some way to assert that text zoom isn't activated when Text Autosizing is compiled in. 1185#if ENABLE(TEXT_AUTOSIZING) 1186 &RenderStyle::specifiedFontSize, 1187#else 1188 &RenderStyle::computedFontSize, 1189#endif 1190 &RenderStyle::setFontSize), 1191 new PropertyWrapper<unsigned short>(CSSPropertyWebkitColumnRuleWidth, &RenderStyle::columnRuleWidth, &RenderStyle::setColumnRuleWidth), 1192 new PropertyWrapper<float>(CSSPropertyWebkitColumnGap, &RenderStyle::columnGap, &RenderStyle::setColumnGap), 1193 new PropertyWrapper<unsigned short>(CSSPropertyWebkitColumnCount, &RenderStyle::columnCount, &RenderStyle::setColumnCount), 1194 new PropertyWrapper<float>(CSSPropertyWebkitColumnWidth, &RenderStyle::columnWidth, &RenderStyle::setColumnWidth), 1195 new PropertyWrapper<short>(CSSPropertyWebkitBorderHorizontalSpacing, &RenderStyle::horizontalBorderSpacing, &RenderStyle::setHorizontalBorderSpacing), 1196 new PropertyWrapper<short>(CSSPropertyWebkitBorderVerticalSpacing, &RenderStyle::verticalBorderSpacing, &RenderStyle::setVerticalBorderSpacing), 1197 new PropertyWrapper<int>(CSSPropertyZIndex, &RenderStyle::zIndex, &RenderStyle::setZIndex), 1198 new PropertyWrapper<short>(CSSPropertyOrphans, &RenderStyle::orphans, &RenderStyle::setOrphans), 1199 new PropertyWrapper<short>(CSSPropertyWidows, &RenderStyle::widows, &RenderStyle::setWidows), 1200 new LengthPropertyWrapper<Length>(CSSPropertyLineHeight, &RenderStyle::specifiedLineHeight, &RenderStyle::setLineHeight), 1201 new PropertyWrapper<int>(CSSPropertyOutlineOffset, &RenderStyle::outlineOffset, &RenderStyle::setOutlineOffset), 1202 new PropertyWrapper<unsigned short>(CSSPropertyOutlineWidth, &RenderStyle::outlineWidth, &RenderStyle::setOutlineWidth), 1203 new PropertyWrapper<float>(CSSPropertyLetterSpacing, &RenderStyle::letterSpacing, &RenderStyle::setLetterSpacing), 1204 new LengthPropertyWrapper<Length>(CSSPropertyWordSpacing, &RenderStyle::wordSpacing, &RenderStyle::setWordSpacing), 1205 new LengthPropertyWrapper<Length>(CSSPropertyTextIndent, &RenderStyle::textIndent, &RenderStyle::setTextIndent), 1206 1207 new PropertyWrapper<float>(CSSPropertyWebkitPerspective, &RenderStyle::perspective, &RenderStyle::setPerspective), 1208 new LengthPropertyWrapper<Length>(CSSPropertyWebkitPerspectiveOriginX, &RenderStyle::perspectiveOriginX, &RenderStyle::setPerspectiveOriginX), 1209 new LengthPropertyWrapper<Length>(CSSPropertyWebkitPerspectiveOriginY, &RenderStyle::perspectiveOriginY, &RenderStyle::setPerspectiveOriginY), 1210 new LengthPropertyWrapper<Length>(CSSPropertyWebkitTransformOriginX, &RenderStyle::transformOriginX, &RenderStyle::setTransformOriginX), 1211 new LengthPropertyWrapper<Length>(CSSPropertyWebkitTransformOriginY, &RenderStyle::transformOriginY, &RenderStyle::setTransformOriginY), 1212 new PropertyWrapper<float>(CSSPropertyWebkitTransformOriginZ, &RenderStyle::transformOriginZ, &RenderStyle::setTransformOriginZ), 1213 new LengthPropertyWrapper<LengthSize>(CSSPropertyBorderTopLeftRadius, &RenderStyle::borderTopLeftRadius, &RenderStyle::setBorderTopLeftRadius), 1214 new LengthPropertyWrapper<LengthSize>(CSSPropertyBorderTopRightRadius, &RenderStyle::borderTopRightRadius, &RenderStyle::setBorderTopRightRadius), 1215 new LengthPropertyWrapper<LengthSize>(CSSPropertyBorderBottomLeftRadius, &RenderStyle::borderBottomLeftRadius, &RenderStyle::setBorderBottomLeftRadius), 1216 new LengthPropertyWrapper<LengthSize>(CSSPropertyBorderBottomRightRadius, &RenderStyle::borderBottomRightRadius, &RenderStyle::setBorderBottomRightRadius), 1217 new PropertyWrapper<EVisibility>(CSSPropertyVisibility, &RenderStyle::visibility, &RenderStyle::setVisibility), 1218 new PropertyWrapper<float>(CSSPropertyZoom, &RenderStyle::zoom, &RenderStyle::setZoomWithoutReturnValue), 1219 1220 new LengthPropertyWrapper<LengthBox>(CSSPropertyClip, &RenderStyle::clip, &RenderStyle::setClip), 1221 1222 new PropertyWrapperAcceleratedOpacity(), 1223 new PropertyWrapperAcceleratedTransform(), 1224#if ENABLE(CSS_FILTERS) 1225 new PropertyWrapperAcceleratedFilter(), 1226#endif 1227 1228 new PropertyWrapperClipPath(CSSPropertyWebkitClipPath, &RenderStyle::clipPath, &RenderStyle::setClipPath), 1229 1230#if ENABLE(CSS_SHAPES) 1231 new PropertyWrapperShape(CSSPropertyWebkitShapeOutside, &RenderStyle::shapeOutside, &RenderStyle::setShapeOutside), 1232 new LengthPropertyWrapper<Length>(CSSPropertyWebkitShapeMargin, &RenderStyle::shapeMargin, &RenderStyle::setShapeMargin), 1233 new PropertyWrapper<float>(CSSPropertyWebkitShapeImageThreshold, &RenderStyle::shapeImageThreshold, &RenderStyle::setShapeImageThreshold), 1234#endif 1235 1236 new PropertyWrapperVisitedAffectedColor(CSSPropertyWebkitColumnRuleColor, MaybeInvalidColor, &RenderStyle::columnRuleColor, &RenderStyle::setColumnRuleColor, &RenderStyle::visitedLinkColumnRuleColor, &RenderStyle::setVisitedLinkColumnRuleColor), 1237 new PropertyWrapperVisitedAffectedColor(CSSPropertyWebkitTextStrokeColor, MaybeInvalidColor, &RenderStyle::textStrokeColor, &RenderStyle::setTextStrokeColor, &RenderStyle::visitedLinkTextStrokeColor, &RenderStyle::setVisitedLinkTextStrokeColor), 1238 new PropertyWrapperVisitedAffectedColor(CSSPropertyWebkitTextFillColor, MaybeInvalidColor, &RenderStyle::textFillColor, &RenderStyle::setTextFillColor, &RenderStyle::visitedLinkTextFillColor, &RenderStyle::setVisitedLinkTextFillColor), 1239 new PropertyWrapperVisitedAffectedColor(CSSPropertyBorderLeftColor, MaybeInvalidColor, &RenderStyle::borderLeftColor, &RenderStyle::setBorderLeftColor, &RenderStyle::visitedLinkBorderLeftColor, &RenderStyle::setVisitedLinkBorderLeftColor), 1240 new PropertyWrapperVisitedAffectedColor(CSSPropertyBorderRightColor, MaybeInvalidColor, &RenderStyle::borderRightColor, &RenderStyle::setBorderRightColor, &RenderStyle::visitedLinkBorderRightColor, &RenderStyle::setVisitedLinkBorderRightColor), 1241 new PropertyWrapperVisitedAffectedColor(CSSPropertyBorderTopColor, MaybeInvalidColor, &RenderStyle::borderTopColor, &RenderStyle::setBorderTopColor, &RenderStyle::visitedLinkBorderTopColor, &RenderStyle::setVisitedLinkBorderTopColor), 1242 new PropertyWrapperVisitedAffectedColor(CSSPropertyBorderBottomColor, MaybeInvalidColor, &RenderStyle::borderBottomColor, &RenderStyle::setBorderBottomColor, &RenderStyle::visitedLinkBorderBottomColor, &RenderStyle::setVisitedLinkBorderBottomColor), 1243 new PropertyWrapperVisitedAffectedColor(CSSPropertyOutlineColor, MaybeInvalidColor, &RenderStyle::outlineColor, &RenderStyle::setOutlineColor, &RenderStyle::visitedLinkOutlineColor, &RenderStyle::setVisitedLinkOutlineColor), 1244 1245 new PropertyWrapperShadow(CSSPropertyBoxShadow, &RenderStyle::boxShadow, &RenderStyle::setBoxShadow), 1246 new PropertyWrapperShadow(CSSPropertyWebkitBoxShadow, &RenderStyle::boxShadow, &RenderStyle::setBoxShadow), 1247 new PropertyWrapperShadow(CSSPropertyTextShadow, &RenderStyle::textShadow, &RenderStyle::setTextShadow), 1248 1249 new PropertyWrapperSVGPaint(CSSPropertyFill, &RenderStyle::fillPaintType, &RenderStyle::fillPaintColor, &RenderStyle::setFillPaintColor), 1250 new PropertyWrapper<float>(CSSPropertyFillOpacity, &RenderStyle::fillOpacity, &RenderStyle::setFillOpacity), 1251 1252 new PropertyWrapperSVGPaint(CSSPropertyStroke, &RenderStyle::strokePaintType, &RenderStyle::strokePaintColor, &RenderStyle::setStrokePaintColor), 1253 new PropertyWrapper<float>(CSSPropertyStrokeOpacity, &RenderStyle::strokeOpacity, &RenderStyle::setStrokeOpacity), 1254 new PropertyWrapper<SVGLength>(CSSPropertyStrokeWidth, &RenderStyle::strokeWidth, &RenderStyle::setStrokeWidth), 1255 new PropertyWrapper< Vector<SVGLength>>(CSSPropertyStrokeDasharray, &RenderStyle::strokeDashArray, &RenderStyle::setStrokeDashArray), 1256 new PropertyWrapper<SVGLength>(CSSPropertyStrokeDashoffset, &RenderStyle::strokeDashOffset, &RenderStyle::setStrokeDashOffset), 1257 new PropertyWrapper<float>(CSSPropertyStrokeMiterlimit, &RenderStyle::strokeMiterLimit, &RenderStyle::setStrokeMiterLimit), 1258 1259 new PropertyWrapper<float>(CSSPropertyFloodOpacity, &RenderStyle::floodOpacity, &RenderStyle::setFloodOpacity), 1260 new PropertyWrapperMaybeInvalidColor(CSSPropertyFloodColor, &RenderStyle::floodColor, &RenderStyle::setFloodColor), 1261 1262 new PropertyWrapper<float>(CSSPropertyStopOpacity, &RenderStyle::stopOpacity, &RenderStyle::setStopOpacity), 1263 new PropertyWrapperMaybeInvalidColor(CSSPropertyStopColor, &RenderStyle::stopColor, &RenderStyle::setStopColor), 1264 1265 new PropertyWrapperMaybeInvalidColor(CSSPropertyLightingColor, &RenderStyle::lightingColor, &RenderStyle::setLightingColor), 1266 1267 new PropertyWrapper<SVGLength>(CSSPropertyBaselineShift, &RenderStyle::baselineShiftValue, &RenderStyle::setBaselineShiftValue), 1268 new PropertyWrapper<SVGLength>(CSSPropertyKerning, &RenderStyle::kerning, &RenderStyle::setKerning), 1269 }; 1270 const unsigned animatableLonghandPropertiesCount = WTF_ARRAY_LENGTH(animatableLonghandPropertyWrappers); 1271 1272 static const CSSPropertyID animatableShorthandProperties[] = { 1273 CSSPropertyBackground, // for background-color, background-position, background-image 1274 CSSPropertyBackgroundPosition, 1275 CSSPropertyFont, // for font-size, font-weight 1276 CSSPropertyWebkitMask, // for mask-position 1277 CSSPropertyWebkitMaskPosition, 1278 CSSPropertyBorderTop, CSSPropertyBorderRight, CSSPropertyBorderBottom, CSSPropertyBorderLeft, 1279 CSSPropertyBorderColor, 1280 CSSPropertyBorderRadius, 1281 CSSPropertyBorderWidth, 1282 CSSPropertyBorder, 1283 CSSPropertyBorderImage, 1284 CSSPropertyBorderSpacing, 1285 CSSPropertyListStyle, // for list-style-image 1286 CSSPropertyMargin, 1287 CSSPropertyOutline, 1288 CSSPropertyPadding, 1289 CSSPropertyWebkitTextStroke, 1290 CSSPropertyWebkitColumnRule, 1291 CSSPropertyWebkitBorderRadius, 1292 CSSPropertyWebkitTransformOrigin 1293 }; 1294 const unsigned animatableShorthandPropertiesCount = WTF_ARRAY_LENGTH(animatableShorthandProperties); 1295 1296 // TODO: 1297 // 1298 // CSSPropertyVerticalAlign 1299 // 1300 // Compound properties that have components that should be animatable: 1301 // 1302 // CSSPropertyWebkitColumns 1303 // CSSPropertyWebkitBoxReflect 1304 1305 // Make sure unused slots have a value 1306 for (int i = 0; i < numCSSProperties; ++i) 1307 m_propertyToIdMap[i] = cInvalidPropertyWrapperIndex; 1308 1309 COMPILE_ASSERT(animatableLonghandPropertiesCount + animatableShorthandPropertiesCount < UCHAR_MAX, numberOfAnimatablePropertiesMustBeLessThanUCharMax); 1310 m_propertyWrappers.reserveInitialCapacity(animatableLonghandPropertiesCount + animatableShorthandPropertiesCount); 1311 1312 // First we put the non-shorthand property wrappers into the map, so the shorthand-building 1313 // code can find them. 1314 1315 for (unsigned i = 0; i < animatableLonghandPropertiesCount; ++i) { 1316 AnimationPropertyWrapperBase* wrapper = animatableLonghandPropertyWrappers[i]; 1317 m_propertyWrappers.uncheckedAppend(std::unique_ptr<AnimationPropertyWrapperBase>(wrapper)); 1318 indexFromPropertyID(wrapper->property()) = i; 1319 } 1320 1321 for (size_t i = 0; i < animatableShorthandPropertiesCount; ++i) { 1322 CSSPropertyID propertyID = animatableShorthandProperties[i]; 1323 StylePropertyShorthand shorthand = shorthandForProperty(propertyID); 1324 if (!shorthand.length()) 1325 continue; 1326 1327 Vector<AnimationPropertyWrapperBase*> longhandWrappers; 1328 longhandWrappers.reserveInitialCapacity(shorthand.length()); 1329 const CSSPropertyID* properties = shorthand.properties(); 1330 for (unsigned j = 0; j < shorthand.length(); ++j) { 1331 unsigned wrapperIndex = indexFromPropertyID(properties[j]); 1332 if (wrapperIndex == cInvalidPropertyWrapperIndex) 1333 continue; 1334 ASSERT(m_propertyWrappers[wrapperIndex]); 1335 longhandWrappers.uncheckedAppend(m_propertyWrappers[wrapperIndex].get()); 1336 } 1337 1338 m_propertyWrappers.uncheckedAppend(std::make_unique<ShorthandPropertyWrapper>(propertyID, WTF::move(longhandWrappers))); 1339 indexFromPropertyID(propertyID) = animatableLonghandPropertiesCount + i; 1340 } 1341} 1342 1343static bool gatherEnclosingShorthandProperties(CSSPropertyID property, AnimationPropertyWrapperBase* wrapper, HashSet<CSSPropertyID>& propertySet) 1344{ 1345 if (!wrapper->isShorthandWrapper()) 1346 return false; 1347 1348 ShorthandPropertyWrapper* shorthandWrapper = static_cast<ShorthandPropertyWrapper*>(wrapper); 1349 bool contained = false; 1350 for (auto& currWrapper : shorthandWrapper->propertyWrappers()) { 1351 if (gatherEnclosingShorthandProperties(property, currWrapper, propertySet) || currWrapper->property() == property) 1352 contained = true; 1353 } 1354 1355 if (contained) 1356 propertySet.add(wrapper->property()); 1357 1358 return contained; 1359} 1360 1361// Returns true if we need to start animation timers 1362bool CSSPropertyAnimation::blendProperties(const AnimationBase* anim, CSSPropertyID prop, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress) 1363{ 1364 ASSERT(prop != CSSPropertyInvalid); 1365 1366 AnimationPropertyWrapperBase* wrapper = CSSPropertyAnimationWrapperMap::instance().wrapperForProperty(prop); 1367 if (wrapper) { 1368 wrapper->blend(anim, dst, a, b, progress); 1369 return !wrapper->animationIsAccelerated() || !anim->isAccelerated(); 1370 } 1371 1372 return false; 1373} 1374 1375bool CSSPropertyAnimation::animationOfPropertyIsAccelerated(CSSPropertyID prop) 1376{ 1377 AnimationPropertyWrapperBase* wrapper = CSSPropertyAnimationWrapperMap::instance().wrapperForProperty(prop); 1378 return wrapper ? wrapper->animationIsAccelerated() : false; 1379} 1380 1381// Note: this is inefficient. It's only called from pauseTransitionAtTime(). 1382HashSet<CSSPropertyID> CSSPropertyAnimation::animatableShorthandsAffectingProperty(CSSPropertyID property) 1383{ 1384 CSSPropertyAnimationWrapperMap& map = CSSPropertyAnimationWrapperMap::instance(); 1385 1386 HashSet<CSSPropertyID> foundProperties; 1387 for (unsigned i = 0; i < map.size(); ++i) 1388 gatherEnclosingShorthandProperties(property, map.wrapperForIndex(i), foundProperties); 1389 1390 return foundProperties; 1391} 1392 1393bool CSSPropertyAnimation::propertiesEqual(CSSPropertyID prop, const RenderStyle* a, const RenderStyle* b) 1394{ 1395 AnimationPropertyWrapperBase* wrapper = CSSPropertyAnimationWrapperMap::instance().wrapperForProperty(prop); 1396 if (wrapper) 1397 return wrapper->equals(a, b); 1398 return true; 1399} 1400 1401CSSPropertyID CSSPropertyAnimation::getPropertyAtIndex(int i, bool& isShorthand) 1402{ 1403 CSSPropertyAnimationWrapperMap& map = CSSPropertyAnimationWrapperMap::instance(); 1404 1405 if (i < 0 || static_cast<unsigned>(i) >= map.size()) 1406 return CSSPropertyInvalid; 1407 1408 AnimationPropertyWrapperBase* wrapper = map.wrapperForIndex(i); 1409 isShorthand = wrapper->isShorthandWrapper(); 1410 return wrapper->property(); 1411} 1412 1413int CSSPropertyAnimation::getNumProperties() 1414{ 1415 return CSSPropertyAnimationWrapperMap::instance().size(); 1416} 1417 1418} 1419