| 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> | 7 #include <math.h> |
| 8 | 8 |
| 9 #include "base/auto_reset.h" | 9 #include "base/auto_reset.h" |
| 10 #include "base/command_line.h" | 10 #include "base/command_line.h" |
| 11 #include "base/metrics/histogram.h" | 11 #include "base/metrics/histogram.h" |
| 12 #include "base/strings/string_number_conversions.h" | 12 #include "base/strings/string_number_conversions.h" |
| 13 #include "content/browser/renderer_host/input/gesture_event_queue.h" | |
| 14 #include "content/browser/renderer_host/input/input_ack_handler.h" | 13 #include "content/browser/renderer_host/input/input_ack_handler.h" |
| 15 #include "content/browser/renderer_host/input/input_router_client.h" | 14 #include "content/browser/renderer_host/input/input_router_client.h" |
| 16 #include "content/browser/renderer_host/input/touch_event_queue.h" | |
| 17 #include "content/browser/renderer_host/input/touchpad_tap_suppression_controlle
r.h" | 15 #include "content/browser/renderer_host/input/touchpad_tap_suppression_controlle
r.h" |
| 18 #include "content/common/content_constants_internal.h" | 16 #include "content/common/content_constants_internal.h" |
| 19 #include "content/common/edit_command.h" | 17 #include "content/common/edit_command.h" |
| 20 #include "content/common/input/input_event_ack_state.h" | 18 #include "content/common/input/input_event_ack_state.h" |
| 21 #include "content/common/input/touch_action.h" | 19 #include "content/common/input/touch_action.h" |
| 22 #include "content/common/input/web_touch_event_traits.h" | 20 #include "content/common/input/web_touch_event_traits.h" |
| 23 #include "content/common/input_messages.h" | 21 #include "content/common/input_messages.h" |
| 24 #include "content/common/view_messages.h" | 22 #include "content/common/view_messages.h" |
| 25 #include "content/public/browser/notification_service.h" | 23 #include "content/public/browser/notification_service.h" |
| 26 #include "content/public/browser/notification_types.h" | 24 #include "content/public/browser/notification_types.h" |
| (...skipping 23 matching lines...) Expand all Loading... |
| 50 case INPUT_EVENT_ACK_STATE_NOT_CONSUMED: return "NOT_CONSUMED"; | 48 case INPUT_EVENT_ACK_STATE_NOT_CONSUMED: return "NOT_CONSUMED"; |
| 51 case INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS: return "NO_CONSUMER_EXISTS"; | 49 case INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS: return "NO_CONSUMER_EXISTS"; |
| 52 case INPUT_EVENT_ACK_STATE_IGNORED: return "IGNORED"; | 50 case INPUT_EVENT_ACK_STATE_IGNORED: return "IGNORED"; |
| 53 } | 51 } |
| 54 DLOG(WARNING) << "Unhandled InputEventAckState in GetEventAckName."; | 52 DLOG(WARNING) << "Unhandled InputEventAckState in GetEventAckName."; |
| 55 return ""; | 53 return ""; |
| 56 } | 54 } |
| 57 | 55 |
| 58 } // namespace | 56 } // namespace |
| 59 | 57 |
| 60 InputRouterImpl::Config::Config() {} | 58 InputRouterImpl::Config::Config() : buffer_wheel_events_until_flush(false) {} |
| 61 | 59 |
| 62 InputRouterImpl::InputRouterImpl(IPC::Sender* sender, | 60 InputRouterImpl::InputRouterImpl(IPC::Sender* sender, |
| 63 InputRouterClient* client, | 61 InputRouterClient* client, |
| 64 InputAckHandler* ack_handler, | 62 InputAckHandler* ack_handler, |
| 65 int routing_id, | 63 int routing_id, |
| 66 const Config& config) | 64 const Config& config) |
| 67 : sender_(sender), | 65 : sender_(sender), |
| 68 client_(client), | 66 client_(client), |
| 69 ack_handler_(ack_handler), | 67 ack_handler_(ack_handler), |
| 70 routing_id_(routing_id), | 68 routing_id_(routing_id), |
| 71 select_message_pending_(false), | 69 select_message_pending_(false), |
| 72 move_caret_pending_(false), | 70 move_caret_pending_(false), |
| 73 mouse_move_pending_(false), | 71 mouse_move_pending_(false), |
| 74 mouse_wheel_pending_(false), | |
| 75 current_ack_source_(ACK_SOURCE_NONE), | 72 current_ack_source_(ACK_SOURCE_NONE), |
| 76 flush_requested_(false), | 73 flush_requested_(false), |
| 77 active_renderer_fling_count_(0), | 74 active_renderer_fling_count_(0), |
| 78 touch_event_queue_(this, config.touch_config), | 75 touch_event_queue_(this, config.touch_config), |
| 79 gesture_event_queue_(this, this, config.gesture_config) { | 76 gesture_event_queue_(this, this, config.gesture_config), |
| 77 wheel_event_queue_(this, config.buffer_wheel_events_until_flush) { |
| 80 DCHECK(sender); | 78 DCHECK(sender); |
| 81 DCHECK(client); | 79 DCHECK(client); |
| 82 DCHECK(ack_handler); | 80 DCHECK(ack_handler); |
| 83 UpdateTouchAckTimeoutEnabled(); | 81 UpdateTouchAckTimeoutEnabled(); |
| 84 } | 82 } |
| 85 | 83 |
| 86 InputRouterImpl::~InputRouterImpl() { | 84 InputRouterImpl::~InputRouterImpl() { |
| 87 STLDeleteElements(&pending_select_messages_); | 85 STLDeleteElements(&pending_select_messages_); |
| 88 } | 86 } |
| 89 | 87 |
| 90 bool InputRouterImpl::SendInput(scoped_ptr<IPC::Message> message) { | 88 bool InputRouterImpl::SendInput(scoped_ptr<IPC::Message> message) { |
| 91 DCHECK(IPC_MESSAGE_ID_CLASS(message->type()) == InputMsgStart); | 89 DCHECK(IPC_MESSAGE_ID_CLASS(message->type()) == InputMsgStart); |
| 92 switch (message->type()) { | 90 switch (message->type()) { |
| 93 // Check for types that require an ACK. | 91 // Check for types that require an ACK. |
| 94 case InputMsg_SelectRange::ID: | 92 case InputMsg_SelectRange::ID: |
| 95 case InputMsg_MoveRangeSelectionExtent::ID: | 93 case InputMsg_MoveRangeSelectionExtent::ID: |
| 96 return SendSelectMessage(message.Pass()); | 94 return SendSelectMessage(message.Pass()); |
| 97 case InputMsg_MoveCaret::ID: | 95 case InputMsg_MoveCaret::ID: |
| 98 return SendMoveCaret(message.Pass()); | 96 return SendMoveCaret(message.Pass()); |
| 99 case InputMsg_HandleInputEvent::ID: | 97 case InputMsg_HandleInputEvent::ID: |
| 100 NOTREACHED() << "WebInputEvents should never be sent via SendInput."; | 98 NOTREACHED() << "WebInputEvents should never be sent via SendInput."; |
| 101 return false; | 99 return false; |
| 102 default: | 100 default: |
| 103 return Send(message.release()); | 101 return Send(message.release()); |
| 104 } | 102 } |
| 105 } | 103 } |
| 106 | 104 |
| 107 void InputRouterImpl::FlushInput(base::TimeTicks flush_time) { | 105 void InputRouterImpl::FlushInput(base::TimeTicks flush_time) { |
| 108 flush_requested_ = true; | 106 flush_requested_ = true; |
| 107 |
| 108 wheel_event_queue_.Flush(); |
| 109 |
| 109 SignalFlushedIfNecessary(); | 110 SignalFlushedIfNecessary(); |
| 110 } | 111 } |
| 111 | 112 |
| 112 void InputRouterImpl::SendMouseEvent( | 113 void InputRouterImpl::SendMouseEvent( |
| 113 const MouseEventWithLatencyInfo& mouse_event) { | 114 const MouseEventWithLatencyInfo& mouse_event) { |
| 114 if (mouse_event.event.type == WebInputEvent::MouseDown && | 115 if (mouse_event.event.type == WebInputEvent::MouseDown && |
| 115 gesture_event_queue_.GetTouchpadTapSuppressionController()-> | 116 gesture_event_queue_.GetTouchpadTapSuppressionController()-> |
| 116 ShouldDeferMouseDown(mouse_event)) | 117 ShouldDeferMouseDown(mouse_event)) |
| 117 return; | 118 return; |
| 118 if (mouse_event.event.type == WebInputEvent::MouseUp && | 119 if (mouse_event.event.type == WebInputEvent::MouseUp && |
| 119 gesture_event_queue_.GetTouchpadTapSuppressionController()-> | 120 gesture_event_queue_.GetTouchpadTapSuppressionController()-> |
| 120 ShouldSuppressMouseUp()) | 121 ShouldSuppressMouseUp()) |
| 121 return; | 122 return; |
| 122 | 123 |
| 123 SendMouseEventImmediately(mouse_event); | 124 SendMouseEventImmediately(mouse_event); |
| 124 } | 125 } |
| 125 | 126 |
| 126 void InputRouterImpl::SendWheelEvent( | 127 void InputRouterImpl::SendWheelEvent( |
| 127 const MouseWheelEventWithLatencyInfo& wheel_event) { | 128 const MouseWheelEventWithLatencyInfo& wheel_event) { |
| 128 if (mouse_wheel_pending_) { | 129 wheel_event_queue_.QueueEvent(wheel_event); |
| 129 // If there's already a mouse wheel event waiting to be sent to the | |
| 130 // renderer, add the new deltas to that event. Not doing so (e.g., by | |
| 131 // dropping the old event, as for mouse moves) results in very slow | |
| 132 // scrolling on the Mac. | |
| 133 if (wheel_event.event.hasPreciseScrollingDeltas) | |
| 134 DCHECK(wheel_event.event.canScroll); | |
| 135 DCHECK(!(wheel_event.event.hasPreciseScrollingDeltas && | |
| 136 !wheel_event.event.canScroll)); | |
| 137 if (coalesced_mouse_wheel_events_.empty() || | |
| 138 (!coalesced_mouse_wheel_events_.empty() && | |
| 139 !coalesced_mouse_wheel_events_.back().CanCoalesceWith(wheel_event))) { | |
| 140 coalesced_mouse_wheel_events_.push_back(wheel_event); | |
| 141 } else { | |
| 142 coalesced_mouse_wheel_events_.back().CoalesceWith(wheel_event); | |
| 143 TRACE_EVENT_INSTANT2("input", "InputRouterImpl::CoalescedWheelEvent", | |
| 144 TRACE_EVENT_SCOPE_THREAD, | |
| 145 "total_dx", | |
| 146 coalesced_mouse_wheel_events_.back().event.deltaX, | |
| 147 "total_dy", | |
| 148 coalesced_mouse_wheel_events_.back().event.deltaY); | |
| 149 } | |
| 150 return; | |
| 151 } | |
| 152 | |
| 153 mouse_wheel_pending_ = true; | |
| 154 current_wheel_event_ = wheel_event; | |
| 155 | |
| 156 LOCAL_HISTOGRAM_COUNTS_100("Renderer.WheelQueueSize", | |
| 157 coalesced_mouse_wheel_events_.size()); | |
| 158 | |
| 159 FilterAndSendWebInputEvent(wheel_event.event, wheel_event.latency); | |
| 160 } | 130 } |
| 161 | 131 |
| 162 void InputRouterImpl::SendKeyboardEvent( | 132 void InputRouterImpl::SendKeyboardEvent( |
| 163 const NativeWebKeyboardEventWithLatencyInfo& key_event) { | 133 const NativeWebKeyboardEventWithLatencyInfo& key_event) { |
| 164 // Put all WebKeyboardEvent objects in a queue since we can't trust the | 134 // Put all WebKeyboardEvent objects in a queue since we can't trust the |
| 165 // renderer and we need to give something to the HandleKeyboardEvent | 135 // renderer and we need to give something to the HandleKeyboardEvent |
| 166 // handler. | 136 // handler. |
| 167 key_queue_.push_back(key_event); | 137 key_queue_.push_back(key_event); |
| 168 LOCAL_HISTOGRAM_COUNTS_100("Renderer.KeyboardQueueSize", key_queue_.size()); | 138 LOCAL_HISTOGRAM_COUNTS_100("Renderer.KeyboardQueueSize", key_queue_.size()); |
| 169 | 139 |
| (...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 243 } | 213 } |
| 244 | 214 |
| 245 void InputRouterImpl::NotifySiteIsMobileOptimized(bool is_mobile_optimized) { | 215 void InputRouterImpl::NotifySiteIsMobileOptimized(bool is_mobile_optimized) { |
| 246 touch_event_queue_.SetIsMobileOptimizedSite(is_mobile_optimized); | 216 touch_event_queue_.SetIsMobileOptimizedSite(is_mobile_optimized); |
| 247 } | 217 } |
| 248 | 218 |
| 249 bool InputRouterImpl::HasPendingEvents() const { | 219 bool InputRouterImpl::HasPendingEvents() const { |
| 250 return !touch_event_queue_.empty() || | 220 return !touch_event_queue_.empty() || |
| 251 !gesture_event_queue_.empty() || | 221 !gesture_event_queue_.empty() || |
| 252 !key_queue_.empty() || | 222 !key_queue_.empty() || |
| 223 !wheel_event_queue_.empty() || |
| 253 mouse_move_pending_ || | 224 mouse_move_pending_ || |
| 254 mouse_wheel_pending_ || | |
| 255 select_message_pending_ || | 225 select_message_pending_ || |
| 256 move_caret_pending_ || | 226 move_caret_pending_ || |
| 257 active_renderer_fling_count_ > 0; | 227 active_renderer_fling_count_ > 0; |
| 258 } | 228 } |
| 259 | 229 |
| 260 bool InputRouterImpl::OnMessageReceived(const IPC::Message& message) { | 230 bool InputRouterImpl::OnMessageReceived(const IPC::Message& message) { |
| 261 bool handled = true; | 231 bool handled = true; |
| 262 IPC_BEGIN_MESSAGE_MAP(InputRouterImpl, message) | 232 IPC_BEGIN_MESSAGE_MAP(InputRouterImpl, message) |
| 263 IPC_MESSAGE_HANDLER(InputHostMsg_HandleInputEvent_ACK, OnInputEventAck) | 233 IPC_MESSAGE_HANDLER(InputHostMsg_HandleInputEvent_ACK, OnInputEventAck) |
| 264 IPC_MESSAGE_HANDLER(InputHostMsg_DidOverscroll, OnDidOverscroll) | 234 IPC_MESSAGE_HANDLER(InputHostMsg_DidOverscroll, OnDidOverscroll) |
| (...skipping 24 matching lines...) Expand all Loading... |
| 289 ack_handler_->OnTouchEventAck(event, ack_result); | 259 ack_handler_->OnTouchEventAck(event, ack_result); |
| 290 } | 260 } |
| 291 | 261 |
| 292 void InputRouterImpl::OnGestureEventAck( | 262 void InputRouterImpl::OnGestureEventAck( |
| 293 const GestureEventWithLatencyInfo& event, | 263 const GestureEventWithLatencyInfo& event, |
| 294 InputEventAckState ack_result) { | 264 InputEventAckState ack_result) { |
| 295 touch_event_queue_.OnGestureEventAck(event, ack_result); | 265 touch_event_queue_.OnGestureEventAck(event, ack_result); |
| 296 ack_handler_->OnGestureEventAck(event, ack_result); | 266 ack_handler_->OnGestureEventAck(event, ack_result); |
| 297 } | 267 } |
| 298 | 268 |
| 269 void InputRouterImpl::SendWheelEventImmediately( |
| 270 const MouseWheelEventWithLatencyInfo& wheel_event) { |
| 271 FilterAndSendWebInputEvent(wheel_event.event, wheel_event.latency); |
| 272 } |
| 273 |
| 274 void InputRouterImpl::OnWheelEventAck( |
| 275 const MouseWheelEventWithLatencyInfo& event, |
| 276 InputEventAckState ack_result) { |
| 277 ack_handler_->OnWheelEventAck(event, ack_result); |
| 278 } |
| 279 |
| 280 void InputRouterImpl::SetNeedsFlush() { |
| 281 client_->SetNeedsFlushInput(); |
| 282 } |
| 283 |
| 299 bool InputRouterImpl::SendSelectMessage( | 284 bool InputRouterImpl::SendSelectMessage( |
| 300 scoped_ptr<IPC::Message> message) { | 285 scoped_ptr<IPC::Message> message) { |
| 301 DCHECK(message->type() == InputMsg_SelectRange::ID || | 286 DCHECK(message->type() == InputMsg_SelectRange::ID || |
| 302 message->type() == InputMsg_MoveRangeSelectionExtent::ID); | 287 message->type() == InputMsg_MoveRangeSelectionExtent::ID); |
| 303 | 288 |
| 304 // TODO(jdduke): Factor out common logic between selection and caret-related | 289 // TODO(jdduke): Factor out common logic between selection and caret-related |
| 305 // IPC messages. | 290 // IPC messages. |
| 306 if (select_message_pending_) { | 291 if (select_message_pending_) { |
| 307 if (!pending_select_messages_.empty() && | 292 if (!pending_select_messages_.empty() && |
| 308 pending_select_messages_.back()->type() == message->type()) { | 293 pending_select_messages_.back()->type() == message->type()) { |
| (...skipping 265 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 574 if (next_mouse_move_) { | 559 if (next_mouse_move_) { |
| 575 DCHECK(next_mouse_move_->event.type == WebInputEvent::MouseMove); | 560 DCHECK(next_mouse_move_->event.type == WebInputEvent::MouseMove); |
| 576 scoped_ptr<MouseEventWithLatencyInfo> next_mouse_move | 561 scoped_ptr<MouseEventWithLatencyInfo> next_mouse_move |
| 577 = next_mouse_move_.Pass(); | 562 = next_mouse_move_.Pass(); |
| 578 SendMouseEvent(*next_mouse_move); | 563 SendMouseEvent(*next_mouse_move); |
| 579 } | 564 } |
| 580 } | 565 } |
| 581 | 566 |
| 582 void InputRouterImpl::ProcessWheelAck(InputEventAckState ack_result, | 567 void InputRouterImpl::ProcessWheelAck(InputEventAckState ack_result, |
| 583 const ui::LatencyInfo& latency) { | 568 const ui::LatencyInfo& latency) { |
| 584 // TODO(miletus): Add renderer side latency to each uncoalesced mouse | 569 wheel_event_queue_.ProcessWheelAck(ack_result, latency); |
| 585 // wheel event and add terminal component to each of them. | |
| 586 current_wheel_event_.latency.AddNewLatencyFrom(latency); | |
| 587 | |
| 588 // Process the unhandled wheel event here before calling SendWheelEvent() | |
| 589 // since it will mutate current_wheel_event_. | |
| 590 ack_handler_->OnWheelEventAck(current_wheel_event_, ack_result); | |
| 591 | |
| 592 // Mark the wheel event complete only after the ACKs have been handled above. | |
| 593 // For example, ACKing the GesturePinchUpdate could cause another | |
| 594 // GesturePinchUpdate to be sent, which should queue a wheel event rather than | |
| 595 // send it immediately. | |
| 596 mouse_wheel_pending_ = false; | |
| 597 | |
| 598 // Send the next (coalesced or synthetic) mouse wheel event. | |
| 599 if (!coalesced_mouse_wheel_events_.empty()) { | |
| 600 MouseWheelEventWithLatencyInfo next_wheel_event = | |
| 601 coalesced_mouse_wheel_events_.front(); | |
| 602 coalesced_mouse_wheel_events_.pop_front(); | |
| 603 SendWheelEvent(next_wheel_event); | |
| 604 } | |
| 605 } | 570 } |
| 606 | 571 |
| 607 void InputRouterImpl::ProcessGestureAck(WebInputEvent::Type type, | 572 void InputRouterImpl::ProcessGestureAck(WebInputEvent::Type type, |
| 608 InputEventAckState ack_result, | 573 InputEventAckState ack_result, |
| 609 const ui::LatencyInfo& latency) { | 574 const ui::LatencyInfo& latency) { |
| 610 if (type == blink::WebInputEvent::GestureFlingStart && | 575 if (type == blink::WebInputEvent::GestureFlingStart && |
| 611 ack_result == INPUT_EVENT_ACK_STATE_CONSUMED) { | 576 ack_result == INPUT_EVENT_ACK_STATE_CONSUMED) { |
| 612 ++active_renderer_fling_count_; | 577 ++active_renderer_fling_count_; |
| 613 } | 578 } |
| 614 | 579 |
| (...skipping 23 matching lines...) Expand all Loading... |
| 638 return; | 603 return; |
| 639 | 604 |
| 640 if (HasPendingEvents()) | 605 if (HasPendingEvents()) |
| 641 return; | 606 return; |
| 642 | 607 |
| 643 flush_requested_ = false; | 608 flush_requested_ = false; |
| 644 client_->DidFlushAllInput(); | 609 client_->DidFlushAllInput(); |
| 645 } | 610 } |
| 646 | 611 |
| 647 } // namespace content | 612 } // namespace content |
| OLD | NEW |