• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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:
~TouchEventQueueClient()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 
empty()122   bool empty() const WARN_UNUSED_RESULT {
123     return touch_queue_.empty();
124   }
125 
size()126   size_t size() const {
127     return touch_queue_.size();
128   }
129 
ack_timeout_enabled()130   bool ack_timeout_enabled() const {
131     return ack_timeout_enabled_;
132   }
133 
has_handlers()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