blob: 83c21cca705ce239236cbf38a6f880b94ed5a268 [file] [log] [blame]
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CC_ANIMATION_WORKLET_ANIMATION_H_
#define CC_ANIMATION_WORKLET_ANIMATION_H_
#include "base/gtest_prod_util.h"
#include "base/optional.h"
#include "base/time/time.h"
#include "cc/animation/animation_export.h"
#include "cc/animation/animation_host.h"
#include "cc/animation/single_keyframe_effect_animation.h"
#include "cc/trees/property_tree.h"
namespace cc {
namespace {
FORWARD_DECLARE_TEST(WorkletAnimationTest, NonImplInstanceDoesNotTickKeyframe);
} // namespace
class AnimationOptions;
class AnimationEffectTimings;
class ScrollTimeline;
// A WorkletAnimation is an animation that allows its animation
// timing to be controlled by an animator instance that is running in a
// AnimationWorkletGlobalScope.
// Two instances of this class are created for Blink WorkletAnimation:
// 1. UI thread instance that keeps all the meta data.
// 2. Impl thread instance that ticks the animations on the Impl thread.
// When Blink WorkletAnimation is updated, it calls the UI thread instance to
// modify its properties. The updated properties are pushed by the UI thread
// instance to the Impl thread instance during commit.
class CC_ANIMATION_EXPORT WorkletAnimation final
: public SingleKeyframeEffectAnimation {
public:
enum class State { PENDING, RUNNING, REMOVED };
WorkletAnimation(int cc_animation_id,
WorkletAnimationId worklet_animation_id,
const std::string& name,
double playback_rate,
std::unique_ptr<ScrollTimeline> scroll_timeline,
std::unique_ptr<AnimationOptions> options,
std::unique_ptr<AnimationEffectTimings> effect_timings,
bool is_controlling_instance);
static scoped_refptr<WorkletAnimation> Create(
WorkletAnimationId worklet_animation_id,
const std::string& name,
double playback_rate,
std::unique_ptr<ScrollTimeline> scroll_timeline,
std::unique_ptr<AnimationOptions> options,
std::unique_ptr<AnimationEffectTimings> effect_timings);
scoped_refptr<Animation> CreateImplInstance() const override;
WorkletAnimationId worklet_animation_id() { return worklet_animation_id_; }
const std::string& name() const { return name_; }
const ScrollTimeline* scroll_timeline() const {
return scroll_timeline_.get();
}
bool IsWorkletAnimation() const override;
void Tick(base::TimeTicks monotonic_time) override;
void UpdateInputState(MutatorInputState* input_state,
base::TimeTicks monotonic_time,
const ScrollTree& scroll_tree,
bool is_active_tree);
void SetOutputState(const MutatorOutputState::AnimationState& state);
void PushPropertiesTo(Animation* animation_impl) override;
// Should be called when the ScrollTimeline attached to this animation has a
// change, such as when the scroll source changes ElementId.
void UpdateScrollTimeline(base::Optional<ElementId> scroller_id,
base::Optional<double> start_scroll_offset,
base::Optional<double> end_scroll_offset);
// Should be called when the pending tree is promoted to active, as this may
// require updating the ElementId for the ScrollTimeline scroll source.
void PromoteScrollTimelinePendingToActive() override;
// Called by Blink WorkletAnimation when its playback rate is updated.
void UpdatePlaybackRate(double playback_rate);
void SetPlaybackRateForTesting(double playback_rate) {
SetPlaybackRate(playback_rate);
}
void RemoveKeyframeModel(int keyframe_model_id) override;
private:
FRIEND_TEST_ALL_PREFIXES(WorkletAnimationTest,
NonImplInstanceDoesNotTickKeyframe);
WorkletAnimation(int cc_animation_id,
WorkletAnimationId worklet_animation_id,
const std::string& name,
double playback_rate,
std::unique_ptr<ScrollTimeline> scroll_timeline,
std::unique_ptr<AnimationOptions> options,
std::unique_ptr<AnimationEffectTimings> effect_timings,
bool is_controlling_instance,
std::unique_ptr<KeyframeEffect> effect);
~WorkletAnimation() override;
// Returns the current time to be passed into the underlying AnimationWorklet.
// The current time is based on the timeline associated with the animation and
// in case of scroll timeline it may be nullopt when the associated scrolling
// node is not available in the particular ScrollTree.
base::Optional<base::TimeDelta> CurrentTime(base::TimeTicks monotonic_time,
const ScrollTree& scroll_tree,
bool is_active_tree);
// Returns true if the worklet animation needs to be updated which happens iff
// its current time is going to be different from last time given these input.
bool NeedsUpdate(base::TimeTicks monotonic_time,
const ScrollTree& scroll_tree,
bool is_active_tree);
std::unique_ptr<AnimationOptions> CloneOptions() const {
return options_ ? options_->Clone() : nullptr;
}
std::unique_ptr<AnimationEffectTimings> CloneEffectTimings() const {
return effect_timings_ ? effect_timings_->Clone() : nullptr;
}
// Updates the playback rate of the Impl thread instance.
// Called by the UI thread WorletAnimation instance during commit.
void SetPlaybackRate(double playback_rate);
bool IsTimelineActive(const ScrollTree& scroll_tree,
bool is_active_tree) const;
WorkletAnimationId worklet_animation_id_;
std::string name_;
// The ScrollTimeline associated with the underlying animation. If null, the
// animation is based on a DocumentTimeline.
//
// TODO(crbug.com/780148): A WorkletAnimation should own an AnimationTimeline
// which must exist but can either be a DocumentTimeline, ScrollTimeline, or
// some other future implementation.
std::unique_ptr<ScrollTimeline> scroll_timeline_;
// Controls speed of the animation.
// https://drafts.csswg.org/web-animations-2/#animation-effect-playback-rate
// For UI thread instance contains the meta value to be pushed to the Impl
// thread instance.
// For the Impl thread instance contains the actual playback rate of the
// animation.
double playback_rate_;
std::unique_ptr<AnimationOptions> options_;
std::unique_ptr<AnimationEffectTimings> effect_timings_;
// Local time is used as an input to the keyframe effect of this animation.
// The value comes from the user script that runs inside the animation worklet
// global scope.
base::Optional<base::TimeDelta> local_time_;
base::Optional<base::TimeTicks> start_time_;
// Last current time used for updating. We use this to skip updating if
// current time has not changed since last update.
base::Optional<base::TimeDelta> last_current_time_;
State state_;
bool is_impl_instance_;
};
inline WorkletAnimation* ToWorkletAnimation(Animation* animation) {
DCHECK(animation->IsWorkletAnimation());
return static_cast<WorkletAnimation*>(animation);
}
} // namespace cc
#endif // CC_ANIMATION_WORKLET_ANIMATION_H_