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
|
// Copyright 2016 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_EVENT_QUEUE_H_
#define CONTENT_BROWSER_RENDERER_HOST_INPUT_MOUSE_WHEEL_EVENT_QUEUE_H_
#include <memory>
#include "base/containers/circular_deque.h"
#include "base/functional/callback.h"
#include "base/memory/raw_ptr.h"
#include "base/trace_event/trace_event.h"
#include "content/common/content_export.h"
#include "content/common/input/event_with_latency_info.h"
#include "third_party/blink/public/common/input/web_input_event.h"
#include "third_party/blink/public/mojom/input/input_event_result.mojom-shared.h"
namespace content {
// This class represents a single queued mouse wheel event. Its main use
// is that it is reported via trace events.
class QueuedWebMouseWheelEvent : public MouseWheelEventWithLatencyInfo {
public:
QueuedWebMouseWheelEvent(const MouseWheelEventWithLatencyInfo& original_event)
: MouseWheelEventWithLatencyInfo(original_event) {
TRACE_EVENT_ASYNC_BEGIN0("input", "MouseWheelEventQueue::QueueEvent", this);
}
QueuedWebMouseWheelEvent(const QueuedWebMouseWheelEvent&) = delete;
QueuedWebMouseWheelEvent& operator=(const QueuedWebMouseWheelEvent&) = delete;
~QueuedWebMouseWheelEvent() {
TRACE_EVENT_ASYNC_END0("input", "MouseWheelEventQueue::QueueEvent", this);
}
};
// Interface with which MouseWheelEventQueue can forward mouse wheel events,
// and dispatch mouse wheel event responses.
class CONTENT_EXPORT MouseWheelEventQueueClient {
public:
using MouseWheelEventHandledCallback =
base::OnceCallback<void(const MouseWheelEventWithLatencyInfo& ack_event,
blink::mojom::InputEventResultSource ack_source,
blink::mojom::InputEventResultState ack_result)>;
virtual ~MouseWheelEventQueueClient() {}
virtual void SendMouseWheelEventImmediately(
const MouseWheelEventWithLatencyInfo& event,
MouseWheelEventHandledCallback callback) = 0;
virtual void OnMouseWheelEventAck(
const MouseWheelEventWithLatencyInfo& event,
blink::mojom::InputEventResultSource ack_source,
blink::mojom::InputEventResultState ack_result) = 0;
virtual void ForwardGestureEventWithLatencyInfo(
const blink::WebGestureEvent& event,
const ui::LatencyInfo& latency_info) = 0;
virtual bool IsWheelScrollInProgress() = 0;
virtual bool IsAutoscrollInProgress() = 0;
};
// A queue for throttling and coalescing mouse wheel events. This class tracks
// wheel events sent to the renderer and receives their ACKs. If the ACK
// reports the event went unconsumed by the renderer, this class will generate
// a sequence of gesture scroll events.
//
// Within a sequence, wheel events are initially forwarded using a blocking
// dispatch. This means that further wheel events are queued and scroll event
// generation will wait (i.e. block) until the in-flight wheel event is ACKed.
// Once a wheel event goes unconsumed, and scrolling begins, dispatch of
// subsequent wheel events becomes non-blocking. This means the wheel event
// will be ACKed by the browser immediately after being dispatched. This will
// cause scroll events to follow the wheel immediately and new wheel events
// will be dispatched immediately rather than queueing.
class CONTENT_EXPORT MouseWheelEventQueue {
public:
// The |client| must outlive the MouseWheelEventQueue.
// |IsWheelScrollInProgress| indicates whether mouse wheel events should
// generate Scroll[Begin|Update|End] on unhandled acknowledge events.
MouseWheelEventQueue(MouseWheelEventQueueClient* client);
MouseWheelEventQueue(const MouseWheelEventQueue&) = delete;
MouseWheelEventQueue& operator=(const MouseWheelEventQueue&) = delete;
~MouseWheelEventQueue();
// Adds an event to the queue. The event may be coalesced with previously
// queued events (e.g. consecutive mouse-wheel events can be coalesced into a
// single mouse-wheel event). The event may also be immediately forwarded to
// the renderer (e.g. when there are no other queued mouse-wheel event).
void QueueEvent(const MouseWheelEventWithLatencyInfo& event);
// When GestureScrollBegin is received, and it is a different source
// than mouse wheels terminate the current GestureScroll if there is one.
// When Gesture{ScrollEnd,FlingStart} is received, resume generating
// gestures.
void OnGestureScrollEvent(const GestureEventWithLatencyInfo& gesture_event);
[[nodiscard]] bool has_pending() const {
return !wheel_queue_.empty() || event_sent_for_gesture_ack_;
}
size_t queued_size() const { return wheel_queue_.size(); }
bool event_in_flight() const {
return event_sent_for_gesture_ack_ != nullptr;
}
private:
// Notifies the queue that a mouse wheel event has been processed by the
// renderer.
void ProcessMouseWheelAck(const MouseWheelEventWithLatencyInfo& ack_event,
blink::mojom::InputEventResultSource ack_source,
blink::mojom::InputEventResultState ack_result);
void TryForwardNextEventToRenderer();
void SendScrollEnd(blink::WebGestureEvent update_event, bool synthetic);
void SendScrollBegin(const blink::WebGestureEvent& gesture_update,
bool synthetic);
// True if gesture scroll events can be generated for the wheel event sent for
// ack.
bool CanGenerateGestureScroll(
blink::mojom::InputEventResultState ack_result) const;
raw_ptr<MouseWheelEventQueueClient> client_;
base::circular_deque<std::unique_ptr<QueuedWebMouseWheelEvent>> wheel_queue_;
std::unique_ptr<QueuedWebMouseWheelEvent> event_sent_for_gesture_ack_;
// True if the ack for the first wheel event in a scroll sequence is not
// consumed. This lets us to send the rest of the wheel events in the sequence
// as non-blocking.
bool send_wheel_events_async_;
blink::WebGestureDevice scrolling_device_;
};
} // namespace content
#endif // CONTENT_BROWSER_RENDERER_HOST_INPUT_MOUSE_WHEEL_EVENT_QUEUE_H_
|