|  | // 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 CONTENT_BROWSER_RENDERER_HOST_INPUT_MOUSE_WHEEL_PHASE_HANDLER_H_ | 
|  | #define CONTENT_BROWSER_RENDERER_HOST_INPUT_MOUSE_WHEEL_PHASE_HANDLER_H_ | 
|  |  | 
|  | #include "base/memory/raw_ptr.h" | 
|  | #include "base/time/time.h" | 
|  | #include "base/timer/timer.h" | 
|  | #include "content/browser/renderer_host/render_widget_host_delegate.h" | 
|  | #include "third_party/blink/public/common/input/web_mouse_wheel_event.h" | 
|  | #include "third_party/blink/public/mojom/input/input_event_result.mojom-shared.h" | 
|  |  | 
|  | namespace content { | 
|  | class RenderWidgetHostViewBase; | 
|  |  | 
|  | // The duration after which a synthetic wheel with zero deltas and | 
|  | // phase = |kPhaseEnded| will be sent after the last wheel event. | 
|  | constexpr base::TimeDelta kDefaultMouseWheelLatchingTransaction = | 
|  | base::Milliseconds(500); | 
|  |  | 
|  | // Maximum allowed difference between coordinates of two mouse wheel events in | 
|  | // the same scroll sequence. | 
|  | const double kWheelLatchingSlopRegion = 10.0; | 
|  |  | 
|  | // On ChromeOS wheel events don't have phase information; However, whenever the | 
|  | // user puts down their fingers on touchpad a GFC is received and at the end of | 
|  | // touchpad scrolling when the user lifts their fingers a GFS is received. This | 
|  | // enum tracks the current state of the touchpad scrolling by listening to GFC | 
|  | // and GFS events. | 
|  | enum TouchpadScrollPhaseState { | 
|  | // Scrolling with normal mouse wheels doesn't give any information about the | 
|  | // state of scrolling. | 
|  | TOUCHPAD_SCROLL_STATE_UNKNOWN = 0, | 
|  | // Shows that the user has put their fingers down and a scroll may start. | 
|  | TOUCHPAD_SCROLL_MAY_BEGIN, | 
|  | // Scrolling has started and the user hasn't lift their fingers, yet. | 
|  | TOUCHPAD_SCROLL_IN_PROGRESS, | 
|  | }; | 
|  |  | 
|  | enum class FirstScrollUpdateAckState { | 
|  | // Shows that the ACK for the first GSU event is not arrived yet. | 
|  | kNotArrived = 0, | 
|  | // Shows that the first GSU event is consumed. | 
|  | kConsumed, | 
|  | // Shows that the first GSU event is not consumed. | 
|  | kNotConsumed, | 
|  | }; | 
|  |  | 
|  | // The MouseWheelPhaseHandler is responsible for adding the proper phase to | 
|  | // wheel events. Phase information is necessary for wheel scrolling since it | 
|  | // shows the start and end of a scrolling sequence. | 
|  | class MouseWheelPhaseHandler { | 
|  | public: | 
|  | MouseWheelPhaseHandler(RenderWidgetHostViewBase* const host_view); | 
|  |  | 
|  | MouseWheelPhaseHandler(const MouseWheelPhaseHandler&) = delete; | 
|  | MouseWheelPhaseHandler& operator=(const MouseWheelPhaseHandler&) = delete; | 
|  |  | 
|  | ~MouseWheelPhaseHandler() {} | 
|  |  | 
|  | void AddPhaseIfNeededAndScheduleEndEvent( | 
|  | blink::WebMouseWheelEvent& mouse_wheel_event, | 
|  | bool should_route_event); | 
|  | void DispatchPendingWheelEndEvent(); | 
|  | void IgnorePendingWheelEndEvent(); | 
|  | void ResetTouchpadScrollSequence(); | 
|  | void SendWheelEndForTouchpadScrollingIfNeeded(bool should_route_event); | 
|  | void TouchpadScrollingMayBegin(); | 
|  |  | 
|  | // Used to set the timer timeout for testing. | 
|  | void set_mouse_wheel_end_dispatch_timeout(base::TimeDelta timeout) { | 
|  | mouse_wheel_end_dispatch_timeout_ = timeout; | 
|  | } | 
|  |  | 
|  | bool HasPendingWheelEndEvent() const { | 
|  | return mouse_wheel_end_dispatch_timer_.IsRunning(); | 
|  | } | 
|  | void GestureEventAck(const blink::WebGestureEvent& event, | 
|  | blink::mojom::InputEventResultState ack_result); | 
|  |  | 
|  | // Used to verify the correctness of touchpad_scroll_phase_state_'s value in | 
|  | // testing. | 
|  | TouchpadScrollPhaseState touchpad_scroll_phase_state_for_test() const { | 
|  | return touchpad_scroll_phase_state_; | 
|  | } | 
|  |  | 
|  | // Used in testing for setting the max time to wait for momentum phase began | 
|  | // after a scroll phase end. | 
|  | void set_max_time_between_phase_ended_and_momentum_phase_began( | 
|  | base::TimeDelta timeout) { | 
|  | max_time_between_phase_ended_and_momentum_phase_began_ = timeout; | 
|  | } | 
|  |  | 
|  | // Used get the max time to wait for a momentum scroll to begin. | 
|  | const base::TimeDelta | 
|  | max_time_between_phase_ended_and_momentum_phase_began() { | 
|  | return max_time_between_phase_ended_and_momentum_phase_began_; | 
|  | } | 
|  |  | 
|  | private: | 
|  | void SendSyntheticWheelEventWithPhaseEnded(bool should_route_event); | 
|  | void ScheduleMouseWheelEndDispatching(bool should_route_event, | 
|  | const base::TimeDelta timeout); | 
|  | bool IsWithinSlopRegion(const blink::WebMouseWheelEvent& wheel_event) const; | 
|  | bool HasDifferentModifiers( | 
|  | const blink::WebMouseWheelEvent& wheel_event) const; | 
|  | bool ShouldBreakLatchingDueToDirectionChange( | 
|  | const blink::WebMouseWheelEvent& wheel_event) const; | 
|  |  | 
|  | const raw_ptr<RenderWidgetHostViewBase> host_view_; | 
|  | base::OneShotTimer mouse_wheel_end_dispatch_timer_; | 
|  | base::TimeDelta mouse_wheel_end_dispatch_timeout_; | 
|  | blink::WebMouseWheelEvent last_mouse_wheel_event_; | 
|  | TouchpadScrollPhaseState touchpad_scroll_phase_state_; | 
|  | // This is used to break the timer based latching when the difference between | 
|  | // the locations of the first wheel event and the current wheel event is | 
|  | // larger than some threshold. The variable value is only valid while the | 
|  | // dispatch timer is running. | 
|  | gfx::Vector2dF first_wheel_location_; | 
|  |  | 
|  | // This is used to break the timer based latching when the new wheel event has | 
|  | // different modifiers or when it is in a different direction from the | 
|  | // previous wheel events and the scrolling has been ignored. | 
|  | blink::WebMouseWheelEvent initial_wheel_event_; | 
|  |  | 
|  | FirstScrollUpdateAckState first_scroll_update_ack_state_ = | 
|  | FirstScrollUpdateAckState::kNotArrived; | 
|  |  | 
|  | // Maximum time that the phase handler waits for arrival of a wheel event with | 
|  | // momentum_phase = kPhaseBegan before sending its previous wheel event with | 
|  | // phase = kPhaseEnded. | 
|  | base::TimeDelta max_time_between_phase_ended_and_momentum_phase_began_ = | 
|  | base::Milliseconds(100); | 
|  | }; | 
|  |  | 
|  | }  // namespace content | 
|  |  | 
|  | #endif  // CONTENT_BROWSER_RENDERER_HOST_INPUT_MOUSE_WHEEL_PHASE_HANDLER_H_ |