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 "AnimationController.h" 31 32 #include "AnimationBase.h" 33 #include "AnimationControllerPrivate.h" 34 #include "CSSParser.h" 35 #include "CompositeAnimation.h" 36 #include "EventNames.h" 37 #include "Frame.h" 38 #include "RenderView.h" 39 #include "WebKitAnimationEvent.h" 40 #include "WebKitTransitionEvent.h" 41 #include <wtf/CurrentTime.h> 42 #include <wtf/UnusedParam.h> 43 44 namespace WebCore { 45 46 static const double cAnimationTimerDelay = 0.025; 47 static const double cBeginAnimationUpdateTimeNotSet = -1; 48 49 AnimationControllerPrivate::AnimationControllerPrivate(Frame* frame) 50 : m_animationTimer(this, &AnimationControllerPrivate::animationTimerFired) 51 , m_updateStyleIfNeededDispatcher(this, &AnimationControllerPrivate::updateStyleIfNeededDispatcherFired) 52 , m_frame(frame) 53 , m_beginAnimationUpdateTime(cBeginAnimationUpdateTimeNotSet) 54 , m_styleAvailableWaiters(0) 55 , m_lastStyleAvailableWaiter(0) 56 , m_responseWaiters(0) 57 , m_lastResponseWaiter(0) 58 , m_waitingForResponse(false) 59 { 60 } 61 62 AnimationControllerPrivate::~AnimationControllerPrivate() 63 { 64 } 65 66 PassRefPtr<CompositeAnimation> AnimationControllerPrivate::accessCompositeAnimation(RenderObject* renderer) 67 { 68 RefPtr<CompositeAnimation> animation = m_compositeAnimations.get(renderer); 69 if (!animation) { 70 animation = CompositeAnimation::create(this); 71 m_compositeAnimations.set(renderer, animation); 72 } 73 return animation; 74 } 75 76 bool AnimationControllerPrivate::clear(RenderObject* renderer) 77 { 78 // Return false if we didn't do anything OR we are suspended (so we don't try to 79 // do a setNeedsStyleRecalc() when suspended). 80 PassRefPtr<CompositeAnimation> animation = m_compositeAnimations.take(renderer); 81 if (!animation) 82 return false; 83 animation->clearRenderer(); 84 return animation->isSuspended(); 85 } 86 87 void AnimationControllerPrivate::updateAnimationTimer(bool callSetChanged/* = false*/) 88 { 89 double needsService = -1; 90 bool calledSetChanged = false; 91 92 RenderObjectAnimationMap::const_iterator animationsEnd = m_compositeAnimations.end(); 93 for (RenderObjectAnimationMap::const_iterator it = m_compositeAnimations.begin(); it != animationsEnd; ++it) { 94 CompositeAnimation* compAnim = it->second.get(); 95 if (!compAnim->isSuspended() && compAnim->hasAnimations()) { 96 double t = compAnim->timeToNextService(); 97 if (t != -1 && (t < needsService || needsService == -1)) 98 needsService = t; 99 if (needsService == 0) { 100 if (callSetChanged) { 101 Node* node = it->first->node(); 102 ASSERT(!node || (node->document() && !node->document()->inPageCache())); 103 node->setNeedsStyleRecalc(SyntheticStyleChange); 104 calledSetChanged = true; 105 } 106 else 107 break; 108 } 109 } 110 } 111 112 if (calledSetChanged) 113 m_frame->document()->updateStyleIfNeeded(); 114 115 // If we want service immediately, we start a repeating timer to reduce the overhead of starting 116 if (needsService == 0) { 117 if (!m_animationTimer.isActive() || m_animationTimer.repeatInterval() == 0) 118 m_animationTimer.startRepeating(cAnimationTimerDelay); 119 return; 120 } 121 122 // If we don't need service, we want to make sure the timer is no longer running 123 if (needsService < 0) { 124 if (m_animationTimer.isActive()) 125 m_animationTimer.stop(); 126 return; 127 } 128 129 // Otherwise, we want to start a one-shot timer so we get here again 130 if (m_animationTimer.isActive()) 131 m_animationTimer.stop(); 132 m_animationTimer.startOneShot(needsService); 133 } 134 135 void AnimationControllerPrivate::updateStyleIfNeededDispatcherFired(Timer<AnimationControllerPrivate>*) 136 { 137 // fire all the events 138 Vector<EventToDispatch>::const_iterator eventsToDispatchEnd = m_eventsToDispatch.end(); 139 for (Vector<EventToDispatch>::const_iterator it = m_eventsToDispatch.begin(); it != eventsToDispatchEnd; ++it) { 140 if (it->eventType == eventNames().webkitTransitionEndEvent) 141 it->element->dispatchEvent(WebKitTransitionEvent::create(it->eventType, it->name, it->elapsedTime)); 142 else 143 it->element->dispatchEvent(WebKitAnimationEvent::create(it->eventType, it->name, it->elapsedTime)); 144 } 145 146 m_eventsToDispatch.clear(); 147 148 // call setChanged on all the elements 149 Vector<RefPtr<Node> >::const_iterator nodeChangesToDispatchEnd = m_nodeChangesToDispatch.end(); 150 for (Vector<RefPtr<Node> >::const_iterator it = m_nodeChangesToDispatch.begin(); it != nodeChangesToDispatchEnd; ++it) 151 (*it)->setNeedsStyleRecalc(SyntheticStyleChange); 152 153 m_nodeChangesToDispatch.clear(); 154 155 if (m_frame) 156 m_frame->document()->updateStyleIfNeeded(); 157 } 158 159 void AnimationControllerPrivate::startUpdateStyleIfNeededDispatcher() 160 { 161 if (!m_updateStyleIfNeededDispatcher.isActive()) 162 m_updateStyleIfNeededDispatcher.startOneShot(0); 163 } 164 165 void AnimationControllerPrivate::addEventToDispatch(PassRefPtr<Element> element, const AtomicString& eventType, const String& name, double elapsedTime) 166 { 167 m_eventsToDispatch.grow(m_eventsToDispatch.size()+1); 168 EventToDispatch& event = m_eventsToDispatch[m_eventsToDispatch.size()-1]; 169 event.element = element; 170 event.eventType = eventType; 171 event.name = name; 172 event.elapsedTime = elapsedTime; 173 174 startUpdateStyleIfNeededDispatcher(); 175 } 176 177 void AnimationControllerPrivate::addNodeChangeToDispatch(PassRefPtr<Node> node) 178 { 179 ASSERT(!node || (node->document() && !node->document()->inPageCache())); 180 if (!node) 181 return; 182 183 m_nodeChangesToDispatch.append(node); 184 startUpdateStyleIfNeededDispatcher(); 185 } 186 187 void AnimationControllerPrivate::animationTimerFired(Timer<AnimationControllerPrivate>*) 188 { 189 // Make sure animationUpdateTime is updated, so that it is current even if no 190 // styleChange has happened (e.g. accelerated animations) 191 setBeginAnimationUpdateTime(cBeginAnimationUpdateTimeNotSet); 192 193 // When the timer fires, all we do is call setChanged on all DOM nodes with running animations and then do an immediate 194 // updateStyleIfNeeded. It will then call back to us with new information. 195 updateAnimationTimer(true); 196 } 197 198 bool AnimationControllerPrivate::isAnimatingPropertyOnRenderer(RenderObject* renderer, CSSPropertyID property, bool isRunningNow) const 199 { 200 RefPtr<CompositeAnimation> animation = m_compositeAnimations.get(renderer); 201 if (!animation) 202 return false; 203 204 return animation->isAnimatingProperty(property, isRunningNow); 205 } 206 207 void AnimationControllerPrivate::suspendAnimations(Document* document) 208 { 209 setBeginAnimationUpdateTime(cBeginAnimationUpdateTimeNotSet); 210 211 RenderObjectAnimationMap::const_iterator animationsEnd = m_compositeAnimations.end(); 212 for (RenderObjectAnimationMap::const_iterator it = m_compositeAnimations.begin(); it != animationsEnd; ++it) { 213 RenderObject* renderer = it->first; 214 if (renderer->document() == document) { 215 CompositeAnimation* compAnim = it->second.get(); 216 compAnim->suspendAnimations(); 217 } 218 } 219 220 updateAnimationTimer(); 221 } 222 223 void AnimationControllerPrivate::resumeAnimations(Document* document) 224 { 225 setBeginAnimationUpdateTime(cBeginAnimationUpdateTimeNotSet); 226 227 RenderObjectAnimationMap::const_iterator animationsEnd = m_compositeAnimations.end(); 228 for (RenderObjectAnimationMap::const_iterator it = m_compositeAnimations.begin(); it != animationsEnd; ++it) { 229 RenderObject* renderer = it->first; 230 if (renderer->document() == document) { 231 CompositeAnimation* compAnim = it->second.get(); 232 compAnim->resumeAnimations(); 233 } 234 } 235 236 updateAnimationTimer(); 237 } 238 239 bool AnimationControllerPrivate::pauseAnimationAtTime(RenderObject* renderer, const String& name, double t) 240 { 241 if (!renderer) 242 return false; 243 244 RefPtr<CompositeAnimation> compAnim = accessCompositeAnimation(renderer); 245 if (!compAnim) 246 return false; 247 248 if (compAnim->pauseAnimationAtTime(name, t)) { 249 renderer->node()->setNeedsStyleRecalc(SyntheticStyleChange); 250 startUpdateStyleIfNeededDispatcher(); 251 return true; 252 } 253 254 return false; 255 } 256 257 bool AnimationControllerPrivate::pauseTransitionAtTime(RenderObject* renderer, const String& property, double t) 258 { 259 if (!renderer) 260 return false; 261 262 RefPtr<CompositeAnimation> compAnim = accessCompositeAnimation(renderer); 263 if (!compAnim) 264 return false; 265 266 if (compAnim->pauseTransitionAtTime(cssPropertyID(property), t)) { 267 renderer->node()->setNeedsStyleRecalc(SyntheticStyleChange); 268 startUpdateStyleIfNeededDispatcher(); 269 return true; 270 } 271 272 return false; 273 } 274 275 double AnimationControllerPrivate::beginAnimationUpdateTime() 276 { 277 if (m_beginAnimationUpdateTime == cBeginAnimationUpdateTimeNotSet) 278 m_beginAnimationUpdateTime = currentTime(); 279 return m_beginAnimationUpdateTime; 280 } 281 282 void AnimationControllerPrivate::endAnimationUpdate() 283 { 284 styleAvailable(); 285 if (!m_waitingForResponse) 286 startTimeResponse(beginAnimationUpdateTime()); 287 } 288 289 void AnimationControllerPrivate::receivedStartTimeResponse(double time) 290 { 291 m_waitingForResponse = false; 292 startTimeResponse(time); 293 } 294 295 PassRefPtr<RenderStyle> AnimationControllerPrivate::getAnimatedStyleForRenderer(RenderObject* renderer) 296 { 297 if (!renderer) 298 return 0; 299 300 RefPtr<CompositeAnimation> rendererAnimations = m_compositeAnimations.get(renderer); 301 if (!rendererAnimations) 302 return renderer->style(); 303 304 // Make sure animationUpdateTime is updated, so that it is current even if no 305 // styleChange has happened (e.g. accelerated animations). 306 setBeginAnimationUpdateTime(cBeginAnimationUpdateTimeNotSet); 307 RefPtr<RenderStyle> animatingStyle = rendererAnimations->getAnimatedStyle(); 308 if (!animatingStyle) 309 animatingStyle = renderer->style(); 310 311 return animatingStyle.release(); 312 } 313 314 unsigned AnimationControllerPrivate::numberOfActiveAnimations() const 315 { 316 unsigned count = 0; 317 318 RenderObjectAnimationMap::const_iterator animationsEnd = m_compositeAnimations.end(); 319 for (RenderObjectAnimationMap::const_iterator it = m_compositeAnimations.begin(); it != animationsEnd; ++it) { 320 CompositeAnimation* compAnim = it->second.get(); 321 count += compAnim->numberOfActiveAnimations(); 322 } 323 324 return count; 325 } 326 327 void AnimationControllerPrivate::addToStyleAvailableWaitList(AnimationBase* animation) 328 { 329 ASSERT(!animation->next()); 330 331 if (m_styleAvailableWaiters) 332 m_lastStyleAvailableWaiter->setNext(animation); 333 else 334 m_styleAvailableWaiters = animation; 335 336 m_lastStyleAvailableWaiter = animation; 337 animation->setNext(0); 338 } 339 340 void AnimationControllerPrivate::removeFromStyleAvailableWaitList(AnimationBase* animationToRemove) 341 { 342 AnimationBase* prevAnimation = 0; 343 for (AnimationBase* animation = m_styleAvailableWaiters; animation; animation = animation->next()) { 344 if (animation == animationToRemove) { 345 if (prevAnimation) 346 prevAnimation->setNext(animation->next()); 347 else 348 m_styleAvailableWaiters = animation->next(); 349 350 if (m_lastStyleAvailableWaiter == animation) 351 m_lastStyleAvailableWaiter = prevAnimation; 352 353 animationToRemove->setNext(0); 354 } 355 } 356 } 357 358 void AnimationControllerPrivate::styleAvailable() 359 { 360 // Go through list of waiters and send them on their way 361 for (AnimationBase* animation = m_styleAvailableWaiters; animation; ) { 362 AnimationBase* nextAnimation = animation->next(); 363 animation->setNext(0); 364 animation->styleAvailable(); 365 animation = nextAnimation; 366 } 367 368 m_styleAvailableWaiters = 0; 369 m_lastStyleAvailableWaiter = 0; 370 } 371 372 void AnimationControllerPrivate::addToStartTimeResponseWaitList(AnimationBase* animation, bool willGetResponse) 373 { 374 // If willGetResponse is true, it means this animation is actually waiting for a response 375 // (which will come in as a call to notifyAnimationStarted()). 376 // In that case we don't need to add it to this list. We just set a waitingForAResponse flag 377 // which says we are waiting for the response. If willGetResponse is false, this animation 378 // is not waiting for a response for itself, but rather for a notifyXXXStarted() call for 379 // another animation to which it will sync. 380 // 381 // When endAnimationUpdate() is called we check to see if the waitingForAResponse flag is 382 // true. If so, we just return and will do our work when the first notifyXXXStarted() call 383 // comes in. If it is false, we will not be getting a notifyXXXStarted() call, so we will 384 // do our work right away. In both cases we call the onAnimationStartResponse() method 385 // on each animation. In the first case we send in the time we got from notifyXXXStarted(). 386 // In the second case, we just pass in the beginAnimationUpdateTime(). 387 // 388 // This will synchronize all software and accelerated animations started in the same 389 // updateStyleIfNeeded cycle. 390 // 391 ASSERT(!animation->next()); 392 393 if (willGetResponse) 394 m_waitingForResponse = true; 395 396 if (m_responseWaiters) 397 m_lastResponseWaiter->setNext(animation); 398 else 399 m_responseWaiters = animation; 400 401 m_lastResponseWaiter = animation; 402 animation->setNext(0); 403 } 404 405 void AnimationControllerPrivate::removeFromStartTimeResponseWaitList(AnimationBase* animationToRemove) 406 { 407 AnimationBase* prevAnimation = 0; 408 for (AnimationBase* animation = m_responseWaiters; animation; animation = animation->next()) { 409 if (animation == animationToRemove) { 410 if (prevAnimation) 411 prevAnimation->setNext(animation->next()); 412 else 413 m_responseWaiters = animation->next(); 414 415 if (m_lastResponseWaiter == animation) 416 m_lastResponseWaiter = prevAnimation; 417 418 animationToRemove->setNext(0); 419 } 420 prevAnimation = animation; 421 } 422 } 423 424 void AnimationControllerPrivate::startTimeResponse(double time) 425 { 426 // Go through list of waiters and send them on their way 427 for (AnimationBase* animation = m_responseWaiters; animation; ) { 428 AnimationBase* nextAnimation = animation->next(); 429 animation->setNext(0); 430 animation->onAnimationStartResponse(time); 431 animation = nextAnimation; 432 } 433 434 m_responseWaiters = 0; 435 m_lastResponseWaiter = 0; 436 } 437 438 AnimationController::AnimationController(Frame* frame) 439 : m_data(new AnimationControllerPrivate(frame)) 440 { 441 } 442 443 AnimationController::~AnimationController() 444 { 445 delete m_data; 446 } 447 448 void AnimationController::cancelAnimations(RenderObject* renderer) 449 { 450 if (!m_data->hasAnimations()) 451 return; 452 453 if (m_data->clear(renderer)) { 454 Node* node = renderer->node(); 455 ASSERT(!node || (node->document() && !node->document()->inPageCache())); 456 node->setNeedsStyleRecalc(SyntheticStyleChange); 457 } 458 } 459 460 PassRefPtr<RenderStyle> AnimationController::updateAnimations(RenderObject* renderer, RenderStyle* newStyle) 461 { 462 // Don't do anything if we're in the cache 463 if (!renderer->document() || renderer->document()->inPageCache()) 464 return newStyle; 465 466 RenderStyle* oldStyle = renderer->style(); 467 468 if ((!oldStyle || (!oldStyle->animations() && !oldStyle->transitions())) && (!newStyle->animations() && !newStyle->transitions())) 469 return newStyle; 470 471 // Don't run transitions when printing. 472 if (renderer->view()->printing()) 473 return newStyle; 474 475 // Fetch our current set of implicit animations from a hashtable. We then compare them 476 // against the animations in the style and make sure we're in sync. If destination values 477 // have changed, we reset the animation. We then do a blend to get new values and we return 478 // a new style. 479 ASSERT(renderer->node()); // FIXME: We do not animate generated content yet. 480 481 RefPtr<CompositeAnimation> rendererAnimations = m_data->accessCompositeAnimation(renderer); 482 RefPtr<RenderStyle> blendedStyle = rendererAnimations->animate(renderer, oldStyle, newStyle); 483 484 m_data->updateAnimationTimer(); 485 486 if (blendedStyle != newStyle) { 487 // If the animations/transitions change opacity or transform, we need to update 488 // the style to impose the stacking rules. Note that this is also 489 // done in CSSStyleSelector::adjustRenderStyle(). 490 if (blendedStyle->hasAutoZIndex() && (blendedStyle->opacity() < 1.0f || blendedStyle->hasTransform())) 491 blendedStyle->setZIndex(0); 492 } 493 return blendedStyle.release(); 494 } 495 496 PassRefPtr<RenderStyle> AnimationController::getAnimatedStyleForRenderer(RenderObject* renderer) 497 { 498 return m_data->getAnimatedStyleForRenderer(renderer); 499 } 500 501 void AnimationController::notifyAnimationStarted(RenderObject*, double startTime) 502 { 503 m_data->receivedStartTimeResponse(startTime); 504 } 505 506 bool AnimationController::pauseAnimationAtTime(RenderObject* renderer, const String& name, double t) 507 { 508 return m_data->pauseAnimationAtTime(renderer, name, t); 509 } 510 511 unsigned AnimationController::numberOfActiveAnimations() const 512 { 513 return m_data->numberOfActiveAnimations(); 514 } 515 516 bool AnimationController::pauseTransitionAtTime(RenderObject* renderer, const String& property, double t) 517 { 518 return m_data->pauseTransitionAtTime(renderer, property, t); 519 } 520 521 bool AnimationController::isAnimatingPropertyOnRenderer(RenderObject* renderer, CSSPropertyID property, bool isRunningNow) const 522 { 523 return m_data->isAnimatingPropertyOnRenderer(renderer, property, isRunningNow); 524 } 525 526 void AnimationController::suspendAnimations(Document* document) 527 { 528 m_data->suspendAnimations(document); 529 } 530 531 void AnimationController::resumeAnimations(Document* document) 532 { 533 m_data->resumeAnimations(document); 534 } 535 536 void AnimationController::beginAnimationUpdate() 537 { 538 m_data->setBeginAnimationUpdateTime(cBeginAnimationUpdateTimeNotSet); 539 } 540 541 void AnimationController::endAnimationUpdate() 542 { 543 m_data->endAnimationUpdate(); 544 } 545 546 bool AnimationController::supportsAcceleratedAnimationOfProperty(CSSPropertyID property) 547 { 548 #if USE(ACCELERATED_COMPOSITING) 549 return AnimationBase::animationOfPropertyIsAccelerated(property); 550 #else 551 UNUSED_PARAM(property); 552 return false; 553 #endif 554 } 555 556 } // namespace WebCore 557