1 /* 2 * Copyright (C) 2007, 2008, 2009 Apple Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of 14 * its contributors may be used to endorse or promote products derived 15 * from this software without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY 18 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY 21 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 23 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 24 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 #include "config.h" 30 #include "AnimationBase.h" 31 32 #include "AnimationControllerPrivate.h" 33 #include "CSSMutableStyleDeclaration.h" 34 #include "CSSPropertyLonghand.h" 35 #include "CSSPropertyNames.h" 36 #include "CString.h" 37 #include "CompositeAnimation.h" 38 #include "Document.h" 39 #include "EventNames.h" 40 #include "FloatConversion.h" 41 #include "Frame.h" 42 #include "IdentityTransformOperation.h" 43 #include "ImplicitAnimation.h" 44 #include "KeyframeAnimation.h" 45 #include "MatrixTransformOperation.h" 46 #include "Matrix3DTransformOperation.h" 47 #include "RenderBox.h" 48 #include "RenderLayer.h" 49 #include "RenderLayerBacking.h" 50 #include "RenderStyle.h" 51 #include "UnitBezier.h" 52 53 #include <algorithm> 54 55 using namespace std; 56 57 namespace WebCore { 58 59 // The epsilon value we pass to UnitBezier::solve given that the animation is going to run over |dur| seconds. The longer the 60 // animation, the more precision we need in the timing function result to avoid ugly discontinuities. 61 static inline double solveEpsilon(double duration) 62 { 63 return 1.0 / (200.0 * duration); 64 } 65 66 static inline double solveCubicBezierFunction(double p1x, double p1y, double p2x, double p2y, double t, double duration) 67 { 68 // Convert from input time to parametric value in curve, then from 69 // that to output time. 70 UnitBezier bezier(p1x, p1y, p2x, p2y); 71 return bezier.solve(t, solveEpsilon(duration)); 72 } 73 74 static inline int blendFunc(const AnimationBase*, int from, int to, double progress) 75 { 76 return int(from + (to - from) * progress); 77 } 78 79 static inline double blendFunc(const AnimationBase*, double from, double to, double progress) 80 { 81 return from + (to - from) * progress; 82 } 83 84 static inline float blendFunc(const AnimationBase*, float from, float to, double progress) 85 { 86 return narrowPrecisionToFloat(from + (to - from) * progress); 87 } 88 89 static inline Color blendFunc(const AnimationBase* anim, const Color& from, const Color& to, double progress) 90 { 91 // We need to preserve the state of the valid flag at the end of the animation 92 if (progress == 1 && !to.isValid()) 93 return Color(); 94 95 // Contrary to the name, RGBA32 actually stores ARGB, so we can initialize Color directly from premultipliedARGBFromColor(). 96 // Also, premultipliedARGBFromColor() bails on zero alpha, so special-case that. 97 Color premultFrom = from.alpha() ? premultipliedARGBFromColor(from) : 0; 98 Color premultTo = to.alpha() ? premultipliedARGBFromColor(to) : 0; 99 100 Color premultBlended(blendFunc(anim, premultFrom.red(), premultTo.red(), progress), 101 blendFunc(anim, premultFrom.green(), premultTo.green(), progress), 102 blendFunc(anim, premultFrom.blue(), premultTo.blue(), progress), 103 blendFunc(anim, premultFrom.alpha(), premultTo.alpha(), progress)); 104 105 return Color(colorFromPremultipliedARGB(premultBlended.rgb())); 106 } 107 108 static inline Length blendFunc(const AnimationBase*, const Length& from, const Length& to, double progress) 109 { 110 return to.blend(from, progress); 111 } 112 113 static inline LengthSize blendFunc(const AnimationBase* anim, const LengthSize& from, const LengthSize& to, double progress) 114 { 115 return LengthSize(blendFunc(anim, from.width(), to.width(), progress), 116 blendFunc(anim, from.height(), to.height(), progress)); 117 } 118 119 static inline IntSize blendFunc(const AnimationBase* anim, const IntSize& from, const IntSize& to, double progress) 120 { 121 return IntSize(blendFunc(anim, from.width(), to.width(), progress), 122 blendFunc(anim, from.height(), to.height(), progress)); 123 } 124 125 static inline ShadowStyle blendFunc(const AnimationBase* anim, ShadowStyle from, ShadowStyle to, double progress) 126 { 127 if (from == to) 128 return to; 129 130 double fromVal = from == Normal ? 1 : 0; 131 double toVal = to == Normal ? 1 : 0; 132 double result = blendFunc(anim, fromVal, toVal, progress); 133 return result > 0 ? Normal : Inset; 134 } 135 136 static inline ShadowData* blendFunc(const AnimationBase* anim, const ShadowData* from, const ShadowData* to, double progress) 137 { 138 ASSERT(from && to); 139 return new ShadowData(blendFunc(anim, from->x, to->x, progress), blendFunc(anim, from->y, to->y, progress), 140 blendFunc(anim, from->blur, to->blur, progress), blendFunc(anim, from->spread, to->spread, progress), 141 blendFunc(anim, from->style, to->style, progress), blendFunc(anim, from->color, to->color, progress)); 142 } 143 144 static inline TransformOperations blendFunc(const AnimationBase* anim, const TransformOperations& from, const TransformOperations& to, double progress) 145 { 146 TransformOperations result; 147 148 // If we have a transform function list, use that to do a per-function animation. Otherwise do a Matrix animation 149 if (anim->isTransformFunctionListValid()) { 150 unsigned fromSize = from.operations().size(); 151 unsigned toSize = to.operations().size(); 152 unsigned size = max(fromSize, toSize); 153 for (unsigned i = 0; i < size; i++) { 154 RefPtr<TransformOperation> fromOp = (i < fromSize) ? from.operations()[i].get() : 0; 155 RefPtr<TransformOperation> toOp = (i < toSize) ? to.operations()[i].get() : 0; 156 RefPtr<TransformOperation> blendedOp = toOp ? toOp->blend(fromOp.get(), progress) : (fromOp ? fromOp->blend(0, progress, true) : 0); 157 if (blendedOp) 158 result.operations().append(blendedOp); 159 else { 160 RefPtr<TransformOperation> identityOp = IdentityTransformOperation::create(); 161 if (progress > 0.5) 162 result.operations().append(toOp ? toOp : identityOp); 163 else 164 result.operations().append(fromOp ? fromOp : identityOp); 165 } 166 } 167 } else { 168 // Convert the TransformOperations into matrices 169 IntSize size = anim->renderer()->isBox() ? toRenderBox(anim->renderer())->borderBoxRect().size() : IntSize(); 170 TransformationMatrix fromT; 171 TransformationMatrix toT; 172 from.apply(size, fromT); 173 to.apply(size, toT); 174 175 toT.blend(fromT, progress); 176 177 // Append the result 178 result.operations().append(Matrix3DTransformOperation::create(toT)); 179 } 180 return result; 181 } 182 183 static inline EVisibility blendFunc(const AnimationBase* anim, EVisibility from, EVisibility to, double progress) 184 { 185 // Any non-zero result means we consider the object to be visible. Only at 0 do we consider the object to be 186 // invisible. The invisible value we use (HIDDEN vs. COLLAPSE) depends on the specified from/to values. 187 double fromVal = from == VISIBLE ? 1. : 0.; 188 double toVal = to == VISIBLE ? 1. : 0.; 189 if (fromVal == toVal) 190 return to; 191 double result = blendFunc(anim, fromVal, toVal, progress); 192 return result > 0. ? VISIBLE : (to != VISIBLE ? to : from); 193 } 194 195 class PropertyWrapperBase; 196 197 static void addShorthandProperties(); 198 static PropertyWrapperBase* wrapperForProperty(int propertyID); 199 200 class PropertyWrapperBase : public Noncopyable { 201 public: 202 PropertyWrapperBase(int prop) 203 : m_prop(prop) 204 { 205 } 206 207 virtual ~PropertyWrapperBase() { } 208 209 virtual bool isShorthandWrapper() const { return false; } 210 virtual bool equals(const RenderStyle* a, const RenderStyle* b) const = 0; 211 virtual void blend(const AnimationBase* anim, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress) const = 0; 212 213 int property() const { return m_prop; } 214 215 #if USE(ACCELERATED_COMPOSITING) 216 virtual bool animationIsAccelerated() const { return false; } 217 #endif 218 219 private: 220 int m_prop; 221 }; 222 223 template <typename T> 224 class PropertyWrapperGetter : public PropertyWrapperBase { 225 public: 226 PropertyWrapperGetter(int prop, T (RenderStyle::*getter)() const) 227 : PropertyWrapperBase(prop) 228 , m_getter(getter) 229 { 230 } 231 232 virtual bool equals(const RenderStyle* a, const RenderStyle* b) const 233 { 234 // If the style pointers are the same, don't bother doing the test. 235 // If either is null, return false. If both are null, return true. 236 if ((!a && !b) || a == b) 237 return true; 238 if (!a || !b) 239 return false; 240 return (a->*m_getter)() == (b->*m_getter)(); 241 } 242 243 protected: 244 T (RenderStyle::*m_getter)() const; 245 }; 246 247 template <typename T> 248 class PropertyWrapper : public PropertyWrapperGetter<T> { 249 public: 250 PropertyWrapper(int prop, T (RenderStyle::*getter)() const, void (RenderStyle::*setter)(T)) 251 : PropertyWrapperGetter<T>(prop, getter) 252 , m_setter(setter) 253 { 254 } 255 256 virtual void blend(const AnimationBase* anim, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress) const 257 { 258 (dst->*m_setter)(blendFunc(anim, (a->*PropertyWrapperGetter<T>::m_getter)(), (b->*PropertyWrapperGetter<T>::m_getter)(), progress)); 259 } 260 261 protected: 262 void (RenderStyle::*m_setter)(T); 263 }; 264 265 #if USE(ACCELERATED_COMPOSITING) 266 class PropertyWrapperAcceleratedOpacity : public PropertyWrapper<float> { 267 public: 268 PropertyWrapperAcceleratedOpacity() 269 : PropertyWrapper<float>(CSSPropertyOpacity, &RenderStyle::opacity, &RenderStyle::setOpacity) 270 { 271 } 272 273 virtual bool animationIsAccelerated() const { return true; } 274 275 virtual void blend(const AnimationBase* anim, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress) const 276 { 277 float fromOpacity = a->opacity(); 278 279 // This makes sure we put the object being animated into a RenderLayer during the animation 280 dst->setOpacity(blendFunc(anim, (fromOpacity == 1) ? 0.999999f : fromOpacity, b->opacity(), progress)); 281 } 282 }; 283 284 class PropertyWrapperAcceleratedTransform : public PropertyWrapper<const TransformOperations&> { 285 public: 286 PropertyWrapperAcceleratedTransform() 287 : PropertyWrapper<const TransformOperations&>(CSSPropertyWebkitTransform, &RenderStyle::transform, &RenderStyle::setTransform) 288 { 289 } 290 291 virtual bool animationIsAccelerated() const { return true; } 292 293 virtual void blend(const AnimationBase* anim, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress) const 294 { 295 dst->setTransform(blendFunc(anim, a->transform(), b->transform(), progress)); 296 } 297 }; 298 #endif // USE(ACCELERATED_COMPOSITING) 299 300 class PropertyWrapperShadow : public PropertyWrapperGetter<ShadowData*> { 301 public: 302 PropertyWrapperShadow(int prop, ShadowData* (RenderStyle::*getter)() const, void (RenderStyle::*setter)(ShadowData*, bool)) 303 : PropertyWrapperGetter<ShadowData*>(prop, getter) 304 , m_setter(setter) 305 { 306 } 307 308 virtual bool equals(const RenderStyle* a, const RenderStyle* b) const 309 { 310 ShadowData* shadowA = (a->*m_getter)(); 311 ShadowData* shadowB = (b->*m_getter)(); 312 313 while (true) { 314 if (!shadowA && !shadowB) // end of both lists 315 return true; 316 317 if (!shadowA || !shadowB) // end of just one of the lists 318 return false; 319 320 if (*shadowA != *shadowB) 321 return false; 322 323 shadowA = shadowA->next; 324 shadowB = shadowB->next; 325 } 326 327 return true; 328 } 329 330 virtual void blend(const AnimationBase* anim, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress) const 331 { 332 ShadowData* shadowA = (a->*m_getter)(); 333 ShadowData* shadowB = (b->*m_getter)(); 334 ShadowData defaultShadowData(0, 0, 0, 0, Normal, Color::transparent); 335 336 ShadowData* newShadowData = 0; 337 338 while (shadowA || shadowB) { 339 ShadowData* srcShadow = shadowA ? shadowA : &defaultShadowData; 340 ShadowData* dstShadow = shadowB ? shadowB : &defaultShadowData; 341 342 if (!newShadowData) 343 newShadowData = blendFunc(anim, srcShadow, dstShadow, progress); 344 else 345 newShadowData->next = blendFunc(anim, srcShadow, dstShadow, progress); 346 347 shadowA = shadowA ? shadowA->next : 0; 348 shadowB = shadowB ? shadowB->next : 0; 349 } 350 351 (dst->*m_setter)(newShadowData, false); 352 } 353 354 private: 355 void (RenderStyle::*m_setter)(ShadowData*, bool); 356 }; 357 358 class PropertyWrapperMaybeInvalidColor : public PropertyWrapperBase { 359 public: 360 PropertyWrapperMaybeInvalidColor(int prop, const Color& (RenderStyle::*getter)() const, void (RenderStyle::*setter)(const Color&)) 361 : PropertyWrapperBase(prop) 362 , m_getter(getter) 363 , m_setter(setter) 364 { 365 } 366 367 virtual bool equals(const RenderStyle* a, const RenderStyle* b) const 368 { 369 Color fromColor = (a->*m_getter)(); 370 Color toColor = (b->*m_getter)(); 371 372 if (!fromColor.isValid() && !toColor.isValid()) 373 return true; 374 375 if (!fromColor.isValid()) 376 fromColor = a->color(); 377 if (!toColor.isValid()) 378 toColor = b->color(); 379 380 return fromColor == toColor; 381 } 382 383 virtual void blend(const AnimationBase* anim, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress) const 384 { 385 Color fromColor = (a->*m_getter)(); 386 Color toColor = (b->*m_getter)(); 387 388 if (!fromColor.isValid() && !toColor.isValid()) 389 return; 390 391 if (!fromColor.isValid()) 392 fromColor = a->color(); 393 if (!toColor.isValid()) 394 toColor = b->color(); 395 (dst->*m_setter)(blendFunc(anim, fromColor, toColor, progress)); 396 } 397 398 private: 399 const Color& (RenderStyle::*m_getter)() const; 400 void (RenderStyle::*m_setter)(const Color&); 401 }; 402 403 // Wrapper base class for an animatable property in a FillLayer 404 class FillLayerPropertyWrapperBase { 405 public: 406 FillLayerPropertyWrapperBase() 407 { 408 } 409 410 virtual ~FillLayerPropertyWrapperBase() { } 411 412 virtual bool equals(const FillLayer* a, const FillLayer* b) const = 0; 413 virtual void blend(const AnimationBase* anim, FillLayer* dst, const FillLayer* a, const FillLayer* b, double progress) const = 0; 414 }; 415 416 template <typename T> 417 class FillLayerPropertyWrapperGetter : public FillLayerPropertyWrapperBase, public Noncopyable { 418 public: 419 FillLayerPropertyWrapperGetter(T (FillLayer::*getter)() const) 420 : m_getter(getter) 421 { 422 } 423 424 virtual bool equals(const FillLayer* a, const FillLayer* b) const 425 { 426 // If the style pointers are the same, don't bother doing the test. 427 // If either is null, return false. If both are null, return true. 428 if ((!a && !b) || a == b) 429 return true; 430 if (!a || !b) 431 return false; 432 return (a->*m_getter)() == (b->*m_getter)(); 433 } 434 435 protected: 436 T (FillLayer::*m_getter)() const; 437 }; 438 439 template <typename T> 440 class FillLayerPropertyWrapper : public FillLayerPropertyWrapperGetter<T> { 441 public: 442 FillLayerPropertyWrapper(T (FillLayer::*getter)() const, void (FillLayer::*setter)(T)) 443 : FillLayerPropertyWrapperGetter<T>(getter) 444 , m_setter(setter) 445 { 446 } 447 448 virtual void blend(const AnimationBase* anim, FillLayer* dst, const FillLayer* a, const FillLayer* b, double progress) const 449 { 450 (dst->*m_setter)(blendFunc(anim, (a->*FillLayerPropertyWrapperGetter<T>::m_getter)(), (b->*FillLayerPropertyWrapperGetter<T>::m_getter)(), progress)); 451 } 452 453 protected: 454 void (FillLayer::*m_setter)(T); 455 }; 456 457 458 class FillLayersPropertyWrapper : public PropertyWrapperBase { 459 public: 460 typedef const FillLayer* (RenderStyle::*LayersGetter)() const; 461 typedef FillLayer* (RenderStyle::*LayersAccessor)(); 462 463 FillLayersPropertyWrapper(int prop, LayersGetter getter, LayersAccessor accessor) 464 : PropertyWrapperBase(prop) 465 , m_layersGetter(getter) 466 , m_layersAccessor(accessor) 467 { 468 switch (prop) { 469 case CSSPropertyBackgroundPositionX: 470 case CSSPropertyWebkitMaskPositionX: 471 m_fillLayerPropertyWrapper = new FillLayerPropertyWrapper<Length>(&FillLayer::xPosition, &FillLayer::setXPosition); 472 break; 473 case CSSPropertyBackgroundPositionY: 474 case CSSPropertyWebkitMaskPositionY: 475 m_fillLayerPropertyWrapper = new FillLayerPropertyWrapper<Length>(&FillLayer::yPosition, &FillLayer::setYPosition); 476 break; 477 case CSSPropertyBackgroundSize: 478 case CSSPropertyWebkitBackgroundSize: 479 case CSSPropertyWebkitMaskSize: 480 m_fillLayerPropertyWrapper = new FillLayerPropertyWrapper<LengthSize>(&FillLayer::sizeLength, &FillLayer::setSizeLength); 481 break; 482 } 483 } 484 485 virtual bool equals(const RenderStyle* a, const RenderStyle* b) const 486 { 487 const FillLayer* fromLayer = (a->*m_layersGetter)(); 488 const FillLayer* toLayer = (b->*m_layersGetter)(); 489 490 while (fromLayer && toLayer) { 491 if (!m_fillLayerPropertyWrapper->equals(fromLayer, toLayer)) 492 return false; 493 494 fromLayer = fromLayer->next(); 495 toLayer = toLayer->next(); 496 } 497 498 return true; 499 } 500 501 virtual void blend(const AnimationBase* anim, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress) const 502 { 503 const FillLayer* aLayer = (a->*m_layersGetter)(); 504 const FillLayer* bLayer = (b->*m_layersGetter)(); 505 FillLayer* dstLayer = (dst->*m_layersAccessor)(); 506 507 while (aLayer && bLayer && dstLayer) { 508 m_fillLayerPropertyWrapper->blend(anim, dstLayer, aLayer, bLayer, progress); 509 aLayer = aLayer->next(); 510 bLayer = bLayer->next(); 511 dstLayer = dstLayer->next(); 512 } 513 } 514 515 private: 516 FillLayerPropertyWrapperBase* m_fillLayerPropertyWrapper; 517 518 LayersGetter m_layersGetter; 519 LayersAccessor m_layersAccessor; 520 }; 521 522 class ShorthandPropertyWrapper : public PropertyWrapperBase { 523 public: 524 ShorthandPropertyWrapper(int property, const CSSPropertyLonghand& longhand) 525 : PropertyWrapperBase(property) 526 { 527 for (unsigned i = 0; i < longhand.length(); ++i) { 528 PropertyWrapperBase* wrapper = wrapperForProperty(longhand.properties()[i]); 529 if (wrapper) 530 m_propertyWrappers.append(wrapper); 531 } 532 } 533 534 virtual bool isShorthandWrapper() const { return true; } 535 536 virtual bool equals(const RenderStyle* a, const RenderStyle* b) const 537 { 538 Vector<PropertyWrapperBase*>::const_iterator end = m_propertyWrappers.end(); 539 for (Vector<PropertyWrapperBase*>::const_iterator it = m_propertyWrappers.begin(); it != end; ++it) { 540 if (!(*it)->equals(a, b)) 541 return false; 542 } 543 return true; 544 } 545 546 virtual void blend(const AnimationBase* anim, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress) const 547 { 548 Vector<PropertyWrapperBase*>::const_iterator end = m_propertyWrappers.end(); 549 for (Vector<PropertyWrapperBase*>::const_iterator it = m_propertyWrappers.begin(); it != end; ++it) 550 (*it)->blend(anim, dst, a, b, progress); 551 } 552 553 private: 554 Vector<PropertyWrapperBase*> m_propertyWrappers; 555 }; 556 557 558 static Vector<PropertyWrapperBase*>* gPropertyWrappers = 0; 559 static int gPropertyWrapperMap[numCSSProperties]; 560 561 static const int cInvalidPropertyWrapperIndex = -1; 562 563 564 static void ensurePropertyMap() 565 { 566 // FIXME: This data is never destroyed. Maybe we should ref count it and toss it when the last AnimationController is destroyed? 567 if (gPropertyWrappers == 0) { 568 gPropertyWrappers = new Vector<PropertyWrapperBase*>(); 569 570 // build the list of property wrappers to do the comparisons and blends 571 gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyLeft, &RenderStyle::left, &RenderStyle::setLeft)); 572 gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyRight, &RenderStyle::right, &RenderStyle::setRight)); 573 gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyTop, &RenderStyle::top, &RenderStyle::setTop)); 574 gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyBottom, &RenderStyle::bottom, &RenderStyle::setBottom)); 575 576 gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyWidth, &RenderStyle::width, &RenderStyle::setWidth)); 577 gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyMinWidth, &RenderStyle::minWidth, &RenderStyle::setMinWidth)); 578 gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyMaxWidth, &RenderStyle::maxWidth, &RenderStyle::setMaxWidth)); 579 580 gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyHeight, &RenderStyle::height, &RenderStyle::setHeight)); 581 gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyMinHeight, &RenderStyle::minHeight, &RenderStyle::setMinHeight)); 582 gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyMaxHeight, &RenderStyle::maxHeight, &RenderStyle::setMaxHeight)); 583 584 gPropertyWrappers->append(new PropertyWrapper<unsigned short>(CSSPropertyBorderLeftWidth, &RenderStyle::borderLeftWidth, &RenderStyle::setBorderLeftWidth)); 585 gPropertyWrappers->append(new PropertyWrapper<unsigned short>(CSSPropertyBorderRightWidth, &RenderStyle::borderRightWidth, &RenderStyle::setBorderRightWidth)); 586 gPropertyWrappers->append(new PropertyWrapper<unsigned short>(CSSPropertyBorderTopWidth, &RenderStyle::borderTopWidth, &RenderStyle::setBorderTopWidth)); 587 gPropertyWrappers->append(new PropertyWrapper<unsigned short>(CSSPropertyBorderBottomWidth, &RenderStyle::borderBottomWidth, &RenderStyle::setBorderBottomWidth)); 588 gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyMarginLeft, &RenderStyle::marginLeft, &RenderStyle::setMarginLeft)); 589 gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyMarginRight, &RenderStyle::marginRight, &RenderStyle::setMarginRight)); 590 gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyMarginTop, &RenderStyle::marginTop, &RenderStyle::setMarginTop)); 591 gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyMarginBottom, &RenderStyle::marginBottom, &RenderStyle::setMarginBottom)); 592 gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyPaddingLeft, &RenderStyle::paddingLeft, &RenderStyle::setPaddingLeft)); 593 gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyPaddingRight, &RenderStyle::paddingRight, &RenderStyle::setPaddingRight)); 594 gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyPaddingTop, &RenderStyle::paddingTop, &RenderStyle::setPaddingTop)); 595 gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyPaddingBottom, &RenderStyle::paddingBottom, &RenderStyle::setPaddingBottom)); 596 gPropertyWrappers->append(new PropertyWrapper<const Color&>(CSSPropertyColor, &RenderStyle::color, &RenderStyle::setColor)); 597 598 gPropertyWrappers->append(new PropertyWrapper<const Color&>(CSSPropertyBackgroundColor, &RenderStyle::backgroundColor, &RenderStyle::setBackgroundColor)); 599 600 gPropertyWrappers->append(new FillLayersPropertyWrapper(CSSPropertyBackgroundPositionX, &RenderStyle::backgroundLayers, &RenderStyle::accessBackgroundLayers)); 601 gPropertyWrappers->append(new FillLayersPropertyWrapper(CSSPropertyBackgroundPositionY, &RenderStyle::backgroundLayers, &RenderStyle::accessBackgroundLayers)); 602 gPropertyWrappers->append(new FillLayersPropertyWrapper(CSSPropertyBackgroundSize, &RenderStyle::backgroundLayers, &RenderStyle::accessBackgroundLayers)); 603 gPropertyWrappers->append(new FillLayersPropertyWrapper(CSSPropertyWebkitBackgroundSize, &RenderStyle::backgroundLayers, &RenderStyle::accessBackgroundLayers)); 604 605 gPropertyWrappers->append(new FillLayersPropertyWrapper(CSSPropertyWebkitMaskPositionX, &RenderStyle::maskLayers, &RenderStyle::accessMaskLayers)); 606 gPropertyWrappers->append(new FillLayersPropertyWrapper(CSSPropertyWebkitMaskPositionY, &RenderStyle::maskLayers, &RenderStyle::accessMaskLayers)); 607 gPropertyWrappers->append(new FillLayersPropertyWrapper(CSSPropertyWebkitMaskSize, &RenderStyle::maskLayers, &RenderStyle::accessMaskLayers)); 608 609 gPropertyWrappers->append(new PropertyWrapper<int>(CSSPropertyFontSize, &RenderStyle::fontSize, &RenderStyle::setBlendedFontSize)); 610 gPropertyWrappers->append(new PropertyWrapper<unsigned short>(CSSPropertyWebkitColumnRuleWidth, &RenderStyle::columnRuleWidth, &RenderStyle::setColumnRuleWidth)); 611 gPropertyWrappers->append(new PropertyWrapper<float>(CSSPropertyWebkitColumnGap, &RenderStyle::columnGap, &RenderStyle::setColumnGap)); 612 gPropertyWrappers->append(new PropertyWrapper<unsigned short>(CSSPropertyWebkitColumnCount, &RenderStyle::columnCount, &RenderStyle::setColumnCount)); 613 gPropertyWrappers->append(new PropertyWrapper<float>(CSSPropertyWebkitColumnWidth, &RenderStyle::columnWidth, &RenderStyle::setColumnWidth)); 614 gPropertyWrappers->append(new PropertyWrapper<short>(CSSPropertyWebkitBorderHorizontalSpacing, &RenderStyle::horizontalBorderSpacing, &RenderStyle::setHorizontalBorderSpacing)); 615 gPropertyWrappers->append(new PropertyWrapper<short>(CSSPropertyWebkitBorderVerticalSpacing, &RenderStyle::verticalBorderSpacing, &RenderStyle::setVerticalBorderSpacing)); 616 gPropertyWrappers->append(new PropertyWrapper<int>(CSSPropertyZIndex, &RenderStyle::zIndex, &RenderStyle::setZIndex)); 617 gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyLineHeight, &RenderStyle::lineHeight, &RenderStyle::setLineHeight)); 618 gPropertyWrappers->append(new PropertyWrapper<int>(CSSPropertyOutlineOffset, &RenderStyle::outlineOffset, &RenderStyle::setOutlineOffset)); 619 gPropertyWrappers->append(new PropertyWrapper<unsigned short>(CSSPropertyOutlineWidth, &RenderStyle::outlineWidth, &RenderStyle::setOutlineWidth)); 620 gPropertyWrappers->append(new PropertyWrapper<int>(CSSPropertyLetterSpacing, &RenderStyle::letterSpacing, &RenderStyle::setLetterSpacing)); 621 gPropertyWrappers->append(new PropertyWrapper<int>(CSSPropertyWordSpacing, &RenderStyle::wordSpacing, &RenderStyle::setWordSpacing)); 622 gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyTextIndent, &RenderStyle::textIndent, &RenderStyle::setTextIndent)); 623 624 gPropertyWrappers->append(new PropertyWrapper<float>(CSSPropertyWebkitPerspective, &RenderStyle::perspective, &RenderStyle::setPerspective)); 625 gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyWebkitPerspectiveOriginX, &RenderStyle::perspectiveOriginX, &RenderStyle::setPerspectiveOriginX)); 626 gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyWebkitPerspectiveOriginY, &RenderStyle::perspectiveOriginY, &RenderStyle::setPerspectiveOriginY)); 627 gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyWebkitTransformOriginX, &RenderStyle::transformOriginX, &RenderStyle::setTransformOriginX)); 628 gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyWebkitTransformOriginY, &RenderStyle::transformOriginY, &RenderStyle::setTransformOriginY)); 629 gPropertyWrappers->append(new PropertyWrapper<float>(CSSPropertyWebkitTransformOriginZ, &RenderStyle::transformOriginZ, &RenderStyle::setTransformOriginZ)); 630 gPropertyWrappers->append(new PropertyWrapper<const IntSize&>(CSSPropertyBorderTopLeftRadius, &RenderStyle::borderTopLeftRadius, &RenderStyle::setBorderTopLeftRadius)); 631 gPropertyWrappers->append(new PropertyWrapper<const IntSize&>(CSSPropertyBorderTopRightRadius, &RenderStyle::borderTopRightRadius, &RenderStyle::setBorderTopRightRadius)); 632 gPropertyWrappers->append(new PropertyWrapper<const IntSize&>(CSSPropertyBorderBottomLeftRadius, &RenderStyle::borderBottomLeftRadius, &RenderStyle::setBorderBottomLeftRadius)); 633 gPropertyWrappers->append(new PropertyWrapper<const IntSize&>(CSSPropertyBorderBottomRightRadius, &RenderStyle::borderBottomRightRadius, &RenderStyle::setBorderBottomRightRadius)); 634 gPropertyWrappers->append(new PropertyWrapper<EVisibility>(CSSPropertyVisibility, &RenderStyle::visibility, &RenderStyle::setVisibility)); 635 gPropertyWrappers->append(new PropertyWrapper<float>(CSSPropertyZoom, &RenderStyle::zoom, &RenderStyle::setZoom)); 636 637 #if USE(ACCELERATED_COMPOSITING) 638 gPropertyWrappers->append(new PropertyWrapperAcceleratedOpacity()); 639 gPropertyWrappers->append(new PropertyWrapperAcceleratedTransform()); 640 #else 641 gPropertyWrappers->append(new PropertyWrapper<float>(CSSPropertyOpacity, &RenderStyle::opacity, &RenderStyle::setOpacity)); 642 gPropertyWrappers->append(new PropertyWrapper<const TransformOperations&>(CSSPropertyWebkitTransform, &RenderStyle::transform, &RenderStyle::setTransform)); 643 #endif 644 645 gPropertyWrappers->append(new PropertyWrapperMaybeInvalidColor(CSSPropertyWebkitColumnRuleColor, &RenderStyle::columnRuleColor, &RenderStyle::setColumnRuleColor)); 646 gPropertyWrappers->append(new PropertyWrapperMaybeInvalidColor(CSSPropertyWebkitTextStrokeColor, &RenderStyle::textStrokeColor, &RenderStyle::setTextStrokeColor)); 647 gPropertyWrappers->append(new PropertyWrapperMaybeInvalidColor(CSSPropertyWebkitTextFillColor, &RenderStyle::textFillColor, &RenderStyle::setTextFillColor)); 648 gPropertyWrappers->append(new PropertyWrapperMaybeInvalidColor(CSSPropertyBorderLeftColor, &RenderStyle::borderLeftColor, &RenderStyle::setBorderLeftColor)); 649 gPropertyWrappers->append(new PropertyWrapperMaybeInvalidColor(CSSPropertyBorderRightColor, &RenderStyle::borderRightColor, &RenderStyle::setBorderRightColor)); 650 gPropertyWrappers->append(new PropertyWrapperMaybeInvalidColor(CSSPropertyBorderTopColor, &RenderStyle::borderTopColor, &RenderStyle::setBorderTopColor)); 651 gPropertyWrappers->append(new PropertyWrapperMaybeInvalidColor(CSSPropertyBorderBottomColor, &RenderStyle::borderBottomColor, &RenderStyle::setBorderBottomColor)); 652 gPropertyWrappers->append(new PropertyWrapperMaybeInvalidColor(CSSPropertyOutlineColor, &RenderStyle::outlineColor, &RenderStyle::setOutlineColor)); 653 654 // These are for shadows 655 gPropertyWrappers->append(new PropertyWrapperShadow(CSSPropertyWebkitBoxShadow, &RenderStyle::boxShadow, &RenderStyle::setBoxShadow)); 656 gPropertyWrappers->append(new PropertyWrapperShadow(CSSPropertyTextShadow, &RenderStyle::textShadow, &RenderStyle::setTextShadow)); 657 658 #if ENABLE(SVG) 659 gPropertyWrappers->append(new PropertyWrapper<float>(CSSPropertyFillOpacity, &RenderStyle::fillOpacity, &RenderStyle::setFillOpacity)); 660 gPropertyWrappers->append(new PropertyWrapper<float>(CSSPropertyFloodOpacity, &RenderStyle::floodOpacity, &RenderStyle::setFloodOpacity)); 661 gPropertyWrappers->append(new PropertyWrapper<float>(CSSPropertyStrokeOpacity, &RenderStyle::strokeOpacity, &RenderStyle::setStrokeOpacity)); 662 #endif 663 664 // TODO: 665 // 666 // CSSPropertyVerticalAlign 667 // 668 // Compound properties that have components that should be animatable: 669 // 670 // CSSPropertyWebkitColumns 671 // CSSPropertyWebkitBoxReflect 672 673 // Make sure unused slots have a value 674 for (unsigned int i = 0; i < static_cast<unsigned int>(numCSSProperties); ++i) 675 gPropertyWrapperMap[i] = cInvalidPropertyWrapperIndex; 676 677 // First we put the non-shorthand property wrappers into the map, so the shorthand-building 678 // code can find them. 679 size_t n = gPropertyWrappers->size(); 680 for (unsigned int i = 0; i < n; ++i) { 681 ASSERT((*gPropertyWrappers)[i]->property() - firstCSSProperty < numCSSProperties); 682 gPropertyWrapperMap[(*gPropertyWrappers)[i]->property() - firstCSSProperty] = i; 683 } 684 685 // Now add the shorthand wrappers. 686 addShorthandProperties(); 687 } 688 } 689 690 static void addPropertyWrapper(int propertyID, PropertyWrapperBase* wrapper) 691 { 692 int propIndex = propertyID - firstCSSProperty; 693 694 ASSERT(gPropertyWrapperMap[propIndex] == cInvalidPropertyWrapperIndex); 695 696 unsigned wrapperIndex = gPropertyWrappers->size(); 697 gPropertyWrappers->append(wrapper); 698 gPropertyWrapperMap[propIndex] = wrapperIndex; 699 } 700 701 static void addShorthandProperties() 702 { 703 static const int animatableShorthandProperties[] = { 704 CSSPropertyBackground, // for background-color, background-position 705 CSSPropertyBackgroundPosition, 706 CSSPropertyWebkitMask, // for mask-position 707 CSSPropertyWebkitMaskPosition, 708 CSSPropertyBorderTop, CSSPropertyBorderRight, CSSPropertyBorderBottom, CSSPropertyBorderLeft, 709 CSSPropertyBorderColor, 710 CSSPropertyBorderWidth, 711 CSSPropertyBorder, 712 CSSPropertyBorderSpacing, 713 CSSPropertyMargin, 714 CSSPropertyOutline, 715 CSSPropertyPadding, 716 CSSPropertyWebkitTextStroke, 717 CSSPropertyWebkitColumnRule, 718 CSSPropertyWebkitBorderRadius, 719 CSSPropertyWebkitTransformOrigin 720 }; 721 722 for (unsigned i = 0; i < sizeof(animatableShorthandProperties) / sizeof(animatableShorthandProperties[0]); ++i) { 723 int propertyID = animatableShorthandProperties[i]; 724 CSSPropertyLonghand longhand = longhandForProperty(propertyID); 725 if (longhand.length() > 0) 726 addPropertyWrapper(propertyID, new ShorthandPropertyWrapper(propertyID, longhand)); 727 } 728 729 // 'font' is not in the shorthand map. 730 static const int animatableFontProperties[] = { 731 CSSPropertyFontSize, 732 CSSPropertyFontWeight 733 }; 734 735 CSSPropertyLonghand fontLonghand(animatableFontProperties, sizeof(animatableFontProperties) / sizeof(animatableFontProperties[0])); 736 addPropertyWrapper(CSSPropertyFont, new ShorthandPropertyWrapper(CSSPropertyFont, fontLonghand)); 737 } 738 739 static PropertyWrapperBase* wrapperForProperty(int propertyID) 740 { 741 int propIndex = propertyID - firstCSSProperty; 742 if (propIndex >= 0 && propIndex < numCSSProperties) { 743 int wrapperIndex = gPropertyWrapperMap[propIndex]; 744 if (wrapperIndex >= 0) 745 return (*gPropertyWrappers)[wrapperIndex]; 746 } 747 return 0; 748 } 749 750 AnimationBase::AnimationBase(const Animation* transition, RenderObject* renderer, CompositeAnimation* compAnim) 751 : m_animState(AnimationStateNew) 752 , m_isAnimating(false) 753 , m_startTime(0) 754 , m_pauseTime(-1) 755 , m_requestedStartTime(0) 756 , m_object(renderer) 757 , m_animation(const_cast<Animation*>(transition)) 758 , m_compAnim(compAnim) 759 , m_fallbackAnimating(false) 760 , m_transformFunctionListValid(false) 761 , m_nextIterationDuration(-1) 762 , m_next(0) 763 { 764 // Compute the total duration 765 m_totalDuration = -1; 766 if (m_animation->iterationCount() > 0) 767 m_totalDuration = m_animation->duration() * m_animation->iterationCount(); 768 } 769 770 AnimationBase::~AnimationBase() 771 { 772 m_compAnim->animationController()->removeFromStyleAvailableWaitList(this); 773 m_compAnim->animationController()->removeFromStartTimeResponseWaitList(this); 774 } 775 776 bool AnimationBase::propertiesEqual(int prop, const RenderStyle* a, const RenderStyle* b) 777 { 778 ensurePropertyMap(); 779 if (prop == cAnimateAll) { 780 size_t n = gPropertyWrappers->size(); 781 for (unsigned int i = 0; i < n; ++i) { 782 PropertyWrapperBase* wrapper = (*gPropertyWrappers)[i]; 783 // No point comparing shorthand wrappers for 'all'. 784 if (!wrapper->isShorthandWrapper() && !wrapper->equals(a, b)) 785 return false; 786 } 787 } else { 788 PropertyWrapperBase* wrapper = wrapperForProperty(prop); 789 if (wrapper) 790 return wrapper->equals(a, b); 791 } 792 return true; 793 } 794 795 int AnimationBase::getPropertyAtIndex(int i, bool& isShorthand) 796 { 797 ensurePropertyMap(); 798 if (i < 0 || i >= static_cast<int>(gPropertyWrappers->size())) 799 return CSSPropertyInvalid; 800 801 PropertyWrapperBase* wrapper = (*gPropertyWrappers)[i]; 802 isShorthand = wrapper->isShorthandWrapper(); 803 return wrapper->property(); 804 } 805 806 int AnimationBase::getNumProperties() 807 { 808 ensurePropertyMap(); 809 return gPropertyWrappers->size(); 810 } 811 812 // Returns true if we need to start animation timers 813 bool AnimationBase::blendProperties(const AnimationBase* anim, int prop, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress) 814 { 815 ASSERT(prop != cAnimateAll); 816 817 ensurePropertyMap(); 818 PropertyWrapperBase* wrapper = wrapperForProperty(prop); 819 if (wrapper) { 820 wrapper->blend(anim, dst, a, b, progress); 821 #if USE(ACCELERATED_COMPOSITING) 822 return !wrapper->animationIsAccelerated() || anim->isFallbackAnimating(); 823 #else 824 return true; 825 #endif 826 } 827 828 return false; 829 } 830 831 #if USE(ACCELERATED_COMPOSITING) 832 bool AnimationBase::animationOfPropertyIsAccelerated(int prop) 833 { 834 ensurePropertyMap(); 835 PropertyWrapperBase* wrapper = wrapperForProperty(prop); 836 return wrapper ? wrapper->animationIsAccelerated() : false; 837 } 838 #endif 839 840 void AnimationBase::setNeedsStyleRecalc(Node* node) 841 { 842 ASSERT(!node || (node->document() && !node->document()->inPageCache())); 843 if (node) 844 node->setNeedsStyleRecalc(SyntheticStyleChange); 845 } 846 847 double AnimationBase::duration() const 848 { 849 return m_animation->duration(); 850 } 851 852 bool AnimationBase::playStatePlaying() const 853 { 854 return m_animation->playState() == AnimPlayStatePlaying; 855 } 856 857 bool AnimationBase::animationsMatch(const Animation* anim) const 858 { 859 return m_animation->animationsMatch(anim); 860 } 861 862 void AnimationBase::updateStateMachine(AnimStateInput input, double param) 863 { 864 // If we get AnimationStateInputRestartAnimation then we force a new animation, regardless of state. 865 if (input == AnimationStateInputMakeNew) { 866 if (m_animState == AnimationStateStartWaitStyleAvailable) 867 m_compAnim->animationController()->removeFromStyleAvailableWaitList(this); 868 m_animState = AnimationStateNew; 869 m_startTime = 0; 870 m_pauseTime = -1; 871 m_requestedStartTime = 0; 872 m_nextIterationDuration = -1; 873 endAnimation(); 874 return; 875 } 876 877 if (input == AnimationStateInputRestartAnimation) { 878 if (m_animState == AnimationStateStartWaitStyleAvailable) 879 m_compAnim->animationController()->removeFromStyleAvailableWaitList(this); 880 m_animState = AnimationStateNew; 881 m_startTime = 0; 882 m_pauseTime = -1; 883 m_requestedStartTime = 0; 884 m_nextIterationDuration = -1; 885 endAnimation(); 886 887 if (!paused()) 888 updateStateMachine(AnimationStateInputStartAnimation, -1); 889 return; 890 } 891 892 if (input == AnimationStateInputEndAnimation) { 893 if (m_animState == AnimationStateStartWaitStyleAvailable) 894 m_compAnim->animationController()->removeFromStyleAvailableWaitList(this); 895 m_animState = AnimationStateDone; 896 endAnimation(); 897 return; 898 } 899 900 if (input == AnimationStateInputPauseOverride) { 901 if (m_animState == AnimationStateStartWaitResponse) { 902 // If we are in AnimationStateStartWaitResponse, the animation will get canceled before 903 // we get a response, so move to the next state. 904 endAnimation(); 905 updateStateMachine(AnimationStateInputStartTimeSet, beginAnimationUpdateTime()); 906 } 907 return; 908 } 909 910 if (input == AnimationStateInputResumeOverride) { 911 if (m_animState == AnimationStateLooping || m_animState == AnimationStateEnding) { 912 // Start the animation 913 startAnimation(beginAnimationUpdateTime() - m_startTime); 914 } 915 return; 916 } 917 918 // Execute state machine 919 switch (m_animState) { 920 case AnimationStateNew: 921 ASSERT(input == AnimationStateInputStartAnimation || input == AnimationStateInputPlayStateRunnning || input == AnimationStateInputPlayStatePaused); 922 if (input == AnimationStateInputStartAnimation || input == AnimationStateInputPlayStateRunnning) { 923 m_requestedStartTime = beginAnimationUpdateTime(); 924 m_animState = AnimationStateStartWaitTimer; 925 } 926 break; 927 case AnimationStateStartWaitTimer: 928 ASSERT(input == AnimationStateInputStartTimerFired || input == AnimationStateInputPlayStatePaused); 929 930 if (input == AnimationStateInputStartTimerFired) { 931 ASSERT(param >= 0); 932 // Start timer has fired, tell the animation to start and wait for it to respond with start time 933 m_animState = AnimationStateStartWaitStyleAvailable; 934 m_compAnim->animationController()->addToStyleAvailableWaitList(this); 935 936 // Trigger a render so we can start the animation 937 if (m_object) 938 m_compAnim->animationController()->addNodeChangeToDispatch(m_object->node()); 939 } else { 940 ASSERT(!paused()); 941 // We're waiting for the start timer to fire and we got a pause. Cancel the timer, pause and wait 942 m_pauseTime = beginAnimationUpdateTime(); 943 m_animState = AnimationStatePausedWaitTimer; 944 } 945 break; 946 case AnimationStateStartWaitStyleAvailable: 947 ASSERT(input == AnimationStateInputStyleAvailable || input == AnimationStateInputPlayStatePaused); 948 949 // Start timer has fired, tell the animation to start and wait for it to respond with start time 950 m_animState = AnimationStateStartWaitResponse; 951 952 overrideAnimations(); 953 954 // Send start event, if needed 955 onAnimationStart(0); // The elapsedTime is always 0 here 956 957 // Start the animation 958 if (overridden()) { 959 // We won't try to start accelerated animations if we are overridden and 960 // just move on to the next state. 961 m_animState = AnimationStateStartWaitResponse; 962 m_fallbackAnimating = true; 963 updateStateMachine(AnimationStateInputStartTimeSet, beginAnimationUpdateTime()); 964 } 965 else { 966 double timeOffset = 0; 967 // If the value for 'animation-delay' is negative then the animation appears to have started in the past. 968 if (m_animation->delay() < 0) 969 timeOffset = -m_animation->delay(); 970 bool started = startAnimation(timeOffset); 971 972 m_compAnim->animationController()->addToStartTimeResponseWaitList(this, started); 973 m_fallbackAnimating = !started; 974 } 975 break; 976 case AnimationStateStartWaitResponse: 977 ASSERT(input == AnimationStateInputStartTimeSet || input == AnimationStateInputPlayStatePaused); 978 979 if (input == AnimationStateInputStartTimeSet) { 980 ASSERT(param >= 0); 981 // We have a start time, set it, unless the startTime is already set 982 if (m_startTime <= 0) { 983 m_startTime = param; 984 // If the value for 'animation-delay' is negative then the animation appears to have started in the past. 985 if (m_animation->delay() < 0) 986 m_startTime += m_animation->delay(); 987 } 988 989 // Decide whether to go into looping or ending state 990 goIntoEndingOrLoopingState(); 991 992 // Dispatch updateStyleIfNeeded so we can start the animation 993 if (m_object) 994 m_compAnim->animationController()->addNodeChangeToDispatch(m_object->node()); 995 } else { 996 // We are pausing while waiting for a start response. Cancel the animation and wait. When 997 // we unpause, we will act as though the start timer just fired 998 m_pauseTime = -1; 999 pauseAnimation(beginAnimationUpdateTime() - m_startTime); 1000 m_animState = AnimationStatePausedWaitResponse; 1001 } 1002 break; 1003 case AnimationStateLooping: 1004 ASSERT(input == AnimationStateInputLoopTimerFired || input == AnimationStateInputPlayStatePaused); 1005 1006 if (input == AnimationStateInputLoopTimerFired) { 1007 ASSERT(param >= 0); 1008 // Loop timer fired, loop again or end. 1009 onAnimationIteration(param); 1010 1011 // Decide whether to go into looping or ending state 1012 goIntoEndingOrLoopingState(); 1013 } else { 1014 // We are pausing while running. Cancel the animation and wait 1015 m_pauseTime = beginAnimationUpdateTime(); 1016 pauseAnimation(beginAnimationUpdateTime() - m_startTime); 1017 m_animState = AnimationStatePausedRun; 1018 } 1019 break; 1020 case AnimationStateEnding: 1021 ASSERT(input == AnimationStateInputEndTimerFired || input == AnimationStateInputPlayStatePaused); 1022 1023 if (input == AnimationStateInputEndTimerFired) { 1024 ASSERT(param >= 0); 1025 // End timer fired, finish up 1026 onAnimationEnd(param); 1027 1028 m_animState = AnimationStateDone; 1029 1030 if (m_object) { 1031 resumeOverriddenAnimations(); 1032 1033 // Fire off another style change so we can set the final value 1034 m_compAnim->animationController()->addNodeChangeToDispatch(m_object->node()); 1035 } 1036 } else { 1037 // We are pausing while running. Cancel the animation and wait 1038 m_pauseTime = beginAnimationUpdateTime(); 1039 pauseAnimation(beginAnimationUpdateTime() - m_startTime); 1040 m_animState = AnimationStatePausedRun; 1041 } 1042 // |this| may be deleted here 1043 break; 1044 case AnimationStatePausedWaitTimer: 1045 ASSERT(input == AnimationStateInputPlayStateRunnning); 1046 ASSERT(paused()); 1047 // Update the times 1048 m_startTime += beginAnimationUpdateTime() - m_pauseTime; 1049 m_pauseTime = -1; 1050 1051 // we were waiting for the start timer to fire, go back and wait again 1052 m_animState = AnimationStateNew; 1053 updateStateMachine(AnimationStateInputStartAnimation, 0); 1054 break; 1055 case AnimationStatePausedWaitResponse: 1056 case AnimationStatePausedRun: 1057 // We treat these two cases the same. The only difference is that, when we are in 1058 // AnimationStatePausedWaitResponse, we don't yet have a valid startTime, so we send 0 to startAnimation. 1059 // When the AnimationStateInputStartTimeSet comes in and we were in AnimationStatePausedRun, we will notice 1060 // that we have already set the startTime and will ignore it. 1061 ASSERT(input == AnimationStateInputPlayStateRunnning || input == AnimationStateInputStartTimeSet); 1062 ASSERT(paused()); 1063 1064 // If we are paused, but we get the callback that notifies us that an accelerated animation started, 1065 // then we ignore the start time and just move into the paused-run state. 1066 if (m_animState == AnimationStatePausedWaitResponse && input == AnimationStateInputStartTimeSet) { 1067 m_animState = AnimationStatePausedRun; 1068 ASSERT(m_startTime == 0); 1069 m_startTime = param; 1070 m_pauseTime += m_startTime; 1071 break; 1072 } 1073 1074 // Update the times 1075 if (m_animState == AnimationStatePausedRun) 1076 m_startTime += beginAnimationUpdateTime() - m_pauseTime; 1077 else 1078 m_startTime = 0; 1079 m_pauseTime = -1; 1080 1081 // We were waiting for a begin time response from the animation, go back and wait again 1082 m_animState = AnimationStateStartWaitResponse; 1083 1084 // Start the animation 1085 if (overridden()) { 1086 // We won't try to start accelerated animations if we are overridden and 1087 // just move on to the next state. 1088 updateStateMachine(AnimationStateInputStartTimeSet, beginAnimationUpdateTime()); 1089 m_fallbackAnimating = true; 1090 } else { 1091 bool started = startAnimation(beginAnimationUpdateTime() - m_startTime); 1092 m_compAnim->animationController()->addToStartTimeResponseWaitList(this, started); 1093 m_fallbackAnimating = !started; 1094 } 1095 break; 1096 case AnimationStateDone: 1097 // We're done. Stay in this state until we are deleted 1098 break; 1099 } 1100 } 1101 1102 void AnimationBase::fireAnimationEventsIfNeeded() 1103 { 1104 // If we are waiting for the delay time to expire and it has, go to the next state 1105 if (m_animState != AnimationStateStartWaitTimer && m_animState != AnimationStateLooping && m_animState != AnimationStateEnding) 1106 return; 1107 1108 // We have to make sure to keep a ref to the this pointer, because it could get destroyed 1109 // during an animation callback that might get called. Since the owner is a CompositeAnimation 1110 // and it ref counts this object, we will keep a ref to that instead. That way the AnimationBase 1111 // can still access the resources of its CompositeAnimation as needed. 1112 RefPtr<AnimationBase> protector(this); 1113 RefPtr<CompositeAnimation> compProtector(m_compAnim); 1114 1115 // Check for start timeout 1116 if (m_animState == AnimationStateStartWaitTimer) { 1117 if (beginAnimationUpdateTime() - m_requestedStartTime >= m_animation->delay()) 1118 updateStateMachine(AnimationStateInputStartTimerFired, 0); 1119 return; 1120 } 1121 1122 double elapsedDuration = beginAnimationUpdateTime() - m_startTime; 1123 // FIXME: we need to ensure that elapsedDuration is never < 0. If it is, this suggests that 1124 // we had a recalcStyle() outside of beginAnimationUpdate()/endAnimationUpdate(). 1125 // Also check in getTimeToNextEvent(). 1126 elapsedDuration = max(elapsedDuration, 0.0); 1127 1128 // Check for end timeout 1129 if (m_totalDuration >= 0 && elapsedDuration >= m_totalDuration) { 1130 // Fire an end event 1131 updateStateMachine(AnimationStateInputEndTimerFired, m_totalDuration); 1132 } else { 1133 // Check for iteration timeout 1134 if (m_nextIterationDuration < 0) { 1135 // Hasn't been set yet, set it 1136 double durationLeft = m_animation->duration() - fmod(elapsedDuration, m_animation->duration()); 1137 m_nextIterationDuration = elapsedDuration + durationLeft; 1138 } 1139 1140 if (elapsedDuration >= m_nextIterationDuration) { 1141 // Set to the next iteration 1142 double previous = m_nextIterationDuration; 1143 double durationLeft = m_animation->duration() - fmod(elapsedDuration, m_animation->duration()); 1144 m_nextIterationDuration = elapsedDuration + durationLeft; 1145 1146 // Send the event 1147 updateStateMachine(AnimationStateInputLoopTimerFired, previous); 1148 } 1149 } 1150 } 1151 1152 void AnimationBase::updatePlayState(bool run) 1153 { 1154 if (paused() == run || isNew()) 1155 updateStateMachine(run ? AnimationStateInputPlayStateRunnning : AnimationStateInputPlayStatePaused, -1); 1156 } 1157 1158 double AnimationBase::timeToNextService() 1159 { 1160 // Returns the time at which next service is required. -1 means no service is required. 0 means 1161 // service is required now, and > 0 means service is required that many seconds in the future. 1162 if (paused() || isNew()) 1163 return -1; 1164 1165 if (m_animState == AnimationStateStartWaitTimer) { 1166 double timeFromNow = m_animation->delay() - (beginAnimationUpdateTime() - m_requestedStartTime); 1167 return max(timeFromNow, 0.0); 1168 } 1169 1170 fireAnimationEventsIfNeeded(); 1171 1172 // In all other cases, we need service right away. 1173 return 0; 1174 } 1175 1176 double AnimationBase::progress(double scale, double offset, const TimingFunction* tf) const 1177 { 1178 if (preActive()) 1179 return 0; 1180 1181 double elapsedTime = getElapsedTime(); 1182 1183 double dur = m_animation->duration(); 1184 if (m_animation->iterationCount() > 0) 1185 dur *= m_animation->iterationCount(); 1186 1187 if (postActive() || !m_animation->duration() || (m_animation->iterationCount() > 0 && elapsedTime >= dur)) 1188 return 1.0; 1189 1190 // Compute the fractional time, taking into account direction. 1191 // There is no need to worry about iterations, we assume that we would have 1192 // short circuited above if we were done. 1193 double fractionalTime = elapsedTime / m_animation->duration(); 1194 int integralTime = static_cast<int>(fractionalTime); 1195 fractionalTime -= integralTime; 1196 1197 if (m_animation->direction() && (integralTime & 1)) 1198 fractionalTime = 1 - fractionalTime; 1199 1200 if (scale != 1 || offset) 1201 fractionalTime = (fractionalTime - offset) * scale; 1202 1203 if (!tf) 1204 tf = &m_animation->timingFunction(); 1205 1206 if (tf->type() == LinearTimingFunction) 1207 return fractionalTime; 1208 1209 // Cubic bezier. 1210 double result = solveCubicBezierFunction(tf->x1(), 1211 tf->y1(), 1212 tf->x2(), 1213 tf->y2(), 1214 fractionalTime, m_animation->duration()); 1215 return result; 1216 } 1217 1218 void AnimationBase::getTimeToNextEvent(double& time, bool& isLooping) const 1219 { 1220 // Decide when the end or loop event needs to fire 1221 double totalDuration = -1; 1222 if (m_animation->iterationCount() > 0) 1223 totalDuration = m_animation->duration() * m_animation->iterationCount(); 1224 1225 const double elapsedDuration = max(beginAnimationUpdateTime() - m_startTime, 0.0); 1226 double durationLeft = 0; 1227 double nextIterationTime = m_totalDuration; 1228 1229 if (m_totalDuration < 0 || elapsedDuration < m_totalDuration) { 1230 durationLeft = m_animation->duration() > 0 ? (m_animation->duration() - fmod(elapsedDuration, m_animation->duration())) : 0; 1231 nextIterationTime = elapsedDuration + durationLeft; 1232 } 1233 1234 if (m_totalDuration < 0 || nextIterationTime < m_totalDuration) { 1235 // We are not at the end yet 1236 ASSERT(nextIterationTime > 0); 1237 isLooping = true; 1238 } else { 1239 // We are at the end 1240 isLooping = false; 1241 } 1242 1243 time = durationLeft; 1244 } 1245 1246 void AnimationBase::goIntoEndingOrLoopingState() 1247 { 1248 double t; 1249 bool isLooping; 1250 getTimeToNextEvent(t, isLooping); 1251 m_animState = isLooping ? AnimationStateLooping : AnimationStateEnding; 1252 } 1253 1254 void AnimationBase::freezeAtTime(double t) 1255 { 1256 ASSERT(m_startTime); // if m_startTime is zero, we haven't started yet, so we'll get a bad pause time. 1257 m_pauseTime = m_startTime + t - m_animation->delay(); 1258 1259 #if USE(ACCELERATED_COMPOSITING) 1260 if (m_object && m_object->hasLayer()) { 1261 RenderLayer* layer = toRenderBoxModelObject(m_object)->layer(); 1262 if (layer->isComposited()) 1263 layer->backing()->suspendAnimations(m_pauseTime); 1264 } 1265 #endif 1266 } 1267 1268 double AnimationBase::beginAnimationUpdateTime() const 1269 { 1270 return m_compAnim->animationController()->beginAnimationUpdateTime(); 1271 } 1272 1273 double AnimationBase::getElapsedTime() const 1274 { 1275 if (paused()) 1276 return m_pauseTime - m_startTime; 1277 if (m_startTime <= 0) 1278 return 0; 1279 if (postActive()) 1280 return 1; 1281 return beginAnimationUpdateTime() - m_startTime; 1282 } 1283 1284 } // namespace WebCore 1285