bool MemoryWatcher::timerTicked() { if (m_state != m_lastNotifiedState) { m_lastNotifiedState = m_state; signalMemoryStateChanged.fire(m_lastNotifiedState); } if (m_state == Normal) { return true; } else if (m_state == Medium) { static int count = 0; if (count++ > kMinIntervalBetweenMediumMemActionsMs) { malloc_trim(0); count = 0; } return true; } m_currRssUsage = getCurrentRssUsage(); g_warning("WebKit MemoryWatcher: LOW MEMORY: State: %s, current RSS usage: %dMB\n", nameForState(m_state), m_currRssUsage); doLowMemActions(true); return true; }
void AnimationBase::goIntoEndingOrLoopingState() { double t; bool isLooping; getTimeToNextEvent(t, isLooping); LOG(Animations, "%p AnimationState %s -> %s", this, nameForState(m_animState), isLooping ? "Looping" : "Ending"); m_animState = isLooping ? AnimationStateLooping : AnimationStateEnding; }
void AnimationBase::fireAnimationEventsIfNeeded() { if (!m_compAnim) return; // If we are waiting for the delay time to expire and it has, go to the next state if (m_animState != AnimationStateStartWaitTimer && m_animState != AnimationStateLooping && m_animState != AnimationStateEnding) return; // We have to make sure to keep a ref to the this pointer, because it could get destroyed // during an animation callback that might get called. Since the owner is a CompositeAnimation // and it ref counts this object, we will keep a ref to that instead. That way the AnimationBase // can still access the resources of its CompositeAnimation as needed. Ref<AnimationBase> protect(*this); Ref<CompositeAnimation> protectCompositeAnimation(*m_compAnim); // Check for start timeout if (m_animState == AnimationStateStartWaitTimer) { if (beginAnimationUpdateTime() - m_requestedStartTime >= m_animation->delay()) updateStateMachine(AnimationStateInputStartTimerFired, 0); return; } double elapsedDuration = beginAnimationUpdateTime() - m_startTime; // FIXME: we need to ensure that elapsedDuration is never < 0. If it is, this suggests that // we had a recalcStyle() outside of beginAnimationUpdate()/endAnimationUpdate(). // Also check in getTimeToNextEvent(). elapsedDuration = max(elapsedDuration, 0.0); // Check for end timeout if (m_totalDuration >= 0 && elapsedDuration >= m_totalDuration) { // We may still be in AnimationStateLooping if we've managed to skip a // whole iteration, in which case we should jump to the end state. LOG(Animations, "%p AnimationState %s -> Ending", this, nameForState(m_animState)); m_animState = AnimationStateEnding; // Fire an end event updateStateMachine(AnimationStateInputEndTimerFired, m_totalDuration); } else { // Check for iteration timeout if (m_nextIterationDuration < 0) { // Hasn't been set yet, set it double durationLeft = m_animation->duration() - fmod(elapsedDuration, m_animation->duration()); m_nextIterationDuration = elapsedDuration + durationLeft; } if (elapsedDuration >= m_nextIterationDuration) { // Set to the next iteration double previous = m_nextIterationDuration; double durationLeft = m_animation->duration() - fmod(elapsedDuration, m_animation->duration()); m_nextIterationDuration = elapsedDuration + durationLeft; // Send the event updateStateMachine(AnimationStateInputLoopTimerFired, previous); } } }
void AnimationBase::freezeAtTime(double t) { if (!m_compAnim) return; if (!m_startTime) { // If we haven't started yet, make it as if we started. LOG(Animations, "%p AnimationState %s -> StartWaitResponse", this, nameForState(m_animState)); m_animState = AnimationStateStartWaitResponse; onAnimationStartResponse(monotonicallyIncreasingTime()); } ASSERT(m_startTime); // if m_startTime is zero, we haven't started yet, so we'll get a bad pause time. if (t <= m_animation->delay()) m_pauseTime = m_startTime; else m_pauseTime = m_startTime + t - m_animation->delay(); if (m_object && m_object->isComposited()) toRenderBoxModelObject(m_object)->suspendAnimations(m_pauseTime); }
void AnimationBase::updateStateMachine(AnimStateInput input, double param) { if (!m_compAnim) return; // If we get AnimationStateInputRestartAnimation then we force a new animation, regardless of state. if (input == AnimationStateInputMakeNew) { if (m_animState == AnimationStateStartWaitStyleAvailable) m_compAnim->animationController()->removeFromAnimationsWaitingForStyle(this); LOG(Animations, "%p AnimationState %s -> New", this, nameForState(m_animState)); m_animState = AnimationStateNew; m_startTime = 0; m_pauseTime = -1; m_requestedStartTime = 0; m_nextIterationDuration = -1; endAnimation(); return; } if (input == AnimationStateInputRestartAnimation) { if (m_animState == AnimationStateStartWaitStyleAvailable) m_compAnim->animationController()->removeFromAnimationsWaitingForStyle(this); LOG(Animations, "%p AnimationState %s -> New", this, nameForState(m_animState)); m_animState = AnimationStateNew; m_startTime = 0; m_pauseTime = -1; m_requestedStartTime = 0; m_nextIterationDuration = -1; endAnimation(); if (!paused()) updateStateMachine(AnimationStateInputStartAnimation, -1); return; } if (input == AnimationStateInputEndAnimation) { if (m_animState == AnimationStateStartWaitStyleAvailable) m_compAnim->animationController()->removeFromAnimationsWaitingForStyle(this); LOG(Animations, "%p AnimationState %s -> Done", this, nameForState(m_animState)); m_animState = AnimationStateDone; endAnimation(); return; } if (input == AnimationStateInputPauseOverride) { if (m_animState == AnimationStateStartWaitResponse) { // If we are in AnimationStateStartWaitResponse, the animation will get canceled before // we get a response, so move to the next state. endAnimation(); updateStateMachine(AnimationStateInputStartTimeSet, beginAnimationUpdateTime()); } return; } if (input == AnimationStateInputResumeOverride) { if (m_animState == AnimationStateLooping || m_animState == AnimationStateEnding) { // Start the animation startAnimation(beginAnimationUpdateTime() - m_startTime); } return; } // Execute state machine switch (m_animState) { case AnimationStateNew: ASSERT(input == AnimationStateInputStartAnimation || input == AnimationStateInputPlayStateRunning || input == AnimationStateInputPlayStatePaused); if (input == AnimationStateInputStartAnimation || input == AnimationStateInputPlayStateRunning) { m_requestedStartTime = beginAnimationUpdateTime(); LOG(Animations, "%p AnimationState %s -> StartWaitTimer", this, nameForState(m_animState)); m_animState = AnimationStateStartWaitTimer; } else { // We are pausing before we even started. LOG(Animations, "%p AnimationState %s -> AnimationStatePausedNew", this, nameForState(m_animState)); m_animState = AnimationStatePausedNew; } break; case AnimationStateStartWaitTimer: ASSERT(input == AnimationStateInputStartTimerFired || input == AnimationStateInputPlayStatePaused); if (input == AnimationStateInputStartTimerFired) { ASSERT(param >= 0); // Start timer has fired, tell the animation to start and wait for it to respond with start time LOG(Animations, "%p AnimationState %s -> StartWaitStyleAvailable", this, nameForState(m_animState)); m_animState = AnimationStateStartWaitStyleAvailable; m_compAnim->animationController()->addToAnimationsWaitingForStyle(this); // Trigger a render so we can start the animation if (m_object && m_object->element()) m_compAnim->animationController()->addElementChangeToDispatch(*m_object->element()); } else { ASSERT(!paused()); // We're waiting for the start timer to fire and we got a pause. Cancel the timer, pause and wait m_pauseTime = beginAnimationUpdateTime(); LOG(Animations, "%p AnimationState %s -> PausedWaitTimer", this, nameForState(m_animState)); m_animState = AnimationStatePausedWaitTimer; } break; case AnimationStateStartWaitStyleAvailable: ASSERT(input == AnimationStateInputStyleAvailable || input == AnimationStateInputPlayStatePaused); if (input == AnimationStateInputStyleAvailable) { // Start timer has fired, tell the animation to start and wait for it to respond with start time LOG(Animations, "%p AnimationState %s -> StartWaitResponse", this, nameForState(m_animState)); m_animState = AnimationStateStartWaitResponse; overrideAnimations(); // Start the animation if (overridden()) { // We won't try to start accelerated animations if we are overridden and // just move on to the next state. LOG(Animations, "%p AnimationState %s -> StartWaitResponse", this, nameForState(m_animState)); m_animState = AnimationStateStartWaitResponse; m_isAccelerated = false; updateStateMachine(AnimationStateInputStartTimeSet, beginAnimationUpdateTime()); } else { double timeOffset = 0; // If the value for 'animation-delay' is negative then the animation appears to have started in the past. if (m_animation->delay() < 0) timeOffset = -m_animation->delay(); bool started = startAnimation(timeOffset); m_compAnim->animationController()->addToAnimationsWaitingForStartTimeResponse(this, started); m_isAccelerated = started; } } else { // We're waiting for the style to be available and we got a pause. Pause and wait m_pauseTime = beginAnimationUpdateTime(); LOG(Animations, "%p AnimationState %s -> PausedWaitStyleAvailable", this, nameForState(m_animState)); m_animState = AnimationStatePausedWaitStyleAvailable; } break; case AnimationStateStartWaitResponse: ASSERT(input == AnimationStateInputStartTimeSet || input == AnimationStateInputPlayStatePaused); if (input == AnimationStateInputStartTimeSet) { ASSERT(param >= 0); // We have a start time, set it, unless the startTime is already set if (m_startTime <= 0) { m_startTime = param; // If the value for 'animation-delay' is negative then the animation appears to have started in the past. if (m_animation->delay() < 0) m_startTime += m_animation->delay(); } // Now that we know the start time, fire the start event. onAnimationStart(0); // The elapsedTime is 0. // Decide whether to go into looping or ending state goIntoEndingOrLoopingState(); // Dispatch updateStyleIfNeeded so we can start the animation if (m_object && m_object->element()) m_compAnim->animationController()->addElementChangeToDispatch(*m_object->element()); } else { // We are pausing while waiting for a start response. Cancel the animation and wait. When // we unpause, we will act as though the start timer just fired m_pauseTime = beginAnimationUpdateTime(); pauseAnimation(beginAnimationUpdateTime() - m_startTime); LOG(Animations, "%p AnimationState %s -> PausedWaitResponse", this, nameForState(m_animState)); m_animState = AnimationStatePausedWaitResponse; } break; case AnimationStateLooping: ASSERT(input == AnimationStateInputLoopTimerFired || input == AnimationStateInputPlayStatePaused); if (input == AnimationStateInputLoopTimerFired) { ASSERT(param >= 0); // Loop timer fired, loop again or end. onAnimationIteration(param); // Decide whether to go into looping or ending state goIntoEndingOrLoopingState(); } else { // We are pausing while running. Cancel the animation and wait m_pauseTime = beginAnimationUpdateTime(); pauseAnimation(beginAnimationUpdateTime() - m_startTime); LOG(Animations, "%p AnimationState %s -> PausedRun", this, nameForState(m_animState)); m_animState = AnimationStatePausedRun; } break; case AnimationStateEnding: #if !LOG_DISABLED if (input != AnimationStateInputEndTimerFired && input != AnimationStateInputPlayStatePaused) LOG_ERROR("State is AnimationStateEnding, but input is not AnimationStateInputEndTimerFired or AnimationStateInputPlayStatePaused. It is %d.", input); #endif if (input == AnimationStateInputEndTimerFired) { ASSERT(param >= 0); // End timer fired, finish up onAnimationEnd(param); LOG(Animations, "%p AnimationState %s -> Done", this, nameForState(m_animState)); m_animState = AnimationStateDone; if (m_object) { if (m_animation->fillsForwards()) { LOG(Animations, "%p AnimationState %s -> FillingForwards", this, nameForState(m_animState)); m_animState = AnimationStateFillingForwards; } else resumeOverriddenAnimations(); // Fire off another style change so we can set the final value if (m_object->element()) m_compAnim->animationController()->addElementChangeToDispatch(*m_object->element()); } } else { // We are pausing while running. Cancel the animation and wait m_pauseTime = beginAnimationUpdateTime(); pauseAnimation(beginAnimationUpdateTime() - m_startTime); LOG(Animations, "%p AnimationState %s -> PausedRun", this, nameForState(m_animState)); m_animState = AnimationStatePausedRun; } // |this| may be deleted here break; case AnimationStatePausedWaitTimer: ASSERT(input == AnimationStateInputPlayStateRunning); ASSERT(paused()); // Update the times m_startTime += beginAnimationUpdateTime() - m_pauseTime; m_pauseTime = -1; // we were waiting for the start timer to fire, go back and wait again LOG(Animations, "%p AnimationState %s -> New", this, nameForState(m_animState)); m_animState = AnimationStateNew; updateStateMachine(AnimationStateInputStartAnimation, 0); break; case AnimationStatePausedNew: case AnimationStatePausedWaitResponse: case AnimationStatePausedWaitStyleAvailable: case AnimationStatePausedRun: // We treat these two cases the same. The only difference is that, when we are in // AnimationStatePausedWaitResponse, we don't yet have a valid startTime, so we send 0 to startAnimation. // When the AnimationStateInputStartTimeSet comes in and we were in AnimationStatePausedRun, we will notice // that we have already set the startTime and will ignore it. ASSERT(input == AnimationStateInputPlayStateRunning || input == AnimationStateInputStartTimeSet || input == AnimationStateInputStyleAvailable || input == AnimationStateInputStartAnimation); ASSERT(paused()); if (input == AnimationStateInputPlayStateRunning) { if (m_animState == AnimationStatePausedNew) { // We were paused before we even started, and now we're supposed // to start, so jump back to the New state and reset. LOG(Animations, "%p AnimationState %s -> AnimationStateNew", this, nameForState(m_animState)); m_animState = AnimationStateNew; updateStateMachine(input, param); break; } // Update the times if (m_animState == AnimationStatePausedRun) m_startTime += beginAnimationUpdateTime() - m_pauseTime; else m_startTime = 0; m_pauseTime = -1; if (m_animState == AnimationStatePausedWaitStyleAvailable) { LOG(Animations, "%p AnimationState %s -> StartWaitStyleAvailable", this, nameForState(m_animState)); m_animState = AnimationStateStartWaitStyleAvailable; } else { // We were either running or waiting for a begin time response from the animation. // Either way we need to restart the animation (possibly with an offset if we // had already been running) and wait for it to start. LOG(Animations, "%p AnimationState %s -> StartWaitResponse", this, nameForState(m_animState)); m_animState = AnimationStateStartWaitResponse; // Start the animation if (overridden()) { // We won't try to start accelerated animations if we are overridden and // just move on to the next state. updateStateMachine(AnimationStateInputStartTimeSet, beginAnimationUpdateTime()); m_isAccelerated = true; } else { bool started = startAnimation(beginAnimationUpdateTime() - m_startTime); m_compAnim->animationController()->addToAnimationsWaitingForStartTimeResponse(this, started); m_isAccelerated = started; } } break; } if (input == AnimationStateInputStartTimeSet) { ASSERT(m_animState == AnimationStatePausedWaitResponse); // We are paused but we got the callback that notifies us that an accelerated animation started. // We ignore the start time and just move into the paused-run state. LOG(Animations, "%p AnimationState %s -> PausedRun", this, nameForState(m_animState)); m_animState = AnimationStatePausedRun; ASSERT(m_startTime == 0); m_startTime = param; m_pauseTime += m_startTime; break; } ASSERT(m_animState == AnimationStatePausedWaitStyleAvailable); // We are paused but we got the callback that notifies us that style has been updated. // We move to the AnimationStatePausedWaitResponse state LOG(Animations, "%p AnimationState %s -> PausedWaitResponse", this, nameForState(m_animState)); m_animState = AnimationStatePausedWaitResponse; overrideAnimations(); break; case AnimationStateFillingForwards: case AnimationStateDone: // We're done. Stay in this state until we are deleted break; } }
void AnimationBase::fireAnimationEventsIfNeeded() { if (!m_compositeAnimation) return; // If we are waiting for the delay time to expire and it has, go to the next state if (m_animationState != AnimationState::StartWaitTimer && m_animationState != AnimationState::Looping && m_animationState != AnimationState::Ending) return; // We have to make sure to keep a ref to the this pointer, because it could get destroyed // during an animation callback that might get called. Since the owner is a CompositeAnimation // and it ref counts this object, we will keep a ref to that instead. That way the AnimationBase // can still access the resources of its CompositeAnimation as needed. Ref<AnimationBase> protect(*this); Ref<CompositeAnimation> protectCompositeAnimation(*m_compositeAnimation); // Check for start timeout if (m_animationState == AnimationState::StartWaitTimer) { #if ENABLE(CSS_ANIMATIONS_LEVEL_2) if (m_animation->trigger() && m_animation->trigger()->isScrollAnimationTrigger()) { if (m_object) { float offset = m_compositeAnimation->animationController().scrollPosition(); ScrollAnimationTrigger& scrollTrigger = downcast<ScrollAnimationTrigger>(*m_animation->trigger().get()); if (offset > scrollTrigger.startValue().value()) updateStateMachine(AnimationStateInput::StartTimerFired, 0); } return; } #endif if (beginAnimationUpdateTime() - m_requestedStartTime >= m_animation->delay()) updateStateMachine(AnimationStateInput::StartTimerFired, 0); return; } double elapsedDuration = beginAnimationUpdateTime() - m_startTime; #if ENABLE(CSS_ANIMATIONS_LEVEL_2) // If we are a triggered animation that depends on scroll, our elapsed // time is determined by the scroll position. if (m_animation->trigger() && m_animation->trigger()->isScrollAnimationTrigger()) elapsedDuration = getElapsedTime(); #endif // FIXME: we need to ensure that elapsedDuration is never < 0. If it is, this suggests that // we had a recalcStyle() outside of beginAnimationUpdate()/endAnimationUpdate(). // Also check in getTimeToNextEvent(). elapsedDuration = std::max(elapsedDuration, 0.0); // Check for end timeout if (m_totalDuration >= 0 && elapsedDuration >= m_totalDuration) { // We may still be in AnimationState::Looping if we've managed to skip a // whole iteration, in which case we should jump to the end state. LOG(Animations, "%p AnimationState %s -> Ending", this, nameForState(m_animationState)); m_animationState = AnimationState::Ending; // Fire an end event updateStateMachine(AnimationStateInput::EndTimerFired, m_totalDuration); } else { // Check for iteration timeout if (m_nextIterationDuration < 0) { // Hasn't been set yet, set it double durationLeft = m_animation->duration() - fmod(elapsedDuration, m_animation->duration()); m_nextIterationDuration = elapsedDuration + durationLeft; } if (elapsedDuration >= m_nextIterationDuration) { // Set to the next iteration double previous = m_nextIterationDuration; double durationLeft = m_animation->duration() - fmod(elapsedDuration, m_animation->duration()); m_nextIterationDuration = elapsedDuration + durationLeft; // Send the event updateStateMachine(AnimationStateInput::LoopTimerFired, previous); } } }