| // Copyright 2017 The Chromium Authors | |
| // Use of this source code is governed by a BSD-style license that can be | |
| // found in the LICENSE file. | |
| #ifndef COMPONENTS_INPUT_FLING_CONTROLLER_H_ | |
| #define COMPONENTS_INPUT_FLING_CONTROLLER_H_ | |
| #include <optional> | |
| #include "base/component_export.h" | |
| #include "base/memory/raw_ptr.h" | |
| #include "base/time/time.h" | |
| #include "components/input/touchpad_tap_suppression_controller.h" | |
| #include "components/input/touchscreen_tap_suppression_controller.h" | |
| #include "third_party/blink/public/mojom/input/input_event_result.mojom-shared.h" | |
| #include "ui/events/blink/fling_booster.h" | |
| #include "ui/events/event_constants.h" | |
| namespace blink { | |
| class WebGestureCurve; | |
| } | |
| namespace input { | |
| class FlingController; | |
| inline constexpr float kDefaultPixelsPerInch = 96.0f; | |
| // Interface with which the FlingController can forward generated fling progress | |
| // events. | |
| class COMPONENT_EXPORT(INPUT) FlingControllerEventSenderClient { | |
| public: | |
| virtual ~FlingControllerEventSenderClient() = default; | |
| virtual void SendGeneratedWheelEvent( | |
| const MouseWheelEventWithLatencyInfo& wheel_event) = 0; | |
| virtual void SendGeneratedGestureScrollEvents( | |
| const GestureEventWithLatencyInfo& gesture_event) = 0; | |
| // Returns the size of visible viewport in screen space, in DIPs. | |
| virtual gfx::Size GetRootWidgetViewportSize() = 0; | |
| }; | |
| // Interface with which the fling progress gets scheduled. | |
| class COMPONENT_EXPORT(INPUT) FlingControllerSchedulerClient { | |
| public: | |
| virtual ~FlingControllerSchedulerClient() = default; | |
| virtual void ScheduleFlingProgress( | |
| base::WeakPtr<FlingController> fling_controller) = 0; | |
| virtual void DidStopFlingingOnBrowser( | |
| base::WeakPtr<FlingController> fling_controller) = 0; | |
| virtual bool ProgressFlingOnFlingStart() = 0; | |
| virtual bool ShouldUseMobileFlingCurve() = 0; | |
| virtual gfx::Vector2dF GetPixelsPerInch( | |
| const gfx::PointF& position_in_screen) = 0; | |
| }; | |
| class COMPONENT_EXPORT(INPUT) FlingController { | |
| public: | |
| struct COMPONENT_EXPORT(INPUT) Config { | |
| Config(); | |
| // Controls touchpad-related tap suppression, disabled by default. | |
| TapSuppressionController::Config touchpad_tap_suppression_config; | |
| // Controls touchscreen-related tap suppression, disabled by default. | |
| TapSuppressionController::Config touchscreen_tap_suppression_config; | |
| }; | |
| struct ActiveFlingParameters { | |
| gfx::Vector2dF velocity; | |
| gfx::PointF point; | |
| gfx::PointF global_point; | |
| int modifiers; | |
| blink::WebGestureDevice source_device; | |
| // Timestamp where the fling curve animation begins physics calculations. | |
| base::TimeTicks start_time; | |
| // Timestamp of the original GestureFlingStart event. | |
| base::TimeTicks fling_start_event_time; | |
| // The scroll axis locking (railing) mode of the GestureFlingStart event, | |
| // forwarded to the scroll updates generated throughout the fling. | |
| ui::GestureScrollRailsMode rails_mode = ui::GestureScrollRailsMode::kNone; | |
| ActiveFlingParameters() : modifiers(0) {} | |
| }; | |
| FlingController(FlingControllerEventSenderClient* event_sender_client, | |
| FlingControllerSchedulerClient* scheduler_client, | |
| const Config& config); | |
| FlingController(const FlingController&) = delete; | |
| FlingController& operator=(const FlingController&) = delete; | |
| ~FlingController(); | |
| // Used to progress an active fling on every begin frame. | |
| void ProgressFling(base::TimeTicks current_time, | |
| std::optional<base::TimeTicks> | |
| first_coalesced_frame_begin_time = std::nullopt); | |
| // Used to halt an active fling progress whenever needed. | |
| void StopFling(); | |
| // The fling controller needs to observe all gesture events. It may consume | |
| // or filter some events. It will return true if the event was consumed or | |
| // filtered and should not be propagated further. | |
| bool ObserveAndMaybeConsumeGestureEvent( | |
| const GestureEventWithLatencyInfo& gesture_event); | |
| void ProcessGestureFlingStart( | |
| const GestureEventWithLatencyInfo& gesture_event); | |
| void ProcessGestureFlingCancel( | |
| const GestureEventWithLatencyInfo& gesture_event); | |
| bool fling_in_progress() const { return fling_curve_.get(); } | |
| gfx::Vector2dF CurrentFlingVelocity() const; | |
| // Returns the |TouchpadTapSuppressionController| instance. | |
| TouchpadTapSuppressionController* GetTouchpadTapSuppressionController(); | |
| void set_clock_for_testing(const base::TickClock* clock) { clock_ = clock; } | |
| // The fling controller observes wheel event acks to track whether the latest | |
| // wheel event was consumed, in which case we should not start a fling scroll | |
| // for flings generated by a touchpad source. | |
| void OnWheelEventAck(const MouseWheelEventWithLatencyInfo& event, | |
| blink::mojom::InputEventResultSource ack_source, | |
| blink::mojom::InputEventResultState ack_result); | |
| protected: | |
| ui::FlingBooster fling_booster_; | |
| private: | |
| // Sub-filter for suppressing taps immediately after a GestureFlingCancel. | |
| bool ObserveAndFilterForTapSuppression( | |
| const GestureEventWithLatencyInfo& gesture_event); | |
| void ScheduleFlingProgress(); | |
| // Used to generate synthetic wheel events from touchpad fling and send them. | |
| void GenerateAndSendWheelEvents(base::TimeTicks current_time, | |
| const gfx::Vector2dF& delta, | |
| blink::WebMouseWheelEvent::Phase phase); | |
| // Used to generate synthetic gesture scroll events from touchscreen fling and | |
| // send them. | |
| void GenerateAndSendGestureScrollEvents( | |
| base::TimeTicks current_time, | |
| blink::WebInputEvent::Type type, | |
| const gfx::Vector2dF& delta = gfx::Vector2dF()); | |
| // Calls one of the GenerateAndSendWheelEvents or | |
| // GenerateAndSendGestureScrollEvents functions depending on the source | |
| // device of the current_fling_parameters_. We send GSU and wheel events | |
| // to progress flings with touchscreen and touchpad source respectively. | |
| // The reason for this difference is that during the touchpad fling we still | |
| // send wheel events to JS and generating GSU events directly is not enough. | |
| void GenerateAndSendFlingProgressEvents(base::TimeTicks current_time, | |
| const gfx::Vector2dF& delta); | |
| void GenerateAndSendFlingEndEvents(base::TimeTicks current_time); | |
| void EndCurrentFling(base::TimeTicks current_time); | |
| // Used to update the fling_curve_ state based on the parameters of the fling | |
| // start event. Returns true if the fling curve was updated for a valid | |
| // fling. Returns false if the parameters should not cause a fling and the | |
| // fling_curve_ is not updated. | |
| bool UpdateCurrentFlingState(const blink::WebGestureEvent& fling_start_event); | |
| bool first_fling_update_sent() const { | |
| return !last_progress_time_.is_null(); | |
| } | |
| raw_ptr<FlingControllerEventSenderClient> event_sender_client_; | |
| raw_ptr<FlingControllerSchedulerClient> scheduler_client_; | |
| // An object tracking the state of touchpad on the delivery of mouse events to | |
| // the renderer to filter mouse immediately after a touchpad fling canceling | |
| // tap. | |
| TouchpadTapSuppressionController touchpad_tap_suppression_controller_; | |
| // An object tracking the state of touchscreen on the delivery of gesture tap | |
| // events to the renderer to filter taps immediately after a touchscreen fling | |
| // canceling tap. | |
| TouchscreenTapSuppressionController | |
| touchscreen_tap_suppression_controller_; | |
| // Gesture curve of the current active fling. nullptr while a fling is not | |
| // active. | |
| std::unique_ptr<blink::WebGestureCurve> fling_curve_; | |
| ActiveFlingParameters current_fling_parameters_; | |
| // The last time fling progress events were sent. | |
| base::TimeTicks last_progress_time_; | |
| // The clock used; overridable for tests. | |
| raw_ptr<const base::TickClock> clock_; | |
| // Time of the last seen scroll update that wasn't filtered. Used to know the | |
| // starting time for a possible fling gesture curve. | |
| base::TimeTicks last_seen_scroll_update_; | |
| // Whether the last wheel event was consumed, to determine whether we should | |
| // allow a fling scroll. | |
| bool last_wheel_event_consumed_ = false; | |
| base::WeakPtrFactory<FlingController> weak_ptr_factory_{this}; | |
| }; | |
| } // namespace input | |
| #endif // COMPONENTS_INPUT_FLING_CONTROLLER_H_ |