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 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253
|
// Copyright 2014 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_GESTURE_EVENT_QUEUE_H_
#define COMPONENTS_INPUT_GESTURE_EVENT_QUEUE_H_
#include <stddef.h>
#include "base/component_export.h"
#include "base/containers/circular_deque.h"
#include "base/memory/raw_ptr.h"
#include "base/time/time.h"
#include "base/timer/timer.h"
#include "components/input/dispatch_to_renderer_callback.h"
#include "components/input/event_with_latency_info.h"
#include "components/input/fling_controller.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 {
class MockRenderWidgetHost;
} // namespace content
namespace input {
class GestureEventQueueTest;
class GestureEventWithLatencyInfoAndCallback
: public GestureEventWithLatencyInfo {
public:
GestureEventWithLatencyInfoAndCallback(
const GestureEventWithLatencyInfo&,
DispatchToRendererCallback dispatch_callback);
GestureEventWithLatencyInfoAndCallback(
GestureEventWithLatencyInfoAndCallback&& event);
~GestureEventWithLatencyInfoAndCallback();
DispatchToRendererCallback dispatch_callback;
};
// Interface with which the GestureEventQueue can forward gesture events, and
// dispatch gesture event responses.
class COMPONENT_EXPORT(INPUT) GestureEventQueueClient {
public:
virtual ~GestureEventQueueClient() = default;
virtual void SendGestureEventImmediately(
const GestureEventWithLatencyInfo& event,
DispatchToRendererCallback& dispatch_callback) = 0;
virtual void OnGestureEventAck(
const GestureEventWithLatencyInfo& event,
blink::mojom::InputEventResultSource ack_source,
blink::mojom::InputEventResultState ack_result) = 0;
};
// Despite its name, this class isn't so much one queue as it is a collection
// of queues and filters. This class applies logic to determine if an event
// should be queued, filtered altogether, or sent immediately; it tracks sent
// events and ACKs them to the clilent in the order they were dispatched. This
// class applies a series of filters and queues for various scenarios:
// 1. The sequence is filtered for bounces. A bounce is when the finger lifts
// from the screen briefly during an in-progress scroll. If this happens,
// non-GestureScrollUpdate events are queued until the de-bounce interval
// passes or another GestureScrollUpdate event occurs.
// 2. Unnecessary GestureFlingCancel events are filtered by fling controller.
// These are GestureFlingCancels that have no corresponding GestureFlingStart
// in the queue. GestureFlingStarts are also filtered and translated to
// scroll gestures by the fling controller.
// 3. Taps immediately after a GestureFlingCancel (caused by the same tap) are
// filtered by fling controller.
// 4. Gesture events are queued while we're waiting to determine the allowed
// touch actions.
// Sent events are kept in a queue until a response from the renderer is
// received for that event. The client is notified of ACKs in the order the
// events were sent, not ACK'd. This means an ACK'd event that was sent after
// an event still awaiting an ACK won't notify the client until the earlier
// event is ACK'd.
class COMPONENT_EXPORT(INPUT) GestureEventQueue {
public:
using GestureWithCallbackQueue =
base::circular_deque<GestureEventWithLatencyInfoAndCallback>;
struct COMPONENT_EXPORT(INPUT) Config {
Config();
FlingController::Config fling_config;
// Determines whether non-scroll gesture events are "debounced" during an
// active scroll sequence, suppressing brief scroll interruptions.
// Zero by default (disabled).
base::TimeDelta debounce_interval;
};
// Both |client| and |touchpad_client| must outlive the GestureEventQueue.
GestureEventQueue(
GestureEventQueueClient* client,
FlingControllerEventSenderClient* fling_event_sender_client,
FlingControllerSchedulerClient* fling_scheduler_client,
const Config& config);
GestureEventQueue(const GestureEventQueue&) = delete;
GestureEventQueue& operator=(const GestureEventQueue&) = delete;
~GestureEventQueue();
// Allow the fling controller to observe the gesture event. Returns true if
// the event was filtered by the fling controller and shouldn't be further
// forwarded.
bool PassToFlingController(const GestureEventWithLatencyInfo&);
// Filter the event for debouncing or forward it to the renderer. Returns
// true if the event was forwarded, false if was filtered for debouncing.
bool DebounceOrForwardEvent(const GestureEventWithLatencyInfo&,
DispatchToRendererCallback& dispatch_callback);
// Adds a gesture to the queue of events that needs to be deferred until the
// touch action is known.
void QueueDeferredEvents(const GestureEventWithLatencyInfo&,
DispatchToRendererCallback&);
// Returns events in the |deferred_gesture_queue_| and empty the queue.
GestureWithCallbackQueue TakeDeferredEvents();
// Indicates that the caller has received an acknowledgement from the renderer
// with state |ack_result| and event |type|.
void ProcessGestureAck(blink::mojom::InputEventResultSource ack_source,
blink::mojom::InputEventResultState ack_result,
blink::WebInputEvent::Type type,
const ui::LatencyInfo& latency);
// Returns the |TouchpadTapSuppressionController| instance.
TouchpadTapSuppressionController*
GetTouchpadTapSuppressionController();
// Sends the gesture event to the renderer. Stores the sent event for when
// the renderer replies with an ACK.
void ForwardGestureEvent(const GestureEventWithLatencyInfo& gesture_event,
DispatchToRendererCallback& dispatch_callback);
bool empty() const {
return sent_events_awaiting_ack_.empty() &&
debouncing_deferral_queue_.empty();
}
// Calls |fling_controller_.StopFling| to halt an active fling if such exists.
void StopFling();
gfx::Vector2dF CurrentFlingVelocity() const;
void set_debounce_interval_time_ms_for_testing(int interval_ms) {
debounce_interval_ = base::Milliseconds(interval_ms);
}
// TODO(nburris): Wheel event acks shouldn't really go through the gesture
// event queue, but this is needed to pass them through to the
// FlingController. The FlingController should probably be owned by the
// InputRouter instead.
void OnWheelEventAck(const MouseWheelEventWithLatencyInfo& event,
blink::mojom::InputEventResultSource ack_source,
blink::mojom::InputEventResultState ack_result);
bool IsFlingActiveForTest() { return FlingInProgressForTest(); }
private:
friend class GestureEventQueueTest;
friend class MockRenderWidgetHost;
class GestureEventWithLatencyInfoAckState
: public GestureEventWithLatencyInfo {
public:
GestureEventWithLatencyInfoAckState(
const GestureEventWithLatencyInfo&);
blink::mojom::InputEventResultState ack_state() const { return ack_state_; }
void set_ack_info(blink::mojom::InputEventResultSource source,
blink::mojom::InputEventResultState state) {
ack_source_ = source;
ack_state_ = state;
}
blink::mojom::InputEventResultSource ack_source() const {
return ack_source_;
}
private:
blink::mojom::InputEventResultSource ack_source_ =
blink::mojom::InputEventResultSource::kUnknown;
blink::mojom::InputEventResultState ack_state_ =
blink::mojom::InputEventResultState::kUnknown;
};
// Inovked on the expiration of the debounce interval to release
// deferred events.
void SendScrollEndingEventsNow();
// Sub-filter for removing bounces from in-progress scrolls.
bool ShouldForwardForBounceReduction(
const GestureEventWithLatencyInfo& gesture_event,
DispatchToRendererCallback& dispatch_callback);
// ACK completed events in order until we have reached an incomplete event.
// Will preserve the FIFO order as events originally arrived.
void AckCompletedEvents();
void AckGestureEventToClient(const GestureEventWithLatencyInfo&,
blink::mojom::InputEventResultSource,
blink::mojom::InputEventResultState);
bool FlingInProgressForTest() const;
// The receiver of all forwarded gesture events.
raw_ptr<GestureEventQueueClient> client_;
// True if a GestureScrollUpdate sequence is in progress.
bool scrolling_in_progress_;
bool processing_acks_ = false;
using GestureQueueWithAckState =
base::circular_deque<GestureEventWithLatencyInfoAckState>;
// Stores outstanding events that have been sent to the renderer but not yet
// been ACK'd. These are kept in the order they were sent in so that they can
// be ACK'd back in order. Note, the renderer can reply to these out-of-order.
// This class makes a note of the ACK state but doesn't actually let the
// client know about the ACK until all events earlier in the queue have been
// ACK'd so that the client sees the ACKs in order.
GestureQueueWithAckState sent_events_awaiting_ack_;
// Timer to release a previously deferred gesture event.
base::OneShotTimer debounce_deferring_timer_;
// Queue of events that have been deferred for debounce.
GestureWithCallbackQueue debouncing_deferral_queue_;
// Queue of gesture events that have been deferred until the main thread touch
// action is known.
GestureWithCallbackQueue deferred_gesture_queue_;
// Time window in which to debounce scroll/fling ends. Note that an interval
// of zero effectively disables debouncing.
base::TimeDelta debounce_interval_;
// An object for filtering unnecessary GFC events, as well as gestureTap/mouse
// events that happen immediately after touchscreen/touchpad fling canceling
// taps.
FlingController fling_controller_;
// True when the last GSE event is either in the debouncing_deferral_queue_ or
// pushed to the queue and dropped from it later on.
bool scroll_end_filtered_by_deboucing_deferral_queue_ = false;
};
} // namespace input
#endif // COMPONENTS_INPUT_GESTURE_EVENT_QUEUE_H_
|