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_TOUCH_EVENT_QUEUE_H_ 6 #define CONTENT_BROWSER_RENDERER_HOST_INPUT_TOUCH_EVENT_QUEUE_H_ 7 8 #include <deque> 9 #include <map> 10 11 #include "base/basictypes.h" 12 #include "base/time/time.h" 13 #include "content/browser/renderer_host/event_with_latency_info.h" 14 #include "content/common/content_export.h" 15 #include "content/common/input/input_event_ack_state.h" 16 #include "third_party/WebKit/public/web/WebInputEvent.h" 17 #include "ui/gfx/geometry/point_f.h" 18 19 namespace content { 20 21 class CoalescedWebTouchEvent; 22 23 // Interface with which TouchEventQueue can forward touch events, and dispatch 24 // touch event responses. 25 class CONTENT_EXPORT TouchEventQueueClient { 26 public: 27 virtual ~TouchEventQueueClient() {} 28 29 virtual void SendTouchEventImmediately( 30 const TouchEventWithLatencyInfo& event) = 0; 31 32 virtual void OnTouchEventAck( 33 const TouchEventWithLatencyInfo& event, 34 InputEventAckState ack_result) = 0; 35 }; 36 37 // A queue for throttling and coalescing touch-events. 38 class CONTENT_EXPORT TouchEventQueue { 39 public: 40 // Different ways of dealing with touch events during scrolling. 41 // TODO(rbyers): Remove this once we're confident that touch move absorption 42 // is OK. http://crbug.com/350430 43 enum TouchScrollingMode { 44 // Send a touchcancel on scroll start and no further touch events for the 45 // duration of the scroll. Chrome Android's traditional behavior. 46 TOUCH_SCROLLING_MODE_TOUCHCANCEL, 47 // Send touchmove events throughout a scroll, blocking on each ACK and 48 // using the disposition to determine whether a scroll update should be 49 // sent. Mobile Safari's default overflow scroll behavior. 50 TOUCH_SCROLLING_MODE_SYNC_TOUCHMOVE, 51 // Send touchmove events throughout a scroll, but throttle sending and 52 // ignore the ACK as long as scrolling remains possible. Unconsumed scroll 53 // events return touchmove events to being dispatched synchronously. 54 TOUCH_SCROLLING_MODE_ASYNC_TOUCHMOVE, 55 TOUCH_SCROLLING_MODE_DEFAULT = TOUCH_SCROLLING_MODE_ASYNC_TOUCHMOVE 56 }; 57 58 struct CONTENT_EXPORT Config { 59 Config(); 60 61 // Determines the bounds of the (square) touchmove slop suppression region. 62 // Defaults to 0 (disabled). 63 double touchmove_slop_suppression_length_dips; 64 65 // Whether the touchmove slop suppression region is boundary inclusive. 66 // Defaults to true. 67 // TODO(jdduke): Remove when unified GR enabled, crbug.com/332418. 68 bool touchmove_slop_suppression_region_includes_boundary; 69 70 // Determines the type of touch scrolling. 71 // Defaults to TouchEventQueue:::TOUCH_SCROLLING_MODE_DEFAULT. 72 TouchEventQueue::TouchScrollingMode touch_scrolling_mode; 73 74 // Controls whether touch ack timeouts will trigger touch cancellation. 75 // Defaults to 200ms. 76 base::TimeDelta touch_ack_timeout_delay; 77 78 // Whether the platform supports touch ack timeout behavior. 79 // Defaults to false (disabled). 80 bool touch_ack_timeout_supported; 81 }; 82 83 // The |client| must outlive the TouchEventQueue. 84 TouchEventQueue(TouchEventQueueClient* client, const Config& config); 85 86 ~TouchEventQueue(); 87 88 // Adds an event to the queue. The event may be coalesced with previously 89 // queued events (e.g. consecutive touch-move events can be coalesced into a 90 // single touch-move event). The event may also be immediately forwarded to 91 // the renderer (e.g. when there are no other queued touch event). 92 void QueueEvent(const TouchEventWithLatencyInfo& event); 93 94 // Notifies the queue that a touch-event has been processed by the renderer. 95 // At this point, the queue may send one or more gesture events and/or 96 // additional queued touch-events to the renderer. 97 void ProcessTouchAck(InputEventAckState ack_result, 98 const ui::LatencyInfo& latency_info); 99 100 // When GestureScrollBegin is received, we send a touch cancel to renderer, 101 // route all the following touch events directly to client, and ignore the 102 // ack for the touch cancel. When Gesture{ScrollEnd,FlingStart} is received, 103 // resume the normal flow of sending touch events to the renderer. 104 void OnGestureScrollEvent(const GestureEventWithLatencyInfo& gesture_event); 105 106 void OnGestureEventAck( 107 const GestureEventWithLatencyInfo& event, 108 InputEventAckState ack_result); 109 110 // Notifies the queue whether the renderer has at least one touch handler. 111 void OnHasTouchEventHandlers(bool has_handlers); 112 113 // Returns whether the currently pending touch event (waiting ACK) is for 114 // a touch start event. 115 bool IsPendingAckTouchStart() const; 116 117 // Sets whether a delayed touch ack will cancel and flush the current 118 // touch sequence. Note that, if the timeout was previously disabled, enabling 119 // it will take effect only for the following touch sequence. 120 void SetAckTimeoutEnabled(bool enabled); 121 122 bool empty() const WARN_UNUSED_RESULT { 123 return touch_queue_.empty(); 124 } 125 126 size_t size() const { 127 return touch_queue_.size(); 128 } 129 130 bool ack_timeout_enabled() const { 131 return ack_timeout_enabled_; 132 } 133 134 bool has_handlers() const { 135 return touch_filtering_state_ != DROP_ALL_TOUCHES; 136 } 137 138 private: 139 class TouchTimeoutHandler; 140 class TouchMoveSlopSuppressor; 141 friend class TouchTimeoutHandler; 142 friend class TouchEventQueueTest; 143 144 bool HasPendingAsyncTouchMoveForTesting() const; 145 bool IsTimeoutRunningForTesting() const; 146 const TouchEventWithLatencyInfo& GetLatestEventForTesting() const; 147 148 // Empties the queue of touch events. This may result in any number of gesture 149 // events being sent to the renderer. 150 void FlushQueue(); 151 152 // Walks the queue, checking each event with |FilterBeforeForwarding()|. 153 // If allowed, forwards the touch event and stops processing further events. 154 // Otherwise, acks the event with |INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS|. 155 void TryForwardNextEventToRenderer(); 156 157 // Forwards the event at the head of the queue to the renderer. 158 void ForwardNextEventToRenderer(); 159 160 // Pops the touch-event from the head of the queue and acks it to the client. 161 void PopTouchEventToClient(InputEventAckState ack_result); 162 163 // Pops the touch-event from the top of the queue and acks it to the client, 164 // updating the event with |renderer_latency_info|. 165 void PopTouchEventToClient(InputEventAckState ack_result, 166 const ui::LatencyInfo& renderer_latency_info); 167 168 // Ack all coalesced events in |acked_event| to the client with |ack_result|. 169 void AckTouchEventToClient(InputEventAckState ack_result, 170 scoped_ptr<CoalescedWebTouchEvent> acked_event); 171 172 // Safely pop the head of the queue. 173 scoped_ptr<CoalescedWebTouchEvent> PopTouchEvent(); 174 175 // Dispatch |touch| to the client. 176 void SendTouchEventImmediately(const TouchEventWithLatencyInfo& touch); 177 178 enum PreFilterResult { 179 ACK_WITH_NO_CONSUMER_EXISTS, 180 ACK_WITH_NOT_CONSUMED, 181 FORWARD_TO_RENDERER, 182 }; 183 // Filter touches prior to forwarding to the renderer, e.g., if the renderer 184 // has no touch handler. 185 PreFilterResult FilterBeforeForwarding(const blink::WebTouchEvent& event); 186 void ForwardToRenderer(const TouchEventWithLatencyInfo& event); 187 void UpdateTouchAckStates(const blink::WebTouchEvent& event, 188 InputEventAckState ack_result); 189 bool AllTouchAckStatesHaveState(InputEventAckState ack_state) const; 190 191 192 // Handles touch event forwarding and ack'ed event dispatch. 193 TouchEventQueueClient* client_; 194 195 typedef std::deque<CoalescedWebTouchEvent*> TouchQueue; 196 TouchQueue touch_queue_; 197 198 // Maintain the ACK status for each touch point. 199 typedef std::map<int, InputEventAckState> TouchPointAckStates; 200 TouchPointAckStates touch_ack_states_; 201 202 // Position of the first touch in the most recent sequence forwarded to the 203 // client. 204 gfx::PointF touch_sequence_start_position_; 205 206 // Used to defer touch forwarding when ack dispatch triggers |QueueEvent()|. 207 // If not NULL, |dispatching_touch_ack_| is the touch event of which the ack 208 // is being dispatched. 209 const CoalescedWebTouchEvent* dispatching_touch_ack_; 210 211 // Used to prevent touch timeout scheduling if we receive a synchronous 212 // ack after forwarding a touch event to the client. 213 bool dispatching_touch_; 214 215 enum TouchFilteringState { 216 FORWARD_ALL_TOUCHES, // Don't filter at all - the default. 217 FORWARD_TOUCHES_UNTIL_TIMEOUT, // Don't filter unless we get an ACK timeout. 218 DROP_TOUCHES_IN_SEQUENCE, // Filter all events until a new touch 219 // sequence is received. 220 DROP_ALL_TOUCHES, // Filter all events, e.g., no touch handler. 221 TOUCH_FILTERING_STATE_DEFAULT = FORWARD_ALL_TOUCHES, 222 }; 223 TouchFilteringState touch_filtering_state_; 224 225 // Optional handler for timed-out touch event acks. 226 bool ack_timeout_enabled_; 227 scoped_ptr<TouchTimeoutHandler> timeout_handler_; 228 229 // Suppression of TouchMove's within a slop region when a sequence has not yet 230 // been preventDefaulted. 231 scoped_ptr<TouchMoveSlopSuppressor> touchmove_slop_suppressor_; 232 233 // Whether touch events should remain buffered and dispatched asynchronously 234 // while a scroll sequence is active. In this mode, touchmove's are throttled 235 // and ack'ed immediately, but remain buffered in |pending_async_touchmove_| 236 // until a sufficient time period has elapsed since the last sent touch event. 237 // For details see the design doc at http://goo.gl/lVyJAa. 238 bool send_touch_events_async_; 239 bool needs_async_touchmove_for_outer_slop_region_; 240 scoped_ptr<TouchEventWithLatencyInfo> pending_async_touchmove_; 241 double last_sent_touch_timestamp_sec_; 242 243 // How touch events are handled during scrolling. For now this is a global 244 // setting for experimentation, but we may evolve it into an app-controlled 245 // mode. 246 const TouchScrollingMode touch_scrolling_mode_; 247 248 DISALLOW_COPY_AND_ASSIGN(TouchEventQueue); 249 }; 250 251 } // namespace content 252 253 #endif // CONTENT_BROWSER_RENDERER_HOST_INPUT_TOUCH_EVENT_QUEUE_H_ 254