Commit a00f53d9 authored by Kevin Ellis's avatar Kevin Ellis Committed by Commit Bot

Align stickiness rules for startTime and reverse with spec for CSSAnimations.

https://github.com/w3c/csswg-drafts/issues/4822

Bug: 1059772
Change-Id: Id21c3c152f8cf6771703a16fcab8e80686608170
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2090197
Commit-Queue: Kevin Ellis <kevers@chromium.org>
Reviewed-by: default avatarRobert Flack <flackr@chromium.org>
Cr-Commit-Position: refs/heads/master@{#749013}
parent 1c34ad4c
...@@ -165,7 +165,7 @@ class CORE_EXPORT Animation : public EventTargetWithInlineData, ...@@ -165,7 +165,7 @@ class CORE_EXPORT Animation : public EventTargetWithInlineData,
virtual void pause(ExceptionState& = ASSERT_NO_EXCEPTION); virtual void pause(ExceptionState& = ASSERT_NO_EXCEPTION);
virtual void play(ExceptionState& = ASSERT_NO_EXCEPTION); virtual void play(ExceptionState& = ASSERT_NO_EXCEPTION);
void reverse(ExceptionState& = ASSERT_NO_EXCEPTION); virtual void reverse(ExceptionState& = ASSERT_NO_EXCEPTION);
void finish(ExceptionState& = ASSERT_NO_EXCEPTION); void finish(ExceptionState& = ASSERT_NO_EXCEPTION);
void updatePlaybackRate(double playback_rate, void updatePlaybackRate(double playback_rate,
ExceptionState& = ASSERT_NO_EXCEPTION); ExceptionState& = ASSERT_NO_EXCEPTION);
...@@ -202,9 +202,9 @@ class CORE_EXPORT Animation : public EventTargetWithInlineData, ...@@ -202,9 +202,9 @@ class CORE_EXPORT Animation : public EventTargetWithInlineData,
double startTime(bool& is_null) const; double startTime(bool& is_null) const;
base::Optional<double> startTime() const; base::Optional<double> startTime() const;
base::Optional<double> StartTimeInternal() const { return start_time_; } base::Optional<double> StartTimeInternal() const { return start_time_; }
void setStartTime(double, virtual void setStartTime(double,
bool is_null, bool is_null,
ExceptionState& = ASSERT_NO_EXCEPTION); ExceptionState& = ASSERT_NO_EXCEPTION);
const AnimationEffect* effect() const { return content_.Get(); } const AnimationEffect* effect() const { return content_.Get(); }
AnimationEffect* effect() { return content_.Get(); } AnimationEffect* effect() { return content_.Get(); }
......
...@@ -15,7 +15,7 @@ CSSAnimation::CSSAnimation(ExecutionContext* execution_context, ...@@ -15,7 +15,7 @@ CSSAnimation::CSSAnimation(ExecutionContext* execution_context,
const String& animation_name) const String& animation_name)
: Animation(execution_context, timeline, content), : Animation(execution_context, timeline, content),
animation_name_(animation_name), animation_name_(animation_name),
sticky_play_state_(Animation::kUnset) {} ignore_css_play_state_(false) {}
String CSSAnimation::playState() const { String CSSAnimation::playState() const {
FlushStyles(); FlushStyles();
...@@ -28,13 +28,29 @@ bool CSSAnimation::pending() const { ...@@ -28,13 +28,29 @@ bool CSSAnimation::pending() const {
} }
void CSSAnimation::pause(ExceptionState& exception_state) { void CSSAnimation::pause(ExceptionState& exception_state) {
sticky_play_state_ = kPaused;
Animation::pause(exception_state); Animation::pause(exception_state);
if (exception_state.HadException())
return;
ignore_css_play_state_ = true;
} }
void CSSAnimation::play(ExceptionState& exception_state) { void CSSAnimation::play(ExceptionState& exception_state) {
sticky_play_state_ = kRunning;
Animation::play(exception_state); Animation::play(exception_state);
if (exception_state.HadException())
return;
ignore_css_play_state_ = true;
}
void CSSAnimation::reverse(ExceptionState& exception_state) {
PlayStateTransitionScope scope(*this);
Animation::reverse(exception_state);
}
void CSSAnimation::setStartTime(double start_time,
bool is_null,
ExceptionState& exception_state) {
PlayStateTransitionScope scope(*this);
Animation::setStartTime(start_time, is_null, exception_state);
} }
void CSSAnimation::FlushStyles() const { void CSSAnimation::FlushStyles() const {
...@@ -44,4 +60,16 @@ void CSSAnimation::FlushStyles() const { ...@@ -44,4 +60,16 @@ void CSSAnimation::FlushStyles() const {
GetDocument()->UpdateStyleAndLayoutTree(); GetDocument()->UpdateStyleAndLayoutTree();
} }
CSSAnimation::PlayStateTransitionScope::PlayStateTransitionScope(
CSSAnimation& animation)
: animation_(animation) {
was_paused_ = animation_.Paused();
}
CSSAnimation::PlayStateTransitionScope::~PlayStateTransitionScope() {
bool is_paused = animation_.Paused();
if (was_paused_ != is_paused)
animation_.ignore_css_play_state_ = true;
}
} // namespace blink } // namespace blink
...@@ -40,22 +40,37 @@ class CORE_EXPORT CSSAnimation : public Animation { ...@@ -40,22 +40,37 @@ class CORE_EXPORT CSSAnimation : public Animation {
// conditionally sticky and override the animation-play-state style. // conditionally sticky and override the animation-play-state style.
void pause(ExceptionState& = ASSERT_NO_EXCEPTION) override; void pause(ExceptionState& = ASSERT_NO_EXCEPTION) override;
void play(ExceptionState& = ASSERT_NO_EXCEPTION) override; void play(ExceptionState& = ASSERT_NO_EXCEPTION) override;
void reverse(ExceptionState& = ASSERT_NO_EXCEPTION) override;
void setStartTime(double,
bool is_null,
ExceptionState& = ASSERT_NO_EXCEPTION) override;
// When set, the override takes precedence over animation-play-state. // When set, subsequent changes to animation-play-state no longer affect the
// play state.
// https://drafts.csswg.org/css-animations-2/#interaction-between-animation-play-state-and-web-animations-API // https://drafts.csswg.org/css-animations-2/#interaction-between-animation-play-state-and-web-animations-API
AnimationPlayState getWebAnimationOverriddenPlayState() { bool getIgnoreCSSPlayState() { return ignore_css_play_state_; }
return sticky_play_state_; void resetIgnoreCSSPlayState() { ignore_css_play_state_ = false; }
}
void ResetWebAnimationOverriddenPlayState() { sticky_play_state_ = kUnset; }
private: private:
void FlushStyles() const; void FlushStyles() const;
class PlayStateTransitionScope {
STACK_ALLOCATED();
public:
explicit PlayStateTransitionScope(CSSAnimation& animation);
~PlayStateTransitionScope();
private:
CSSAnimation& animation_;
bool was_paused_;
};
String animation_name_; String animation_name_;
// When set, the web-animation API is overruling the animation-play-state // When set, the web-animation API is overruling the animation-play-state
// style. // style.
AnimationPlayState sticky_play_state_; bool ignore_css_play_state_;
}; };
template <> template <>
......
...@@ -399,17 +399,12 @@ void CSSAnimations::CalculateAnimationUpdate(CSSAnimationUpdate& update, ...@@ -399,17 +399,12 @@ void CSSAnimations::CalculateAnimationUpdate(CSSAnimationUpdate& update,
// play state via the animation-play-state style. Ensure that the new // play state via the animation-play-state style. Ensure that the new
// play state based on animation-play-state differs from the current // play state based on animation-play-state differs from the current
// play state and that the change is not blocked by a sticky state. // play state and that the change is not blocked by a sticky state.
Animation::AnimationPlayState sticky_override =
animation->getWebAnimationOverriddenPlayState();
bool toggle_pause_state = false; bool toggle_pause_state = false;
if (is_paused != was_paused) { if (is_paused != was_paused && !animation->getIgnoreCSSPlayState()) {
if (animation->Paused() && sticky_override != Animation::kPaused && if (animation->Paused() && !is_paused)
!is_paused) {
toggle_pause_state = true; toggle_pause_state = true;
} else if (animation->Playing() && else if (animation->Playing() && is_paused)
sticky_override != Animation::kRunning && is_paused) {
toggle_pause_state = true; toggle_pause_state = true;
}
} }
if (keyframes_rule != existing_animation->style_rule || if (keyframes_rule != existing_animation->style_rule ||
...@@ -504,10 +499,10 @@ void CSSAnimations::MaybeApplyPendingUpdate(Element* element) { ...@@ -504,10 +499,10 @@ void CSSAnimations::MaybeApplyPendingUpdate(Element* element) {
if (animation->Paused()) { if (animation->Paused()) {
animation->Unpause(); animation->Unpause();
animation->ResetWebAnimationOverriddenPlayState(); animation->resetIgnoreCSSPlayState();
} else { } else {
animation->pause(); animation->pause();
animation->ResetWebAnimationOverriddenPlayState(); animation->resetIgnoreCSSPlayState();
} }
if (animation->Outdated()) if (animation->Outdated())
animation->Update(kTimingUpdateOnDemand); animation->Update(kTimingUpdateOnDemand);
...@@ -552,7 +547,7 @@ void CSSAnimations::MaybeApplyPendingUpdate(Element* element) { ...@@ -552,7 +547,7 @@ void CSSAnimations::MaybeApplyPendingUpdate(Element* element) {
animation->play(); animation->play();
if (inert_animation->Paused()) if (inert_animation->Paused())
animation->pause(); animation->pause();
animation->ResetWebAnimationOverriddenPlayState(); animation->resetIgnoreCSSPlayState();
animation->Update(kTimingUpdateOnDemand); animation->Update(kTimingUpdateOnDemand);
running_animations_.push_back( running_animations_.push_back(
......
This is a testharness.js-based test.
PASS play() overrides animation-play-state
PASS play() does NOT override the animation-play-state if there was an error
PASS pause() overrides animation-play-state
FAIL reverse() overrides animation-play-state when it starts playing the animation assert_equals: Should still be running even after flipping the animation-play-state expected "running" but got "paused"
PASS reverse() does NOT override animation-play-state if the animation is already running
FAIL Setting the startTime to null overrides animation-play-state if the animation is already running assert_equals: Should still be paused even after flipping the animation-play-state expected "paused" but got "running"
FAIL Setting the startTime to non-null overrides animation-play-state if the animation is paused assert_equals: Should still be running even after flipping the animation-play-state expected "running" but got "paused"
PASS Setting the startTime to non-null does NOT override the animation-play-state if the animation is already running
PASS Setting the current time completes a pending pause
Harness: the test ran to completion.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment