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