1 // Copyright 2013 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_FILTER_H_ 6 #define CONTENT_BROWSER_RENDERER_HOST_INPUT_GESTURE_EVENT_FILTER_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/port/browser/event_with_latency_info.h" 14 #include "third_party/WebKit/public/web/WebInputEvent.h" 15 #include "ui/gfx/transform.h" 16 17 namespace content { 18 class InputRouter; 19 class MockRenderWidgetHost; 20 class TouchpadTapSuppressionController; 21 class TouchscreenTapSuppressionController; 22 23 // Maintains WebGestureEvents in a queue before forwarding them to the renderer 24 // to apply a sequence of filters on them: 25 // 1. Zero-velocity fling-starts from touchpad are filtered. 26 // 2. The sequence is filtered for bounces. A bounce is when the finger lifts 27 // from the screen briefly during an in-progress scroll. If this happens, 28 // non-GestureScrollUpdate events are queued until the de-bounce interval 29 // passes or another GestureScrollUpdate event occurs. 30 // 3. Unnecessary GestureFlingCancel events are filtered. These are 31 // GestureFlingCancels that have no corresponding GestureFlingStart in the 32 // queue. 33 // 4. Taps immediately after a GestureFlingCancel (caused by the same tap) are 34 // filtered. 35 // 5. Whenever possible, events in the queue are coalesced to have as few events 36 // as possible and therefore maximize the chance that the event stream can be 37 // handled entirely by the compositor thread. 38 // Events in the queue are forwarded to the renderer one by one; i.e., each 39 // event is sent after receiving the ACK for previous one. The only exception is 40 // that if a GestureScrollUpdate is followed by a GesturePinchUpdate, they are 41 // sent together. 42 // TODO(rjkroege): Possibly refactor into a filter chain: 43 // http://crbug.com/148443. 44 class GestureEventFilter { 45 public: 46 // The |input_router| must outlive the GestureEventFilter. 47 explicit GestureEventFilter(InputRouter* input_router); 48 ~GestureEventFilter(); 49 50 // Returns |true| if the caller should immediately forward the provided 51 // |GestureEventWithLatencyInfo| argument to the renderer. 52 bool ShouldForward(const GestureEventWithLatencyInfo&); 53 54 // Indicates that the caller has received an acknowledgement from the renderer 55 // with state |processed| and event |type|. May send events if the queue is 56 // not empty. 57 void ProcessGestureAck(bool processed, int type); 58 59 // Sets the state of the |fling_in_progress_| field to indicate that a fling 60 // is definitely not in progress. 61 void FlingHasBeenHalted(); 62 63 // Returns the |TouchpadTapSuppressionController| instance. 64 TouchpadTapSuppressionController* GetTouchpadTapSuppressionController(); 65 66 // Returns whether there are any gesture event in the queue. 67 bool HasQueuedGestureEvents() const; 68 69 // Returns the last gesture event that was sent to the renderer. 70 const WebKit::WebGestureEvent& GetGestureEventAwaitingAck() const; 71 72 // Tries forwarding the event to the tap deferral sub-filter. 73 void ForwardGestureEventForDeferral( 74 const GestureEventWithLatencyInfo& gesture_event); 75 76 // Tries forwarding the event, skipping the tap deferral sub-filter. 77 void ForwardGestureEventSkipDeferral( 78 const GestureEventWithLatencyInfo& gesture_event); 79 80 private: 81 friend class MockRenderWidgetHost; 82 friend class ImmediateInputRouterTest; 83 84 // TODO(mohsen): There are a bunch of ShouldForward.../ShouldDiscard... 85 // methods that are getting confusing. This should be somehow fixed. Maybe 86 // while refactoring GEF: http://crbug.com/148443. 87 88 // Invoked on the expiration of the timer to release a deferred 89 // GestureTapDown to the renderer. 90 void SendGestureTapDownNow(); 91 92 // Inovked on the expiration of the debounce interval to release 93 // deferred events. 94 void SendScrollEndingEventsNow(); 95 96 // Returns |true| if the given GestureFlingCancel should be discarded 97 // as unnecessary. 98 bool ShouldDiscardFlingCancelEvent( 99 const GestureEventWithLatencyInfo& gesture_event) const; 100 101 // Returns |true| if the only event in the queue is the current event and 102 // hence that event should be handled now. 103 bool ShouldHandleEventNow() const; 104 105 // Merge or append a GestureScrollUpdate or GesturePinchUpdate into 106 // the coalescing queue. 107 void MergeOrInsertScrollAndPinchEvent( 108 const GestureEventWithLatencyInfo& gesture_event); 109 110 // Sub-filter for removing zero-velocity fling-starts from touchpad. 111 bool ShouldForwardForZeroVelocityFlingStart( 112 const GestureEventWithLatencyInfo& gesture_event) const; 113 114 // Sub-filter for removing bounces from in-progress scrolls. 115 bool ShouldForwardForBounceReduction( 116 const GestureEventWithLatencyInfo& gesture_event); 117 118 // Sub-filter for removing unnecessary GestureFlingCancels. 119 bool ShouldForwardForGFCFiltering( 120 const GestureEventWithLatencyInfo& gesture_event) const; 121 122 // Sub-filter for suppressing taps immediately after a GestureFlingCancel. 123 bool ShouldForwardForTapSuppression( 124 const GestureEventWithLatencyInfo& gesture_event); 125 126 // Sub-filter for deferring GestureTapDowns. 127 bool ShouldForwardForTapDeferral( 128 const GestureEventWithLatencyInfo& gesture_event); 129 130 // Puts the events in a queue to forward them one by one; i.e., forward them 131 // whenever ACK for previous event is received. This queue also tries to 132 // coalesce events as much as possible. 133 bool ShouldForwardForCoalescing( 134 const GestureEventWithLatencyInfo& gesture_event); 135 136 // Whether the event_in_queue is GesturePinchUpdate or 137 // GestureScrollUpdate and it has the same modifiers as the 138 // new event. 139 bool ShouldTryMerging( 140 const GestureEventWithLatencyInfo& new_event, 141 const GestureEventWithLatencyInfo& event_in_queue)const; 142 143 // Returns the transform matrix corresponding to the gesture event. 144 // Assumes the gesture event sent is either GestureScrollUpdate or 145 // GesturePinchUpdate. Returns the identity matrix otherwise. 146 gfx::Transform GetTransformForEvent( 147 const GestureEventWithLatencyInfo& gesture_event) const; 148 149 // The receiver of all forwarded gesture events. 150 InputRouter* input_router_; 151 152 // True if a GestureFlingStart is in progress on the renderer or 153 // queued without a subsequent queued GestureFlingCancel event. 154 bool fling_in_progress_; 155 156 // True if a GestureScrollUpdate sequence is in progress. 157 bool scrolling_in_progress_; 158 159 // True if two related gesture events were sent before without waiting 160 // for an ACK, so the next gesture ACK should be ignored. 161 bool ignore_next_ack_; 162 163 // Transform that holds the combined transform matrix for the current 164 // scroll-pinch sequence at the end of the queue. 165 gfx::Transform combined_scroll_pinch_; 166 167 // Timer to release a previously deferred GestureTapDown event. 168 base::OneShotTimer<GestureEventFilter> send_gtd_timer_; 169 170 // An object tracking the state of touchpad on the delivery of mouse events to 171 // the renderer to filter mouse immediately after a touchpad fling canceling 172 // tap. 173 // TODO(mohsen): Move touchpad tap suppression out of GestureEventFilter since 174 // GEF is meant to only be used for touchscreen gesture events. 175 scoped_ptr<TouchpadTapSuppressionController> 176 touchpad_tap_suppression_controller_; 177 178 // An object tracking the state of touchscreen on the delivery of gesture tap 179 // events to the renderer to filter taps immediately after a touchscreen fling 180 // canceling tap. 181 scoped_ptr<TouchscreenTapSuppressionController> 182 touchscreen_tap_suppression_controller_; 183 184 typedef std::deque<GestureEventWithLatencyInfo> GestureEventQueue; 185 186 // Queue of coalesced gesture events not yet sent to the renderer. 187 GestureEventQueue coalesced_gesture_events_; 188 189 // Tap gesture event currently subject to deferral. 190 GestureEventWithLatencyInfo deferred_tap_down_event_; 191 192 // Timer to release a previously deferred GestureTapDown event. 193 base::OneShotTimer<GestureEventFilter> debounce_deferring_timer_; 194 195 // Queue of events that have been deferred for debounce. 196 GestureEventQueue debouncing_deferral_queue_; 197 198 // Time window in which to defer a GestureTapDown. 199 int maximum_tap_gap_time_ms_; 200 201 // Time window in which to debounce scroll/fling ends. 202 // TODO(rjkroege): Make this dynamically configurable. 203 int debounce_interval_time_ms_; 204 205 DISALLOW_COPY_AND_ASSIGN(GestureEventFilter); 206 }; 207 208 } // namespace content 209 210 #endif // CONTENT_BROWSER_RENDERER_HOST_INPUT_GESTURE_EVENT_FILTER_H_ 211