summaryrefslogtreecommitdiff
path: root/Source/WebCore/page/animation
diff options
context:
space:
mode:
Diffstat (limited to 'Source/WebCore/page/animation')
-rw-r--r--Source/WebCore/page/animation/AnimationBase.cpp618
-rw-r--r--Source/WebCore/page/animation/AnimationBase.h196
-rw-r--r--Source/WebCore/page/animation/AnimationController.cpp645
-rw-r--r--Source/WebCore/page/animation/CSSAnimationController.cpp805
-rw-r--r--Source/WebCore/page/animation/CSSAnimationController.h (renamed from Source/WebCore/page/animation/AnimationController.h)75
-rw-r--r--Source/WebCore/page/animation/CSSAnimationControllerPrivate.h (renamed from Source/WebCore/page/animation/AnimationControllerPrivate.h)99
-rw-r--r--Source/WebCore/page/animation/CSSPropertyAnimation.cpp824
-rw-r--r--Source/WebCore/page/animation/CSSPropertyAnimation.h9
-rw-r--r--Source/WebCore/page/animation/CompositeAnimation.cpp444
-rw-r--r--Source/WebCore/page/animation/CompositeAnimation.h47
-rw-r--r--Source/WebCore/page/animation/ImplicitAnimation.cpp165
-rw-r--r--Source/WebCore/page/animation/ImplicitAnimation.h49
-rw-r--r--Source/WebCore/page/animation/KeyframeAnimation.cpp342
-rw-r--r--Source/WebCore/page/animation/KeyframeAnimation.h69
14 files changed, 2536 insertions, 1851 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
diff --git a/Source/WebCore/page/animation/AnimationBase.h b/Source/WebCore/page/animation/AnimationBase.h
index 51673374d..f3387d2ef 100644
--- a/Source/WebCore/page/animation/AnimationBase.h
+++ b/Source/WebCore/page/animation/AnimationBase.h
@@ -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.
*
@@ -26,23 +26,19 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef AnimationBase_h
-#define AnimationBase_h
+#pragma once
#include "Animation.h"
#include "CSSPropertyNames.h"
#include "RenderStyleConstants.h"
-#include <wtf/HashMap.h>
-#include <wtf/HashSet.h>
-#include <wtf/RefCounted.h>
#include <wtf/text/AtomicString.h>
namespace WebCore {
-class AnimationBase;
-class AnimationController;
class CompositeAnimation;
class Element;
+class FloatRect;
+class LayoutRect;
class RenderElement;
class RenderStyle;
class TimingFunction;
@@ -50,7 +46,7 @@ class TimingFunction;
class AnimationBase : public RefCounted<AnimationBase> {
friend class CompositeAnimation;
friend class CSSPropertyAnimation;
-
+ WTF_MAKE_FAST_ALLOCATED;
public:
AnimationBase(const Animation& transition, RenderElement*, CompositeAnimation*);
virtual ~AnimationBase() { }
@@ -58,9 +54,9 @@ public:
RenderElement* renderer() const { return m_object; }
void clear()
{
- endAnimation();
- m_object = 0;
- m_compAnim = 0;
+ endAnimation();
+ m_object = nullptr;
+ m_compositeAnimation = nullptr;
}
double duration() const;
@@ -68,106 +64,129 @@ public:
// Animations and Transitions go through the states below. When entering the STARTED state
// the animation is started. This may or may not require deferred response from the animator.
// If so, we stay in this state until that response is received (and it returns the start time).
- // Otherwise, we use the current time as the start time and go immediately to AnimationStateLooping
- // or AnimationStateEnding.
- enum AnimState {
- AnimationStateNew, // animation just created, animation not running yet
- AnimationStateStartWaitTimer, // start timer running, waiting for fire
- AnimationStateStartWaitStyleAvailable, // waiting for style setup so we can start animations
- AnimationStateStartWaitResponse, // animation started, waiting for response
- AnimationStateLooping, // response received, animation running, loop timer running, waiting for fire
- AnimationStateEnding, // received, animation running, end timer running, waiting for fire
- AnimationStatePausedNew, // in pause mode when animation was created
- AnimationStatePausedWaitTimer, // in pause mode when animation started
- AnimationStatePausedWaitStyleAvailable, // in pause mode when waiting for style setup
- AnimationStatePausedWaitResponse, // animation paused when in STARTING state
- AnimationStatePausedRun, // animation paused when in LOOPING or ENDING state
- AnimationStateDone, // end timer fired, animation finished and removed
- AnimationStateFillingForwards // animation has ended and is retaining its final value
+ // Otherwise, we use the current time as the start time and go immediately to AnimationState::Looping
+ // or AnimationState::Ending.
+ enum class AnimationState {
+ New, // animation just created, animation not running yet
+ StartWaitTimer, // start timer running, waiting for fire
+ StartWaitStyleAvailable, // waiting for style setup so we can start animations
+ StartWaitResponse, // animation started, waiting for response
+ Looping, // response received, animation running, loop timer running, waiting for fire
+ Ending, // received, animation running, end timer running, waiting for fire
+ PausedNew, // in pause mode when animation was created
+ PausedWaitTimer, // in pause mode when animation started
+ PausedWaitStyleAvailable, // in pause mode when waiting for style setup
+ PausedWaitResponse, // animation paused when in STARTING state
+ PausedRun, // animation paused when in LOOPING or ENDING state
+ Done, // end timer fired, animation finished and removed
+ FillingForwards // animation has ended and is retaining its final value
};
- enum AnimStateInput {
- AnimationStateInputMakeNew, // reset back to new from any state
- AnimationStateInputStartAnimation, // animation requests a start
- AnimationStateInputRestartAnimation, // force a restart from any state
- AnimationStateInputStartTimerFired, // start timer fired
- AnimationStateInputStyleAvailable, // style is setup, ready to start animating
- AnimationStateInputStartTimeSet, // m_startTime was set
- AnimationStateInputLoopTimerFired, // loop timer fired
- AnimationStateInputEndTimerFired, // end timer fired
- AnimationStateInputPauseOverride, // pause an animation due to override
- AnimationStateInputResumeOverride, // resume an overridden animation
- AnimationStateInputPlayStateRunning, // play state paused -> running
- AnimationStateInputPlayStatePaused, // play state running -> paused
- AnimationStateInputEndAnimation // force an end from any state
+ enum class AnimationStateInput {
+ MakeNew, // reset back to new from any state
+ StartAnimation, // animation requests a start
+ RestartAnimation, // force a restart from any state
+ StartTimerFired, // start timer fired
+ StyleAvailable, // style is setup, ready to start animating
+ StartTimeSet, // m_startTime was set
+ LoopTimerFired, // loop timer fired
+ EndTimerFired, // end timer fired
+ PauseOverride, // pause an animation due to override
+ ResumeOverride, // resume an overridden animation
+ PlayStateRunning, // play state paused -> running
+ PlayStatePaused, // play state running -> paused
+ EndAnimation // force an end from any state
};
- // Called when animation is in AnimationStateNew to start animation
- void updateStateMachine(AnimStateInput, double param);
+ // Called when animation is in AnimationState::New to start animation
+ void updateStateMachine(AnimationStateInput, double param);
// Animation has actually started, at passed time
void onAnimationStartResponse(double startTime)
{
- updateStateMachine(AnimationBase::AnimationStateInputStartTimeSet, startTime);
+ updateStateMachine(AnimationStateInput::StartTimeSet, startTime);
}
// Called to change to or from paused state
void updatePlayState(EAnimPlayState);
bool playStatePlaying() const;
- bool waitingToStart() const { return m_animState == AnimationStateNew || m_animState == AnimationStateStartWaitTimer || m_animState == AnimationStatePausedNew; }
+ bool waitingToStart() const { return m_animationState == AnimationState::New || m_animationState == AnimationState::StartWaitTimer || m_animationState == AnimationState::PausedNew; }
bool preActive() const
{
- return m_animState == AnimationStateNew || m_animState == AnimationStateStartWaitTimer || m_animState == AnimationStateStartWaitStyleAvailable || m_animState == AnimationStateStartWaitResponse;
+ return m_animationState == AnimationState::New || m_animationState == AnimationState::StartWaitTimer || m_animationState == AnimationState::StartWaitStyleAvailable || m_animationState == AnimationState::StartWaitResponse;
}
- bool postActive() const { return m_animState == AnimationStateDone; }
+ bool postActive() const { return m_animationState == AnimationState::Done; }
+ bool fillingForwards() const { return m_animationState == AnimationState::FillingForwards; }
bool active() const { return !postActive() && !preActive(); }
bool running() const { return !isNew() && !postActive(); }
- bool paused() const { return m_pauseTime >= 0 || m_animState == AnimationStatePausedNew; }
- bool isNew() const { return m_animState == AnimationStateNew || m_animState == AnimationStatePausedNew; }
- bool waitingForStartTime() const { return m_animState == AnimationStateStartWaitResponse; }
- bool waitingForStyleAvailable() const { return m_animState == AnimationStateStartWaitStyleAvailable; }
+ bool paused() const { return m_pauseTime || m_animationState == AnimationState::PausedNew; }
+ bool inPausedState() const { return m_animationState >= AnimationState::PausedNew && m_animationState <= AnimationState::PausedRun; }
+ bool isNew() const { return m_animationState == AnimationState::New || m_animationState == AnimationState::PausedNew; }
+ bool waitingForStartTime() const { return m_animationState == AnimationState::StartWaitResponse; }
+ bool waitingForStyleAvailable() const { return m_animationState == AnimationState::StartWaitStyleAvailable; }
+
+ bool isAccelerated() const { return m_isAccelerated; }
virtual double timeToNextService();
- double progress(double scale, double offset, const TimingFunction*) const;
+ double progress(double scale = 1, double offset = 0, const TimingFunction* = nullptr) const;
- virtual void animate(CompositeAnimation*, RenderElement*, const RenderStyle* /*currentStyle*/, RenderStyle* /*targetStyle*/, RefPtr<RenderStyle>& /*animatedStyle*/) = 0;
- virtual void getAnimatedStyle(RefPtr<RenderStyle>& /*animatedStyle*/) = 0;
+ // Returns true if the animation state changed.
+ virtual bool animate(CompositeAnimation*, RenderElement*, const RenderStyle* /*currentStyle*/, const RenderStyle* /*targetStyle*/, std::unique_ptr<RenderStyle>& /*animatedStyle*/, bool& didBlendStyle) = 0;
+ virtual void getAnimatedStyle(std::unique_ptr<RenderStyle>& /*animatedStyle*/) = 0;
+
+ virtual bool computeExtentOfTransformAnimation(LayoutRect&) const = 0;
virtual bool shouldFireEvents() const { return false; }
void fireAnimationEventsIfNeeded();
- bool animationsMatch(const Animation*) const;
+ bool animationsMatch(const Animation&) const;
- void setAnimation(const Animation& animation) { m_animation = const_cast<Animation*>(&animation); }
+ const Animation& animation() const { return m_animation; }
+ void setAnimation(const Animation& animation) { m_animation = const_cast<Animation&>(animation); }
// Return true if this animation is overridden. This will only be the case for
// ImplicitAnimations and is used to determine whether or not we should force
// set the start time. If an animation is overridden, it will probably not get
- // back the AnimationStateInputStartTimeSet input.
+ // back the AnimationStateInput::StartTimeSet input.
virtual bool overridden() const { return false; }
// Does this animation/transition involve the given property?
virtual bool affectsProperty(CSSPropertyID /*property*/) const { return false; }
- bool isAnimatingProperty(CSSPropertyID property, bool acceleratedOnly, bool isRunningNow) const
+ enum RunningStates {
+ Delaying = 1 << 0,
+ Paused = 1 << 1,
+ Running = 1 << 2,
+ };
+ typedef unsigned RunningState;
+ bool isAnimatingProperty(CSSPropertyID property, bool acceleratedOnly, RunningState runningState) const
{
if (acceleratedOnly && !m_isAccelerated)
return false;
-
- if (isRunningNow)
- return (!waitingToStart() && !postActive()) && affectsProperty(property);
- return !postActive() && affectsProperty(property);
+ if (!affectsProperty(property))
+ return false;
+
+ if ((runningState & Delaying) && preActive())
+ return true;
+
+ if ((runningState & Paused) && inPausedState())
+ return true;
+
+ if ((runningState & Running) && !inPausedState() && (m_animationState >= AnimationState::StartWaitStyleAvailable && m_animationState < AnimationState::Done))
+ return true;
+
+ return false;
}
- // FIXME: rename this using the "lists match" terminology.
- bool isTransformFunctionListValid() const { return m_transformFunctionListValid; }
-#if ENABLE(CSS_FILTERS)
+ bool transformFunctionListsMatch() const { return m_transformFunctionListsMatch; }
bool filterFunctionListsMatch() const { return m_filterFunctionListsMatch; }
+#if ENABLE(FILTERS_LEVEL_2)
+ bool backdropFilterFunctionListsMatch() const { return m_backdropFilterFunctionListsMatch; }
#endif
// Freeze the animation; used by DumpRenderTree.
@@ -186,16 +205,14 @@ public:
void styleAvailable()
{
ASSERT(waitingForStyleAvailable());
- updateStateMachine(AnimationBase::AnimationStateInputStyleAvailable, -1);
+ updateStateMachine(AnimationStateInput::StyleAvailable, -1);
}
- const Animation& animation() const { return *m_animation; }
-
protected:
virtual void overrideAnimations() { }
virtual void resumeOverriddenAnimations() { }
- CompositeAnimation* compositeAnimation() { return m_compAnim; }
+ CompositeAnimation* compositeAnimation() { return m_compositeAnimation; }
// These are called when the corresponding timer fires so subclasses can do any extra work
virtual void onAnimationStart(double /*elapsedTime*/) { }
@@ -211,7 +228,7 @@ protected:
void goIntoEndingOrLoopingState();
- bool isAccelerated() const { return m_isAccelerated; }
+ AnimationState state() const { return m_animationState; }
static void setNeedsStyleRecalc(Element*);
@@ -219,26 +236,27 @@ protected:
double fractionalTime(double scale, double elapsedTime, double offset) const;
- AnimState m_animState;
-
- bool m_isAccelerated;
- bool m_transformFunctionListValid;
-#if ENABLE(CSS_FILTERS)
- bool m_filterFunctionListsMatch;
-#endif
- double m_startTime;
- double m_pauseTime;
- double m_requestedStartTime;
-
- double m_totalDuration;
- double m_nextIterationDuration;
+ // These return true if we can easily compute a bounding box by applying the style's transform to the bounds rect.
+ bool computeTransformedExtentViaTransformList(const FloatRect& rendererBox, const RenderStyle&, LayoutRect& bounds) const;
+ bool computeTransformedExtentViaMatrix(const FloatRect& rendererBox, const RenderStyle&, LayoutRect& bounds) const;
RenderElement* m_object;
-
- RefPtr<Animation> m_animation;
- CompositeAnimation* m_compAnim;
+ CompositeAnimation* m_compositeAnimation; // Ideally this would be a reference, but it has to be cleared if an animation is destroyed inside an event callback.
+ Ref<Animation> m_animation;
+
+ std::optional<double> m_startTime;
+ std::optional<double> m_pauseTime;
+ double m_requestedStartTime { 0 };
+ std::optional<double> m_totalDuration;
+ std::optional<double> m_nextIterationDuration;
+
+ AnimationState m_animationState { AnimationState::New };
+ bool m_isAccelerated { false };
+ bool m_transformFunctionListsMatch { false };
+ bool m_filterFunctionListsMatch { false };
+#if ENABLE(FILTERS_LEVEL_2)
+ bool m_backdropFilterFunctionListsMatch { false };
+#endif
};
} // namespace WebCore
-
-#endif // AnimationBase_h
diff --git a/Source/WebCore/page/animation/AnimationController.cpp b/Source/WebCore/page/animation/AnimationController.cpp
deleted file mode 100644
index 5b8c90b8a..000000000
--- a/Source/WebCore/page/animation/AnimationController.cpp
+++ /dev/null
@@ -1,645 +0,0 @@
-/*
- * Copyright (C) 2007, 2008, 2009 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 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
- * its contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "config.h"
-#include "AnimationController.h"
-
-#include "AnimationBase.h"
-#include "AnimationControllerPrivate.h"
-#include "CSSParser.h"
-#include "CSSPropertyAnimation.h"
-#include "CompositeAnimation.h"
-#include "EventNames.h"
-#include "Frame.h"
-#include "FrameView.h"
-#include "Logging.h"
-#include "PseudoElement.h"
-#include "RenderView.h"
-#include "TransitionEvent.h"
-#include "WebKitAnimationEvent.h"
-#include "WebKitTransitionEvent.h"
-#include <wtf/CurrentTime.h>
-
-namespace WebCore {
-
-static const double cAnimationTimerDelay = 0.025;
-static const double cBeginAnimationUpdateTimeNotSet = -1;
-
-AnimationControllerPrivate::AnimationControllerPrivate(Frame& frame)
- : m_animationTimer(this, &AnimationControllerPrivate::animationTimerFired)
- , m_updateStyleIfNeededDispatcher(this, &AnimationControllerPrivate::updateStyleIfNeededDispatcherFired)
- , m_frame(frame)
- , m_beginAnimationUpdateTime(cBeginAnimationUpdateTimeNotSet)
- , m_animationsWaitingForStyle()
- , m_animationsWaitingForStartTimeResponse()
- , m_waitingForAsyncStartNotification(false)
- , m_isSuspended(false)
- , m_allowsNewAnimationsWhileSuspended(false)
-{
-}
-
-AnimationControllerPrivate::~AnimationControllerPrivate()
-{
-}
-
-CompositeAnimation& AnimationControllerPrivate::ensureCompositeAnimation(RenderElement* renderer)
-{
- auto result = m_compositeAnimations.add(renderer, nullptr);
- if (result.isNewEntry)
- result.iterator->value = CompositeAnimation::create(this);
- return *result.iterator->value;
-}
-
-bool AnimationControllerPrivate::clear(RenderElement* renderer)
-{
- // Return false if we didn't do anything OR we are suspended (so we don't try to
- // do a setNeedsStyleRecalc() when suspended).
- RefPtr<CompositeAnimation> animation = m_compositeAnimations.take(renderer);
- if (!animation)
- return false;
- animation->clearRenderer();
- return animation->isSuspended();
-}
-
-double AnimationControllerPrivate::updateAnimations(SetChanged callSetChanged/* = DoNotCallSetChanged*/)
-{
- double timeToNextService = -1;
- bool calledSetChanged = false;
-
- auto end = m_compositeAnimations.end();
- for (auto it = m_compositeAnimations.begin(); it != end; ++it) {
- CompositeAnimation& animation = *it->value;
- if (!animation.isSuspended() && animation.hasAnimations()) {
- double t = animation.timeToNextService();
- if (t != -1 && (t < timeToNextService || timeToNextService == -1))
- timeToNextService = t;
- if (!timeToNextService) {
- if (callSetChanged != CallSetChanged)
- break;
- Element* element = it->key->element();
- ASSERT(element);
- ASSERT(!element->document().inPageCache());
- element->setNeedsStyleRecalc(SyntheticStyleChange);
- calledSetChanged = true;
- }
- }
- }
-
- if (calledSetChanged)
- m_frame.document()->updateStyleIfNeeded();
-
- return timeToNextService;
-}
-
-void AnimationControllerPrivate::updateAnimationTimerForRenderer(RenderElement* renderer)
-{
- double timeToNextService = 0;
-
- const CompositeAnimation* compositeAnimation = m_compositeAnimations.get(renderer);
- if (!compositeAnimation->isSuspended() && compositeAnimation->hasAnimations())
- timeToNextService = compositeAnimation->timeToNextService();
-
- if (m_animationTimer.isActive() && (m_animationTimer.repeatInterval() || m_animationTimer.nextFireInterval() <= timeToNextService))
- return;
-
- m_animationTimer.startOneShot(timeToNextService);
-}
-
-void AnimationControllerPrivate::updateAnimationTimer(SetChanged callSetChanged/* = DoNotCallSetChanged*/)
-{
- double timeToNextService = updateAnimations(callSetChanged);
-
- LOG(Animations, "updateAnimationTimer: timeToNextService is %.2f", timeToNextService);
-
- // If we want service immediately, we start a repeating timer to reduce the overhead of starting
- if (!timeToNextService) {
- if (!m_animationTimer.isActive() || m_animationTimer.repeatInterval() == 0)
- m_animationTimer.startRepeating(cAnimationTimerDelay);
- return;
- }
-
- // If we don't need service, we want to make sure the timer is no longer running
- if (timeToNextService < 0) {
- if (m_animationTimer.isActive())
- m_animationTimer.stop();
- return;
- }
-
- // Otherwise, we want to start a one-shot timer so we get here again
- m_animationTimer.startOneShot(timeToNextService);
-}
-
-void AnimationControllerPrivate::updateStyleIfNeededDispatcherFired(Timer<AnimationControllerPrivate>&)
-{
- fireEventsAndUpdateStyle();
-}
-
-void AnimationControllerPrivate::fireEventsAndUpdateStyle()
-{
- // Protect the frame from getting destroyed in the event handler
- Ref<Frame> protector(m_frame);
-
- bool updateStyle = !m_eventsToDispatch.isEmpty() || !m_elementChangesToDispatch.isEmpty();
-
- // fire all the events
- Vector<EventToDispatch> eventsToDispatch = std::move(m_eventsToDispatch);
- Vector<EventToDispatch>::const_iterator eventsToDispatchEnd = eventsToDispatch.end();
- for (Vector<EventToDispatch>::const_iterator it = eventsToDispatch.begin(); it != eventsToDispatchEnd; ++it) {
- Element* element = it->element.get();
- if (it->eventType == eventNames().transitionendEvent)
- element->dispatchEvent(TransitionEvent::create(it->eventType, it->name, it->elapsedTime, PseudoElement::pseudoElementNameForEvents(element->pseudoId())));
- else
- element->dispatchEvent(WebKitAnimationEvent::create(it->eventType, it->name, it->elapsedTime));
- }
-
- for (unsigned i = 0, size = m_elementChangesToDispatch.size(); i < size; ++i)
- m_elementChangesToDispatch[i]->setNeedsStyleRecalc(SyntheticStyleChange);
-
- m_elementChangesToDispatch.clear();
-
- if (updateStyle)
- m_frame.document()->updateStyleIfNeeded();
-}
-
-void AnimationControllerPrivate::startUpdateStyleIfNeededDispatcher()
-{
- if (!m_updateStyleIfNeededDispatcher.isActive())
- m_updateStyleIfNeededDispatcher.startOneShot(0);
-}
-
-void AnimationControllerPrivate::addEventToDispatch(PassRefPtr<Element> element, const AtomicString& eventType, const String& name, double elapsedTime)
-{
- m_eventsToDispatch.grow(m_eventsToDispatch.size()+1);
- EventToDispatch& event = m_eventsToDispatch[m_eventsToDispatch.size()-1];
- event.element = element;
- event.eventType = eventType;
- event.name = name;
- event.elapsedTime = elapsedTime;
-
- startUpdateStyleIfNeededDispatcher();
-}
-
-void AnimationControllerPrivate::addElementChangeToDispatch(PassRef<Element> element)
-{
- m_elementChangesToDispatch.append(std::move(element));
- ASSERT(!m_elementChangesToDispatch.last()->document().inPageCache());
- startUpdateStyleIfNeededDispatcher();
-}
-
-#if ENABLE(REQUEST_ANIMATION_FRAME)
-void AnimationControllerPrivate::animationFrameCallbackFired()
-{
- double timeToNextService = updateAnimations(CallSetChanged);
-
- if (timeToNextService >= 0)
- m_frame.document()->view()->scheduleAnimation();
-}
-#endif
-
-void AnimationControllerPrivate::animationTimerFired(Timer<AnimationControllerPrivate>&)
-{
- // Make sure animationUpdateTime is updated, so that it is current even if no
- // styleChange has happened (e.g. accelerated animations)
- setBeginAnimationUpdateTime(cBeginAnimationUpdateTimeNotSet);
-
- // When the timer fires, all we do is call setChanged on all DOM nodes with running animations and then do an immediate
- // updateStyleIfNeeded. It will then call back to us with new information.
- updateAnimationTimer(CallSetChanged);
-
- // Fire events right away, to avoid a flash of unanimated style after an animation completes, and before
- // the 'end' event fires.
- fireEventsAndUpdateStyle();
-}
-
-bool AnimationControllerPrivate::isRunningAnimationOnRenderer(RenderElement* renderer, CSSPropertyID property, bool isRunningNow) const
-{
- const CompositeAnimation* animation = m_compositeAnimations.get(renderer);
- return animation && animation->isAnimatingProperty(property, false, isRunningNow);
-}
-
-bool AnimationControllerPrivate::isRunningAcceleratedAnimationOnRenderer(RenderElement* renderer, CSSPropertyID property, bool isRunningNow) const
-{
- const CompositeAnimation* animation = m_compositeAnimations.get(renderer);
- return animation && animation->isAnimatingProperty(property, true, isRunningNow);
-}
-
-void AnimationControllerPrivate::suspendAnimations()
-{
- if (isSuspended())
- return;
-
- suspendAnimationsForDocument(m_frame.document());
-
- // Traverse subframes
- for (Frame* child = m_frame.tree().firstChild(); child; child = child->tree().nextSibling())
- child->animation().suspendAnimations();
-
- m_isSuspended = true;
-}
-
-void AnimationControllerPrivate::resumeAnimations()
-{
- if (!isSuspended())
- return;
-
- resumeAnimationsForDocument(m_frame.document());
-
- // Traverse subframes
- for (Frame* child = m_frame.tree().firstChild(); child; child = child->tree().nextSibling())
- child->animation().resumeAnimations();
-
- m_isSuspended = false;
-}
-
-void AnimationControllerPrivate::suspendAnimationsForDocument(Document* document)
-{
- setBeginAnimationUpdateTime(cBeginAnimationUpdateTimeNotSet);
-
- for (auto it = m_compositeAnimations.begin(), end = m_compositeAnimations.end(); it != end; ++it) {
- if (&it->key->document() == document)
- it->value->suspendAnimations();
- }
-
- updateAnimationTimer();
-}
-
-void AnimationControllerPrivate::resumeAnimationsForDocument(Document* document)
-{
- setBeginAnimationUpdateTime(cBeginAnimationUpdateTimeNotSet);
-
- for (auto it = m_compositeAnimations.begin(), end = m_compositeAnimations.end(); it != end; ++it) {
- if (&it->key->document() == document)
- it->value->resumeAnimations();
- }
-
- updateAnimationTimer();
-}
-
-void AnimationControllerPrivate::startAnimationsIfNotSuspended(Document* document)
-{
- if (!isSuspended() || allowsNewAnimationsWhileSuspended())
- resumeAnimationsForDocument(document);
-}
-
-void AnimationControllerPrivate::setAllowsNewAnimationsWhileSuspended(bool allowed)
-{
- m_allowsNewAnimationsWhileSuspended = allowed;
-}
-
-bool AnimationControllerPrivate::pauseAnimationAtTime(RenderElement* renderer, const AtomicString& name, double t)
-{
- if (!renderer)
- return false;
-
- CompositeAnimation& compositeAnimation = ensureCompositeAnimation(renderer);
- if (compositeAnimation.pauseAnimationAtTime(name, t)) {
- renderer->element()->setNeedsStyleRecalc(SyntheticStyleChange);
- startUpdateStyleIfNeededDispatcher();
- return true;
- }
-
- return false;
-}
-
-bool AnimationControllerPrivate::pauseTransitionAtTime(RenderElement* renderer, const String& property, double t)
-{
- if (!renderer)
- return false;
-
- CompositeAnimation& compositeAnimation = ensureCompositeAnimation(renderer);
- if (compositeAnimation.pauseTransitionAtTime(cssPropertyID(property), t)) {
- renderer->element()->setNeedsStyleRecalc(SyntheticStyleChange);
- startUpdateStyleIfNeededDispatcher();
- return true;
- }
-
- return false;
-}
-
-double AnimationControllerPrivate::beginAnimationUpdateTime()
-{
- if (m_beginAnimationUpdateTime == cBeginAnimationUpdateTimeNotSet)
- m_beginAnimationUpdateTime = monotonicallyIncreasingTime();
- return m_beginAnimationUpdateTime;
-}
-
-void AnimationControllerPrivate::endAnimationUpdate()
-{
- styleAvailable();
- if (!m_waitingForAsyncStartNotification)
- startTimeResponse(beginAnimationUpdateTime());
-}
-
-void AnimationControllerPrivate::receivedStartTimeResponse(double time)
-{
- m_waitingForAsyncStartNotification = false;
- startTimeResponse(time);
-}
-
-PassRefPtr<RenderStyle> AnimationControllerPrivate::getAnimatedStyleForRenderer(RenderElement* renderer)
-{
- if (!renderer)
- return 0;
-
- const CompositeAnimation* rendererAnimations = m_compositeAnimations.get(renderer);
- if (!rendererAnimations)
- return &renderer->style();
-
- RefPtr<RenderStyle> animatingStyle = rendererAnimations->getAnimatedStyle();
- if (!animatingStyle)
- animatingStyle = &renderer->style();
-
- return animatingStyle.release();
-}
-
-unsigned AnimationControllerPrivate::numberOfActiveAnimations(Document* document) const
-{
- unsigned count = 0;
-
- for (auto it = m_compositeAnimations.begin(), end = m_compositeAnimations.end(); it != end; ++it) {
- if (&it->key->document() == document)
- count += it->value->numberOfActiveAnimations();
- }
-
- return count;
-}
-
-void AnimationControllerPrivate::addToAnimationsWaitingForStyle(AnimationBase* animation)
-{
- // Make sure this animation is not in the start time waiters
- m_animationsWaitingForStartTimeResponse.remove(animation);
-
- m_animationsWaitingForStyle.add(animation);
-}
-
-void AnimationControllerPrivate::removeFromAnimationsWaitingForStyle(AnimationBase* animationToRemove)
-{
- m_animationsWaitingForStyle.remove(animationToRemove);
-}
-
-void AnimationControllerPrivate::styleAvailable()
-{
- // Go through list of waiters and send them on their way
- for (const auto& waitingAnimation : m_animationsWaitingForStyle)
- waitingAnimation->styleAvailable();
-
- m_animationsWaitingForStyle.clear();
-}
-
-void AnimationControllerPrivate::addToAnimationsWaitingForStartTimeResponse(AnimationBase* animation, bool willGetResponse)
-{
- // If willGetResponse is true, it means this animation is actually waiting for a response
- // (which will come in as a call to notifyAnimationStarted()).
- // In that case we don't need to add it to this list. We just set a waitingForAResponse flag
- // which says we are waiting for the response. If willGetResponse is false, this animation
- // is not waiting for a response for itself, but rather for a notifyXXXStarted() call for
- // another animation to which it will sync.
- //
- // When endAnimationUpdate() is called we check to see if the waitingForAResponse flag is
- // true. If so, we just return and will do our work when the first notifyXXXStarted() call
- // comes in. If it is false, we will not be getting a notifyXXXStarted() call, so we will
- // do our work right away. In both cases we call the onAnimationStartResponse() method
- // on each animation. In the first case we send in the time we got from notifyXXXStarted().
- // In the second case, we just pass in the beginAnimationUpdateTime().
- //
- // This will synchronize all software and accelerated animations started in the same
- // updateStyleIfNeeded cycle.
- //
-
- if (willGetResponse)
- m_waitingForAsyncStartNotification = true;
-
- m_animationsWaitingForStartTimeResponse.add(animation);
-}
-
-void AnimationControllerPrivate::removeFromAnimationsWaitingForStartTimeResponse(AnimationBase* animationToRemove)
-{
- m_animationsWaitingForStartTimeResponse.remove(animationToRemove);
-
- if (m_animationsWaitingForStartTimeResponse.isEmpty())
- m_waitingForAsyncStartNotification = false;
-}
-
-void AnimationControllerPrivate::startTimeResponse(double time)
-{
- // Go through list of waiters and send them on their way
-
- for (const auto& animation : m_animationsWaitingForStartTimeResponse)
- animation->onAnimationStartResponse(time);
-
- m_animationsWaitingForStartTimeResponse.clear();
- m_waitingForAsyncStartNotification = false;
-}
-
-void AnimationControllerPrivate::animationWillBeRemoved(AnimationBase* animation)
-{
- removeFromAnimationsWaitingForStyle(animation);
- removeFromAnimationsWaitingForStartTimeResponse(animation);
-}
-
-AnimationController::AnimationController(Frame& frame)
- : m_data(std::make_unique<AnimationControllerPrivate>(frame))
- , m_beginAnimationUpdateCount(0)
-{
-}
-
-AnimationController::~AnimationController()
-{
-}
-
-void AnimationController::cancelAnimations(RenderElement* renderer)
-{
- if (!m_data->hasAnimations())
- return;
-
- if (m_data->clear(renderer)) {
- Element* element = renderer->element();
- ASSERT(!element || !element->document().inPageCache());
- if (element)
- element->setNeedsStyleRecalc(SyntheticStyleChange);
- }
-}
-
-PassRef<RenderStyle> AnimationController::updateAnimations(RenderElement& renderer, PassRef<RenderStyle> newStyle)
-{
- // Don't do anything if we're in the cache
- if (renderer.document().inPageCache())
- return newStyle;
-
- RenderStyle* oldStyle = renderer.hasInitializedStyle() ? &renderer.style() : nullptr;
-
- if ((!oldStyle || (!oldStyle->animations() && !oldStyle->transitions())) && (!newStyle.get().animations() && !newStyle.get().transitions()))
- return newStyle;
-
- // Don't run transitions when printing.
- if (renderer.view().printing())
- return newStyle;
-
- // Fetch our current set of implicit animations from a hashtable. We then compare them
- // against the animations in the style and make sure we're in sync. If destination values
- // have changed, we reset the animation. We then do a blend to get new values and we return
- // a new style.
-
- // We don't support anonymous pseudo elements like :first-line or :first-letter.
- ASSERT(renderer.element());
-
- Ref<RenderStyle> newStyleBeforeAnimation(std::move(newStyle));
-
- CompositeAnimation& rendererAnimations = m_data->ensureCompositeAnimation(&renderer);
- auto blendedStyle = rendererAnimations.animate(renderer, oldStyle, newStyleBeforeAnimation.get());
-
- if (renderer.parent() || newStyleBeforeAnimation->animations() || (oldStyle && oldStyle->animations())) {
- m_data->updateAnimationTimerForRenderer(&renderer);
-#if ENABLE(REQUEST_ANIMATION_FRAME)
- renderer.view().frameView().scheduleAnimation();
-#endif
- }
-
- if (&blendedStyle.get() != &newStyleBeforeAnimation.get()) {
- // If the animations/transitions change opacity or transform, we need to update
- // the style to impose the stacking rules. Note that this is also
- // done in StyleResolver::adjustRenderStyle().
- if (blendedStyle.get().hasAutoZIndex() && (blendedStyle.get().opacity() < 1.0f || blendedStyle.get().hasTransform()))
- blendedStyle.get().setZIndex(0);
- }
- return blendedStyle;
-}
-
-PassRefPtr<RenderStyle> AnimationController::getAnimatedStyleForRenderer(RenderElement* renderer)
-{
- return m_data->getAnimatedStyleForRenderer(renderer);
-}
-
-void AnimationController::notifyAnimationStarted(RenderElement*, double startTime)
-{
- m_data->receivedStartTimeResponse(startTime);
-}
-
-bool AnimationController::pauseAnimationAtTime(RenderElement* renderer, const AtomicString& name, double t)
-{
- return m_data->pauseAnimationAtTime(renderer, name, t);
-}
-
-unsigned AnimationController::numberOfActiveAnimations(Document* document) const
-{
- return m_data->numberOfActiveAnimations(document);
-}
-
-bool AnimationController::pauseTransitionAtTime(RenderElement* renderer, const String& property, double t)
-{
- return m_data->pauseTransitionAtTime(renderer, property, t);
-}
-
-bool AnimationController::isRunningAnimationOnRenderer(RenderElement* renderer, CSSPropertyID property, bool isRunningNow) const
-{
- return m_data->isRunningAnimationOnRenderer(renderer, property, isRunningNow);
-}
-
-bool AnimationController::isRunningAcceleratedAnimationOnRenderer(RenderElement* renderer, CSSPropertyID property, bool isRunningNow) const
-{
- return m_data->isRunningAcceleratedAnimationOnRenderer(renderer, property, isRunningNow);
-}
-
-bool AnimationController::isSuspended() const
-{
- return m_data->isSuspended();
-}
-
-void AnimationController::suspendAnimations()
-{
- LOG(Animations, "controller is suspending animations");
- m_data->suspendAnimations();
-}
-
-void AnimationController::resumeAnimations()
-{
- LOG(Animations, "controller is resuming animations");
- m_data->resumeAnimations();
-}
-
-bool AnimationController::allowsNewAnimationsWhileSuspended() const
-{
- return m_data->allowsNewAnimationsWhileSuspended();
-}
-
-void AnimationController::setAllowsNewAnimationsWhileSuspended(bool allowed)
-{
- m_data->setAllowsNewAnimationsWhileSuspended(allowed);
-}
-
-#if ENABLE(REQUEST_ANIMATION_FRAME)
-void AnimationController::serviceAnimations()
-{
- m_data->animationFrameCallbackFired();
-}
-#endif
-
-void AnimationController::suspendAnimationsForDocument(Document* document)
-{
- LOG(Animations, "suspending animations for document %p", document);
- m_data->suspendAnimationsForDocument(document);
-}
-
-void AnimationController::resumeAnimationsForDocument(Document* document)
-{
- LOG(Animations, "resuming animations for document %p", document);
- m_data->resumeAnimationsForDocument(document);
-}
-
-void AnimationController::startAnimationsIfNotSuspended(Document* document)
-{
- LOG(Animations, "animations may start for document %p", document);
- m_data->startAnimationsIfNotSuspended(document);
-}
-
-void AnimationController::beginAnimationUpdate()
-{
- if (!m_beginAnimationUpdateCount)
- m_data->setBeginAnimationUpdateTime(cBeginAnimationUpdateTimeNotSet);
- ++m_beginAnimationUpdateCount;
-}
-
-void AnimationController::endAnimationUpdate()
-{
- ASSERT(m_beginAnimationUpdateCount > 0);
- --m_beginAnimationUpdateCount;
- if (!m_beginAnimationUpdateCount)
- m_data->endAnimationUpdate();
-}
-
-bool AnimationController::supportsAcceleratedAnimationOfProperty(CSSPropertyID property)
-{
-#if USE(ACCELERATED_COMPOSITING)
- return CSSPropertyAnimation::animationOfPropertyIsAccelerated(property);
-#else
- UNUSED_PARAM(property);
- return false;
-#endif
-}
-
-} // namespace WebCore
diff --git a/Source/WebCore/page/animation/CSSAnimationController.cpp b/Source/WebCore/page/animation/CSSAnimationController.cpp
new file mode 100644
index 000000000..b71ed2e43
--- /dev/null
+++ b/Source/WebCore/page/animation/CSSAnimationController.cpp
@@ -0,0 +1,805 @@
+/*
+ * Copyright (C) 2007, 2008, 2009 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 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 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "CSSAnimationController.h"
+
+#include "AnimationBase.h"
+#include "AnimationEvent.h"
+#include "CSSAnimationControllerPrivate.h"
+#include "CSSPropertyAnimation.h"
+#include "CSSPropertyParser.h"
+#include "CompositeAnimation.h"
+#include "EventNames.h"
+#include "Frame.h"
+#include "FrameView.h"
+#include "Logging.h"
+#include "PseudoElement.h"
+#include "RenderView.h"
+#include "TransitionEvent.h"
+#include "WebKitAnimationEvent.h"
+#include "WebKitTransitionEvent.h"
+#include <wtf/CurrentTime.h>
+
+namespace WebCore {
+
+// Allow a little more than 60fps to make sure we can at least hit that frame rate.
+static const double cAnimationTimerDelay = 0.015;
+static const double cBeginAnimationUpdateTimeNotSet = -1;
+
+class AnimationPrivateUpdateBlock {
+public:
+ AnimationPrivateUpdateBlock(CSSAnimationControllerPrivate& animationController)
+ : m_animationController(animationController)
+ {
+ m_animationController.beginAnimationUpdate();
+ }
+
+ ~AnimationPrivateUpdateBlock()
+ {
+ m_animationController.endAnimationUpdate();
+ }
+
+ CSSAnimationControllerPrivate& m_animationController;
+};
+
+CSSAnimationControllerPrivate::CSSAnimationControllerPrivate(Frame& frame)
+ : m_animationTimer(*this, &CSSAnimationControllerPrivate::animationTimerFired)
+ , m_updateStyleIfNeededDispatcher(*this, &CSSAnimationControllerPrivate::updateStyleIfNeededDispatcherFired)
+ , m_frame(frame)
+ , m_beginAnimationUpdateTime(cBeginAnimationUpdateTimeNotSet)
+ , m_beginAnimationUpdateCount(0)
+ , m_waitingForAsyncStartNotification(false)
+ , m_isSuspended(false)
+ , m_allowsNewAnimationsWhileSuspended(false)
+{
+}
+
+CSSAnimationControllerPrivate::~CSSAnimationControllerPrivate()
+{
+}
+
+CompositeAnimation& CSSAnimationControllerPrivate::ensureCompositeAnimation(RenderElement& renderer)
+{
+ auto result = m_compositeAnimations.add(&renderer, nullptr);
+ if (result.isNewEntry) {
+ result.iterator->value = CompositeAnimation::create(*this);
+ renderer.setIsCSSAnimating(true);
+ }
+
+ if (animationsAreSuspendedForDocument(&renderer.document()))
+ result.iterator->value->suspendAnimations();
+
+ return *result.iterator->value;
+}
+
+bool CSSAnimationControllerPrivate::clear(RenderElement& renderer)
+{
+ LOG(Animations, "CSSAnimationControllerPrivate %p clear: %p", this, &renderer);
+
+ ASSERT(renderer.isCSSAnimating());
+ ASSERT(m_compositeAnimations.contains(&renderer));
+
+ Element* element = renderer.element();
+
+ m_eventsToDispatch.removeAllMatching([element] (const EventToDispatch& info) {
+ return info.element.ptr() == element;
+ });
+
+ m_elementChangesToDispatch.removeAllMatching([element](auto& currentElement) {
+ return currentElement.ptr() == element;
+ });
+
+ // Return false if we didn't do anything OR we are suspended (so we don't try to
+ // do a invalidateStyleForSubtree() when suspended).
+ RefPtr<CompositeAnimation> animation = m_compositeAnimations.take(&renderer);
+ ASSERT(animation);
+ renderer.setIsCSSAnimating(false);
+ animation->clearRenderer();
+ return animation->isSuspended();
+}
+
+double CSSAnimationControllerPrivate::updateAnimations(SetChanged callSetChanged/* = DoNotCallSetChanged*/)
+{
+ AnimationPrivateUpdateBlock updateBlock(*this);
+ double timeToNextService = -1;
+ bool calledSetChanged = false;
+
+ for (auto& compositeAnimation : m_compositeAnimations) {
+ CompositeAnimation& animation = *compositeAnimation.value;
+ if (!animation.isSuspended() && animation.hasAnimations()) {
+ double t = animation.timeToNextService();
+ if (t != -1 && (t < timeToNextService || timeToNextService == -1))
+ timeToNextService = t;
+ if (!timeToNextService) {
+ if (callSetChanged != CallSetChanged)
+ break;
+ Element* element = compositeAnimation.key->element();
+ ASSERT(element);
+ ASSERT(element->document().pageCacheState() == Document::NotInPageCache);
+ element->invalidateStyleAndLayerComposition();
+ calledSetChanged = true;
+ }
+ }
+ }
+
+ if (calledSetChanged)
+ m_frame.document()->updateStyleIfNeeded();
+
+ return timeToNextService;
+}
+
+void CSSAnimationControllerPrivate::updateAnimationTimerForRenderer(RenderElement& renderer)
+{
+ double timeToNextService = 0;
+
+ const CompositeAnimation* compositeAnimation = m_compositeAnimations.get(&renderer);
+ if (!compositeAnimation->isSuspended() && compositeAnimation->hasAnimations())
+ timeToNextService = compositeAnimation->timeToNextService();
+
+ if (m_animationTimer.isActive() && (m_animationTimer.repeatInterval() || m_animationTimer.nextFireInterval() <= timeToNextService))
+ return;
+
+ m_animationTimer.startOneShot(timeToNextService);
+}
+
+void CSSAnimationControllerPrivate::updateAnimationTimer(SetChanged callSetChanged/* = DoNotCallSetChanged*/)
+{
+ double timeToNextService = updateAnimations(callSetChanged);
+
+ LOG(Animations, "updateAnimationTimer: timeToNextService is %.2f", timeToNextService);
+
+ // If we want service immediately, we start a repeating timer to reduce the overhead of starting
+ if (!timeToNextService) {
+ if (!m_animationTimer.isActive() || !m_animationTimer.repeatInterval())
+ m_animationTimer.startRepeating(cAnimationTimerDelay);
+ return;
+ }
+
+ // If we don't need service, we want to make sure the timer is no longer running
+ if (timeToNextService < 0) {
+ if (m_animationTimer.isActive())
+ m_animationTimer.stop();
+ return;
+ }
+
+ // Otherwise, we want to start a one-shot timer so we get here again
+ m_animationTimer.startOneShot(timeToNextService);
+}
+
+void CSSAnimationControllerPrivate::updateStyleIfNeededDispatcherFired()
+{
+ fireEventsAndUpdateStyle();
+}
+
+void CSSAnimationControllerPrivate::fireEventsAndUpdateStyle()
+{
+ // Protect the frame from getting destroyed in the event handler
+ Ref<Frame> protector(m_frame);
+
+ bool updateStyle = !m_eventsToDispatch.isEmpty() || !m_elementChangesToDispatch.isEmpty();
+
+ // fire all the events
+ Vector<EventToDispatch> eventsToDispatch = WTFMove(m_eventsToDispatch);
+ for (auto& event : eventsToDispatch) {
+ Element& element = event.element;
+ if (event.eventType == eventNames().transitionendEvent)
+ element.dispatchEvent(TransitionEvent::create(event.eventType, event.name, event.elapsedTime, PseudoElement::pseudoElementNameForEvents(element.pseudoId())));
+ else
+ element.dispatchEvent(AnimationEvent::create(event.eventType, event.name, event.elapsedTime));
+ }
+
+ for (auto& change : m_elementChangesToDispatch)
+ change->invalidateStyleAndLayerComposition();
+
+ m_elementChangesToDispatch.clear();
+
+ if (updateStyle)
+ m_frame.document()->updateStyleIfNeeded();
+}
+
+void CSSAnimationControllerPrivate::startUpdateStyleIfNeededDispatcher()
+{
+ if (!m_updateStyleIfNeededDispatcher.isActive())
+ m_updateStyleIfNeededDispatcher.startOneShot(0);
+}
+
+void CSSAnimationControllerPrivate::addEventToDispatch(Element& element, const AtomicString& eventType, const String& name, double elapsedTime)
+{
+ m_eventsToDispatch.append({ element, eventType, name, elapsedTime });
+ startUpdateStyleIfNeededDispatcher();
+}
+
+void CSSAnimationControllerPrivate::addElementChangeToDispatch(Element& element)
+{
+ m_elementChangesToDispatch.append(element);
+ ASSERT(m_elementChangesToDispatch.last()->document().pageCacheState() == Document::NotInPageCache);
+ startUpdateStyleIfNeededDispatcher();
+}
+
+void CSSAnimationControllerPrivate::animationFrameCallbackFired()
+{
+ double timeToNextService = updateAnimations(CallSetChanged);
+
+ if (timeToNextService >= 0)
+ m_frame.document()->view()->scheduleAnimation();
+}
+
+void CSSAnimationControllerPrivate::animationTimerFired()
+{
+ // We need to keep the frame alive, since it owns us.
+ Ref<Frame> protector(m_frame);
+
+ // The animation timer might fire before the layout timer, in
+ // which case we might create some animations with incorrect
+ // values if we don't layout first.
+ if (m_requiresLayout) {
+ if (auto* frameView = m_frame.document()->view()) {
+ if (frameView->needsLayout())
+ frameView->forceLayout();
+ }
+ m_requiresLayout = false;
+ }
+
+ // Make sure animationUpdateTime is updated, so that it is current even if no
+ // styleChange has happened (e.g. accelerated animations)
+ AnimationPrivateUpdateBlock updateBlock(*this);
+
+ // When the timer fires, all we do is call setChanged on all DOM nodes with running animations and then do an immediate
+ // updateStyleIfNeeded. It will then call back to us with new information.
+ updateAnimationTimer(CallSetChanged);
+
+ // Fire events right away, to avoid a flash of unanimated style after an animation completes, and before
+ // the 'end' event fires.
+ fireEventsAndUpdateStyle();
+}
+
+bool CSSAnimationControllerPrivate::isRunningAnimationOnRenderer(RenderElement& renderer, CSSPropertyID property, AnimationBase::RunningState runningState) const
+{
+ ASSERT(renderer.isCSSAnimating());
+ ASSERT(m_compositeAnimations.contains(&renderer));
+ const CompositeAnimation& animation = *m_compositeAnimations.get(&renderer);
+ return animation.isAnimatingProperty(property, false, runningState);
+}
+
+bool CSSAnimationControllerPrivate::isRunningAcceleratedAnimationOnRenderer(RenderElement& renderer, CSSPropertyID property, AnimationBase::RunningState runningState) const
+{
+ ASSERT(renderer.isCSSAnimating());
+ ASSERT(m_compositeAnimations.contains(&renderer));
+ const CompositeAnimation& animation = *m_compositeAnimations.get(&renderer);
+ return animation.isAnimatingProperty(property, true, runningState);
+}
+
+void CSSAnimationControllerPrivate::suspendAnimations()
+{
+ if (isSuspended())
+ return;
+
+ suspendAnimationsForDocument(m_frame.document());
+
+ // Traverse subframes
+ for (Frame* child = m_frame.tree().firstChild(); child; child = child->tree().nextSibling())
+ child->animation().suspendAnimations();
+
+ m_isSuspended = true;
+}
+
+void CSSAnimationControllerPrivate::resumeAnimations()
+{
+ if (!isSuspended())
+ return;
+
+ resumeAnimationsForDocument(m_frame.document());
+
+ // Traverse subframes
+ for (Frame* child = m_frame.tree().firstChild(); child; child = child->tree().nextSibling())
+ child->animation().resumeAnimations();
+
+ m_isSuspended = false;
+}
+
+bool CSSAnimationControllerPrivate::animationsAreSuspendedForDocument(Document* document)
+{
+ return isSuspended() || m_suspendedDocuments.contains(document);
+}
+
+void CSSAnimationControllerPrivate::detachFromDocument(Document* document)
+{
+ m_suspendedDocuments.remove(document);
+}
+
+void CSSAnimationControllerPrivate::suspendAnimationsForDocument(Document* document)
+{
+ if (animationsAreSuspendedForDocument(document))
+ return;
+
+ m_suspendedDocuments.add(document);
+
+ AnimationPrivateUpdateBlock updateBlock(*this);
+
+ for (auto& animation : m_compositeAnimations) {
+ if (&animation.key->document() == document)
+ animation.value->suspendAnimations();
+ }
+
+ updateAnimationTimer();
+}
+
+void CSSAnimationControllerPrivate::resumeAnimationsForDocument(Document* document)
+{
+ if (!animationsAreSuspendedForDocument(document))
+ return;
+
+ detachFromDocument(document);
+
+ AnimationPrivateUpdateBlock updateBlock(*this);
+
+ for (auto& animation : m_compositeAnimations) {
+ if (&animation.key->document() == document)
+ animation.value->resumeAnimations();
+ }
+
+ updateAnimationTimer();
+}
+
+void CSSAnimationControllerPrivate::startAnimationsIfNotSuspended(Document* document)
+{
+ if (!animationsAreSuspendedForDocument(document) || allowsNewAnimationsWhileSuspended())
+ resumeAnimationsForDocument(document);
+}
+
+void CSSAnimationControllerPrivate::setAllowsNewAnimationsWhileSuspended(bool allowed)
+{
+ m_allowsNewAnimationsWhileSuspended = allowed;
+}
+
+bool CSSAnimationControllerPrivate::pauseAnimationAtTime(RenderElement* renderer, const AtomicString& name, double t)
+{
+ if (!renderer)
+ return false;
+
+ CompositeAnimation& compositeAnimation = ensureCompositeAnimation(*renderer);
+ if (compositeAnimation.pauseAnimationAtTime(name, t)) {
+ renderer->element()->invalidateStyleAndLayerComposition();
+ startUpdateStyleIfNeededDispatcher();
+ return true;
+ }
+
+ return false;
+}
+
+bool CSSAnimationControllerPrivate::pauseTransitionAtTime(RenderElement* renderer, const String& property, double t)
+{
+ if (!renderer)
+ return false;
+
+ CompositeAnimation& compositeAnimation = ensureCompositeAnimation(*renderer);
+ if (compositeAnimation.pauseTransitionAtTime(cssPropertyID(property), t)) {
+ renderer->element()->invalidateStyleAndLayerComposition();
+ startUpdateStyleIfNeededDispatcher();
+ return true;
+ }
+
+ return false;
+}
+
+double CSSAnimationControllerPrivate::beginAnimationUpdateTime()
+{
+ ASSERT(m_beginAnimationUpdateCount);
+ if (m_beginAnimationUpdateTime == cBeginAnimationUpdateTimeNotSet)
+ m_beginAnimationUpdateTime = monotonicallyIncreasingTime();
+
+ return m_beginAnimationUpdateTime;
+}
+
+void CSSAnimationControllerPrivate::beginAnimationUpdate()
+{
+ if (!m_beginAnimationUpdateCount)
+ setBeginAnimationUpdateTime(cBeginAnimationUpdateTimeNotSet);
+ ++m_beginAnimationUpdateCount;
+}
+
+void CSSAnimationControllerPrivate::endAnimationUpdate()
+{
+ ASSERT(m_beginAnimationUpdateCount > 0);
+ if (m_beginAnimationUpdateCount == 1) {
+ styleAvailable();
+ if (!m_waitingForAsyncStartNotification)
+ startTimeResponse(beginAnimationUpdateTime());
+ }
+ --m_beginAnimationUpdateCount;
+}
+
+void CSSAnimationControllerPrivate::receivedStartTimeResponse(double time)
+{
+ LOG(Animations, "CSSAnimationControllerPrivate %p receivedStartTimeResponse %f", this, time);
+
+ m_waitingForAsyncStartNotification = false;
+ startTimeResponse(time);
+}
+
+std::unique_ptr<RenderStyle> CSSAnimationControllerPrivate::getAnimatedStyleForRenderer(RenderElement& renderer)
+{
+ AnimationPrivateUpdateBlock animationUpdateBlock(*this);
+
+ ASSERT(renderer.isCSSAnimating());
+ ASSERT(m_compositeAnimations.contains(&renderer));
+ const CompositeAnimation& rendererAnimations = *m_compositeAnimations.get(&renderer);
+ std::unique_ptr<RenderStyle> animatingStyle = rendererAnimations.getAnimatedStyle();
+ if (!animatingStyle)
+ animatingStyle = RenderStyle::clonePtr(renderer.style());
+
+ return animatingStyle;
+}
+
+bool CSSAnimationControllerPrivate::computeExtentOfAnimation(RenderElement& renderer, LayoutRect& bounds) const
+{
+ ASSERT(renderer.isCSSAnimating());
+ ASSERT(m_compositeAnimations.contains(&renderer));
+
+ const CompositeAnimation& rendererAnimations = *m_compositeAnimations.get(&renderer);
+ if (!rendererAnimations.isAnimatingProperty(CSSPropertyTransform, false, AnimationBase::Running | AnimationBase::Paused))
+ return true;
+
+ return rendererAnimations.computeExtentOfTransformAnimation(bounds);
+}
+
+unsigned CSSAnimationControllerPrivate::numberOfActiveAnimations(Document* document) const
+{
+ unsigned count = 0;
+
+ for (auto& animation : m_compositeAnimations) {
+ if (&animation.key->document() == document)
+ count += animation.value->numberOfActiveAnimations();
+ }
+
+ return count;
+}
+
+void CSSAnimationControllerPrivate::addToAnimationsWaitingForStyle(AnimationBase* animation)
+{
+ // Make sure this animation is not in the start time waiters
+ m_animationsWaitingForStartTimeResponse.remove(animation);
+
+ m_animationsWaitingForStyle.add(animation);
+}
+
+void CSSAnimationControllerPrivate::removeFromAnimationsWaitingForStyle(AnimationBase* animationToRemove)
+{
+ m_animationsWaitingForStyle.remove(animationToRemove);
+}
+
+void CSSAnimationControllerPrivate::styleAvailable()
+{
+ // Go through list of waiters and send them on their way
+ for (const auto& waitingAnimation : m_animationsWaitingForStyle)
+ waitingAnimation->styleAvailable();
+
+ m_animationsWaitingForStyle.clear();
+}
+
+void CSSAnimationControllerPrivate::addToAnimationsWaitingForStartTimeResponse(AnimationBase* animation, bool willGetResponse)
+{
+ // If willGetResponse is true, it means this animation is actually waiting for a response
+ // (which will come in as a call to notifyAnimationStarted()).
+ // In that case we don't need to add it to this list. We just set a waitingForAResponse flag
+ // which says we are waiting for the response. If willGetResponse is false, this animation
+ // is not waiting for a response for itself, but rather for a notifyXXXStarted() call for
+ // another animation to which it will sync.
+ //
+ // When endAnimationUpdate() is called we check to see if the waitingForAResponse flag is
+ // true. If so, we just return and will do our work when the first notifyXXXStarted() call
+ // comes in. If it is false, we will not be getting a notifyXXXStarted() call, so we will
+ // do our work right away. In both cases we call the onAnimationStartResponse() method
+ // on each animation. In the first case we send in the time we got from notifyXXXStarted().
+ // In the second case, we just pass in the beginAnimationUpdateTime().
+ //
+ // This will synchronize all software and accelerated animations started in the same
+ // updateStyleIfNeeded cycle.
+ //
+
+ if (willGetResponse)
+ m_waitingForAsyncStartNotification = true;
+
+ m_animationsWaitingForStartTimeResponse.add(animation);
+}
+
+void CSSAnimationControllerPrivate::removeFromAnimationsWaitingForStartTimeResponse(AnimationBase* animationToRemove)
+{
+ m_animationsWaitingForStartTimeResponse.remove(animationToRemove);
+
+ if (m_animationsWaitingForStartTimeResponse.isEmpty())
+ m_waitingForAsyncStartNotification = false;
+}
+
+void CSSAnimationControllerPrivate::startTimeResponse(double time)
+{
+ // Go through list of waiters and send them on their way
+
+ for (const auto& animation : m_animationsWaitingForStartTimeResponse)
+ animation->onAnimationStartResponse(time);
+
+ m_animationsWaitingForStartTimeResponse.clear();
+ m_waitingForAsyncStartNotification = false;
+}
+
+void CSSAnimationControllerPrivate::animationWillBeRemoved(AnimationBase* animation)
+{
+ LOG(Animations, "CSSAnimationControllerPrivate %p animationWillBeRemoved: %p", this, animation);
+
+ removeFromAnimationsWaitingForStyle(animation);
+ removeFromAnimationsWaitingForStartTimeResponse(animation);
+#if ENABLE(CSS_ANIMATIONS_LEVEL_2)
+ removeFromAnimationsDependentOnScroll(animation);
+#endif
+
+ bool anyAnimationsWaitingForAsyncStart = false;
+ for (auto& animation : m_animationsWaitingForStartTimeResponse) {
+ if (animation->waitingForStartTime() && animation->isAccelerated()) {
+ anyAnimationsWaitingForAsyncStart = true;
+ break;
+ }
+ }
+
+ if (!anyAnimationsWaitingForAsyncStart)
+ m_waitingForAsyncStartNotification = false;
+}
+
+#if ENABLE(CSS_ANIMATIONS_LEVEL_2)
+void CSSAnimationControllerPrivate::addToAnimationsDependentOnScroll(AnimationBase* animation)
+{
+ m_animationsDependentOnScroll.add(animation);
+}
+
+void CSSAnimationControllerPrivate::removeFromAnimationsDependentOnScroll(AnimationBase* animation)
+{
+ m_animationsDependentOnScroll.remove(animation);
+}
+
+void CSSAnimationControllerPrivate::scrollWasUpdated()
+{
+ auto* view = m_frame.view();
+ if (!view || !wantsScrollUpdates())
+ return;
+
+ m_scrollPosition = view->scrollPositionForFixedPosition().y().toFloat();
+
+ // FIXME: This is updating all the animations, rather than just the ones
+ // that are dependent on scroll. We to go from our AnimationBase to its CompositeAnimation
+ // so we can execute code similar to updateAnimations.
+ // https://bugs.webkit.org/show_bug.cgi?id=144170
+ updateAnimations(CallSetChanged);
+}
+#endif
+
+CSSAnimationController::CSSAnimationController(Frame& frame)
+ : m_data(std::make_unique<CSSAnimationControllerPrivate>(frame))
+{
+}
+
+CSSAnimationController::~CSSAnimationController()
+{
+}
+
+void CSSAnimationController::cancelAnimations(RenderElement& renderer)
+{
+ if (!renderer.isCSSAnimating())
+ return;
+
+ if (!m_data->clear(renderer))
+ return;
+
+ Element* element = renderer.element();
+ if (!element || element->document().renderTreeBeingDestroyed())
+ return;
+ ASSERT(element->document().pageCacheState() == Document::NotInPageCache);
+ element->invalidateStyleAndLayerComposition();
+}
+
+bool CSSAnimationController::updateAnimations(RenderElement& renderer, const RenderStyle& newStyle, std::unique_ptr<RenderStyle>& animatedStyle)
+{
+ auto* oldStyle = renderer.hasInitializedStyle() ? &renderer.style() : nullptr;
+ if ((!oldStyle || (!oldStyle->animations() && !oldStyle->transitions())) && (!newStyle.animations() && !newStyle.transitions()))
+ return false;
+
+ if (renderer.document().pageCacheState() != Document::NotInPageCache)
+ return false;
+
+ // Don't run transitions when printing.
+ if (renderer.view().printing())
+ return false;
+
+ // Fetch our current set of implicit animations from a hashtable. We then compare them
+ // against the animations in the style and make sure we're in sync. If destination values
+ // have changed, we reset the animation. We then do a blend to get new values and we return
+ // a new style.
+
+ // We don't support anonymous pseudo elements like :first-line or :first-letter.
+ ASSERT(renderer.element());
+
+ CompositeAnimation& rendererAnimations = m_data->ensureCompositeAnimation(renderer);
+ bool animationStateChanged = rendererAnimations.animate(renderer, oldStyle, newStyle, animatedStyle);
+
+ if (renderer.parent() || newStyle.animations() || (oldStyle && oldStyle->animations())) {
+ auto& frameView = renderer.view().frameView();
+ if (rendererAnimations.hasAnimationThatDependsOnLayout())
+ m_data->setRequiresLayout();
+ m_data->updateAnimationTimerForRenderer(renderer);
+ frameView.scheduleAnimation();
+ }
+
+ return animationStateChanged;
+}
+
+std::unique_ptr<RenderStyle> CSSAnimationController::getAnimatedStyleForRenderer(RenderElement& renderer)
+{
+ if (!renderer.isCSSAnimating())
+ return RenderStyle::clonePtr(renderer.style());
+ return m_data->getAnimatedStyleForRenderer(renderer);
+}
+
+bool CSSAnimationController::computeExtentOfAnimation(RenderElement& renderer, LayoutRect& bounds) const
+{
+ if (!renderer.isCSSAnimating())
+ return true;
+
+ return m_data->computeExtentOfAnimation(renderer, bounds);
+}
+
+void CSSAnimationController::notifyAnimationStarted(RenderElement& renderer, double startTime)
+{
+ LOG(Animations, "CSSAnimationController %p notifyAnimationStarted on renderer %p, time=%f", this, &renderer, startTime);
+ UNUSED_PARAM(renderer);
+
+ AnimationUpdateBlock animationUpdateBlock(this);
+ m_data->receivedStartTimeResponse(startTime);
+}
+
+bool CSSAnimationController::pauseAnimationAtTime(RenderElement* renderer, const AtomicString& name, double t)
+{
+ AnimationUpdateBlock animationUpdateBlock(this);
+ return m_data->pauseAnimationAtTime(renderer, name, t);
+}
+
+unsigned CSSAnimationController::numberOfActiveAnimations(Document* document) const
+{
+ return m_data->numberOfActiveAnimations(document);
+}
+
+bool CSSAnimationController::pauseTransitionAtTime(RenderElement* renderer, const String& property, double t)
+{
+ AnimationUpdateBlock animationUpdateBlock(this);
+ return m_data->pauseTransitionAtTime(renderer, property, t);
+}
+
+bool CSSAnimationController::isRunningAnimationOnRenderer(RenderElement& renderer, CSSPropertyID property, AnimationBase::RunningState runningState) const
+{
+ return renderer.isCSSAnimating() && m_data->isRunningAnimationOnRenderer(renderer, property, runningState);
+}
+
+bool CSSAnimationController::isRunningAcceleratedAnimationOnRenderer(RenderElement& renderer, CSSPropertyID property, AnimationBase::RunningState runningState) const
+{
+ return renderer.isCSSAnimating() && m_data->isRunningAcceleratedAnimationOnRenderer(renderer, property, runningState);
+}
+
+bool CSSAnimationController::isSuspended() const
+{
+ return m_data->isSuspended();
+}
+
+void CSSAnimationController::suspendAnimations()
+{
+ LOG(Animations, "controller is suspending animations");
+ m_data->suspendAnimations();
+}
+
+void CSSAnimationController::resumeAnimations()
+{
+ LOG(Animations, "controller is resuming animations");
+ m_data->resumeAnimations();
+}
+
+bool CSSAnimationController::allowsNewAnimationsWhileSuspended() const
+{
+ return m_data->allowsNewAnimationsWhileSuspended();
+}
+
+void CSSAnimationController::setAllowsNewAnimationsWhileSuspended(bool allowed)
+{
+ m_data->setAllowsNewAnimationsWhileSuspended(allowed);
+}
+
+void CSSAnimationController::serviceAnimations()
+{
+ m_data->animationFrameCallbackFired();
+}
+
+bool CSSAnimationController::animationsAreSuspendedForDocument(Document* document)
+{
+ return m_data->animationsAreSuspendedForDocument(document);
+}
+
+void CSSAnimationController::detachFromDocument(Document* document)
+{
+ return m_data->detachFromDocument(document);
+}
+
+void CSSAnimationController::suspendAnimationsForDocument(Document* document)
+{
+ LOG(Animations, "suspending animations for document %p", document);
+ m_data->suspendAnimationsForDocument(document);
+}
+
+void CSSAnimationController::resumeAnimationsForDocument(Document* document)
+{
+ LOG(Animations, "resuming animations for document %p", document);
+ AnimationUpdateBlock animationUpdateBlock(this);
+ m_data->resumeAnimationsForDocument(document);
+}
+
+void CSSAnimationController::startAnimationsIfNotSuspended(Document* document)
+{
+ LOG(Animations, "animations may start for document %p", document);
+
+ AnimationUpdateBlock animationUpdateBlock(this);
+ m_data->startAnimationsIfNotSuspended(document);
+}
+
+void CSSAnimationController::beginAnimationUpdate()
+{
+ m_data->beginAnimationUpdate();
+}
+
+void CSSAnimationController::endAnimationUpdate()
+{
+ m_data->endAnimationUpdate();
+}
+
+bool CSSAnimationController::supportsAcceleratedAnimationOfProperty(CSSPropertyID property)
+{
+ return CSSPropertyAnimation::animationOfPropertyIsAccelerated(property);
+}
+
+#if ENABLE(CSS_ANIMATIONS_LEVEL_2)
+bool CSSAnimationController::wantsScrollUpdates() const
+{
+ return m_data->wantsScrollUpdates();
+}
+
+void CSSAnimationController::scrollWasUpdated()
+{
+ m_data->scrollWasUpdated();
+}
+#endif
+
+bool CSSAnimationController::hasAnimations() const
+{
+ return m_data->hasAnimations();
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/page/animation/AnimationController.h b/Source/WebCore/page/animation/CSSAnimationController.h
index c29af5d82..d473cd173 100644
--- a/Source/WebCore/page/animation/AnimationController.h
+++ b/Source/WebCore/page/animation/CSSAnimationController.h
@@ -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.
*
@@ -26,69 +26,80 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef AnimationController_h
-#define AnimationController_h
+#pragma once
+#include "AnimationBase.h"
#include "CSSPropertyNames.h"
#include <wtf/Forward.h>
-#include <wtf/OwnPtr.h>
namespace WebCore {
-class AnimationBase;
-class AnimationControllerPrivate;
+class CSSAnimationControllerPrivate;
class Document;
class Element;
class Frame;
+class LayoutRect;
class RenderElement;
class RenderStyle;
-class AnimationController {
+class CSSAnimationController {
+ WTF_MAKE_FAST_ALLOCATED;
public:
- explicit AnimationController(Frame&);
- ~AnimationController();
+ explicit CSSAnimationController(Frame&);
+ ~CSSAnimationController();
- void cancelAnimations(RenderElement*);
- PassRef<RenderStyle> updateAnimations(RenderElement&, PassRef<RenderStyle> newStyle);
- PassRefPtr<RenderStyle> getAnimatedStyleForRenderer(RenderElement*);
+ void cancelAnimations(RenderElement&);
+ bool updateAnimations(RenderElement&, const RenderStyle& newStyle, std::unique_ptr<RenderStyle>& animatedStyle);
+ std::unique_ptr<RenderStyle> getAnimatedStyleForRenderer(RenderElement&);
+
+ // If possible, compute the visual extent of any transform animation on the given renderer
+ // using the given rect, returning the result in the rect. Return false if there is some
+ // transform animation but we were unable to cheaply compute its affect on the extent.
+ bool computeExtentOfAnimation(RenderElement&, LayoutRect&) const;
// This is called when an accelerated animation or transition has actually started to animate.
- void notifyAnimationStarted(RenderElement*, double startTime);
+ void notifyAnimationStarted(RenderElement&, double startTime);
- bool pauseAnimationAtTime(RenderElement*, const AtomicString& name, double t); // To be used only for testing
- bool pauseTransitionAtTime(RenderElement*, const String& property, double t); // To be used only for testing
- unsigned numberOfActiveAnimations(Document*) const; // To be used only for testing
+ WEBCORE_EXPORT bool pauseAnimationAtTime(RenderElement*, const AtomicString& name, double t); // To be used only for testing
+ WEBCORE_EXPORT bool pauseTransitionAtTime(RenderElement*, const String& property, double t); // To be used only for testing
+ WEBCORE_EXPORT unsigned numberOfActiveAnimations(Document*) const; // To be used only for testing
- bool isRunningAnimationOnRenderer(RenderElement*, CSSPropertyID, bool isRunningNow = true) const;
- bool isRunningAcceleratedAnimationOnRenderer(RenderElement*, CSSPropertyID, bool isRunningNow = true) const;
+ bool isRunningAnimationOnRenderer(RenderElement&, CSSPropertyID, AnimationBase::RunningState) const;
+ bool isRunningAcceleratedAnimationOnRenderer(RenderElement&, CSSPropertyID, AnimationBase::RunningState) const;
- bool isSuspended() const;
- void suspendAnimations();
- void resumeAnimations();
-#if ENABLE(REQUEST_ANIMATION_FRAME)
+ WEBCORE_EXPORT bool isSuspended() const;
+ WEBCORE_EXPORT void suspendAnimations();
+ WEBCORE_EXPORT void resumeAnimations();
void serviceAnimations();
-#endif
- void suspendAnimationsForDocument(Document*);
- void resumeAnimationsForDocument(Document*);
+ WEBCORE_EXPORT void suspendAnimationsForDocument(Document*);
+ WEBCORE_EXPORT void resumeAnimationsForDocument(Document*);
+ WEBCORE_EXPORT bool animationsAreSuspendedForDocument(Document*);
+ void detachFromDocument(Document*);
void startAnimationsIfNotSuspended(Document*);
void beginAnimationUpdate();
void endAnimationUpdate();
- bool allowsNewAnimationsWhileSuspended() const;
- void setAllowsNewAnimationsWhileSuspended(bool);
+ WEBCORE_EXPORT bool allowsNewAnimationsWhileSuspended() const;
+ WEBCORE_EXPORT void setAllowsNewAnimationsWhileSuspended(bool);
static bool supportsAcceleratedAnimationOfProperty(CSSPropertyID);
+#if ENABLE(CSS_ANIMATIONS_LEVEL_2)
+ bool wantsScrollUpdates() const;
+ void scrollWasUpdated();
+#endif
+
+ bool hasAnimations() const;
+
private:
- const std::unique_ptr<AnimationControllerPrivate> m_data;
- int m_beginAnimationUpdateCount;
+ const std::unique_ptr<CSSAnimationControllerPrivate> m_data;
};
class AnimationUpdateBlock {
public:
- AnimationUpdateBlock(AnimationController* animationController)
+ AnimationUpdateBlock(CSSAnimationController* animationController)
: m_animationController(animationController)
{
if (m_animationController)
@@ -101,9 +112,7 @@ public:
m_animationController->endAnimationUpdate();
}
- AnimationController* m_animationController;
+ CSSAnimationController* m_animationController;
};
} // namespace WebCore
-
-#endif // AnimationController_h
diff --git a/Source/WebCore/page/animation/AnimationControllerPrivate.h b/Source/WebCore/page/animation/CSSAnimationControllerPrivate.h
index f03092280..c4996c331 100644
--- a/Source/WebCore/page/animation/AnimationControllerPrivate.h
+++ b/Source/WebCore/page/animation/CSSAnimationControllerPrivate.h
@@ -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.
*
@@ -26,76 +26,68 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef AnimationControllerPrivate_h
-#define AnimationControllerPrivate_h
+#pragma once
-#include "CSSPropertyNames.h"
+#include "AnimationBase.h"
#include "Timer.h"
#include <wtf/HashMap.h>
#include <wtf/HashSet.h>
-#include <wtf/PassRefPtr.h>
-#include <wtf/RefPtr.h>
#include <wtf/Vector.h>
-#include <wtf/text/AtomicString.h>
-#include <wtf/text/WTFString.h>
namespace WebCore {
-class AnimationBase;
class CompositeAnimation;
class Document;
-class Element;
class Frame;
-class RenderElement;
-class RenderStyle;
-enum SetChanged {
- DoNotCallSetChanged = 0,
- CallSetChanged = 1
-};
+enum SetChanged { DoNotCallSetChanged, CallSetChanged };
-class AnimationControllerPrivate {
- WTF_MAKE_NONCOPYABLE(AnimationControllerPrivate); WTF_MAKE_FAST_ALLOCATED;
+class CSSAnimationControllerPrivate {
+ WTF_MAKE_FAST_ALLOCATED;
public:
- explicit AnimationControllerPrivate(Frame&);
- ~AnimationControllerPrivate();
+ explicit CSSAnimationControllerPrivate(Frame&);
+ ~CSSAnimationControllerPrivate();
// Returns the time until the next animation needs to be serviced, or -1 if there are none.
double updateAnimations(SetChanged callSetChanged = DoNotCallSetChanged);
void updateAnimationTimer(SetChanged callSetChanged = DoNotCallSetChanged);
- CompositeAnimation& ensureCompositeAnimation(RenderElement*);
- bool clear(RenderElement*);
+ CompositeAnimation& ensureCompositeAnimation(RenderElement&);
+ bool clear(RenderElement&);
- void updateStyleIfNeededDispatcherFired(Timer<AnimationControllerPrivate>&);
+ void updateStyleIfNeededDispatcherFired();
void startUpdateStyleIfNeededDispatcher();
- void addEventToDispatch(PassRefPtr<Element> element, const AtomicString& eventType, const String& name, double elapsedTime);
- void addElementChangeToDispatch(PassRef<Element>);
+ void addEventToDispatch(Element&, const AtomicString& eventType, const String& name, double elapsedTime);
+ void addElementChangeToDispatch(Element&);
bool hasAnimations() const { return !m_compositeAnimations.isEmpty(); }
bool isSuspended() const { return m_isSuspended; }
void suspendAnimations();
void resumeAnimations();
-#if ENABLE(REQUEST_ANIMATION_FRAME)
void animationFrameCallbackFired();
-#endif
void suspendAnimationsForDocument(Document*);
void resumeAnimationsForDocument(Document*);
+ bool animationsAreSuspendedForDocument(Document*);
void startAnimationsIfNotSuspended(Document*);
+ void detachFromDocument(Document*);
- bool isRunningAnimationOnRenderer(RenderElement*, CSSPropertyID, bool isRunningNow) const;
- bool isRunningAcceleratedAnimationOnRenderer(RenderElement*, CSSPropertyID, bool isRunningNow) const;
+ bool isRunningAnimationOnRenderer(RenderElement&, CSSPropertyID, AnimationBase::RunningState) const;
+ bool isRunningAcceleratedAnimationOnRenderer(RenderElement&, CSSPropertyID, AnimationBase::RunningState) const;
bool pauseAnimationAtTime(RenderElement*, const AtomicString& name, double t);
bool pauseTransitionAtTime(RenderElement*, const String& property, double t);
unsigned numberOfActiveAnimations(Document*) const;
- PassRefPtr<RenderStyle> getAnimatedStyleForRenderer(RenderElement* renderer);
+ std::unique_ptr<RenderStyle> getAnimatedStyleForRenderer(RenderElement&);
+
+ bool computeExtentOfAnimation(RenderElement&, LayoutRect&) const;
double beginAnimationUpdateTime();
void setBeginAnimationUpdateTime(double t) { m_beginAnimationUpdateTime = t; }
+
+ void beginAnimationUpdate();
void endAnimationUpdate();
void receivedStartTimeResponse(double);
@@ -107,48 +99,65 @@ public:
void animationWillBeRemoved(AnimationBase*);
- void updateAnimationTimerForRenderer(RenderElement*);
+ void updateAnimationTimerForRenderer(RenderElement&);
bool allowsNewAnimationsWhileSuspended() const { return m_allowsNewAnimationsWhileSuspended; }
void setAllowsNewAnimationsWhileSuspended(bool);
+ void setRequiresLayout() { m_requiresLayout = true; }
+
+#if ENABLE(CSS_ANIMATIONS_LEVEL_2)
+ bool wantsScrollUpdates() const { return !m_animationsDependentOnScroll.isEmpty(); }
+ void addToAnimationsDependentOnScroll(AnimationBase*);
+ void removeFromAnimationsDependentOnScroll(AnimationBase*);
+
+ void scrollWasUpdated();
+ float scrollPosition() const { return m_scrollPosition; }
+#endif
+
private:
- void animationTimerFired(Timer<AnimationControllerPrivate>&);
+ void animationTimerFired();
void styleAvailable();
void fireEventsAndUpdateStyle();
void startTimeResponse(double t);
HashMap<RenderElement*, RefPtr<CompositeAnimation>> m_compositeAnimations;
- Timer<AnimationControllerPrivate> m_animationTimer;
- Timer<AnimationControllerPrivate> m_updateStyleIfNeededDispatcher;
+ Timer m_animationTimer;
+ Timer m_updateStyleIfNeededDispatcher;
Frame& m_frame;
-
- class EventToDispatch {
- public:
- RefPtr<Element> element;
+
+ struct EventToDispatch {
+ Ref<Element> element;
AtomicString eventType;
String name;
double elapsedTime;
};
-
Vector<EventToDispatch> m_eventsToDispatch;
Vector<Ref<Element>> m_elementChangesToDispatch;
-
+ HashSet<Document*> m_suspendedDocuments;
+
double m_beginAnimationUpdateTime;
- typedef HashSet<RefPtr<AnimationBase>> WaitingAnimationsSet;
- WaitingAnimationsSet m_animationsWaitingForStyle;
- WaitingAnimationsSet m_animationsWaitingForStartTimeResponse;
+ using AnimationsSet = HashSet<RefPtr<AnimationBase>>;
+ AnimationsSet m_animationsWaitingForStyle;
+ AnimationsSet m_animationsWaitingForStartTimeResponse;
+
+ int m_beginAnimationUpdateCount;
+
bool m_waitingForAsyncStartNotification;
bool m_isSuspended;
+ bool m_requiresLayout { false };
// Used to flag whether we should revert to previous buggy
// behavior of allowing new transitions and animations to
// run even when this object is suspended.
bool m_allowsNewAnimationsWhileSuspended;
+
+#if ENABLE(CSS_ANIMATIONS_LEVEL_2)
+ AnimationsSet m_animationsDependentOnScroll;
+ float m_scrollPosition { 0 };
+#endif
};
} // namespace WebCore
-
-#endif // AnimationControllerPrivate_h
diff --git a/Source/WebCore/page/animation/CSSPropertyAnimation.cpp b/Source/WebCore/page/animation/CSSPropertyAnimation.cpp
index 291129e93..98b87c947 100644
--- a/Source/WebCore/page/animation/CSSPropertyAnimation.cpp
+++ b/Source/WebCore/page/animation/CSSPropertyAnimation.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2007, 2008, 2009, 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 2007, 2008, 2009, 2013, 2016 Apple Inc. All rights reserved.
* Copyright (C) 2012, 2013 Adobe Systems Incorporated. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -11,7 +11,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.
*
@@ -41,7 +41,9 @@
#include "CachedImage.h"
#include "ClipPathOperation.h"
#include "FloatConversion.h"
+#include "FontTaggedSettings.h"
#include "IdentityTransformOperation.h"
+#include "Logging.h"
#include "Matrix3DTransformOperation.h"
#include "MatrixTransformOperation.h"
#include "RenderBox.h"
@@ -50,9 +52,13 @@
#include "StyleGeneratedImage.h"
#include "StylePropertyShorthand.h"
#include "StyleResolver.h"
+#include "TextStream.h"
#include <algorithm>
+#include <memory>
#include <wtf/MathExtras.h>
+#include <wtf/NeverDestroyed.h>
#include <wtf/Noncopyable.h>
+#include <wtf/PointerComparison.h>
#include <wtf/RefCounted.h>
namespace WebCore {
@@ -62,11 +68,6 @@ static inline int blendFunc(const AnimationBase*, int from, int to, double progr
return blend(from, to, progress);
}
-static inline unsigned blendFunc(const AnimationBase*, unsigned from, unsigned to, double progress)
-{
- return blend(from, to, progress);
-}
-
static inline double blendFunc(const AnimationBase*, double from, double to, double progress)
{
return blend(from, to, progress);
@@ -84,13 +85,12 @@ static inline Color blendFunc(const AnimationBase*, const Color& from, const Col
static inline Length blendFunc(const AnimationBase*, const Length& from, const Length& to, double progress)
{
- return to.blend(from, narrowPrecisionToFloat(progress));
+ return blend(from, to, progress);
}
static inline LengthSize blendFunc(const AnimationBase* anim, const LengthSize& from, const LengthSize& to, double progress)
{
- return LengthSize(blendFunc(anim, from.width(), to.width(), progress),
- blendFunc(anim, from.height(), to.height(), progress));
+ return { blendFunc(anim, from.width, to.width, progress), blendFunc(anim, from.height, to.height, progress) };
}
static inline ShadowStyle blendFunc(const AnimationBase* anim, ShadowStyle from, ShadowStyle to, double progress)
@@ -104,28 +104,28 @@ static inline ShadowStyle blendFunc(const AnimationBase* anim, ShadowStyle from,
return result > 0 ? Normal : Inset;
}
-static inline PassOwnPtr<ShadowData> blendFunc(const AnimationBase* anim, const ShadowData* from, const ShadowData* to, double progress)
+static inline std::unique_ptr<ShadowData> blendFunc(const AnimationBase* anim, const ShadowData* from, const ShadowData* to, double progress)
{
ASSERT(from && to);
if (from->style() != to->style())
- return adoptPtr(new ShadowData(*to));
-
- return adoptPtr(new ShadowData(blend(from->location(), to->location(), progress),
- blend(from->radius(), to->radius(), progress),
- blend(from->spread(), to->spread(), progress),
- blendFunc(anim, from->style(), to->style(), progress),
- from->isWebkitBoxShadow(),
- blend(from->color(), to->color(), progress)));
+ return std::make_unique<ShadowData>(*to);
+
+ return std::make_unique<ShadowData>(blend(from->location(), to->location(), progress),
+ blend(from->radius(), to->radius(), progress),
+ blend(from->spread(), to->spread(), progress),
+ blendFunc(anim, from->style(), to->style(), progress),
+ from->isWebkitBoxShadow(),
+ blend(from->color(), to->color(), progress));
}
-static inline TransformOperations blendFunc(const AnimationBase* anim, const TransformOperations& from, const TransformOperations& to, double progress)
+static inline TransformOperations blendFunc(const AnimationBase* animation, const TransformOperations& from, const TransformOperations& to, double progress)
{
- if (anim->isTransformFunctionListValid())
+ if (animation->transformFunctionListsMatch())
return to.blendByMatchingOperations(from, progress);
- return to.blendByUsingMatrixInterpolation(from, progress, anim->renderer()->isBox() ? toRenderBox(anim->renderer())->borderBoxRect().size() : LayoutSize());
+ return to.blendByUsingMatrixInterpolation(from, progress, is<RenderBox>(*animation->renderer()) ? downcast<RenderBox>(*animation->renderer()).borderBoxRect().size() : LayoutSize());
}
-static inline PassRefPtr<ClipPathOperation> blendFunc(const AnimationBase*, ClipPathOperation* from, ClipPathOperation* to, double progress)
+static inline RefPtr<ClipPathOperation> blendFunc(const AnimationBase*, ClipPathOperation* from, ClipPathOperation* to, double progress)
{
if (!from || !to)
return to;
@@ -134,44 +134,40 @@ static inline PassRefPtr<ClipPathOperation> blendFunc(const AnimationBase*, Clip
if (from->type() != ClipPathOperation::Shape || to->type() != ClipPathOperation::Shape)
return to;
- const BasicShape* fromShape = static_cast<ShapeClipPathOperation*>(from)->basicShape();
- const BasicShape* toShape = static_cast<ShapeClipPathOperation*>(to)->basicShape();
+ const BasicShape& fromShape = downcast<ShapeClipPathOperation>(*from).basicShape();
+ const BasicShape& toShape = downcast<ShapeClipPathOperation>(*to).basicShape();
- if (!fromShape->canBlend(toShape))
+ if (!fromShape.canBlend(toShape))
return to;
- return ShapeClipPathOperation::create(toShape->blend(fromShape, progress));
+ return ShapeClipPathOperation::create(toShape.blend(fromShape, progress));
}
-#if ENABLE(CSS_SHAPES)
-static inline PassRefPtr<ShapeValue> blendFunc(const AnimationBase*, ShapeValue* from, ShapeValue* to, double progress)
+static inline RefPtr<ShapeValue> blendFunc(const AnimationBase*, ShapeValue* from, ShapeValue* to, double progress)
{
if (!from || !to)
return to;
- // FIXME Bug 102723: Shape-inside should be able to animate a value of 'outside-shape' when shape-outside is set to a BasicShape
- if (from->type() != ShapeValue::Shape || to->type() != ShapeValue::Shape)
+ if (from->type() != ShapeValue::Type::Shape || to->type() != ShapeValue::Type::Shape)
return to;
- if (from->layoutBox() != to->layoutBox())
+ if (from->cssBox() != to->cssBox())
return to;
- const BasicShape* fromShape = from->shape();
- const BasicShape* toShape = to->shape();
+ const BasicShape& fromShape = *from->shape();
+ const BasicShape& toShape = *to->shape();
- if (!fromShape->canBlend(toShape))
+ if (!fromShape.canBlend(toShape))
return to;
- return ShapeValue::createShapeValue(toShape->blend(fromShape, progress), to->layoutBox());
+ return ShapeValue::create(toShape.blend(fromShape, progress), to->cssBox());
}
-#endif
-#if ENABLE(CSS_FILTERS)
-static inline PassRefPtr<FilterOperation> blendFunc(const AnimationBase* anim, FilterOperation* fromOp, FilterOperation* toOp, double progress, bool blendToPassthrough = false)
+static inline RefPtr<FilterOperation> blendFunc(const AnimationBase* animation, FilterOperation* fromOp, FilterOperation* toOp, double progress, bool blendToPassthrough = false)
{
ASSERT(toOp);
if (toOp->blendingNeedsRendererSize()) {
- LayoutSize size = anim->renderer()->isBox() ? toRenderBox(anim->renderer())->borderBoxRect().size() : LayoutSize();
+ LayoutSize size = is<RenderBox>(*animation->renderer()) ? downcast<RenderBox>(*animation->renderer()).borderBoxRect().size() : LayoutSize();
return toOp->blend(fromOp, progress, size, blendToPassthrough);
}
return toOp->blend(fromOp, progress, blendToPassthrough);
@@ -200,12 +196,18 @@ static inline FilterOperations blendFilterOperations(const AnimationBase* anim,
return result;
}
-static inline FilterOperations blendFunc(const AnimationBase* anim, const FilterOperations& from, const FilterOperations& to, double progress)
+static inline FilterOperations blendFunc(const AnimationBase* anim, const FilterOperations& from, const FilterOperations& to, double progress, bool animatingBackdropFilter = false)
{
FilterOperations result;
// If we have a filter function list, use that to do a per-function animation.
+#if ENABLE(FILTERS_LEVEL_2)
+ if ((!animatingBackdropFilter && anim->filterFunctionListsMatch()) || (animatingBackdropFilter && anim->backdropFilterFunctionListsMatch()))
+#else
+ UNUSED_PARAM(animatingBackdropFilter);
if (anim->filterFunctionListsMatch())
+#endif
+
result = blendFilterOperations(anim, from, to, progress);
else {
// If the filter function lists don't match, we could try to cross-fade, but don't yet have a way to represent that in CSS.
@@ -216,20 +218,18 @@ static inline FilterOperations blendFunc(const AnimationBase* anim, const Filter
return result;
}
-static inline PassRefPtr<StyleImage> blendFilter(const AnimationBase* anim, CachedImage* image, const FilterOperations& from, const FilterOperations& to, double progress)
+static inline RefPtr<StyleImage> blendFilter(const AnimationBase* anim, CachedImage* image, const FilterOperations& from, const FilterOperations& to, double progress)
{
ASSERT(image);
FilterOperations filterResult = blendFilterOperations(anim, from, to, progress);
- RefPtr<StyleCachedImage> styledImage = StyleCachedImage::create(image);
- auto imageValue = CSSImageValue::create(image->url(), styledImage.get());
- auto filterValue = ComputedStyleExtractor::valueForFilter(&anim->renderer()->style(), filterResult, DoNotAdjustPixelValues);
+ auto imageValue = CSSImageValue::create(*image);
+ auto filterValue = ComputedStyleExtractor::valueForFilter(anim->renderer()->style(), filterResult, DoNotAdjustPixelValues);
- auto result = CSSFilterImageValue::create(std::move(imageValue), std::move(filterValue));
+ auto result = CSSFilterImageValue::create(WTFMove(imageValue), WTFMove(filterValue));
result.get().setFilterOperations(filterResult);
- return StyleGeneratedImage::create(std::move(result));
+ return StyleGeneratedImage::create(WTFMove(result));
}
-#endif // ENABLE(CSS_FILTERS)
static inline EVisibility blendFunc(const AnimationBase* anim, EVisibility from, EVisibility to, double progress)
{
@@ -252,12 +252,12 @@ static inline LengthBox blendFunc(const AnimationBase* anim, const LengthBox& fr
return result;
}
-#if ENABLE(SVG)
-static inline SVGLength blendFunc(const AnimationBase*, const SVGLength& from, const SVGLength& to, double progress)
+static inline SVGLengthValue blendFunc(const AnimationBase*, const SVGLengthValue& from, const SVGLengthValue& to, double progress)
{
return to.blend(from, narrowPrecisionToFloat(progress));
}
-static inline Vector<SVGLength> blendFunc(const AnimationBase*, const Vector<SVGLength>& from, const Vector<SVGLength>& to, double progress)
+
+static inline Vector<SVGLengthValue> blendFunc(const AnimationBase*, const Vector<SVGLengthValue>& from, const Vector<SVGLengthValue>& to, double progress)
{
size_t fromLength = from.size();
size_t toLength = to.size();
@@ -272,14 +272,13 @@ static inline Vector<SVGLength> blendFunc(const AnimationBase*, const Vector<SVG
else
resultLength = fromLength * toLength;
}
- Vector<SVGLength> result(resultLength);
+ Vector<SVGLengthValue> result(resultLength);
for (size_t i = 0; i < resultLength; ++i)
result[i] = to[i % toLength].blend(from[i % fromLength], narrowPrecisionToFloat(progress));
return result;
}
-#endif
-static inline PassRefPtr<StyleImage> crossfadeBlend(const AnimationBase*, StyleCachedImage* fromStyleImage, StyleCachedImage* toStyleImage, double progress)
+static inline RefPtr<StyleImage> crossfadeBlend(const AnimationBase*, StyleCachedImage* fromStyleImage, StyleCachedImage* toStyleImage, double progress)
{
// If progress is at one of the extremes, we want getComputedStyle to show the image,
// not a completed cross-fade, so we hand back one of the existing images.
@@ -287,69 +286,69 @@ static inline PassRefPtr<StyleImage> crossfadeBlend(const AnimationBase*, StyleC
return fromStyleImage;
if (progress == 1)
return toStyleImage;
+ if (!fromStyleImage->cachedImage() || !toStyleImage->cachedImage())
+ return toStyleImage;
- auto fromImageValue = CSSImageValue::create(fromStyleImage->cachedImage()->url(), fromStyleImage);
- auto toImageValue = CSSImageValue::create(toStyleImage->cachedImage()->url(), toStyleImage);
+ auto fromImageValue = CSSImageValue::create(*fromStyleImage->cachedImage());
+ auto toImageValue = CSSImageValue::create(*toStyleImage->cachedImage());
+ auto percentageValue = CSSPrimitiveValue::create(progress, CSSPrimitiveValue::CSS_NUMBER);
- auto crossfadeValue = CSSCrossfadeValue::create(std::move(fromImageValue), std::move(toImageValue));
- crossfadeValue.get().setPercentage(CSSPrimitiveValue::create(progress, CSSPrimitiveValue::CSS_NUMBER));
- return StyleGeneratedImage::create(std::move(crossfadeValue));
+ auto crossfadeValue = CSSCrossfadeValue::create(WTFMove(fromImageValue), WTFMove(toImageValue), WTFMove(percentageValue));
+ return StyleGeneratedImage::create(WTFMove(crossfadeValue));
}
-static inline PassRefPtr<StyleImage> blendFunc(const AnimationBase* anim, StyleImage* from, StyleImage* to, double progress)
+static inline RefPtr<StyleImage> blendFunc(const AnimationBase* anim, StyleImage* from, StyleImage* to, double progress)
{
if (!from || !to)
return to;
// Animation between two generated images. Cross fade for all other cases.
- if (from->isGeneratedImage() && to->isGeneratedImage()) {
- CSSImageGeneratorValue& fromGenerated = toStyleGeneratedImage(from)->imageValue();
- CSSImageGeneratorValue& toGenerated = toStyleGeneratedImage(to)->imageValue();
+ if (is<StyleGeneratedImage>(*from) && is<StyleGeneratedImage>(*to)) {
+ CSSImageGeneratorValue& fromGenerated = downcast<StyleGeneratedImage>(*from).imageValue();
+ CSSImageGeneratorValue& toGenerated = downcast<StyleGeneratedImage>(*to).imageValue();
-#if ENABLE(CSS_FILTERS)
- if (fromGenerated.isFilterImageValue() && toGenerated.isFilterImageValue()) {
+ if (is<CSSFilterImageValue>(fromGenerated) && is<CSSFilterImageValue>(toGenerated)) {
// Animation of generated images just possible if input images are equal.
// Otherwise fall back to cross fade animation.
- CSSFilterImageValue& fromFilter = toCSSFilterImageValue(fromGenerated);
- CSSFilterImageValue& toFilter = toCSSFilterImageValue(toGenerated);
+ CSSFilterImageValue& fromFilter = downcast<CSSFilterImageValue>(fromGenerated);
+ CSSFilterImageValue& toFilter = downcast<CSSFilterImageValue>(toGenerated);
if (fromFilter.equalInputImages(toFilter) && fromFilter.cachedImage())
return blendFilter(anim, fromFilter.cachedImage(), fromFilter.filterOperations(), toFilter.filterOperations(), progress);
}
-#endif
- if (fromGenerated.isCrossfadeValue() && toGenerated.isCrossfadeValue()) {
- CSSCrossfadeValue& fromCrossfade = toCSSCrossfadeValue(fromGenerated);
- CSSCrossfadeValue& toCrossfade = toCSSCrossfadeValue(toGenerated);
- if (fromCrossfade.equalInputImages(toCrossfade))
- return StyleGeneratedImage::create(*toCrossfade.blend(fromCrossfade, progress));
+ if (is<CSSCrossfadeValue>(fromGenerated) && is<CSSCrossfadeValue>(toGenerated)) {
+ CSSCrossfadeValue& fromCrossfade = downcast<CSSCrossfadeValue>(fromGenerated);
+ CSSCrossfadeValue& toCrossfade = downcast<CSSCrossfadeValue>(toGenerated);
+ if (fromCrossfade.equalInputImages(toCrossfade)) {
+ if (auto crossfadeBlend = toCrossfade.blend(fromCrossfade, progress))
+ return StyleGeneratedImage::create(*crossfadeBlend);
+ }
}
// FIXME: Add support for animation between two *gradient() functions.
// https://bugs.webkit.org/show_bug.cgi?id=119956
-#if ENABLE(CSS_FILTERS)
- } else if (from->isGeneratedImage() && to->isCachedImage()) {
- CSSImageGeneratorValue& fromGenerated = toStyleGeneratedImage(from)->imageValue();
- if (fromGenerated.isFilterImageValue()) {
- CSSFilterImageValue& fromFilter = toCSSFilterImageValue(fromGenerated);
- if (fromFilter.cachedImage() && static_cast<StyleCachedImage*>(to)->cachedImage() == fromFilter.cachedImage())
+ } else if (is<StyleGeneratedImage>(*from) && is<StyleCachedImage>(*to)) {
+ CSSImageGeneratorValue& fromGenerated = downcast<StyleGeneratedImage>(*from).imageValue();
+ if (is<CSSFilterImageValue>(fromGenerated)) {
+ CSSFilterImageValue& fromFilter = downcast<CSSFilterImageValue>(fromGenerated);
+ if (fromFilter.cachedImage() && downcast<StyleCachedImage>(*to).cachedImage() == fromFilter.cachedImage())
return blendFilter(anim, fromFilter.cachedImage(), fromFilter.filterOperations(), FilterOperations(), progress);
}
// FIXME: Add interpolation between cross-fade and image source.
- } else if (from->isCachedImage() && to->isGeneratedImage()) {
- CSSImageGeneratorValue& toGenerated = toStyleGeneratedImage(to)->imageValue();
- if (toGenerated.isFilterImageValue()) {
- CSSFilterImageValue& toFilter = toCSSFilterImageValue(toGenerated);
- if (toFilter.cachedImage() && static_cast<StyleCachedImage*>(from)->cachedImage() == toFilter.cachedImage())
+ } else if (is<StyleCachedImage>(*from) && is<StyleGeneratedImage>(*to)) {
+ CSSImageGeneratorValue& toGenerated = downcast<StyleGeneratedImage>(*to).imageValue();
+ if (is<CSSFilterImageValue>(toGenerated)) {
+ CSSFilterImageValue& toFilter = downcast<CSSFilterImageValue>(toGenerated);
+ if (toFilter.cachedImage() && downcast<StyleCachedImage>(*from).cachedImage() == toFilter.cachedImage())
return blendFilter(anim, toFilter.cachedImage(), FilterOperations(), toFilter.filterOperations(), progress);
}
-#endif
// FIXME: Add interpolation between image source and cross-fade.
}
// FIXME: Add support cross fade between cached and generated images.
// https://bugs.webkit.org/show_bug.cgi?id=78293
- if (from->isCachedImage() && to->isCachedImage())
- return crossfadeBlend(anim, static_cast<StyleCachedImage*>(from), static_cast<StyleCachedImage*>(to), progress);
+ if (is<StyleCachedImage>(*from) && is<StyleCachedImage>(*to))
+ return crossfadeBlend(anim, downcast<StyleCachedImage>(from), downcast<StyleCachedImage>(to), progress);
return to;
}
@@ -367,11 +366,31 @@ static inline NinePieceImage blendFunc(const AnimationBase* anim, const NinePiec
if (from.image()->imageSize(anim->renderer(), 1.0) != to.image()->imageSize(anim->renderer(), 1.0))
return to;
- RefPtr<StyleImage> newContentImage = blendFunc(anim, from.image(), to.image(), progress);
+ return NinePieceImage(blendFunc(anim, from.image(), to.image(), progress),
+ from.imageSlices(), from.fill(), from.borderSlices(), from.outset(), from.horizontalRule(), from.verticalRule());
+}
+
+#if ENABLE(VARIATION_FONTS)
- return NinePieceImage(newContentImage, from.imageSlices(), from.fill(), from.borderSlices(), from.outset(), from.horizontalRule(), from.verticalRule());
+static inline FontVariationSettings blendFunc(const AnimationBase* anim, const FontVariationSettings& from, const FontVariationSettings& to, double progress)
+{
+ if (from.size() != to.size())
+ return FontVariationSettings();
+ FontVariationSettings result;
+ unsigned size = from.size();
+ for (unsigned i = 0; i < size; ++i) {
+ auto& fromItem = from.at(i);
+ auto& toItem = to.at(i);
+ if (fromItem.tag() != toItem.tag())
+ return FontVariationSettings();
+ float interpolated = blendFunc(anim, fromItem.value(), toItem.value(), progress);
+ result.insert({ fromItem.tag(), interpolated });
+ }
+ return result;
}
+#endif
+
class AnimationPropertyWrapperBase {
WTF_MAKE_NONCOPYABLE(AnimationPropertyWrapperBase);
WTF_MAKE_FAST_ALLOCATED;
@@ -386,12 +405,14 @@ public:
virtual bool isShorthandWrapper() const { return false; }
virtual bool equals(const RenderStyle* a, const RenderStyle* b) const = 0;
virtual void blend(const AnimationBase*, RenderStyle*, const RenderStyle*, const RenderStyle*, double) const = 0;
+
+#if !LOG_DISABLED
+ virtual void logBlend(const RenderStyle* a, const RenderStyle* b, const RenderStyle* result, double) const = 0;
+#endif
CSSPropertyID property() const { return m_prop; }
-#if USE(ACCELERATED_COMPOSITING)
virtual bool animationIsAccelerated() const { return false; }
-#endif
private:
CSSPropertyID m_prop;
@@ -399,6 +420,7 @@ private:
template <typename T>
class PropertyWrapperGetter : public AnimationPropertyWrapperBase {
+ WTF_MAKE_FAST_ALLOCATED;
public:
PropertyWrapperGetter(CSSPropertyID prop, T (RenderStyle::*getter)() const)
: AnimationPropertyWrapperBase(prop)
@@ -406,23 +428,34 @@ public:
{
}
- virtual bool equals(const RenderStyle* a, const RenderStyle* b) const
+ bool equals(const RenderStyle* a, const RenderStyle* b) const override
{
- // If the style pointers are the same, don't bother doing the test.
- // If either is null, return false. If both are null, return true.
- if ((!a && !b) || a == b)
+ if (a == b)
return true;
if (!a || !b)
return false;
return (a->*m_getter)() == (b->*m_getter)();
}
+ T value(const RenderStyle* a) const
+ {
+ return (a->*m_getter)();
+ }
+
+#if !LOG_DISABLED
+ void logBlend(const RenderStyle* a, const RenderStyle* b, const RenderStyle* result, double progress) const final
+ {
+ LOG_WITH_STREAM(Animations, stream << " blending " << getPropertyName(property()) << " from " << value(a) << " to " << value(b) << " at " << TextStream::FormatNumberRespectingIntegers(progress) << " -> " << value(result));
+ }
+#endif
+
protected:
T (RenderStyle::*m_getter)() const;
};
template <typename T>
class PropertyWrapper : public PropertyWrapperGetter<T> {
+ WTF_MAKE_FAST_ALLOCATED;
public:
PropertyWrapper(CSSPropertyID prop, T (RenderStyle::*getter)() const, void (RenderStyle::*setter)(T))
: PropertyWrapperGetter<T>(prop, getter)
@@ -430,7 +463,7 @@ public:
{
}
- virtual void blend(const AnimationBase* anim, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress) const
+ void blend(const AnimationBase* anim, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress) const override
{
(dst->*m_setter)(blendFunc(anim, (a->*PropertyWrapperGetter<T>::m_getter)(), (b->*PropertyWrapperGetter<T>::m_getter)(), progress));
}
@@ -441,69 +474,131 @@ protected:
template <typename T>
class RefCountedPropertyWrapper : public PropertyWrapperGetter<T*> {
+ WTF_MAKE_FAST_ALLOCATED;
public:
- RefCountedPropertyWrapper(CSSPropertyID prop, T* (RenderStyle::*getter)() const, void (RenderStyle::*setter)(PassRefPtr<T>))
+ RefCountedPropertyWrapper(CSSPropertyID prop, T* (RenderStyle::*getter)() const, void (RenderStyle::*setter)(RefPtr<T>&&))
: PropertyWrapperGetter<T*>(prop, getter)
, m_setter(setter)
{
}
- virtual void blend(const AnimationBase* anim, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress) const
+ void blend(const AnimationBase* anim, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress) const override
{
(dst->*m_setter)(blendFunc(anim, (a->*PropertyWrapperGetter<T*>::m_getter)(), (b->*PropertyWrapperGetter<T*>::m_getter)(), progress));
}
protected:
- void (RenderStyle::*m_setter)(PassRefPtr<T>);
+ void (RenderStyle::*m_setter)(RefPtr<T>&&);
};
template <typename T>
class LengthPropertyWrapper : public PropertyWrapperGetter<const T&> {
+ WTF_MAKE_FAST_ALLOCATED;
public:
- LengthPropertyWrapper(CSSPropertyID prop, const T& (RenderStyle::*getter)() const, void (RenderStyle::*setter)(T))
+ LengthPropertyWrapper(CSSPropertyID prop, const T& (RenderStyle::*getter)() const, void (RenderStyle::*setter)(T&&))
: PropertyWrapperGetter<const T&>(prop, getter)
, m_setter(setter)
{
}
- virtual void blend(const AnimationBase* anim, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress) const
+ void blend(const AnimationBase* anim, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress) const override
{
(dst->*m_setter)(blendFunc(anim, (a->*PropertyWrapperGetter<const T&>::m_getter)(), (b->*PropertyWrapperGetter<const T&>::m_getter)(), progress));
}
protected:
- void (RenderStyle::*m_setter)(T);
+ void (RenderStyle::*m_setter)(T&&);
};
class PropertyWrapperClipPath : public RefCountedPropertyWrapper<ClipPathOperation> {
+ WTF_MAKE_FAST_ALLOCATED;
public:
- PropertyWrapperClipPath(CSSPropertyID prop, ClipPathOperation* (RenderStyle::*getter)() const, void (RenderStyle::*setter)(PassRefPtr<ClipPathOperation>))
+ PropertyWrapperClipPath(CSSPropertyID prop, ClipPathOperation* (RenderStyle::*getter)() const, void (RenderStyle::*setter)(RefPtr<ClipPathOperation>&&))
: RefCountedPropertyWrapper<ClipPathOperation>(prop, getter, setter)
{
}
+
+ bool equals(const RenderStyle* a, const RenderStyle* b) const override
+ {
+ // If the style pointers are the same, don't bother doing the test.
+ // If either is null, return false. If both are null, return true.
+ if (a == b)
+ return true;
+ if (!a || !b)
+ return false;
+
+ ClipPathOperation* clipPathA = (a->*m_getter)();
+ ClipPathOperation* clipPathB = (b->*m_getter)();
+ if (clipPathA == clipPathB)
+ return true;
+ if (!clipPathA || !clipPathB)
+ return false;
+ return *clipPathA == *clipPathB;
+ }
+};
+
+#if ENABLE(VARIATION_FONTS)
+class PropertyWrapperFontVariationSettings : public PropertyWrapper<FontVariationSettings> {
+ WTF_MAKE_FAST_ALLOCATED;
+public:
+ PropertyWrapperFontVariationSettings(CSSPropertyID prop, FontVariationSettings (RenderStyle::*getter)() const, void (RenderStyle::*setter)(FontVariationSettings))
+ : PropertyWrapper<FontVariationSettings>(prop, getter, setter)
+ {
+ }
+
+ bool equals(const RenderStyle* a, const RenderStyle* b) const override
+ {
+ // If the style pointers are the same, don't bother doing the test.
+ // If either is null, return false. If both are null, return true.
+ if (a == b)
+ return true;
+ if (!a || !b)
+ return false;
+
+ const FontVariationSettings& variationSettingsA = (a->*m_getter)();
+ const FontVariationSettings& variationSettingsB = (b->*m_getter)();
+ return variationSettingsA == variationSettingsB;
+ }
};
+#endif
-#if ENABLE(CSS_SHAPES)
class PropertyWrapperShape : public RefCountedPropertyWrapper<ShapeValue> {
+ WTF_MAKE_FAST_ALLOCATED;
public:
- PropertyWrapperShape(CSSPropertyID prop, ShapeValue* (RenderStyle::*getter)() const, void (RenderStyle::*setter)(PassRefPtr<ShapeValue>))
+ PropertyWrapperShape(CSSPropertyID prop, ShapeValue* (RenderStyle::*getter)() const, void (RenderStyle::*setter)(RefPtr<ShapeValue>&&))
: RefCountedPropertyWrapper<ShapeValue>(prop, getter, setter)
{
}
+
+ bool equals(const RenderStyle* a, const RenderStyle* b) const override
+ {
+ // If the style pointers are the same, don't bother doing the test.
+ // If either is null, return false. If both are null, return true.
+ if (a == b)
+ return true;
+ if (!a || !b)
+ return false;
+
+ ShapeValue* shapeA = (a->*m_getter)();
+ ShapeValue* shapeB = (b->*m_getter)();
+ if (shapeA == shapeB)
+ return true;
+ if (!shapeA || !shapeB)
+ return false;
+ return *shapeA == *shapeB;
+ }
};
-#endif
class StyleImagePropertyWrapper : public RefCountedPropertyWrapper<StyleImage> {
+ WTF_MAKE_FAST_ALLOCATED;
public:
- StyleImagePropertyWrapper(CSSPropertyID prop, StyleImage* (RenderStyle::*getter)() const, void (RenderStyle::*setter)(PassRefPtr<StyleImage>))
+ StyleImagePropertyWrapper(CSSPropertyID prop, StyleImage* (RenderStyle::*getter)() const, void (RenderStyle::*setter)(RefPtr<StyleImage>&&))
: RefCountedPropertyWrapper<StyleImage>(prop, getter, setter)
{
}
- virtual bool equals(const RenderStyle* a, const RenderStyle* b) const
+ bool equals(const RenderStyle* a, const RenderStyle* b) const override
{
- // If the style pointers are the same, don't bother doing the test.
- // If either is null, return false. If both are null, return true.
if (a == b)
return true;
if (!a || !b)
@@ -511,67 +606,82 @@ public:
StyleImage* imageA = (a->*m_getter)();
StyleImage* imageB = (b->*m_getter)();
- return StyleImage::imagesEquivalent(imageA, imageB);
+ return arePointingToEqualData(imageA, imageB);
}
};
-class PropertyWrapperColor : public PropertyWrapperGetter<Color> {
+class PropertyWrapperColor : public PropertyWrapperGetter<const Color&> {
+ WTF_MAKE_FAST_ALLOCATED;
public:
- PropertyWrapperColor(CSSPropertyID prop, Color (RenderStyle::*getter)() const, void (RenderStyle::*setter)(const Color&))
- : PropertyWrapperGetter<Color>(prop, getter)
+ PropertyWrapperColor(CSSPropertyID prop, const Color& (RenderStyle::*getter)() const, void (RenderStyle::*setter)(const Color&))
+ : PropertyWrapperGetter<const Color&>(prop, getter)
, m_setter(setter)
{
}
- virtual void blend(const AnimationBase* anim, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress) const
+ void blend(const AnimationBase* anim, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress) const override
{
- (dst->*m_setter)(blendFunc(anim, (a->*PropertyWrapperGetter<Color>::m_getter)(), (b->*PropertyWrapperGetter<Color>::m_getter)(), progress));
+ (dst->*m_setter)(blendFunc(anim, (a->*PropertyWrapperGetter<const Color&>::m_getter)(), (b->*PropertyWrapperGetter<const Color&>::m_getter)(), progress));
}
protected:
void (RenderStyle::*m_setter)(const Color&);
};
-
-#if USE(ACCELERATED_COMPOSITING)
class PropertyWrapperAcceleratedOpacity : public PropertyWrapper<float> {
+ WTF_MAKE_FAST_ALLOCATED;
public:
PropertyWrapperAcceleratedOpacity()
: PropertyWrapper<float>(CSSPropertyOpacity, &RenderStyle::opacity, &RenderStyle::setOpacity)
{
}
- virtual bool animationIsAccelerated() const { return true; }
+ bool animationIsAccelerated() const override { return true; }
- virtual void blend(const AnimationBase* anim, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress) const
+ void blend(const AnimationBase* anim, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress) const override
{
- float fromOpacity = a->opacity();
-
- // This makes sure we put the object being animated into a RenderLayer during the animation
- dst->setOpacity(blendFunc(anim, (fromOpacity == 1) ? 0.999999f : fromOpacity, b->opacity(), progress));
+ dst->setOpacity(blendFunc(anim, a->opacity(), b->opacity(), progress));
}
};
class PropertyWrapperAcceleratedTransform : public PropertyWrapper<const TransformOperations&> {
+ WTF_MAKE_FAST_ALLOCATED;
public:
PropertyWrapperAcceleratedTransform()
- : PropertyWrapper<const TransformOperations&>(CSSPropertyWebkitTransform, &RenderStyle::transform, &RenderStyle::setTransform)
+ : PropertyWrapper<const TransformOperations&>(CSSPropertyTransform, &RenderStyle::transform, &RenderStyle::setTransform)
{
}
- virtual bool animationIsAccelerated() const { return true; }
+ bool animationIsAccelerated() const override { return true; }
- virtual void blend(const AnimationBase* anim, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress) const
+ void blend(const AnimationBase* anim, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress) const override
{
dst->setTransform(blendFunc(anim, a->transform(), b->transform(), progress));
}
};
-#if ENABLE(CSS_FILTERS)
class PropertyWrapperAcceleratedFilter : public PropertyWrapper<const FilterOperations&> {
+ WTF_MAKE_FAST_ALLOCATED;
public:
PropertyWrapperAcceleratedFilter()
- : PropertyWrapper<const FilterOperations&>(CSSPropertyWebkitFilter, &RenderStyle::filter, &RenderStyle::setFilter)
+ : PropertyWrapper<const FilterOperations&>(CSSPropertyFilter, &RenderStyle::filter, &RenderStyle::setFilter)
+ {
+ }
+
+ bool animationIsAccelerated() const override { return true; }
+
+ void blend(const AnimationBase* anim, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress) const override
+ {
+ dst->setFilter(blendFunc(anim, a->filter(), b->filter(), progress));
+ }
+};
+
+#if ENABLE(FILTERS_LEVEL_2)
+class PropertyWrapperAcceleratedBackdropFilter : public PropertyWrapper<const FilterOperations&> {
+ WTF_MAKE_FAST_ALLOCATED;
+public:
+ PropertyWrapperAcceleratedBackdropFilter()
+ : PropertyWrapper<const FilterOperations&>(CSSPropertyWebkitBackdropFilter, &RenderStyle::backdropFilter, &RenderStyle::setBackdropFilter)
{
}
@@ -579,11 +689,10 @@ public:
virtual void blend(const AnimationBase* anim, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress) const
{
- dst->setFilter(blendFunc(anim, a->filter(), b->filter(), progress));
+ dst->setBackdropFilter(blendFunc(anim, a->backdropFilter(), b->backdropFilter(), progress, true));
}
};
#endif
-#endif // USE(ACCELERATED_COMPOSITING)
static inline size_t shadowListLength(const ShadowData* shadow)
{
@@ -595,32 +704,37 @@ static inline size_t shadowListLength(const ShadowData* shadow)
static inline const ShadowData* shadowForBlending(const ShadowData* srcShadow, const ShadowData* otherShadow)
{
- DEFINE_STATIC_LOCAL(ShadowData, defaultShadowData, (IntPoint(), 0, 0, Normal, false, Color::transparent));
- DEFINE_STATIC_LOCAL(ShadowData, defaultInsetShadowData, (IntPoint(), 0, 0, Inset, false, Color::transparent));
-
- DEFINE_STATIC_LOCAL(ShadowData, defaultWebKitBoxShadowData, (IntPoint(), 0, 0, Normal, true, Color::transparent));
- DEFINE_STATIC_LOCAL(ShadowData, defaultInsetWebKitBoxShadowData, (IntPoint(), 0, 0, Inset, true, Color::transparent));
+ static NeverDestroyed<ShadowData> defaultShadowData(IntPoint(), 0, 0, Normal, false, Color::transparent);
+ static NeverDestroyed<ShadowData> defaultInsetShadowData(IntPoint(), 0, 0, Inset, false, Color::transparent);
+ static NeverDestroyed<ShadowData> defaultWebKitBoxShadowData(IntPoint(), 0, 0, Normal, true, Color::transparent);
+ static NeverDestroyed<ShadowData> defaultInsetWebKitBoxShadowData(IntPoint(), 0, 0, Inset, true, Color::transparent);
if (srcShadow)
return srcShadow;
if (otherShadow->style() == Inset)
- return otherShadow->isWebkitBoxShadow() ? &defaultInsetWebKitBoxShadowData : &defaultInsetShadowData;
+ return otherShadow->isWebkitBoxShadow() ? &defaultInsetWebKitBoxShadowData.get() : &defaultInsetShadowData.get();
- return otherShadow->isWebkitBoxShadow() ? &defaultWebKitBoxShadowData : &defaultShadowData;
+ return otherShadow->isWebkitBoxShadow() ? &defaultWebKitBoxShadowData.get() : &defaultShadowData.get();
}
class PropertyWrapperShadow : public AnimationPropertyWrapperBase {
+ WTF_MAKE_FAST_ALLOCATED;
public:
- PropertyWrapperShadow(CSSPropertyID prop, const ShadowData* (RenderStyle::*getter)() const, void (RenderStyle::*setter)(PassOwnPtr<ShadowData>, bool))
+ PropertyWrapperShadow(CSSPropertyID prop, const ShadowData* (RenderStyle::*getter)() const, void (RenderStyle::*setter)(std::unique_ptr<ShadowData>, bool))
: AnimationPropertyWrapperBase(prop)
, m_getter(getter)
, m_setter(setter)
{
}
- virtual bool equals(const RenderStyle* a, const RenderStyle* b) const
+ bool equals(const RenderStyle* a, const RenderStyle* b) const override
{
+ if (a == b)
+ return true;
+ if (!a || !b)
+ return false;
+
const ShadowData* shadowA = (a->*m_getter)();
const ShadowData* shadowB = (b->*m_getter)();
@@ -643,7 +757,7 @@ public:
return true;
}
- virtual void blend(const AnimationBase* anim, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress) const
+ void blend(const AnimationBase* anim, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress) const override
{
const ShadowData* shadowA = (a->*m_getter)();
const ShadowData* shadowB = (b->*m_getter)();
@@ -659,23 +773,31 @@ public:
(dst->*m_setter)(blendMismatchedShadowLists(anim, progress, shadowA, shadowB, fromLength, toLength), false);
}
+#if !LOG_DISABLED
+ void logBlend(const RenderStyle*, const RenderStyle*, const RenderStyle*, double progress) const final
+ {
+ // FIXME: better logging.
+ LOG_WITH_STREAM(Animations, stream << " blending ShadowData at " << TextStream::FormatNumberRespectingIntegers(progress));
+ }
+#endif
+
private:
- PassOwnPtr<ShadowData> blendSimpleOrMatchedShadowLists(const AnimationBase* anim, double progress, const ShadowData* shadowA, const ShadowData* shadowB) const
+ std::unique_ptr<ShadowData> blendSimpleOrMatchedShadowLists(const AnimationBase* anim, double progress, const ShadowData* shadowA, const ShadowData* shadowB) const
{
- OwnPtr<ShadowData> newShadowData;
+ std::unique_ptr<ShadowData> newShadowData;
ShadowData* lastShadow = 0;
while (shadowA || shadowB) {
const ShadowData* srcShadow = shadowForBlending(shadowA, shadowB);
const ShadowData* dstShadow = shadowForBlending(shadowB, shadowA);
- OwnPtr<ShadowData> blendedShadow = blendFunc(anim, srcShadow, dstShadow, progress);
+ std::unique_ptr<ShadowData> blendedShadow = blendFunc(anim, srcShadow, dstShadow, progress);
ShadowData* blendedShadowPtr = blendedShadow.get();
if (!lastShadow)
- newShadowData = blendedShadow.release();
+ newShadowData = WTFMove(blendedShadow);
else
- lastShadow->setNext(blendedShadow.release());
+ lastShadow->setNext(WTFMove(blendedShadow));
lastShadow = blendedShadowPtr;
@@ -683,10 +805,10 @@ private:
shadowB = shadowB ? shadowB->next() : 0;
}
- return newShadowData.release();
+ return newShadowData;
}
- PassOwnPtr<ShadowData> blendMismatchedShadowLists(const AnimationBase* anim, double progress, const ShadowData* shadowA, const ShadowData* shadowB, int fromLength, int toLength) const
+ std::unique_ptr<ShadowData> blendMismatchedShadowLists(const AnimationBase* anim, double progress, const ShadowData* shadowA, const ShadowData* shadowB, int fromLength, int toLength) const
{
// The shadows in ShadowData are stored in reverse order, so when animating mismatched lists,
// reverse them and match from the end.
@@ -702,7 +824,7 @@ private:
shadowB = shadowB->next();
}
- OwnPtr<ShadowData> newShadowData;
+ std::unique_ptr<ShadowData> newShadowData;
int maxLength = std::max(fromLength, toLength);
for (int i = 0; i < maxLength; ++i) {
@@ -712,32 +834,38 @@ private:
const ShadowData* srcShadow = shadowForBlending(fromShadow, toShadow);
const ShadowData* dstShadow = shadowForBlending(toShadow, fromShadow);
- OwnPtr<ShadowData> blendedShadow = blendFunc(anim, srcShadow, dstShadow, progress);
+ std::unique_ptr<ShadowData> blendedShadow = blendFunc(anim, srcShadow, dstShadow, progress);
// Insert at the start of the list to preserve the order.
- blendedShadow->setNext(newShadowData.release());
- newShadowData = blendedShadow.release();
+ blendedShadow->setNext(WTFMove(newShadowData));
+ newShadowData = WTFMove(blendedShadow);
}
- return newShadowData.release();
+ return newShadowData;
}
const ShadowData* (RenderStyle::*m_getter)() const;
- void (RenderStyle::*m_setter)(PassOwnPtr<ShadowData>, bool);
+ void (RenderStyle::*m_setter)(std::unique_ptr<ShadowData>, bool);
};
class PropertyWrapperMaybeInvalidColor : public AnimationPropertyWrapperBase {
+ WTF_MAKE_FAST_ALLOCATED;
public:
- PropertyWrapperMaybeInvalidColor(CSSPropertyID prop, Color (RenderStyle::*getter)() const, void (RenderStyle::*setter)(const Color&))
+ PropertyWrapperMaybeInvalidColor(CSSPropertyID prop, const Color& (RenderStyle::*getter)() const, void (RenderStyle::*setter)(const Color&))
: AnimationPropertyWrapperBase(prop)
, m_getter(getter)
, m_setter(setter)
{
}
- virtual bool equals(const RenderStyle* a, const RenderStyle* b) const
+ bool equals(const RenderStyle* a, const RenderStyle* b) const override
{
- Color fromColor = (a->*m_getter)();
- Color toColor = (b->*m_getter)();
+ if (a == b)
+ return true;
+ if (!a || !b)
+ return false;
+
+ Color fromColor = value(a);
+ Color toColor = value(b);
if (!fromColor.isValid() && !toColor.isValid())
return true;
@@ -750,10 +878,10 @@ public:
return fromColor == toColor;
}
- virtual void blend(const AnimationBase* anim, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress) const
+ void blend(const AnimationBase* anim, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress) const override
{
- Color fromColor = (a->*m_getter)();
- Color toColor = (b->*m_getter)();
+ Color fromColor = value(a);
+ Color toColor = value(b);
if (!fromColor.isValid() && !toColor.isValid())
return;
@@ -765,46 +893,69 @@ public:
(dst->*m_setter)(blendFunc(anim, fromColor, toColor, progress));
}
+ Color value(const RenderStyle* a) const
+ {
+ return (a->*m_getter)();
+ }
+
+#if !LOG_DISABLED
+ void logBlend(const RenderStyle* a, const RenderStyle* b, const RenderStyle* result, double progress) const final
+ {
+ // FIXME: better logging.
+ LOG_WITH_STREAM(Animations, stream << " blending " << getPropertyName(property()) << " from " << value(a) << " to " << value(b) << " at " << TextStream::FormatNumberRespectingIntegers(progress) << " -> " << value(result));
+ }
+#endif
+
private:
- Color (RenderStyle::*m_getter)() const;
+ const Color& (RenderStyle::*m_getter)() const;
void (RenderStyle::*m_setter)(const Color&);
};
enum MaybeInvalidColorTag { MaybeInvalidColor };
class PropertyWrapperVisitedAffectedColor : public AnimationPropertyWrapperBase {
+ WTF_MAKE_FAST_ALLOCATED;
public:
- PropertyWrapperVisitedAffectedColor(CSSPropertyID prop, Color (RenderStyle::*getter)() const, void (RenderStyle::*setter)(const Color&),
- Color (RenderStyle::*visitedGetter)() const, void (RenderStyle::*visitedSetter)(const Color&))
+ PropertyWrapperVisitedAffectedColor(CSSPropertyID prop, const Color& (RenderStyle::*getter)() const, void (RenderStyle::*setter)(const Color&),
+ const Color& (RenderStyle::*visitedGetter)() const, void (RenderStyle::*visitedSetter)(const Color&))
: AnimationPropertyWrapperBase(prop)
- , m_wrapper(adoptPtr(new PropertyWrapperColor(prop, getter, setter)))
- , m_visitedWrapper(adoptPtr(new PropertyWrapperColor(prop, visitedGetter, visitedSetter)))
+ , m_wrapper(std::make_unique<PropertyWrapperColor>(prop, getter, setter))
+ , m_visitedWrapper(std::make_unique<PropertyWrapperColor>(prop, visitedGetter, visitedSetter))
{
}
- PropertyWrapperVisitedAffectedColor(CSSPropertyID prop, MaybeInvalidColorTag, Color (RenderStyle::*getter)() const, void (RenderStyle::*setter)(const Color&),
- Color (RenderStyle::*visitedGetter)() const, void (RenderStyle::*visitedSetter)(const Color&))
+ PropertyWrapperVisitedAffectedColor(CSSPropertyID prop, MaybeInvalidColorTag, const Color& (RenderStyle::*getter)() const, void (RenderStyle::*setter)(const Color&),
+ const Color& (RenderStyle::*visitedGetter)() const, void (RenderStyle::*visitedSetter)(const Color&))
: AnimationPropertyWrapperBase(prop)
- , m_wrapper(adoptPtr(new PropertyWrapperMaybeInvalidColor(prop, getter, setter)))
- , m_visitedWrapper(adoptPtr(new PropertyWrapperMaybeInvalidColor(prop, visitedGetter, visitedSetter)))
+ , m_wrapper(std::make_unique<PropertyWrapperMaybeInvalidColor>(prop, getter, setter))
+ , m_visitedWrapper(std::make_unique<PropertyWrapperMaybeInvalidColor>(prop, visitedGetter, visitedSetter))
{
}
- virtual bool equals(const RenderStyle* a, const RenderStyle* b) const
+ bool equals(const RenderStyle* a, const RenderStyle* b) const override
{
return m_wrapper->equals(a, b) && m_visitedWrapper->equals(a, b);
}
- virtual void blend(const AnimationBase* anim, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress) const
+ void blend(const AnimationBase* anim, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress) const override
{
m_wrapper->blend(anim, dst, a, b, progress);
m_visitedWrapper->blend(anim, dst, a, b, progress);
}
+#if !LOG_DISABLED
+ void logBlend(const RenderStyle* a, const RenderStyle* b, const RenderStyle* result, double progress) const final
+ {
+ m_wrapper->logBlend(a, b, result, progress);
+ m_visitedWrapper->logBlend(a, b, result, progress);
+ }
+#endif
+
private:
- OwnPtr<AnimationPropertyWrapperBase> m_wrapper;
- OwnPtr<AnimationPropertyWrapperBase> m_visitedWrapper;
+ std::unique_ptr<AnimationPropertyWrapperBase> m_wrapper;
+ std::unique_ptr<AnimationPropertyWrapperBase> m_visitedWrapper;
};
// Wrapper base class for an animatable property in a FillLayer
class FillLayerAnimationPropertyWrapperBase {
+ WTF_MAKE_FAST_ALLOCATED;
public:
FillLayerAnimationPropertyWrapperBase()
{
@@ -818,6 +969,7 @@ public:
template <typename T>
class FillLayerPropertyWrapperGetter : public FillLayerAnimationPropertyWrapperBase {
+ WTF_MAKE_FAST_ALLOCATED;
WTF_MAKE_NONCOPYABLE(FillLayerPropertyWrapperGetter);
public:
FillLayerPropertyWrapperGetter(T (FillLayer::*getter)() const)
@@ -825,13 +977,11 @@ public:
{
}
- virtual bool equals(const FillLayer* a, const FillLayer* b) const
+ bool equals(const FillLayer* a, const FillLayer* b) const override
{
- // If the style pointers are the same, don't bother doing the test.
- // If either is null, return false. If both are null, return true.
- if ((!a && !b) || a == b)
- return true;
- if (!a || !b)
+ if (a == b)
+ return true;
+ if (!a || !b)
return false;
return (a->*m_getter)() == (b->*m_getter)();
}
@@ -842,6 +992,7 @@ protected:
template <typename T>
class FillLayerPropertyWrapper : public FillLayerPropertyWrapperGetter<const T&> {
+ WTF_MAKE_FAST_ALLOCATED;
public:
FillLayerPropertyWrapper(const T& (FillLayer::*getter)() const, void (FillLayer::*setter)(T))
: FillLayerPropertyWrapperGetter<const T&>(getter)
@@ -849,7 +1000,7 @@ public:
{
}
- virtual void blend(const AnimationBase* anim, FillLayer* dst, const FillLayer* a, const FillLayer* b, double progress) const
+ void blend(const AnimationBase* anim, FillLayer* dst, const FillLayer* a, const FillLayer* b, double progress) const override
{
(dst->*m_setter)(blendFunc(anim, (a->*FillLayerPropertyWrapperGetter<const T&>::m_getter)(), (b->*FillLayerPropertyWrapperGetter<const T&>::m_getter)(), progress));
}
@@ -860,33 +1011,33 @@ protected:
template <typename T>
class FillLayerRefCountedPropertyWrapper : public FillLayerPropertyWrapperGetter<T*> {
+ WTF_MAKE_FAST_ALLOCATED;
public:
- FillLayerRefCountedPropertyWrapper(T* (FillLayer::*getter)() const, void (FillLayer::*setter)(PassRefPtr<T>))
+ FillLayerRefCountedPropertyWrapper(T* (FillLayer::*getter)() const, void (FillLayer::*setter)(RefPtr<T>&&))
: FillLayerPropertyWrapperGetter<T*>(getter)
, m_setter(setter)
{
}
- virtual void blend(const AnimationBase* anim, FillLayer* dst, const FillLayer* a, const FillLayer* b, double progress) const
+ void blend(const AnimationBase* anim, FillLayer* dst, const FillLayer* a, const FillLayer* b, double progress) const override
{
(dst->*m_setter)(blendFunc(anim, (a->*FillLayerPropertyWrapperGetter<T*>::m_getter)(), (b->*FillLayerPropertyWrapperGetter<T*>::m_getter)(), progress));
}
protected:
- void (FillLayer::*m_setter)(PassRefPtr<T>);
+ void (FillLayer::*m_setter)(RefPtr<T>&&);
};
class FillLayerStyleImagePropertyWrapper : public FillLayerRefCountedPropertyWrapper<StyleImage> {
+ WTF_MAKE_FAST_ALLOCATED;
public:
- FillLayerStyleImagePropertyWrapper(StyleImage* (FillLayer::*getter)() const, void (FillLayer::*setter)(PassRefPtr<StyleImage>))
+ FillLayerStyleImagePropertyWrapper(StyleImage* (FillLayer::*getter)() const, void (FillLayer::*setter)(RefPtr<StyleImage>&&))
: FillLayerRefCountedPropertyWrapper<StyleImage>(getter, setter)
{
}
- virtual bool equals(const FillLayer* a, const FillLayer* b) const
+ bool equals(const FillLayer* a, const FillLayer* b) const override
{
- // If the style pointers are the same, don't bother doing the test.
- // If either is null, return false. If both are null, return true.
if (a == b)
return true;
if (!a || !b)
@@ -894,14 +1045,15 @@ public:
StyleImage* imageA = (a->*m_getter)();
StyleImage* imageB = (b->*m_getter)();
- return StyleImage::imagesEquivalent(imageA, imageB);
+ return arePointingToEqualData(imageA, imageB);
}
};
class FillLayersPropertyWrapper : public AnimationPropertyWrapperBase {
+ WTF_MAKE_FAST_ALLOCATED;
public:
- typedef const FillLayer* (RenderStyle::*LayersGetter)() const;
- typedef FillLayer* (RenderStyle::*LayersAccessor)();
+ typedef const FillLayer& (RenderStyle::*LayersGetter)() const;
+ typedef FillLayer& (RenderStyle::*LayersAccessor)();
FillLayersPropertyWrapper(CSSPropertyID prop, LayersGetter getter, LayersAccessor accessor)
: AnimationPropertyWrapperBase(prop)
@@ -911,29 +1063,34 @@ public:
switch (prop) {
case CSSPropertyBackgroundPositionX:
case CSSPropertyWebkitMaskPositionX:
- m_fillLayerPropertyWrapper = new FillLayerPropertyWrapper<Length>(&FillLayer::xPosition, &FillLayer::setXPosition);
+ m_fillLayerPropertyWrapper = std::make_unique<FillLayerPropertyWrapper<Length>>(&FillLayer::xPosition, &FillLayer::setXPosition);
break;
case CSSPropertyBackgroundPositionY:
case CSSPropertyWebkitMaskPositionY:
- m_fillLayerPropertyWrapper = new FillLayerPropertyWrapper<Length>(&FillLayer::yPosition, &FillLayer::setYPosition);
+ m_fillLayerPropertyWrapper = std::make_unique<FillLayerPropertyWrapper<Length>>(&FillLayer::yPosition, &FillLayer::setYPosition);
break;
case CSSPropertyBackgroundSize:
case CSSPropertyWebkitBackgroundSize:
case CSSPropertyWebkitMaskSize:
- m_fillLayerPropertyWrapper = new FillLayerPropertyWrapper<LengthSize>(&FillLayer::sizeLength, &FillLayer::setSizeLength);
+ m_fillLayerPropertyWrapper = std::make_unique<FillLayerPropertyWrapper<LengthSize>>(&FillLayer::sizeLength, &FillLayer::setSizeLength);
break;
case CSSPropertyBackgroundImage:
- m_fillLayerPropertyWrapper = new FillLayerStyleImagePropertyWrapper(&FillLayer::image, &FillLayer::setImage);
+ m_fillLayerPropertyWrapper = std::make_unique<FillLayerStyleImagePropertyWrapper>(&FillLayer::image, &FillLayer::setImage);
break;
default:
break;
}
}
- virtual bool equals(const RenderStyle* a, const RenderStyle* b) const
+ bool equals(const RenderStyle* a, const RenderStyle* b) const override
{
- const FillLayer* fromLayer = (a->*m_layersGetter)();
- const FillLayer* toLayer = (b->*m_layersGetter)();
+ if (a == b)
+ return true;
+ if (!a || !b)
+ return false;
+
+ auto* fromLayer = &(a->*m_layersGetter)();
+ auto* toLayer = &(b->*m_layersGetter)();
while (fromLayer && toLayer) {
if (!m_fillLayerPropertyWrapper->equals(fromLayer, toLayer))
@@ -946,11 +1103,11 @@ public:
return true;
}
- virtual void blend(const AnimationBase* anim, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress) const
+ void blend(const AnimationBase* anim, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress) const override
{
- const FillLayer* aLayer = (a->*m_layersGetter)();
- const FillLayer* bLayer = (b->*m_layersGetter)();
- FillLayer* dstLayer = (dst->*m_layersAccessor)();
+ auto* aLayer = &(a->*m_layersGetter)();
+ auto* bLayer = &(b->*m_layersGetter)();
+ auto* dstLayer = &(dst->*m_layersAccessor)();
while (aLayer && bLayer && dstLayer) {
m_fillLayerPropertyWrapper->blend(anim, dstLayer, aLayer, bLayer, progress);
@@ -960,57 +1117,77 @@ public:
}
}
+#if !LOG_DISABLED
+ void logBlend(const RenderStyle*, const RenderStyle*, const RenderStyle*, double progress) const final
+ {
+ // FIXME: better logging.
+ LOG_WITH_STREAM(Animations, stream << " blending FillLayers at " << TextStream::FormatNumberRespectingIntegers(progress));
+ }
+#endif
+
private:
- FillLayerAnimationPropertyWrapperBase* m_fillLayerPropertyWrapper;
+ std::unique_ptr<FillLayerAnimationPropertyWrapperBase> m_fillLayerPropertyWrapper;
LayersGetter m_layersGetter;
LayersAccessor m_layersAccessor;
};
class ShorthandPropertyWrapper : public AnimationPropertyWrapperBase {
+ WTF_MAKE_FAST_ALLOCATED;
public:
ShorthandPropertyWrapper(CSSPropertyID property, Vector<AnimationPropertyWrapperBase*> longhandWrappers)
: AnimationPropertyWrapperBase(property)
+ , m_propertyWrappers(WTFMove(longhandWrappers))
{
- m_propertyWrappers.swap(longhandWrappers);
}
- virtual bool isShorthandWrapper() const { return true; }
+ bool isShorthandWrapper() const override { return true; }
- virtual bool equals(const RenderStyle* a, const RenderStyle* b) const
+ bool equals(const RenderStyle* a, const RenderStyle* b) const override
{
- Vector<AnimationPropertyWrapperBase*>::const_iterator end = m_propertyWrappers.end();
- for (Vector<AnimationPropertyWrapperBase*>::const_iterator it = m_propertyWrappers.begin(); it != end; ++it) {
- if (!(*it)->equals(a, b))
+ if (a == b)
+ return true;
+ if (!a || !b)
+ return false;
+
+ for (auto& wrapper : m_propertyWrappers) {
+ if (!wrapper->equals(a, b))
return false;
}
return true;
}
- virtual void blend(const AnimationBase* anim, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress) const
+ void blend(const AnimationBase* anim, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress) const override
+ {
+ for (auto& wrapper : m_propertyWrappers)
+ wrapper->blend(anim, dst, a, b, progress);
+ }
+
+#if !LOG_DISABLED
+ void logBlend(const RenderStyle*, const RenderStyle*, const RenderStyle*, double progress) const final
{
- Vector<AnimationPropertyWrapperBase*>::const_iterator end = m_propertyWrappers.end();
- for (Vector<AnimationPropertyWrapperBase*>::const_iterator it = m_propertyWrappers.begin(); it != end; ++it)
- (*it)->blend(anim, dst, a, b, progress);
+ // FIXME: better logging.
+ LOG_WITH_STREAM(Animations, stream << " blending shorthand property " << getPropertyName(property()) << " at " << TextStream::FormatNumberRespectingIntegers(progress));
}
+#endif
- const Vector<AnimationPropertyWrapperBase*> propertyWrappers() const { return m_propertyWrappers; }
+ const Vector<AnimationPropertyWrapperBase*>& propertyWrappers() const { return m_propertyWrappers; }
private:
Vector<AnimationPropertyWrapperBase*> m_propertyWrappers;
};
class PropertyWrapperFlex : public AnimationPropertyWrapperBase {
+ WTF_MAKE_FAST_ALLOCATED;
public:
- PropertyWrapperFlex() : AnimationPropertyWrapperBase(CSSPropertyWebkitFlex)
+ PropertyWrapperFlex()
+ : AnimationPropertyWrapperBase(CSSPropertyFlex)
{
}
- virtual bool equals(const RenderStyle* a, const RenderStyle* b) const
+ bool equals(const RenderStyle* a, const RenderStyle* b) const override
{
- // If the style pointers are the same, don't bother doing the test.
- // If either is null, return false. If both are null, return true.
- if ((!a && !b) || a == b)
+ if (a == b)
return true;
if (!a || !b)
return false;
@@ -1018,18 +1195,26 @@ public:
return a->flexBasis() == b->flexBasis() && a->flexGrow() == b->flexGrow() && a->flexShrink() == b->flexShrink();
}
- virtual void blend(const AnimationBase* anim, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress) const
+ void blend(const AnimationBase* anim, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress) const override
{
dst->setFlexBasis(blendFunc(anim, a->flexBasis(), b->flexBasis(), progress));
dst->setFlexGrow(blendFunc(anim, a->flexGrow(), b->flexGrow(), progress));
dst->setFlexShrink(blendFunc(anim, a->flexShrink(), b->flexShrink(), progress));
}
+
+#if !LOG_DISABLED
+ void logBlend(const RenderStyle*, const RenderStyle*, const RenderStyle*, double progress) const final
+ {
+ // FIXME: better logging.
+ LOG_WITH_STREAM(Animations, stream << " blending flex at " << TextStream::FormatNumberRespectingIntegers(progress));
+ }
+#endif
};
-#if ENABLE(SVG)
class PropertyWrapperSVGPaint : public AnimationPropertyWrapperBase {
+ WTF_MAKE_FAST_ALLOCATED;
public:
- PropertyWrapperSVGPaint(CSSPropertyID prop, const SVGPaint::SVGPaintType& (RenderStyle::*paintTypeGetter)() const, Color (RenderStyle::*getter)() const, void (RenderStyle::*setter)(const Color&))
+ PropertyWrapperSVGPaint(CSSPropertyID prop, const SVGPaintType& (RenderStyle::*paintTypeGetter)() const, Color (RenderStyle::*getter)() const, void (RenderStyle::*setter)(const Color&))
: AnimationPropertyWrapperBase(prop)
, m_paintTypeGetter(paintTypeGetter)
, m_getter(getter)
@@ -1037,15 +1222,20 @@ public:
{
}
- virtual bool equals(const RenderStyle* a, const RenderStyle* b) const
+ bool equals(const RenderStyle* a, const RenderStyle* b) const override
{
+ if (a == b)
+ return true;
+ if (!a || !b)
+ return false;
+
if ((a->*m_paintTypeGetter)() != (b->*m_paintTypeGetter)())
return false;
// We only support animations between SVGPaints that are pure Color values.
// For everything else we must return true for this method, otherwise
// we will try to animate between values forever.
- if ((a->*m_paintTypeGetter)() == SVGPaint::SVG_PAINTTYPE_RGBCOLOR) {
+ if ((a->*m_paintTypeGetter)() == SVG_PAINTTYPE_RGBCOLOR) {
Color fromColor = (a->*m_getter)();
Color toColor = (b->*m_getter)();
@@ -1062,10 +1252,10 @@ public:
return true;
}
- virtual void blend(const AnimationBase* anim, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress) const
+ void blend(const AnimationBase* anim, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress) const override
{
- if ((a->*m_paintTypeGetter)() != SVGPaint::SVG_PAINTTYPE_RGBCOLOR
- || (b->*m_paintTypeGetter)() != SVGPaint::SVG_PAINTTYPE_RGBCOLOR)
+ if ((a->*m_paintTypeGetter)() != SVG_PAINTTYPE_RGBCOLOR
+ || (b->*m_paintTypeGetter)() != SVG_PAINTTYPE_RGBCOLOR)
return;
Color fromColor = (a->*m_getter)();
@@ -1081,32 +1271,38 @@ public:
(dst->*m_setter)(blendFunc(anim, fromColor, toColor, progress));
}
+#if !LOG_DISABLED
+ void logBlend(const RenderStyle*, const RenderStyle*, const RenderStyle*, double progress) const final
+ {
+ // FIXME: better logging.
+ LOG_WITH_STREAM(Animations, stream << " blending SVGPaint at " << TextStream::FormatNumberRespectingIntegers(progress));
+ }
+#endif
+
private:
- const SVGPaint::SVGPaintType& (RenderStyle::*m_paintTypeGetter)() const;
+ const SVGPaintType& (RenderStyle::*m_paintTypeGetter)() const;
Color (RenderStyle::*m_getter)() const;
void (RenderStyle::*m_setter)(const Color&);
};
-#endif
class CSSPropertyAnimationWrapperMap {
+ WTF_MAKE_FAST_ALLOCATED;
public:
- static CSSPropertyAnimationWrapperMap& instance()
+ static CSSPropertyAnimationWrapperMap& singleton()
{
- // FIXME: This data is never destroyed. Maybe we should ref count it and toss it when the last AnimationController is destroyed?
- DEFINE_STATIC_LOCAL(OwnPtr<CSSPropertyAnimationWrapperMap>, map, ());
- if (!map)
- map = adoptPtr(new CSSPropertyAnimationWrapperMap);
- return *map;
+ // FIXME: This data is never destroyed. Maybe we should ref count it and toss it when the last CSSAnimationController is destroyed?
+ static NeverDestroyed<CSSPropertyAnimationWrapperMap> map;
+ return map;
}
AnimationPropertyWrapperBase* wrapperForProperty(CSSPropertyID propertyID)
{
if (propertyID < firstCSSProperty || propertyID > lastCSSProperty)
- return 0;
+ return nullptr;
unsigned wrapperIndex = indexFromPropertyID(propertyID);
if (wrapperIndex == cInvalidPropertyWrapperIndex)
- return 0;
+ return nullptr;
return m_propertyWrappers[wrapperIndex].get();
}
@@ -1124,15 +1320,19 @@ public:
private:
CSSPropertyAnimationWrapperMap();
+ ~CSSPropertyAnimationWrapperMap() = delete;
+
unsigned char& indexFromPropertyID(CSSPropertyID propertyID)
{
return m_propertyToIdMap[propertyID - firstCSSProperty];
}
- Vector<OwnPtr<AnimationPropertyWrapperBase>> m_propertyWrappers;
+ Vector<std::unique_ptr<AnimationPropertyWrapperBase>> m_propertyWrappers;
unsigned char m_propertyToIdMap[numCSSProperties];
static const unsigned char cInvalidPropertyWrapperIndex = UCHAR_MAX;
+
+ friend class WTF::NeverDestroyed<CSSPropertyAnimationWrapperMap>;
};
CSSPropertyAnimationWrapperMap::CSSPropertyAnimationWrapperMap()
@@ -1154,10 +1354,10 @@ CSSPropertyAnimationWrapperMap::CSSPropertyAnimationWrapperMap()
new PropertyWrapperFlex(),
- new PropertyWrapper<unsigned>(CSSPropertyBorderLeftWidth, &RenderStyle::borderLeftWidth, &RenderStyle::setBorderLeftWidth),
- new PropertyWrapper<unsigned>(CSSPropertyBorderRightWidth, &RenderStyle::borderRightWidth, &RenderStyle::setBorderRightWidth),
- new PropertyWrapper<unsigned>(CSSPropertyBorderTopWidth, &RenderStyle::borderTopWidth, &RenderStyle::setBorderTopWidth),
- new PropertyWrapper<unsigned>(CSSPropertyBorderBottomWidth, &RenderStyle::borderBottomWidth, &RenderStyle::setBorderBottomWidth),
+ new PropertyWrapper<float>(CSSPropertyBorderLeftWidth, &RenderStyle::borderLeftWidth, &RenderStyle::setBorderLeftWidth),
+ new PropertyWrapper<float>(CSSPropertyBorderRightWidth, &RenderStyle::borderRightWidth, &RenderStyle::setBorderRightWidth),
+ new PropertyWrapper<float>(CSSPropertyBorderTopWidth, &RenderStyle::borderTopWidth, &RenderStyle::setBorderTopWidth),
+ new PropertyWrapper<float>(CSSPropertyBorderBottomWidth, &RenderStyle::borderBottomWidth, &RenderStyle::setBorderBottomWidth),
new LengthPropertyWrapper<Length>(CSSPropertyMarginLeft, &RenderStyle::marginLeft, &RenderStyle::setMarginLeft),
new LengthPropertyWrapper<Length>(CSSPropertyMarginRight, &RenderStyle::marginRight, &RenderStyle::setMarginRight),
new LengthPropertyWrapper<Length>(CSSPropertyMarginTop, &RenderStyle::marginTop, &RenderStyle::setMarginTop),
@@ -1170,7 +1370,7 @@ CSSPropertyAnimationWrapperMap::CSSPropertyAnimationWrapperMap()
new PropertyWrapperVisitedAffectedColor(CSSPropertyBackgroundColor, &RenderStyle::backgroundColor, &RenderStyle::setBackgroundColor, &RenderStyle::visitedLinkBackgroundColor, &RenderStyle::setVisitedLinkBackgroundColor),
- new FillLayersPropertyWrapper(CSSPropertyBackgroundImage, &RenderStyle::backgroundLayers, &RenderStyle::accessBackgroundLayers),
+ new FillLayersPropertyWrapper(CSSPropertyBackgroundImage, &RenderStyle::backgroundLayers, &RenderStyle::ensureBackgroundLayers),
new StyleImagePropertyWrapper(CSSPropertyListStyleImage, &RenderStyle::listStyleImage, &RenderStyle::setListStyleImage),
new StyleImagePropertyWrapper(CSSPropertyWebkitMaskImage, &RenderStyle::maskImage, &RenderStyle::setMaskImage),
@@ -1182,47 +1382,38 @@ CSSPropertyAnimationWrapperMap::CSSPropertyAnimationWrapperMap()
new StyleImagePropertyWrapper(CSSPropertyWebkitMaskBoxImageSource, &RenderStyle::maskBoxImageSource, &RenderStyle::setMaskBoxImageSource),
new PropertyWrapper<const NinePieceImage&>(CSSPropertyWebkitMaskBoxImage, &RenderStyle::maskBoxImage, &RenderStyle::setMaskBoxImage),
- new FillLayersPropertyWrapper(CSSPropertyBackgroundPositionX, &RenderStyle::backgroundLayers, &RenderStyle::accessBackgroundLayers),
- new FillLayersPropertyWrapper(CSSPropertyBackgroundPositionY, &RenderStyle::backgroundLayers, &RenderStyle::accessBackgroundLayers),
- new FillLayersPropertyWrapper(CSSPropertyBackgroundSize, &RenderStyle::backgroundLayers, &RenderStyle::accessBackgroundLayers),
- new FillLayersPropertyWrapper(CSSPropertyWebkitBackgroundSize, &RenderStyle::backgroundLayers, &RenderStyle::accessBackgroundLayers),
-
- new FillLayersPropertyWrapper(CSSPropertyWebkitMaskPositionX, &RenderStyle::maskLayers, &RenderStyle::accessMaskLayers),
- new FillLayersPropertyWrapper(CSSPropertyWebkitMaskPositionY, &RenderStyle::maskLayers, &RenderStyle::accessMaskLayers),
- new FillLayersPropertyWrapper(CSSPropertyWebkitMaskSize, &RenderStyle::maskLayers, &RenderStyle::accessMaskLayers),
-
- new PropertyWrapper<float>(CSSPropertyFontSize,
- // Must pass a specified size to setFontSize if Text Autosizing is enabled, but a computed size
- // if text zoom is enabled (if neither is enabled it's irrelevant as they're probably the same).
- // FIXME: Find some way to assert that text zoom isn't activated when Text Autosizing is compiled in.
-#if ENABLE(TEXT_AUTOSIZING)
- &RenderStyle::specifiedFontSize,
-#else
- &RenderStyle::computedFontSize,
-#endif
- &RenderStyle::setFontSize),
- new PropertyWrapper<unsigned short>(CSSPropertyWebkitColumnRuleWidth, &RenderStyle::columnRuleWidth, &RenderStyle::setColumnRuleWidth),
- new PropertyWrapper<float>(CSSPropertyWebkitColumnGap, &RenderStyle::columnGap, &RenderStyle::setColumnGap),
- new PropertyWrapper<unsigned short>(CSSPropertyWebkitColumnCount, &RenderStyle::columnCount, &RenderStyle::setColumnCount),
- new PropertyWrapper<float>(CSSPropertyWebkitColumnWidth, &RenderStyle::columnWidth, &RenderStyle::setColumnWidth),
- new PropertyWrapper<short>(CSSPropertyWebkitBorderHorizontalSpacing, &RenderStyle::horizontalBorderSpacing, &RenderStyle::setHorizontalBorderSpacing),
- new PropertyWrapper<short>(CSSPropertyWebkitBorderVerticalSpacing, &RenderStyle::verticalBorderSpacing, &RenderStyle::setVerticalBorderSpacing),
+ new FillLayersPropertyWrapper(CSSPropertyBackgroundPositionX, &RenderStyle::backgroundLayers, &RenderStyle::ensureBackgroundLayers),
+ new FillLayersPropertyWrapper(CSSPropertyBackgroundPositionY, &RenderStyle::backgroundLayers, &RenderStyle::ensureBackgroundLayers),
+ new FillLayersPropertyWrapper(CSSPropertyBackgroundSize, &RenderStyle::backgroundLayers, &RenderStyle::ensureBackgroundLayers),
+ new FillLayersPropertyWrapper(CSSPropertyWebkitBackgroundSize, &RenderStyle::backgroundLayers, &RenderStyle::ensureBackgroundLayers),
+
+ new FillLayersPropertyWrapper(CSSPropertyWebkitMaskPositionX, &RenderStyle::maskLayers, &RenderStyle::ensureMaskLayers),
+ new FillLayersPropertyWrapper(CSSPropertyWebkitMaskPositionY, &RenderStyle::maskLayers, &RenderStyle::ensureMaskLayers),
+ new FillLayersPropertyWrapper(CSSPropertyWebkitMaskSize, &RenderStyle::maskLayers, &RenderStyle::ensureMaskLayers),
+
+ new PropertyWrapper<float>(CSSPropertyFontSize, &RenderStyle::computedFontSize, &RenderStyle::setFontSize),
+ new PropertyWrapper<unsigned short>(CSSPropertyColumnRuleWidth, &RenderStyle::columnRuleWidth, &RenderStyle::setColumnRuleWidth),
+ new PropertyWrapper<float>(CSSPropertyColumnGap, &RenderStyle::columnGap, &RenderStyle::setColumnGap),
+ new PropertyWrapper<unsigned short>(CSSPropertyColumnCount, &RenderStyle::columnCount, &RenderStyle::setColumnCount),
+ new PropertyWrapper<float>(CSSPropertyColumnWidth, &RenderStyle::columnWidth, &RenderStyle::setColumnWidth),
+ new PropertyWrapper<float>(CSSPropertyWebkitBorderHorizontalSpacing, &RenderStyle::horizontalBorderSpacing, &RenderStyle::setHorizontalBorderSpacing),
+ new PropertyWrapper<float>(CSSPropertyWebkitBorderVerticalSpacing, &RenderStyle::verticalBorderSpacing, &RenderStyle::setVerticalBorderSpacing),
new PropertyWrapper<int>(CSSPropertyZIndex, &RenderStyle::zIndex, &RenderStyle::setZIndex),
new PropertyWrapper<short>(CSSPropertyOrphans, &RenderStyle::orphans, &RenderStyle::setOrphans),
new PropertyWrapper<short>(CSSPropertyWidows, &RenderStyle::widows, &RenderStyle::setWidows),
new LengthPropertyWrapper<Length>(CSSPropertyLineHeight, &RenderStyle::specifiedLineHeight, &RenderStyle::setLineHeight),
- new PropertyWrapper<int>(CSSPropertyOutlineOffset, &RenderStyle::outlineOffset, &RenderStyle::setOutlineOffset),
- new PropertyWrapper<unsigned short>(CSSPropertyOutlineWidth, &RenderStyle::outlineWidth, &RenderStyle::setOutlineWidth),
+ new PropertyWrapper<float>(CSSPropertyOutlineOffset, &RenderStyle::outlineOffset, &RenderStyle::setOutlineOffset),
+ new PropertyWrapper<float>(CSSPropertyOutlineWidth, &RenderStyle::outlineWidth, &RenderStyle::setOutlineWidth),
new PropertyWrapper<float>(CSSPropertyLetterSpacing, &RenderStyle::letterSpacing, &RenderStyle::setLetterSpacing),
new LengthPropertyWrapper<Length>(CSSPropertyWordSpacing, &RenderStyle::wordSpacing, &RenderStyle::setWordSpacing),
new LengthPropertyWrapper<Length>(CSSPropertyTextIndent, &RenderStyle::textIndent, &RenderStyle::setTextIndent),
- new PropertyWrapper<float>(CSSPropertyWebkitPerspective, &RenderStyle::perspective, &RenderStyle::setPerspective),
- new LengthPropertyWrapper<Length>(CSSPropertyWebkitPerspectiveOriginX, &RenderStyle::perspectiveOriginX, &RenderStyle::setPerspectiveOriginX),
- new LengthPropertyWrapper<Length>(CSSPropertyWebkitPerspectiveOriginY, &RenderStyle::perspectiveOriginY, &RenderStyle::setPerspectiveOriginY),
- new LengthPropertyWrapper<Length>(CSSPropertyWebkitTransformOriginX, &RenderStyle::transformOriginX, &RenderStyle::setTransformOriginX),
- new LengthPropertyWrapper<Length>(CSSPropertyWebkitTransformOriginY, &RenderStyle::transformOriginY, &RenderStyle::setTransformOriginY),
- new PropertyWrapper<float>(CSSPropertyWebkitTransformOriginZ, &RenderStyle::transformOriginZ, &RenderStyle::setTransformOriginZ),
+ new PropertyWrapper<float>(CSSPropertyPerspective, &RenderStyle::perspective, &RenderStyle::setPerspective),
+ new LengthPropertyWrapper<Length>(CSSPropertyPerspectiveOriginX, &RenderStyle::perspectiveOriginX, &RenderStyle::setPerspectiveOriginX),
+ new LengthPropertyWrapper<Length>(CSSPropertyPerspectiveOriginY, &RenderStyle::perspectiveOriginY, &RenderStyle::setPerspectiveOriginY),
+ new LengthPropertyWrapper<Length>(CSSPropertyTransformOriginX, &RenderStyle::transformOriginX, &RenderStyle::setTransformOriginX),
+ new LengthPropertyWrapper<Length>(CSSPropertyTransformOriginY, &RenderStyle::transformOriginY, &RenderStyle::setTransformOriginY),
+ new PropertyWrapper<float>(CSSPropertyTransformOriginZ, &RenderStyle::transformOriginZ, &RenderStyle::setTransformOriginZ),
new LengthPropertyWrapper<LengthSize>(CSSPropertyBorderTopLeftRadius, &RenderStyle::borderTopLeftRadius, &RenderStyle::setBorderTopLeftRadius),
new LengthPropertyWrapper<LengthSize>(CSSPropertyBorderTopRightRadius, &RenderStyle::borderTopRightRadius, &RenderStyle::setBorderTopRightRadius),
new LengthPropertyWrapper<LengthSize>(CSSPropertyBorderBottomLeftRadius, &RenderStyle::borderBottomLeftRadius, &RenderStyle::setBorderBottomLeftRadius),
@@ -1232,30 +1423,19 @@ CSSPropertyAnimationWrapperMap::CSSPropertyAnimationWrapperMap()
new LengthPropertyWrapper<LengthBox>(CSSPropertyClip, &RenderStyle::clip, &RenderStyle::setClip),
-#if USE(ACCELERATED_COMPOSITING)
new PropertyWrapperAcceleratedOpacity(),
new PropertyWrapperAcceleratedTransform(),
-#if ENABLE(CSS_FILTERS)
new PropertyWrapperAcceleratedFilter(),
+#if ENABLE(FILTERS_LEVEL_2)
+ new PropertyWrapperAcceleratedBackdropFilter(),
#endif
-#else
- new PropertyWrapper<float>(CSSPropertyOpacity, &RenderStyle::opacity, &RenderStyle::setOpacity),
- new PropertyWrapper<const TransformOperations&>(CSSPropertyWebkitTransform, &RenderStyle::transform, &RenderStyle::setTransform),
-#if ENABLE(CSS_FILTERS)
- new PropertyWrapper<const FilterOperations&>(CSSPropertyWebkitFilter, &RenderStyle::filter, &RenderStyle::setFilter),
-#endif
-#endif
-
new PropertyWrapperClipPath(CSSPropertyWebkitClipPath, &RenderStyle::clipPath, &RenderStyle::setClipPath),
-#if ENABLE(CSS_SHAPES)
- new PropertyWrapperShape(CSSPropertyWebkitShapeInside, &RenderStyle::shapeInside, &RenderStyle::setShapeInside),
- new PropertyWrapperShape(CSSPropertyWebkitShapeOutside, &RenderStyle::shapeOutside, &RenderStyle::setShapeOutside),
- new LengthPropertyWrapper<Length>(CSSPropertyWebkitShapeMargin, &RenderStyle::shapeMargin, &RenderStyle::setShapeMargin),
- new PropertyWrapper<float>(CSSPropertyWebkitShapeImageThreshold, &RenderStyle::shapeImageThreshold, &RenderStyle::setShapeImageThreshold),
-#endif
+ new PropertyWrapperShape(CSSPropertyShapeOutside, &RenderStyle::shapeOutside, &RenderStyle::setShapeOutside),
+ new LengthPropertyWrapper<Length>(CSSPropertyShapeMargin, &RenderStyle::shapeMargin, &RenderStyle::setShapeMargin),
+ new PropertyWrapper<float>(CSSPropertyShapeImageThreshold, &RenderStyle::shapeImageThreshold, &RenderStyle::setShapeImageThreshold),
- new PropertyWrapperVisitedAffectedColor(CSSPropertyWebkitColumnRuleColor, MaybeInvalidColor, &RenderStyle::columnRuleColor, &RenderStyle::setColumnRuleColor, &RenderStyle::visitedLinkColumnRuleColor, &RenderStyle::setVisitedLinkColumnRuleColor),
+ new PropertyWrapperVisitedAffectedColor(CSSPropertyColumnRuleColor, MaybeInvalidColor, &RenderStyle::columnRuleColor, &RenderStyle::setColumnRuleColor, &RenderStyle::visitedLinkColumnRuleColor, &RenderStyle::setVisitedLinkColumnRuleColor),
new PropertyWrapperVisitedAffectedColor(CSSPropertyWebkitTextStrokeColor, MaybeInvalidColor, &RenderStyle::textStrokeColor, &RenderStyle::setTextStrokeColor, &RenderStyle::visitedLinkTextStrokeColor, &RenderStyle::setVisitedLinkTextStrokeColor),
new PropertyWrapperVisitedAffectedColor(CSSPropertyWebkitTextFillColor, MaybeInvalidColor, &RenderStyle::textFillColor, &RenderStyle::setTextFillColor, &RenderStyle::visitedLinkTextFillColor, &RenderStyle::setVisitedLinkTextFillColor),
new PropertyWrapperVisitedAffectedColor(CSSPropertyBorderLeftColor, MaybeInvalidColor, &RenderStyle::borderLeftColor, &RenderStyle::setBorderLeftColor, &RenderStyle::visitedLinkBorderLeftColor, &RenderStyle::setVisitedLinkBorderLeftColor),
@@ -1268,17 +1448,24 @@ CSSPropertyAnimationWrapperMap::CSSPropertyAnimationWrapperMap()
new PropertyWrapperShadow(CSSPropertyWebkitBoxShadow, &RenderStyle::boxShadow, &RenderStyle::setBoxShadow),
new PropertyWrapperShadow(CSSPropertyTextShadow, &RenderStyle::textShadow, &RenderStyle::setTextShadow),
-#if ENABLE(SVG)
new PropertyWrapperSVGPaint(CSSPropertyFill, &RenderStyle::fillPaintType, &RenderStyle::fillPaintColor, &RenderStyle::setFillPaintColor),
new PropertyWrapper<float>(CSSPropertyFillOpacity, &RenderStyle::fillOpacity, &RenderStyle::setFillOpacity),
new PropertyWrapperSVGPaint(CSSPropertyStroke, &RenderStyle::strokePaintType, &RenderStyle::strokePaintColor, &RenderStyle::setStrokePaintColor),
new PropertyWrapper<float>(CSSPropertyStrokeOpacity, &RenderStyle::strokeOpacity, &RenderStyle::setStrokeOpacity),
- new PropertyWrapper<SVGLength>(CSSPropertyStrokeWidth, &RenderStyle::strokeWidth, &RenderStyle::setStrokeWidth),
- new PropertyWrapper< Vector<SVGLength>>(CSSPropertyStrokeDasharray, &RenderStyle::strokeDashArray, &RenderStyle::setStrokeDashArray),
- new PropertyWrapper<SVGLength>(CSSPropertyStrokeDashoffset, &RenderStyle::strokeDashOffset, &RenderStyle::setStrokeDashOffset),
+ new PropertyWrapper<Vector<SVGLengthValue>>(CSSPropertyStrokeDasharray, &RenderStyle::strokeDashArray, &RenderStyle::setStrokeDashArray),
new PropertyWrapper<float>(CSSPropertyStrokeMiterlimit, &RenderStyle::strokeMiterLimit, &RenderStyle::setStrokeMiterLimit),
+ new LengthPropertyWrapper<Length>(CSSPropertyCx, &RenderStyle::cx, &RenderStyle::setCx),
+ new LengthPropertyWrapper<Length>(CSSPropertyCy, &RenderStyle::cy, &RenderStyle::setCy),
+ new LengthPropertyWrapper<Length>(CSSPropertyR, &RenderStyle::r, &RenderStyle::setR),
+ new LengthPropertyWrapper<Length>(CSSPropertyRx, &RenderStyle::rx, &RenderStyle::setRx),
+ new LengthPropertyWrapper<Length>(CSSPropertyRy, &RenderStyle::ry, &RenderStyle::setRy),
+ new LengthPropertyWrapper<Length>(CSSPropertyStrokeDashoffset, &RenderStyle::strokeDashOffset, &RenderStyle::setStrokeDashOffset),
+ new LengthPropertyWrapper<Length>(CSSPropertyStrokeWidth, &RenderStyle::strokeWidth, &RenderStyle::setStrokeWidth),
+ new LengthPropertyWrapper<Length>(CSSPropertyX, &RenderStyle::x, &RenderStyle::setX),
+ new LengthPropertyWrapper<Length>(CSSPropertyY, &RenderStyle::y, &RenderStyle::setY),
+
new PropertyWrapper<float>(CSSPropertyFloodOpacity, &RenderStyle::floodOpacity, &RenderStyle::setFloodOpacity),
new PropertyWrapperMaybeInvalidColor(CSSPropertyFloodColor, &RenderStyle::floodColor, &RenderStyle::setFloodColor),
@@ -1287,8 +1474,10 @@ CSSPropertyAnimationWrapperMap::CSSPropertyAnimationWrapperMap()
new PropertyWrapperMaybeInvalidColor(CSSPropertyLightingColor, &RenderStyle::lightingColor, &RenderStyle::setLightingColor),
- new PropertyWrapper<SVGLength>(CSSPropertyBaselineShift, &RenderStyle::baselineShiftValue, &RenderStyle::setBaselineShiftValue),
- new PropertyWrapper<SVGLength>(CSSPropertyKerning, &RenderStyle::kerning, &RenderStyle::setKerning),
+ new PropertyWrapper<SVGLengthValue>(CSSPropertyBaselineShift, &RenderStyle::baselineShiftValue, &RenderStyle::setBaselineShiftValue),
+ new PropertyWrapper<SVGLengthValue>(CSSPropertyKerning, &RenderStyle::kerning, &RenderStyle::setKerning),
+#if ENABLE(VARIATION_FONTS)
+ new PropertyWrapperFontVariationSettings(CSSPropertyFontVariationSettings, &RenderStyle::fontVariationSettings, &RenderStyle::setFontVariationSettings),
#endif
};
const unsigned animatableLonghandPropertiesCount = WTF_ARRAY_LENGTH(animatableLonghandPropertyWrappers);
@@ -1311,9 +1500,9 @@ CSSPropertyAnimationWrapperMap::CSSPropertyAnimationWrapperMap()
CSSPropertyOutline,
CSSPropertyPadding,
CSSPropertyWebkitTextStroke,
- CSSPropertyWebkitColumnRule,
+ CSSPropertyColumnRule,
CSSPropertyWebkitBorderRadius,
- CSSPropertyWebkitTransformOrigin
+ CSSPropertyTransformOrigin
};
const unsigned animatableShorthandPropertiesCount = WTF_ARRAY_LENGTH(animatableShorthandProperties);
@@ -1323,7 +1512,7 @@ CSSPropertyAnimationWrapperMap::CSSPropertyAnimationWrapperMap()
//
// Compound properties that have components that should be animatable:
//
- // CSSPropertyWebkitColumns
+ // CSSPropertyColumns
// CSSPropertyWebkitBoxReflect
// Make sure unused slots have a value
@@ -1338,7 +1527,7 @@ CSSPropertyAnimationWrapperMap::CSSPropertyAnimationWrapperMap()
for (unsigned i = 0; i < animatableLonghandPropertiesCount; ++i) {
AnimationPropertyWrapperBase* wrapper = animatableLonghandPropertyWrappers[i];
- m_propertyWrappers.uncheckedAppend(adoptPtr(wrapper));
+ m_propertyWrappers.uncheckedAppend(std::unique_ptr<AnimationPropertyWrapperBase>(wrapper));
indexFromPropertyID(wrapper->property()) = i;
}
@@ -1359,7 +1548,7 @@ CSSPropertyAnimationWrapperMap::CSSPropertyAnimationWrapperMap()
longhandWrappers.uncheckedAppend(m_propertyWrappers[wrapperIndex].get());
}
- m_propertyWrappers.uncheckedAppend(adoptPtr(new ShorthandPropertyWrapper(propertyID, longhandWrappers)));
+ m_propertyWrappers.uncheckedAppend(std::make_unique<ShorthandPropertyWrapper>(propertyID, WTFMove(longhandWrappers)));
indexFromPropertyID(propertyID) = animatableLonghandPropertiesCount + i;
}
}
@@ -1370,11 +1559,8 @@ static bool gatherEnclosingShorthandProperties(CSSPropertyID property, Animation
return false;
ShorthandPropertyWrapper* shorthandWrapper = static_cast<ShorthandPropertyWrapper*>(wrapper);
-
bool contained = false;
- for (size_t i = 0; i < shorthandWrapper->propertyWrappers().size(); ++i) {
- AnimationPropertyWrapperBase* currWrapper = shorthandWrapper->propertyWrappers()[i];
-
+ for (auto& currWrapper : shorthandWrapper->propertyWrappers()) {
if (gatherEnclosingShorthandProperties(property, currWrapper, propertySet) || currWrapper->property() == property)
contained = true;
}
@@ -1390,31 +1576,27 @@ bool CSSPropertyAnimation::blendProperties(const AnimationBase* anim, CSSPropert
{
ASSERT(prop != CSSPropertyInvalid);
- AnimationPropertyWrapperBase* wrapper = CSSPropertyAnimationWrapperMap::instance().wrapperForProperty(prop);
+ AnimationPropertyWrapperBase* wrapper = CSSPropertyAnimationWrapperMap::singleton().wrapperForProperty(prop);
if (wrapper) {
wrapper->blend(anim, dst, a, b, progress);
-#if USE(ACCELERATED_COMPOSITING)
- return !wrapper->animationIsAccelerated() || !anim->isAccelerated();
-#else
- return true;
+#if !LOG_DISABLED
+ wrapper->logBlend(a, b, dst, progress);
#endif
+ return !wrapper->animationIsAccelerated() || !anim->isAccelerated();
}
-
return false;
}
-#if USE(ACCELERATED_COMPOSITING)
bool CSSPropertyAnimation::animationOfPropertyIsAccelerated(CSSPropertyID prop)
{
- AnimationPropertyWrapperBase* wrapper = CSSPropertyAnimationWrapperMap::instance().wrapperForProperty(prop);
+ AnimationPropertyWrapperBase* wrapper = CSSPropertyAnimationWrapperMap::singleton().wrapperForProperty(prop);
return wrapper ? wrapper->animationIsAccelerated() : false;
}
-#endif
// Note: this is inefficient. It's only called from pauseTransitionAtTime().
HashSet<CSSPropertyID> CSSPropertyAnimation::animatableShorthandsAffectingProperty(CSSPropertyID property)
{
- CSSPropertyAnimationWrapperMap& map = CSSPropertyAnimationWrapperMap::instance();
+ CSSPropertyAnimationWrapperMap& map = CSSPropertyAnimationWrapperMap::singleton();
HashSet<CSSPropertyID> foundProperties;
for (unsigned i = 0; i < map.size(); ++i)
@@ -1425,7 +1607,7 @@ HashSet<CSSPropertyID> CSSPropertyAnimation::animatableShorthandsAffectingProper
bool CSSPropertyAnimation::propertiesEqual(CSSPropertyID prop, const RenderStyle* a, const RenderStyle* b)
{
- AnimationPropertyWrapperBase* wrapper = CSSPropertyAnimationWrapperMap::instance().wrapperForProperty(prop);
+ AnimationPropertyWrapperBase* wrapper = CSSPropertyAnimationWrapperMap::singleton().wrapperForProperty(prop);
if (wrapper)
return wrapper->equals(a, b);
return true;
@@ -1433,7 +1615,7 @@ bool CSSPropertyAnimation::propertiesEqual(CSSPropertyID prop, const RenderStyle
CSSPropertyID CSSPropertyAnimation::getPropertyAtIndex(int i, bool& isShorthand)
{
- CSSPropertyAnimationWrapperMap& map = CSSPropertyAnimationWrapperMap::instance();
+ CSSPropertyAnimationWrapperMap& map = CSSPropertyAnimationWrapperMap::singleton();
if (i < 0 || static_cast<unsigned>(i) >= map.size())
return CSSPropertyInvalid;
@@ -1445,7 +1627,7 @@ CSSPropertyID CSSPropertyAnimation::getPropertyAtIndex(int i, bool& isShorthand)
int CSSPropertyAnimation::getNumProperties()
{
- return CSSPropertyAnimationWrapperMap::instance().size();
+ return CSSPropertyAnimationWrapperMap::singleton().size();
}
}
diff --git a/Source/WebCore/page/animation/CSSPropertyAnimation.h b/Source/WebCore/page/animation/CSSPropertyAnimation.h
index c41c7dd90..98ec9a154 100644
--- a/Source/WebCore/page/animation/CSSPropertyAnimation.h
+++ b/Source/WebCore/page/animation/CSSPropertyAnimation.h
@@ -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.
*
@@ -26,8 +26,7 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef CSSPropertyAnimation_h
-#define CSSPropertyAnimation_h
+#pragma once
#include "CSSPropertyNames.h"
#include "RenderStyleConstants.h"
@@ -40,9 +39,7 @@ class RenderStyle;
class CSSPropertyAnimation {
public:
-#if USE(ACCELERATED_COMPOSITING)
static bool animationOfPropertyIsAccelerated(CSSPropertyID);
-#endif
static bool propertiesEqual(CSSPropertyID, const RenderStyle* a, const RenderStyle* b);
static CSSPropertyID getPropertyAtIndex(int, bool& isShorthand);
static int getNumProperties();
@@ -54,5 +51,3 @@ public:
};
} // namespace WebCore
-
-#endif // CSSPropertyAnimation_h
diff --git a/Source/WebCore/page/animation/CompositeAnimation.cpp b/Source/WebCore/page/animation/CompositeAnimation.cpp
index e18779ea7..f89f1e514 100644
--- a/Source/WebCore/page/animation/CompositeAnimation.cpp
+++ b/Source/WebCore/page/animation/CompositeAnimation.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,7 +29,7 @@
#include "config.h"
#include "CompositeAnimation.h"
-#include "AnimationControllerPrivate.h"
+#include "CSSAnimationControllerPrivate.h"
#include "CSSPropertyAnimation.h"
#include "CSSPropertyNames.h"
#include "ImplicitAnimation.h"
@@ -37,14 +37,15 @@
#include "Logging.h"
#include "RenderElement.h"
#include "RenderStyle.h"
+#include <wtf/NeverDestroyed.h>
#include <wtf/text/CString.h>
namespace WebCore {
-CompositeAnimation::CompositeAnimation(AnimationControllerPrivate* animationController)
+CompositeAnimation::CompositeAnimation(CSSAnimationControllerPrivate& animationController)
: m_animationController(animationController)
{
- m_suspended = animationController->isSuspended() && !animationController->allowsNewAnimationsWhileSuspended();
+ m_suspended = m_animationController.isSuspended() && !m_animationController.allowsNewAnimationsWhileSuspended();
}
CompositeAnimation::~CompositeAnimation()
@@ -62,25 +63,21 @@ void CompositeAnimation::clearRenderer()
if (!m_transitions.isEmpty()) {
// Clear the renderers from all running animations, in case we are in the middle of
// an animation callback (see https://bugs.webkit.org/show_bug.cgi?id=22052)
- CSSPropertyTransitionsMap::const_iterator transitionsEnd = m_transitions.end();
- for (CSSPropertyTransitionsMap::const_iterator it = m_transitions.begin(); it != transitionsEnd; ++it) {
- ImplicitAnimation* transition = it->value.get();
- animationController()->animationWillBeRemoved(transition);
+ for (auto& transition : m_transitions.values()) {
+ animationController().animationWillBeRemoved(transition.get());
transition->clear();
}
}
if (!m_keyframeAnimations.isEmpty()) {
m_keyframeAnimations.checkConsistency();
- AnimationNameMap::const_iterator animationsEnd = m_keyframeAnimations.end();
- for (AnimationNameMap::const_iterator it = m_keyframeAnimations.begin(); it != animationsEnd; ++it) {
- KeyframeAnimation* anim = it->value.get();
- animationController()->animationWillBeRemoved(anim);
- anim->clear();
+ for (auto& animation : m_keyframeAnimations.values()) {
+ animationController().animationWillBeRemoved(animation.get());
+ animation->clear();
}
}
}
-void CompositeAnimation::updateTransitions(RenderElement* renderer, RenderStyle* currentStyle, RenderStyle* targetStyle)
+void CompositeAnimation::updateTransitions(RenderElement* renderer, const RenderStyle* currentStyle, const RenderStyle* targetStyle)
{
// If currentStyle is null or there are no old or new transitions, just skip it
if (!currentStyle || (!targetStyle->transitions() && m_transitions.isEmpty()))
@@ -88,20 +85,19 @@ void CompositeAnimation::updateTransitions(RenderElement* renderer, RenderStyle*
// Mark all existing transitions as no longer active. We will mark the still active ones
// in the next loop and then toss the ones that didn't get marked.
- CSSPropertyTransitionsMap::const_iterator end = m_transitions.end();
- for (CSSPropertyTransitionsMap::const_iterator it = m_transitions.begin(); it != end; ++it)
- it->value->setActive(false);
+ for (auto& transition : m_transitions.values())
+ transition->setActive(false);
- RefPtr<RenderStyle> modifiedCurrentStyle;
+ std::unique_ptr<RenderStyle> modifiedCurrentStyle;
// Check to see if we need to update the active transitions
if (targetStyle->transitions()) {
for (size_t i = 0; i < targetStyle->transitions()->size(); ++i) {
- const Animation& animation = targetStyle->transitions()->animation(i);
+ auto& animation = targetStyle->transitions()->animation(i);
bool isActiveTransition = !m_suspended && (animation.duration() || animation.delay() > 0);
Animation::AnimationMode mode = animation.animationMode();
- if (mode == Animation::AnimateNone)
+ if (mode == Animation::AnimateNone || mode == Animation::AnimateUnknownProperty)
continue;
CSSPropertyID prop = animation.property();
@@ -125,8 +121,8 @@ void CompositeAnimation::updateTransitions(RenderElement* renderer, RenderStyle*
// If there is a running animation for this property, the transition is overridden
// and we have to use the unanimatedStyle from the animation. We do the test
// against the unanimated style here, but we "override" the transition later.
- RefPtr<KeyframeAnimation> keyframeAnim = getAnimationForProperty(prop);
- RenderStyle* fromStyle = keyframeAnim ? keyframeAnim->unanimatedStyle() : currentStyle;
+ auto* keyframeAnimation = animationForProperty(prop);
+ auto* fromStyle = keyframeAnimation ? keyframeAnimation->unanimatedStyle() : currentStyle;
// See if there is a current transition for this prop
ImplicitAnimation* implAnim = m_transitions.get(prop);
@@ -148,18 +144,16 @@ void CompositeAnimation::updateTransitions(RenderElement* renderer, RenderStyle*
// list. In this case, the latter one overrides the earlier one, so we
// behave as though this is a running animation being replaced.
if (!implAnim->isTargetPropertyEqual(prop, targetStyle)) {
-#if USE(ACCELERATED_COMPOSITING)
// For accelerated animations we need to return a new RenderStyle with the _current_ value
// of the property, so that restarted transitions use the correct starting point.
if (CSSPropertyAnimation::animationOfPropertyIsAccelerated(prop) && implAnim->isAccelerated()) {
if (!modifiedCurrentStyle)
- modifiedCurrentStyle = RenderStyle::clone(currentStyle);
+ modifiedCurrentStyle = RenderStyle::clonePtr(*currentStyle);
implAnim->blendPropertyValueInStyle(prop, modifiedCurrentStyle.get());
}
-#endif
LOG(Animations, "Removing existing ImplicitAnimation %p for property %s", implAnim, getPropertyName(prop));
- animationController()->animationWillBeRemoved(implAnim);
+ animationController().animationWillBeRemoved(implAnim);
m_transitions.remove(prop);
equal = false;
}
@@ -174,11 +168,11 @@ void CompositeAnimation::updateTransitions(RenderElement* renderer, RenderStyle*
// <https://bugs.webkit.org/show_bug.cgi?id=24787>
if (!equal && isActiveTransition) {
// Add the new transition
- RefPtr<ImplicitAnimation> implicitAnimation = ImplicitAnimation::create(animation, prop, renderer, this, modifiedCurrentStyle ? modifiedCurrentStyle.get() : fromStyle);
- LOG(Animations, "Created ImplicitAnimation %p for property %s duration %.2f delay %.2f", implicitAnimation.get(), getPropertyName(prop), animation.duration(), animation.delay());
- m_transitions.set(prop, implicitAnimation.release());
+ auto implicitAnimation = ImplicitAnimation::create(animation, prop, renderer, this, modifiedCurrentStyle ? modifiedCurrentStyle.get() : fromStyle);
+ LOG(Animations, "Created ImplicitAnimation %p on renderer %p for property %s duration %.2f delay %.2f", implicitAnimation.ptr(), renderer, getPropertyName(prop), animation.duration(), animation.delay());
+ m_transitions.set(prop, WTFMove(implicitAnimation));
}
-
+
// We only need one pass for the single prop case
if (!all)
break;
@@ -188,158 +182,184 @@ void CompositeAnimation::updateTransitions(RenderElement* renderer, RenderStyle*
// Make a list of transitions to be removed
Vector<int> toBeRemoved;
- end = m_transitions.end();
- for (CSSPropertyTransitionsMap::const_iterator it = m_transitions.begin(); it != end; ++it) {
- ImplicitAnimation* anim = it->value.get();
- if (!anim->active()) {
- animationController()->animationWillBeRemoved(anim);
- toBeRemoved.append(anim->animatingProperty());
- LOG(Animations, "Removing ImplicitAnimation %p for property %s", anim, getPropertyName(anim->animatingProperty()));
+ for (auto& transition : m_transitions.values()) {
+ if (!transition->active()) {
+ animationController().animationWillBeRemoved(transition.get());
+ toBeRemoved.append(transition->animatingProperty());
+ LOG(Animations, "Removing ImplicitAnimation %p from renderer %p for property %s", transition.get(), renderer, getPropertyName(transition->animatingProperty()));
}
}
// Now remove the transitions from the list
- for (size_t j = 0; j < toBeRemoved.size(); ++j)
- m_transitions.remove(toBeRemoved[j]);
+ for (auto propertyToRemove : toBeRemoved)
+ m_transitions.remove(propertyToRemove);
}
-void CompositeAnimation::updateKeyframeAnimations(RenderElement* renderer, RenderStyle* currentStyle, RenderStyle* targetStyle)
+void CompositeAnimation::updateKeyframeAnimations(RenderElement* renderer, const RenderStyle* currentStyle, const RenderStyle* targetStyle)
{
// Nothing to do if we don't have any animations, and didn't have any before
if (m_keyframeAnimations.isEmpty() && !targetStyle->hasAnimations())
return;
m_keyframeAnimations.checkConsistency();
+
+ if (currentStyle && currentStyle->hasAnimations() && targetStyle->hasAnimations() && *(currentStyle->animations()) == *(targetStyle->animations()))
+ return;
+
+#if ENABLE(CSS_ANIMATIONS_LEVEL_2)
+ m_hasScrollTriggeredAnimation = false;
+#endif
+
+ AnimationNameMap newAnimations;
+
+ // Toss the animation order map.
+ m_keyframeAnimationOrderMap.clear();
- AnimationNameMap::const_iterator kfend = m_keyframeAnimations.end();
+ static NeverDestroyed<const AtomicString> none("none", AtomicString::ConstructFromLiteral);
- if (currentStyle && currentStyle->hasAnimations() && targetStyle->hasAnimations() && *(currentStyle->animations()) == *(targetStyle->animations())) {
- // The current and target animations are the same so we just need to toss any
- // animation which is finished (postActive).
- for (AnimationNameMap::const_iterator it = m_keyframeAnimations.begin(); it != kfend; ++it) {
- if (it->value->postActive())
- it->value->setIndex(-1);
- }
- } else {
- // Mark all existing animations as no longer active.
- for (AnimationNameMap::const_iterator it = m_keyframeAnimations.begin(); it != kfend; ++it)
- it->value->setIndex(-1);
+ // Now mark any still active animations as active and add any new animations.
+ if (targetStyle->animations()) {
+ int numAnims = targetStyle->animations()->size();
+ for (int i = 0; i < numAnims; ++i) {
+ auto& animation = targetStyle->animations()->animation(i);
+ AtomicString animationName(animation.name());
+
+ if (!animation.isValidAnimation())
+ continue;
- // Toss the animation order map.
- m_keyframeAnimationOrderMap.clear();
+ // See if there is a current animation for this name.
+ RefPtr<KeyframeAnimation> keyframeAnim = m_keyframeAnimations.get(animationName.impl());
+ if (keyframeAnim) {
+ newAnimations.add(keyframeAnim->name().impl(), keyframeAnim);
- DEFINE_STATIC_LOCAL(const AtomicString, none, ("none", AtomicString::ConstructFromLiteral));
-
- // Now mark any still active animations as active and add any new animations.
- if (targetStyle->animations()) {
- int numAnims = targetStyle->animations()->size();
- for (int i = 0; i < numAnims; ++i) {
- const Animation& animation = targetStyle->animations()->animation(i);
- AtomicString animationName(animation.name());
-
- if (!animation.isValidAnimation())
+ if (keyframeAnim->postActive())
continue;
-
- // See if there is a current animation for this name.
- RefPtr<KeyframeAnimation> keyframeAnim = m_keyframeAnimations.get(animationName.impl());
-
- if (keyframeAnim) {
- // If this animation is postActive, skip it so it gets removed at the end of this function.
- if (keyframeAnim->postActive())
- continue;
-
- // This one is still active.
-
- // Animations match, but play states may differ. Update if needed.
- keyframeAnim->updatePlayState(animation.playState());
-
- // Set the saved animation to this new one, just in case the play state has changed.
- keyframeAnim->setAnimation(animation);
- keyframeAnim->setIndex(i);
- } else if ((animation.duration() || animation.delay()) && animation.iterationCount() && animationName != none) {
- keyframeAnim = KeyframeAnimation::create(animation, renderer, i, this, targetStyle);
- LOG(Animations, "Creating KeyframeAnimation %p with keyframes %s, duration %.2f, delay %.2f, iterations %.2f", keyframeAnim.get(), animation.name().utf8().data(), animation.duration(), animation.delay(), animation.iterationCount());
- if (m_suspended) {
- keyframeAnim->updatePlayState(AnimPlayStatePaused);
- LOG(Animations, " (created in suspended/paused state)");
- }
-#if !LOG_DISABLED
- for (auto it = keyframeAnim->keyframes().beginProperties(), end = keyframeAnim->keyframes().endProperties(); it != end; ++it)
- LOG(Animations, " property %s", getPropertyName(*it));
+
+#if ENABLE(CSS_ANIMATIONS_LEVEL_2)
+ if (animation.trigger()->isScrollAnimationTrigger())
+ m_hasScrollTriggeredAnimation = true;
#endif
- m_keyframeAnimations.set(keyframeAnim->name().impl(), keyframeAnim);
+
+ // Animations match, but play states may differ. Update if needed.
+ keyframeAnim->updatePlayState(animation.playState());
+
+ // Set the saved animation to this new one, just in case the play state has changed.
+ keyframeAnim->setAnimation(animation);
+ } else if ((animation.duration() || animation.delay()) && animation.iterationCount() && animationName != none) {
+ keyframeAnim = KeyframeAnimation::create(animation, renderer, this, targetStyle);
+ LOG(Animations, "Creating KeyframeAnimation %p on renderer %p with keyframes %s, duration %.2f, delay %.2f, iterations %.2f", keyframeAnim.get(), renderer, animation.name().utf8().data(), animation.duration(), animation.delay(), animation.iterationCount());
+
+ if (m_suspended) {
+ keyframeAnim->updatePlayState(AnimPlayStatePaused);
+ LOG(Animations, " (created in suspended/paused state)");
}
-
- // Add this to the animation order map.
- if (keyframeAnim)
- m_keyframeAnimationOrderMap.append(keyframeAnim->name().impl());
+#if !LOG_DISABLED
+ for (auto propertyID : keyframeAnim->keyframes().properties())
+ LOG(Animations, " property %s", getPropertyName(propertyID));
+#endif
+
+#if ENABLE(CSS_ANIMATIONS_LEVEL_2)
+ if (animation.trigger()->isScrollAnimationTrigger())
+ m_hasScrollTriggeredAnimation = true;
+#endif
+
+ newAnimations.set(keyframeAnim->name().impl(), keyframeAnim);
}
+
+ // Add this to the animation order map.
+ if (keyframeAnim)
+ m_keyframeAnimationOrderMap.append(keyframeAnim->name().impl());
}
}
// Make a list of animations to be removed.
- Vector<AtomicStringImpl*> animsToBeRemoved;
- kfend = m_keyframeAnimations.end();
- for (AnimationNameMap::const_iterator it = m_keyframeAnimations.begin(); it != kfend; ++it) {
- KeyframeAnimation* keyframeAnim = it->value.get();
- if (keyframeAnim->index() < 0) {
- animsToBeRemoved.append(keyframeAnim->name().impl());
- animationController()->animationWillBeRemoved(keyframeAnim);
- keyframeAnim->clear();
- LOG(Animations, "Removing KeyframeAnimation %p", keyframeAnim);
+ for (auto& animation : m_keyframeAnimations.values()) {
+ if (!newAnimations.contains(animation->name().impl())) {
+ animationController().animationWillBeRemoved(animation.get());
+ animation->clear();
+ LOG(Animations, "Removing KeyframeAnimation %p from renderer %p", animation.get(), renderer);
}
}
- // Now remove the animations from the list.
- for (size_t j = 0; j < animsToBeRemoved.size(); ++j)
- m_keyframeAnimations.remove(animsToBeRemoved[j]);
+ std::swap(newAnimations, m_keyframeAnimations);
}
-PassRef<RenderStyle> CompositeAnimation::animate(RenderElement& renderer, RenderStyle* currentStyle, RenderStyle& targetStyle)
+bool CompositeAnimation::animate(RenderElement& renderer, const RenderStyle* currentStyle, const RenderStyle& targetStyle, std::unique_ptr<RenderStyle>& blendedStyle)
{
- RefPtr<RenderStyle> resultStyle;
-
// We don't do any transitions if we don't have a currentStyle (on startup).
updateTransitions(&renderer, currentStyle, &targetStyle);
updateKeyframeAnimations(&renderer, currentStyle, &targetStyle);
m_keyframeAnimations.checkConsistency();
+ bool animationStateChanged = false;
+ bool forceStackingContext = false;
+
if (currentStyle) {
// Now that we have transition objects ready, let them know about the new goal state. We want them
// to fill in a RenderStyle*& only if needed.
- if (!m_transitions.isEmpty()) {
- CSSPropertyTransitionsMap::const_iterator end = m_transitions.end();
- for (CSSPropertyTransitionsMap::const_iterator it = m_transitions.begin(); it != end; ++it) {
- if (ImplicitAnimation* anim = it->value.get())
- anim->animate(this, &renderer, currentStyle, &targetStyle, resultStyle);
- }
+ bool checkForStackingContext = false;
+ for (auto& transition : m_transitions.values()) {
+ bool didBlendStyle = false;
+ if (transition->animate(this, &renderer, currentStyle, &targetStyle, blendedStyle, didBlendStyle))
+ animationStateChanged = true;
+
+ if (didBlendStyle)
+ checkForStackingContext |= WillChangeData::propertyCreatesStackingContext(transition->animatingProperty());
+ }
+
+ if (blendedStyle && checkForStackingContext) {
+ // Note that this is similar to code in StyleResolver::adjustRenderStyle() but only needs to consult
+ // animatable properties that can trigger stacking context.
+ if (blendedStyle->opacity() < 1.0f
+ || blendedStyle->hasTransformRelatedProperty()
+ || blendedStyle->hasMask()
+ || blendedStyle->clipPath()
+ || blendedStyle->boxReflect()
+ || blendedStyle->hasFilter()
+#if ENABLE(FILTERS_LEVEL_2)
+ || blendedStyle->hasBackdropFilter()
+#endif
+ )
+ forceStackingContext = true;
}
}
// Now that we have animation objects ready, let them know about the new goal state. We want them
// to fill in a RenderStyle*& only if needed.
- for (Vector<AtomicStringImpl*>::const_iterator it = m_keyframeAnimationOrderMap.begin(); it != m_keyframeAnimationOrderMap.end(); ++it) {
- RefPtr<KeyframeAnimation> keyframeAnim = m_keyframeAnimations.get(*it);
- if (keyframeAnim)
- keyframeAnim->animate(this, &renderer, currentStyle, &targetStyle, resultStyle);
+ for (auto& name : m_keyframeAnimationOrderMap) {
+ RefPtr<KeyframeAnimation> keyframeAnim = m_keyframeAnimations.get(name);
+ if (keyframeAnim) {
+ bool didBlendStyle = false;
+ if (keyframeAnim->animate(this, &renderer, currentStyle, &targetStyle, blendedStyle, didBlendStyle))
+ animationStateChanged = true;
+
+ forceStackingContext |= didBlendStyle && keyframeAnim->triggersStackingContext();
+ m_hasAnimationThatDependsOnLayout |= keyframeAnim->dependsOnLayout();
+ }
}
- return resultStyle ? resultStyle.releaseNonNull() : targetStyle;
+ // https://drafts.csswg.org/css-animations-1/
+ // While an animation is applied but has not finished, or has finished but has an animation-fill-mode of forwards or both,
+ // the user agent must act as if the will-change property ([css-will-change-1]) on the element additionally
+ // includes all the properties animated by the animation.
+ if (forceStackingContext && blendedStyle) {
+ if (blendedStyle->hasAutoZIndex())
+ blendedStyle->setZIndex(0);
+ }
+
+ return animationStateChanged;
}
-PassRefPtr<RenderStyle> CompositeAnimation::getAnimatedStyle() const
+std::unique_ptr<RenderStyle> CompositeAnimation::getAnimatedStyle() const
{
- RefPtr<RenderStyle> resultStyle;
- CSSPropertyTransitionsMap::const_iterator end = m_transitions.end();
- for (CSSPropertyTransitionsMap::const_iterator it = m_transitions.begin(); it != end; ++it) {
- if (ImplicitAnimation* implicitAnimation = it->value.get())
- implicitAnimation->getAnimatedStyle(resultStyle);
- }
+ std::unique_ptr<RenderStyle> resultStyle;
+ for (auto& transition : m_transitions.values())
+ transition->getAnimatedStyle(resultStyle);
m_keyframeAnimations.checkConsistency();
- for (Vector<AtomicStringImpl*>::const_iterator it = m_keyframeAnimationOrderMap.begin(); it != m_keyframeAnimationOrderMap.end(); ++it) {
- RefPtr<KeyframeAnimation> keyframeAnimation = m_keyframeAnimations.get(*it);
+ for (auto& name : m_keyframeAnimationOrderMap) {
+ RefPtr<KeyframeAnimation> keyframeAnimation = m_keyframeAnimations.get(name);
if (keyframeAnimation)
keyframeAnimation->getAnimatedStyle(resultStyle);
}
@@ -354,10 +374,10 @@ double CompositeAnimation::timeToNextService() const
double minT = -1;
if (!m_transitions.isEmpty()) {
- CSSPropertyTransitionsMap::const_iterator transitionsEnd = m_transitions.end();
- for (CSSPropertyTransitionsMap::const_iterator it = m_transitions.begin(); it != transitionsEnd; ++it) {
- ImplicitAnimation* transition = it->value.get();
- double t = transition ? transition->timeToNextService() : -1;
+ for (auto& transition : m_transitions.values()) {
+ double t = transition->timeToNextService();
+ if (t == -1)
+ continue;
if (t < minT || minT == -1)
minT = t;
if (minT == 0)
@@ -366,10 +386,10 @@ double CompositeAnimation::timeToNextService() const
}
if (!m_keyframeAnimations.isEmpty()) {
m_keyframeAnimations.checkConsistency();
- AnimationNameMap::const_iterator animationsEnd = m_keyframeAnimations.end();
- for (AnimationNameMap::const_iterator it = m_keyframeAnimations.begin(); it != animationsEnd; ++it) {
- KeyframeAnimation* animation = it->value.get();
- double t = animation ? animation->timeToNextService() : -1;
+ for (auto& animation : m_keyframeAnimations.values()) {
+ double t = animation->timeToNextService();
+ if (t == -1)
+ continue;
if (t < minT || minT == -1)
minT = t;
if (minT == 0)
@@ -380,23 +400,53 @@ double CompositeAnimation::timeToNextService() const
return minT;
}
-PassRefPtr<KeyframeAnimation> CompositeAnimation::getAnimationForProperty(CSSPropertyID property) const
+KeyframeAnimation* CompositeAnimation::animationForProperty(CSSPropertyID property) const
{
- RefPtr<KeyframeAnimation> retval;
-
+ KeyframeAnimation* result = nullptr;
+
// We want to send back the last animation with the property if there are multiples.
// So we need to iterate through all animations
if (!m_keyframeAnimations.isEmpty()) {
m_keyframeAnimations.checkConsistency();
- AnimationNameMap::const_iterator animationsEnd = m_keyframeAnimations.end();
- for (AnimationNameMap::const_iterator it = m_keyframeAnimations.begin(); it != animationsEnd; ++it) {
- RefPtr<KeyframeAnimation> anim = it->value;
- if (anim->hasAnimationForProperty(property))
- retval = anim;
+ for (auto& animation : m_keyframeAnimations.values()) {
+ if (animation->hasAnimationForProperty(property))
+ result = animation.get();
}
}
+
+ return result;
+}
+
+bool CompositeAnimation::computeExtentOfTransformAnimation(LayoutRect& bounds) const
+{
+ // If more than one transition and animation affect transform, give up.
+ bool seenTransformAnimation = false;
+
+ for (auto& animation : m_keyframeAnimations.values()) {
+ if (!animation->hasAnimationForProperty(CSSPropertyTransform))
+ continue;
+
+ if (seenTransformAnimation)
+ return false;
+
+ seenTransformAnimation = true;
+
+ if (!animation->computeExtentOfTransformAnimation(bounds))
+ return false;
+ }
+
+ for (auto& transition : m_transitions.values()) {
+ if (transition->animatingProperty() != CSSPropertyTransform || !transition->hasStyle())
+ continue;
+
+ if (seenTransformAnimation)
+ return false;
+
+ if (!transition->computeExtentOfTransformAnimation(bounds))
+ return false;
+ }
- return retval;
+ return true;
}
void CompositeAnimation::suspendAnimations()
@@ -408,18 +458,14 @@ void CompositeAnimation::suspendAnimations()
if (!m_keyframeAnimations.isEmpty()) {
m_keyframeAnimations.checkConsistency();
- AnimationNameMap::const_iterator animationsEnd = m_keyframeAnimations.end();
- for (AnimationNameMap::const_iterator it = m_keyframeAnimations.begin(); it != animationsEnd; ++it) {
- if (KeyframeAnimation* anim = it->value.get())
- anim->updatePlayState(AnimPlayStatePaused);
- }
+ for (auto& animation : m_keyframeAnimations.values())
+ animation->updatePlayState(AnimPlayStatePaused);
}
+
if (!m_transitions.isEmpty()) {
- CSSPropertyTransitionsMap::const_iterator transitionsEnd = m_transitions.end();
- for (CSSPropertyTransitionsMap::const_iterator it = m_transitions.begin(); it != transitionsEnd; ++it) {
- ImplicitAnimation* anim = it->value.get();
- if (anim && anim->hasStyle())
- anim->updatePlayState(AnimPlayStatePaused);
+ for (auto& transition : m_transitions.values()) {
+ if (transition->hasStyle())
+ transition->updatePlayState(AnimPlayStatePaused);
}
}
}
@@ -433,32 +479,26 @@ void CompositeAnimation::resumeAnimations()
if (!m_keyframeAnimations.isEmpty()) {
m_keyframeAnimations.checkConsistency();
- AnimationNameMap::const_iterator animationsEnd = m_keyframeAnimations.end();
- for (AnimationNameMap::const_iterator it = m_keyframeAnimations.begin(); it != animationsEnd; ++it) {
- KeyframeAnimation* anim = it->value.get();
- if (anim && anim->playStatePlaying())
- anim->updatePlayState(AnimPlayStatePlaying);
+ for (auto& animation : m_keyframeAnimations.values()) {
+ if (animation->playStatePlaying())
+ animation->updatePlayState(AnimPlayStatePlaying);
}
}
if (!m_transitions.isEmpty()) {
- CSSPropertyTransitionsMap::const_iterator transitionsEnd = m_transitions.end();
- for (CSSPropertyTransitionsMap::const_iterator it = m_transitions.begin(); it != transitionsEnd; ++it) {
- ImplicitAnimation* anim = it->value.get();
- if (anim && anim->hasStyle())
- anim->updatePlayState(AnimPlayStatePlaying);
+ for (auto& transition : m_transitions.values()) {
+ if (transition->hasStyle())
+ transition->updatePlayState(AnimPlayStatePlaying);
}
}
}
void CompositeAnimation::overrideImplicitAnimations(CSSPropertyID property)
{
- CSSPropertyTransitionsMap::const_iterator end = m_transitions.end();
if (!m_transitions.isEmpty()) {
- for (CSSPropertyTransitionsMap::const_iterator it = m_transitions.begin(); it != end; ++it) {
- ImplicitAnimation* anim = it->value.get();
- if (anim && anim->animatingProperty() == property)
- anim->setOverridden(true);
+ for (auto& transition : m_transitions.values()) {
+ if (transition->animatingProperty() == property)
+ transition->setOverridden(true);
}
}
}
@@ -466,32 +506,26 @@ void CompositeAnimation::overrideImplicitAnimations(CSSPropertyID property)
void CompositeAnimation::resumeOverriddenImplicitAnimations(CSSPropertyID property)
{
if (!m_transitions.isEmpty()) {
- CSSPropertyTransitionsMap::const_iterator end = m_transitions.end();
- for (CSSPropertyTransitionsMap::const_iterator it = m_transitions.begin(); it != end; ++it) {
- ImplicitAnimation* anim = it->value.get();
- if (anim && anim->animatingProperty() == property)
- anim->setOverridden(false);
+ for (auto& transition : m_transitions.values()) {
+ if (transition->animatingProperty() == property)
+ transition->setOverridden(false);
}
}
}
-bool CompositeAnimation::isAnimatingProperty(CSSPropertyID property, bool acceleratedOnly, bool isRunningNow) const
+bool CompositeAnimation::isAnimatingProperty(CSSPropertyID property, bool acceleratedOnly, AnimationBase::RunningState runningState) const
{
if (!m_keyframeAnimations.isEmpty()) {
m_keyframeAnimations.checkConsistency();
- AnimationNameMap::const_iterator animationsEnd = m_keyframeAnimations.end();
- for (AnimationNameMap::const_iterator it = m_keyframeAnimations.begin(); it != animationsEnd; ++it) {
- KeyframeAnimation* anim = it->value.get();
- if (anim && anim->isAnimatingProperty(property, acceleratedOnly, isRunningNow))
+ for (auto& animation : m_keyframeAnimations.values()) {
+ if (animation->isAnimatingProperty(property, acceleratedOnly, runningState))
return true;
}
}
if (!m_transitions.isEmpty()) {
- CSSPropertyTransitionsMap::const_iterator transitionsEnd = m_transitions.end();
- for (CSSPropertyTransitionsMap::const_iterator it = m_transitions.begin(); it != transitionsEnd; ++it) {
- ImplicitAnimation* anim = it->value.get();
- if (anim && anim->isAnimatingProperty(property, acceleratedOnly, isRunningNow))
+ for (auto& transition : m_transitions.values()) {
+ if (transition->isAnimatingProperty(property, acceleratedOnly, runningState))
return true;
}
}
@@ -506,13 +540,8 @@ bool CompositeAnimation::pauseAnimationAtTime(const AtomicString& name, double t
if (!keyframeAnim || !keyframeAnim->running())
return false;
- double count = keyframeAnim->m_animation->iterationCount();
- if ((t >= 0.0) && ((count == Animation::IterationCountInfinite) || (t <= count * keyframeAnim->duration()))) {
- keyframeAnim->freezeAtTime(t);
- return true;
- }
-
- return false;
+ keyframeAnim->freezeAtTime(t);
+ return true;
}
bool CompositeAnimation::pauseTransitionAtTime(CSSPropertyID property, double t)
@@ -526,9 +555,8 @@ bool CompositeAnimation::pauseTransitionAtTime(CSSPropertyID property, double t)
// This code is only used for testing, so performance is not critical here.
HashSet<CSSPropertyID> shorthandProperties = CSSPropertyAnimation::animatableShorthandsAffectingProperty(property);
bool anyPaused = false;
- HashSet<CSSPropertyID>::const_iterator end = shorthandProperties.end();
- for (HashSet<CSSPropertyID>::const_iterator it = shorthandProperties.begin(); it != end; ++it) {
- if (pauseTransitionAtTime(*it, t))
+ for (auto propertyID : shorthandProperties) {
+ if (pauseTransitionAtTime(propertyID, t))
anyPaused = true;
}
return anyPaused;
@@ -549,23 +577,15 @@ unsigned CompositeAnimation::numberOfActiveAnimations() const
{
unsigned count = 0;
- if (!m_keyframeAnimations.isEmpty()) {
- m_keyframeAnimations.checkConsistency();
- AnimationNameMap::const_iterator animationsEnd = m_keyframeAnimations.end();
- for (AnimationNameMap::const_iterator it = m_keyframeAnimations.begin(); it != animationsEnd; ++it) {
- KeyframeAnimation* anim = it->value.get();
- if (anim->running())
- ++count;
- }
+ m_keyframeAnimations.checkConsistency();
+ for (auto& animation : m_keyframeAnimations.values()) {
+ if (animation->running())
+ ++count;
}
- if (!m_transitions.isEmpty()) {
- CSSPropertyTransitionsMap::const_iterator transitionsEnd = m_transitions.end();
- for (CSSPropertyTransitionsMap::const_iterator it = m_transitions.begin(); it != transitionsEnd; ++it) {
- ImplicitAnimation* anim = it->value.get();
- if (anim->running())
- ++count;
- }
+ for (auto& transition : m_transitions.values()) {
+ if (transition->running())
+ ++count;
}
return count;
diff --git a/Source/WebCore/page/animation/CompositeAnimation.h b/Source/WebCore/page/animation/CompositeAnimation.h
index 48c679ef2..715de586d 100644
--- a/Source/WebCore/page/animation/CompositeAnimation.h
+++ b/Source/WebCore/page/animation/CompositeAnimation.h
@@ -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.
*
@@ -26,8 +26,7 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef CompositeAnimation_h
-#define CompositeAnimation_h
+#pragma once
#include "ImplicitAnimation.h"
#include "KeyframeAnimation.h"
@@ -37,30 +36,32 @@
namespace WebCore {
-class AnimationControllerPrivate;
-class AnimationController;
+class CSSAnimationControllerPrivate;
+class CSSAnimationController;
class RenderElement;
class RenderStyle;
// A CompositeAnimation represents a collection of animations that are running
// on a single RenderElement, such as a number of properties transitioning at once.
class CompositeAnimation : public RefCounted<CompositeAnimation> {
+ WTF_MAKE_FAST_ALLOCATED;
public:
- static PassRefPtr<CompositeAnimation> create(AnimationControllerPrivate* animationController)
+ static Ref<CompositeAnimation> create(CSSAnimationControllerPrivate& animationController)
{
- return adoptRef(new CompositeAnimation(animationController));
+ return adoptRef(*new CompositeAnimation(animationController));
};
~CompositeAnimation();
void clearRenderer();
- PassRef<RenderStyle> animate(RenderElement&, RenderStyle* currentStyle, RenderStyle& targetStyle);
- PassRefPtr<RenderStyle> getAnimatedStyle() const;
+ bool animate(RenderElement&, const RenderStyle* currentStyle, const RenderStyle& targetStyle, std::unique_ptr<RenderStyle>& blendedStyle);
+ std::unique_ptr<RenderStyle> getAnimatedStyle() const;
+ bool computeExtentOfTransformAnimation(LayoutRect&) const;
double timeToNextService() const;
- AnimationControllerPrivate* animationController() const { return m_animationController; }
+ CSSAnimationControllerPrivate& animationController() const { return m_animationController; }
void suspendAnimations();
void resumeAnimations();
@@ -68,9 +69,9 @@ public:
bool hasAnimations() const { return !m_transitions.isEmpty() || !m_keyframeAnimations.isEmpty(); }
- bool isAnimatingProperty(CSSPropertyID, bool acceleratedOnly, bool isRunningNow) const;
+ bool isAnimatingProperty(CSSPropertyID, bool acceleratedOnly, AnimationBase::RunningState) const;
- PassRefPtr<KeyframeAnimation> getAnimationForProperty(CSSPropertyID) const;
+ KeyframeAnimation* animationForProperty(CSSPropertyID) const;
void overrideImplicitAnimations(CSSPropertyID);
void resumeOverriddenImplicitAnimations(CSSPropertyID);
@@ -79,22 +80,30 @@ public:
bool pauseTransitionAtTime(CSSPropertyID, double);
unsigned numberOfActiveAnimations() const;
+#if ENABLE(CSS_ANIMATIONS_LEVEL_2)
+ bool hasScrollTriggeredAnimation() const { return m_hasScrollTriggeredAnimation; }
+#endif
+
+ bool hasAnimationThatDependsOnLayout() const { return m_hasAnimationThatDependsOnLayout; }
+
private:
- CompositeAnimation(AnimationControllerPrivate*);
+ CompositeAnimation(CSSAnimationControllerPrivate&);
- void updateTransitions(RenderElement*, RenderStyle* currentStyle, RenderStyle* targetStyle);
- void updateKeyframeAnimations(RenderElement*, RenderStyle* currentStyle, RenderStyle* targetStyle);
+ void updateTransitions(RenderElement*, const RenderStyle* currentStyle, const RenderStyle* targetStyle);
+ void updateKeyframeAnimations(RenderElement*, const RenderStyle* currentStyle, const RenderStyle* targetStyle);
typedef HashMap<int, RefPtr<ImplicitAnimation>> CSSPropertyTransitionsMap;
- typedef HashMap<AtomicStringImpl*, RefPtr<KeyframeAnimation>> AnimationNameMap;
+ typedef HashMap<AtomicStringImpl*, RefPtr<KeyframeAnimation>> AnimationNameMap;
- AnimationControllerPrivate* m_animationController;
+ CSSAnimationControllerPrivate& m_animationController;
CSSPropertyTransitionsMap m_transitions;
AnimationNameMap m_keyframeAnimations;
Vector<AtomicStringImpl*> m_keyframeAnimationOrderMap;
bool m_suspended;
+ bool m_hasAnimationThatDependsOnLayout { false };
+#if ENABLE(CSS_ANIMATIONS_LEVEL_2)
+ bool m_hasScrollTriggeredAnimation { false };
+#endif
};
} // namespace WebCore
-
-#endif // CompositeAnimation_h
diff --git a/Source/WebCore/page/animation/ImplicitAnimation.cpp b/Source/WebCore/page/animation/ImplicitAnimation.cpp
index af1d78819..924eb4b35 100644
--- a/Source/WebCore/page/animation/ImplicitAnimation.cpp
+++ b/Source/WebCore/page/animation/ImplicitAnimation.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.
*
@@ -27,24 +27,24 @@
*/
#include "config.h"
+#include "ImplicitAnimation.h"
-#include "AnimationControllerPrivate.h"
+#include "CSSAnimationControllerPrivate.h"
#include "CSSPropertyAnimation.h"
#include "CompositeAnimation.h"
#include "EventNames.h"
-#include "ImplicitAnimation.h"
+#include "GeometryUtilities.h"
#include "KeyframeAnimation.h"
-#include "RenderBoxModelObject.h"
+#include "RenderBox.h"
+#include "StylePendingResources.h"
namespace WebCore {
-ImplicitAnimation::ImplicitAnimation(const Animation& transition, CSSPropertyID animatingProperty, RenderElement* renderer, CompositeAnimation* compAnim, RenderStyle* fromStyle)
+ImplicitAnimation::ImplicitAnimation(const Animation& transition, CSSPropertyID animatingProperty, RenderElement* renderer, CompositeAnimation* compAnim, const RenderStyle* fromStyle)
: AnimationBase(transition, renderer, compAnim)
+ , m_fromStyle(RenderStyle::clonePtr(*fromStyle))
, m_transitionProperty(transition.property())
, m_animatingProperty(animatingProperty)
- , m_overridden(false)
- , m_active(true)
- , m_fromStyle(fromStyle)
{
ASSERT(animatingProperty != CSSPropertyInvalid);
}
@@ -61,12 +61,14 @@ bool ImplicitAnimation::shouldSendEventForListener(Document::ListenerType inList
return m_object->document().hasListenerType(inListenerType);
}
-void ImplicitAnimation::animate(CompositeAnimation*, RenderElement*, const RenderStyle*, RenderStyle* targetStyle, RefPtr<RenderStyle>& animatedStyle)
+bool ImplicitAnimation::animate(CompositeAnimation*, RenderElement*, const RenderStyle*, const RenderStyle* targetStyle, std::unique_ptr<RenderStyle>& animatedStyle, bool& didBlendStyle)
{
// If we get this far and the animation is done, it means we are cleaning up a just finished animation.
// So just return. Everything is already all cleaned up.
if (postActive())
- return;
+ return false;
+
+ AnimationState oldState = state();
// Reset to start the transition if we are new
if (isNew())
@@ -75,40 +77,64 @@ void ImplicitAnimation::animate(CompositeAnimation*, RenderElement*, const Rende
// Run a cycle of animation.
// We know we will need a new render style, so make one if needed
if (!animatedStyle)
- animatedStyle = RenderStyle::clone(targetStyle);
+ animatedStyle = RenderStyle::clonePtr(*targetStyle);
-#if USE(ACCELERATED_COMPOSITING)
- bool needsAnim = CSSPropertyAnimation::blendProperties(this, m_animatingProperty, animatedStyle.get(), m_fromStyle.get(), m_toStyle.get(), progress(1, 0, 0));
+ CSSPropertyAnimation::blendProperties(this, m_animatingProperty, animatedStyle.get(), m_fromStyle.get(), m_toStyle.get(), progress());
// FIXME: we also need to detect cases where we have to software animate for other reasons,
// such as a child using inheriting the transform. https://bugs.webkit.org/show_bug.cgi?id=23902
- if (!needsAnim)
- // If we are running an accelerated animation, set a flag in the style which causes the style
- // to compare as different to any other style. This ensures that changes to the property
- // that is animating are correctly detected during the animation (e.g. when a transition
- // gets interrupted).
- animatedStyle->setIsRunningAcceleratedAnimation();
-#endif
// Fire the start timeout if needed
fireAnimationEventsIfNeeded();
+
+ didBlendStyle = true;
+ return state() != oldState;
}
-void ImplicitAnimation::getAnimatedStyle(RefPtr<RenderStyle>& animatedStyle)
+void ImplicitAnimation::getAnimatedStyle(std::unique_ptr<RenderStyle>& animatedStyle)
{
if (!animatedStyle)
- animatedStyle = RenderStyle::clone(m_toStyle.get());
+ animatedStyle = RenderStyle::clonePtr(*m_toStyle);
+
+ CSSPropertyAnimation::blendProperties(this, m_animatingProperty, animatedStyle.get(), m_fromStyle.get(), m_toStyle.get(), progress());
+}
+
+bool ImplicitAnimation::computeExtentOfTransformAnimation(LayoutRect& bounds) const
+{
+ ASSERT(hasStyle());
+
+ if (!is<RenderBox>(m_object))
+ return true; // Non-boxes don't get transformed;
- CSSPropertyAnimation::blendProperties(this, m_animatingProperty, animatedStyle.get(), m_fromStyle.get(), m_toStyle.get(), progress(1, 0, 0));
+ ASSERT(m_animatingProperty == CSSPropertyTransform);
+
+ RenderBox& box = downcast<RenderBox>(*m_object);
+ FloatRect rendererBox = snapRectToDevicePixels(box.borderBoxRect(), box.document().deviceScaleFactor());
+
+ LayoutRect startBounds = bounds;
+ LayoutRect endBounds = bounds;
+
+ if (transformFunctionListsMatch()) {
+ if (!computeTransformedExtentViaTransformList(rendererBox, *m_fromStyle, startBounds))
+ return false;
+
+ if (!computeTransformedExtentViaTransformList(rendererBox, *m_toStyle, endBounds))
+ return false;
+ } else {
+ if (!computeTransformedExtentViaMatrix(rendererBox, *m_fromStyle, startBounds))
+ return false;
+
+ if (!computeTransformedExtentViaMatrix(rendererBox, *m_toStyle, endBounds))
+ return false;
+ }
+
+ bounds = unionRect(startBounds, endBounds);
+ return true;
}
bool ImplicitAnimation::startAnimation(double timeOffset)
{
-#if USE(ACCELERATED_COMPOSITING)
if (m_object && m_object->isComposited())
- return toRenderBoxModelObject(m_object)->startTransition(timeOffset, m_animatingProperty, m_fromStyle.get(), m_toStyle.get());
-#else
- UNUSED_PARAM(timeOffset);
-#endif
+ return downcast<RenderBoxModelObject>(*m_object).startTransition(timeOffset, m_animatingProperty, m_fromStyle.get(), m_toStyle.get());
return false;
}
@@ -117,12 +143,8 @@ void ImplicitAnimation::pauseAnimation(double timeOffset)
if (!m_object)
return;
-#if USE(ACCELERATED_COMPOSITING)
if (m_object->isComposited())
- toRenderBoxModelObject(m_object)->transitionPaused(timeOffset, m_animatingProperty);
-#else
- UNUSED_PARAM(timeOffset);
-#endif
+ downcast<RenderBoxModelObject>(*m_object).transitionPaused(timeOffset, m_animatingProperty);
// Restore the original (unanimated) style
if (!paused())
setNeedsStyleRecalc(m_object->element());
@@ -130,10 +152,8 @@ void ImplicitAnimation::pauseAnimation(double timeOffset)
void ImplicitAnimation::endAnimation()
{
-#if USE(ACCELERATED_COMPOSITING)
if (m_object && m_object->isComposited())
- toRenderBoxModelObject(m_object)->transitionFinished(m_animatingProperty);
-#endif
+ downcast<RenderBoxModelObject>(*m_object).transitionFinished(m_animatingProperty);
}
void ImplicitAnimation::onAnimationEnd(double elapsedTime)
@@ -143,10 +163,9 @@ void ImplicitAnimation::onAnimationEnd(double elapsedTime)
// running. But now that the transition has completed, we need to update this style with its new
// destination. If we didn't, the next time through we would think a transition had started
// (comparing the old unanimated style with the new final style of the transition).
- RefPtr<KeyframeAnimation> keyframeAnim = m_compAnim->getAnimationForProperty(m_animatingProperty);
- if (keyframeAnim)
- keyframeAnim->setUnanimatedStyle(m_toStyle);
-
+ if (auto* animation = m_compositeAnimation->animationForProperty(m_animatingProperty))
+ animation->setUnanimatedStyle(RenderStyle::clonePtr(*m_toStyle));
+
sendTransitionEvent(eventNames().transitionendEvent, elapsedTime);
endAnimation();
}
@@ -162,12 +181,12 @@ bool ImplicitAnimation::sendTransitionEvent(const AtomicString& eventType, doubl
// Dispatch the event
RefPtr<Element> element = m_object->element();
- ASSERT(!element || !element->document().inPageCache());
+ ASSERT(!element || element->document().pageCacheState() == Document::NotInPageCache);
if (!element)
return false;
// Schedule event handling
- m_compAnim->animationController()->addEventToDispatch(element, eventType, propertyName, elapsedTime);
+ m_compositeAnimation->animationController().addEventToDispatch(*element, eventType, propertyName, elapsedTime);
// Restore the original (unanimated) style
if (eventType == eventNames().transitionendEvent && element->renderer())
@@ -180,21 +199,25 @@ bool ImplicitAnimation::sendTransitionEvent(const AtomicString& eventType, doubl
return false; // Didn't dispatch an event
}
-void ImplicitAnimation::reset(RenderStyle* to)
+void ImplicitAnimation::reset(const RenderStyle* to)
{
ASSERT(to);
ASSERT(m_fromStyle);
- m_toStyle = to;
+ m_toStyle = RenderStyle::clonePtr(*to);
+
+ if (m_object && m_object->element())
+ Style::loadPendingResources(*m_toStyle, m_object->element()->document(), m_object->element());
// Restart the transition
if (m_fromStyle && m_toStyle)
- updateStateMachine(AnimationStateInputRestartAnimation, -1);
+ updateStateMachine(AnimationStateInput::RestartAnimation, -1);
// set the transform animation list
validateTransformFunctionList();
-#if ENABLE(CSS_FILTERS)
checkForMatchingFilterFunctionLists();
+#if ENABLE(FILTERS_LEVEL_2)
+ checkForMatchingBackdropFilterFunctionLists();
#endif
}
@@ -204,7 +227,7 @@ void ImplicitAnimation::setOverridden(bool b)
return;
m_overridden = b;
- updateStateMachine(m_overridden ? AnimationStateInputPauseOverride : AnimationStateInputResumeOverride, -1);
+ updateStateMachine(m_overridden ? AnimationStateInput::PauseOverride : AnimationStateInput::ResumeOverride, -1);
}
bool ImplicitAnimation::affectsProperty(CSSPropertyID property) const
@@ -229,12 +252,12 @@ void ImplicitAnimation::blendPropertyValueInStyle(CSSPropertyID prop, RenderStyl
if (!m_toStyle)
return;
- CSSPropertyAnimation::blendProperties(this, prop, currentStyle, m_fromStyle.get(), m_toStyle.get(), progress(1, 0, 0));
+ CSSPropertyAnimation::blendProperties(this, prop, currentStyle, m_fromStyle.get(), m_toStyle.get(), progress());
}
void ImplicitAnimation::validateTransformFunctionList()
{
- m_transformFunctionListValid = false;
+ m_transformFunctionListsMatch = false;
if (!m_fromStyle || !m_toStyle)
return;
@@ -248,44 +271,53 @@ void ImplicitAnimation::validateTransformFunctionList()
if (val->operations().isEmpty())
return;
- // An emtpy transform list matches anything.
+ // An empty transform list matches anything.
if (val != toVal && !toVal->operations().isEmpty() && !val->operationsMatch(*toVal))
return;
// Transform lists match.
- m_transformFunctionListValid = true;
+ m_transformFunctionListsMatch = true;
+}
+
+static bool filterOperationsMatch(const FilterOperations* fromOperations, const FilterOperations& toOperations)
+{
+ if (fromOperations->operations().isEmpty())
+ fromOperations = &toOperations;
+
+ if (fromOperations->operations().isEmpty())
+ return false;
+
+ if (fromOperations != &toOperations && !toOperations.operations().isEmpty() && !fromOperations->operationsMatch(toOperations))
+ return false;
+
+ return true;
}
-#if ENABLE(CSS_FILTERS)
void ImplicitAnimation::checkForMatchingFilterFunctionLists()
{
m_filterFunctionListsMatch = false;
-
+
if (!m_fromStyle || !m_toStyle)
return;
-
- const FilterOperations* val = &m_fromStyle->filter();
- const FilterOperations* toVal = &m_toStyle->filter();
- if (val->operations().isEmpty())
- val = toVal;
+ m_filterFunctionListsMatch = filterOperationsMatch(&m_fromStyle->filter(), m_toStyle->filter());
+}
- if (val->operations().isEmpty())
- return;
-
- // An emtpy filter list matches anything.
- if (val != toVal && !toVal->operations().isEmpty() && !val->operationsMatch(*toVal))
+#if ENABLE(FILTERS_LEVEL_2)
+void ImplicitAnimation::checkForMatchingBackdropFilterFunctionLists()
+{
+ m_backdropFilterFunctionListsMatch = false;
+
+ if (!m_fromStyle || !m_toStyle)
return;
- // Filter lists match.
- m_filterFunctionListsMatch = true;
+ m_backdropFilterFunctionListsMatch = filterOperationsMatch(&m_fromStyle->backdropFilter(), m_toStyle->backdropFilter());
}
#endif
double ImplicitAnimation::timeToNextService()
{
double t = AnimationBase::timeToNextService();
-#if USE(ACCELERATED_COMPOSITING)
if (t != 0 || preActive())
return t;
@@ -295,7 +327,6 @@ double ImplicitAnimation::timeToNextService()
bool isLooping;
getTimeToNextEvent(t, isLooping);
}
-#endif
return t;
}
diff --git a/Source/WebCore/page/animation/ImplicitAnimation.h b/Source/WebCore/page/animation/ImplicitAnimation.h
index df651141e..9447417b0 100644
--- a/Source/WebCore/page/animation/ImplicitAnimation.h
+++ b/Source/WebCore/page/animation/ImplicitAnimation.h
@@ -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.
*
@@ -26,8 +26,7 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef ImplicitAnimation_h
-#define ImplicitAnimation_h
+#pragma once
#include "AnimationBase.h"
#include "CSSPropertyNames.h"
@@ -41,27 +40,29 @@ class RenderElement;
// for a single RenderElement.
class ImplicitAnimation : public AnimationBase {
public:
- static PassRefPtr<ImplicitAnimation> create(const Animation& animation, CSSPropertyID animatingProperty, RenderElement* renderer, CompositeAnimation* compositeAnimation, RenderStyle* fromStyle)
+ static Ref<ImplicitAnimation> create(const Animation& animation, CSSPropertyID animatingProperty, RenderElement* renderer, CompositeAnimation* compositeAnimation, const RenderStyle* fromStyle)
{
- return adoptRef(new ImplicitAnimation(animation, animatingProperty, renderer, compositeAnimation, fromStyle));
+ return adoptRef(*new ImplicitAnimation(animation, animatingProperty, renderer, compositeAnimation, fromStyle));
};
CSSPropertyID transitionProperty() const { return m_transitionProperty; }
CSSPropertyID animatingProperty() const { return m_animatingProperty; }
- virtual void onAnimationEnd(double elapsedTime) override;
- virtual bool startAnimation(double timeOffset) override;
- virtual void pauseAnimation(double timeOffset) override;
- virtual void endAnimation() override;
+ void onAnimationEnd(double elapsedTime) override;
+ bool startAnimation(double timeOffset) override;
+ void pauseAnimation(double timeOffset) override;
+ void endAnimation() override;
- virtual void animate(CompositeAnimation*, RenderElement*, const RenderStyle* currentStyle, RenderStyle* targetStyle, RefPtr<RenderStyle>& animatedStyle) override;
- virtual void getAnimatedStyle(RefPtr<RenderStyle>& animatedStyle) override;
- virtual void reset(RenderStyle* to);
+ bool animate(CompositeAnimation*, RenderElement*, const RenderStyle* currentStyle, const RenderStyle* targetStyle, std::unique_ptr<RenderStyle>& animatedStyle, bool& didBlendStyle) override;
+ void getAnimatedStyle(std::unique_ptr<RenderStyle>& animatedStyle) override;
+ void reset(const RenderStyle* to);
+
+ bool computeExtentOfTransformAnimation(LayoutRect&) const override;
void setOverridden(bool);
- virtual bool overridden() const override { return m_overridden; }
+ bool overridden() const override { return m_overridden; }
- virtual bool affectsProperty(CSSPropertyID) const override;
+ bool affectsProperty(CSSPropertyID) const override;
bool hasStyle() const { return m_fromStyle && m_toStyle; }
@@ -69,7 +70,7 @@ public:
void blendPropertyValueInStyle(CSSPropertyID, RenderStyle*);
- virtual double timeToNextService() override;
+ double timeToNextService() override;
bool active() const { return m_active; }
void setActive(bool b) { m_active = b; }
@@ -79,24 +80,24 @@ protected:
bool sendTransitionEvent(const AtomicString&, double elapsedTime);
void validateTransformFunctionList();
-#if ENABLE(CSS_FILTERS)
void checkForMatchingFilterFunctionLists();
+#if ENABLE(FILTERS_LEVEL_2)
+ void checkForMatchingBackdropFilterFunctionLists();
#endif
private:
- ImplicitAnimation(const Animation&, CSSPropertyID, RenderElement*, CompositeAnimation*, RenderStyle*);
+ ImplicitAnimation(const Animation&, CSSPropertyID, RenderElement*, CompositeAnimation*, const RenderStyle*);
virtual ~ImplicitAnimation();
+ // The two styles that we are blending.
+ std::unique_ptr<RenderStyle> m_fromStyle;
+ std::unique_ptr<RenderStyle> m_toStyle;
+
CSSPropertyID m_transitionProperty; // Transition property as specified in the RenderStyle.
CSSPropertyID m_animatingProperty; // Specific property for this ImplicitAnimation
- bool m_overridden; // true when there is a keyframe animation that overrides the transitioning property
- bool m_active; // used for culling the list of transitions
- // The two styles that we are blending.
- RefPtr<RenderStyle> m_fromStyle;
- RefPtr<RenderStyle> m_toStyle;
+ bool m_active { true }; // Used for culling the list of transitions.
+ bool m_overridden { false }; // True when there is a keyframe animation that overrides the transitioning property
};
} // namespace WebCore
-
-#endif // ImplicitAnimation_h
diff --git a/Source/WebCore/page/animation/KeyframeAnimation.cpp b/Source/WebCore/page/animation/KeyframeAnimation.cpp
index 8f661c6c3..5294b0a31 100644
--- a/Source/WebCore/page/animation/KeyframeAnimation.cpp
+++ b/Source/WebCore/page/animation/KeyframeAnimation.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,33 +29,37 @@
#include "config.h"
#include "KeyframeAnimation.h"
-#include "AnimationControllerPrivate.h"
+#include "CSSAnimationControllerPrivate.h"
#include "CSSPropertyAnimation.h"
#include "CSSPropertyNames.h"
#include "CompositeAnimation.h"
#include "EventNames.h"
-#include "RenderBoxModelObject.h"
+#include "GeometryUtilities.h"
+#include "RenderBox.h"
#include "RenderStyle.h"
+#include "StylePendingResources.h"
#include "StyleResolver.h"
+#include "StyleScope.h"
+#include "TranslateTransformOperation.h"
+#include "WillChangeData.h"
namespace WebCore {
-KeyframeAnimation::KeyframeAnimation(const Animation& animation, RenderElement* renderer, int index, CompositeAnimation* compAnim, RenderStyle* unanimatedStyle)
- : AnimationBase(animation, renderer, compAnim)
+KeyframeAnimation::KeyframeAnimation(const Animation& animation, RenderElement* renderer, CompositeAnimation* compositeAnimation, const RenderStyle* unanimatedStyle)
+ : AnimationBase(animation, renderer, compositeAnimation)
, m_keyframes(animation.name())
- , m_index(index)
- , m_startEventDispatched(false)
- , m_unanimatedStyle(unanimatedStyle)
+ , m_unanimatedStyle(RenderStyle::clonePtr(*unanimatedStyle))
{
- // Get the keyframe RenderStyles
- if (m_object && m_object->element())
- m_object->document().ensureStyleResolver().keyframeStylesForAnimation(m_object->element(), unanimatedStyle, m_keyframes);
+ resolveKeyframeStyles();
// Update the m_transformFunctionListValid flag based on whether the function lists in the keyframes match.
validateTransformFunctionList();
-#if ENABLE(CSS_FILTERS)
checkForMatchingFilterFunctionLists();
+#if ENABLE(FILTERS_LEVEL_2)
+ checkForMatchingBackdropFilterFunctionLists();
#endif
+ computeStackingContextImpact();
+ computeLayoutDependency();
}
KeyframeAnimation::~KeyframeAnimation()
@@ -65,38 +69,60 @@ KeyframeAnimation::~KeyframeAnimation()
endAnimation();
}
-static const Animation* getAnimationFromStyleByName(const RenderStyle* style, const AtomicString& name)
+void KeyframeAnimation::computeStackingContextImpact()
{
- if (!style->animations())
- return 0;
-
- for (size_t i = 0; i < style->animations()->size(); i++) {
- if (name == style->animations()->animation(i).name())
- return &style->animations()->animation(i);
+ for (auto propertyID : m_keyframes.properties()) {
+ if (WillChangeData::propertyCreatesStackingContext(propertyID)) {
+ m_triggersStackingContext = true;
+ break;
+ }
}
+}
+
+void KeyframeAnimation::computeLayoutDependency()
+{
+ if (!m_keyframes.containsProperty(CSSPropertyTransform))
+ return;
- return 0;
+ size_t numKeyframes = m_keyframes.size();
+ for (size_t i = 0; i < numKeyframes; i++) {
+ auto* keyframeStyle = m_keyframes[i].style();
+ if (!keyframeStyle) {
+ ASSERT_NOT_REACHED();
+ continue;
+ }
+ if (keyframeStyle->hasTransform()) {
+ auto& transformOperations = keyframeStyle->transform();
+ for (auto operation : transformOperations.operations()) {
+ if (operation->isTranslateTransformOperationType()) {
+ auto translation = downcast<TranslateTransformOperation>(operation.get());
+ if (translation->x().isPercent() || translation->y().isPercent()) {
+ m_dependsOnLayout = true;
+ return;
+ }
+ }
+ }
+ }
+ }
}
void KeyframeAnimation::fetchIntervalEndpointsForProperty(CSSPropertyID property, const RenderStyle*& fromStyle, const RenderStyle*& toStyle, double& prog) const
{
+ size_t numKeyframes = m_keyframes.size();
+ if (!numKeyframes)
+ return;
+
// Find the first key
double elapsedTime = getElapsedTime();
if (m_animation->duration() && m_animation->iterationCount() != Animation::IterationCountInfinite)
elapsedTime = std::min(elapsedTime, m_animation->duration() * m_animation->iterationCount());
const double fractionalTime = this->fractionalTime(1, elapsedTime, 0);
-
- size_t numKeyframes = m_keyframes.size();
- if (!numKeyframes)
- return;
-
ASSERT(!m_keyframes[0].key());
ASSERT(m_keyframes[m_keyframes.size() - 1].key() == 1);
-
+
int prevIndex = -1;
int nextIndex = -1;
-
// FIXME: with a lot of keys, this linear search will be slow. We could binary search.
for (size_t i = 0; i < numKeyframes; ++i) {
const KeyframeValue& currKeyFrame = m_keyframes[i];
@@ -108,16 +134,11 @@ void KeyframeAnimation::fetchIntervalEndpointsForProperty(CSSPropertyID property
nextIndex = i;
break;
}
-
prevIndex = i;
}
- double scale = 1;
- double offset = 0;
-
if (prevIndex == -1)
prevIndex = 0;
-
if (nextIndex == -1)
nextIndex = m_keyframes.size() - 1;
@@ -126,32 +147,32 @@ void KeyframeAnimation::fetchIntervalEndpointsForProperty(CSSPropertyID property
fromStyle = prevKeyframe.style();
toStyle = nextKeyframe.style();
-
- offset = prevKeyframe.key();
- scale = 1.0 / (nextKeyframe.key() - prevKeyframe.key());
- const TimingFunction* timingFunction = 0;
- if (const Animation* matchedAnimation = getAnimationFromStyleByName(fromStyle, name()))
- timingFunction = matchedAnimation->timingFunction().get();
+ double offset = prevKeyframe.key();
+ double scale = 1.0 / (nextIndex == prevIndex ? 1 : (nextKeyframe.key() - prevKeyframe.key()));
- prog = progress(scale, offset, timingFunction);
+ prog = progress(scale, offset, prevKeyframe.timingFunction(name()));
}
-void KeyframeAnimation::animate(CompositeAnimation* compositeAnimation, RenderElement*, const RenderStyle*, RenderStyle* targetStyle, RefPtr<RenderStyle>& animatedStyle)
+bool KeyframeAnimation::animate(CompositeAnimation* compositeAnimation, RenderElement*, const RenderStyle*, const RenderStyle* targetStyle, std::unique_ptr<RenderStyle>& animatedStyle, bool& didBlendStyle)
{
// Fire the start timeout if needed
fireAnimationEventsIfNeeded();
// If we have not yet started, we will not have a valid start time, so just start the animation if needed.
- if (isNew() && m_animation->playState() == AnimPlayStatePlaying && !compositeAnimation->isSuspended())
- updateStateMachine(AnimationStateInputStartAnimation, -1);
+ if (isNew()) {
+ if (m_animation->playState() == AnimPlayStatePlaying && !compositeAnimation->isSuspended())
+ updateStateMachine(AnimationStateInput::StartAnimation, -1);
+ else if (m_animation->playState() == AnimPlayStatePaused)
+ updateStateMachine(AnimationStateInput::PlayStatePaused, -1);
+ }
// If we get this far and the animation is done, it means we are cleaning up a just finished animation.
// If so, we need to send back the targetStyle.
if (postActive()) {
if (!animatedStyle)
- animatedStyle = const_cast<RenderStyle*>(targetStyle);
- return;
+ animatedStyle = RenderStyle::clonePtr(*targetStyle);
+ return false;
}
// If we are waiting for the start timer, we don't want to change the style yet.
@@ -160,65 +181,95 @@ void KeyframeAnimation::animate(CompositeAnimation* compositeAnimation, RenderEl
// Special case 2 - if there is a backwards fill mode, then we want to continue
// through to the style blend so that we get the fromStyle.
if (waitingToStart() && m_animation->delay() > 0 && !m_animation->fillsBackwards())
- return;
+ return false;
// If we have no keyframes, don't animate.
if (!m_keyframes.size()) {
- updateStateMachine(AnimationStateInputEndAnimation, -1);
- return;
+ updateStateMachine(AnimationStateInput::EndAnimation, -1);
+ return false;
}
+ // FIXME: the code below never changes the state, so this function always returns false.
+ AnimationState oldState = state();
+
// Run a cycle of animation.
// We know we will need a new render style, so make one if needed.
if (!animatedStyle)
- animatedStyle = RenderStyle::clone(targetStyle);
+ animatedStyle = RenderStyle::clonePtr(*targetStyle);
// FIXME: we need to be more efficient about determining which keyframes we are animating between.
// We should cache the last pair or something.
- HashSet<CSSPropertyID>::const_iterator endProperties = m_keyframes.endProperties();
- for (HashSet<CSSPropertyID>::const_iterator it = m_keyframes.beginProperties(); it != endProperties; ++it) {
+ for (auto propertyID : m_keyframes.properties()) {
// Get the from/to styles and progress between
- const RenderStyle* fromStyle = 0;
- const RenderStyle* toStyle = 0;
- double progress = 0.0;
- fetchIntervalEndpointsForProperty(*it, fromStyle, toStyle, progress);
-
-#if USE(ACCELERATED_COMPOSITING)
- bool needsAnim = CSSPropertyAnimation::blendProperties(this, *it, animatedStyle.get(), fromStyle, toStyle, progress);
- if (!needsAnim)
- // If we are running an accelerated animation, set a flag in the style
- // to indicate it. This can be used to make sure we get an updated
- // style for hit testing, etc.
- animatedStyle->setIsRunningAcceleratedAnimation();
-#endif
+ const RenderStyle* fromStyle = nullptr;
+ const RenderStyle* toStyle = nullptr;
+ double progress = 0;
+ fetchIntervalEndpointsForProperty(propertyID, fromStyle, toStyle, progress);
+
+ CSSPropertyAnimation::blendProperties(this, propertyID, animatedStyle.get(), fromStyle, toStyle, progress);
}
+
+ didBlendStyle = true;
+ return state() != oldState;
}
-void KeyframeAnimation::getAnimatedStyle(RefPtr<RenderStyle>& animatedStyle)
+void KeyframeAnimation::getAnimatedStyle(std::unique_ptr<RenderStyle>& animatedStyle)
{
- // If we're in the delay phase and we're not backwards filling, tell the caller
- // to use the current style.
- if (waitingToStart() && m_animation->delay() > 0 && !m_animation->fillsBackwards())
+ // If we're done, or in the delay phase and we're not backwards filling, tell the caller to use the current style.
+ if (postActive() || (waitingToStart() && m_animation->delay() > 0 && !m_animation->fillsBackwards()))
return;
if (!m_keyframes.size())
return;
if (!animatedStyle)
- animatedStyle = RenderStyle::clone(&m_object->style());
+ animatedStyle = RenderStyle::clonePtr(m_object->style());
- HashSet<CSSPropertyID>::const_iterator endProperties = m_keyframes.endProperties();
- for (HashSet<CSSPropertyID>::const_iterator it = m_keyframes.beginProperties(); it != endProperties; ++it) {
+ for (auto propertyID : m_keyframes.properties()) {
// Get the from/to styles and progress between
- const RenderStyle* fromStyle = 0;
- const RenderStyle* toStyle = 0;
- double progress = 0.0;
- fetchIntervalEndpointsForProperty(*it, fromStyle, toStyle, progress);
+ const RenderStyle* fromStyle = nullptr;
+ const RenderStyle* toStyle = nullptr;
+ double progress = 0;
+ fetchIntervalEndpointsForProperty(propertyID, fromStyle, toStyle, progress);
- CSSPropertyAnimation::blendProperties(this, *it, animatedStyle.get(), fromStyle, toStyle, progress);
+ CSSPropertyAnimation::blendProperties(this, propertyID, animatedStyle.get(), fromStyle, toStyle, progress);
}
}
+bool KeyframeAnimation::computeExtentOfTransformAnimation(LayoutRect& bounds) const
+{
+ ASSERT(m_keyframes.containsProperty(CSSPropertyTransform));
+
+ if (!is<RenderBox>(m_object))
+ return true; // Non-boxes don't get transformed;
+
+ RenderBox& box = downcast<RenderBox>(*m_object);
+ FloatRect rendererBox = snapRectToDevicePixels(box.borderBoxRect(), box.document().deviceScaleFactor());
+
+ FloatRect cumulativeBounds = bounds;
+
+ for (auto& keyframe : m_keyframes.keyframes()) {
+ if (!keyframe.containsProperty(CSSPropertyTransform))
+ continue;
+
+ LayoutRect keyframeBounds = bounds;
+
+ bool canCompute;
+ if (transformFunctionListsMatch())
+ canCompute = computeTransformedExtentViaTransformList(rendererBox, *keyframe.style(), keyframeBounds);
+ else
+ canCompute = computeTransformedExtentViaMatrix(rendererBox, *keyframe.style(), keyframeBounds);
+
+ if (!canCompute)
+ return false;
+
+ cumulativeBounds.unite(keyframeBounds);
+ }
+
+ bounds = LayoutRect(cumulativeBounds);
+ return true;
+}
+
bool KeyframeAnimation::hasAnimationForProperty(CSSPropertyID property) const
{
return m_keyframes.containsProperty(property);
@@ -226,13 +277,8 @@ bool KeyframeAnimation::hasAnimationForProperty(CSSPropertyID property) const
bool KeyframeAnimation::startAnimation(double timeOffset)
{
-#if USE(ACCELERATED_COMPOSITING)
- if (m_object && m_object->isComposited()) {
- return toRenderBoxModelObject(m_object)->startAnimation(timeOffset, m_animation.get(), m_keyframes);
- }
-#else
- UNUSED_PARAM(timeOffset);
-#endif
+ if (m_object && m_object->isComposited())
+ return downcast<RenderBoxModelObject>(*m_object).startAnimation(timeOffset, m_animation.ptr(), m_keyframes);
return false;
}
@@ -241,12 +287,9 @@ void KeyframeAnimation::pauseAnimation(double timeOffset)
if (!m_object)
return;
-#if USE(ACCELERATED_COMPOSITING)
if (m_object->isComposited())
- toRenderBoxModelObject(m_object)->animationPaused(timeOffset, m_keyframes.animationName());
-#else
- UNUSED_PARAM(timeOffset);
-#endif
+ downcast<RenderBoxModelObject>(*m_object).animationPaused(timeOffset, m_keyframes.animationName());
+
// Restore the original (unanimated) style
if (!paused())
setNeedsStyleRecalc(m_object->element());
@@ -257,10 +300,9 @@ void KeyframeAnimation::endAnimation()
if (!m_object)
return;
-#if USE(ACCELERATED_COMPOSITING)
if (m_object->isComposited())
- toRenderBoxModelObject(m_object)->animationFinished(m_keyframes.animationName());
-#endif
+ downcast<RenderBoxModelObject>(*m_object).animationFinished(m_keyframes.animationName());
+
// Restore the original (unanimated) style
if (!paused())
setNeedsStyleRecalc(m_object->element());
@@ -273,17 +315,17 @@ bool KeyframeAnimation::shouldSendEventForListener(Document::ListenerType listen
void KeyframeAnimation::onAnimationStart(double elapsedTime)
{
- sendAnimationEvent(eventNames().webkitAnimationStartEvent, elapsedTime);
+ sendAnimationEvent(eventNames().animationstartEvent, elapsedTime);
}
void KeyframeAnimation::onAnimationIteration(double elapsedTime)
{
- sendAnimationEvent(eventNames().webkitAnimationIterationEvent, elapsedTime);
+ sendAnimationEvent(eventNames().animationiterationEvent, elapsedTime);
}
void KeyframeAnimation::onAnimationEnd(double elapsedTime)
{
- sendAnimationEvent(eventNames().webkitAnimationEndEvent, elapsedTime);
+ sendAnimationEvent(eventNames().animationendEvent, elapsedTime);
// End the animation if we don't fill forwards. Forward filling
// animations are ended properly in the class destructor.
if (!m_animation->fillsForwards())
@@ -293,12 +335,12 @@ void KeyframeAnimation::onAnimationEnd(double elapsedTime)
bool KeyframeAnimation::sendAnimationEvent(const AtomicString& eventType, double elapsedTime)
{
Document::ListenerType listenerType;
- if (eventType == eventNames().webkitAnimationIterationEvent)
+ if (eventType == eventNames().webkitAnimationIterationEvent || eventType == eventNames().animationiterationEvent)
listenerType = Document::ANIMATIONITERATION_LISTENER;
- else if (eventType == eventNames().webkitAnimationEndEvent)
+ else if (eventType == eventNames().webkitAnimationEndEvent || eventType == eventNames().animationendEvent)
listenerType = Document::ANIMATIONEND_LISTENER;
else {
- ASSERT(eventType == eventNames().webkitAnimationStartEvent);
+ ASSERT(eventType == eventNames().webkitAnimationStartEvent || eventType == eventNames().animationstartEvent);
if (m_startEventDispatched)
return false;
m_startEventDispatched = true;
@@ -309,15 +351,15 @@ bool KeyframeAnimation::sendAnimationEvent(const AtomicString& eventType, double
// Dispatch the event
RefPtr<Element> element = m_object->element();
- ASSERT(!element || !element->document().inPageCache());
+ ASSERT(!element || element->document().pageCacheState() == Document::NotInPageCache);
if (!element)
return false;
// Schedule event handling
- m_compAnim->animationController()->addEventToDispatch(element, eventType, m_keyframes.animationName(), elapsedTime);
+ m_compositeAnimation->animationController().addEventToDispatch(*element, eventType, m_keyframes.animationName(), elapsedTime);
// Restore the original (unanimated) style
- if (eventType == eventNames().webkitAnimationEndEvent && element->renderer())
+ if ((eventType == eventNames().webkitAnimationEndEvent || eventType == eventNames().animationendEvent) && element->renderer())
setNeedsStyleRecalc(element.get());
return true; // Did dispatch an event
@@ -329,17 +371,15 @@ bool KeyframeAnimation::sendAnimationEvent(const AtomicString& eventType, double
void KeyframeAnimation::overrideAnimations()
{
// This will override implicit animations that match the properties in the keyframe animation
- HashSet<CSSPropertyID>::const_iterator end = m_keyframes.endProperties();
- for (HashSet<CSSPropertyID>::const_iterator it = m_keyframes.beginProperties(); it != end; ++it)
- compositeAnimation()->overrideImplicitAnimations(*it);
+ for (auto propertyID : m_keyframes.properties())
+ compositeAnimation()->overrideImplicitAnimations(propertyID);
}
void KeyframeAnimation::resumeOverriddenAnimations()
{
// This will resume overridden implicit animations
- HashSet<CSSPropertyID>::const_iterator end = m_keyframes.endProperties();
- for (HashSet<CSSPropertyID>::const_iterator it = m_keyframes.beginProperties(); it != end; ++it)
- compositeAnimation()->resumeOverriddenImplicitAnimations(*it);
+ for (auto propertyID : m_keyframes.properties())
+ compositeAnimation()->resumeOverriddenImplicitAnimations(propertyID);
}
bool KeyframeAnimation::affectsProperty(CSSPropertyID property) const
@@ -347,11 +387,27 @@ bool KeyframeAnimation::affectsProperty(CSSPropertyID property) const
return m_keyframes.containsProperty(property);
}
+void KeyframeAnimation::resolveKeyframeStyles()
+{
+ if (!m_object || !m_object->element())
+ return;
+ auto& element = *m_object->element();
+
+ if (auto* styleScope = Style::Scope::forOrdinal(element, m_animation->nameStyleScopeOrdinal()))
+ styleScope->resolver().keyframeStylesForAnimation(*m_object->element(), m_unanimatedStyle.get(), m_keyframes);
+
+ // Ensure resource loads for all the frames.
+ for (auto& keyframe : m_keyframes.keyframes()) {
+ if (auto* style = const_cast<RenderStyle*>(keyframe.style()))
+ Style::loadPendingResources(*style, element.document(), &element);
+ }
+}
+
void KeyframeAnimation::validateTransformFunctionList()
{
- m_transformFunctionListValid = false;
+ m_transformFunctionListsMatch = false;
- if (m_keyframes.size() < 2 || !m_keyframes.containsProperty(CSSPropertyWebkitTransform))
+ if (m_keyframes.size() < 2 || !m_keyframes.containsProperty(CSSPropertyTransform))
return;
// Empty transforms match anything, so find the first non-empty entry as the reference
@@ -384,16 +440,14 @@ void KeyframeAnimation::validateTransformFunctionList()
return;
}
- // Keyframes are valid
- m_transformFunctionListValid = true;
+ m_transformFunctionListsMatch = true;
}
-#if ENABLE(CSS_FILTERS)
void KeyframeAnimation::checkForMatchingFilterFunctionLists()
{
m_filterFunctionListsMatch = false;
- if (m_keyframes.size() < 2 || !m_keyframes.containsProperty(CSSPropertyWebkitFilter))
+ if (m_keyframes.size() < 2 || !m_keyframes.containsProperty(CSSPropertyFilter))
return;
// Empty filters match anything, so find the first non-empty entry as the reference
@@ -401,8 +455,7 @@ void KeyframeAnimation::checkForMatchingFilterFunctionLists()
size_t firstNonEmptyFilterKeyframeIndex = numKeyframes;
for (size_t i = 0; i < numKeyframes; ++i) {
- const KeyframeValue& currentKeyframe = m_keyframes[i];
- if (currentKeyframe.style()->filter().operations().size()) {
+ if (m_keyframes[i].style()->filter().operations().size()) {
firstNonEmptyFilterKeyframeIndex = i;
break;
}
@@ -410,39 +463,74 @@ void KeyframeAnimation::checkForMatchingFilterFunctionLists()
if (firstNonEmptyFilterKeyframeIndex == numKeyframes)
return;
-
- const FilterOperations* firstVal = &m_keyframes[firstNonEmptyFilterKeyframeIndex].style()->filter();
+
+ auto& firstVal = m_keyframes[firstNonEmptyFilterKeyframeIndex].style()->filter();
for (size_t i = firstNonEmptyFilterKeyframeIndex + 1; i < numKeyframes; ++i) {
- const KeyframeValue& currentKeyframe = m_keyframes[i];
- const FilterOperations* val = &currentKeyframe.style()->filter();
-
+ auto& value = m_keyframes[i].style()->filter();
+
// An emtpy filter list matches anything.
- if (val->operations().isEmpty())
+ if (value.operations().isEmpty())
continue;
-
- if (!firstVal->operationsMatch(*val))
+
+ if (!firstVal.operationsMatch(value))
return;
}
-
+
m_filterFunctionListsMatch = true;
}
+
+#if ENABLE(FILTERS_LEVEL_2)
+void KeyframeAnimation::checkForMatchingBackdropFilterFunctionLists()
+{
+ m_backdropFilterFunctionListsMatch = false;
+
+ if (m_keyframes.size() < 2 || !m_keyframes.containsProperty(CSSPropertyWebkitBackdropFilter))
+ return;
+
+ // Empty filters match anything, so find the first non-empty entry as the reference
+ size_t numKeyframes = m_keyframes.size();
+ size_t firstNonEmptyFilterKeyframeIndex = numKeyframes;
+
+ for (size_t i = 0; i < numKeyframes; ++i) {
+ if (m_keyframes[i].style()->backdropFilter().operations().size()) {
+ firstNonEmptyFilterKeyframeIndex = i;
+ break;
+ }
+ }
+
+ if (firstNonEmptyFilterKeyframeIndex == numKeyframes)
+ return;
+
+ auto& firstVal = m_keyframes[firstNonEmptyFilterKeyframeIndex].style()->backdropFilter();
+
+ for (size_t i = firstNonEmptyFilterKeyframeIndex + 1; i < numKeyframes; ++i) {
+ auto& value = m_keyframes[i].style()->backdropFilter();
+
+ // An emtpy filter list matches anything.
+ if (value.operations().isEmpty())
+ continue;
+
+ if (!firstVal.operationsMatch(value))
+ return;
+ }
+
+ m_backdropFilterFunctionListsMatch = true;
+}
#endif
double KeyframeAnimation::timeToNextService()
{
double t = AnimationBase::timeToNextService();
-#if USE(ACCELERATED_COMPOSITING)
if (t != 0 || preActive())
return t;
// A return value of 0 means we need service. But if we only have accelerated animations we
// only need service at the end of the transition
- HashSet<CSSPropertyID>::const_iterator endProperties = m_keyframes.endProperties();
bool acceleratedPropertiesOnly = true;
- for (HashSet<CSSPropertyID>::const_iterator it = m_keyframes.beginProperties(); it != endProperties; ++it) {
- if (!CSSPropertyAnimation::animationOfPropertyIsAccelerated(*it) || !isAccelerated()) {
+ for (auto propertyID : m_keyframes.properties()) {
+ if (!CSSPropertyAnimation::animationOfPropertyIsAccelerated(propertyID) || !isAccelerated()) {
acceleratedPropertiesOnly = false;
break;
}
@@ -452,7 +540,7 @@ double KeyframeAnimation::timeToNextService()
bool isLooping;
getTimeToNextEvent(t, isLooping);
}
-#endif
+
return t;
}
diff --git a/Source/WebCore/page/animation/KeyframeAnimation.h b/Source/WebCore/page/animation/KeyframeAnimation.h
index 34ebd9951..8731d343c 100644
--- a/Source/WebCore/page/animation/KeyframeAnimation.h
+++ b/Source/WebCore/page/animation/KeyframeAnimation.h
@@ -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.
*
@@ -26,8 +26,7 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef KeyframeAnimation_h
-#define KeyframeAnimation_h
+#pragma once
#include "AnimationBase.h"
#include "Document.h"
@@ -40,66 +39,72 @@ class RenderStyle;
// A KeyframeAnimation tracks the state of an explicit animation for a single RenderElement.
class KeyframeAnimation final : public AnimationBase {
public:
- static RefPtr<KeyframeAnimation> create(const Animation& animation, RenderElement* renderer, int index, CompositeAnimation* compositeAnimation, RenderStyle* unanimatedStyle)
+ static Ref<KeyframeAnimation> create(const Animation& animation, RenderElement* renderer, CompositeAnimation* compositeAnimation, const RenderStyle* unanimatedStyle)
{
- return adoptRef(new KeyframeAnimation(animation, renderer, index, compositeAnimation, unanimatedStyle));
+ return adoptRef(*new KeyframeAnimation(animation, renderer, compositeAnimation, unanimatedStyle));
}
- virtual void animate(CompositeAnimation*, RenderElement*, const RenderStyle* currentStyle, RenderStyle* targetStyle, RefPtr<RenderStyle>& animatedStyle) override;
- virtual void getAnimatedStyle(RefPtr<RenderStyle>&) override;
+ bool animate(CompositeAnimation*, RenderElement*, const RenderStyle* currentStyle, const RenderStyle* targetStyle, std::unique_ptr<RenderStyle>& animatedStyle, bool& didBlendStyle) override;
+ void getAnimatedStyle(std::unique_ptr<RenderStyle>&) override;
+
+ bool computeExtentOfTransformAnimation(LayoutRect&) const override;
const KeyframeList& keyframes() const { return m_keyframes; }
const AtomicString& name() const { return m_keyframes.animationName(); }
- int index() const { return m_index; }
- void setIndex(int i) { m_index = i; }
bool hasAnimationForProperty(CSSPropertyID) const;
-
- void setUnanimatedStyle(PassRefPtr<RenderStyle> style) { m_unanimatedStyle = style; }
+
+ bool triggersStackingContext() const { return m_triggersStackingContext; }
+ bool dependsOnLayout() const { return m_dependsOnLayout; }
+
+ void setUnanimatedStyle(std::unique_ptr<RenderStyle> style) { m_unanimatedStyle = WTFMove(style); }
RenderStyle* unanimatedStyle() const { return m_unanimatedStyle.get(); }
- virtual double timeToNextService() override;
+ double timeToNextService() override;
protected:
- virtual void onAnimationStart(double elapsedTime) override;
- virtual void onAnimationIteration(double elapsedTime) override;
- virtual void onAnimationEnd(double elapsedTime) override;
- virtual bool startAnimation(double timeOffset) override;
- virtual void pauseAnimation(double timeOffset) override;
- virtual void endAnimation() override;
+ void onAnimationStart(double elapsedTime) override;
+ void onAnimationIteration(double elapsedTime) override;
+ void onAnimationEnd(double elapsedTime) override;
+ bool startAnimation(double timeOffset) override;
+ void pauseAnimation(double timeOffset) override;
+ void endAnimation() override;
- virtual void overrideAnimations() override;
- virtual void resumeOverriddenAnimations() override;
+ void overrideAnimations() override;
+ void resumeOverriddenAnimations() override;
bool shouldSendEventForListener(Document::ListenerType inListenerType) const;
bool sendAnimationEvent(const AtomicString&, double elapsedTime);
- virtual bool affectsProperty(CSSPropertyID) const override;
+ bool affectsProperty(CSSPropertyID) const override;
+ bool computeExtentOfAnimationForMatrixAnimation(const FloatRect& rendererBox, LayoutRect&) const;
+
+ bool computeExtentOfAnimationForMatchingTransformLists(const FloatRect& rendererBox, LayoutRect&) const;
+
+ void computeStackingContextImpact();
+ void computeLayoutDependency();
+ void resolveKeyframeStyles();
void validateTransformFunctionList();
-#if ENABLE(CSS_FILTERS)
void checkForMatchingFilterFunctionLists();
+#if ENABLE(FILTERS_LEVEL_2)
+ void checkForMatchingBackdropFilterFunctionLists();
#endif
private:
- KeyframeAnimation(const Animation&, RenderElement*, int index, CompositeAnimation*, RenderStyle* unanimatedStyle);
+ KeyframeAnimation(const Animation&, RenderElement*, CompositeAnimation*, const RenderStyle* unanimatedStyle);
virtual ~KeyframeAnimation();
// Get the styles for the given property surrounding the current animation time and the progress between them.
void fetchIntervalEndpointsForProperty(CSSPropertyID, const RenderStyle*& fromStyle, const RenderStyle*& toStyle, double& progress) const;
- // The keyframes that we are blending.
KeyframeList m_keyframes;
+ std::unique_ptr<RenderStyle> m_unanimatedStyle; // The style just before we started animation
- // The order in which this animation appears in the animation-name style.
- int m_index;
- bool m_startEventDispatched;
-
- // The style just before we started animation
- RefPtr<RenderStyle> m_unanimatedStyle;
+ bool m_startEventDispatched { false };
+ bool m_triggersStackingContext { false };
+ bool m_dependsOnLayout { false };
};
} // namespace WebCore
-
-#endif // KeyframeAnimation_h