| OLD | NEW |
| (Empty) |
| 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 "core/frame/animation/AnimationBase.h" | |
| 31 | |
| 32 #include "core/frame/animation/AnimationControllerPrivate.h" | |
| 33 #include "core/frame/animation/CompositeAnimation.h" | |
| 34 #include "core/rendering/RenderBox.h" | |
| 35 #include "platform/animation/AnimationUtilities.h" | |
| 36 #include "platform/animation/TimingFunction.h" | |
| 37 #include <algorithm> | |
| 38 | |
| 39 using namespace std; | |
| 40 | |
| 41 namespace WebCore { | |
| 42 | |
| 43 AnimationBase::AnimationBase(const CSSAnimationData* transition, RenderObject& r
enderer, CompositeAnimation* compAnim) | |
| 44 : m_animState(AnimationStateNew) | |
| 45 , m_isAccelerated(false) | |
| 46 , m_transformFunctionListValid(false) | |
| 47 , m_filterFunctionListsMatch(false) | |
| 48 , m_startTime(0) | |
| 49 , m_pauseTime(-1) | |
| 50 , m_requestedStartTime(0) | |
| 51 , m_totalDuration(-1) | |
| 52 , m_nextIterationDuration(-1) | |
| 53 , m_object(&renderer) | |
| 54 , m_animation(const_cast<CSSAnimationData*>(transition)) | |
| 55 , m_compAnim(compAnim) | |
| 56 { | |
| 57 // Compute the total duration | |
| 58 if (m_animation->iterationCount() > 0) | |
| 59 m_totalDuration = m_animation->duration() * m_animation->iterationCount(
); | |
| 60 } | |
| 61 | |
| 62 void AnimationBase::setNeedsStyleRecalc(Node* node) | |
| 63 { | |
| 64 if (node) | |
| 65 node->setNeedsStyleRecalc(LocalStyleChange); | |
| 66 } | |
| 67 | |
| 68 double AnimationBase::duration() const | |
| 69 { | |
| 70 return m_animation->duration(); | |
| 71 } | |
| 72 | |
| 73 bool AnimationBase::playStatePlaying() const | |
| 74 { | |
| 75 return m_animation->playState() == AnimPlayStatePlaying; | |
| 76 } | |
| 77 | |
| 78 void AnimationBase::updateStateMachine(AnimStateInput input, double param) | |
| 79 { | |
| 80 if (!m_compAnim) | |
| 81 return; | |
| 82 | |
| 83 // If we get AnimationStateInputRestartAnimation then we force a new animati
on, regardless of state. | |
| 84 if (input == AnimationStateInputMakeNew) { | |
| 85 if (m_animState == AnimationStateStartWaitStyleAvailable) | |
| 86 m_compAnim->animationController()->removeFromAnimationsWaitingForSty
le(this); | |
| 87 m_animState = AnimationStateNew; | |
| 88 m_startTime = 0; | |
| 89 m_pauseTime = -1; | |
| 90 m_requestedStartTime = 0; | |
| 91 m_nextIterationDuration = -1; | |
| 92 endAnimation(); | |
| 93 return; | |
| 94 } | |
| 95 | |
| 96 if (input == AnimationStateInputRestartAnimation) { | |
| 97 if (m_animState == AnimationStateStartWaitStyleAvailable) | |
| 98 m_compAnim->animationController()->removeFromAnimationsWaitingForSty
le(this); | |
| 99 m_animState = AnimationStateNew; | |
| 100 m_startTime = 0; | |
| 101 m_pauseTime = -1; | |
| 102 m_requestedStartTime = 0; | |
| 103 m_nextIterationDuration = -1; | |
| 104 endAnimation(); | |
| 105 | |
| 106 if (!paused()) | |
| 107 updateStateMachine(AnimationStateInputStartAnimation, -1); | |
| 108 return; | |
| 109 } | |
| 110 | |
| 111 if (input == AnimationStateInputEndAnimation) { | |
| 112 if (m_animState == AnimationStateStartWaitStyleAvailable) | |
| 113 m_compAnim->animationController()->removeFromAnimationsWaitingForSty
le(this); | |
| 114 m_animState = AnimationStateDone; | |
| 115 endAnimation(); | |
| 116 return; | |
| 117 } | |
| 118 | |
| 119 if (input == AnimationStateInputPauseOverride) { | |
| 120 if (m_animState == AnimationStateStartWaitResponse) { | |
| 121 // If we are in AnimationStateStartWaitResponse, the animation will
get canceled before | |
| 122 // we get a response, so move to the next state. | |
| 123 endAnimation(); | |
| 124 updateStateMachine(AnimationStateInputStartTimeSet, beginAnimationUp
dateTime()); | |
| 125 } | |
| 126 return; | |
| 127 } | |
| 128 | |
| 129 if (input == AnimationStateInputResumeOverride) { | |
| 130 if (m_animState == AnimationStateLooping || m_animState == AnimationStat
eEnding) { | |
| 131 // Start the animation | |
| 132 startAnimation(beginAnimationUpdateTime() - m_startTime); | |
| 133 } | |
| 134 return; | |
| 135 } | |
| 136 | |
| 137 // Execute state machine | |
| 138 switch (m_animState) { | |
| 139 case AnimationStateNew: | |
| 140 ASSERT(input == AnimationStateInputStartAnimation || input == Animat
ionStateInputPlayStateRunning || input == AnimationStateInputPlayStatePaused); | |
| 141 if (input == AnimationStateInputStartAnimation || input == Animation
StateInputPlayStateRunning) { | |
| 142 m_requestedStartTime = beginAnimationUpdateTime(); | |
| 143 m_animState = AnimationStateStartWaitTimer; | |
| 144 } | |
| 145 break; | |
| 146 case AnimationStateStartWaitTimer: | |
| 147 ASSERT(input == AnimationStateInputStartTimerFired || input == Anima
tionStateInputPlayStatePaused); | |
| 148 | |
| 149 if (input == AnimationStateInputStartTimerFired) { | |
| 150 ASSERT(param >= 0); | |
| 151 // Start timer has fired, tell the animation to start and wait f
or it to respond with start time | |
| 152 m_animState = AnimationStateStartWaitStyleAvailable; | |
| 153 m_compAnim->animationController()->addToAnimationsWaitingForStyl
e(this); | |
| 154 | |
| 155 // Trigger a render so we can start the animation | |
| 156 if (m_object) | |
| 157 m_compAnim->animationController()->addNodeChangeToDispatch(m
_object->node()); | |
| 158 } else { | |
| 159 ASSERT(!paused()); | |
| 160 // We're waiting for the start timer to fire and we got a pause.
Cancel the timer, pause and wait | |
| 161 m_pauseTime = beginAnimationUpdateTime(); | |
| 162 m_animState = AnimationStatePausedWaitTimer; | |
| 163 } | |
| 164 break; | |
| 165 case AnimationStateStartWaitStyleAvailable: | |
| 166 ASSERT(input == AnimationStateInputStyleAvailable || input == Animat
ionStateInputPlayStatePaused); | |
| 167 | |
| 168 if (input == AnimationStateInputStyleAvailable) { | |
| 169 // Start timer has fired, tell the animation to start and wait f
or it to respond with start time | |
| 170 m_animState = AnimationStateStartWaitResponse; | |
| 171 | |
| 172 overrideAnimations(); | |
| 173 | |
| 174 // Start the animation | |
| 175 if (overridden()) { | |
| 176 m_animState = AnimationStateStartWaitResponse; | |
| 177 updateStateMachine(AnimationStateInputStartTimeSet, beginAni
mationUpdateTime()); | |
| 178 } else { | |
| 179 double timeOffset = 0; | |
| 180 // If the value for 'animation-delay' is negative then the a
nimation appears to have started in the past. | |
| 181 if (m_animation->delay() < 0) | |
| 182 timeOffset = -m_animation->delay(); | |
| 183 startAnimation(timeOffset); | |
| 184 m_compAnim->animationController()->addToAnimationsWaitingFor
StartTimeResponse(this, isAccelerated()); | |
| 185 } | |
| 186 } else { | |
| 187 // We're waiting for the style to be available and we got a paus
e. Pause and wait | |
| 188 m_pauseTime = beginAnimationUpdateTime(); | |
| 189 m_animState = AnimationStatePausedWaitStyleAvailable; | |
| 190 } | |
| 191 break; | |
| 192 case AnimationStateStartWaitResponse: | |
| 193 ASSERT(input == AnimationStateInputStartTimeSet || input == Animatio
nStateInputPlayStatePaused); | |
| 194 | |
| 195 if (input == AnimationStateInputStartTimeSet) { | |
| 196 ASSERT(param >= 0); | |
| 197 // We have a start time, set it, unless the startTime is already
set | |
| 198 if (m_startTime <= 0) { | |
| 199 m_startTime = param; | |
| 200 // If the value for 'animation-delay' is negative then the a
nimation appears to have started in the past. | |
| 201 if (m_animation->delay() < 0) | |
| 202 m_startTime += m_animation->delay(); | |
| 203 } | |
| 204 | |
| 205 // Now that we know the start time, fire the start event. | |
| 206 onAnimationStart(0); // The elapsedTime is 0. | |
| 207 | |
| 208 // Decide whether to go into looping or ending state | |
| 209 goIntoEndingOrLoopingState(); | |
| 210 | |
| 211 // Dispatch updateStyleIfNeeded so we can start the animation | |
| 212 if (m_object) | |
| 213 m_compAnim->animationController()->addNodeChangeToDispatch(m
_object->node()); | |
| 214 } else { | |
| 215 // We are pausing while waiting for a start response. Cancel the
animation and wait. When | |
| 216 // we unpause, we will act as though the start timer just fired | |
| 217 m_pauseTime = beginAnimationUpdateTime(); | |
| 218 pauseAnimation(beginAnimationUpdateTime() - m_startTime); | |
| 219 m_animState = AnimationStatePausedWaitResponse; | |
| 220 } | |
| 221 break; | |
| 222 case AnimationStateLooping: | |
| 223 ASSERT(input == AnimationStateInputLoopTimerFired || input == Animat
ionStateInputPlayStatePaused); | |
| 224 | |
| 225 if (input == AnimationStateInputLoopTimerFired) { | |
| 226 ASSERT(param >= 0); | |
| 227 // Loop timer fired, loop again or end. | |
| 228 onAnimationIteration(param); | |
| 229 | |
| 230 // Decide whether to go into looping or ending state | |
| 231 goIntoEndingOrLoopingState(); | |
| 232 } else { | |
| 233 // We are pausing while running. Cancel the animation and wait | |
| 234 m_pauseTime = beginAnimationUpdateTime(); | |
| 235 pauseAnimation(beginAnimationUpdateTime() - m_startTime); | |
| 236 m_animState = AnimationStatePausedRun; | |
| 237 } | |
| 238 break; | |
| 239 case AnimationStateEnding: | |
| 240 #if !LOG_DISABLED | |
| 241 if (input != AnimationStateInputEndTimerFired && input != AnimationS
tateInputPlayStatePaused) | |
| 242 WTF_LOG_ERROR("State is AnimationStateEnding, but input is not A
nimationStateInputEndTimerFired or AnimationStateInputPlayStatePaused. It is %d.
", input); | |
| 243 #endif | |
| 244 if (input == AnimationStateInputEndTimerFired) { | |
| 245 | |
| 246 ASSERT(param >= 0); | |
| 247 // End timer fired, finish up | |
| 248 onAnimationEnd(param); | |
| 249 | |
| 250 m_animState = AnimationStateDone; | |
| 251 | |
| 252 if (m_object) { | |
| 253 if (m_animation->fillsForwards()) | |
| 254 m_animState = AnimationStateFillingForwards; | |
| 255 else | |
| 256 resumeOverriddenAnimations(); | |
| 257 | |
| 258 // Fire off another style change so we can set the final val
ue | |
| 259 m_compAnim->animationController()->addNodeChangeToDispatch(m
_object->node()); | |
| 260 } | |
| 261 } else { | |
| 262 // We are pausing while running. Cancel the animation and wait | |
| 263 m_pauseTime = beginAnimationUpdateTime(); | |
| 264 pauseAnimation(beginAnimationUpdateTime() - m_startTime); | |
| 265 m_animState = AnimationStatePausedRun; | |
| 266 } | |
| 267 // |this| may be deleted here | |
| 268 break; | |
| 269 case AnimationStatePausedWaitTimer: | |
| 270 ASSERT(input == AnimationStateInputPlayStateRunning); | |
| 271 ASSERT(paused()); | |
| 272 // Update the times | |
| 273 m_startTime += beginAnimationUpdateTime() - m_pauseTime; | |
| 274 m_pauseTime = -1; | |
| 275 | |
| 276 // we were waiting for the start timer to fire, go back and wait aga
in | |
| 277 m_animState = AnimationStateNew; | |
| 278 updateStateMachine(AnimationStateInputStartAnimation, 0); | |
| 279 break; | |
| 280 case AnimationStatePausedWaitResponse: | |
| 281 case AnimationStatePausedWaitStyleAvailable: | |
| 282 case AnimationStatePausedRun: | |
| 283 // We treat these two cases the same. The only difference is that, w
hen we are in | |
| 284 // AnimationStatePausedWaitResponse, we don't yet have a valid start
Time, so we send 0 to startAnimation. | |
| 285 // When the AnimationStateInputStartTimeSet comes in and we were in
AnimationStatePausedRun, we will notice | |
| 286 // that we have already set the startTime and will ignore it. | |
| 287 ASSERT(input == AnimationStateInputPlayStateRunning || input == Anim
ationStateInputStartTimeSet || input == AnimationStateInputStyleAvailable); | |
| 288 ASSERT(paused()); | |
| 289 | |
| 290 if (input == AnimationStateInputPlayStateRunning) { | |
| 291 // Update the times | |
| 292 if (m_animState == AnimationStatePausedRun) | |
| 293 m_startTime += beginAnimationUpdateTime() - m_pauseTime; | |
| 294 else | |
| 295 m_startTime = 0; | |
| 296 m_pauseTime = -1; | |
| 297 | |
| 298 if (m_animState == AnimationStatePausedWaitStyleAvailable) | |
| 299 m_animState = AnimationStateStartWaitStyleAvailable; | |
| 300 else { | |
| 301 // We were either running or waiting for a begin time respon
se from the animation. | |
| 302 // Either way we need to restart the animation (possibly wit
h an offset if we | |
| 303 // had already been running) and wait for it to start. | |
| 304 m_animState = AnimationStateStartWaitResponse; | |
| 305 | |
| 306 // Start the animation | |
| 307 if (overridden()) { | |
| 308 updateStateMachine(AnimationStateInputStartTimeSet, begi
nAnimationUpdateTime()); | |
| 309 } else { | |
| 310 startAnimation(beginAnimationUpdateTime() - m_startTime)
; | |
| 311 m_compAnim->animationController()->addToAnimationsWaitin
gForStartTimeResponse(this, isAccelerated()); | |
| 312 } | |
| 313 } | |
| 314 break; | |
| 315 } | |
| 316 | |
| 317 if (input == AnimationStateInputStartTimeSet) { | |
| 318 ASSERT(m_animState == AnimationStatePausedWaitResponse); | |
| 319 | |
| 320 // We are paused but we got the callback that notifies us that a
n accelerated animation started. | |
| 321 // We ignore the start time and just move into the paused-run st
ate. | |
| 322 m_animState = AnimationStatePausedRun; | |
| 323 ASSERT(m_startTime == 0); | |
| 324 m_startTime = param; | |
| 325 m_pauseTime += m_startTime; | |
| 326 break; | |
| 327 } | |
| 328 | |
| 329 ASSERT(m_animState == AnimationStatePausedWaitStyleAvailable); | |
| 330 // We are paused but we got the callback that notifies us that style
has been updated. | |
| 331 // We move to the AnimationStatePausedWaitResponse state | |
| 332 m_animState = AnimationStatePausedWaitResponse; | |
| 333 overrideAnimations(); | |
| 334 break; | |
| 335 case AnimationStateFillingForwards: | |
| 336 case AnimationStateDone: | |
| 337 // We're done. Stay in this state until we are deleted | |
| 338 break; | |
| 339 } | |
| 340 } | |
| 341 | |
| 342 void AnimationBase::fireAnimationEventsIfNeeded() | |
| 343 { | |
| 344 if (!m_compAnim) | |
| 345 return; | |
| 346 | |
| 347 // If we are waiting for the delay time to expire and it has, go to the next
state | |
| 348 if (m_animState != AnimationStateStartWaitTimer && m_animState != AnimationS
tateLooping && m_animState != AnimationStateEnding) | |
| 349 return; | |
| 350 | |
| 351 // We have to make sure to keep a ref to the this pointer, because it could
get destroyed | |
| 352 // during an animation callback that might get called. Since the owner is a
CompositeAnimation | |
| 353 // and it ref counts this object, we will keep a ref to that instead. That w
ay the AnimationBase | |
| 354 // can still access the resources of its CompositeAnimation as needed. | |
| 355 RefPtr<AnimationBase> protector(this); | |
| 356 RefPtr<CompositeAnimation> compProtector(m_compAnim); | |
| 357 | |
| 358 // Check for start timeout | |
| 359 if (m_animState == AnimationStateStartWaitTimer) { | |
| 360 if (beginAnimationUpdateTime() - m_requestedStartTime >= m_animation->de
lay()) | |
| 361 updateStateMachine(AnimationStateInputStartTimerFired, 0); | |
| 362 return; | |
| 363 } | |
| 364 | |
| 365 double elapsedDuration = getElapsedTime(); | |
| 366 | |
| 367 // Check for end timeout | |
| 368 if (m_totalDuration >= 0 && elapsedDuration >= m_totalDuration) { | |
| 369 // We may still be in AnimationStateLooping if we've managed to skip a | |
| 370 // whole iteration, in which case we should jump to the end state. | |
| 371 m_animState = AnimationStateEnding; | |
| 372 | |
| 373 // Fire an end event | |
| 374 updateStateMachine(AnimationStateInputEndTimerFired, m_totalDuration); | |
| 375 } else { | |
| 376 // Check for iteration timeout | |
| 377 if (m_nextIterationDuration < 0) { | |
| 378 // Hasn't been set yet, set it | |
| 379 double durationLeft = m_animation->duration() - fmod(elapsedDuration
, m_animation->duration()); | |
| 380 m_nextIterationDuration = elapsedDuration + durationLeft; | |
| 381 } | |
| 382 | |
| 383 if (elapsedDuration >= m_nextIterationDuration) { | |
| 384 // Set to the next iteration | |
| 385 double previous = m_nextIterationDuration; | |
| 386 double durationLeft = m_animation->duration() - fmod(elapsedDuration
, m_animation->duration()); | |
| 387 m_nextIterationDuration = elapsedDuration + durationLeft; | |
| 388 | |
| 389 // Send the event | |
| 390 updateStateMachine(AnimationStateInputLoopTimerFired, previous); | |
| 391 } | |
| 392 } | |
| 393 } | |
| 394 | |
| 395 void AnimationBase::updatePlayState(EAnimPlayState playState) | |
| 396 { | |
| 397 if (!m_compAnim) | |
| 398 return; | |
| 399 | |
| 400 // Set the state machine to the desired state. | |
| 401 bool pause = playState == AnimPlayStatePaused; | |
| 402 | |
| 403 if (pause == paused() && !isNew()) | |
| 404 return; | |
| 405 | |
| 406 updateStateMachine(pause ? AnimationStateInputPlayStatePaused : AnimationSt
ateInputPlayStateRunning, -1); | |
| 407 } | |
| 408 | |
| 409 double AnimationBase::timeToNextService() | |
| 410 { | |
| 411 // Returns the time at which next service is required. -1 means no service i
s required. 0 means | |
| 412 // service is required now, and > 0 means service is required that many seco
nds in the future. | |
| 413 if (paused() || isNew() || m_animState == AnimationStateFillingForwards) | |
| 414 return -1; | |
| 415 | |
| 416 if (m_animState == AnimationStateStartWaitTimer) { | |
| 417 double timeFromNow = m_animation->delay() - (beginAnimationUpdateTime()
- m_requestedStartTime); | |
| 418 return max(timeFromNow, 0.0); | |
| 419 } | |
| 420 | |
| 421 fireAnimationEventsIfNeeded(); | |
| 422 | |
| 423 // In all other cases, we need service right away. | |
| 424 return 0; | |
| 425 } | |
| 426 | |
| 427 // Compute the fractional time, taking into account direction. | |
| 428 // There is no need to worry about iterations, we assume that we would have | |
| 429 // short circuited above if we were done. | |
| 430 | |
| 431 double AnimationBase::fractionalTime(double scale, double elapsedTime, double of
fset) const | |
| 432 { | |
| 433 double fractionalTime = m_animation->duration() ? (elapsedTime / m_animation
->duration()) : 1; | |
| 434 // FIXME: startTime can be before the current animation "frame" time. This i
s to sync with the frame time | |
| 435 // concept in AnimationTimeController. So we need to somehow sync the two. U
ntil then, the possible | |
| 436 // error is small and will probably not be noticeable. Until we fix this, re
move the assert. | |
| 437 // https://bugs.webkit.org/show_bug.cgi?id=52037 | |
| 438 // ASSERT(fractionalTime >= 0); | |
| 439 if (fractionalTime < 0) | |
| 440 fractionalTime = 0; | |
| 441 | |
| 442 int integralTime = static_cast<int>(fractionalTime); | |
| 443 const int integralIterationCount = static_cast<int>(m_animation->iterationCo
unt()); | |
| 444 const bool iterationCountHasFractional = m_animation->iterationCount() - int
egralIterationCount; | |
| 445 if (m_animation->iterationCount() != CSSAnimationData::IterationCountInfinit
e && !iterationCountHasFractional) | |
| 446 integralTime = min(integralTime, integralIterationCount - 1); | |
| 447 | |
| 448 fractionalTime -= integralTime; | |
| 449 | |
| 450 // Thie method can be called with an elapsedTime which very slightly | |
| 451 // exceeds the end of the animation. In this case, clamp the | |
| 452 // fractionalTime. | |
| 453 if (fractionalTime > 1) | |
| 454 fractionalTime = 1; | |
| 455 ASSERT(fractionalTime >= 0 && fractionalTime <= 1); | |
| 456 | |
| 457 if (((m_animation->direction() == CSSAnimationData::AnimationDirectionAltern
ate) && (integralTime & 1)) | |
| 458 || ((m_animation->direction() == CSSAnimationData::AnimationDirectionAlt
ernateReverse) && !(integralTime & 1)) | |
| 459 || m_animation->direction() == CSSAnimationData::AnimationDirectionRever
se) | |
| 460 fractionalTime = 1 - fractionalTime; | |
| 461 | |
| 462 fractionalTime -= offset; | |
| 463 // Note that if fractionalTime == 0 here, scale may be infinity, but in | |
| 464 // this case we don't need to apply scale anyway. | |
| 465 if (scale != 1.0 && fractionalTime) { | |
| 466 ASSERT(scale >= 0 && !std::isinf(scale)); | |
| 467 fractionalTime *= scale; | |
| 468 } | |
| 469 | |
| 470 ASSERT(fractionalTime >= 0 && fractionalTime <= 1); | |
| 471 return fractionalTime; | |
| 472 } | |
| 473 | |
| 474 double AnimationBase::progress(double scale, double offset, const TimingFunction
* timingFunction) const | |
| 475 { | |
| 476 if (preActive()) | |
| 477 return 0; | |
| 478 | |
| 479 double dur = m_animation->duration(); | |
| 480 if (m_animation->iterationCount() > 0) | |
| 481 dur *= m_animation->iterationCount(); | |
| 482 | |
| 483 if (postActive() || !m_animation->duration()) | |
| 484 return 1.0; | |
| 485 | |
| 486 double elapsedTime = getElapsedTime(); | |
| 487 if (m_animation->iterationCount() > 0 && elapsedTime >= dur) { | |
| 488 const int integralIterationCount = static_cast<int>(m_animation->iterati
onCount()); | |
| 489 const bool iterationCountHasFractional = m_animation->iterationCount() -
integralIterationCount; | |
| 490 return (integralIterationCount % 2 || iterationCountHasFractional) ? 1.0
: 0.0; | |
| 491 } | |
| 492 | |
| 493 const double fractionalTime = this->fractionalTime(scale, elapsedTime, offse
t); | |
| 494 | |
| 495 if (!timingFunction) | |
| 496 timingFunction = m_animation->timingFunction(); | |
| 497 | |
| 498 return timingFunction->evaluate(fractionalTime, accuracyForDuration(m_animat
ion->duration())); | |
| 499 } | |
| 500 | |
| 501 void AnimationBase::getTimeToNextEvent(double& time, bool& isLooping) const | |
| 502 { | |
| 503 if (postActive()) { | |
| 504 time = -1; | |
| 505 isLooping = false; | |
| 506 return; | |
| 507 } | |
| 508 | |
| 509 // Decide when the end or loop event needs to fire | |
| 510 const double elapsedDuration = getElapsedTime(); | |
| 511 double durationLeft = 0; | |
| 512 double nextIterationTime = m_totalDuration; | |
| 513 | |
| 514 if (m_totalDuration < 0 || elapsedDuration < m_totalDuration) { | |
| 515 durationLeft = m_animation->duration() > 0 ? (m_animation->duration() -
fmod(elapsedDuration, m_animation->duration())) : 0; | |
| 516 nextIterationTime = elapsedDuration + durationLeft; | |
| 517 } | |
| 518 | |
| 519 if (m_totalDuration < 0 || nextIterationTime < m_totalDuration) { | |
| 520 // We are not at the end yet | |
| 521 ASSERT(m_totalDuration < 0 || nextIterationTime > 0); | |
| 522 isLooping = true; | |
| 523 } else { | |
| 524 // We are at the end | |
| 525 isLooping = false; | |
| 526 } | |
| 527 | |
| 528 time = durationLeft; | |
| 529 } | |
| 530 | |
| 531 void AnimationBase::goIntoEndingOrLoopingState() | |
| 532 { | |
| 533 double t; | |
| 534 bool isLooping; | |
| 535 getTimeToNextEvent(t, isLooping); | |
| 536 m_animState = isLooping ? AnimationStateLooping : AnimationStateEnding; | |
| 537 } | |
| 538 | |
| 539 void AnimationBase::freezeAtTime(double t) | |
| 540 { | |
| 541 if (!m_compAnim) | |
| 542 return; | |
| 543 | |
| 544 if (!m_startTime) { | |
| 545 // If we haven't started yet, make it as if we started. | |
| 546 m_animState = AnimationStateStartWaitResponse; | |
| 547 onAnimationStartResponse(beginAnimationUpdateTime()); | |
| 548 } | |
| 549 | |
| 550 ASSERT(m_startTime); // if m_startTime is zero, we haven't started ye
t, so we'll get a bad pause time. | |
| 551 if (t <= m_animation->delay()) | |
| 552 m_pauseTime = m_startTime; | |
| 553 else | |
| 554 m_pauseTime = m_startTime + t - m_animation->delay(); | |
| 555 | |
| 556 // It is possible that m_isAccelerated is true and m_object->compositingStat
e() is NotComposited, because of style change. | |
| 557 // So, both conditions need to be checked. | |
| 558 if (m_object && m_object->compositingState() == PaintsIntoOwnBacking && isAc
celerated()) | |
| 559 pauseAnimation(t); | |
| 560 } | |
| 561 | |
| 562 double AnimationBase::beginAnimationUpdateTime() const | |
| 563 { | |
| 564 if (!m_compAnim) | |
| 565 return 0; | |
| 566 | |
| 567 return m_compAnim->animationController()->beginAnimationUpdateTime(); | |
| 568 } | |
| 569 | |
| 570 double AnimationBase::getElapsedTime() const | |
| 571 { | |
| 572 ASSERT(!postActive()); | |
| 573 if (paused()) | |
| 574 return m_pauseTime - m_startTime; | |
| 575 if (m_startTime <= 0) | |
| 576 return 0; | |
| 577 | |
| 578 double elapsedTime = beginAnimationUpdateTime() - m_startTime; | |
| 579 // It's possible for the start time to be ahead of the last update time | |
| 580 // if the compositor has just sent notification for the start of an | |
| 581 // accelerated animation. | |
| 582 return max(elapsedTime, 0.0); | |
| 583 } | |
| 584 | |
| 585 } // namespace WebCore | |
| OLD | NEW |