#ifndef CC_ANIMATION_SCROLL_OFFSET_ANIMATION_CURVE_H_
#define CC_ANIMATION_SCROLL_OFFSET_ANIMATION_CURVE_H_
#include <memory>
#include <optional>
#include "base/memory/raw_ptr.h"
#include "base/time/time.h"
#include "cc/animation/animation_export.h"
#include "ui/gfx/animation/keyframe/animation_curve.h"
#include "ui/gfx/geometry/point_f.h"
#include "ui/gfx/geometry/vector2d_f.h"
namespace gfx {
class TimingFunction;
}
namespace cc {
class CC_ANIMATION_EXPORT ScrollOffsetAnimationCurve
: public gfx::AnimationCurve {
public:
class Target {
public:
~Target() = default;
virtual void OnScrollOffsetAnimated(const gfx::PointF& value,
int target_property_id,
gfx::KeyframeModel* keyframe_model) = 0;
};
enum class DurationBehavior {
kDeltaBased,
kConstant,
kInverseDelta
};
enum class ScrollType { kProgrammatic, kKeyboard, kMouseWheel, kAutoScroll };
static const ScrollOffsetAnimationCurve* ToScrollOffsetAnimationCurve(
const AnimationCurve* c);
static ScrollOffsetAnimationCurve* ToScrollOffsetAnimationCurve(
AnimationCurve* c);
static base::TimeDelta LinearSegmentDuration(const gfx::Vector2dF& delta,
base::TimeDelta delayed_by,
float velocity);
ScrollOffsetAnimationCurve(const ScrollOffsetAnimationCurve&) = delete;
~ScrollOffsetAnimationCurve() override;
ScrollOffsetAnimationCurve& operator=(const ScrollOffsetAnimationCurve&) =
delete;
void SetInitialValue(const gfx::PointF& initial_value,
base::TimeDelta delayed_by = base::TimeDelta(),
float velocity = 0);
bool HasSetInitialValue() const;
gfx::PointF GetValue(base::TimeDelta t) const;
gfx::PointF target_value() const { return target_value_; }
void UpdateTarget(base::TimeDelta t, const gfx::PointF& new_target);
void ApplyAdjustment(const gfx::Vector2dF& adjustment);
base::TimeDelta Duration() const override;
int Type() const override;
const char* TypeName() const override;
std::unique_ptr<gfx::AnimationCurve> Clone() const override;
std::unique_ptr<ScrollOffsetAnimationCurve>
CloneToScrollOffsetAnimationCurve() const;
void Tick(base::TimeDelta t,
int property_id,
gfx::KeyframeModel* keyframe_model,
gfx::TimingFunction::LimitDirection limit_direction =
gfx::TimingFunction::LimitDirection::RIGHT) const override;
static void SetAnimationDurationForTesting(base::TimeDelta duration);
void set_target(Target* target) { target_ = target; }
private:
FRIEND_TEST_ALL_PREFIXES(ScrollOffsetAnimationCurveTest, CurveWithLargeDelay);
FRIEND_TEST_ALL_PREFIXES(ScrollOffsetAnimationCurveTest,
UpdateTargetZeroLastSegmentDuration);
friend class ScrollOffsetAnimationCurveFactory;
enum class AnimationType { kLinear, kEaseInOut };
ScrollOffsetAnimationCurve(
const gfx::PointF& target_value,
AnimationType animation_type,
ScrollType scroll_type,
std::optional<DurationBehavior> duration_behavior = std::nullopt);
ScrollOffsetAnimationCurve(
const gfx::PointF& target_value,
std::unique_ptr<gfx::TimingFunction> timing_function,
AnimationType animation_type,
ScrollType scroll_type,
std::optional<DurationBehavior> duration_behavior);
base::TimeDelta SegmentDuration(
const gfx::Vector2dF& delta,
base::TimeDelta delayed_by,
std::optional<double> velocity = std::nullopt);
base::TimeDelta EaseInOutSegmentDuration(const gfx::Vector2dF& delta,
DurationBehavior duration_behavior,
base::TimeDelta delayed_by);
base::TimeDelta EaseInOutBoundedSegmentDuration(
const gfx::Vector2dF& new_delta,
base::TimeDelta t,
base::TimeDelta delayed_by);
double CalculateVelocity(base::TimeDelta t);
std::unique_ptr<gfx::TimingFunction> GetEasingFunction(
std::optional<double> slope);
gfx::PointF initial_value_;
gfx::PointF target_value_;
base::TimeDelta total_animation_duration_;
base::TimeDelta last_retarget_;
std::unique_ptr<gfx::TimingFunction> timing_function_;
const AnimationType animation_type_;
const ScrollType scroll_type_;
std::optional<DurationBehavior> duration_behavior_;
bool has_set_initial_value_;
static std::optional<double> animation_duration_for_testing_;
raw_ptr<Target, DanglingUntriaged> target_ = nullptr;
};
}
#endif