Chromium Code Reviews| 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/command_line.h" | |
| 8 #include "base/debug/trace_event.h" | 9 #include "base/debug/trace_event.h" |
| 9 #include "base/stl_util.h" | 10 #include "base/stl_util.h" |
| 11 #include "content/browser/renderer_host/input/timeout_monitor.h" | |
| 12 #include "content/common/input/web_input_event_traits.h" | |
| 13 #include "content/public/common/content_switches.h" | |
| 14 | |
| 15 using blink::WebInputEvent; | |
| 16 using blink::WebTouchEvent; | |
| 17 using blink::WebTouchPoint; | |
| 10 | 18 |
| 11 namespace content { | 19 namespace content { |
| 20 namespace { | |
| 21 | |
| 22 const InputEventAckState kDefaultNotForwardedAck = | |
| 23 INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS; | |
| 12 | 24 |
| 13 typedef std::vector<TouchEventWithLatencyInfo> WebTouchEventWithLatencyList; | 25 typedef std::vector<TouchEventWithLatencyInfo> WebTouchEventWithLatencyList; |
| 26 typedef std::map<int, InputEventAckState> AckStates; | |
|
sadrul
2013/12/06 07:35:18
This isn't used anywhere?
jdduke (slow)
2013/12/06 17:17:20
Done.
| |
| 27 | |
| 28 TouchEventWithLatencyInfo ObtainCancelEventForTouchEvent( | |
| 29 const TouchEventWithLatencyInfo& event_to_cancel) { | |
| 30 TouchEventWithLatencyInfo event = event_to_cancel; | |
| 31 event.event.type = WebInputEvent::TouchCancel; | |
| 32 for (size_t i = 0; i < event.event.touchesLength; i++) | |
| 33 event.event.touches[i].state = WebTouchPoint::StateCancelled; | |
| 34 return event; | |
| 35 } | |
| 36 | |
| 37 } // namespace | |
| 38 | |
| 39 class TouchEventQueue::TouchTimeoutHandler { | |
| 40 public: | |
| 41 TouchTimeoutHandler(TouchEventQueue* touch_queue, size_t timeout_delay_ms) | |
| 42 : touch_queue_(touch_queue), | |
| 43 timeout_delay_(base::TimeDelta::FromMilliseconds(timeout_delay_ms)), | |
| 44 pending_ack_state_(PENDING_ACK_NONE), | |
| 45 timeout_monitor_(base::Bind(&TouchTimeoutHandler::OnTimeOut, | |
| 46 base::Unretained(this))) {} | |
| 47 | |
| 48 ~TouchTimeoutHandler() {} | |
| 49 | |
| 50 void Start(const TouchEventWithLatencyInfo& event) { | |
| 51 DCHECK_EQ(pending_ack_state_, PENDING_ACK_NONE); | |
| 52 DCHECK(event.event.type == WebInputEvent::TouchStart || | |
| 53 event.event.type == WebInputEvent::TouchMove); | |
| 54 timeout_event_ = event; | |
| 55 timeout_monitor_.Restart(timeout_delay_); | |
| 56 } | |
| 57 | |
| 58 bool ConfirmTouchEvent(InputEventAckState ack_result) { | |
| 59 switch (pending_ack_state_) { | |
| 60 case PENDING_ACK_NONE: | |
| 61 timeout_monitor_.Stop(); | |
| 62 return false; | |
| 63 case PENDING_ACK_ORIGINAL_EVENT: | |
| 64 if (AckedTimeoutEventRequiresCancel(ack_result)) { | |
| 65 SetPendingAckState(PENDING_ACK_CANCEL_EVENT); | |
| 66 TouchEventWithLatencyInfo cancel_event = | |
| 67 ObtainCancelEventForTouchEvent(timeout_event_); | |
| 68 touch_queue_->UpdateTouchAckStates( | |
| 69 cancel_event.event, kDefaultNotForwardedAck); | |
| 70 touch_queue_->client_->SendTouchEventImmediately(cancel_event); | |
| 71 } else { | |
| 72 SetPendingAckState(PENDING_ACK_NONE); | |
| 73 touch_queue_->UpdateTouchAckStates(timeout_event_.event, ack_result); | |
| 74 } | |
| 75 return true; | |
| 76 case PENDING_ACK_CANCEL_EVENT: | |
| 77 SetPendingAckState(PENDING_ACK_NONE); | |
| 78 return true; | |
| 79 } | |
| 80 return false; | |
| 81 } | |
| 82 | |
| 83 bool HasTimeoutEvent() const { | |
| 84 return pending_ack_state_ != PENDING_ACK_NONE; | |
| 85 } | |
| 86 | |
| 87 bool IsTimeoutTimerRunning() const { | |
| 88 return timeout_monitor_.IsRunning(); | |
| 89 } | |
| 90 | |
| 91 private: | |
| 92 enum PendingAckState { | |
| 93 PENDING_ACK_NONE, | |
| 94 PENDING_ACK_ORIGINAL_EVENT, | |
| 95 PENDING_ACK_CANCEL_EVENT, | |
| 96 }; | |
| 97 | |
| 98 void OnTimeOut() { | |
| 99 SetPendingAckState(PENDING_ACK_ORIGINAL_EVENT); | |
| 100 touch_queue_->FlushQueue(); | |
| 101 } | |
| 102 | |
| 103 // Skip a cancel event if the timed-out event had no consumer. | |
| 104 bool AckedTimeoutEventRequiresCancel(InputEventAckState ack_result) const { | |
| 105 DCHECK(HasTimeoutEvent()); | |
| 106 if (ack_result != INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS) | |
| 107 return true; | |
| 108 if (timeout_event_.event.type != WebInputEvent::TouchStart) | |
| 109 return true; | |
| 110 for (unsigned i = 0; i < timeout_event_.event.touchesLength; ++i) { | |
| 111 const WebTouchPoint& point = timeout_event_.event.touches[i]; | |
| 112 if (point.state != WebTouchPoint::StatePressed) | |
| 113 return true; | |
| 114 } | |
| 115 return false; | |
| 116 } | |
| 117 | |
| 118 void SetPendingAckState(PendingAckState new_pending_ack_state) { | |
| 119 DCHECK_NE(pending_ack_state_, new_pending_ack_state); | |
| 120 switch (new_pending_ack_state) { | |
| 121 case PENDING_ACK_ORIGINAL_EVENT: | |
| 122 DCHECK_EQ(pending_ack_state_, PENDING_ACK_NONE); | |
| 123 TRACE_EVENT_ASYNC_BEGIN0("input", "TouchEventTimeout", this); | |
| 124 break; | |
| 125 case PENDING_ACK_CANCEL_EVENT: | |
| 126 DCHECK_EQ(pending_ack_state_, PENDING_ACK_ORIGINAL_EVENT); | |
| 127 DCHECK(!timeout_monitor_.IsRunning()); | |
| 128 DCHECK(touch_queue_->empty()); | |
| 129 TRACE_EVENT_ASYNC_STEP_INTO0( | |
| 130 "input", "TouchEventTimeout", this, "CancelEvent"); | |
| 131 break; | |
| 132 case PENDING_ACK_NONE: | |
| 133 DCHECK(!timeout_monitor_.IsRunning()); | |
| 134 DCHECK(touch_queue_->empty()); | |
| 135 TRACE_EVENT_ASYNC_END0("input", "TouchEventTimeout", this); | |
| 136 break; | |
| 137 } | |
| 138 pending_ack_state_ = new_pending_ack_state; | |
| 139 } | |
| 140 | |
| 141 | |
| 142 TouchEventQueue* touch_queue_; | |
| 143 | |
| 144 // How long to wait on a touch ack before cancelling the touch sequence. | |
| 145 base::TimeDelta timeout_delay_; | |
| 146 | |
| 147 // The touch event source for which we expect the next ack. | |
| 148 PendingAckState pending_ack_state_; | |
| 149 | |
| 150 // The event for which the ack timeout is triggered. | |
| 151 TouchEventWithLatencyInfo timeout_event_; | |
| 152 | |
| 153 // Provides timeout-based callback behavior. | |
| 154 TimeoutMonitor timeout_monitor_; | |
| 155 }; | |
| 156 | |
| 14 | 157 |
| 15 // This class represents a single coalesced touch event. However, it also keeps | 158 // 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 | 159 // 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 | 160 // 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 | 161 // 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. | 162 // the Client receives the event with their original timestamp. |
| 20 class CoalescedWebTouchEvent { | 163 class CoalescedWebTouchEvent { |
| 21 public: | 164 public: |
| 22 explicit CoalescedWebTouchEvent(const TouchEventWithLatencyInfo& event) | 165 explicit CoalescedWebTouchEvent(const TouchEventWithLatencyInfo& event, |
|
sadrul
2013/12/06 07:35:18
remove explicit
jdduke (slow)
2013/12/06 17:17:20
Done.
| |
| 166 bool ignore_ack) | |
| 23 : coalesced_event_(event), | 167 : coalesced_event_(event), |
| 24 ignore_ack_(false) { | 168 ignore_ack_(ignore_ack) { |
| 25 events_.push_back(event); | 169 events_.push_back(event); |
| 26 TRACE_EVENT_ASYNC_BEGIN0( | 170 TRACE_EVENT_ASYNC_BEGIN0( |
| 27 "input", "TouchEventQueue::QueueEvent", this); | 171 "input", "TouchEventQueue::QueueEvent", this); |
| 28 } | 172 } |
| 29 | 173 |
| 30 ~CoalescedWebTouchEvent() { | 174 ~CoalescedWebTouchEvent() { |
| 31 TRACE_EVENT_ASYNC_END0( | 175 TRACE_EVENT_ASYNC_END0( |
| 32 "input", "TouchEventQueue::QueueEvent", this); | 176 "input", "TouchEventQueue::QueueEvent", this); |
| 33 } | 177 } |
| 34 | 178 |
| (...skipping 22 matching lines...) Expand all Loading... | |
| 57 return events_.begin(); | 201 return events_.begin(); |
| 58 } | 202 } |
| 59 | 203 |
| 60 WebTouchEventWithLatencyList::iterator end() { | 204 WebTouchEventWithLatencyList::iterator end() { |
| 61 return events_.end(); | 205 return events_.end(); |
| 62 } | 206 } |
| 63 | 207 |
| 64 size_t size() const { return events_.size(); } | 208 size_t size() const { return events_.size(); } |
| 65 | 209 |
| 66 bool ignore_ack() const { return ignore_ack_; } | 210 bool ignore_ack() const { return ignore_ack_; } |
| 67 void set_ignore_ack(bool value) { ignore_ack_ = value; } | |
| 68 | 211 |
| 69 private: | 212 private: |
| 70 // This is the event that is forwarded to the renderer. | 213 // This is the event that is forwarded to the renderer. |
| 71 TouchEventWithLatencyInfo coalesced_event_; | 214 TouchEventWithLatencyInfo coalesced_event_; |
| 72 | 215 |
| 73 // This is the list of the original events that were coalesced. | 216 // This is the list of the original events that were coalesced. |
| 74 WebTouchEventWithLatencyList events_; | 217 WebTouchEventWithLatencyList events_; |
| 75 | 218 |
| 76 // If |ignore_ack_| is true, don't send this touch event to client | 219 // If |ignore_ack_| is true, don't send this touch event to client |
| 77 // when the event is acked. | 220 // when the event is acked. |
| 78 bool ignore_ack_; | 221 bool ignore_ack_; |
| 79 | 222 |
| 80 DISALLOW_COPY_AND_ASSIGN(CoalescedWebTouchEvent); | 223 DISALLOW_COPY_AND_ASSIGN(CoalescedWebTouchEvent); |
| 81 }; | 224 }; |
| 82 | 225 |
| 83 TouchEventQueue::TouchEventQueue(TouchEventQueueClient* client) | 226 TouchEventQueue::TouchEventQueue(TouchEventQueueClient* client) |
| 84 : client_(client), | 227 : client_(client), |
| 85 dispatching_touch_ack_(NULL), | 228 dispatching_touch_ack_(NULL), |
| 86 no_touch_to_renderer_(false) { | 229 dispatching_touch_(false), |
| 230 no_touch_to_renderer_(false), | |
| 231 renderer_is_consuming_gesture_(false), | |
| 232 ack_timeout_enabled_(false) { | |
| 87 DCHECK(client); | 233 DCHECK(client); |
| 88 } | 234 } |
| 89 | 235 |
| 90 TouchEventQueue::~TouchEventQueue() { | 236 TouchEventQueue::~TouchEventQueue() { |
| 91 if (!touch_queue_.empty()) | 237 if (!touch_queue_.empty()) |
| 92 STLDeleteElements(&touch_queue_); | 238 STLDeleteElements(&touch_queue_); |
| 93 } | 239 } |
| 94 | 240 |
| 95 void TouchEventQueue::QueueEvent(const TouchEventWithLatencyInfo& event) { | 241 void TouchEventQueue::QueueEvent(const TouchEventWithLatencyInfo& event) { |
| 96 // If the queueing of |event| was triggered by an ack dispatch, defer | 242 // If the queueing of |event| was triggered by an ack dispatch, defer |
| 97 // processing the event until the dispatch has finished. | 243 // processing the event until the dispatch has finished. |
| 98 if (touch_queue_.empty() && !dispatching_touch_ack_) { | 244 if (touch_queue_.empty() && !dispatching_touch_ack_) { |
| 99 // There is no touch event in the queue. Forward it to the renderer | 245 // There is no touch event in the queue. Forward it to the renderer |
| 100 // immediately. | 246 // immediately. |
| 101 touch_queue_.push_back(new CoalescedWebTouchEvent(event)); | 247 touch_queue_.push_back(new CoalescedWebTouchEvent(event, false)); |
| 102 TryForwardNextEventToRenderer(); | 248 TryForwardNextEventToRenderer(); |
| 103 return; | 249 return; |
| 104 } | 250 } |
| 105 | 251 |
| 106 // If the last queued touch-event was a touch-move, and the current event is | 252 // If the last queued touch-event was a touch-move, and the current event is |
| 107 // also a touch-move, then the events can be coalesced into a single event. | 253 // also a touch-move, then the events can be coalesced into a single event. |
| 108 if (touch_queue_.size() > 1) { | 254 if (touch_queue_.size() > 1) { |
| 109 CoalescedWebTouchEvent* last_event = touch_queue_.back(); | 255 CoalescedWebTouchEvent* last_event = touch_queue_.back(); |
| 110 if (last_event->CoalesceEventIfPossible(event)) | 256 if (last_event->CoalesceEventIfPossible(event)) |
| 111 return; | 257 return; |
| 112 } | 258 } |
| 113 touch_queue_.push_back(new CoalescedWebTouchEvent(event)); | 259 touch_queue_.push_back(new CoalescedWebTouchEvent(event, false)); |
| 114 } | 260 } |
| 115 | 261 |
| 116 void TouchEventQueue::ProcessTouchAck(InputEventAckState ack_result, | 262 void TouchEventQueue::ProcessTouchAck(InputEventAckState ack_result, |
| 117 const ui::LatencyInfo& latency_info) { | 263 const ui::LatencyInfo& latency_info) { |
| 118 DCHECK(!dispatching_touch_ack_); | 264 DCHECK(!dispatching_touch_ack_); |
| 265 dispatching_touch_ = false; | |
| 266 | |
| 267 if (timeout_handler_ && timeout_handler_->ConfirmTouchEvent(ack_result)) | |
| 268 return; | |
| 269 | |
| 119 if (touch_queue_.empty()) | 270 if (touch_queue_.empty()) |
| 120 return; | 271 return; |
| 121 | 272 |
| 122 // Update the ACK status for each touch point in the ACKed event. | 273 if (ack_result == INPUT_EVENT_ACK_STATE_CONSUMED) |
| 123 const blink::WebTouchEvent& event = | 274 renderer_is_consuming_gesture_ = true; |
| 275 | |
| 276 const WebTouchEvent& acked_event = | |
| 124 touch_queue_.front()->coalesced_event().event; | 277 touch_queue_.front()->coalesced_event().event; |
| 125 if (event.type == blink::WebInputEvent::TouchEnd || | 278 UpdateTouchAckStates(acked_event, ack_result); |
| 126 event.type == blink::WebInputEvent::TouchCancel) { | |
| 127 // The points have been released. Erase the ACK states. | |
| 128 for (unsigned i = 0; i < event.touchesLength; ++i) { | |
| 129 const blink::WebTouchPoint& point = event.touches[i]; | |
| 130 if (point.state == blink::WebTouchPoint::StateReleased || | |
| 131 point.state == blink::WebTouchPoint::StateCancelled) | |
| 132 touch_ack_states_.erase(point.id); | |
| 133 } | |
| 134 } else if (event.type == blink::WebInputEvent::TouchStart) { | |
| 135 for (unsigned i = 0; i < event.touchesLength; ++i) { | |
| 136 const blink::WebTouchPoint& point = event.touches[i]; | |
| 137 if (point.state == blink::WebTouchPoint::StatePressed) | |
| 138 touch_ack_states_[point.id] = ack_result; | |
| 139 } | |
| 140 } | |
| 141 | |
| 142 PopTouchEventToClient(ack_result, latency_info); | 279 PopTouchEventToClient(ack_result, latency_info); |
| 143 TryForwardNextEventToRenderer(); | 280 TryForwardNextEventToRenderer(); |
| 144 } | 281 } |
| 145 | 282 |
| 146 void TouchEventQueue::TryForwardNextEventToRenderer() { | 283 void TouchEventQueue::TryForwardNextEventToRenderer() { |
| 147 DCHECK(!dispatching_touch_ack_); | 284 DCHECK(!dispatching_touch_ack_); |
| 148 // If there are queued touch events, then try to forward them to the renderer | 285 // If there are queued touch events, then try to forward them to the renderer |
| 149 // immediately, or ACK the events back to the client if appropriate. | 286 // immediately, or ACK the events back to the client if appropriate. |
| 150 while (!touch_queue_.empty()) { | 287 while (!touch_queue_.empty()) { |
| 151 const TouchEventWithLatencyInfo& touch = | 288 const TouchEventWithLatencyInfo& touch = |
| 152 touch_queue_.front()->coalesced_event(); | 289 touch_queue_.front()->coalesced_event(); |
| 290 if (touch.event.type == WebInputEvent::TouchStart) | |
| 291 renderer_is_consuming_gesture_ = false; | |
|
sadrul
2013/12/06 07:35:18
Do you also want to check if touch.event.touchesLe
jdduke (slow)
2013/12/06 17:17:20
Of course! I guess in theory we could get multipl
| |
| 153 if (ShouldForwardToRenderer(touch.event)) { | 292 if (ShouldForwardToRenderer(touch.event)) { |
| 154 client_->SendTouchEventImmediately(touch); | 293 ForwardToRenderer(touch); |
| 155 break; | 294 break; |
| 156 } | 295 } |
| 157 PopTouchEventToClient(INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS, | 296 PopTouchEventToClient(kDefaultNotForwardedAck, ui::LatencyInfo()); |
| 158 ui::LatencyInfo()); | |
| 159 } | 297 } |
| 160 } | 298 } |
| 161 | 299 |
| 300 void TouchEventQueue::ForwardToRenderer( | |
| 301 const TouchEventWithLatencyInfo& touch) { | |
| 302 DCHECK(!dispatching_touch_); | |
| 303 // A synchronous ack will reset |dispatching_touch_|, in which case | |
| 304 // the touch timeout should not be started. | |
| 305 base::AutoReset<bool> dispatching_touch(&dispatching_touch_, true); | |
| 306 client_->SendTouchEventImmediately(touch); | |
| 307 if (ack_timeout_enabled_ && | |
| 308 dispatching_touch_ && | |
| 309 !renderer_is_consuming_gesture_ && | |
| 310 (touch.event.type == WebInputEvent::TouchStart || | |
| 311 touch.event.type == WebInputEvent::TouchMove)) { | |
| 312 DCHECK(timeout_handler_); | |
| 313 timeout_handler_->Start(touch); | |
| 314 } | |
| 315 } | |
| 316 | |
| 162 void TouchEventQueue::OnGestureScrollEvent( | 317 void TouchEventQueue::OnGestureScrollEvent( |
| 163 const GestureEventWithLatencyInfo& gesture_event) { | 318 const GestureEventWithLatencyInfo& gesture_event) { |
| 164 blink::WebInputEvent::Type type = gesture_event.event.type; | 319 blink::WebInputEvent::Type type = gesture_event.event.type; |
| 165 if (type == blink::WebInputEvent::GestureScrollBegin) { | 320 if (type == blink::WebInputEvent::GestureScrollBegin) { |
| 166 // We assume the scroll event are generated synchronously from | 321 // We assume the scroll event are generated synchronously from |
| 167 // dispatching a touch event ack, so that we can fake a cancel | 322 // dispatching a touch event ack, so that we can fake a cancel |
| 168 // event that has the correct touch ids as the touch event that | 323 // event that has the correct touch ids as the touch event that |
| 169 // is being acked. If not, we don't do the touch-cancel optimization. | 324 // is being acked. If not, we don't do the touch-cancel optimization. |
| 170 if (no_touch_to_renderer_ || !dispatching_touch_ack_) | 325 if (no_touch_to_renderer_ || !dispatching_touch_ack_) |
| 171 return; | 326 return; |
| 172 no_touch_to_renderer_ = true; | 327 no_touch_to_renderer_ = true; |
| 328 | |
| 329 // If we have a timeout event, a cancel has already been dispatched | |
| 330 // for the current touch stream. | |
| 331 if (HasTimeoutEvent()) | |
| 332 return; | |
| 333 | |
| 173 // Fake a TouchCancel to cancel the touch points of the touch event | 334 // Fake a TouchCancel to cancel the touch points of the touch event |
| 174 // that is currently being acked. | 335 // that is currently being acked. |
| 175 TouchEventWithLatencyInfo cancel_event = | 336 // Note: |dispatching_touch_ack_| is non-null when we reach here, meaning we |
| 176 dispatching_touch_ack_->coalesced_event(); | |
| 177 cancel_event.event.type = blink::WebInputEvent::TouchCancel; | |
| 178 for (size_t i = 0; i < cancel_event.event.touchesLength; i++) | |
| 179 cancel_event.event.touches[i].state = | |
| 180 blink::WebTouchPoint::StateCancelled; | |
| 181 CoalescedWebTouchEvent* coalesced_cancel_event = | |
| 182 new CoalescedWebTouchEvent(cancel_event); | |
| 183 // Ignore the ack of the touch cancel so when it is acked, it won't get | |
| 184 // sent to gesture recognizer. | |
| 185 coalesced_cancel_event->set_ignore_ack(true); | |
| 186 // |dispatching_touch_ack_| is non-null when we reach here, meaning we | |
| 187 // are in the scope of PopTouchEventToClient() and that no touch event | 337 // are in the scope of PopTouchEventToClient() and that no touch event |
| 188 // in the queue is waiting for ack from renderer. So we can just insert | 338 // in the queue is waiting for ack from renderer. So we can just insert |
| 189 // the touch cancel at the beginning of the queue. | 339 // the touch cancel at the beginning of the queue. |
| 190 touch_queue_.push_front(coalesced_cancel_event); | 340 touch_queue_.push_front(new CoalescedWebTouchEvent( |
| 341 ObtainCancelEventForTouchEvent( | |
| 342 dispatching_touch_ack_->coalesced_event()), true)); | |
| 191 } else if (type == blink::WebInputEvent::GestureScrollEnd || | 343 } else if (type == blink::WebInputEvent::GestureScrollEnd || |
| 192 type == blink::WebInputEvent::GestureFlingStart) { | 344 type == blink::WebInputEvent::GestureFlingStart) { |
| 193 no_touch_to_renderer_ = false; | 345 no_touch_to_renderer_ = false; |
| 194 } | 346 } |
| 195 } | 347 } |
| 196 | 348 |
| 197 void TouchEventQueue::FlushQueue() { | 349 void TouchEventQueue::FlushQueue() { |
| 198 DCHECK(!dispatching_touch_ack_); | 350 DCHECK(!dispatching_touch_ack_); |
| 351 DCHECK(!dispatching_touch_); | |
| 199 while (!touch_queue_.empty()) | 352 while (!touch_queue_.empty()) |
| 200 PopTouchEventToClient(INPUT_EVENT_ACK_STATE_NOT_CONSUMED, | 353 PopTouchEventToClient(kDefaultNotForwardedAck, ui::LatencyInfo()); |
| 201 ui::LatencyInfo()); | |
| 202 } | 354 } |
| 203 | 355 |
| 204 size_t TouchEventQueue::GetQueueSize() const { | 356 void TouchEventQueue::SetAckTimeoutEnabled(bool enabled, |
| 205 return touch_queue_.size(); | 357 size_t ack_timeout_delay_ms) { |
| 358 if (!enabled) { | |
| 359 // Avoid resetting |timeout_handler_|, as an outstanding timeout may | |
| 360 // be active and must be completed for ack handling consistency. | |
| 361 ack_timeout_enabled_ = false; | |
| 362 return; | |
| 363 } | |
| 364 | |
| 365 ack_timeout_enabled_ = true; | |
| 366 if (!timeout_handler_) | |
| 367 timeout_handler_.reset(new TouchTimeoutHandler(this, ack_timeout_delay_ms)); | |
| 206 } | 368 } |
| 207 | 369 |
| 208 const TouchEventWithLatencyInfo& TouchEventQueue::GetLatestEvent() const { | 370 bool TouchEventQueue::HasTimeoutEvent() const { |
| 371 return timeout_handler_ && timeout_handler_->HasTimeoutEvent(); | |
| 372 } | |
| 373 | |
| 374 bool TouchEventQueue::IsTimeoutRunningForTesting() const { | |
| 375 return timeout_handler_ && timeout_handler_->IsTimeoutTimerRunning(); | |
| 376 } | |
| 377 | |
| 378 const TouchEventWithLatencyInfo& | |
| 379 TouchEventQueue::GetLatestEventForTesting() const { | |
| 209 return touch_queue_.back()->coalesced_event(); | 380 return touch_queue_.back()->coalesced_event(); |
| 210 } | 381 } |
| 211 | 382 |
| 212 void TouchEventQueue::PopTouchEventToClient( | 383 void TouchEventQueue::PopTouchEventToClient( |
| 213 InputEventAckState ack_result, | 384 InputEventAckState ack_result, |
| 214 const ui::LatencyInfo& renderer_latency_info) { | 385 const ui::LatencyInfo& renderer_latency_info) { |
| 386 DCHECK(!dispatching_touch_ack_); | |
| 215 if (touch_queue_.empty()) | 387 if (touch_queue_.empty()) |
| 216 return; | 388 return; |
| 217 scoped_ptr<CoalescedWebTouchEvent> acked_event(touch_queue_.front()); | 389 scoped_ptr<CoalescedWebTouchEvent> acked_event(touch_queue_.front()); |
| 218 touch_queue_.pop_front(); | 390 touch_queue_.pop_front(); |
| 219 | 391 |
| 220 if (acked_event->ignore_ack()) | 392 if (acked_event->ignore_ack()) |
| 221 return; | 393 return; |
| 222 | 394 |
| 223 // Note that acking the touch-event may result in multiple gestures being sent | 395 // Note that acking the touch-event may result in multiple gestures being sent |
| 224 // to the renderer, or touch-events being queued. | 396 // to the renderer, or touch-events being queued. |
| 225 base::AutoReset<CoalescedWebTouchEvent*> | 397 base::AutoReset<CoalescedWebTouchEvent*> |
| 226 dispatching_touch_ack(&dispatching_touch_ack_, acked_event.get()); | 398 dispatching_touch_ack(&dispatching_touch_ack_, acked_event.get()); |
| 227 | 399 |
| 228 for (WebTouchEventWithLatencyList::iterator iter = acked_event->begin(), | 400 for (WebTouchEventWithLatencyList::iterator iter = acked_event->begin(), |
| 229 end = acked_event->end(); | 401 end = acked_event->end(); |
| 230 iter != end; ++iter) { | 402 iter != end; ++iter) { |
| 231 iter->latency.AddNewLatencyFrom(renderer_latency_info); | 403 iter->latency.AddNewLatencyFrom(renderer_latency_info); |
| 232 client_->OnTouchEventAck((*iter), ack_result); | 404 client_->OnTouchEventAck((*iter), ack_result); |
| 233 } | 405 } |
| 234 } | 406 } |
| 235 | 407 |
| 236 bool TouchEventQueue::ShouldForwardToRenderer( | 408 bool TouchEventQueue::ShouldForwardToRenderer( |
| 237 const blink::WebTouchEvent& event) const { | 409 const WebTouchEvent& event) const { |
| 410 if (HasTimeoutEvent()) | |
| 411 return false; | |
| 412 | |
| 238 if (no_touch_to_renderer_ && | 413 if (no_touch_to_renderer_ && |
| 239 event.type != blink::WebInputEvent::TouchCancel) | 414 event.type != blink::WebInputEvent::TouchCancel) |
| 240 return false; | 415 return false; |
| 241 | 416 |
| 242 // Touch press events should always be forwarded to the renderer. | 417 // Touch press events should always be forwarded to the renderer. |
| 243 if (event.type == blink::WebInputEvent::TouchStart) | 418 if (event.type == WebInputEvent::TouchStart) |
| 244 return true; | 419 return true; |
| 245 | 420 |
| 246 for (unsigned int i = 0; i < event.touchesLength; ++i) { | 421 for (unsigned int i = 0; i < event.touchesLength; ++i) { |
| 247 const blink::WebTouchPoint& point = event.touches[i]; | 422 const WebTouchPoint& point = event.touches[i]; |
| 248 // If a point has been stationary, then don't take it into account. | 423 // If a point has been stationary, then don't take it into account. |
| 249 if (point.state == blink::WebTouchPoint::StateStationary) | 424 if (point.state == WebTouchPoint::StateStationary) |
| 250 continue; | 425 continue; |
| 251 | 426 |
| 252 if (touch_ack_states_.count(point.id) > 0) { | 427 if (touch_ack_states_.count(point.id) > 0) { |
| 253 if (touch_ack_states_.find(point.id)->second != | 428 if (touch_ack_states_.find(point.id)->second != |
| 254 INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS) | 429 INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS) |
| 255 return true; | 430 return true; |
| 256 } else { | 431 } else { |
| 257 // If the ACK status of a point is unknown, then the event should be | 432 // If the ACK status of a point is unknown, then the event should be |
| 258 // forwarded to the renderer. | 433 // forwarded to the renderer. |
| 259 return true; | 434 return true; |
| 260 } | 435 } |
| 261 } | 436 } |
| 262 | 437 |
| 263 return false; | 438 return false; |
| 264 } | 439 } |
| 265 | 440 |
| 441 void TouchEventQueue::UpdateTouchAckStates(const WebTouchEvent& event, | |
| 442 InputEventAckState ack_result) { | |
| 443 // Update the ACK status for each touch point in the ACKed event. | |
| 444 if (event.type == WebInputEvent::TouchEnd || | |
| 445 event.type == WebInputEvent::TouchCancel) { | |
| 446 // The points have been released. Erase the ACK states. | |
| 447 for (unsigned i = 0; i < event.touchesLength; ++i) { | |
| 448 const WebTouchPoint& point = event.touches[i]; | |
| 449 if (point.state == WebTouchPoint::StateReleased || | |
| 450 point.state == WebTouchPoint::StateCancelled) | |
| 451 touch_ack_states_.erase(point.id); | |
| 452 } | |
| 453 } else if (event.type == WebInputEvent::TouchStart) { | |
| 454 for (unsigned i = 0; i < event.touchesLength; ++i) { | |
| 455 const WebTouchPoint& point = event.touches[i]; | |
| 456 if (point.state == WebTouchPoint::StatePressed) | |
| 457 touch_ack_states_[point.id] = ack_result; | |
| 458 } | |
| 459 } | |
| 460 } | |
| 461 | |
| 266 } // namespace content | 462 } // namespace content |
| OLD | NEW |