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 namespace WebCore { 43 44 KeyframeAnimation::KeyframeAnimation(const Animation* animation, RenderObject* renderer, int index, CompositeAnimation* compAnim, RenderStyle* unanimatedStyle) 45 : AnimationBase(animation, renderer, compAnim) 46 , m_keyframes(renderer, animation->name()) 47 , m_index(index) 48 , m_unanimatedStyle(unanimatedStyle) 49 { 50 // Get the keyframe RenderStyles 51 if (m_object && m_object->node() && m_object->node()->isElementNode()) 52 m_object->document()->styleSelector()->keyframeStylesForAnimation(static_cast<Element*>(m_object->node()), unanimatedStyle, m_keyframes); 53 54 // Update the m_transformFunctionListValid flag based on whether the function lists in the keyframes match. 55 validateTransformFunctionList(); 56 } 57 58 KeyframeAnimation::~KeyframeAnimation() 59 { 60 // Make sure to tell the renderer that we are ending. This will make sure any accelerated animations are removed. 61 if (!postActive()) 62 endAnimation(); 63 } 64 65 void KeyframeAnimation::getKeyframeAnimationInterval(const RenderStyle*& fromStyle, const RenderStyle*& toStyle, double& prog) const 66 { 67 // Find the first key 68 double elapsedTime = getElapsedTime(); 69 70 double t = m_animation->duration() ? (elapsedTime / m_animation->duration()) : 1; 71 int i = static_cast<int>(t); 72 t -= i; 73 if (m_animation->direction() && (i & 1)) 74 t = 1 - t; 75 76 double scale = 1; 77 double offset = 0; 78 Vector<KeyframeValue>::const_iterator endKeyframes = m_keyframes.endKeyframes(); 79 for (Vector<KeyframeValue>::const_iterator it = m_keyframes.beginKeyframes(); it != endKeyframes; ++it) { 80 if (t < it->key()) { 81 // The first key should always be 0, so we should never succeed on the first key 82 if (!fromStyle) 83 break; 84 scale = 1.0 / (it->key() - offset); 85 toStyle = it->style(); 86 break; 87 } 88 89 offset = it->key(); 90 fromStyle = it->style(); 91 } 92 93 if (!fromStyle || !toStyle) 94 return; 95 96 const TimingFunction* timingFunction = 0; 97 if (fromStyle->animations() && fromStyle->animations()->size() > 0) { 98 // We get the timing function from the first animation, because we've synthesized a RenderStyle for each keyframe. 99 timingFunction = &(fromStyle->animations()->animation(0)->timingFunction()); 100 } 101 102 prog = progress(scale, offset, timingFunction); 103 } 104 105 void KeyframeAnimation::animate(CompositeAnimation*, RenderObject*, const RenderStyle*, RenderStyle* targetStyle, RefPtr<RenderStyle>& animatedStyle) 106 { 107 // Fire the start timeout if needed 108 fireAnimationEventsIfNeeded(); 109 110 // If we have not yet started, we will not have a valid start time, so just start the animation if needed. 111 if (isNew() && m_animation->playState() == AnimPlayStatePlaying) 112 updateStateMachine(AnimationStateInputStartAnimation, -1); 113 114 // If we get this far and the animation is done, it means we are cleaning up a just finished animation. 115 // If so, we need to send back the targetStyle. 116 if (postActive()) { 117 if (!animatedStyle) 118 animatedStyle = const_cast<RenderStyle*>(targetStyle); 119 return; 120 } 121 122 // If we are waiting for the start timer, we don't want to change the style yet. 123 // Special case - if the delay time is 0, then we do want to set the first frame of the 124 // animation right away. This avoids a flash when the animation starts. 125 if (waitingToStart() && m_animation->delay() > 0) 126 return; 127 128 // FIXME: we need to be more efficient about determining which keyframes we are animating between. 129 // We should cache the last pair or something. 130 131 // Get the from/to styles and progress between 132 const RenderStyle* fromStyle = 0; 133 const RenderStyle* toStyle = 0; 134 double progress; 135 getKeyframeAnimationInterval(fromStyle, toStyle, progress); 136 137 // If either style is 0 we have an invalid case, just stop the animation. 138 if (!fromStyle || !toStyle) { 139 updateStateMachine(AnimationStateInputEndAnimation, -1); 140 return; 141 } 142 143 // Run a cycle of animation. 144 // We know we will need a new render style, so make one if needed. 145 if (!animatedStyle) 146 animatedStyle = RenderStyle::clone(targetStyle); 147 148 HashSet<int>::const_iterator endProperties = m_keyframes.endProperties(); 149 for (HashSet<int>::const_iterator it = m_keyframes.beginProperties(); it != endProperties; ++it) { 150 bool needsAnim = blendProperties(this, *it, animatedStyle.get(), fromStyle, toStyle, progress); 151 if (needsAnim) 152 setAnimating(); 153 else { 154 #if USE(ACCELERATED_COMPOSITING) 155 // If we are running an accelerated animation, set a flag in the style 156 // to indicate it. This can be used to make sure we get an updated 157 // style for hit testing, etc. 158 animatedStyle->setIsRunningAcceleratedAnimation(); 159 #endif 160 } 161 } 162 } 163 164 void KeyframeAnimation::getAnimatedStyle(RefPtr<RenderStyle>& animatedStyle) 165 { 166 // Get the from/to styles and progress between 167 const RenderStyle* fromStyle = 0; 168 const RenderStyle* toStyle = 0; 169 double progress; 170 getKeyframeAnimationInterval(fromStyle, toStyle, progress); 171 172 // If either style is 0 we have an invalid case 173 if (!fromStyle || !toStyle) 174 return; 175 176 if (!animatedStyle) 177 animatedStyle = RenderStyle::clone(m_object->style()); 178 179 HashSet<int>::const_iterator endProperties = m_keyframes.endProperties(); 180 for (HashSet<int>::const_iterator it = m_keyframes.beginProperties(); it != endProperties; ++it) 181 blendProperties(this, *it, animatedStyle.get(), fromStyle, toStyle, progress); 182 } 183 184 bool KeyframeAnimation::hasAnimationForProperty(int property) const 185 { 186 HashSet<int>::const_iterator end = m_keyframes.endProperties(); 187 for (HashSet<int>::const_iterator it = m_keyframes.beginProperties(); it != end; ++it) { 188 if (*it == property) 189 return true; 190 } 191 192 return false; 193 } 194 195 bool KeyframeAnimation::startAnimation(double timeOffset) 196 { 197 #if USE(ACCELERATED_COMPOSITING) 198 if (m_object && m_object->hasLayer()) { 199 RenderLayer* layer = toRenderBoxModelObject(m_object)->layer(); 200 if (layer->isComposited()) 201 return layer->backing()->startAnimation(timeOffset, m_animation.get(), m_keyframes); 202 } 203 #else 204 UNUSED_PARAM(timeOffset); 205 #endif 206 return false; 207 } 208 209 void KeyframeAnimation::pauseAnimation(double timeOffset) 210 { 211 if (!m_object) 212 return; 213 214 #if USE(ACCELERATED_COMPOSITING) 215 if (m_object->hasLayer()) { 216 RenderLayer* layer = toRenderBoxModelObject(m_object)->layer(); 217 if (layer->isComposited()) 218 layer->backing()->animationPaused(timeOffset, m_keyframes.animationName()); 219 } 220 #else 221 UNUSED_PARAM(timeOffset); 222 #endif 223 // Restore the original (unanimated) style 224 if (!paused()) 225 setNeedsStyleRecalc(m_object->node()); 226 } 227 228 void KeyframeAnimation::endAnimation() 229 { 230 if (!m_object) 231 return; 232 233 #if USE(ACCELERATED_COMPOSITING) 234 if (m_object->hasLayer()) { 235 RenderLayer* layer = toRenderBoxModelObject(m_object)->layer(); 236 if (layer->isComposited()) 237 layer->backing()->animationFinished(m_keyframes.animationName()); 238 } 239 #endif 240 // Restore the original (unanimated) style 241 if (!paused()) 242 setNeedsStyleRecalc(m_object->node()); 243 } 244 245 bool KeyframeAnimation::shouldSendEventForListener(Document::ListenerType listenerType) const 246 { 247 return m_object->document()->hasListenerType(listenerType); 248 } 249 250 void KeyframeAnimation::onAnimationStart(double elapsedTime) 251 { 252 sendAnimationEvent(eventNames().webkitAnimationStartEvent, elapsedTime); 253 } 254 255 void KeyframeAnimation::onAnimationIteration(double elapsedTime) 256 { 257 sendAnimationEvent(eventNames().webkitAnimationIterationEvent, elapsedTime); 258 } 259 260 void KeyframeAnimation::onAnimationEnd(double elapsedTime) 261 { 262 sendAnimationEvent(eventNames().webkitAnimationEndEvent, elapsedTime); 263 endAnimation(); 264 } 265 266 bool KeyframeAnimation::sendAnimationEvent(const AtomicString& eventType, double elapsedTime) 267 { 268 Document::ListenerType listenerType; 269 if (eventType == eventNames().webkitAnimationIterationEvent) 270 listenerType = Document::ANIMATIONITERATION_LISTENER; 271 else if (eventType == eventNames().webkitAnimationEndEvent) 272 listenerType = Document::ANIMATIONEND_LISTENER; 273 else { 274 ASSERT(eventType == eventNames().webkitAnimationStartEvent); 275 listenerType = Document::ANIMATIONSTART_LISTENER; 276 } 277 278 if (shouldSendEventForListener(listenerType)) { 279 // Dispatch the event 280 RefPtr<Element> element; 281 if (m_object->node() && m_object->node()->isElementNode()) 282 element = static_cast<Element*>(m_object->node()); 283 284 ASSERT(!element || (element->document() && !element->document()->inPageCache())); 285 if (!element) 286 return false; 287 288 // Schedule event handling 289 m_compAnim->animationController()->addEventToDispatch(element, eventType, m_keyframes.animationName(), elapsedTime); 290 291 // Restore the original (unanimated) style 292 if (eventType == eventNames().webkitAnimationEndEvent && element->renderer()) 293 setNeedsStyleRecalc(element.get()); 294 295 return true; // Did dispatch an event 296 } 297 298 return false; // Did not dispatch an event 299 } 300 301 void KeyframeAnimation::overrideAnimations() 302 { 303 // This will override implicit animations that match the properties in the keyframe animation 304 HashSet<int>::const_iterator end = m_keyframes.endProperties(); 305 for (HashSet<int>::const_iterator it = m_keyframes.beginProperties(); it != end; ++it) 306 compositeAnimation()->overrideImplicitAnimations(*it); 307 } 308 309 void KeyframeAnimation::resumeOverriddenAnimations() 310 { 311 // This will resume overridden implicit animations 312 HashSet<int>::const_iterator end = m_keyframes.endProperties(); 313 for (HashSet<int>::const_iterator it = m_keyframes.beginProperties(); it != end; ++it) 314 compositeAnimation()->resumeOverriddenImplicitAnimations(*it); 315 } 316 317 bool KeyframeAnimation::affectsProperty(int property) const 318 { 319 HashSet<int>::const_iterator end = m_keyframes.endProperties(); 320 for (HashSet<int>::const_iterator it = m_keyframes.beginProperties(); it != end; ++it) { 321 if (*it == property) 322 return true; 323 } 324 return false; 325 } 326 327 void KeyframeAnimation::validateTransformFunctionList() 328 { 329 m_transformFunctionListValid = false; 330 331 if (m_keyframes.size() < 2 || !m_keyframes.containsProperty(CSSPropertyWebkitTransform)) 332 return; 333 334 Vector<KeyframeValue>::const_iterator end = m_keyframes.endKeyframes(); 335 336 // Empty transforms match anything, so find the first non-empty entry as the reference 337 size_t firstIndex = 0; 338 Vector<KeyframeValue>::const_iterator firstIt = end; 339 340 for (Vector<KeyframeValue>::const_iterator it = m_keyframes.beginKeyframes(); it != end; ++it, ++firstIndex) { 341 if (it->style()->transform().operations().size() > 0) { 342 firstIt = it; 343 break; 344 } 345 } 346 347 if (firstIt == end) 348 return; 349 350 const TransformOperations* firstVal = &firstIt->style()->transform(); 351 352 // See if the keyframes are valid 353 for (Vector<KeyframeValue>::const_iterator it = firstIt+1; it != end; ++it) { 354 const TransformOperations* val = &it->style()->transform(); 355 356 // A null transform matches anything 357 if (val->operations().isEmpty()) 358 continue; 359 360 // If the sizes of the function lists don't match, the lists don't match 361 if (firstVal->operations().size() != val->operations().size()) 362 return; 363 364 // If the types of each function are not the same, the lists don't match 365 for (size_t j = 0; j < firstVal->operations().size(); ++j) { 366 if (!firstVal->operations()[j]->isSameType(*val->operations()[j])) 367 return; 368 } 369 } 370 371 // Keyframes are valid 372 m_transformFunctionListValid = true; 373 } 374 375 double KeyframeAnimation::timeToNextService() 376 { 377 double t = AnimationBase::timeToNextService(); 378 #if USE(ACCELERATED_COMPOSITING) 379 if (t != 0 || preActive()) 380 return t; 381 382 // A return value of 0 means we need service. But if we only have accelerated animations we 383 // only need service at the end of the transition 384 HashSet<int>::const_iterator endProperties = m_keyframes.endProperties(); 385 bool acceleratedPropertiesOnly = true; 386 387 for (HashSet<int>::const_iterator it = m_keyframes.beginProperties(); it != endProperties; ++it) { 388 if (!animationOfPropertyIsAccelerated(*it) || isFallbackAnimating()) { 389 acceleratedPropertiesOnly = false; 390 break; 391 } 392 } 393 394 if (acceleratedPropertiesOnly) { 395 bool isLooping; 396 getTimeToNextEvent(t, isLooping); 397 } 398 #endif 399 return t; 400 } 401 402 } // namespace WebCore 403