Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(801)

Side by Side Diff: content/browser/renderer_host/input/input_router_impl.cc

Issue 1405613002: Support vsync-aligned wheel event dispatch (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@input_cleanup_todo
Patch Set: Rebase Created 5 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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
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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698