#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 "content/common/content_export.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;
constexpr base::TimeDelta kDefaultMouseWheelLatchingTransaction =
base::Milliseconds(500);
const double kWheelLatchingSlopRegion = 10.0;
enum TouchpadScrollPhaseState {
TOUCHPAD_SCROLL_STATE_UNKNOWN = 0,
TOUCHPAD_SCROLL_MAY_BEGIN,
TOUCHPAD_SCROLL_IN_PROGRESS,
};
enum class FirstScrollUpdateAckState {
kNotArrived = 0,
kConsumed,
kNotConsumed,
};
class CONTENT_EXPORT 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,
bool is_fling_capable);
void DispatchPendingWheelEndEvent();
void IgnorePendingWheelEndEvent();
void ResetTouchpadScrollSequence();
void SendWheelEndForTouchpadScrollingIfNeeded(bool should_route_event);
void TouchpadScrollingMayBegin();
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);
TouchpadScrollPhaseState touchpad_scroll_phase_state_for_test() const {
return touchpad_scroll_phase_state_;
}
void set_max_time_between_phase_ended_and_momentum_phase_began(
base::TimeDelta timeout) {
max_time_between_phase_ended_and_momentum_phase_began_ = timeout;
}
const base::TimeDelta
max_time_between_phase_ended_and_momentum_phase_began() {
return max_time_between_phase_ended_and_momentum_phase_began_;
}
void DidEnterBackForwardCache();
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_;
gfx::Vector2dF first_wheel_location_;
blink::WebMouseWheelEvent initial_wheel_event_;
FirstScrollUpdateAckState first_scroll_update_ack_state_ =
FirstScrollUpdateAckState::kNotArrived;
base::TimeDelta max_time_between_phase_ended_and_momentum_phase_began_ =
base::Milliseconds(100);
};
}
#endif