Skip to content

Commit

Permalink
Initial implementation of progress based ScrollTimelines
Browse files Browse the repository at this point in the history
This work is the first step in implementing upcoming spec change in:
w3c/csswg-drafts#4862

Converted AnimationTimeline::currentTime() to CSSNumberish
Added AnimationTimeline::duration

Bug: 1140602

Change-Id: I5c9b8b7130b91faae5f172493ba5f55d77b4bdd6
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2476900
Commit-Queue: Jordan Taylor <[email protected]>
Reviewed-by: Robert Flack <[email protected]>
Cr-Commit-Position: refs/heads/master@{#826533}
  • Loading branch information
Jordan Taylor authored and Commit Bot committed Nov 11, 2020
1 parent 96f5440 commit 65b2df4
Show file tree
Hide file tree
Showing 20 changed files with 702 additions and 196 deletions.
20 changes: 19 additions & 1 deletion third_party/blink/renderer/core/animation/animation.cc
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
#include "base/metrics/histogram_macros.h"
#include "third_party/blink/public/platform/platform.h"
#include "third_party/blink/public/platform/task_type.h"
#include "third_party/blink/renderer/bindings/core/v8/double_or_scroll_timeline_auto_keyword.h"
#include "third_party/blink/renderer/core/animation/animation_timeline.h"
#include "third_party/blink/renderer/core/animation/animation_utils.h"
#include "third_party/blink/renderer/core/animation/compositor_animations.h"
Expand Down Expand Up @@ -193,6 +194,23 @@ Animation* Animation::Create(AnimationEffect* effect,
}
DCHECK(IsA<DocumentTimeline>(timeline) || timeline->IsScrollTimeline());

// TODO(crbug.com/1097041): Support 'auto' value.
if (timeline->IsScrollTimeline()) {
DoubleOrScrollTimelineAutoKeyword time_range;
To<ScrollTimeline>(timeline)->timeRange(time_range);
// TODO(crbug.com/1140602): Support progress based animations
// We are currently abusing the intended use of the "auto" keyword. We are
// using it here as a signal to use progress based timeline instead of
// having a range based current time. We are doing this maintain backwards
// compatibility with existing tests.
if (time_range.IsScrollTimelineAutoKeyword()) {
exception_state.ThrowDOMException(
DOMExceptionCode::kNotSupportedError,
"progress based animations are not supported");
return nullptr;
}
}

auto* context = timeline->GetDocument()->GetExecutionContext();
return MakeGarbageCollected<Animation>(context, timeline, effect);
}
Expand Down Expand Up @@ -290,7 +308,7 @@ Document* Animation::GetDocument() const {
}

base::Optional<double> Animation::TimelineTime() const {
return timeline_ ? timeline_->currentTime() : base::nullopt;
return timeline_ ? timeline_->CurrentTimeMilliseconds() : base::nullopt;
}

// https://drafts.csswg.org/web-animations/#setting-the-current-time-of-an-animation.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -258,7 +258,7 @@ TEST_F(AnimationAnimationTestNoCompositing, InitialState) {

StartTimeline();
EXPECT_EQ("finished", animation->playState());
EXPECT_EQ(0, timeline->currentTime());
EXPECT_EQ(0, timeline->CurrentTimeMilliseconds());
EXPECT_EQ(0, animation->currentTime());
EXPECT_FALSE(animation->Paused());
EXPECT_FALSE(animation->pending());
Expand Down
12 changes: 11 additions & 1 deletion third_party/blink/renderer/core/animation/animation_timeline.cc
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,13 @@ bool CompareAnimations(const Member<Animation>& left,
Animation::CompareAnimationsOrdering::kPointerOrder);
}

