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/command_line.h" |
| 9 #include "base/debug/trace_event.h" | 9 #include "base/debug/trace_event.h" |
| 10 #include "base/stl_util.h" | 10 #include "base/stl_util.h" |
| (...skipping 222 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 233 bool ignore_ack_; | 233 bool ignore_ack_; |
| 234 | 234 |
| 235 DISALLOW_COPY_AND_ASSIGN(CoalescedWebTouchEvent); | 235 DISALLOW_COPY_AND_ASSIGN(CoalescedWebTouchEvent); |
| 236 }; | 236 }; |
| 237 | 237 |
| 238 TouchEventQueue::TouchEventQueue(TouchEventQueueClient* client) | 238 TouchEventQueue::TouchEventQueue(TouchEventQueueClient* client) |
| 239 : client_(client), | 239 : client_(client), |
| 240 dispatching_touch_ack_(NULL), | 240 dispatching_touch_ack_(NULL), |
| 241 dispatching_touch_(false), | 241 dispatching_touch_(false), |
| 242 touch_filtering_state_(TOUCH_FILTERING_STATE_DEFAULT), | 242 touch_filtering_state_(TOUCH_FILTERING_STATE_DEFAULT), |
| 243 ack_timeout_enabled_(false) { | 243 ack_timeout_enabled_(false), |
| 244 touch_scrolling_mode_(GetTouchScrollingMode()), | |
| 245 absorbing_touch_moves_(false) { | |
| 244 DCHECK(client); | 246 DCHECK(client); |
| 245 } | 247 } |
| 246 | 248 |
| 247 TouchEventQueue::~TouchEventQueue() { | 249 TouchEventQueue::~TouchEventQueue() { |
| 248 if (!touch_queue_.empty()) | 250 if (!touch_queue_.empty()) |
| 249 STLDeleteElements(&touch_queue_); | 251 STLDeleteElements(&touch_queue_); |
| 250 } | 252 } |
| 251 | 253 |
| 252 void TouchEventQueue::QueueEvent(const TouchEventWithLatencyInfo& event) { | 254 void TouchEventQueue::QueueEvent(const TouchEventWithLatencyInfo& event) { |
| 253 // If the queueing of |event| was triggered by an ack dispatch, defer | 255 // If the queueing of |event| was triggered by an ack dispatch, defer |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 319 void TouchEventQueue::ForwardToRenderer( | 321 void TouchEventQueue::ForwardToRenderer( |
| 320 const TouchEventWithLatencyInfo& touch) { | 322 const TouchEventWithLatencyInfo& touch) { |
| 321 DCHECK(!dispatching_touch_); | 323 DCHECK(!dispatching_touch_); |
| 322 DCHECK_NE(touch_filtering_state_, DROP_ALL_TOUCHES); | 324 DCHECK_NE(touch_filtering_state_, DROP_ALL_TOUCHES); |
| 323 | 325 |
| 324 if (IsNewTouchSequence(touch.event)) { | 326 if (IsNewTouchSequence(touch.event)) { |
| 325 touch_filtering_state_ = | 327 touch_filtering_state_ = |
| 326 ack_timeout_enabled_ ? FORWARD_TOUCHES_UNTIL_TIMEOUT | 328 ack_timeout_enabled_ ? FORWARD_TOUCHES_UNTIL_TIMEOUT |
| 327 : FORWARD_ALL_TOUCHES; | 329 : FORWARD_ALL_TOUCHES; |
| 328 touch_ack_states_.clear(); | 330 touch_ack_states_.clear(); |
| 331 absorbing_touch_moves_ = false; | |
| 329 } | 332 } |
| 330 | 333 |
| 331 // A synchronous ack will reset |dispatching_touch_|, in which case | 334 // A synchronous ack will reset |dispatching_touch_|, in which case |
| 332 // the touch timeout should not be started. | 335 // the touch timeout should not be started. |
| 333 base::AutoReset<bool> dispatching_touch(&dispatching_touch_, true); | 336 base::AutoReset<bool> dispatching_touch(&dispatching_touch_, true); |
| 334 client_->SendTouchEventImmediately(touch); | 337 client_->SendTouchEventImmediately(touch); |
| 335 if (dispatching_touch_ && | 338 if (dispatching_touch_ && |
| 336 touch_filtering_state_ == FORWARD_TOUCHES_UNTIL_TIMEOUT && | 339 touch_filtering_state_ == FORWARD_TOUCHES_UNTIL_TIMEOUT && |
| 337 ShouldTouchTypeTriggerTimeout(touch.event.type)) { | 340 ShouldTouchTypeTriggerTimeout(touch.event.type)) { |
| 338 DCHECK(timeout_handler_); | 341 DCHECK(timeout_handler_); |
| 339 timeout_handler_->Start(touch); | 342 timeout_handler_->Start(touch); |
| 340 } | 343 } |
| 341 } | 344 } |
| 342 | 345 |
| 343 void TouchEventQueue::OnGestureScrollEvent( | 346 void TouchEventQueue::OnGestureScrollEvent( |
| 344 const GestureEventWithLatencyInfo& gesture_event) { | 347 const GestureEventWithLatencyInfo& gesture_event) { |
| 345 if (gesture_event.event.type != blink::WebInputEvent::GestureScrollBegin) | 348 if (gesture_event.event.type != blink::WebInputEvent::GestureScrollBegin) |
| 346 return; | 349 return; |
| 347 | 350 |
| 351 if (touch_scrolling_mode_ != TOUCH_SCROLLING_MODE_TOUCHCANCEL) | |
| 352 return; | |
| 353 | |
| 348 // We assume that scroll events are generated synchronously from | 354 // We assume that scroll events are generated synchronously from |
| 349 // dispatching a touch event ack. This allows us to generate a synthetic | 355 // dispatching a touch event ack. This allows us to generate a synthetic |
| 350 // cancel event that has the same touch ids as the touch event that | 356 // cancel event that has the same touch ids as the touch event that |
| 351 // is being acked. Otherwise, we don't perform the touch-cancel optimization. | 357 // is being acked. Otherwise, we don't perform the touch-cancel optimization. |
| 352 if (!dispatching_touch_ack_) | 358 if (!dispatching_touch_ack_) |
| 353 return; | 359 return; |
| 354 | 360 |
| 355 if (touch_filtering_state_ == DROP_TOUCHES_IN_SEQUENCE) | 361 if (touch_filtering_state_ == DROP_TOUCHES_IN_SEQUENCE) |
| 356 return; | 362 return; |
| 357 | 363 |
| 358 touch_filtering_state_ = DROP_TOUCHES_IN_SEQUENCE; | 364 touch_filtering_state_ = DROP_TOUCHES_IN_SEQUENCE; |
| 359 | 365 |
| 360 // Fake a TouchCancel to cancel the touch points of the touch event | 366 // Fake a TouchCancel to cancel the touch points of the touch event |
| 361 // that is currently being acked. | 367 // that is currently being acked. |
| 362 // Note: |dispatching_touch_ack_| is non-null when we reach here, meaning we | 368 // Note: |dispatching_touch_ack_| is non-null when we reach here, meaning we |
| 363 // are in the scope of PopTouchEventToClient() and that no touch event | 369 // are in the scope of PopTouchEventToClient() and that no touch event |
| 364 // in the queue is waiting for ack from renderer. So we can just insert | 370 // in the queue is waiting for ack from renderer. So we can just insert |
| 365 // the touch cancel at the beginning of the queue. | 371 // the touch cancel at the beginning of the queue. |
| 366 touch_queue_.push_front(new CoalescedWebTouchEvent( | 372 touch_queue_.push_front(new CoalescedWebTouchEvent( |
| 367 ObtainCancelEventForTouchEvent( | 373 ObtainCancelEventForTouchEvent( |
| 368 dispatching_touch_ack_->coalesced_event()), true)); | 374 dispatching_touch_ack_->coalesced_event()), true)); |
| 369 } | 375 } |
| 370 | 376 |
| 377 void TouchEventQueue::OnGestureEventAck( | |
| 378 const GestureEventWithLatencyInfo& event, | |
| 379 InputEventAckState ack_result) { | |
| 380 if (touch_scrolling_mode_ != TOUCH_SCROLLING_MODE_ABSORB_TOUCHMOVE) | |
|
jdduke (slow)
2014/01/31 20:01:16
Could this be racy? If the GSU ack is delayed? Or
Rick Byers
2014/02/01 23:09:34
Yes, this could be racy. I was thinking it was OK
| |
| 381 return; | |
| 382 | |
| 383 if (event.event.type != blink::WebInputEvent::GestureScrollUpdate) | |
| 384 return; | |
| 385 | |
| 386 // Suspend sending touchmove events as long as the scroll events are handled. | |
| 387 absorbing_touch_moves_ = (ack_result == INPUT_EVENT_ACK_STATE_CONSUMED); | |
| 388 } | |
| 389 | |
| 371 void TouchEventQueue::OnHasTouchEventHandlers(bool has_handlers) { | 390 void TouchEventQueue::OnHasTouchEventHandlers(bool has_handlers) { |
| 372 DCHECK(!dispatching_touch_ack_); | 391 DCHECK(!dispatching_touch_ack_); |
| 373 DCHECK(!dispatching_touch_); | 392 DCHECK(!dispatching_touch_); |
| 374 | 393 |
| 375 if (has_handlers) { | 394 if (has_handlers) { |
| 376 if (touch_filtering_state_ == DROP_ALL_TOUCHES) { | 395 if (touch_filtering_state_ == DROP_ALL_TOUCHES) { |
| 377 // If no touch handler was previously registered, ensure that we don't | 396 // If no touch handler was previously registered, ensure that we don't |
| 378 // send a partial touch sequence to the renderer. | 397 // send a partial touch sequence to the renderer. |
| 379 DCHECK(touch_queue_.empty()); | 398 DCHECK(touch_queue_.empty()); |
| 380 touch_filtering_state_ = DROP_TOUCHES_IN_SEQUENCE; | 399 touch_filtering_state_ = DROP_TOUCHES_IN_SEQUENCE; |
| (...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 471 if (touch_filtering_state_ == DROP_ALL_TOUCHES) | 490 if (touch_filtering_state_ == DROP_ALL_TOUCHES) |
| 472 return false; | 491 return false; |
| 473 | 492 |
| 474 if (touch_filtering_state_ == DROP_TOUCHES_IN_SEQUENCE && | 493 if (touch_filtering_state_ == DROP_TOUCHES_IN_SEQUENCE && |
| 475 event.type != WebInputEvent::TouchCancel) { | 494 event.type != WebInputEvent::TouchCancel) { |
| 476 if (IsNewTouchSequence(event)) | 495 if (IsNewTouchSequence(event)) |
| 477 return true; | 496 return true; |
| 478 return false; | 497 return false; |
| 479 } | 498 } |
| 480 | 499 |
| 500 if (absorbing_touch_moves_ && event.type == WebInputEvent::TouchMove) | |
| 501 return false; | |
| 502 | |
| 481 // Touch press events should always be forwarded to the renderer. | 503 // Touch press events should always be forwarded to the renderer. |
| 482 if (event.type == WebInputEvent::TouchStart) | 504 if (event.type == WebInputEvent::TouchStart) |
| 483 return true; | 505 return true; |
| 484 | 506 |
| 485 for (unsigned int i = 0; i < event.touchesLength; ++i) { | 507 for (unsigned int i = 0; i < event.touchesLength; ++i) { |
| 486 const WebTouchPoint& point = event.touches[i]; | 508 const WebTouchPoint& point = event.touches[i]; |
| 487 // If a point has been stationary, then don't take it into account. | 509 // If a point has been stationary, then don't take it into account. |
| 488 if (point.state == WebTouchPoint::StateStationary) | 510 if (point.state == WebTouchPoint::StateStationary) |
| 489 continue; | 511 continue; |
| 490 | 512 |
| (...skipping 25 matching lines...) Expand all Loading... | |
| 516 } | 538 } |
| 517 } else if (event.type == WebInputEvent::TouchStart) { | 539 } else if (event.type == WebInputEvent::TouchStart) { |
| 518 for (unsigned i = 0; i < event.touchesLength; ++i) { | 540 for (unsigned i = 0; i < event.touchesLength; ++i) { |
| 519 const WebTouchPoint& point = event.touches[i]; | 541 const WebTouchPoint& point = event.touches[i]; |
| 520 if (point.state == WebTouchPoint::StatePressed) | 542 if (point.state == WebTouchPoint::StatePressed) |
| 521 touch_ack_states_[point.id] = ack_result; | 543 touch_ack_states_[point.id] = ack_result; |
| 522 } | 544 } |
| 523 } | 545 } |
| 524 } | 546 } |
| 525 | 547 |
| 548 // static | |
| 549 TouchEventQueue::TouchScrollingMode TouchEventQueue::GetTouchScrollingMode() | |
|
jdduke (slow)
2014/01/31 20:01:16
Any reason not to just put this in the anon namesp
Rick Byers
2014/02/01 23:09:34
Done.
| |
| 550 { | |
| 551 std::string modeString = CommandLine::ForCurrentProcess()-> | |
| 552 GetSwitchValueASCII(switches::kTouchScrollingMode); | |
| 553 if (modeString == switches::kTouchScrollingModeSyncTouchmove) | |
| 554 return TOUCH_SCROLLING_MODE_SYNC_TOUCHMOVE; | |
| 555 if (modeString == switches::kTouchScrollingModeAbsorbTouchmove) | |
| 556 return TOUCH_SCROLLING_MODE_ABSORB_TOUCHMOVE; | |
| 557 if (modeString != "" && | |
| 558 modeString != switches::kTouchScrollingModeTouchcancel) | |
| 559 LOG(ERROR) << "Invalid --touch-scrolling-mode option: " << modeString; | |
| 560 return TOUCH_SCROLLING_MODE_TOUCHCANCEL; | |
| 561 } | |
| 562 | |
| 563 | |
| 526 } // namespace content | 564 } // namespace content |
| OLD | NEW |