1 /* 2 * Copyright (C) 2007 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 "KeyframeAnimation.h" 31 32 #include "AnimationControllerPrivate.h" 33 #include "CSSPropertyNames.h" 34 #include "CSSStyleSelector.h" 35 #include "CompositeAnimation.h" 36 #include "EventNames.h" 37 #include "RenderLayer.h" 38 #include "RenderLayerBacking.h" 39 #include "RenderStyle.h" 40 #include <wtf/UnusedParam.h> 41 42 using namespace std; 43 44 namespace WebCore { 45 46 KeyframeAnimation::KeyframeAnimation(const Animation* animation, RenderObject* renderer, int index, CompositeAnimation* compAnim, RenderStyle* unanimatedStyle) 47 : AnimationBase(animation, renderer, compAnim) 48 , m_keyframes(renderer, animation->name()) 49 , m_index(index) 50 , m_startEventDispatched(false) 51 , m_unanimatedStyle(unanimatedStyle) 52 { 53 // Get the keyframe RenderStyles 54 if (m_object && m_object->node() && m_object->node()->isElementNode()) 55 m_object->document()->styleSelector()->keyframeStylesForAnimation(static_cast<Element*>(m_object->node()), unanimatedStyle, m_keyframes); 56 57 // Update the m_transformFunctionListValid flag based on whether the function lists in the keyframes match. 58 validateTransformFunctionList(); 59 } 60 61 KeyframeAnimation::~KeyframeAnimation() 62 { 63 // Make sure to tell the renderer that we are ending. This will make sure any accelerated animations are removed. 64 if (!postActive()) 65 endAnimation(); 66 } 67 68 void KeyframeAnimation::fetchIntervalEndpointsForProperty(int property, const RenderStyle*& fromStyle, const RenderStyle*& toStyle, double& prog) const 69 { 70 // Find the first key 71 double elapsedTime = getElapsedTime(); 72 if (m_animation->duration() && m_animation->iterationCount() != Animation::IterationCountInfinite) 73 elapsedTime = min(elapsedTime, m_animation->duration() * m_animation->iterationCount()); 74 75 double fractionalTime = m_animation->duration() ? (elapsedTime / m_animation->duration()) : 1; 76 77 // FIXME: startTime can be before the current animation "frame" time. This is to sync with the frame time 78 // concept in AnimationTimeController. So we need to somehow sync the two. Until then, the possible 79 // error is small and will probably not be noticeable. Until we fix this, remove the assert. 80 // https://bugs.webkit.org/show_bug.cgi?id=52037 81 // ASSERT(fractionalTime >= 0); 82 if (fractionalTime < 0) 83 fractionalTime = 0; 84 85 // FIXME: share this code with AnimationBase::progress(). 86 int iteration = static_cast<int>(fractionalTime); 87 if (m_animation->iterationCount() != Animation::IterationCountInfinite) 88 iteration = min(iteration, m_animation->iterationCount() - 1); 89 fractionalTime -= iteration; 90 91 bool reversing = (m_animation->direction() == Animation::AnimationDirectionAlternate) && (iteration & 1); 92 if (reversing) 93 fractionalTime = 1 - fractionalTime; 94 95 size_t numKeyframes = m_keyframes.size(); 96 if (!numKeyframes) 97 return; 98 99 ASSERT(!m_keyframes[0].key()); 100 ASSERT(m_keyframes[m_keyframes.size() - 1].key() == 1); 101 102 int prevIndex = -1; 103 int nextIndex = -1; 104 105 // FIXME: with a lot of keys, this linear search will be slow. We could binary search. 106 for (size_t i = 0; i < numKeyframes; ++i) { 107 const KeyframeValue& currKeyFrame = m_keyframes[i]; 108 109 if (!currKeyFrame.containsProperty(property)) 110 continue; 111 112 if (fractionalTime < currKeyFrame.key()) { 113 nextIndex = i; 114 break; 115 } 116 117 prevIndex = i; 118 } 119 120 double scale = 1; 121 double offset = 0; 122 123 if (prevIndex == -1) 124 prevIndex = 0; 125 126 if (nextIndex == -1) 127 nextIndex = m_keyframes.size() - 1; 128 129 const KeyframeValue& prevKeyframe = m_keyframes[prevIndex]; 130 const KeyframeValue& nextKeyframe = m_keyframes[nextIndex]; 131 132 fromStyle = prevKeyframe.style(); 133 toStyle = nextKeyframe.style(); 134 135 offset = prevKeyframe.key(); 136 scale = 1.0 / (nextKeyframe.key() - prevKeyframe.key()); 137 138 const TimingFunction* timingFunction = 0; 139 if (fromStyle->animations() && fromStyle->animations()->size() > 0) { 140 // We get the timing function from the first animation, because we've synthesized a RenderStyle for each keyframe. 141 timingFunction = fromStyle->animations()->animation(0)->timingFunction().get(); 142 } 143 144 prog = progress(scale, offset, timingFunction); 145 } 146 147 void KeyframeAnimation::animate(CompositeAnimation*, RenderObject*, const RenderStyle*, RenderStyle* targetStyle, RefPtr<RenderStyle>& animatedStyle) 148 { 149 // Fire the start timeout if needed 150 fireAnimationEventsIfNeeded(); 151 152 // If we have not yet started, we will not have a valid start time, so just start the animation if needed. 153 if (isNew() && m_animation->playState() == AnimPlayStatePlaying) 154 updateStateMachine(AnimationStateInputStartAnimation, -1); 155 156 // If we get this far and the animation is done, it means we are cleaning up a just finished animation. 157 // If so, we need to send back the targetStyle. 158 if (postActive()) { 159 if (!animatedStyle) 160 animatedStyle = const_cast<RenderStyle*>(targetStyle); 161 return; 162 } 163 164 // If we are waiting for the start timer, we don't want to change the style yet. 165 // Special case 1 - if the delay time is 0, then we do want to set the first frame of the 166 // animation right away. This avoids a flash when the animation starts. 167 // Special case 2 - if there is a backwards fill mode, then we want to continue 168 // through to the style blend so that we get the fromStyle. 169 if (waitingToStart() && m_animation->delay() > 0 && !m_animation->fillsBackwards()) 170 return; 171 172 // If we have no keyframes, don't animate. 173 if (!m_keyframes.size()) { 174 updateStateMachine(AnimationStateInputEndAnimation, -1); 175 return; 176 } 177 178 // Run a cycle of animation. 179 // We know we will need a new render style, so make one if needed. 180 if (!animatedStyle) 181 animatedStyle = RenderStyle::clone(targetStyle); 182 183 // FIXME: we need to be more efficient about determining which keyframes we are animating between. 184 // We should cache the last pair or something. 185 HashSet<int>::const_iterator endProperties = m_keyframes.endProperties(); 186 for (HashSet<int>::const_iterator it = m_keyframes.beginProperties(); it != endProperties; ++it) { 187 int property = *it; 188 189 // Get the from/to styles and progress between 190 const RenderStyle* fromStyle = 0; 191 const RenderStyle* toStyle = 0; 192 double progress = 0.0; 193 fetchIntervalEndpointsForProperty(property, fromStyle, toStyle, progress); 194 195 bool needsAnim = blendProperties(this, property, animatedStyle.get(), fromStyle, toStyle, progress); 196 if (needsAnim) 197 setAnimating(); 198 else { 199 #if USE(ACCELERATED_COMPOSITING) 200 // If we are running an accelerated animation, set a flag in the style 201 // to indicate it. This can be used to make sure we get an updated 202 // style for hit testing, etc. 203 animatedStyle->setIsRunningAcceleratedAnimation(); 204 #endif 205 } 206 } 207 } 208 209 void KeyframeAnimation::getAnimatedStyle(RefPtr<RenderStyle>& animatedStyle) 210 { 211 // If we're in the delay phase and we're not backwards filling, tell the caller 212 // to use the current style. 213 if (waitingToStart() && m_animation->delay() > 0 && !m_animation->fillsBackwards()) 214 return; 215 216 if (!m_keyframes.size()) 217 return; 218 219 if (!animatedStyle) 220 animatedStyle = RenderStyle::clone(m_object->style()); 221 222 HashSet<int>::const_iterator endProperties = m_keyframes.endProperties(); 223 for (HashSet<int>::const_iterator it = m_keyframes.beginProperties(); it != endProperties; ++it) { 224 int property = *it; 225 226 // Get the from/to styles and progress between 227 const RenderStyle* fromStyle = 0; 228 const RenderStyle* toStyle = 0; 229 double progress = 0.0; 230 fetchIntervalEndpointsForProperty(property, fromStyle, toStyle, progress); 231 232 blendProperties(this, property, animatedStyle.get(), fromStyle, toStyle, progress); 233 } 234 } 235 236 bool KeyframeAnimation::hasAnimationForProperty(int property) const 237 { 238 // FIXME: why not just m_keyframes.containsProperty()? 239 HashSet<int>::const_iterator end = m_keyframes.endProperties(); 240 for (HashSet<int>::const_iterator it = m_keyframes.beginProperties(); it != end; ++it) { 241 if (*it == property) 242 return true; 243 } 244 245 return false; 246 } 247 248 bool KeyframeAnimation::startAnimation(double timeOffset) 249 { 250 #if USE(ACCELERATED_COMPOSITING) 251 if (m_object && m_object->hasLayer()) { 252 RenderLayer* layer = toRenderBoxModelObject(m_object)->layer(); 253 if (layer->isComposited()) 254 return layer->backing()->startAnimation(timeOffset, m_animation.get(), m_keyframes); 255 } 256 #else 257 UNUSED_PARAM(timeOffset); 258 #endif 259 return false; 260 } 261 262 void KeyframeAnimation::pauseAnimation(double timeOffset) 263 { 264 if (!m_object) 265 return; 266 267 #if USE(ACCELERATED_COMPOSITING) 268 if (m_object->hasLayer()) { 269 RenderLayer* layer = toRenderBoxModelObject(m_object)->layer(); 270 if (layer->isComposited()) 271 layer->backing()->animationPaused(timeOffset, m_keyframes.animationName()); 272 } 273 #else 274 UNUSED_PARAM(timeOffset); 275 #endif 276 // Restore the original (unanimated) style 277 if (!paused()) 278 setNeedsStyleRecalc(m_object->node()); 279 } 280 281 void KeyframeAnimation::endAnimation() 282 { 283 if (!m_object) 284 return; 285 286 #if USE(ACCELERATED_COMPOSITING) 287 if (m_object->hasLayer()) { 288 RenderLayer* layer = toRenderBoxModelObject(m_object)->layer(); 289 if (layer->isComposited()) 290 layer->backing()->animationFinished(m_keyframes.animationName()); 291 } 292 #endif 293 // Restore the original (unanimated) style 294 if (!paused()) 295 setNeedsStyleRecalc(m_object->node()); 296 } 297 298 bool KeyframeAnimation::shouldSendEventForListener(Document::ListenerType listenerType) const 299 { 300 return m_object->document()->hasListenerType(listenerType); 301 } 302 303 void KeyframeAnimation::onAnimationStart(double elapsedTime) 304 { 305 sendAnimationEvent(eventNames().webkitAnimationStartEvent, elapsedTime); 306 } 307 308 void KeyframeAnimation::onAnimationIteration(double elapsedTime) 309 { 310 sendAnimationEvent(eventNames().webkitAnimationIterationEvent, elapsedTime); 311 } 312 313 void KeyframeAnimation::onAnimationEnd(double elapsedTime) 314 { 315 sendAnimationEvent(eventNames().webkitAnimationEndEvent, elapsedTime); 316 // End the animation if we don't fill forwards. Forward filling 317 // animations are ended properly in the class destructor. 318 if (!m_animation->fillsForwards()) 319 endAnimation(); 320 } 321 322 bool KeyframeAnimation::sendAnimationEvent(const AtomicString& eventType, double elapsedTime) 323 { 324 Document::ListenerType listenerType; 325 if (eventType == eventNames().webkitAnimationIterationEvent) 326 listenerType = Document::ANIMATIONITERATION_LISTENER; 327 else if (eventType == eventNames().webkitAnimationEndEvent) 328 listenerType = Document::ANIMATIONEND_LISTENER; 329 else { 330 ASSERT(eventType == eventNames().webkitAnimationStartEvent); 331 if (m_startEventDispatched) 332 return false; 333 m_startEventDispatched = true; 334 listenerType = Document::ANIMATIONSTART_LISTENER; 335 } 336 337 if (shouldSendEventForListener(listenerType)) { 338 // Dispatch the event 339 RefPtr<Element> element; 340 if (m_object->node() && m_object->node()->isElementNode()) 341 element = static_cast<Element*>(m_object->node()); 342 343 ASSERT(!element || (element->document() && !element->document()->inPageCache())); 344 if (!element) 345 return false; 346 347 // Schedule event handling 348 m_compAnim->animationController()->addEventToDispatch(element, eventType, m_keyframes.animationName(), elapsedTime); 349 350 // Restore the original (unanimated) style 351 if (eventType == eventNames().webkitAnimationEndEvent && element->renderer()) 352 setNeedsStyleRecalc(element.get()); 353 354 return true; // Did dispatch an event 355 } 356 357 return false; // Did not dispatch an event 358 } 359 360 void KeyframeAnimation::overrideAnimations() 361 { 362 // This will override implicit animations that match the properties in the keyframe animation 363 HashSet<int>::const_iterator end = m_keyframes.endProperties(); 364 for (HashSet<int>::const_iterator it = m_keyframes.beginProperties(); it != end; ++it) 365 compositeAnimation()->overrideImplicitAnimations(*it); 366 } 367 368 void KeyframeAnimation::resumeOverriddenAnimations() 369 { 370 // This will resume overridden implicit animations 371 HashSet<int>::const_iterator end = m_keyframes.endProperties(); 372 for (HashSet<int>::const_iterator it = m_keyframes.beginProperties(); it != end; ++it) 373 compositeAnimation()->resumeOverriddenImplicitAnimations(*it); 374 } 375 376 bool KeyframeAnimation::affectsProperty(int property) const 377 { 378 HashSet<int>::const_iterator end = m_keyframes.endProperties(); 379 for (HashSet<int>::const_iterator it = m_keyframes.beginProperties(); it != end; ++it) { 380 if (*it == property) 381 return true; 382 } 383 return false; 384 } 385 386 void KeyframeAnimation::validateTransformFunctionList() 387 { 388 m_transformFunctionListValid = false; 389 390 if (m_keyframes.size() < 2 || !m_keyframes.containsProperty(CSSPropertyWebkitTransform)) 391 return; 392 393 // Empty transforms match anything, so find the first non-empty entry as the reference 394 size_t numKeyframes = m_keyframes.size(); 395 size_t firstNonEmptyTransformKeyframeIndex = numKeyframes; 396 397 for (size_t i = 0; i < numKeyframes; ++i) { 398 const KeyframeValue& currentKeyframe = m_keyframes[i]; 399 if (currentKeyframe.style()->transform().operations().size()) { 400 firstNonEmptyTransformKeyframeIndex = i; 401 break; 402 } 403 } 404 405 if (firstNonEmptyTransformKeyframeIndex == numKeyframes) 406 return; 407 408 const TransformOperations* firstVal = &m_keyframes[firstNonEmptyTransformKeyframeIndex].style()->transform(); 409 410 // See if the keyframes are valid 411 for (size_t i = firstNonEmptyTransformKeyframeIndex + 1; i < numKeyframes; ++i) { 412 const KeyframeValue& currentKeyframe = m_keyframes[i]; 413 const TransformOperations* val = ¤tKeyframe.style()->transform(); 414 415 // A null transform matches anything 416 if (val->operations().isEmpty()) 417 continue; 418 419 // If the sizes of the function lists don't match, the lists don't match 420 if (firstVal->operations().size() != val->operations().size()) 421 return; 422 423 // If the types of each function are not the same, the lists don't match 424 for (size_t j = 0; j < firstVal->operations().size(); ++j) { 425 if (!firstVal->operations()[j]->isSameType(*val->operations()[j])) 426 return; 427 } 428 } 429 430 // Keyframes are valid 431 m_transformFunctionListValid = true; 432 } 433 434 double KeyframeAnimation::timeToNextService() 435 { 436 double t = AnimationBase::timeToNextService(); 437 #if USE(ACCELERATED_COMPOSITING) 438 if (t != 0 || preActive()) 439 return t; 440 441 // A return value of 0 means we need service. But if we only have accelerated animations we 442 // only need service at the end of the transition 443 HashSet<int>::const_iterator endProperties = m_keyframes.endProperties(); 444 bool acceleratedPropertiesOnly = true; 445 446 for (HashSet<int>::const_iterator it = m_keyframes.beginProperties(); it != endProperties; ++it) { 447 if (!animationOfPropertyIsAccelerated(*it) || !isAccelerated()) { 448 acceleratedPropertiesOnly = false; 449 break; 450 } 451 } 452 453 if (acceleratedPropertiesOnly) { 454 bool isLooping; 455 getTimeToNextEvent(t, isLooping); 456 } 457 #endif 458 return t; 459 } 460 461 } // namespace WebCore 462