Commit f8992f6f authored by Stephen McGruer's avatar Stephen McGruer Committed by Commit Bot

Web Animations: Early-exit from setCurrentTime if new time is null

The spec says that setting the current time to null should throw if the
existing currentTime is non-null, or do nothing otherwise.

Bug: 818196
Change-Id: Iac89e46d6b884c924c88b603fbec77b61a337ce2
Reviewed-on: https://chromium-review.googlesource.com/946050Reviewed-by: default avatarXida Chen <xidachen@chromium.org>
Commit-Queue: Stephen McGruer <smcgruer@chromium.org>
Cr-Commit-Position: refs/heads/master@{#542682}
parent 3b0de264
This is a testharness.js-based test. This is a testharness.js-based test.
FAIL Setting the current time of a pending animation to unresolved does not throw a TypeError Failed to set the 'currentTime' property on 'Animation': currentTime may not be changed from resolved to unresolved
PASS Setting the current time of a playing animation to unresolved throws a TypeError
PASS Setting the current time of a paused animation to unresolved throws a TypeError
FAIL Setting the current time of a pausing animation applies a pending playback rate assert_true: expected true got undefined FAIL Setting the current time of a pausing animation applies a pending playback rate assert_true: expected true got undefined
Harness: the test ran to completion. Harness: the test ran to completion.
...@@ -11,6 +11,39 @@ ...@@ -11,6 +11,39 @@
<script> <script>
'use strict'; 'use strict';
test(t => {
const anim = new Animation();
assert_equals(anim.playState, 'idle');
assert_equals(anim.currentTime, null);
// This should not throw because the currentTime is already null.
anim.currentTime = null;
}, 'Setting the current time of a pending animation to unresolved does not'
+ ' throw a TypeError');
promise_test(async t => {
const anim = createDiv(t).animate(null, 100 * MS_PER_SEC);
await anim.ready;
assert_greater_than_equal(anim.currentTime, 0);
assert_throws({ name: 'TypeError' }, () => {
anim.currentTime = null;
});
}, 'Setting the current time of a playing animation to unresolved throws a'
+ ' TypeError');
promise_test(async t => {
const anim = createDiv(t).animate(null, 100 * MS_PER_SEC);
await anim.ready;
anim.pause();
assert_greater_than_equal(anim.currentTime, 0);
assert_throws({ name: 'TypeError' }, () => {
anim.currentTime = null;
});
}, 'Setting the current time of a paused animation to unresolved throws a'
+ ' TypeError');
promise_test(async t => { promise_test(async t => {
const anim = createDiv(t).animate(null, 100 * MS_PER_SEC); const anim = createDiv(t).animate(null, 100 * MS_PER_SEC);
await anim.ready; await anim.ready;
......
...@@ -164,9 +164,22 @@ bool Animation::Limited(double current_time) const { ...@@ -164,9 +164,22 @@ bool Animation::Limited(double current_time) const {
(playback_rate_ > 0 && current_time >= EffectEnd()); (playback_rate_ > 0 && current_time >= EffectEnd());
} }
void Animation::setCurrentTime(double new_current_time, bool is_null) { void Animation::setCurrentTime(double new_current_time,
bool is_null,
ExceptionState& exception_state) {
PlayStateUpdateScope update_scope(*this, kTimingUpdateOnDemand); PlayStateUpdateScope update_scope(*this, kTimingUpdateOnDemand);
// Step 1. of the procedure to silently set the current time of an
// animation states that we abort if the new time is null.
if (is_null) {
// If the current time is resolved, then throw a TypeError.
if (!IsNull(CurrentTimeInternal())) {
exception_state.ThrowTypeError(
"currentTime may not be changed from resolved to unresolved");
}
return;
}
if (PlayStateInternal() == kIdle) if (PlayStateInternal() == kIdle)
paused_ = true; paused_ = true;
...@@ -455,6 +468,7 @@ double Animation::CalculateStartTime(double current_time) const { ...@@ -455,6 +468,7 @@ double Animation::CalculateStartTime(double current_time) const {
} }
double Animation::CalculateCurrentTime() const { double Animation::CalculateCurrentTime() const {
// TODO(crbug.com/818196): By spec, this should be unresolved, not 0.
if (IsNull(start_time_) || !timeline_) if (IsNull(start_time_) || !timeline_)
return 0; return 0;
return (timeline_->EffectiveTime() - start_time_) * playback_rate_; return (timeline_->EffectiveTime() - start_time_) * playback_rate_;
......
...@@ -112,7 +112,9 @@ class CORE_EXPORT Animation final : public EventTargetWithInlineData, ...@@ -112,7 +112,9 @@ class CORE_EXPORT Animation final : public EventTargetWithInlineData,
double currentTime(bool& is_null); double currentTime(bool& is_null);
double currentTime(); double currentTime();
void setCurrentTime(double new_current_time, bool is_null); void setCurrentTime(double new_current_time,
bool is_null,
ExceptionState& = ASSERT_NO_EXCEPTION);
double CurrentTimeInternal() const; double CurrentTimeInternal() const;
double UnlimitedCurrentTimeInternal() const; double UnlimitedCurrentTimeInternal() const;
......
...@@ -43,7 +43,7 @@ enum AnimationPlayState { "idle", "pending", "running", "paused", "finished" }; ...@@ -43,7 +43,7 @@ enum AnimationPlayState { "idle", "pending", "running", "paused", "finished" };
[RuntimeEnabled=WebAnimationsAPI] attribute AnimationEffectReadOnly? effect; [RuntimeEnabled=WebAnimationsAPI] attribute AnimationEffectReadOnly? effect;
[RuntimeEnabled=WebAnimationsAPI] readonly attribute AnimationTimeline? timeline; [RuntimeEnabled=WebAnimationsAPI] readonly attribute AnimationTimeline? timeline;
[Measure] attribute double? startTime; [Measure] attribute double? startTime;
[Measure] attribute double? currentTime; [Measure, RaisesException=Setter] attribute double? currentTime;
[Measure] attribute double playbackRate; [Measure] attribute double playbackRate;
[Measure] readonly attribute AnimationPlayState playState; [Measure] readonly attribute AnimationPlayState playState;
[Measure, RaisesException] void finish(); [Measure, RaisesException] void finish();
......
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