Home | History | Annotate | Download | only in input
      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