#include "config.h"
#include "CSSAnimation.h"
#include "Animation.h"
#include "AnimationEvent.h"
#include "Element.h"
#include "InspectorInstrumentation.h"
#include "RenderStyle.h"
#include <wtf/IsoMallocInlines.h>
namespace WebCore {
WTF_MAKE_ISO_ALLOCATED_IMPL(CSSAnimation);
Ref<CSSAnimation> CSSAnimation::create(Element& owningElement, const Animation& backingAnimation, const RenderStyle* oldStyle, const RenderStyle& newStyle)
{
auto result = adoptRef(*new CSSAnimation(owningElement, backingAnimation));
result->initialize(oldStyle, newStyle);
InspectorInstrumentation::didCreateWebAnimation(result.get());
return result;
}
CSSAnimation::CSSAnimation(Element& element, const Animation& backingAnimation)
: DeclarativeAnimation(element, backingAnimation)
, m_animationName(backingAnimation.name())
{
}
void CSSAnimation::syncPropertiesWithBackingAnimation()
{
DeclarativeAnimation::syncPropertiesWithBackingAnimation();
if (!effect())
return;
suspendEffectInvalidation();
auto& animation = backingAnimation();
auto* animationEffect = effect();
if (!m_overriddenProperties.contains(Property::FillMode)) {
switch (animation.fillMode()) {
case AnimationFillMode::None:
animationEffect->setFill(FillMode::None);
break;
case AnimationFillMode::Backwards:
animationEffect->setFill(FillMode::Backwards);
break;
case AnimationFillMode::Forwards:
animationEffect->setFill(FillMode::Forwards);
break;
case AnimationFillMode::Both:
animationEffect->setFill(FillMode::Both);
break;
}
}
if (!m_overriddenProperties.contains(Property::Direction)) {
switch (animation.direction()) {
case Animation::AnimationDirectionNormal:
animationEffect->setDirection(PlaybackDirection::Normal);
break;
case Animation::AnimationDirectionAlternate:
animationEffect->setDirection(PlaybackDirection::Alternate);
break;
case Animation::AnimationDirectionReverse:
animationEffect->setDirection(PlaybackDirection::Reverse);
break;
case Animation::AnimationDirectionAlternateReverse:
animationEffect->setDirection(PlaybackDirection::AlternateReverse);
break;
}
}
if (!m_overriddenProperties.contains(Property::IterationCount)) {
auto iterationCount = animation.iterationCount();
animationEffect->setIterations(iterationCount == Animation::IterationCountInfinite ? std::numeric_limits<double>::infinity() : iterationCount);
}
if (!m_overriddenProperties.contains(Property::Delay))
animationEffect->setDelay(Seconds(animation.delay()));
if (!m_overriddenProperties.contains(Property::Duration))
animationEffect->setIterationDuration(Seconds(animation.duration()));
animationEffect->updateStaticTimingProperties();
effectTimingDidChange();
if (!m_overriddenProperties.contains(Property::PlayState)) {
if (animation.playState() == AnimationPlayState::Playing && playState() == WebAnimation::PlayState::Paused)
play();
else if (animation.playState() == AnimationPlayState::Paused && playState() == WebAnimation::PlayState::Running)
pause();
}
unsuspendEffectInvalidation();
}
ExceptionOr<void> CSSAnimation::bindingsPlay()
{
auto retVal = DeclarativeAnimation::bindingsPlay();
if (!retVal.hasException())
m_overriddenProperties.add(Property::PlayState);
return retVal;
}
ExceptionOr<void> CSSAnimation::bindingsPause()
{
auto retVal = DeclarativeAnimation::bindingsPause();
if (!retVal.hasException())
m_overriddenProperties.add(Property::PlayState);
return retVal;
}
void CSSAnimation::setBindingsEffect(RefPtr<AnimationEffect>&& newEffect)
{
auto* previousEffect = effect();
DeclarativeAnimation::setBindingsEffect(WTFMove(newEffect));
if (effect() != previousEffect) {
m_overriddenProperties.add(Property::Duration);
m_overriddenProperties.add(Property::TimingFunction);
m_overriddenProperties.add(Property::IterationCount);
m_overriddenProperties.add(Property::Direction);
m_overriddenProperties.add(Property::Delay);
m_overriddenProperties.add(Property::FillMode);
}
}
void CSSAnimation::setBindingsStartTime(Optional<double> startTime)
{
auto previousPlayState = playState();
DeclarativeAnimation::setBindingsStartTime(startTime);
auto currentPlayState = playState();
if (currentPlayState != previousPlayState && (currentPlayState == PlayState::Paused || previousPlayState == PlayState::Paused))
m_overriddenProperties.add(Property::PlayState);
}
ExceptionOr<void> CSSAnimation::bindingsReverse()
{
auto previousPlayState = playState();
auto retVal = DeclarativeAnimation::bindingsReverse();
if (!retVal.hasException()) {
auto currentPlayState = playState();
if (currentPlayState != previousPlayState && (currentPlayState == PlayState::Paused || previousPlayState == PlayState::Paused))
m_overriddenProperties.add(Property::PlayState);
}
return retVal;
}
void CSSAnimation::effectTimingWasUpdatedUsingBindings(OptionalEffectTiming timing)
{
if (timing.duration)
m_overriddenProperties.add(Property::Duration);
if (timing.iterations)
m_overriddenProperties.add(Property::IterationCount);
if (timing.delay)
m_overriddenProperties.add(Property::Delay);
if (!timing.easing.isNull())
m_overriddenProperties.add(Property::TimingFunction);
if (timing.fill)
m_overriddenProperties.add(Property::FillMode);
if (timing.direction)
m_overriddenProperties.add(Property::Direction);
}
void CSSAnimation::effectKeyframesWereSetUsingBindings()
{
m_overriddenProperties.add(Property::TimingFunction);
}
Ref<AnimationEventBase> CSSAnimation::createEvent(const AtomString& eventType, double elapsedTime, const String& pseudoId, Optional<Seconds> timelineTime)
{
return AnimationEvent::create(eventType, m_animationName, elapsedTime, pseudoId, timelineTime, this);
}
}