1// Copyright 2014 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#ifndef CONTENT_BROWSER_RENDERER_HOST_INPUT_GESTURE_EVENT_QUEUE_H_
6#define CONTENT_BROWSER_RENDERER_HOST_INPUT_GESTURE_EVENT_QUEUE_H_
7
8#include <deque>
9
10#include "base/basictypes.h"
11#include "base/memory/scoped_ptr.h"
12#include "base/timer/timer.h"
13#include "content/browser/renderer_host/event_with_latency_info.h"
14#include "content/browser/renderer_host/input/tap_suppression_controller.h"
15#include "content/browser/renderer_host/input/touchpad_tap_suppression_controller.h"
16#include "content/browser/renderer_host/input/touchscreen_tap_suppression_controller.h"
17#include "content/common/content_export.h"
18#include "content/common/input/input_event_ack_state.h"
19#include "third_party/WebKit/public/web/WebInputEvent.h"
20#include "ui/gfx/transform.h"
21
22namespace content {
23class GestureEventQueueTest;
24class InputRouter;
25class MockRenderWidgetHost;
26
27// Interface with which the GestureEventQueue can forward gesture events, and
28// dispatch gesture event responses.
29class CONTENT_EXPORT GestureEventQueueClient {
30 public:
31  virtual ~GestureEventQueueClient() {}
32
33  virtual void SendGestureEventImmediately(
34      const GestureEventWithLatencyInfo& event) = 0;
35
36  virtual void OnGestureEventAck(
37      const GestureEventWithLatencyInfo& event,
38      InputEventAckState ack_result) = 0;
39};
40
41// Maintains WebGestureEvents in a queue before forwarding them to the renderer
42// to apply a sequence of filters on them:
43// 1. The sequence is filtered for bounces. A bounce is when the finger lifts
44//    from the screen briefly during an in-progress scroll. Ifco this happens,
45//    non-GestureScrollUpdate events are queued until the de-bounce interval
46//    passes or another GestureScrollUpdate event occurs.
47// 2. Unnecessary GestureFlingCancel events are filtered. These are
48//    GestureFlingCancels that have no corresponding GestureFlingStart in the
49//    queue.
50// 3. Taps immediately after a GestureFlingCancel (caused by the same tap) are
51//    filtered.
52// 4. Whenever possible, events in the queue are coalesced to have as few events
53//    as possible and therefore maximize the chance that the event stream can be
54//    handled entirely by the compositor thread.
55// Events in the queue are forwarded to the renderer one by one; i.e., each
56// event is sent after receiving the ACK for previous one. The only exception is
57// that if a GestureScrollUpdate is followed by a GesturePinchUpdate, they are
58// sent together.
59// TODO(rjkroege): Possibly refactor into a filter chain:
60// http://crbug.com/148443.
61class CONTENT_EXPORT GestureEventQueue {
62 public:
63  struct CONTENT_EXPORT Config {
64    Config();
65
66    // Controls touchpad-related tap suppression, disabled by default.
67    TapSuppressionController::Config touchpad_tap_suppression_config;
68
69    // Controls touchscreen-related tap suppression, disabled by default.
70    TapSuppressionController::Config touchscreen_tap_suppression_config;
71
72    // Determines whether non-scroll gesture events are "debounced" during an
73    // active scroll sequence, suppressing brief scroll interruptions.
74    // Zero by default (disabled).
75    base::TimeDelta debounce_interval;
76  };
77
78  // Both |client| and |touchpad_client| must outlive the GestureEventQueue.
79  GestureEventQueue(GestureEventQueueClient* client,
80                    TouchpadTapSuppressionControllerClient* touchpad_client,
81                    const Config& config);
82  ~GestureEventQueue();
83
84  // Returns |true| if the caller should immediately forward the provided
85  // |GestureEventWithLatencyInfo| argument to the renderer.
86  // If this function returns false, then the event may be queued and forwared
87  // at a later point.
88  bool ShouldForward(const GestureEventWithLatencyInfo&);
89
90  // Indicates that the caller has received an acknowledgement from the renderer
91  // with state |ack_result| and event |type|. May send events if the queue is
92  // not empty.
93  void ProcessGestureAck(InputEventAckState ack_result,
94                         blink::WebInputEvent::Type type,
95                         const ui::LatencyInfo& latency);
96
97  // Sets the state of the |fling_in_progress_| field to indicate that a fling
98  // is definitely not in progress.
99  void FlingHasBeenHalted();
100
101  // Returns the |TouchpadTapSuppressionController| instance.
102  TouchpadTapSuppressionController* GetTouchpadTapSuppressionController();
103
104  void ForwardGestureEvent(const GestureEventWithLatencyInfo& gesture_event);
105
106  // Whether the queue is expecting a gesture event ack.
107  bool ExpectingGestureAck() const;
108
109  bool empty() const {
110    return coalesced_gesture_events_.empty() &&
111           debouncing_deferral_queue_.empty();
112  }
113
114  void set_debounce_interval_time_ms_for_testing(int interval_ms) {
115    debounce_interval_ = base::TimeDelta::FromMilliseconds(interval_ms);
116  }
117
118 private:
119  friend class GestureEventQueueTest;
120  friend class MockRenderWidgetHost;
121
122  // TODO(mohsen): There are a bunch of ShouldForward.../ShouldDiscard...
123  // methods that are getting confusing. This should be somehow fixed. Maybe
124  // while refactoring GEQ: http://crbug.com/148443.
125
126  // Inovked on the expiration of the debounce interval to release
127  // deferred events.
128  void SendScrollEndingEventsNow();
129
130  // Returns |true| if the given GestureFlingCancel should be discarded
131  // as unnecessary.
132  bool ShouldDiscardFlingCancelEvent(
133      const GestureEventWithLatencyInfo& gesture_event) const;
134
135  // Returns |true| if the only event in the queue is the current event and
136  // hence that event should be handled now.
137  bool ShouldHandleEventNow() const;
138
139  // Merge or append a GestureScrollUpdate or GesturePinchUpdate into
140  // the coalescing queue.
141  void MergeOrInsertScrollAndPinchEvent(
142      const GestureEventWithLatencyInfo& gesture_event);
143
144  // Sub-filter for removing bounces from in-progress scrolls.
145  bool ShouldForwardForBounceReduction(
146      const GestureEventWithLatencyInfo& gesture_event);
147
148  // Sub-filter for removing unnecessary GestureFlingCancels.
149  bool ShouldForwardForGFCFiltering(
150      const GestureEventWithLatencyInfo& gesture_event) const;
151
152  // Sub-filter for suppressing taps immediately after a GestureFlingCancel.
153  bool ShouldForwardForTapSuppression(
154      const GestureEventWithLatencyInfo& gesture_event);
155
156  // Puts the events in a queue to forward them one by one; i.e., forward them
157  // whenever ACK for previous event is received. This queue also tries to
158  // coalesce events as much as possible.
159  bool ShouldForwardForCoalescing(
160      const GestureEventWithLatencyInfo& gesture_event);
161
162  // Whether the event_in_queue is GesturePinchUpdate or
163  // GestureScrollUpdate and it has the same modifiers as the
164  // new event.
165  bool ShouldTryMerging(
166      const GestureEventWithLatencyInfo& new_event,
167      const GestureEventWithLatencyInfo& event_in_queue)const;
168
169  // Returns the transform matrix corresponding to the gesture event.
170  // Assumes the gesture event sent is either GestureScrollUpdate or
171  // GesturePinchUpdate. Returns the identity matrix otherwise.
172  gfx::Transform GetTransformForEvent(
173      const GestureEventWithLatencyInfo& gesture_event) const;
174
175  // The number of sent events for which we're awaiting an ack.  These events
176  // remain at the head of the queue until ack'ed.
177  size_t EventsInFlightCount() const;
178
179  // The receiver of all forwarded gesture events.
180  GestureEventQueueClient* client_;
181
182  // True if a GestureFlingStart is in progress on the renderer or
183  // queued without a subsequent queued GestureFlingCancel event.
184  bool fling_in_progress_;
185
186  // True if a GestureScrollUpdate sequence is in progress.
187  bool scrolling_in_progress_;
188
189  // True if two related gesture events were sent before without waiting
190  // for an ACK, so the next gesture ACK should be ignored.
191  bool ignore_next_ack_;
192
193  // An object tracking the state of touchpad on the delivery of mouse events to
194  // the renderer to filter mouse immediately after a touchpad fling canceling
195  // tap.
196  // TODO(mohsen): Move touchpad tap suppression out of GestureEventQueue since
197  // GEQ is meant to only be used for touchscreen gesture events.
198  TouchpadTapSuppressionController touchpad_tap_suppression_controller_;
199
200  // An object tracking the state of touchscreen on the delivery of gesture tap
201  // events to the renderer to filter taps immediately after a touchscreen fling
202  // canceling tap.
203  TouchscreenTapSuppressionController touchscreen_tap_suppression_controller_;
204
205  typedef std::deque<GestureEventWithLatencyInfo> GestureQueue;
206
207  // Queue of coalesced gesture events not yet sent to the renderer. If
208  // |ignore_next_ack_| is false, then the event at the front of the queue has
209  // been sent and is awaiting an ACK, and all other events have yet to be sent.
210  // If |ignore_next_ack_| is true, then the two events at the front of the
211  // queue have been sent, and the second is awaiting an ACK. All other events
212  // have yet to be sent.
213  GestureQueue coalesced_gesture_events_;
214
215  // Timer to release a previously deferred gesture event.
216  base::OneShotTimer<GestureEventQueue> debounce_deferring_timer_;
217
218  // Queue of events that have been deferred for debounce.
219  GestureQueue debouncing_deferral_queue_;
220
221  // Time window in which to debounce scroll/fling ends. Note that an interval
222  // of zero effectively disables debouncing.
223  base::TimeDelta debounce_interval_;
224
225  DISALLOW_COPY_AND_ASSIGN(GestureEventQueue);
226};
227
228}  // namespace content
229
230#endif  // CONTENT_BROWSER_RENDERER_HOST_INPUT_GESTURE_EVENT_QUEUE_H_
231