blob: f145ea85d9edd9cb4428506d1669a4d7287bcab0 [file] [log] [blame]
Avi Drissman4e1b7bc32022-09-15 14:03:501// Copyright 2013 The Chromium Authors
ssidf50c67c12015-02-25 17:43:042// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
Aman Verma8378f3f2023-11-29 18:08:465#include "content/common/input/synthetic_smooth_move_gesture.h"
ssidf50c67c12015-02-25 17:43:046
avib533f5d2015-12-25 03:11:157#include <stdint.h>
8
Hans Wennborg0917de892020-04-28 20:21:159#include "base/check_op.h"
10#include "base/notreached.h"
Peter Kasting4a06d95a2023-10-30 18:20:4311#include "base/time/time.h"
Dave Tapuska6db16e32020-06-09 13:58:0612#include "third_party/blink/public/common/input/synthetic_web_input_event_builders.h"
ssidf50c67c12015-02-25 17:43:0413#include "ui/gfx/geometry/point_f.h"
14
15namespace content {
16namespace {
17
ssidf50c67c12015-02-25 17:43:0418gfx::Vector2dF ProjectScalarOntoVector(float scalar,
19 const gfx::Vector2dF& vector) {
20 return gfx::ScaleVector2d(vector, scalar / vector.Length());
21}
22
Navid Zolghadrca1490a2020-02-03 19:13:0023// returns the animation progress along an arctan curve to provide simple
24// ease-in ease-out behavior.
25float GetCurvedRatio(const base::TimeTicks& current,
26 const base::TimeTicks& start,
27 const base::TimeTicks& end,
28 int speed_in_pixels_s) {
29 // Increasing this would make the start and the end of the curv smoother.
30 // Hence the higher value for the higher speed.
31 const float kArctanRange = sqrt(static_cast<double>(speed_in_pixels_s)) / 100;
32
33 const float kMaxArctan = std::atan(kArctanRange / 2);
34 const float kMinArctan = std::atan(-kArctanRange / 2);
35
Peter Kasting852091b2020-08-14 00:10:3236 float linear_ratio = (current - start) / (end - start);
Navid Zolghadrca1490a2020-02-03 19:13:0037 return (std::atan(kArctanRange * linear_ratio - kArctanRange / 2) -
38 kMinArctan) /
39 (kMaxArctan - kMinArctan);
40}
41
ssidf50c67c12015-02-25 17:43:0442} // namespace
43
Lan Wei4d2507c2020-07-20 22:36:0444SyntheticSmoothMoveGestureParams::SyntheticSmoothMoveGestureParams() = default;
ssidf50c67c12015-02-25 17:43:0445
vmpstr33895d992016-02-24 20:55:2146SyntheticSmoothMoveGestureParams::SyntheticSmoothMoveGestureParams(
47 const SyntheticSmoothMoveGestureParams& other) = default;
48
Lan Wei4d2507c2020-07-20 22:36:0449SyntheticSmoothMoveGestureParams::~SyntheticSmoothMoveGestureParams() = default;
ssidf50c67c12015-02-25 17:43:0450
David Bokan6d776aa2023-07-14 21:13:3851SyntheticGestureParams::GestureType
52SyntheticSmoothMoveGestureParams::GetGestureType() const {
53 return SMOOTH_MOVE_GESTURE;
54}
55
ssidf50c67c12015-02-25 17:43:0456SyntheticSmoothMoveGesture::SyntheticSmoothMoveGesture(
David Bokan6d776aa2023-07-14 21:13:3857 const SyntheticSmoothMoveGestureParams& gesture_params)
58 : SyntheticGestureBase(gesture_params),
59 current_move_segment_start_position_(params().start_point) {
60 CHECK_EQ(SyntheticGestureParams::SMOOTH_MOVE_GESTURE,
61 gesture_params.GetGestureType());
62}
ssidf50c67c12015-02-25 17:43:0463
64SyntheticSmoothMoveGesture::~SyntheticSmoothMoveGesture() {}
65
66SyntheticGesture::Result SyntheticSmoothMoveGesture::ForwardInputEvents(
67 const base::TimeTicks& timestamp,
68 SyntheticGestureTarget* target) {
David Bokan865adbf2023-04-13 20:12:1969 CHECK(dispatching_controller_);
70
71 // Keep this on the stack so we can check if the forwarded event caused the
72 // deletion of the controller (which owns `this`).
73 base::WeakPtr<SyntheticGestureController> weak_controller =
74 dispatching_controller_;
75
ssidf50c67c12015-02-25 17:43:0476 if (state_ == SETUP) {
77 state_ = STARTED;
78 current_move_segment_ = -1;
79 current_move_segment_stop_time_ = timestamp;
80 }
81
David Bokan6d776aa2023-07-14 21:13:3882 switch (params().input_type) {
ssidf50c67c12015-02-25 17:43:0483 case SyntheticSmoothMoveGestureParams::TOUCH_INPUT:
lanwei1060f1f2016-11-28 23:00:3184 if (!synthetic_pointer_driver_)
Gyuyoung Kimb37010642021-02-22 06:40:5885 synthetic_pointer_driver_ = SyntheticPointerDriver::Create(
Danil Somsikov39baf6a22021-11-09 21:01:2386 content::mojom::GestureSourceType::kTouchInput,
David Bokan6d776aa2023-07-14 21:13:3887 params().from_devtools_debugger);
ssidf50c67c12015-02-25 17:43:0488 ForwardTouchInputEvents(timestamp, target);
89 break;
90 case SyntheticSmoothMoveGestureParams::MOUSE_DRAG_INPUT:
lanwei1060f1f2016-11-28 23:00:3191 if (!synthetic_pointer_driver_)
Gyuyoung Kimb37010642021-02-22 06:40:5892 synthetic_pointer_driver_ = SyntheticPointerDriver::Create(
Danil Somsikov39baf6a22021-11-09 21:01:2393 content::mojom::GestureSourceType::kMouseInput,
David Bokan6d776aa2023-07-14 21:13:3894 params().from_devtools_debugger);
ssidf50c67c12015-02-25 17:43:0495 ForwardMouseClickInputEvents(timestamp, target);
96 break;
97 case SyntheticSmoothMoveGestureParams::MOUSE_WHEEL_INPUT:
98 ForwardMouseWheelInputEvents(timestamp, target);
David Bokan9af981b2023-02-16 15:29:0099 // A mousewheel should not be able to close the WebContents.
David Bokan865adbf2023-04-13 20:12:19100 CHECK(weak_controller);
ssidf50c67c12015-02-25 17:43:04101 break;
102 default:
103 return SyntheticGesture::GESTURE_SOURCE_TYPE_NOT_IMPLEMENTED;
104 }
David Bokan865adbf2023-04-13 20:12:19105 if (!weak_controller) {
David Bokan9af981b2023-02-16 15:29:00106 // A pointer gesture can cause the controller (and therefore `this`) to be
107 // synchronously deleted (e.g. clicking tab-close). Return immediately in
108 // this case.
109 return SyntheticGesture::GESTURE_ABORT;
110 }
111
ssidf50c67c12015-02-25 17:43:04112 return (state_ == DONE) ? SyntheticGesture::GESTURE_FINISHED
113 : SyntheticGesture::GESTURE_RUNNING;
114}
115
116// TODO(ssid): Clean up the switch statements by adding functions instead of
117// large code, in the Forward*Events functions. Move the actions for all input
118// types to different class (SyntheticInputDevice) which generates input events
119// for all input types. The gesture class can use instance of device actions.
120// Refer: crbug.com/461825
121
David Bokan9af981b2023-02-16 15:29:00122// CAUTION: forwarding a pointer press/release can cause `this` to be deleted.
ssidf50c67c12015-02-25 17:43:04123void SyntheticSmoothMoveGesture::ForwardTouchInputEvents(
124 const base::TimeTicks& timestamp,
125 SyntheticGestureTarget* target) {
David Bokan865adbf2023-04-13 20:12:19126 // Keep this on the stack so we can check if the forwarded event caused the
127 // deletion of the controller (which owns `this`).
128 base::WeakPtr<SyntheticGestureController> weak_controller =
129 dispatching_controller_;
ssidf50c67c12015-02-25 17:43:04130 switch (state_) {
131 case STARTED:
132 if (MoveIsNoOp()) {
133 state_ = DONE;
134 break;
135 }
David Bokan6d776aa2023-07-14 21:13:38136 if (params().add_slop) {
ssidf50c67c12015-02-25 17:43:04137 AddTouchSlopToFirstDistance(target);
David Bokan6d776aa2023-07-14 21:13:38138 }
ssidf50c67c12015-02-25 17:43:04139 ComputeNextMoveSegment();
Dave Tapuska675a5192018-02-16 18:26:42140 PressPoint(target, timestamp);
David Bokan865adbf2023-04-13 20:12:19141 if (!weak_controller) {
David Bokan9af981b2023-02-16 15:29:00142 return;
143 }
ssidf50c67c12015-02-25 17:43:04144 state_ = MOVING;
145 break;
146 case MOVING: {
Dave Tapuska675a5192018-02-16 18:26:42147 base::TimeTicks event_timestamp = ClampTimestamp(timestamp);
ssidf50c67c12015-02-25 17:43:04148 gfx::Vector2dF delta = GetPositionDeltaAtTime(event_timestamp);
lanweid4461a2c2015-11-20 13:50:20149 MovePoint(target, delta, event_timestamp);
David Bokan865adbf2023-04-13 20:12:19150 // A move should never be able to cause deletion of the controller.
151 CHECK(weak_controller);
ssidf50c67c12015-02-25 17:43:04152
153 if (FinishedCurrentMoveSegment(event_timestamp)) {
154 if (!IsLastMoveSegment()) {
155 current_move_segment_start_position_ +=
David Bokan6d776aa2023-07-14 21:13:38156 params().distances[current_move_segment_];
ssidf50c67c12015-02-25 17:43:04157 ComputeNextMoveSegment();
David Bokan6d776aa2023-07-14 21:13:38158 } else if (params().prevent_fling) {
ssidf50c67c12015-02-25 17:43:04159 state_ = STOPPING;
160 } else {
lanweid4461a2c2015-11-20 13:50:20161 ReleasePoint(target, event_timestamp);
David Bokan865adbf2023-04-13 20:12:19162 if (!weak_controller) {
David Bokan9af981b2023-02-16 15:29:00163 return;
164 }
ssidf50c67c12015-02-25 17:43:04165 state_ = DONE;
166 }
167 }
168 } break;
169 case STOPPING:
170 if (timestamp - current_move_segment_stop_time_ >=
171 target->PointerAssumedStoppedTime()) {
Dave Tapuska675a5192018-02-16 18:26:42172 base::TimeTicks event_timestamp = current_move_segment_stop_time_ +
173 target->PointerAssumedStoppedTime();
lanweid4461a2c2015-11-20 13:50:20174 ReleasePoint(target, event_timestamp);
David Bokan865adbf2023-04-13 20:12:19175 if (!weak_controller) {
David Bokan9af981b2023-02-16 15:29:00176 return;
177 }
ssidf50c67c12015-02-25 17:43:04178 state_ = DONE;
179 }
180 break;
181 case SETUP:
Peter Boströmfc7ddc182024-10-31 19:37:21182 NOTREACHED()
ssidf50c67c12015-02-25 17:43:04183 << "State SETUP invalid for synthetic scroll using touch input.";
184 case DONE:
Peter Boströmfc7ddc182024-10-31 19:37:21185 NOTREACHED()
ssidf50c67c12015-02-25 17:43:04186 << "State DONE invalid for synthetic scroll using touch input.";
187 }
188}
189
190void SyntheticSmoothMoveGesture::ForwardMouseWheelInputEvents(
191 const base::TimeTicks& timestamp,
192 SyntheticGestureTarget* target) {
193 switch (state_) {
194 case STARTED:
195 if (MoveIsNoOp()) {
196 state_ = DONE;
197 break;
198 }
199 ComputeNextMoveSegment();
200 state_ = MOVING;
sahel8f2fa602017-09-08 21:32:35201 break;
ssidf50c67c12015-02-25 17:43:04202 case MOVING: {
ssidf50c67c12015-02-25 17:43:04203 base::TimeTicks event_timestamp = ClampTimestamp(timestamp);
sahel8f2fa602017-09-08 21:32:35204 gfx::Vector2dF delta = GetPositionDeltaAtTime(event_timestamp) -
205 current_move_segment_total_delta_;
David Bokancbeb064c2017-11-13 17:00:01206 if (delta.x() || delta.y()) {
207 blink::WebMouseWheelEvent::Phase phase =
208 needs_scroll_begin_ ? blink::WebMouseWheelEvent::kPhaseBegan
209 : blink::WebMouseWheelEvent::kPhaseChanged;
Lan Weied6202b2020-04-28 03:09:19210 ForwardMouseWheelEvent(target, delta, phase, event_timestamp,
David Bokan6d776aa2023-07-14 21:13:38211 params().modifiers);
David Bokancbeb064c2017-11-13 17:00:01212 current_move_segment_total_delta_ += delta;
213 needs_scroll_begin_ = false;
214 }
ssidf50c67c12015-02-25 17:43:04215
216 if (FinishedCurrentMoveSegment(event_timestamp)) {
217 if (!IsLastMoveSegment()) {
sahel8f2fa602017-09-08 21:32:35218 current_move_segment_total_delta_ = gfx::Vector2dF();
ssidf50c67c12015-02-25 17:43:04219 ComputeNextMoveSegment();
ssidf50c67c12015-02-25 17:43:04220 } else {
221 state_ = DONE;
Lan Wei8fdb3042018-08-18 01:03:40222
223 // Start flinging on the swipe action.
David Bokan6d776aa2023-07-14 21:13:38224 if (!params().prevent_fling && (params().fling_velocity_x != 0 ||
225 params().fling_velocity_y != 0)) {
Lan Wei8fdb3042018-08-18 01:03:40226 ForwardFlingGestureEvent(
Dave Tapuskab5a72eb2020-04-21 22:12:56227 target, blink::WebGestureEvent::Type::kGestureFlingStart);
Lan Wei8fdb3042018-08-18 01:03:40228 } else {
229 // Forward a wheel event with phase ended and zero deltas.
230 ForwardMouseWheelEvent(target, gfx::Vector2d(),
231 blink::WebMouseWheelEvent::kPhaseEnded,
David Bokan6d776aa2023-07-14 21:13:38232 event_timestamp, params().modifiers);
Lan Wei8fdb3042018-08-18 01:03:40233 }
sahel955c3292017-08-17 14:56:44234 needs_scroll_begin_ = true;
ssidf50c67c12015-02-25 17:43:04235 }
236 }
237 } break;
238 case SETUP:
Peter Boströmfc7ddc182024-10-31 19:37:21239 NOTREACHED() << "State SETUP invalid for synthetic scroll using mouse "
240 "wheel input.";
ssidf50c67c12015-02-25 17:43:04241 case STOPPING:
Peter Boströmfc7ddc182024-10-31 19:37:21242 NOTREACHED() << "State STOPPING invalid for synthetic scroll using mouse "
243 "wheel input.";
ssidf50c67c12015-02-25 17:43:04244 case DONE:
Peter Boströmfc7ddc182024-10-31 19:37:21245 NOTREACHED()
ssidf50c67c12015-02-25 17:43:04246 << "State DONE invalid for synthetic scroll using mouse wheel input.";
247 }
248}
249
David Bokan9af981b2023-02-16 15:29:00250// CAUTION: forwarding a pointer press/release can cause `this` to be deleted.
ssidf50c67c12015-02-25 17:43:04251void SyntheticSmoothMoveGesture::ForwardMouseClickInputEvents(
252 const base::TimeTicks& timestamp,
253 SyntheticGestureTarget* target) {
David Bokan865adbf2023-04-13 20:12:19254 // Keep this on the stack so we can check if the forwarded event caused the
255 // deletion of the controller (which owns `this`).
256 base::WeakPtr<SyntheticGestureController> weak_controller =
257 dispatching_controller_;
ssidf50c67c12015-02-25 17:43:04258 switch (state_) {
259 case STARTED:
260 if (MoveIsNoOp()) {
261 state_ = DONE;
262 break;
263 }
264 ComputeNextMoveSegment();
Dave Tapuska675a5192018-02-16 18:26:42265 PressPoint(target, timestamp);
David Bokan865adbf2023-04-13 20:12:19266 if (!weak_controller) {
David Bokan9af981b2023-02-16 15:29:00267 return;
268 }
ssidf50c67c12015-02-25 17:43:04269 state_ = MOVING;
270 break;
271 case MOVING: {
272 base::TimeTicks event_timestamp = ClampTimestamp(timestamp);
273 gfx::Vector2dF delta = GetPositionDeltaAtTime(event_timestamp);
lanweid4461a2c2015-11-20 13:50:20274 MovePoint(target, delta, event_timestamp);
ssidf50c67c12015-02-25 17:43:04275
276 if (FinishedCurrentMoveSegment(event_timestamp)) {
277 if (!IsLastMoveSegment()) {
278 current_move_segment_start_position_ +=
David Bokan6d776aa2023-07-14 21:13:38279 params().distances[current_move_segment_];
ssidf50c67c12015-02-25 17:43:04280 ComputeNextMoveSegment();
281 } else {
lanweid4461a2c2015-11-20 13:50:20282 ReleasePoint(target, event_timestamp);
David Bokan865adbf2023-04-13 20:12:19283 if (!weak_controller) {
David Bokan9af981b2023-02-16 15:29:00284 return;
285 }
ssidf50c67c12015-02-25 17:43:04286 state_ = DONE;
287 }
288 }
289 } break;
290 case STOPPING:
Peter Boströmfc7ddc182024-10-31 19:37:21291 NOTREACHED()
ssidf50c67c12015-02-25 17:43:04292 << "State STOPPING invalid for synthetic drag using mouse input.";
293 case SETUP:
Peter Boströmfc7ddc182024-10-31 19:37:21294 NOTREACHED()
ssidf50c67c12015-02-25 17:43:04295 << "State SETUP invalid for synthetic drag using mouse input.";
296 case DONE:
Peter Boströmfc7ddc182024-10-31 19:37:21297 NOTREACHED()
ssidf50c67c12015-02-25 17:43:04298 << "State DONE invalid for synthetic drag using mouse input.";
299 }
300}
301
ssidf50c67c12015-02-25 17:43:04302void SyntheticSmoothMoveGesture::ForwardMouseWheelEvent(
303 SyntheticGestureTarget* target,
304 const gfx::Vector2dF& delta,
sahel60b41cdf2017-06-26 21:34:17305 const blink::WebMouseWheelEvent::Phase phase,
Lan Weied6202b2020-04-28 03:09:19306 const base::TimeTicks& timestamp,
Lan Wei4d2507c2020-07-20 22:36:04307 int modifiers) const {
David Bokan6d776aa2023-07-14 21:13:38308 if (params().from_devtools_debugger) {
Danil Somsikov39baf6a22021-11-09 21:01:23309 modifiers |= blink::WebInputEvent::kFromDebugger;
310 }
ssidf50c67c12015-02-25 17:43:04311 blink::WebMouseWheelEvent mouse_wheel_event =
Dave Tapuska6db16e32020-06-09 13:58:06312 blink::SyntheticWebMouseWheelEventBuilder::Build(
David Bokan6d776aa2023-07-14 21:13:38313 0, 0, delta.x(), delta.y(), modifiers, params().granularity);
ssidf50c67c12015-02-25 17:43:04314
Blink Reformat1c4d759e2017-04-09 16:34:54315 mouse_wheel_event.SetPositionInWidget(
mustaqc51f3aab2017-04-05 15:43:11316 current_move_segment_start_position_.x(),
317 current_move_segment_start_position_.y());
sahel60b41cdf2017-06-26 21:34:17318 mouse_wheel_event.phase = phase;
ssidf50c67c12015-02-25 17:43:04319
Daniel Cheng224569ee2018-04-25 05:45:06320 mouse_wheel_event.SetTimeStamp(timestamp);
ssidf50c67c12015-02-25 17:43:04321
322 target->DispatchInputEventToPlatform(mouse_wheel_event);
323}
324
Lan Wei8fdb3042018-08-18 01:03:40325void SyntheticSmoothMoveGesture::ForwardFlingGestureEvent(
326 SyntheticGestureTarget* target,
327 const blink::WebInputEvent::Type type) const {
328 blink::WebGestureEvent fling_gesture_event =
Dave Tapuska6db16e32020-06-09 13:58:06329 blink::SyntheticWebGestureEventBuilder::Build(
Daniel Cheng7f9ec902019-04-18 05:07:00330 type, blink::WebGestureDevice::kTouchpad);
David Bokan6d776aa2023-07-14 21:13:38331 fling_gesture_event.data.fling_start.velocity_x = params().fling_velocity_x;
332 fling_gesture_event.data.fling_start.velocity_y = params().fling_velocity_y;
Lan Wei8fdb3042018-08-18 01:03:40333 fling_gesture_event.SetPositionInWidget(current_move_segment_start_position_);
334 target->DispatchInputEventToPlatform(fling_gesture_event);
335}
336
lanweid4461a2c2015-11-20 13:50:20337void SyntheticSmoothMoveGesture::PressPoint(SyntheticGestureTarget* target,
338 const base::TimeTicks& timestamp) {
ssidf50c67c12015-02-25 17:43:04339 DCHECK_EQ(current_move_segment_, 0);
lanwei1060f1f2016-11-28 23:00:31340 synthetic_pointer_driver_->Press(current_move_segment_start_position_.x(),
341 current_move_segment_start_position_.y());
342 synthetic_pointer_driver_->DispatchEvent(target, timestamp);
ssidf50c67c12015-02-25 17:43:04343}
344
lanweid4461a2c2015-11-20 13:50:20345void SyntheticSmoothMoveGesture::MovePoint(SyntheticGestureTarget* target,
346 const gfx::Vector2dF& delta,
347 const base::TimeTicks& timestamp) {
ssidf50c67c12015-02-25 17:43:04348 DCHECK_GE(current_move_segment_, 0);
David Bokan6d776aa2023-07-14 21:13:38349 DCHECK_LT(current_move_segment_, static_cast<int>(params().distances.size()));
lanweid4461a2c2015-11-20 13:50:20350 gfx::PointF new_position = current_move_segment_start_position_ + delta;
lanwei1060f1f2016-11-28 23:00:31351 synthetic_pointer_driver_->Move(new_position.x(), new_position.y());
352 synthetic_pointer_driver_->DispatchEvent(target, timestamp);
ssidf50c67c12015-02-25 17:43:04353}
354
lanweid4461a2c2015-11-20 13:50:20355void SyntheticSmoothMoveGesture::ReleasePoint(
ssidf50c67c12015-02-25 17:43:04356 SyntheticGestureTarget* target,
357 const base::TimeTicks& timestamp) {
358 DCHECK_EQ(current_move_segment_,
David Bokan6d776aa2023-07-14 21:13:38359 static_cast<int>(params().distances.size()) - 1);
lanweid4461a2c2015-11-20 13:50:20360 gfx::PointF position;
David Bokan6d776aa2023-07-14 21:13:38361 if (params().input_type ==
lanweid4461a2c2015-11-20 13:50:20362 SyntheticSmoothMoveGestureParams::MOUSE_DRAG_INPUT) {
363 position = current_move_segment_start_position_ +
364 GetPositionDeltaAtTime(timestamp);
365 }
lanwei1060f1f2016-11-28 23:00:31366 synthetic_pointer_driver_->Release();
367 synthetic_pointer_driver_->DispatchEvent(target, timestamp);
ssidf50c67c12015-02-25 17:43:04368}
369
370void SyntheticSmoothMoveGesture::AddTouchSlopToFirstDistance(
371 SyntheticGestureTarget* target) {
David Bokan6d776aa2023-07-14 21:13:38372 DCHECK_GE(params().distances.size(), 1ul);
373 gfx::Vector2dF& first_move_distance = params().distances[0];
ssidf50c67c12015-02-25 17:43:04374 DCHECK_GT(first_move_distance.Length(), 0);
David Bokan11bf6abb2018-10-24 21:27:35375 first_move_distance += ProjectScalarOntoVector(target->GetTouchSlopInDips(),
376 first_move_distance);
ssidf50c67c12015-02-25 17:43:04377}
378
379gfx::Vector2dF SyntheticSmoothMoveGesture::GetPositionDeltaAtTime(
380 const base::TimeTicks& timestamp) const {
381 // Make sure the final delta is correct. Using the computation below can lead
382 // to issues with floating point precision.
David Bokancbeb064c2017-11-13 17:00:01383 // TODO(bokan): This comment makes it sound like we have pixel perfect
384 // precision. In fact, gestures can accumulate a significant amount of
385 // error (e.g. due to snapping to physical pixels on each event).
ssidf50c67c12015-02-25 17:43:04386 if (FinishedCurrentMoveSegment(timestamp))
David Bokan6d776aa2023-07-14 21:13:38387 return params().distances[current_move_segment_];
ssidf50c67c12015-02-25 17:43:04388
Navid Zolghadrca1490a2020-02-03 19:13:00389 return gfx::ScaleVector2d(
David Bokan6d776aa2023-07-14 21:13:38390 params().distances[current_move_segment_],
Navid Zolghadrca1490a2020-02-03 19:13:00391 GetCurvedRatio(timestamp, current_move_segment_start_time_,
392 current_move_segment_stop_time_,
David Bokan6d776aa2023-07-14 21:13:38393 params().speed_in_pixels_s));
ssidf50c67c12015-02-25 17:43:04394}
395
396void SyntheticSmoothMoveGesture::ComputeNextMoveSegment() {
397 current_move_segment_++;
David Bokan6d776aa2023-07-14 21:13:38398 DCHECK_LT(current_move_segment_, static_cast<int>(params().distances.size()));
Sahir Vellanie0d798d2020-04-27 19:43:27399 // Percentage based scrolls do not require velocity and are delivered in a
400 // single segment. No need to compute another segment
Yaroslav Shalivskyyf90b4aa2024-11-23 00:15:54401 const auto duration =
402 base::Seconds(double{params().distances[current_move_segment_].Length()} /
403 params().speed_in_pixels_s);
404 current_move_segment_start_time_ = current_move_segment_stop_time_;
405 current_move_segment_stop_time_ = current_move_segment_start_time_ + duration;
ssidf50c67c12015-02-25 17:43:04406}
407
408base::TimeTicks SyntheticSmoothMoveGesture::ClampTimestamp(
409 const base::TimeTicks& timestamp) const {
410 return std::min(timestamp, current_move_segment_stop_time_);
411}
412
413bool SyntheticSmoothMoveGesture::FinishedCurrentMoveSegment(
414 const base::TimeTicks& timestamp) const {
415 return timestamp >= current_move_segment_stop_time_;
416}
417
418bool SyntheticSmoothMoveGesture::IsLastMoveSegment() const {
David Bokan6d776aa2023-07-14 21:13:38419 DCHECK_LT(current_move_segment_, static_cast<int>(params().distances.size()));
ssidf50c67c12015-02-25 17:43:04420 return current_move_segment_ ==
David Bokan6d776aa2023-07-14 21:13:38421 static_cast<int>(params().distances.size()) - 1;
ssidf50c67c12015-02-25 17:43:04422}
423
424bool SyntheticSmoothMoveGesture::MoveIsNoOp() const {
David Bokan6d776aa2023-07-14 21:13:38425 return params().distances.size() == 0 || params().distances[0].IsZero();
ssidf50c67c12015-02-25 17:43:04426}
427
428} // namespace content