summaryrefslogtreecommitdiff
path: root/Source/WebCore/page/animation/AnimationBase.cpp
diff options
context:
space:
mode:
authorLorry Tar Creator <lorry-tar-importer@lorry>2017-06-27 06:07:23 +0000
committerLorry Tar Creator <lorry-tar-importer@lorry>2017-06-27 06:07:23 +0000
commit1bf1084f2b10c3b47fd1a588d85d21ed0eb41d0c (patch)
tree46dcd36c86e7fbc6e5df36deb463b33e9967a6f7 /Source/WebCore/page/animation/AnimationBase.cpp
parent32761a6cee1d0dee366b885b7b9c777e67885688 (diff)
downloadWebKitGtk-tarball-master.tar.gz
Diffstat (limited to 'Source/WebCore/page/animation/AnimationBase.cpp')
-rw-r--r--Source/WebCore/page/animation/AnimationBase.cpp618
1 files changed, 388 insertions, 230 deletions
diff --git a/Source/WebCore/page/animation/AnimationBase.cpp b/Source/WebCore/page/animation/AnimationBase.cpp
index dd3315ebb..44bfe82a3 100644
--- a/Source/WebCore/page/animation/AnimationBase.cpp
+++ b/Source/WebCore/page/animation/AnimationBase.cpp
@@ -10,7 +10,7 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * 3. Neither the name of Apple Inc. ("Apple") nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
@@ -29,16 +29,18 @@
#include "config.h"
#include "AnimationBase.h"
-#include "AnimationControllerPrivate.h"
+#include "CSSAnimationControllerPrivate.h"
#include "CSSPrimitiveValue.h"
#include "CSSPropertyAnimation.h"
#include "CompositeAnimation.h"
#include "Document.h"
-#include "EventNames.h"
#include "FloatConversion.h"
+#include "GeometryUtilities.h"
#include "Logging.h"
#include "RenderBox.h"
#include "RenderStyle.h"
+#include "RenderView.h"
+#include "SpringSolver.h"
#include "UnitBezier.h"
#include <algorithm>
#include <wtf/CurrentTime.h>
@@ -68,21 +70,16 @@ static inline double solveStepsFunction(int numSteps, bool stepAtStart, double t
return floor(numSteps * t) / numSteps;
}
-AnimationBase::AnimationBase(const Animation& transition, RenderElement* renderer, CompositeAnimation* compAnim)
- : m_animState(AnimationStateNew)
- , m_isAccelerated(false)
- , m_transformFunctionListValid(false)
-#if ENABLE(CSS_FILTERS)
- , m_filterFunctionListsMatch(false)
-#endif
- , m_startTime(0)
- , m_pauseTime(-1)
- , m_requestedStartTime(0)
- , m_totalDuration(-1)
- , m_nextIterationDuration(-1)
- , m_object(renderer)
- , m_animation(const_cast<Animation*>(&transition))
- , m_compAnim(compAnim)
+static inline double solveSpringFunction(double mass, double stiffness, double damping, double initialVelocity, double t, double duration)
+{
+ SpringSolver solver(mass, stiffness, damping, initialVelocity);
+ return solver.solve(t * duration);
+}
+
+AnimationBase::AnimationBase(const Animation& animation, RenderElement* renderer, CompositeAnimation* compositeAnimation)
+ : m_object(renderer)
+ , m_compositeAnimation(compositeAnimation)
+ , m_animation(const_cast<Animation&>(animation))
{
// Compute the total duration
if (m_animation->iterationCount() > 0)
@@ -91,9 +88,11 @@ AnimationBase::AnimationBase(const Animation& transition, RenderElement* rendere
void AnimationBase::setNeedsStyleRecalc(Element* element)
{
- ASSERT(!element || !element->document().inPageCache());
- if (element)
- element->setNeedsStyleRecalc(SyntheticStyleChange);
+ if (!element || element->document().renderTreeBeingDestroyed())
+ return;
+
+ ASSERT(element->document().pageCacheState() == Document::NotInPageCache);
+ element->invalidateStyleAndLayerComposition();
}
double AnimationBase::duration() const
@@ -106,137 +105,164 @@ bool AnimationBase::playStatePlaying() const
return m_animation->playState() == AnimPlayStatePlaying;
}
-bool AnimationBase::animationsMatch(const Animation* anim) const
+bool AnimationBase::animationsMatch(const Animation& animation) const
{
- return m_animation->animationsMatch(anim);
+ return m_animation->animationsMatch(animation);
}
#if !LOG_DISABLED
-static const char* nameForState(AnimationBase::AnimState state)
+static const char* nameForState(AnimationBase::AnimationState state)
{
switch (state) {
- case AnimationBase::AnimationStateNew: return "New";
- case AnimationBase::AnimationStateStartWaitTimer: return "StartWaitTimer";
- case AnimationBase::AnimationStateStartWaitStyleAvailable: return "StartWaitStyleAvailable";
- case AnimationBase::AnimationStateStartWaitResponse: return "StartWaitResponse";
- case AnimationBase::AnimationStateLooping: return "Looping";
- case AnimationBase::AnimationStateEnding: return "Ending";
- case AnimationBase::AnimationStatePausedNew: return "PausedNew";
- case AnimationBase::AnimationStatePausedWaitTimer: return "PausedWaitTimer";
- case AnimationBase::AnimationStatePausedWaitStyleAvailable: return "PausedWaitStyleAvailable";
- case AnimationBase::AnimationStatePausedWaitResponse: return "PausedWaitResponse";
- case AnimationBase::AnimationStatePausedRun: return "PausedRun";
- case AnimationBase::AnimationStateDone: return "Done";
- case AnimationBase::AnimationStateFillingForwards: return "FillingForwards";
+ case AnimationBase::AnimationState::New: return "New";
+ case AnimationBase::AnimationState::StartWaitTimer: return "StartWaitTimer";
+ case AnimationBase::AnimationState::StartWaitStyleAvailable: return "StartWaitStyleAvailable";
+ case AnimationBase::AnimationState::StartWaitResponse: return "StartWaitResponse";
+ case AnimationBase::AnimationState::Looping: return "Looping";
+ case AnimationBase::AnimationState::Ending: return "Ending";
+ case AnimationBase::AnimationState::PausedNew: return "PausedNew";
+ case AnimationBase::AnimationState::PausedWaitTimer: return "PausedWaitTimer";
+ case AnimationBase::AnimationState::PausedWaitStyleAvailable: return "PausedWaitStyleAvailable";
+ case AnimationBase::AnimationState::PausedWaitResponse: return "PausedWaitResponse";
+ case AnimationBase::AnimationState::PausedRun: return "PausedRun";
+ case AnimationBase::AnimationState::Done: return "Done";
+ case AnimationBase::AnimationState::FillingForwards: return "FillingForwards";
+ }
+ return "";
+}
+
+static const char* nameForStateInput(AnimationBase::AnimationStateInput input)
+{
+ switch (input) {
+ case AnimationBase::AnimationStateInput::MakeNew: return "MakeNew";
+ case AnimationBase::AnimationStateInput::StartAnimation: return "StartAnimation";
+ case AnimationBase::AnimationStateInput::RestartAnimation: return "RestartAnimation";
+ case AnimationBase::AnimationStateInput::StartTimerFired: return "StartTimerFired";
+ case AnimationBase::AnimationStateInput::StyleAvailable: return "StyleAvailable";
+ case AnimationBase::AnimationStateInput::StartTimeSet: return "StartTimeSet";
+ case AnimationBase::AnimationStateInput::LoopTimerFired: return "LoopTimerFired";
+ case AnimationBase::AnimationStateInput::EndTimerFired: return "EndTimerFired";
+ case AnimationBase::AnimationStateInput::PauseOverride: return "PauseOverride";
+ case AnimationBase::AnimationStateInput::ResumeOverride: return "ResumeOverride";
+ case AnimationBase::AnimationStateInput::PlayStateRunning: return "PlayStateRunning";
+ case AnimationBase::AnimationStateInput::PlayStatePaused: return "PlayStatePaused";
+ case AnimationBase::AnimationStateInput::EndAnimation: return "EndAnimation";
}
return "";
}
#endif
-void AnimationBase::updateStateMachine(AnimStateInput input, double param)
+void AnimationBase::updateStateMachine(AnimationStateInput input, double param)
{
- if (!m_compAnim)
+ if (!m_compositeAnimation)
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;
+ // If we get AnimationStateInput::RestartAnimation then we force a new animation, regardless of state.
+ if (input == AnimationStateInput::MakeNew) {
+ if (m_animationState == AnimationState::StartWaitStyleAvailable)
+ m_compositeAnimation->animationController().removeFromAnimationsWaitingForStyle(this);
+ LOG(Animations, "%p AnimationState %s -> New", this, nameForState(m_animationState));
+ m_animationState = AnimationState::New;
+ m_startTime = std::nullopt;
+ m_pauseTime = std::nullopt;
m_requestedStartTime = 0;
- m_nextIterationDuration = -1;
+ m_nextIterationDuration = std::nullopt;
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;
+ if (input == AnimationStateInput::RestartAnimation) {
+ if (m_animationState == AnimationState::StartWaitStyleAvailable)
+ m_compositeAnimation->animationController().removeFromAnimationsWaitingForStyle(this);
+ LOG(Animations, "%p AnimationState %s -> New", this, nameForState(m_animationState));
+ m_animationState = AnimationState::New;
+ m_startTime = std::nullopt;
+ m_pauseTime = std::nullopt;
m_requestedStartTime = 0;
- m_nextIterationDuration = -1;
+ m_nextIterationDuration = std::nullopt;
endAnimation();
if (!paused())
- updateStateMachine(AnimationStateInputStartAnimation, -1);
+ updateStateMachine(AnimationStateInput::StartAnimation, -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;
+ if (input == AnimationStateInput::EndAnimation) {
+ if (m_animationState == AnimationState::StartWaitStyleAvailable)
+ m_compositeAnimation->animationController().removeFromAnimationsWaitingForStyle(this);
+ LOG(Animations, "%p AnimationState %s -> Done", this, nameForState(m_animationState));
+ m_animationState = AnimationState::Done;
endAnimation();
return;
}
- if (input == AnimationStateInputPauseOverride) {
- if (m_animState == AnimationStateStartWaitResponse) {
- // If we are in AnimationStateStartWaitResponse, the animation will get canceled before
+ if (input == AnimationStateInput::PauseOverride) {
+ if (m_animationState == AnimationState::StartWaitResponse) {
+ // If we are in AnimationState::StartWaitResponse, the animation will get canceled before
// we get a response, so move to the next state.
endAnimation();
- updateStateMachine(AnimationStateInputStartTimeSet, beginAnimationUpdateTime());
+ updateStateMachine(AnimationStateInput::StartTimeSet, beginAnimationUpdateTime());
}
return;
}
- if (input == AnimationStateInputResumeOverride) {
- if (m_animState == AnimationStateLooping || m_animState == AnimationStateEnding) {
+ if (input == AnimationStateInput::ResumeOverride) {
+ if (m_animationState == AnimationState::Looping || m_animationState == AnimationState::Ending) {
// Start the animation
- startAnimation(beginAnimationUpdateTime() - m_startTime);
+ startAnimation(beginAnimationUpdateTime() - m_startTime.value_or(0));
}
return;
}
// Execute state machine
- switch (m_animState) {
- case AnimationStateNew:
- ASSERT(input == AnimationStateInputStartAnimation || input == AnimationStateInputPlayStateRunning || input == AnimationStateInputPlayStatePaused);
- if (input == AnimationStateInputStartAnimation || input == AnimationStateInputPlayStateRunning) {
+ switch (m_animationState) {
+ case AnimationState::New:
+ ASSERT(input == AnimationStateInput::StartAnimation || input == AnimationStateInput::PlayStateRunning || input == AnimationStateInput::PlayStatePaused);
+
+ if (input == AnimationStateInput::StartAnimation || input == AnimationStateInput::PlayStateRunning) {
m_requestedStartTime = beginAnimationUpdateTime();
- LOG(Animations, "%p AnimationState %s -> StartWaitTimer", this, nameForState(m_animState));
- m_animState = AnimationStateStartWaitTimer;
+ LOG(Animations, "%p AnimationState %s -> StartWaitTimer", this, nameForState(m_animationState));
+ m_animationState = AnimationState::StartWaitTimer;
} else {
// We are pausing before we even started.
- LOG(Animations, "%p AnimationState %s -> AnimationStatePausedNew", this, nameForState(m_animState));
- m_animState = AnimationStatePausedNew;
+ LOG(Animations, "%p AnimationState %s -> AnimationState::PausedNew", this, nameForState(m_animationState));
+ m_animationState = AnimationState::PausedNew;
+ m_pauseTime = std::nullopt;
}
+
+#if ENABLE(CSS_ANIMATIONS_LEVEL_2)
+ if (m_animation->trigger() && m_animation->trigger()->isScrollAnimationTrigger())
+ m_compositeAnimation->animationController().addToAnimationsDependentOnScroll(this);
+#endif
break;
- case AnimationStateStartWaitTimer:
- ASSERT(input == AnimationStateInputStartTimerFired || input == AnimationStateInputPlayStatePaused);
+ case AnimationState::StartWaitTimer:
+ ASSERT(input == AnimationStateInput::StartTimerFired || input == AnimationStateInput::PlayStatePaused);
- if (input == AnimationStateInputStartTimerFired) {
+ if (input == AnimationStateInput::StartTimerFired) {
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);
+ LOG(Animations, "%p AnimationState %s -> StartWaitStyleAvailable (time is %f)", this, nameForState(m_animationState), param);
+ m_animationState = AnimationState::StartWaitStyleAvailable;
+ m_compositeAnimation->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());
+ m_compositeAnimation->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;
+ LOG(Animations, "%p AnimationState %s -> PausedWaitTimer", this, nameForState(m_animationState));
+ m_animationState = AnimationState::PausedWaitTimer;
}
break;
- case AnimationStateStartWaitStyleAvailable:
- ASSERT(input == AnimationStateInputStyleAvailable || input == AnimationStateInputPlayStatePaused);
+ case AnimationState::StartWaitStyleAvailable:
+ ASSERT(input == AnimationStateInput::StyleAvailable || input == AnimationStateInput::PlayStatePaused);
- if (input == AnimationStateInputStyleAvailable) {
+ if (input == AnimationStateInput::StyleAvailable) {
// 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;
+ LOG(Animations, "%p AnimationState %s -> StartWaitResponse (time is %f)", this, nameForState(m_animationState), param);
+ m_animationState = AnimationState::StartWaitResponse;
overrideAnimations();
@@ -244,10 +270,10 @@ void AnimationBase::updateStateMachine(AnimStateInput input, double param)
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;
+ LOG(Animations, "%p AnimationState %s -> StartWaitResponse", this, nameForState(m_animationState));
+ m_animationState = AnimationState::StartWaitResponse;
m_isAccelerated = false;
- updateStateMachine(AnimationStateInputStartTimeSet, beginAnimationUpdateTime());
+ updateStateMachine(AnimationStateInput::StartTimeSet, beginAnimationUpdateTime());
} else {
double timeOffset = 0;
// If the value for 'animation-delay' is negative then the animation appears to have started in the past.
@@ -255,27 +281,29 @@ void AnimationBase::updateStateMachine(AnimStateInput input, double param)
timeOffset = -m_animation->delay();
bool started = startAnimation(timeOffset);
- m_compAnim->animationController()->addToAnimationsWaitingForStartTimeResponse(this, started);
+ m_compositeAnimation->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;
+ LOG(Animations, "%p AnimationState %s -> PausedWaitStyleAvailable", this, nameForState(m_animationState));
+ m_animationState = AnimationState::PausedWaitStyleAvailable;
}
break;
- case AnimationStateStartWaitResponse:
- ASSERT(input == AnimationStateInputStartTimeSet || input == AnimationStateInputPlayStatePaused);
+ case AnimationState::StartWaitResponse:
+ ASSERT(input == AnimationStateInput::StartTimeSet || input == AnimationStateInput::PlayStatePaused);
+
+ if (input == AnimationStateInput::StartTimeSet) {
+ ASSERT(param > -0.001); // Sometimes Core Animation gives us a beginTime slightly into the future.
+ LOG(Animations, "%p AnimationState %s -> StartTimeSet (time is %f)", this, nameForState(m_animationState), param);
- if (input == AnimationStateInputStartTimeSet) {
- ASSERT(param >= 0);
// We have a start time, set it, unless the startTime is already set
- if (m_startTime <= 0) {
+ if (!m_startTime) {
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();
+ m_startTime = m_startTime.value() + m_animation->delay();
}
// Now that we know the start time, fire the start event.
@@ -286,21 +314,23 @@ void AnimationBase::updateStateMachine(AnimStateInput input, double param)
// Dispatch updateStyleIfNeeded so we can start the animation
if (m_object && m_object->element())
- m_compAnim->animationController()->addElementChangeToDispatch(*m_object->element());
+ m_compositeAnimation->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;
+ pauseAnimation(beginAnimationUpdateTime() - m_startTime.value_or(0));
+ LOG(Animations, "%p AnimationState %s -> PausedWaitResponse", this, nameForState(m_animationState));
+ m_animationState = AnimationState::PausedWaitResponse;
}
break;
- case AnimationStateLooping:
- ASSERT(input == AnimationStateInputLoopTimerFired || input == AnimationStateInputPlayStatePaused);
+ case AnimationState::Looping:
+ ASSERT(input == AnimationStateInput::LoopTimerFired || input == AnimationStateInput::PlayStatePaused);
- if (input == AnimationStateInputLoopTimerFired) {
+ if (input == AnimationStateInput::LoopTimerFired) {
ASSERT(param >= 0);
+ LOG(Animations, "%p AnimationState %s -> LoopTimerFired (time is %f)", this, nameForState(m_animationState), param);
+
// Loop timer fired, loop again or end.
onAnimationIteration(param);
@@ -309,178 +339,198 @@ void AnimationBase::updateStateMachine(AnimStateInput input, double param)
} 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;
+ pauseAnimation(beginAnimationUpdateTime() - m_startTime.value_or(0));
+ LOG(Animations, "%p AnimationState %s -> PausedRun", this, nameForState(m_animationState));
+ m_animationState = AnimationState::PausedRun;
}
break;
- case AnimationStateEnding:
+ case AnimationState::Ending:
#if !LOG_DISABLED
- if (input != AnimationStateInputEndTimerFired && input != AnimationStateInputPlayStatePaused)
- LOG_ERROR("State is AnimationStateEnding, but input is not AnimationStateInputEndTimerFired or AnimationStateInputPlayStatePaused. It is %d.", input);
+ if (input != AnimationStateInput::EndTimerFired && input != AnimationStateInput::PlayStatePaused)
+ LOG_ERROR("State is AnimationState::Ending, but input is not AnimationStateInput::EndTimerFired or AnimationStateInput::PlayStatePaused. It is %s.", nameForStateInput(input));
#endif
- if (input == AnimationStateInputEndTimerFired) {
-
+ if (input == AnimationStateInput::EndTimerFired) {
ASSERT(param >= 0);
// End timer fired, finish up
onAnimationEnd(param);
- LOG(Animations, "%p AnimationState %s -> Done", this, nameForState(m_animState));
- m_animState = AnimationStateDone;
+ LOG(Animations, "%p AnimationState %s -> Done (time is %f)", this, nameForState(m_animationState), param);
+ m_animationState = AnimationState::Done;
if (m_object) {
if (m_animation->fillsForwards()) {
- LOG(Animations, "%p AnimationState %s -> FillingForwards", this, nameForState(m_animState));
- m_animState = AnimationStateFillingForwards;
+ LOG(Animations, "%p AnimationState %s -> FillingForwards", this, nameForState(m_animationState));
+ m_animationState = AnimationState::FillingForwards;
} 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());
+ m_compositeAnimation->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;
+ pauseAnimation(beginAnimationUpdateTime() - m_startTime.value_or(0));
+ LOG(Animations, "%p AnimationState %s -> PausedRun", this, nameForState(m_animationState));
+ m_animationState = AnimationState::PausedRun;
}
// |this| may be deleted here
break;
- case AnimationStatePausedWaitTimer:
- ASSERT(input == AnimationStateInputPlayStateRunning);
+ case AnimationState::PausedWaitTimer:
+ ASSERT(input == AnimationStateInput::PlayStateRunning);
ASSERT(paused());
// Update the times
- m_startTime += beginAnimationUpdateTime() - m_pauseTime;
- m_pauseTime = -1;
+ m_startTime = m_startTime.value() + beginAnimationUpdateTime() - m_pauseTime.value_or(0);
+ m_pauseTime = std::nullopt;
// 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);
+ LOG(Animations, "%p AnimationState %s -> New", this, nameForState(m_animationState));
+ m_animationState = AnimationState::New;
+ updateStateMachine(AnimationStateInput::StartAnimation, 0);
break;
- case AnimationStatePausedNew:
- case AnimationStatePausedWaitResponse:
- case AnimationStatePausedWaitStyleAvailable:
- case AnimationStatePausedRun:
+ case AnimationState::PausedNew:
+ case AnimationState::PausedWaitResponse:
+ case AnimationState::PausedWaitStyleAvailable:
+ case AnimationState::PausedRun:
// 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
+ // AnimationState::PausedWaitResponse, we don't yet have a valid startTime, so we send 0 to startAnimation.
+ // When the AnimationStateInput::StartTimeSet comes in and we were in AnimationState::PausedRun, we will notice
// that we have already set the startTime and will ignore it.
- ASSERT(input == AnimationStateInputPlayStateRunning || input == AnimationStateInputStartTimeSet || input == AnimationStateInputStyleAvailable || input == AnimationStateInputStartAnimation);
+ ASSERT(input == AnimationStateInput::PlayStatePaused || input == AnimationStateInput::PlayStateRunning || input == AnimationStateInput::StartTimeSet || input == AnimationStateInput::StyleAvailable || input == AnimationStateInput::StartAnimation);
ASSERT(paused());
- if (input == AnimationStateInputPlayStateRunning) {
- if (m_animState == AnimationStatePausedNew) {
+ if (input == AnimationStateInput::PlayStateRunning) {
+ if (m_animationState == AnimationState::PausedNew) {
// 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;
+ LOG(Animations, "%p AnimationState %s -> AnimationState::New", this, nameForState(m_animationState));
+ m_animationState = AnimationState::New;
+ m_pauseTime = std::nullopt;
updateStateMachine(input, param);
break;
}
// Update the times
- if (m_animState == AnimationStatePausedRun)
- m_startTime += beginAnimationUpdateTime() - m_pauseTime;
+ if (m_animationState == AnimationState::PausedRun)
+ m_startTime = m_startTime.value() + beginAnimationUpdateTime() - m_pauseTime.value_or(0);
else
m_startTime = 0;
- m_pauseTime = -1;
- if (m_animState == AnimationStatePausedWaitStyleAvailable) {
- LOG(Animations, "%p AnimationState %s -> StartWaitStyleAvailable", this, nameForState(m_animState));
- m_animState = AnimationStateStartWaitStyleAvailable;
+ m_pauseTime = std::nullopt;
+
+ if (m_animationState == AnimationState::PausedWaitStyleAvailable) {
+ LOG(Animations, "%p AnimationState %s -> StartWaitStyleAvailable", this, nameForState(m_animationState));
+ m_animationState = AnimationState::StartWaitStyleAvailable;
} 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;
+ LOG(Animations, "%p AnimationState %s -> StartWaitResponse", this, nameForState(m_animationState));
+ m_animationState = AnimationState::StartWaitResponse;
// 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());
+ updateStateMachine(AnimationStateInput::StartTimeSet, beginAnimationUpdateTime());
m_isAccelerated = true;
} else {
- bool started = startAnimation(beginAnimationUpdateTime() - m_startTime);
- m_compAnim->animationController()->addToAnimationsWaitingForStartTimeResponse(this, started);
+ bool started = startAnimation(beginAnimationUpdateTime() - m_startTime.value_or(0));
+ m_compositeAnimation->animationController().addToAnimationsWaitingForStartTimeResponse(this, started);
m_isAccelerated = started;
}
}
break;
}
- if (input == AnimationStateInputStartTimeSet) {
- ASSERT(m_animState == AnimationStatePausedWaitResponse);
+ if (input == AnimationStateInput::StartTimeSet) {
+ ASSERT(m_animationState == AnimationState::PausedWaitResponse);
// 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);
+ LOG(Animations, "%p AnimationState %s -> PausedRun (time is %f)", this, nameForState(m_animationState), param);
+ m_animationState = AnimationState::PausedRun;
+ ASSERT(!m_startTime);
m_startTime = param;
- m_pauseTime += m_startTime;
+ m_pauseTime = m_pauseTime.value_or(0) + param;
break;
}
- ASSERT(m_animState == AnimationStatePausedWaitStyleAvailable);
+ ASSERT(m_animationState == AnimationState::PausedNew || m_animationState == AnimationState::PausedWaitStyleAvailable);
// 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;
+ // We move to the AnimationState::PausedWaitResponse state
+ LOG(Animations, "%p AnimationState %s -> PausedWaitResponse", this, nameForState(m_animationState));
+ m_animationState = AnimationState::PausedWaitResponse;
overrideAnimations();
break;
- case AnimationStateFillingForwards:
- case AnimationStateDone:
+ case AnimationState::FillingForwards:
+ case AnimationState::Done:
// We're done. Stay in this state until we are deleted
break;
}
}
-
+
void AnimationBase::fireAnimationEventsIfNeeded()
{
- if (!m_compAnim)
+ if (!m_compositeAnimation)
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)
+ 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_compAnim);
+ Ref<AnimationBase> protectedThis(*this);
+ Ref<CompositeAnimation> protectCompositeAnimation(*m_compositeAnimation);
// Check for start timeout
- if (m_animState == AnimationStateStartWaitTimer) {
+ 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();
+ auto& scrollTrigger = downcast<ScrollAnimationTrigger>(*m_animation->trigger());
+ if (offset > scrollTrigger.startValue().value())
+ updateStateMachine(AnimationStateInput::StartTimerFired, 0);
+ }
+
+ return;
+ }
+#endif
if (beginAnimationUpdateTime() - m_requestedStartTime >= m_animation->delay())
- updateStateMachine(AnimationStateInputStartTimerFired, 0);
+ updateStateMachine(AnimationStateInput::StartTimerFired, 0);
return;
}
-
- double elapsedDuration = beginAnimationUpdateTime() - m_startTime;
+
+ double elapsedDuration = beginAnimationUpdateTime() - m_startTime.value_or(0);
+#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 AnimationStateLooping if we've managed to skip a
+ if (m_totalDuration && elapsedDuration >= m_totalDuration.value()) {
+ // 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_animState));
- m_animState = AnimationStateEnding;
+ LOG(Animations, "%p AnimationState %s -> Ending", this, nameForState(m_animationState));
+ m_animationState = AnimationState::Ending;
// Fire an end event
- updateStateMachine(AnimationStateInputEndTimerFired, m_totalDuration);
+ updateStateMachine(AnimationStateInput::EndTimerFired, m_totalDuration.value());
} else {
// Check for iteration timeout
- if (m_nextIterationDuration < 0) {
+ if (!m_nextIterationDuration) {
// Hasn't been set yet, set it
double durationLeft = m_animation->duration() - fmod(elapsedDuration, m_animation->duration());
m_nextIterationDuration = elapsedDuration + durationLeft;
@@ -488,40 +538,51 @@ void AnimationBase::fireAnimationEventsIfNeeded()
if (elapsedDuration >= m_nextIterationDuration) {
// Set to the next iteration
- double previous = m_nextIterationDuration;
+ double previous = m_nextIterationDuration.value();
double durationLeft = m_animation->duration() - fmod(elapsedDuration, m_animation->duration());
m_nextIterationDuration = elapsedDuration + durationLeft;
// Send the event
- updateStateMachine(AnimationStateInputLoopTimerFired, previous);
+ updateStateMachine(AnimationStateInput::LoopTimerFired, previous);
}
}
}
void AnimationBase::updatePlayState(EAnimPlayState playState)
{
- if (!m_compAnim)
+ if (!m_compositeAnimation)
return;
// When we get here, we can have one of 4 desired states: running, paused, suspended, paused & suspended.
// The state machine can be in one of two states: running, paused.
// Set the state machine to the desired state.
- bool pause = playState == AnimPlayStatePaused || m_compAnim->isSuspended();
+ bool pause = playState == AnimPlayStatePaused || m_compositeAnimation->isSuspended();
if (pause == paused() && !isNew())
return;
- updateStateMachine(pause ? AnimationStateInputPlayStatePaused : AnimationStateInputPlayStateRunning, -1);
+ updateStateMachine(pause ? AnimationStateInput::PlayStatePaused : AnimationStateInput::PlayStateRunning, -1);
}
double AnimationBase::timeToNextService()
{
// Returns the time at which next service is required. -1 means no service is required. 0 means
// service is required now, and > 0 means service is required that many seconds in the future.
- if (paused() || isNew() || m_animState == AnimationStateFillingForwards)
+ if (paused() || isNew() || postActive() || fillingForwards())
return -1;
- if (m_animState == AnimationStateStartWaitTimer) {
+ if (m_animationState == AnimationState::StartWaitTimer) {
+#if ENABLE(CSS_ANIMATIONS_LEVEL_2)
+ if (m_animation->trigger()->isScrollAnimationTrigger()) {
+ if (m_object) {
+ float currentScrollPosition = m_object->view().frameView().scrollPositionForFixedPosition().y().toFloat();
+ auto& scrollTrigger = downcast<ScrollAnimationTrigger>(*m_animation->trigger());
+ if (currentScrollPosition >= scrollTrigger.startValue().value() && (!scrollTrigger.hasEndValue() || currentScrollPosition <= scrollTrigger.endValue().value()))
+ return 0;
+ }
+ return -1;
+ }
+#endif
double timeFromNow = m_animation->delay() - (beginAnimationUpdateTime() - m_requestedStartTime);
return std::max(timeFromNow, 0.0);
}
@@ -566,39 +627,45 @@ double AnimationBase::fractionalTime(double scale, double elapsedTime, double of
return fractionalTime;
}
-double AnimationBase::progress(double scale, double offset, const TimingFunction* tf) const
+double AnimationBase::progress(double scale, double offset, const TimingFunction* timingFunction) const
{
if (preActive())
return 0;
+ if (postActive())
+ return 1;
+
double elapsedTime = getElapsedTime();
- double dur = m_animation->duration();
+ double duration = m_animation->duration();
if (m_animation->iterationCount() > 0)
- dur *= m_animation->iterationCount();
+ duration *= m_animation->iterationCount();
- if (postActive() || !m_animation->duration())
- return 1.0;
+ if (fillingForwards())
+ elapsedTime = duration;
- if (m_animation->iterationCount() > 0 && elapsedTime >= dur) {
- const int integralIterationCount = static_cast<int>(m_animation->iterationCount());
- const bool iterationCountHasFractional = m_animation->iterationCount() - integralIterationCount;
- return (integralIterationCount % 2 || iterationCountHasFractional) ? 1.0 : 0.0;
- }
+ double fractionalTime = this->fractionalTime(scale, elapsedTime, offset);
- const double fractionalTime = this->fractionalTime(scale, elapsedTime, offset);
+ if (m_animation->iterationCount() > 0 && elapsedTime >= duration) {
+ if (WTF::isIntegral(fractionalTime))
+ return fractionalTime;
+ }
- if (!tf)
- tf = m_animation->timingFunction().get();
+ if (!timingFunction)
+ timingFunction = m_animation->timingFunction();
- switch (tf->type()) {
+ switch (timingFunction->type()) {
case TimingFunction::CubicBezierFunction: {
- const CubicBezierTimingFunction* function = static_cast<const CubicBezierTimingFunction*>(tf);
- return solveCubicBezierFunction(function->x1(), function->y1(), function->x2(), function->y2(), fractionalTime, m_animation->duration());
+ auto& function = *static_cast<const CubicBezierTimingFunction*>(timingFunction);
+ return solveCubicBezierFunction(function.x1(), function.y1(), function.x2(), function.y2(), fractionalTime, m_animation->duration());
}
case TimingFunction::StepsFunction: {
- const StepsTimingFunction* stepsTimingFunction = static_cast<const StepsTimingFunction*>(tf);
- return solveStepsFunction(stepsTimingFunction->numberOfSteps(), stepsTimingFunction->stepAtStart(), fractionalTime);
+ auto& function = *static_cast<const StepsTimingFunction*>(timingFunction);
+ return solveStepsFunction(function.numberOfSteps(), function.stepAtStart(), fractionalTime);
+ }
+ case TimingFunction::SpringFunction: {
+ auto& function = *static_cast<const SpringTimingFunction*>(timingFunction);
+ return solveSpringFunction(function.mass(), function.stiffness(), function.damping(), function.initialVelocity(), fractionalTime, m_animation->duration());
}
case TimingFunction::LinearFunction:
return fractionalTime;
@@ -611,16 +678,16 @@ double AnimationBase::progress(double scale, double offset, const TimingFunction
void AnimationBase::getTimeToNextEvent(double& time, bool& isLooping) const
{
// Decide when the end or loop event needs to fire
- const double elapsedDuration = std::max(beginAnimationUpdateTime() - m_startTime, 0.0);
+ const double elapsedDuration = std::max(beginAnimationUpdateTime() - m_startTime.value_or(0), 0.0);
double durationLeft = 0;
- double nextIterationTime = m_totalDuration;
+ double nextIterationTime = m_totalDuration.value_or(0);
- if (m_totalDuration < 0 || elapsedDuration < m_totalDuration) {
+ if (!m_totalDuration || elapsedDuration < m_totalDuration.value()) {
durationLeft = m_animation->duration() > 0 ? (m_animation->duration() - fmod(elapsedDuration, m_animation->duration())) : 0;
nextIterationTime = elapsedDuration + durationLeft;
}
- if (m_totalDuration < 0 || nextIterationTime < m_totalDuration) {
+ if (!m_totalDuration || nextIterationTime < m_totalDuration.value()) {
// We are not at the end yet
ASSERT(nextIterationTime > 0);
isLooping = true;
@@ -637,52 +704,70 @@ 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;
+ LOG(Animations, "%p AnimationState %s -> %s", this, nameForState(m_animationState), isLooping ? "Looping" : "Ending");
+ m_animationState = isLooping ? AnimationState::Looping : AnimationState::Ending;
}
void AnimationBase::freezeAtTime(double t)
{
- if (!m_compAnim)
+ if (!m_compositeAnimation)
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;
+ LOG(Animations, "%p AnimationState %s -> StartWaitResponse", this, nameForState(m_animationState));
+ m_animationState = AnimationState::StartWaitResponse;
onAnimationStartResponse(monotonicallyIncreasingTime());
}
- ASSERT(m_startTime); // if m_startTime is zero, we haven't started yet, so we'll get a bad pause time.
+ 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;
+ m_pauseTime = m_startTime.value_or(0);
else
- m_pauseTime = m_startTime + t - m_animation->delay();
+ m_pauseTime = m_startTime.value_or(0) + t - m_animation->delay();
-#if USE(ACCELERATED_COMPOSITING)
if (m_object && m_object->isComposited())
- toRenderBoxModelObject(m_object)->suspendAnimations(m_pauseTime);
-#endif
+ downcast<RenderBoxModelObject>(*m_object).suspendAnimations(m_pauseTime.value());
}
double AnimationBase::beginAnimationUpdateTime() const
{
- if (!m_compAnim)
+ if (!m_compositeAnimation)
return 0;
- return m_compAnim->animationController()->beginAnimationUpdateTime();
+ return m_compositeAnimation->animationController().beginAnimationUpdateTime();
}
double AnimationBase::getElapsedTime() const
{
- if (paused())
- return m_pauseTime - m_startTime;
- if (m_startTime <= 0)
+#if ENABLE(CSS_ANIMATIONS_LEVEL_2)
+ if (m_animation->trigger() && m_animation->trigger()->isScrollAnimationTrigger()) {
+ auto& scrollTrigger = downcast<ScrollAnimationTrigger>(*m_animation->trigger());
+ if (scrollTrigger.hasEndValue() && m_object) {
+ float offset = m_compositeAnimation->animationController().scrollPosition();
+ float startValue = scrollTrigger.startValue().value();
+ if (offset < startValue)
+ return 0;
+ float endValue = scrollTrigger.endValue().value();
+ if (offset > endValue)
+ return m_animation->duration();
+ return m_animation->duration() * (offset - startValue) / (endValue - startValue);
+ }
+ }
+#endif
+
+ if (paused()) {
+ double delayOffset = (!m_startTime && m_animation->delay() < 0) ? m_animation->delay() : 0;
+ return m_pauseTime.value_or(0) - m_startTime.value_or(0) - delayOffset;
+ }
+
+ if (!m_startTime)
return 0;
- if (postActive())
- return 1;
- return beginAnimationUpdateTime() - m_startTime;
+ if (postActive() || fillingForwards())
+ return m_totalDuration.value_or(0);
+
+ return beginAnimationUpdateTime() - m_startTime.value_or(0);
}
void AnimationBase::setElapsedTime(double time)
@@ -701,4 +786,77 @@ void AnimationBase::pause()
// FIXME: implement this method
}
+static bool containsRotation(const Vector<RefPtr<TransformOperation>>& operations)
+{
+ for (const auto& operation : operations) {
+ if (operation->type() == TransformOperation::ROTATE)
+ return true;
+ }
+ return false;
+}
+
+bool AnimationBase::computeTransformedExtentViaTransformList(const FloatRect& rendererBox, const RenderStyle& style, LayoutRect& bounds) const
+{
+ FloatRect floatBounds = bounds;
+ FloatPoint transformOrigin;
+
+ bool applyTransformOrigin = containsRotation(style.transform().operations()) || style.transform().affectedByTransformOrigin();
+ if (applyTransformOrigin) {
+ float offsetX = style.transformOriginX().isPercent() ? rendererBox.x() : 0;
+ float offsetY = style.transformOriginY().isPercent() ? rendererBox.y() : 0;
+
+ transformOrigin.setX(floatValueForLength(style.transformOriginX(), rendererBox.width()) + offsetX);
+ transformOrigin.setY(floatValueForLength(style.transformOriginY(), rendererBox.height()) + offsetY);
+ // Ignore transformOriginZ because we'll bail if we encounter any 3D transforms.
+
+ floatBounds.moveBy(-transformOrigin);
+ }
+
+ for (const auto& operation : style.transform().operations()) {
+ if (operation->type() == TransformOperation::ROTATE) {
+ // For now, just treat this as a full rotation. This could take angle into account to reduce inflation.
+ floatBounds = boundsOfRotatingRect(floatBounds);
+ } else {
+ TransformationMatrix transform;
+ operation->apply(transform, rendererBox.size());
+ if (!transform.isAffine())
+ return false;
+
+ if (operation->type() == TransformOperation::MATRIX || operation->type() == TransformOperation::MATRIX_3D) {
+ TransformationMatrix::Decomposed2Type toDecomp;
+ transform.decompose2(toDecomp);
+ // Any rotation prevents us from using a simple start/end rect union.
+ if (toDecomp.angle)
+ return false;
+ }
+
+ floatBounds = transform.mapRect(floatBounds);
+ }
+ }
+
+ if (applyTransformOrigin)
+ floatBounds.moveBy(transformOrigin);
+
+ bounds = LayoutRect(floatBounds);
+ return true;
+}
+
+bool AnimationBase::computeTransformedExtentViaMatrix(const FloatRect& rendererBox, const RenderStyle& style, LayoutRect& bounds) const
+{
+ TransformationMatrix transform;
+ style.applyTransform(transform, rendererBox, RenderStyle::IncludeTransformOrigin);
+ if (!transform.isAffine())
+ return false;
+
+ TransformationMatrix::Decomposed2Type fromDecomp;
+ transform.decompose2(fromDecomp);
+ // Any rotation prevents us from using a simple start/end rect union.
+ if (fromDecomp.angle)
+ return false;
+
+ bounds = LayoutRect(transform.mapRect(bounds));
+ return true;
+
+}
+
} // namespace WebCore