| OLD | NEW | 
|    1 // Copyright 2013 The Chromium Authors. All rights reserved. |    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 |    2 // Use of this source code is governed by a BSD-style license that can be | 
|    3 // found in the LICENSE file. |    3 // found in the LICENSE file. | 
|    4  |    4  | 
|    5 #include "content/browser/renderer_host/input/touch_event_queue.h" |    5 #include "content/browser/renderer_host/input/touch_event_queue.h" | 
|    6  |    6  | 
|    7 #include "base/auto_reset.h" |    7 #include "base/auto_reset.h" | 
|    8 #include "base/debug/trace_event.h" |    8 #include "base/debug/trace_event.h" | 
|    9 #include "base/stl_util.h" |    9 #include "base/stl_util.h" | 
|   10  |   10  | 
|   11 namespace content { |   11 namespace content { | 
|   12  |   12  | 
|   13 typedef std::vector<TouchEventWithLatencyInfo> WebTouchEventWithLatencyList; |   13 typedef std::vector<TouchEventWithLatencyInfo> WebTouchEventWithLatencyList; | 
|   14  |   14  | 
|   15 // This class represents a single coalesced touch event. However, it also keeps |   15 // This class represents a single coalesced touch event. However, it also keeps | 
|   16 // track of all the original touch-events that were coalesced into a single |   16 // track of all the original touch-events that were coalesced into a single | 
|   17 // event. The coalesced event is forwarded to the renderer, while the original |   17 // event. The coalesced event is forwarded to the renderer, while the original | 
|   18 // touch-events are sent to the Client (on ACK for the coalesced event) so that |   18 // touch-events are sent to the Client (on ACK for the coalesced event) so that | 
|   19 // the Client receives the event with their original timestamp. |   19 // the Client receives the event with their original timestamp. | 
|   20 class CoalescedWebTouchEvent { |   20 class CoalescedWebTouchEvent { | 
|   21  public: |   21  public: | 
|   22   explicit CoalescedWebTouchEvent(const TouchEventWithLatencyInfo& event) |   22   explicit CoalescedWebTouchEvent(const TouchEventWithLatencyInfo& event) | 
|   23       : coalesced_event_(event) { |   23       : coalesced_event_(event), | 
 |   24         ignore_ack_(false) { | 
|   24     events_.push_back(event); |   25     events_.push_back(event); | 
|   25     TRACE_EVENT_ASYNC_BEGIN0( |   26     TRACE_EVENT_ASYNC_BEGIN0( | 
|   26         "input", "TouchEventQueue::QueueEvent", this); |   27         "input", "TouchEventQueue::QueueEvent", this); | 
|   27   } |   28   } | 
|   28  |   29  | 
|   29   ~CoalescedWebTouchEvent() { |   30   ~CoalescedWebTouchEvent() { | 
|   30     TRACE_EVENT_ASYNC_END0( |   31     TRACE_EVENT_ASYNC_END0( | 
|   31         "input", "TouchEventQueue::QueueEvent", this); |   32         "input", "TouchEventQueue::QueueEvent", this); | 
|   32   } |   33   } | 
|   33  |   34  | 
|   34   // Coalesces the event with the existing event if possible. Returns whether |   35   // Coalesces the event with the existing event if possible. Returns whether | 
|   35   // the event was coalesced. |   36   // the event was coalesced. | 
|   36   bool CoalesceEventIfPossible( |   37   bool CoalesceEventIfPossible( | 
|   37       const TouchEventWithLatencyInfo& event_with_latency) { |   38       const TouchEventWithLatencyInfo& event_with_latency) { | 
|   38     if (coalesced_event_.event.type == WebKit::WebInputEvent::TouchMove && |   39     if (coalesced_event_.event.type == WebKit::WebInputEvent::TouchMove && | 
|   39         event_with_latency.event.type == WebKit::WebInputEvent::TouchMove && |   40         event_with_latency.event.type == WebKit::WebInputEvent::TouchMove && | 
|   40         coalesced_event_.event.modifiers == |   41         coalesced_event_.event.modifiers == | 
|   41         event_with_latency.event.modifiers && |   42         event_with_latency.event.modifiers && | 
|   42         coalesced_event_.event.touchesLength == |   43         coalesced_event_.event.touchesLength == | 
|   43         event_with_latency.event.touchesLength) { |   44         event_with_latency.event.touchesLength && | 
 |   45         !ignore_ack_) { | 
|   44       TRACE_EVENT_INSTANT0( |   46       TRACE_EVENT_INSTANT0( | 
|   45           "input", "TouchEventQueue::MoveCoalesced", TRACE_EVENT_SCOPE_THREAD); |   47           "input", "TouchEventQueue::MoveCoalesced", TRACE_EVENT_SCOPE_THREAD); | 
|   46       events_.push_back(event_with_latency); |   48       events_.push_back(event_with_latency); | 
|   47       // The WebTouchPoints include absolute position information. So it is |   49       // The WebTouchPoints include absolute position information. So it is | 
|   48       // sufficient to simply replace the previous event with the new event. |   50       // sufficient to simply replace the previous event with the new event. | 
|   49       // However, it is necessary to make sure that all the points have the |   51       // However, it is necessary to make sure that all the points have the | 
|   50       // correct state, i.e. the touch-points that moved in the last event, but |   52       // correct state, i.e. the touch-points that moved in the last event, but | 
|   51       // didn't change in the current event, will have Stationary state. It is |   53       // didn't change in the current event, will have Stationary state. It is | 
|   52       // necessary to change them back to Moved state. |   54       // necessary to change them back to Moved state. | 
|   53       const WebKit::WebTouchEvent last_event = coalesced_event_.event; |   55       const WebKit::WebTouchEvent last_event = coalesced_event_.event; | 
| (...skipping 18 matching lines...) Expand all  Loading... | 
|   72   WebTouchEventWithLatencyList::const_iterator begin() const { |   74   WebTouchEventWithLatencyList::const_iterator begin() const { | 
|   73     return events_.begin(); |   75     return events_.begin(); | 
|   74   } |   76   } | 
|   75  |   77  | 
|   76   WebTouchEventWithLatencyList::const_iterator end() const { |   78   WebTouchEventWithLatencyList::const_iterator end() const { | 
|   77     return events_.end(); |   79     return events_.end(); | 
|   78   } |   80   } | 
|   79  |   81  | 
|   80   size_t size() const { return events_.size(); } |   82   size_t size() const { return events_.size(); } | 
|   81  |   83  | 
 |   84   bool ignore_ack() const { return ignore_ack_; } | 
 |   85   void set_ignore_ack(bool value) { ignore_ack_ = value; } | 
 |   86  | 
|   82  private: |   87  private: | 
|   83   // This is the event that is forwarded to the renderer. |   88   // This is the event that is forwarded to the renderer. | 
|   84   TouchEventWithLatencyInfo coalesced_event_; |   89   TouchEventWithLatencyInfo coalesced_event_; | 
|   85  |   90  | 
|   86   // This is the list of the original events that were coalesced. |   91   // This is the list of the original events that were coalesced. | 
|   87   WebTouchEventWithLatencyList events_; |   92   WebTouchEventWithLatencyList events_; | 
|   88  |   93  | 
 |   94   // If |ignore_ack_| is true, don't send this touch event to client | 
 |   95   // when the event is acked. | 
 |   96   bool ignore_ack_; | 
 |   97  | 
|   89   DISALLOW_COPY_AND_ASSIGN(CoalescedWebTouchEvent); |   98   DISALLOW_COPY_AND_ASSIGN(CoalescedWebTouchEvent); | 
|   90 }; |   99 }; | 
|   91  |  100  | 
|   92 TouchEventQueue::TouchEventQueue(TouchEventQueueClient* client) |  101 TouchEventQueue::TouchEventQueue(TouchEventQueueClient* client) | 
|   93     : client_(client), |  102     : client_(client), | 
|   94       dispatching_touch_ack_(false), |  103       dispatching_touch_ack_(NULL), | 
|   95       no_touch_move_to_renderer_(false) { |  104       no_touch_to_renderer_(false) { | 
|   96   DCHECK(client); |  105   DCHECK(client); | 
|   97 } |  106 } | 
|   98  |  107  | 
|   99 TouchEventQueue::~TouchEventQueue() { |  108 TouchEventQueue::~TouchEventQueue() { | 
|  100   if (!touch_queue_.empty()) |  109   if (!touch_queue_.empty()) | 
|  101     STLDeleteElements(&touch_queue_); |  110     STLDeleteElements(&touch_queue_); | 
|  102 } |  111 } | 
|  103  |  112  | 
|  104 void TouchEventQueue::QueueEvent(const TouchEventWithLatencyInfo& event) { |  113 void TouchEventQueue::QueueEvent(const TouchEventWithLatencyInfo& event) { | 
|  105   // If the queueing of |event| was triggered by an ack dispatch, defer |  114   // If the queueing of |event| was triggered by an ack dispatch, defer | 
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|  146       if (point.state == WebKit::WebTouchPoint::StatePressed) |  155       if (point.state == WebKit::WebTouchPoint::StatePressed) | 
|  147         touch_ack_states_[point.id] = ack_result; |  156         touch_ack_states_[point.id] = ack_result; | 
|  148     } |  157     } | 
|  149   } |  158   } | 
|  150  |  159  | 
|  151   PopTouchEventToClient(ack_result, latency_info); |  160   PopTouchEventToClient(ack_result, latency_info); | 
|  152   TryForwardNextEventToRenderer(); |  161   TryForwardNextEventToRenderer(); | 
|  153 } |  162 } | 
|  154  |  163  | 
|  155 void TouchEventQueue::TryForwardNextEventToRenderer() { |  164 void TouchEventQueue::TryForwardNextEventToRenderer() { | 
 |  165   DCHECK(!dispatching_touch_ack_); | 
|  156   // If there are queued touch events, then try to forward them to the renderer |  166   // If there are queued touch events, then try to forward them to the renderer | 
|  157   // immediately, or ACK the events back to the client if appropriate. |  167   // immediately, or ACK the events back to the client if appropriate. | 
|  158   while (!touch_queue_.empty()) { |  168   while (!touch_queue_.empty()) { | 
|  159     const TouchEventWithLatencyInfo& touch = |  169     const TouchEventWithLatencyInfo& touch = | 
|  160         touch_queue_.front()->coalesced_event(); |  170         touch_queue_.front()->coalesced_event(); | 
|  161     if (ShouldForwardToRenderer(touch.event)) { |  171     if (ShouldForwardToRenderer(touch.event)) { | 
|  162       client_->SendTouchEventImmediately(touch); |  172       client_->SendTouchEventImmediately(touch); | 
|  163       break; |  173       break; | 
|  164     } |  174     } | 
|  165     PopTouchEventToClient(INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS, |  175     PopTouchEventToClient(INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS, | 
|  166                           ui::LatencyInfo()); |  176                           ui::LatencyInfo()); | 
|  167   } |  177   } | 
|  168 } |  178 } | 
|  169  |  179  | 
 |  180 void TouchEventQueue::OnGestureScrollEvent( | 
 |  181     const GestureEventWithLatencyInfo& gesture_event) { | 
 |  182   WebKit::WebInputEvent::Type type = gesture_event.event.type; | 
 |  183   if (type == WebKit::WebInputEvent::GestureScrollBegin) { | 
 |  184     // We assume the scroll event are generated synchronously from | 
 |  185     // dispatching a touch event ack, so that we can fake a cancel | 
 |  186     // event that has the correct touch ids as the touch event that | 
 |  187     // is being acked. If not, we don't do the touch-cancel optimization. | 
 |  188     if (no_touch_to_renderer_ || !dispatching_touch_ack_) | 
 |  189       return; | 
 |  190     no_touch_to_renderer_ = true; | 
 |  191     // Fake a TouchCancel to cancel the touch points of the touch event | 
 |  192     // that is currently being acked. | 
 |  193     TouchEventWithLatencyInfo cancel_event = | 
 |  194         dispatching_touch_ack_->coalesced_event(); | 
 |  195     cancel_event.event.type = WebKit::WebInputEvent::TouchCancel; | 
 |  196     for (size_t i = 0; i < cancel_event.event.touchesLength; i++) | 
 |  197       cancel_event.event.touches[i].state = | 
 |  198           WebKit::WebTouchPoint::StateCancelled; | 
 |  199     CoalescedWebTouchEvent* coalesced_cancel_event = | 
 |  200         new CoalescedWebTouchEvent(cancel_event); | 
 |  201     // Ignore the ack of the touch cancel so when it is acked, it won't get | 
 |  202     // sent to gesture recognizer. | 
 |  203     coalesced_cancel_event->set_ignore_ack(true); | 
 |  204     // |dispatching_touch_ack_| is non-null when we reach here, meaning we | 
 |  205     // are in the scope of PopTouchEventToClient() and that no touch event | 
 |  206     // in the queue is waiting for ack from renderer. So we can just insert | 
 |  207     // the touch cancel at the beginning of the queue. | 
 |  208     touch_queue_.push_front(coalesced_cancel_event); | 
 |  209   } else if (type == WebKit::WebInputEvent::GestureScrollEnd || | 
 |  210              type == WebKit::WebInputEvent::GestureFlingStart) { | 
 |  211     no_touch_to_renderer_ = false; | 
 |  212   } | 
 |  213 } | 
 |  214  | 
|  170 void TouchEventQueue::FlushQueue() { |  215 void TouchEventQueue::FlushQueue() { | 
|  171   DCHECK(!dispatching_touch_ack_); |  216   DCHECK(!dispatching_touch_ack_); | 
|  172   while (!touch_queue_.empty()) |  217   while (!touch_queue_.empty()) | 
|  173     PopTouchEventToClient(INPUT_EVENT_ACK_STATE_NOT_CONSUMED, |  218     PopTouchEventToClient(INPUT_EVENT_ACK_STATE_NOT_CONSUMED, | 
|  174                           ui::LatencyInfo()); |  219                           ui::LatencyInfo()); | 
|  175 } |  220 } | 
|  176  |  221  | 
|  177 size_t TouchEventQueue::GetQueueSize() const { |  222 size_t TouchEventQueue::GetQueueSize() const { | 
|  178   return touch_queue_.size(); |  223   return touch_queue_.size(); | 
|  179 } |  224 } | 
|  180  |  225  | 
|  181 const TouchEventWithLatencyInfo& TouchEventQueue::GetLatestEvent() const { |  226 const TouchEventWithLatencyInfo& TouchEventQueue::GetLatestEvent() const { | 
|  182   return touch_queue_.back()->coalesced_event(); |  227   return touch_queue_.back()->coalesced_event(); | 
|  183 } |  228 } | 
|  184  |  229  | 
|  185 void TouchEventQueue::PopTouchEventToClient( |  230 void TouchEventQueue::PopTouchEventToClient( | 
|  186     InputEventAckState ack_result, |  231     InputEventAckState ack_result, | 
|  187     const ui::LatencyInfo& renderer_latency_info) { |  232     const ui::LatencyInfo& renderer_latency_info) { | 
|  188   if (touch_queue_.empty()) |  233   if (touch_queue_.empty()) | 
|  189     return; |  234     return; | 
|  190   scoped_ptr<CoalescedWebTouchEvent> acked_event(touch_queue_.front()); |  235   scoped_ptr<CoalescedWebTouchEvent> acked_event(touch_queue_.front()); | 
|  191   touch_queue_.pop_front(); |  236   touch_queue_.pop_front(); | 
|  192  |  237  | 
 |  238   if (acked_event->ignore_ack()) | 
 |  239     return; | 
 |  240  | 
|  193   // Note that acking the touch-event may result in multiple gestures being sent |  241   // Note that acking the touch-event may result in multiple gestures being sent | 
|  194   // to the renderer, or touch-events being queued. |  242   // to the renderer, or touch-events being queued. | 
|  195   base::AutoReset<bool> dispatching_touch_ack(&dispatching_touch_ack_, true); |  243   base::AutoReset<CoalescedWebTouchEvent*> | 
 |  244       dispatching_touch_ack(&dispatching_touch_ack_, acked_event.get()); | 
|  196  |  245  | 
|  197   base::TimeTicks now = base::TimeTicks::HighResNow(); |  246   base::TimeTicks now = base::TimeTicks::HighResNow(); | 
|  198   for (WebTouchEventWithLatencyList::const_iterator iter = acked_event->begin(), |  247   for (WebTouchEventWithLatencyList::const_iterator iter = acked_event->begin(), | 
|  199        end = acked_event->end(); |  248        end = acked_event->end(); | 
|  200        iter != end; ++iter) { |  249        iter != end; ++iter) { | 
|  201     ui::LatencyInfo* latency = const_cast<ui::LatencyInfo*>(&(iter->latency)); |  250     ui::LatencyInfo* latency = const_cast<ui::LatencyInfo*>(&(iter->latency)); | 
|  202     latency->AddNewLatencyFrom(renderer_latency_info); |  251     latency->AddNewLatencyFrom(renderer_latency_info); | 
|  203     latency->AddLatencyNumberWithTimestamp( |  252     latency->AddLatencyNumberWithTimestamp( | 
|  204         ui::INPUT_EVENT_LATENCY_ACKED_COMPONENT, 0, 0, now, 1); |  253         ui::INPUT_EVENT_LATENCY_ACKED_COMPONENT, 0, 0, now, 1); | 
|  205     client_->OnTouchEventAck((*iter), ack_result); |  254     client_->OnTouchEventAck((*iter), ack_result); | 
|  206   } |  255   } | 
|  207 } |  256 } | 
|  208  |  257  | 
|  209 bool TouchEventQueue::ShouldForwardToRenderer( |  258 bool TouchEventQueue::ShouldForwardToRenderer( | 
|  210     const WebKit::WebTouchEvent& event) const { |  259     const WebKit::WebTouchEvent& event) const { | 
 |  260   if (no_touch_to_renderer_ && | 
 |  261       event.type != WebKit::WebInputEvent::TouchCancel) | 
 |  262     return false; | 
 |  263  | 
|  211   // Touch press events should always be forwarded to the renderer. |  264   // Touch press events should always be forwarded to the renderer. | 
|  212   if (event.type == WebKit::WebInputEvent::TouchStart) |  265   if (event.type == WebKit::WebInputEvent::TouchStart) | 
|  213     return true; |  266     return true; | 
|  214  |  267  | 
|  215   if (event.type == WebKit::WebInputEvent::TouchMove && |  | 
|  216       no_touch_move_to_renderer_) |  | 
|  217     return false; |  | 
|  218  |  | 
|  219   for (unsigned int i = 0; i < event.touchesLength; ++i) { |  268   for (unsigned int i = 0; i < event.touchesLength; ++i) { | 
|  220     const WebKit::WebTouchPoint& point = event.touches[i]; |  269     const WebKit::WebTouchPoint& point = event.touches[i]; | 
|  221     // If a point has been stationary, then don't take it into account. |  270     // If a point has been stationary, then don't take it into account. | 
|  222     if (point.state == WebKit::WebTouchPoint::StateStationary) |  271     if (point.state == WebKit::WebTouchPoint::StateStationary) | 
|  223       continue; |  272       continue; | 
|  224  |  273  | 
|  225     if (touch_ack_states_.count(point.id) > 0) { |  274     if (touch_ack_states_.count(point.id) > 0) { | 
|  226       if (touch_ack_states_.find(point.id)->second != |  275       if (touch_ack_states_.find(point.id)->second != | 
|  227           INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS) |  276           INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS) | 
|  228         return true; |  277         return true; | 
|  229     } else { |  278     } else { | 
|  230       // If the ACK status of a point is unknown, then the event should be |  279       // If the ACK status of a point is unknown, then the event should be | 
|  231       // forwarded to the renderer. |  280       // forwarded to the renderer. | 
|  232       return true; |  281       return true; | 
|  233     } |  282     } | 
|  234   } |  283   } | 
|  235  |  284  | 
|  236   return false; |  285   return false; | 
|  237 } |  286 } | 
|  238  |  287  | 
|  239 }  // namespace content |  288 }  // namespace content | 
| OLD | NEW |