| 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 <math.h> |
| 8 |
| 7 #include "base/auto_reset.h" | 9 #include "base/auto_reset.h" |
| 8 #include "base/command_line.h" | 10 #include "base/command_line.h" |
| 9 #include "base/metrics/histogram.h" | 11 #include "base/metrics/histogram.h" |
| 10 #include "base/strings/string_number_conversions.h" | 12 #include "base/strings/string_number_conversions.h" |
| 11 #include "content/browser/renderer_host/input/gesture_event_queue.h" | 13 #include "content/browser/renderer_host/input/gesture_event_queue.h" |
| 12 #include "content/browser/renderer_host/input/input_ack_handler.h" | 14 #include "content/browser/renderer_host/input/input_ack_handler.h" |
| 13 #include "content/browser/renderer_host/input/input_router_client.h" | 15 #include "content/browser/renderer_host/input/input_router_client.h" |
| 14 #include "content/browser/renderer_host/input/touch_event_queue.h" | 16 #include "content/browser/renderer_host/input/touch_event_queue.h" |
| 15 #include "content/browser/renderer_host/input/touchpad_tap_suppression_controlle
r.h" | 17 #include "content/browser/renderer_host/input/touchpad_tap_suppression_controlle
r.h" |
| 16 #include "content/browser/renderer_host/overscroll_controller.h" | 18 #include "content/browser/renderer_host/overscroll_controller.h" |
| (...skipping 156 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 173 if (mouse_event.event.type == WebInputEvent::MouseUp && | 175 if (mouse_event.event.type == WebInputEvent::MouseUp && |
| 174 gesture_event_queue_.GetTouchpadTapSuppressionController()-> | 176 gesture_event_queue_.GetTouchpadTapSuppressionController()-> |
| 175 ShouldSuppressMouseUp()) | 177 ShouldSuppressMouseUp()) |
| 176 return; | 178 return; |
| 177 | 179 |
| 178 SendMouseEventImmediately(mouse_event); | 180 SendMouseEventImmediately(mouse_event); |
| 179 } | 181 } |
| 180 | 182 |
| 181 void InputRouterImpl::SendWheelEvent( | 183 void InputRouterImpl::SendWheelEvent( |
| 182 const MouseWheelEventWithLatencyInfo& wheel_event) { | 184 const MouseWheelEventWithLatencyInfo& wheel_event) { |
| 183 // If there's already a mouse wheel event waiting to be sent to the renderer, | 185 SendWheelEvent(QueuedWheelEvent(wheel_event, false)); |
| 184 // add the new deltas to that event. Not doing so (e.g., by dropping the old | 186 } |
| 185 // event, as for mouse moves) results in very slow scrolling on the Mac (on | 187 |
| 186 // which many, very small wheel events are sent). | 188 void InputRouterImpl::SendWheelEvent(const QueuedWheelEvent& wheel_event) { |
| 187 if (mouse_wheel_pending_) { | 189 if (mouse_wheel_pending_) { |
| 190 // If there's already a mouse wheel event waiting to be sent to the |
| 191 // renderer, add the new deltas to that event. Not doing so (e.g., by |
| 192 // dropping the old event, as for mouse moves) results in very slow |
| 193 // scrolling on the Mac (on which many, very small wheel events are sent). |
| 194 // Note that we can't coalesce wheel events for pinches because the GEQ |
| 195 // expects one ACK for each (but it's fine to coalesce non-pinch wheels |
| 196 // into a pinch one). Note that the GestureEventQueue ensures we only |
| 197 // ever have a single pinch event queued here. |
| 188 if (coalesced_mouse_wheel_events_.empty() || | 198 if (coalesced_mouse_wheel_events_.empty() || |
| 189 !coalesced_mouse_wheel_events_.back().CanCoalesceWith(wheel_event)) { | 199 wheel_event.synthesized_from_pinch || |
| 200 !coalesced_mouse_wheel_events_.back().event.CanCoalesceWith( |
| 201 wheel_event.event)) { |
| 190 coalesced_mouse_wheel_events_.push_back(wheel_event); | 202 coalesced_mouse_wheel_events_.push_back(wheel_event); |
| 191 } else { | 203 } else { |
| 192 coalesced_mouse_wheel_events_.back().CoalesceWith(wheel_event); | 204 coalesced_mouse_wheel_events_.back().event.CoalesceWith( |
| 205 wheel_event.event); |
| 193 } | 206 } |
| 194 return; | 207 return; |
| 195 } | 208 } |
| 209 |
| 196 mouse_wheel_pending_ = true; | 210 mouse_wheel_pending_ = true; |
| 197 current_wheel_event_ = wheel_event; | 211 current_wheel_event_ = wheel_event; |
| 198 | 212 |
| 199 HISTOGRAM_COUNTS_100("Renderer.WheelQueueSize", | 213 HISTOGRAM_COUNTS_100("Renderer.WheelQueueSize", |
| 200 coalesced_mouse_wheel_events_.size()); | 214 coalesced_mouse_wheel_events_.size()); |
| 201 | 215 |
| 202 FilterAndSendWebInputEvent(wheel_event.event, wheel_event.latency, false); | 216 FilterAndSendWebInputEvent( |
| 217 wheel_event.event.event, wheel_event.event.latency, false); |
| 203 } | 218 } |
| 204 | 219 |
| 205 void InputRouterImpl::SendKeyboardEvent(const NativeWebKeyboardEvent& key_event, | 220 void InputRouterImpl::SendKeyboardEvent(const NativeWebKeyboardEvent& key_event, |
| 206 const ui::LatencyInfo& latency_info, | 221 const ui::LatencyInfo& latency_info, |
| 207 bool is_keyboard_shortcut) { | 222 bool is_keyboard_shortcut) { |
| 208 // Put all WebKeyboardEvent objects in a queue since we can't trust the | 223 // Put all WebKeyboardEvent objects in a queue since we can't trust the |
| 209 // renderer and we need to give something to the HandleKeyboardEvent | 224 // renderer and we need to give something to the HandleKeyboardEvent |
| 210 // handler. | 225 // handler. |
| 211 key_queue_.push_back(key_event); | 226 key_queue_.push_back(key_event); |
| 212 HISTOGRAM_COUNTS_100("Renderer.KeyboardQueueSize", key_queue_.size()); | 227 HISTOGRAM_COUNTS_100("Renderer.KeyboardQueueSize", key_queue_.size()); |
| (...skipping 158 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 371 | 386 |
| 372 void InputRouterImpl::FilterAndSendWebInputEvent( | 387 void InputRouterImpl::FilterAndSendWebInputEvent( |
| 373 const WebInputEvent& input_event, | 388 const WebInputEvent& input_event, |
| 374 const ui::LatencyInfo& latency_info, | 389 const ui::LatencyInfo& latency_info, |
| 375 bool is_keyboard_shortcut) { | 390 bool is_keyboard_shortcut) { |
| 376 TRACE_EVENT1("input", | 391 TRACE_EVENT1("input", |
| 377 "InputRouterImpl::FilterAndSendWebInputEvent", | 392 "InputRouterImpl::FilterAndSendWebInputEvent", |
| 378 "type", | 393 "type", |
| 379 WebInputEventTraits::GetName(input_event.type)); | 394 WebInputEventTraits::GetName(input_event.type)); |
| 380 | 395 |
| 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. | 396 // Any input event cancels a pending mouse move event. |
| 395 next_mouse_move_.reset(); | 397 next_mouse_move_.reset(); |
| 396 | 398 |
| 397 OfferToHandlers(input_event, latency_info, is_keyboard_shortcut); | 399 OfferToHandlers(input_event, latency_info, is_keyboard_shortcut); |
| 398 } | 400 } |
| 399 | 401 |
| 400 void InputRouterImpl::OfferToHandlers(const WebInputEvent& input_event, | 402 void InputRouterImpl::OfferToHandlers(const WebInputEvent& input_event, |
| 401 const ui::LatencyInfo& latency_info, | 403 const ui::LatencyInfo& latency_info, |
| 402 bool is_keyboard_shortcut) { | 404 bool is_keyboard_shortcut) { |
| 403 // Trackpad pinch gestures are not yet handled by the renderer. | 405 if (input_event.type == WebInputEvent::GesturePinchUpdate) { |
| 404 // TODO(rbyers): Send mousewheel for trackpad pinch - crbug.com/289887. | 406 const WebGestureEvent& pinch_event = |
| 405 if (input_event.type == WebInputEvent::GesturePinchUpdate && | 407 static_cast<const WebGestureEvent&>(input_event); |
| 406 static_cast<const WebGestureEvent&>(input_event).sourceDevice == | 408 if (pinch_event.sourceDevice == WebGestureEvent::Touchpad) { |
| 407 WebGestureEvent::Touchpad) { | 409 SendSyntheticWheelEventForPinch(pinch_event, latency_info); |
| 408 ProcessInputEventAck(input_event.type, | 410 return; |
| 409 INPUT_EVENT_ACK_STATE_NOT_CONSUMED, | 411 } |
| 410 latency_info, | |
| 411 ACK_SOURCE_NONE); | |
| 412 return; | |
| 413 } | 412 } |
| 414 | 413 |
| 415 if (OfferToOverscrollController(input_event, latency_info)) | 414 if (OfferToOverscrollController(input_event, latency_info)) |
| 416 return; | 415 return; |
| 417 | 416 |
| 418 if (OfferToClient(input_event, latency_info)) | 417 if (OfferToClient(input_event, latency_info)) |
| 419 return; | 418 return; |
| 420 | 419 |
| 421 OfferToRenderer(input_event, latency_info, is_keyboard_shortcut); | 420 OfferToRenderer(input_event, latency_info, is_keyboard_shortcut); |
| 422 | 421 |
| (...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 508 // or in-flight event count metrics. | 507 // or in-flight event count metrics. |
| 509 if (!WebInputEventTraits::IgnoresAckDisposition(input_event)) { | 508 if (!WebInputEventTraits::IgnoresAckDisposition(input_event)) { |
| 510 input_event_start_time_ = TimeTicks::Now(); | 509 input_event_start_time_ = TimeTicks::Now(); |
| 511 client_->IncrementInFlightEventCount(); | 510 client_->IncrementInFlightEventCount(); |
| 512 } | 511 } |
| 513 return true; | 512 return true; |
| 514 } | 513 } |
| 515 return false; | 514 return false; |
| 516 } | 515 } |
| 517 | 516 |
| 517 void InputRouterImpl::SendSyntheticWheelEventForPinch( |
| 518 const blink::WebGestureEvent& pinch_event, |
| 519 const ui::LatencyInfo& latency_info) { |
| 520 // We match typical trackpad behavior on Windows by sending fake wheel events |
| 521 // with the ctrl modifier set when we see trackpad pinch gestures. Ideally |
| 522 // we'd someday get a standard 'pinch' event and send that instead. |
| 523 |
| 524 WebMouseWheelEvent wheelEvent; |
| 525 wheelEvent.type = WebInputEvent::MouseWheel; |
| 526 wheelEvent.timeStampSeconds = pinch_event.timeStampSeconds; |
| 527 wheelEvent.windowX = wheelEvent.x = pinch_event.x; |
| 528 wheelEvent.windowY = wheelEvent.y = pinch_event.y; |
| 529 wheelEvent.globalX = pinch_event.globalX; |
| 530 wheelEvent.globalY = pinch_event.globalY; |
| 531 wheelEvent.modifiers = pinch_event.modifiers | WebInputEvent::ControlKey; |
| 532 wheelEvent.deltaX = 0; |
| 533 // The function to convert scales to deltaY values is designed to be |
| 534 // compatible with websites existing use of wheel events, and with existing |
| 535 // Windows trackpad behavior. In particular, we want: |
| 536 // - deltas should accumulate via addition: f(s1*s2)==f(s1)+f(s2) |
| 537 // - deltas should invert via negation: f(1/s) == -f(s) |
| 538 // - zoom in should be positive: f(s) > 0 iff s > 1 |
| 539 // - magnitude roughly matches wheels: f(2) > 25 && f(2) < 100 |
| 540 // - a formula that's relatively easy to use from JavaScript |
| 541 // Note that 'wheel' event deltaY values have their sign inverted. So to |
| 542 // convert a wheel deltaY back to a scale use Math.exp(-deltaY/100). |
| 543 wheelEvent.deltaY = 100.0f * log(pinch_event.data.pinchUpdate.scale); |
| 544 wheelEvent.hasPreciseScrollingDeltas = true; |
| 545 wheelEvent.wheelTicksX = 0; |
| 546 wheelEvent.wheelTicksY = pinch_event.data.pinchUpdate.scale > 1 ? 1 : -1; |
| 547 |
| 548 SendWheelEvent(QueuedWheelEvent( |
| 549 MouseWheelEventWithLatencyInfo(wheelEvent, latency_info), true)); |
| 550 } |
| 551 |
| 518 void InputRouterImpl::OnInputEventAck(WebInputEvent::Type event_type, | 552 void InputRouterImpl::OnInputEventAck(WebInputEvent::Type event_type, |
| 519 InputEventAckState ack_result, | 553 InputEventAckState ack_result, |
| 520 const ui::LatencyInfo& latency_info) { | 554 const ui::LatencyInfo& latency_info) { |
| 521 client_->DecrementInFlightEventCount(); | 555 client_->DecrementInFlightEventCount(); |
| 522 | 556 |
| 523 // Log the time delta for processing an input event. | 557 // Log the time delta for processing an input event. |
| 524 TimeDelta delta = TimeTicks::Now() - input_event_start_time_; | 558 TimeDelta delta = TimeTicks::Now() - input_event_start_time_; |
| 525 UMA_HISTOGRAM_TIMES("MPArch.IIR_InputEventDelta", delta); | 559 UMA_HISTOGRAM_TIMES("MPArch.IIR_InputEventDelta", delta); |
| 526 | 560 |
| 527 ProcessInputEventAck(event_type, ack_result, latency_info, RENDERER); | 561 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_) { | 674 if (next_mouse_move_) { |
| 641 DCHECK(next_mouse_move_->event.type == WebInputEvent::MouseMove); | 675 DCHECK(next_mouse_move_->event.type == WebInputEvent::MouseMove); |
| 642 scoped_ptr<MouseEventWithLatencyInfo> next_mouse_move | 676 scoped_ptr<MouseEventWithLatencyInfo> next_mouse_move |
| 643 = next_mouse_move_.Pass(); | 677 = next_mouse_move_.Pass(); |
| 644 SendMouseEvent(*next_mouse_move); | 678 SendMouseEvent(*next_mouse_move); |
| 645 } | 679 } |
| 646 } | 680 } |
| 647 | 681 |
| 648 void InputRouterImpl::ProcessWheelAck(InputEventAckState ack_result, | 682 void InputRouterImpl::ProcessWheelAck(InputEventAckState ack_result, |
| 649 const ui::LatencyInfo& latency) { | 683 const ui::LatencyInfo& latency) { |
| 650 ProcessAckForOverscroll(current_wheel_event_.event, ack_result); | |
| 651 | |
| 652 // TODO(miletus): Add renderer side latency to each uncoalesced mouse | 684 // TODO(miletus): Add renderer side latency to each uncoalesced mouse |
| 653 // wheel event and add terminal component to each of them. | 685 // wheel event and add terminal component to each of them. |
| 654 current_wheel_event_.latency.AddNewLatencyFrom(latency); | 686 current_wheel_event_.event.latency.AddNewLatencyFrom(latency); |
| 655 // Process the unhandled wheel event here before calling SendWheelEvent() | 687 |
| 656 // since it will mutate current_wheel_event_. | 688 if (current_wheel_event_.synthesized_from_pinch) { |
| 657 ack_handler_->OnWheelEventAck(current_wheel_event_, ack_result); | 689 // Ack the GesturePinchUpdate event that generated this wheel event. |
| 690 ProcessInputEventAck(WebInputEvent::GesturePinchUpdate, |
| 691 ack_result, |
| 692 current_wheel_event_.event.latency, |
| 693 ACK_SOURCE_NONE); |
| 694 } else { |
| 695 // Process the unhandled wheel event here before calling SendWheelEvent() |
| 696 // since it will mutate current_wheel_event_. |
| 697 ProcessAckForOverscroll(current_wheel_event_.event.event, ack_result); |
| 698 ack_handler_->OnWheelEventAck(current_wheel_event_.event, ack_result); |
| 699 } |
| 658 mouse_wheel_pending_ = false; | 700 mouse_wheel_pending_ = false; |
| 659 | 701 |
| 660 // Now send the next (coalesced) mouse wheel event. | 702 // Send the next (coalesced or synthetic) mouse wheel event. |
| 661 if (!coalesced_mouse_wheel_events_.empty()) { | 703 if (!coalesced_mouse_wheel_events_.empty()) { |
| 662 MouseWheelEventWithLatencyInfo next_wheel_event = | 704 QueuedWheelEvent next_wheel_event = coalesced_mouse_wheel_events_.front(); |
| 663 coalesced_mouse_wheel_events_.front(); | |
| 664 coalesced_mouse_wheel_events_.pop_front(); | 705 coalesced_mouse_wheel_events_.pop_front(); |
| 665 SendWheelEvent(next_wheel_event); | 706 SendWheelEvent(next_wheel_event); |
| 666 } | 707 } |
| 667 } | 708 } |
| 668 | 709 |
| 669 void InputRouterImpl::ProcessGestureAck(WebInputEvent::Type type, | 710 void InputRouterImpl::ProcessGestureAck(WebInputEvent::Type type, |
| 670 InputEventAckState ack_result, | 711 InputEventAckState ack_result, |
| 671 const ui::LatencyInfo& latency) { | 712 const ui::LatencyInfo& latency) { |
| 672 // If |ack_result| originated from the overscroll controller, only | 713 // If |ack_result| originated from the overscroll controller, only |
| 673 // feed |gesture_event_queue_| the ack if it was expecting one. | 714 // 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_ || | 786 mouse_wheel_pending_ || |
| 746 select_range_pending_ || | 787 select_range_pending_ || |
| 747 move_caret_pending_; | 788 move_caret_pending_; |
| 748 } | 789 } |
| 749 | 790 |
| 750 bool InputRouterImpl::IsInOverscrollGesture() const { | 791 bool InputRouterImpl::IsInOverscrollGesture() const { |
| 751 OverscrollController* controller = client_->GetOverscrollController(); | 792 OverscrollController* controller = client_->GetOverscrollController(); |
| 752 return controller && controller->overscroll_mode() != OVERSCROLL_NONE; | 793 return controller && controller->overscroll_mode() != OVERSCROLL_NONE; |
| 753 } | 794 } |
| 754 | 795 |
| 796 InputRouterImpl::QueuedWheelEvent::QueuedWheelEvent() { |
| 797 } |
| 798 |
| 799 InputRouterImpl::QueuedWheelEvent::QueuedWheelEvent( |
| 800 const MouseWheelEventWithLatencyInfo& event, |
| 801 bool synthesized_from_pinch) |
| 802 : event(event), synthesized_from_pinch(synthesized_from_pinch) { |
| 803 } |
| 804 |
| 805 InputRouterImpl::QueuedWheelEvent::~QueuedWheelEvent() { |
| 806 } |
| 807 |
| 755 } // namespace content | 808 } // namespace content |
| OLD | NEW |