base::Optional<double> AnimationTimeline::currentTime() {
void AnimationTimeline::currentTime(CSSNumberish& currentTime) {
base::Optional<base::TimeDelta> result = CurrentPhaseAndTime().time;
currentTime = result ? CSSNumberish::FromDouble(result->InMillisecondsF())
: CSSNumberish();
}

base::Optional<double> AnimationTimeline::CurrentTimeMilliseconds() {
base::Optional<base::TimeDelta> result = CurrentPhaseAndTime().time;
return result ? base::make_optional(result->InMillisecondsF())
: base::nullopt;
Expand All @@ -51,6 +57,10 @@ base::Optional<double> AnimationTimeline::CurrentTimeSeconds() {
return result ? base::make_optional(result->InSecondsF()) : base::nullopt;
}

void AnimationTimeline::duration(CSSNumberish& duration) {
duration = CSSNumberish();
}

String AnimationTimeline::phase() {
switch (CurrentPhaseAndTime().phase) {
case TimelinePhase::kInactive:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

#include "third_party/blink/renderer/core/animation/animation.h"
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/core/css/cssom/css_numeric_value.h"
#include "third_party/blink/renderer/platform/animation/compositor_animation_timeline.h"
#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"

Expand Down Expand Up @@ -34,9 +35,12 @@ class CORE_EXPORT AnimationTimeline : public ScriptWrappable {
AnimationTimeline(Document*);
~AnimationTimeline() override = default;

base::Optional<double> currentTime();
virtual void currentTime(CSSNumberish&);
base::Optional<double> CurrentTimeMilliseconds();
base::Optional<double> CurrentTimeSeconds();

virtual void duration(CSSNumberish&);

String phase();
TimelinePhase Phase() { return CurrentPhaseAndTime().phase; }

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ enum TimelinePhase { "inactive", "before", "active", "after" };
RuntimeEnabled=WebAnimationsAPI,
Exposed=Window
] interface AnimationTimeline {
readonly attribute double? currentTime;
readonly attribute CSSNumberish? currentTime;
[RuntimeEnabled=ScrollTimeline] readonly attribute CSSNumberish? duration;
[RuntimeEnabled=ScrollTimeline] readonly attribute TimelinePhase phase;
};
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@
// https://drafts.csswg.org/web-animations/#the-computedeffecttiming-dictionary

dictionary ComputedEffectTiming : EffectTiming {
unrestricted double endTime;
unrestricted double activeDuration;
double? localTime;
double? progress;
unrestricted double? currentIteration;
CSSNumberish endTime;
CSSNumberish activeDuration;
CSSNumberish? localTime;
double? progress;
unrestricted double? currentIteration;
};
Original file line number Diff line number Diff line change
Expand Up @@ -1039,7 +1039,8 @@ void CSSAnimations::MaybeApplyPendingUpdate(Element* element) {

// Set the current time as the start time for retargeted transitions
if (retargeted_compositor_transitions.Contains(property)) {
animation->setStartTime(element->GetDocument().Timeline().currentTime());
animation->setStartTime(
element->GetDocument().Timeline().CurrentTimeMilliseconds());
}
animation->Update(kTimingUpdateOnDemand);
running_transition->animation = animation;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ bool DocumentTimeline::IsActive() const {
// timeline current time.
base::Optional<base::TimeDelta>
DocumentTimeline::InitialStartTimeForAnimations() {
base::Optional<double> current_time_ms = currentTime();
base::Optional<double> current_time_ms = CurrentTimeMilliseconds();
if (current_time_ms.has_value()) {
return base::TimeDelta::FromMillisecondsD(current_time_ms.value());
}
Expand Down
66 changes: 33 additions & 33 deletions third_party/blink/renderer/core/animation/document_timeline_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ class AnimationDocumentTimelineTest : public PageTestBase {
timeline->SetTimingForTesting(platform_timing);

timeline->ResetForTesting();
ASSERT_EQ(0, timeline->currentTime());
ASSERT_EQ(0, timeline->CurrentTimeMilliseconds());
}

void TearDown() override {
Expand Down Expand Up @@ -163,11 +163,11 @@ TEST_F(AnimationDocumentTimelineTest, EmptyKeyframeAnimation) {
timeline->Play(keyframe_effect);

UpdateClockAndService(0);
EXPECT_FLOAT_EQ(0, timeline->currentTime().value());
EXPECT_FLOAT_EQ(0, timeline->CurrentTimeMilliseconds().value());
EXPECT_FALSE(keyframe_effect->IsInEffect());

UpdateClockAndService(1000);
EXPECT_FLOAT_EQ(1000, timeline->currentTime().value());
EXPECT_FLOAT_EQ(1000, timeline->CurrentTimeMilliseconds().value());
}

TEST_F(AnimationDocumentTimelineTest, EmptyForwardsKeyframeAnimation) {
Expand All @@ -180,32 +180,32 @@ TEST_F(AnimationDocumentTimelineTest, EmptyForwardsKeyframeAnimation) {
timeline->Play(keyframe_effect);

UpdateClockAndService(0);
EXPECT_EQ(0, timeline->currentTime());
EXPECT_EQ(0, timeline->CurrentTimeMilliseconds());
EXPECT_TRUE(keyframe_effect->IsInEffect());

UpdateClockAndService(1000);
EXPECT_FLOAT_EQ(1000, timeline->currentTime().value());
EXPECT_FLOAT_EQ(1000, timeline->CurrentTimeMilliseconds().value());
}

TEST_F(AnimationDocumentTimelineTest, ZeroTime) {
GetAnimationClock().UpdateTime(TimeTicksFromMillisecondsD(1000));
EXPECT_EQ(1000, timeline->currentTime());
EXPECT_EQ(1000, timeline->CurrentTimeMilliseconds());

GetAnimationClock().UpdateTime(TimeTicksFromMillisecondsD(2000));
EXPECT_EQ(2000, timeline->currentTime());
EXPECT_EQ(2000, timeline->CurrentTimeMilliseconds());
}

TEST_F(AnimationDocumentTimelineTest, CurrentTimeSeconds) {
GetAnimationClock().UpdateTime(TimeTicksFromMillisecondsD(2000));
EXPECT_EQ(2, timeline->CurrentTimeSeconds());
EXPECT_EQ(2000, timeline->currentTime());
EXPECT_EQ(2000, timeline->CurrentTimeMilliseconds());

auto* document_without_frame = Document::CreateForTest();
auto* inactive_timeline = MakeGarbageCollected<DocumentTimeline>(
document_without_frame, base::TimeDelta(), platform_timing);

EXPECT_FALSE(inactive_timeline->CurrentTimeSeconds());
EXPECT_FALSE(inactive_timeline->currentTime());
EXPECT_FALSE(inactive_timeline->CurrentTimeMilliseconds());
}

TEST_F(AnimationDocumentTimelineTest, PlaybackRateNormal) {
Expand All @@ -215,11 +215,11 @@ TEST_F(AnimationDocumentTimelineTest, PlaybackRateNormal) {
EXPECT_EQ(1.0, timeline->PlaybackRate());
GetAnimationClock().UpdateTime(TimeTicksFromMillisecondsD(1000));
EXPECT_EQ(zero_time, timeline->ZeroTime());
EXPECT_EQ(1000, timeline->currentTime());
EXPECT_EQ(1000, timeline->CurrentTimeMilliseconds());

GetAnimationClock().UpdateTime(TimeTicksFromMillisecondsD(2000));
EXPECT_EQ(zero_time, timeline->ZeroTime());
EXPECT_EQ(2000, timeline->currentTime());
EXPECT_EQ(2000, timeline->CurrentTimeMilliseconds());
}

TEST_F(AnimationDocumentTimelineTest, PlaybackRateNormalWithOriginTime) {
Expand All @@ -230,33 +230,33 @@ TEST_F(AnimationDocumentTimelineTest, PlaybackRateNormalWithOriginTime) {

EXPECT_EQ(1.0, timeline->PlaybackRate());
EXPECT_EQ(base::TimeTicks() + origin_time, timeline->ZeroTime());
EXPECT_EQ(1000, timeline->currentTime());
EXPECT_EQ(1000, timeline->CurrentTimeMilliseconds());

GetAnimationClock().UpdateTime(TimeTicksFromMillisecondsD(100));
EXPECT_EQ(base::TimeTicks() + origin_time, timeline->ZeroTime());
EXPECT_EQ(1100, timeline->currentTime());
EXPECT_EQ(1100, timeline->CurrentTimeMilliseconds());

GetAnimationClock().UpdateTime(TimeTicksFromMillisecondsD(200));
EXPECT_EQ(base::TimeTicks() + origin_time, timeline->ZeroTime());
EXPECT_EQ(1200, timeline->currentTime());
EXPECT_EQ(1200, timeline->CurrentTimeMilliseconds());
}

TEST_F(AnimationDocumentTimelineTest, PlaybackRatePause) {
GetAnimationClock().UpdateTime(TimeTicksFromMillisecondsD(1000));
EXPECT_EQ(base::TimeTicks(), timeline->ZeroTime());
EXPECT_EQ(1000, timeline->currentTime());
EXPECT_EQ(1000, timeline->CurrentTimeMilliseconds());

timeline->SetPlaybackRate(0.0);
EXPECT_EQ(0.0, timeline->PlaybackRate());
GetAnimationClock().UpdateTime(TimeTicksFromMillisecondsD(2000));
EXPECT_EQ(TimeTicksFromMillisecondsD(1000), timeline->ZeroTime());
EXPECT_EQ(1000, timeline->currentTime());
EXPECT_EQ(1000, timeline->CurrentTimeMilliseconds());

timeline->SetPlaybackRate(1.0);
EXPECT_EQ(1.0, timeline->PlaybackRate());
GetAnimationClock().UpdateTime(TimeTicksFromMillisecondsD(4000));
EXPECT_EQ(TimeTicksFromMillisecondsD(1000), timeline->ZeroTime());
EXPECT_EQ(3000, timeline->currentTime());
EXPECT_EQ(3000, timeline->CurrentTimeMilliseconds());
}

TEST_F(AnimationDocumentTimelineTest, PlaybackRatePauseWithOriginTime) {
Expand All @@ -266,61 +266,61 @@ TEST_F(AnimationDocumentTimelineTest, PlaybackRatePauseWithOriginTime) {
timeline->ResetForTesting();

EXPECT_EQ(base::TimeTicks() + origin_time, timeline->ZeroTime());
EXPECT_EQ(1000, timeline->currentTime());
EXPECT_EQ(1000, timeline->CurrentTimeMilliseconds());
GetAnimationClock().UpdateTime(TimeTicksFromMillisecondsD(100));
EXPECT_EQ(base::TimeTicks() + origin_time, timeline->ZeroTime());
EXPECT_EQ(1100, timeline->currentTime());
EXPECT_EQ(1100, timeline->CurrentTimeMilliseconds());

timeline->SetPlaybackRate(0.0);
EXPECT_EQ(0.0, timeline->PlaybackRate());
GetAnimationClock().UpdateTime(TimeTicksFromMillisecondsD(200));
EXPECT_EQ(TimeTicksFromMillisecondsD(1100), timeline->ZeroTime());
EXPECT_EQ(1100, timeline->currentTime());
EXPECT_EQ(1100, timeline->CurrentTimeMilliseconds());

timeline->SetPlaybackRate(1.0);
EXPECT_EQ(1.0, timeline->PlaybackRate());
EXPECT_EQ(TimeTicksFromMillisecondsD(-900), timeline->ZeroTime());
EXPECT_EQ(1100, timeline->currentTime());
EXPECT_EQ(1100, timeline->CurrentTimeMilliseconds());

GetAnimationClock().UpdateTime(TimeTicksFromMillisecondsD(400));
EXPECT_EQ(TimeTicksFromMillisecondsD(-900), timeline->ZeroTime());
EXPECT_EQ(1300, timeline->currentTime());
EXPECT_EQ(1300, timeline->CurrentTimeMilliseconds());
}

TEST_F(AnimationDocumentTimelineTest, PlaybackRateSlow) {
GetAnimationClock().UpdateTime(TimeTicksFromMillisecondsD(1000));
EXPECT_EQ(base::TimeTicks(), timeline->ZeroTime());
EXPECT_EQ(1000, timeline->currentTime());
EXPECT_EQ(1000, timeline->CurrentTimeMilliseconds());

timeline->SetPlaybackRate(0.5);
EXPECT_EQ(0.5, timeline->PlaybackRate());
GetAnimationClock().UpdateTime(TimeTicksFromMillisecondsD(3000));
EXPECT_EQ(TimeTicksFromMillisecondsD(-1000), timeline->ZeroTime());
EXPECT_EQ(2000, timeline->currentTime());
EXPECT_EQ(2000, timeline->CurrentTimeMilliseconds());

timeline->SetPlaybackRate(1.0);
EXPECT_EQ(1.0, timeline->PlaybackRate());
GetAnimationClock().UpdateTime(TimeTicksFromMillisecondsD(4000));
EXPECT_EQ(TimeTicksFromMillisecondsD(1000), timeline->ZeroTime());
EXPECT_EQ(3000, timeline->currentTime());
EXPECT_EQ(3000, timeline->CurrentTimeMilliseconds());
}

TEST_F(AnimationDocumentTimelineTest, PlaybackRateFast) {
GetAnimationClock().UpdateTime(TimeTicksFromMillisecondsD(1000));
EXPECT_EQ(base::TimeTicks(), timeline->ZeroTime());
EXPECT_EQ(1000, timeline->currentTime());
EXPECT_EQ(1000, timeline->CurrentTimeMilliseconds());

timeline->SetPlaybackRate(2.0);
EXPECT_EQ(2.0, timeline->PlaybackRate());
GetAnimationClock().UpdateTime(TimeTicksFromMillisecondsD(3000));
EXPECT_EQ(TimeTicksFromMillisecondsD(500), timeline->ZeroTime());
EXPECT_EQ(5000, timeline->currentTime());
EXPECT_EQ(5000, timeline->CurrentTimeMilliseconds());

timeline->SetPlaybackRate(1.0);
EXPECT_EQ(1.0, timeline->PlaybackRate());
GetAnimationClock().UpdateTime(TimeTicksFromMillisecondsD(4000));
EXPECT_EQ(TimeTicksFromMillisecondsD(-2000), timeline->ZeroTime());
EXPECT_EQ(6000, timeline->currentTime());
EXPECT_EQ(6000, timeline->CurrentTimeMilliseconds());
}

TEST_F(AnimationDocumentTimelineTest, PlaybackRateFastWithOriginTime) {
Expand All @@ -330,25 +330,25 @@ TEST_F(AnimationDocumentTimelineTest, PlaybackRateFastWithOriginTime) {

GetAnimationClock().UpdateTime(TimeTicksFromMillisecondsD(100000));
EXPECT_EQ(TimeTicksFromMillisecondsD(-1000000), timeline->ZeroTime());
EXPECT_EQ(1100000, timeline->currentTime());
EXPECT_EQ(1100000, timeline->CurrentTimeMilliseconds());

timeline->SetPlaybackRate(2.0);
EXPECT_EQ(2.0, timeline->PlaybackRate());
EXPECT_EQ(TimeTicksFromMillisecondsD(-450000), timeline->ZeroTime());
EXPECT_EQ(1100000, timeline->currentTime());
EXPECT_EQ(1100000, timeline->CurrentTimeMilliseconds());

GetAnimationClock().UpdateTime(TimeTicksFromMillisecondsD(300000));
EXPECT_EQ(TimeTicksFromMillisecondsD(-450000), timeline->ZeroTime());
EXPECT_EQ(1500000, timeline->currentTime());
EXPECT_EQ(1500000, timeline->CurrentTimeMilliseconds());

timeline->SetPlaybackRate(1.0);
EXPECT_EQ(1.0, timeline->PlaybackRate());
EXPECT_EQ(TimeTicksFromMillisecondsD(-1200000), timeline->ZeroTime());
EXPECT_EQ(1500000, timeline->currentTime());
EXPECT_EQ(1500000, timeline->CurrentTimeMilliseconds());

GetAnimationClock().UpdateTime(TimeTicksFromMillisecondsD(400000));
EXPECT_EQ(TimeTicksFromMillisecondsD(-1200000), timeline->ZeroTime());
EXPECT_EQ(1600000, timeline->currentTime());
EXPECT_EQ(1600000, timeline->CurrentTimeMilliseconds());
}

TEST_F(AnimationDocumentTimelineTest, PauseForTesting) {
Expand Down
Loading

0 comments on commit 65b2df4

Please sign in to comment.