1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
cc / animation / scroll_offset_animation_curve.h [blame]
// Copyright 2013 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#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 gfx
namespace cc {
// ScrollOffsetAnimationCurve computes scroll offset as a function of time
// during a scroll offset animation.
//
// Scroll offset animations can run either in Blink or in cc, in response to
// user input or programmatic scroll operations. For more information about
// scheduling and servicing scroll animations, see blink::ScrollAnimator and
// blink::ProgrammaticScrollAnimator.
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;
};
// Indicates how the animation duration should be computed for Ease-in-out
// style scroll animation curves.
enum class DurationBehavior {
// Duration proportional to scroll delta; used for programmatic scrolls.
kDeltaBased,
// Constant duration; used for keyboard scrolls.
kConstant,
// Duration inversely proportional to scroll delta within certain bounds.
// Used for mouse wheels, makes fast wheel flings feel "snappy" while
// preserving smoothness of slow wheel movements.
kInverseDelta
};
static const ScrollOffsetAnimationCurve* ToScrollOffsetAnimationCurve(
const AnimationCurve* c);
static ScrollOffsetAnimationCurve* ToScrollOffsetAnimationCurve(
AnimationCurve* c);
// There is inherent delay in input processing; it may take many milliseconds
// from the time of user input to when when we're actually able to handle it
// here. This delay is represented by the |delayed_by| value. The way we have
// decided to factor this in is by reducing the duration of the resulting
// animation by this delayed amount. This also applies to
// LinearSegmentDuration.
static base::TimeDelta EaseInOutSegmentDuration(
const gfx::Vector2dF& delta,
DurationBehavior duration_behavior,
base::TimeDelta delayed_by);
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;
// Sets the initial offset and velocity (in pixels per second).
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_; }
// Updates the current curve to aim at a new target, starting at time t
// relative to the start of the animation. The duration is recomputed based
// on the animation type the curve was constructed with. The timing function
// is modified to preserve velocity at t.
void UpdateTarget(base::TimeDelta t, const gfx::PointF& new_target);
// Shifts the entire curve by a delta without affecting its shape or timing.
// Used for scroll anchoring adjustments that happen during scroll animations
// (see blink::ScrollAnimator::AdjustAnimation).
void ApplyAdjustment(const gfx::Vector2dF& adjustment);
// AnimationCurve implementation
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 class ScrollOffsetAnimationCurveFactory;
enum class AnimationType { kLinear, kEaseInOut };
// |duration_behavior| should be provided if (and only if) |animation_type| is
// kEaseInOut.
ScrollOffsetAnimationCurve(
const gfx::PointF& target_value,
AnimationType animation_type,
std::optional<DurationBehavior> duration_behavior = std::nullopt);
ScrollOffsetAnimationCurve(
const gfx::PointF& target_value,
std::unique_ptr<gfx::TimingFunction> timing_function,
AnimationType animation_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 EaseInOutBoundedSegmentDuration(
const gfx::Vector2dF& new_delta,
base::TimeDelta t,
base::TimeDelta delayed_by);
// Returns the velocity at time t in units of pixels per second.
double CalculateVelocity(base::TimeDelta t);
gfx::PointF initial_value_;
gfx::PointF target_value_;
base::TimeDelta total_animation_duration_;
// Time from animation start to most recent UpdateTarget.
base::TimeDelta last_retarget_;
std::unique_ptr<gfx::TimingFunction> timing_function_;
AnimationType animation_type_;
// Only valid when |animation_type_| is EASE_IN_OUT.
std::optional<DurationBehavior> duration_behavior_;
bool has_set_initial_value_;
static std::optional<double> animation_duration_for_testing_;
raw_ptr<Target, DanglingUntriaged> target_ = nullptr;
};
} // namespace cc
#endif // CC_ANIMATION_SCROLL_OFFSET_ANIMATION_CURVE_H_