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/input_router_impl.h" | 5 #include "content/browser/renderer_host/input/input_router_impl.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/metrics/histogram.h" | 9 #include "base/metrics/histogram.h" |
| 10 #include "base/strings/string_number_conversions.h" | 10 #include "base/strings/string_number_conversions.h" |
| (...skipping 162 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 173 if (mouse_event.event.type == WebInputEvent::MouseUp && | 173 if (mouse_event.event.type == WebInputEvent::MouseUp && |
| 174 gesture_event_queue_.GetTouchpadTapSuppressionController()-> | 174 gesture_event_queue_.GetTouchpadTapSuppressionController()-> |
| 175 ShouldSuppressMouseUp()) | 175 ShouldSuppressMouseUp()) |
| 176 return; | 176 return; |
| 177 | 177 |
| 178 SendMouseEventImmediately(mouse_event); | 178 SendMouseEventImmediately(mouse_event); |
| 179 } | 179 } |
| 180 | 180 |
| 181 void InputRouterImpl::SendWheelEvent( | 181 void InputRouterImpl::SendWheelEvent( |
| 182 const MouseWheelEventWithLatencyInfo& wheel_event) { | 182 const MouseWheelEventWithLatencyInfo& wheel_event) { |
| 183 // If there's already a mouse wheel event waiting to be sent to the renderer, | 183 SendWheelEvent(QueuedWheelEvent(wheel_event, false)); |
| 184 // add the new deltas to that event. Not doing so (e.g., by dropping the old | 184 } |
| 185 // event, as for mouse moves) results in very slow scrolling on the Mac (on | 185 |
| 186 // which many, very small wheel events are sent). | 186 void InputRouterImpl::SendWheelEvent(const QueuedWheelEvent& wheel_event) { |
| 187 if (mouse_wheel_pending_) { | 187 if (mouse_wheel_pending_) { |
| 188 // If there's already a mouse wheel event waiting to be sent to the | |
| 189 // renderer, add the new deltas to that event. Not doing so (e.g., by | |
| 190 // dropping the old event, as for mouse moves) results in very slow | |
| 191 // scrolling on the Mac (on which many, very small wheel events are sent). | |
| 192 // Note that we can't coalesce wheel events for pinches because the GEQ | |
| 193 // expects one ACK for each (but it's fine to coalesce non-pinch wheels | |
| 194 // into a pinch one). Note that the GestureEventQueue ensures we only | |
| 195 // ever have a single pinch event queued here. | |
| 188 if (coalesced_mouse_wheel_events_.empty() || | 196 if (coalesced_mouse_wheel_events_.empty() || |
| 189 !coalesced_mouse_wheel_events_.back().CanCoalesceWith(wheel_event)) { | 197 wheel_event.synthesized_from_pinch || |
| 198 !coalesced_mouse_wheel_events_.back().event.CanCoalesceWith( | |
| 199 wheel_event.event)) { | |
| 190 coalesced_mouse_wheel_events_.push_back(wheel_event); | 200 coalesced_mouse_wheel_events_.push_back(wheel_event); |
| 191 } else { | 201 } else { |
| 192 coalesced_mouse_wheel_events_.back().CoalesceWith(wheel_event); | 202 coalesced_mouse_wheel_events_.back().event.CoalesceWith( |
| 203 wheel_event.event); | |
| 193 } | 204 } |
| 194 return; | 205 return; |
| 195 } | 206 } |
| 207 | |
| 196 mouse_wheel_pending_ = true; | 208 mouse_wheel_pending_ = true; |
| 197 current_wheel_event_ = wheel_event; | 209 current_wheel_event_ = wheel_event; |
| 198 | 210 |
| 199 HISTOGRAM_COUNTS_100("Renderer.WheelQueueSize", | 211 HISTOGRAM_COUNTS_100("Renderer.WheelQueueSize", |
| 200 coalesced_mouse_wheel_events_.size()); | 212 coalesced_mouse_wheel_events_.size()); |
| 201 | 213 |
| 202 FilterAndSendWebInputEvent(wheel_event.event, wheel_event.latency, false); | 214 FilterAndSendWebInputEvent( |
| 215 wheel_event.event.event, wheel_event.event.latency, false); | |
| 203 } | 216 } |
| 204 | 217 |
| 205 void InputRouterImpl::SendKeyboardEvent(const NativeWebKeyboardEvent& key_event, | 218 void InputRouterImpl::SendKeyboardEvent(const NativeWebKeyboardEvent& key_event, |
| 206 const ui::LatencyInfo& latency_info, | 219 const ui::LatencyInfo& latency_info, |
| 207 bool is_keyboard_shortcut) { | 220 bool is_keyboard_shortcut) { |
| 208 // Put all WebKeyboardEvent objects in a queue since we can't trust the | 221 // Put all WebKeyboardEvent objects in a queue since we can't trust the |
| 209 // renderer and we need to give something to the HandleKeyboardEvent | 222 // renderer and we need to give something to the HandleKeyboardEvent |
| 210 // handler. | 223 // handler. |
| 211 key_queue_.push_back(key_event); | 224 key_queue_.push_back(key_event); |
| 212 HISTOGRAM_COUNTS_100("Renderer.KeyboardQueueSize", key_queue_.size()); | 225 HISTOGRAM_COUNTS_100("Renderer.KeyboardQueueSize", key_queue_.size()); |
| (...skipping 158 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 371 | 384 |
| 372 void InputRouterImpl::FilterAndSendWebInputEvent( | 385 void InputRouterImpl::FilterAndSendWebInputEvent( |
| 373 const WebInputEvent& input_event, | 386 const WebInputEvent& input_event, |
| 374 const ui::LatencyInfo& latency_info, | 387 const ui::LatencyInfo& latency_info, |
| 375 bool is_keyboard_shortcut) { | 388 bool is_keyboard_shortcut) { |
| 376 TRACE_EVENT1("input", | 389 TRACE_EVENT1("input", |
| 377 "InputRouterImpl::FilterAndSendWebInputEvent", | 390 "InputRouterImpl::FilterAndSendWebInputEvent", |
| 378 "type", | 391 "type", |
| 379 WebInputEventTraits::GetName(input_event.type)); | 392 WebInputEventTraits::GetName(input_event.type)); |
| 380 | 393 |
| 381 // Transmit any pending wheel events on a non-wheel event. This ensures that | |
| 382 // final PhaseEnded wheel event is received, which is necessary to terminate | |
| 383 // rubber-banding, for example. | |
| 384 if (input_event.type != WebInputEvent::MouseWheel) { | |
| 385 WheelEventQueue mouse_wheel_events; | |
| 386 mouse_wheel_events.swap(coalesced_mouse_wheel_events_); | |
| 387 for (size_t i = 0; i < mouse_wheel_events.size(); ++i) { | |
| 388 OfferToHandlers(mouse_wheel_events[i].event, | |
| 389 mouse_wheel_events[i].latency, | |
| 390 false); | |
| 391 } | |
| 392 } | |
| 393 | |
| 394 // Any input event cancels a pending mouse move event. | 394 // Any input event cancels a pending mouse move event. |
| 395 next_mouse_move_.reset(); | 395 next_mouse_move_.reset(); |
| 396 | 396 |
| 397 OfferToHandlers(input_event, latency_info, is_keyboard_shortcut); | 397 OfferToHandlers(input_event, latency_info, is_keyboard_shortcut); |
| 398 } | 398 } |
| 399 | 399 |
| 400 void InputRouterImpl::OfferToHandlers(const WebInputEvent& input_event, | 400 void InputRouterImpl::OfferToHandlers(const WebInputEvent& input_event, |
| 401 const ui::LatencyInfo& latency_info, | 401 const ui::LatencyInfo& latency_info, |
| 402 bool is_keyboard_shortcut) { | 402 bool is_keyboard_shortcut) { |
| 403 // Trackpad pinch gestures are not yet handled by the renderer. | 403 if (input_event.type == WebInputEvent::GesturePinchUpdate) { |
|
jdduke (slow)
2014/05/01 15:44:47
Can we move this to |SendGestureEventImmediately|.
Rick Byers
2014/05/01 17:34:57
With a bit of refactoring, yes. That's better - t
| |
| 404 // TODO(rbyers): Send mousewheel for trackpad pinch - crbug.com/289887. | 404 const WebGestureEvent& pinch_event = |
| 405 if (input_event.type == WebInputEvent::GesturePinchUpdate && | 405 static_cast<const WebGestureEvent&>(input_event); |
| 406 static_cast<const WebGestureEvent&>(input_event).sourceDevice == | 406 if (pinch_event.sourceDevice == WebGestureEvent::Touchpad) { |
| 407 WebGestureEvent::Touchpad) { | 407 SendSyntheticWheelEventForPinch(pinch_event, latency_info); |
| 408 ProcessInputEventAck(input_event.type, | 408 return; |
| 409 INPUT_EVENT_ACK_STATE_NOT_CONSUMED, | 409 } |
| 410 latency_info, | |
| 411 ACK_SOURCE_NONE); | |
| 412 return; | |
| 413 } | 410 } |
| 414 | 411 |
| 415 if (OfferToOverscrollController(input_event, latency_info)) | 412 if (OfferToOverscrollController(input_event, latency_info)) |
| 416 return; | 413 return; |
| 417 | 414 |
| 418 if (OfferToClient(input_event, latency_info)) | 415 if (OfferToClient(input_event, latency_info)) |
| 419 return; | 416 return; |
| 420 | 417 |
| 421 OfferToRenderer(input_event, latency_info, is_keyboard_shortcut); | 418 OfferToRenderer(input_event, latency_info, is_keyboard_shortcut); |
| 422 | 419 |
| (...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 508 // or in-flight event count metrics. | 505 // or in-flight event count metrics. |
| 509 if (!WebInputEventTraits::IgnoresAckDisposition(input_event)) { | 506 if (!WebInputEventTraits::IgnoresAckDisposition(input_event)) { |
| 510 input_event_start_time_ = TimeTicks::Now(); | 507 input_event_start_time_ = TimeTicks::Now(); |
| 511 client_->IncrementInFlightEventCount(); | 508 client_->IncrementInFlightEventCount(); |
| 512 } | 509 } |
| 513 return true; | 510 return true; |
| 514 } | 511 } |
| 515 return false; | 512 return false; |
| 516 } | 513 } |
| 517 | 514 |
| 515 void InputRouterImpl::SendSyntheticWheelEventForPinch( | |
| 516 const blink::WebGestureEvent& pinch_event, | |
| 517 const ui::LatencyInfo& latency_info) { | |
| 518 // We match typical trackpad behavior on Windows by sending fake wheel events | |
| 519 // with the ctrl modifier set when we see trackpad pinch gestures. Ideally | |
| 520 // we'd someday get a standard 'pinch' event and send that instead. | |
| 521 | |
| 522 WebMouseWheelEvent wheelEvent; | |
| 523 wheelEvent.type = WebInputEvent::MouseWheel; | |
| 524 wheelEvent.timeStampSeconds = pinch_event.timeStampSeconds; | |
| 525 wheelEvent.windowX = wheelEvent.x = pinch_event.x; | |
| 526 wheelEvent.windowY = wheelEvent.y = pinch_event.y; | |
| 527 wheelEvent.globalX = pinch_event.globalX; | |
| 528 wheelEvent.globalY = pinch_event.globalY; | |
| 529 wheelEvent.modifiers = pinch_event.modifiers | WebInputEvent::ControlKey; | |
| 530 wheelEvent.deltaX = 0; | |
| 531 // For maximum compatibility with wheels, deltaY here is a "magnification | |
| 532 // percentage". Note that wheel events in JS have the sign reversed. | |
| 533 wheelEvent.deltaY = 100.0f * (1.0f - pinch_event.data.pinchUpdate.scale); | |
|
jdduke (slow)
2014/05/01 15:44:47
Maybe DCHECK that the scale is positive? Is the ma
Rick Byers
2014/05/01 17:34:57
Done.
| |
| 534 wheelEvent.hasPreciseScrollingDeltas = true; | |
| 535 wheelEvent.wheelTicksX = 0; | |
| 536 wheelEvent.wheelTicksY = pinch_event.data.pinchUpdate.scale > 1 ? 1 : -1; | |
| 537 | |
| 538 SendWheelEvent(QueuedWheelEvent( | |
| 539 MouseWheelEventWithLatencyInfo(wheelEvent, latency_info), true)); | |
| 540 } | |
| 541 | |
| 518 void InputRouterImpl::OnInputEventAck(WebInputEvent::Type event_type, | 542 void InputRouterImpl::OnInputEventAck(WebInputEvent::Type event_type, |
| 519 InputEventAckState ack_result, | 543 InputEventAckState ack_result, |
| 520 const ui::LatencyInfo& latency_info) { | 544 const ui::LatencyInfo& latency_info) { |
| 521 client_->DecrementInFlightEventCount(); | 545 client_->DecrementInFlightEventCount(); |
| 522 | 546 |
| 523 // Log the time delta for processing an input event. | 547 // Log the time delta for processing an input event. |
| 524 TimeDelta delta = TimeTicks::Now() - input_event_start_time_; | 548 TimeDelta delta = TimeTicks::Now() - input_event_start_time_; |
| 525 UMA_HISTOGRAM_TIMES("MPArch.IIR_InputEventDelta", delta); | 549 UMA_HISTOGRAM_TIMES("MPArch.IIR_InputEventDelta", delta); |
| 526 | 550 |
| 527 ProcessInputEventAck(event_type, ack_result, latency_info, RENDERER); | 551 ProcessInputEventAck(event_type, ack_result, latency_info, RENDERER); |
| (...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 640 if (next_mouse_move_) { | 664 if (next_mouse_move_) { |
| 641 DCHECK(next_mouse_move_->event.type == WebInputEvent::MouseMove); | 665 DCHECK(next_mouse_move_->event.type == WebInputEvent::MouseMove); |
| 642 scoped_ptr<MouseEventWithLatencyInfo> next_mouse_move | 666 scoped_ptr<MouseEventWithLatencyInfo> next_mouse_move |
| 643 = next_mouse_move_.Pass(); | 667 = next_mouse_move_.Pass(); |
| 644 SendMouseEvent(*next_mouse_move); | 668 SendMouseEvent(*next_mouse_move); |
| 645 } | 669 } |
| 646 } | 670 } |
| 647 | 671 |
| 648 void InputRouterImpl::ProcessWheelAck(InputEventAckState ack_result, | 672 void InputRouterImpl::ProcessWheelAck(InputEventAckState ack_result, |
| 649 const ui::LatencyInfo& latency) { | 673 const ui::LatencyInfo& latency) { |
| 650 ProcessAckForOverscroll(current_wheel_event_.event, ack_result); | |
| 651 | |
| 652 // TODO(miletus): Add renderer side latency to each uncoalesced mouse | 674 // TODO(miletus): Add renderer side latency to each uncoalesced mouse |
| 653 // wheel event and add terminal component to each of them. | 675 // wheel event and add terminal component to each of them. |
| 654 current_wheel_event_.latency.AddNewLatencyFrom(latency); | 676 current_wheel_event_.event.latency.AddNewLatencyFrom(latency); |
| 655 // Process the unhandled wheel event here before calling SendWheelEvent() | 677 |
| 656 // since it will mutate current_wheel_event_. | 678 if (current_wheel_event_.synthesized_from_pinch) { |
| 657 ack_handler_->OnWheelEventAck(current_wheel_event_, ack_result); | 679 // Ack the GesturePinchUpdate event that generated this wheel event. |
| 680 ProcessInputEventAck(WebInputEvent::GesturePinchUpdate, | |
| 681 ack_result, | |
| 682 current_wheel_event_.event.latency, | |
| 683 ACK_SOURCE_NONE); | |
|
jdduke (slow)
2014/05/01 15:44:47
ACK_SOURCE_NONE -> current_ack_source_
Rick Byers
2014/05/01 17:34:57
Done.
| |
| 684 } else { | |
| 685 // Process the unhandled wheel event here before calling SendWheelEvent() | |
| 686 // since it will mutate current_wheel_event_. | |
| 687 ProcessAckForOverscroll(current_wheel_event_.event.event, ack_result); | |
| 688 ack_handler_->OnWheelEventAck(current_wheel_event_.event, ack_result); | |
| 689 } | |
| 658 mouse_wheel_pending_ = false; | 690 mouse_wheel_pending_ = false; |
|
jdduke (slow)
2014/05/01 15:44:47
Could you put a note that the order this bool is s
Rick Byers
2014/05/01 17:34:57
Done.
| |
| 659 | 691 |
| 660 // Now send the next (coalesced) mouse wheel event. | 692 // Send the next (coalesced or synthetic) mouse wheel event. |
| 661 if (!coalesced_mouse_wheel_events_.empty()) { | 693 if (!coalesced_mouse_wheel_events_.empty()) { |
| 662 MouseWheelEventWithLatencyInfo next_wheel_event = | 694 QueuedWheelEvent next_wheel_event = coalesced_mouse_wheel_events_.front(); |
| 663 coalesced_mouse_wheel_events_.front(); | |
| 664 coalesced_mouse_wheel_events_.pop_front(); | 695 coalesced_mouse_wheel_events_.pop_front(); |
| 665 SendWheelEvent(next_wheel_event); | 696 SendWheelEvent(next_wheel_event); |
| 666 } | 697 } |
| 667 } | 698 } |
| 668 | 699 |
| 669 void InputRouterImpl::ProcessGestureAck(WebInputEvent::Type type, | 700 void InputRouterImpl::ProcessGestureAck(WebInputEvent::Type type, |
| 670 InputEventAckState ack_result, | 701 InputEventAckState ack_result, |
| 671 const ui::LatencyInfo& latency) { | 702 const ui::LatencyInfo& latency) { |
| 672 // If |ack_result| originated from the overscroll controller, only | 703 // If |ack_result| originated from the overscroll controller, only |
| 673 // feed |gesture_event_queue_| the ack if it was expecting one. | 704 // feed |gesture_event_queue_| the ack if it was expecting one. |
| (...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 745 mouse_wheel_pending_ || | 776 mouse_wheel_pending_ || |
| 746 select_range_pending_ || | 777 select_range_pending_ || |
| 747 move_caret_pending_; | 778 move_caret_pending_; |
| 748 } | 779 } |
| 749 | 780 |
| 750 bool InputRouterImpl::IsInOverscrollGesture() const { | 781 bool InputRouterImpl::IsInOverscrollGesture() const { |
| 751 OverscrollController* controller = client_->GetOverscrollController(); | 782 OverscrollController* controller = client_->GetOverscrollController(); |
| 752 return controller && controller->overscroll_mode() != OVERSCROLL_NONE; | 783 return controller && controller->overscroll_mode() != OVERSCROLL_NONE; |
| 753 } | 784 } |
| 754 | 785 |
| 786 InputRouterImpl::QueuedWheelEvent::QueuedWheelEvent() { | |
|
jdduke (slow)
2014/05/01 15:44:47
synthesized_from_pinch(false)
Rick Byers
2014/05/01 17:34:57
Thanks! Done.
| |
| 787 } | |
| 788 | |
| 789 InputRouterImpl::QueuedWheelEvent::QueuedWheelEvent( | |
| 790 const MouseWheelEventWithLatencyInfo& event, | |
| 791 bool synthesized_from_pinch) | |
| 792 : event(event), synthesized_from_pinch(synthesized_from_pinch) { | |
| 793 } | |
| 794 | |
| 795 InputRouterImpl::QueuedWheelEvent::~QueuedWheelEvent() { | |
| 796 } | |
| 797 | |
| 755 } // namespace content | 798 } // namespace content |
| OLD | NEW |