File: gesture_event_queue.h

package info (click to toggle)
chromium 139.0.7258.127-1
  • links: PTS, VCS
  • area: main
  • in suites:
  • size: 6,122,068 kB
  • sloc: cpp: 35,100,771; ansic: 7,163,530; javascript: 4,103,002; python: 1,436,920; asm: 946,517; xml: 746,709; pascal: 187,653; perl: 88,691; sh: 88,436; objc: 79,953; sql: 51,488; cs: 44,583; fortran: 24,137; makefile: 22,147; tcl: 15,277; php: 13,980; yacc: 8,984; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (253 lines) | stat: -rw-r--r-- 10,405 bytes parent folder | download | duplicates (6)
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_