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
3 // found in the LICENSE file.
4
5 #include "content/browser/renderer_host/input/input_router_impl.h"
6
7 #include "base/auto_reset.h"
8 #include "base/command_line.h"
9 #include "base/metrics/histogram.h"
10 #include "base/strings/string_number_conversions.h"
11 #include "content/browser/renderer_host/input/gesture_event_filter.h"
12 #include "content/browser/renderer_host/input/input_ack_handler.h"
13 #include "content/browser/renderer_host/input/input_router_client.h"
14 #include "content/browser/renderer_host/input/touch_event_queue.h"
15 #include "content/browser/renderer_host/input/touchpad_tap_suppression_controller.h"
16 #include "content/browser/renderer_host/overscroll_controller.h"
17 #include "content/common/content_constants_internal.h"
18 #include "content/common/edit_command.h"
19 #include "content/common/input/touch_action.h"
20 #include "content/common/input/web_input_event_traits.h"
21 #include "content/common/input_messages.h"
22 #include "content/common/view_messages.h"
23 #include "content/port/common/input_event_ack_state.h"
24 #include "content/public/browser/notification_service.h"
25 #include "content/public/browser/notification_types.h"
26 #include "content/public/browser/user_metrics.h"
27 #include "content/public/common/content_switches.h"
28 #include "ipc/ipc_sender.h"
29 #include "ui/events/event.h"
30 #include "ui/events/keycodes/keyboard_codes.h"
31
32 using base::Time;
33 using base::TimeDelta;
34 using base::TimeTicks;
35 using blink::WebGestureEvent;
36 using blink::WebInputEvent;
37 using blink::WebKeyboardEvent;
38 using blink::WebMouseEvent;
39 using blink::WebMouseWheelEvent;
40
41 namespace content {
42 namespace {
43
GetTouchAckTimeoutDelayMs(size_t * touch_ack_timeout_delay_ms)44 bool GetTouchAckTimeoutDelayMs(size_t* touch_ack_timeout_delay_ms) {
45 CommandLine* parsed_command_line = CommandLine::ForCurrentProcess();
46 if (!parsed_command_line->HasSwitch(switches::kTouchAckTimeoutDelayMs))
47 return false;
48
49 std::string timeout_string = parsed_command_line->GetSwitchValueASCII(
50 switches::kTouchAckTimeoutDelayMs);
51 size_t timeout_value;
52 if (!base::StringToSizeT(timeout_string, &timeout_value))
53 return false;
54
55 *touch_ack_timeout_delay_ms = timeout_value;
56 return true;
57 }
58
MakeGestureEvent(WebInputEvent::Type type,double timestamp_seconds,int x,int y,int modifiers,const ui::LatencyInfo latency)59 GestureEventWithLatencyInfo MakeGestureEvent(WebInputEvent::Type type,
60 double timestamp_seconds,
61 int x,
62 int y,
63 int modifiers,
64 const ui::LatencyInfo latency) {
65 WebGestureEvent result;
66
67 result.type = type;
68 result.x = x;
69 result.y = y;
70 result.sourceDevice = WebGestureEvent::Touchscreen;
71 result.timeStampSeconds = timestamp_seconds;
72 result.modifiers = modifiers;
73
74 return GestureEventWithLatencyInfo(result, latency);
75 }
76
GetEventAckName(InputEventAckState ack_result)77 const char* GetEventAckName(InputEventAckState ack_result) {
78 switch(ack_result) {
79 case INPUT_EVENT_ACK_STATE_UNKNOWN: return "UNKNOWN";
80 case INPUT_EVENT_ACK_STATE_CONSUMED: return "CONSUMED";
81 case INPUT_EVENT_ACK_STATE_NOT_CONSUMED: return "NOT_CONSUMED";
82 case INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS: return "NO_CONSUMER_EXISTS";
83 case INPUT_EVENT_ACK_STATE_IGNORED: return "IGNORED";
84 }
85 DLOG(WARNING) << "Unhandled InputEventAckState in GetEventAckName.";
86 return "";
87 }
88
89 } // namespace
90
InputRouterImpl(IPC::Sender * sender,InputRouterClient * client,InputAckHandler * ack_handler,int routing_id)91 InputRouterImpl::InputRouterImpl(IPC::Sender* sender,
92 InputRouterClient* client,
93 InputAckHandler* ack_handler,
94 int routing_id)
95 : sender_(sender),
96 client_(client),
97 ack_handler_(ack_handler),
98 routing_id_(routing_id),
99 select_range_pending_(false),
100 move_caret_pending_(false),
101 mouse_move_pending_(false),
102 mouse_wheel_pending_(false),
103 has_touch_handler_(false),
104 touch_ack_timeout_enabled_(false),
105 touch_ack_timeout_delay_ms_(std::numeric_limits<size_t>::max()),
106 current_ack_source_(ACK_SOURCE_NONE),
107 gesture_event_filter_(new GestureEventFilter(this, this)) {
108 DCHECK(sender);
109 DCHECK(client);
110 DCHECK(ack_handler);
111 touch_event_queue_.reset(new TouchEventQueue(this));
112 touch_ack_timeout_enabled_ =
113 GetTouchAckTimeoutDelayMs(&touch_ack_timeout_delay_ms_);
114 touch_event_queue_->SetAckTimeoutEnabled(touch_ack_timeout_enabled_,
115 touch_ack_timeout_delay_ms_);
116 }
117
~InputRouterImpl()118 InputRouterImpl::~InputRouterImpl() {}
119
Flush()120 void InputRouterImpl::Flush() {}
121
SendInput(scoped_ptr<IPC::Message> message)122 bool InputRouterImpl::SendInput(scoped_ptr<IPC::Message> message) {
123 DCHECK(IPC_MESSAGE_ID_CLASS(message->type()) == InputMsgStart);
124 switch (message->type()) {
125 // Check for types that require an ACK.
126 case InputMsg_SelectRange::ID:
127 return SendSelectRange(message.Pass());
128 case InputMsg_MoveCaret::ID:
129 return SendMoveCaret(message.Pass());
130 case InputMsg_HandleInputEvent::ID:
131 NOTREACHED() << "WebInputEvents should never be sent via SendInput.";
132 return false;
133 default:
134 return Send(message.release());
135 }
136 }
137
SendMouseEvent(const MouseEventWithLatencyInfo & mouse_event)138 void InputRouterImpl::SendMouseEvent(
139 const MouseEventWithLatencyInfo& mouse_event) {
140 // Order is important here; we need to convert all MouseEvents before they
141 // propagate further, e.g., to the tap suppression controller.
142 if (CommandLine::ForCurrentProcess()->HasSwitch(
143 switches::kSimulateTouchScreenWithMouse)) {
144 SimulateTouchGestureWithMouse(mouse_event);
145 return;
146 }
147
148 if (mouse_event.event.type == WebInputEvent::MouseDown &&
149 gesture_event_filter_->GetTouchpadTapSuppressionController()->
150 ShouldDeferMouseDown(mouse_event))
151 return;
152 if (mouse_event.event.type == WebInputEvent::MouseUp &&
153 gesture_event_filter_->GetTouchpadTapSuppressionController()->
154 ShouldSuppressMouseUp())
155 return;
156
157 SendMouseEventImmediately(mouse_event);
158 }
159
SendWheelEvent(const MouseWheelEventWithLatencyInfo & wheel_event)160 void InputRouterImpl::SendWheelEvent(
161 const MouseWheelEventWithLatencyInfo& wheel_event) {
162 // If there's already a mouse wheel event waiting to be sent to the renderer,
163 // add the new deltas to that event. Not doing so (e.g., by dropping the old
164 // event, as for mouse moves) results in very slow scrolling on the Mac (on
165 // which many, very small wheel events are sent).
166 if (mouse_wheel_pending_) {
167 if (coalesced_mouse_wheel_events_.empty() ||
168 !coalesced_mouse_wheel_events_.back().CanCoalesceWith(wheel_event)) {
169 coalesced_mouse_wheel_events_.push_back(wheel_event);
170 } else {
171 coalesced_mouse_wheel_events_.back().CoalesceWith(wheel_event);
172 }
173 return;
174 }
175 mouse_wheel_pending_ = true;
176 current_wheel_event_ = wheel_event;
177
178 HISTOGRAM_COUNTS_100("Renderer.WheelQueueSize",
179 coalesced_mouse_wheel_events_.size());
180
181 FilterAndSendWebInputEvent(wheel_event.event, wheel_event.latency, false);
182 }
183
SendKeyboardEvent(const NativeWebKeyboardEvent & key_event,const ui::LatencyInfo & latency_info,bool is_keyboard_shortcut)184 void InputRouterImpl::SendKeyboardEvent(const NativeWebKeyboardEvent& key_event,
185 const ui::LatencyInfo& latency_info,
186 bool is_keyboard_shortcut) {
187 // Put all WebKeyboardEvent objects in a queue since we can't trust the
188 // renderer and we need to give something to the HandleKeyboardEvent
189 // handler.
190 key_queue_.push_back(key_event);
191 HISTOGRAM_COUNTS_100("Renderer.KeyboardQueueSize", key_queue_.size());
192
193 gesture_event_filter_->FlingHasBeenHalted();
194
195 // Only forward the non-native portions of our event.
196 FilterAndSendWebInputEvent(key_event, latency_info, is_keyboard_shortcut);
197 }
198
SendGestureEvent(const GestureEventWithLatencyInfo & gesture_event)199 void InputRouterImpl::SendGestureEvent(
200 const GestureEventWithLatencyInfo& gesture_event) {
201 if (touch_action_filter_.FilterGestureEvent(gesture_event.event))
202 return;
203
204 touch_event_queue_->OnGestureScrollEvent(gesture_event);
205
206 if (!IsInOverscrollGesture() &&
207 !gesture_event_filter_->ShouldForward(gesture_event)) {
208 OverscrollController* controller = client_->GetOverscrollController();
209 if (controller)
210 controller->DiscardingGestureEvent(gesture_event.event);
211 return;
212 }
213
214 FilterAndSendWebInputEvent(gesture_event.event, gesture_event.latency, false);
215 }
216
SendTouchEvent(const TouchEventWithLatencyInfo & touch_event)217 void InputRouterImpl::SendTouchEvent(
218 const TouchEventWithLatencyInfo& touch_event) {
219 touch_event_queue_->QueueEvent(touch_event);
220 }
221
222 // Forwards MouseEvent without passing it through
223 // TouchpadTapSuppressionController.
SendMouseEventImmediately(const MouseEventWithLatencyInfo & mouse_event)224 void InputRouterImpl::SendMouseEventImmediately(
225 const MouseEventWithLatencyInfo& mouse_event) {
226 // Avoid spamming the renderer with mouse move events. It is important
227 // to note that WM_MOUSEMOVE events are anyways synthetic, but since our
228 // thread is able to rapidly consume WM_MOUSEMOVE events, we may get way
229 // more WM_MOUSEMOVE events than we wish to send to the renderer.
230 if (mouse_event.event.type == WebInputEvent::MouseMove) {
231 if (mouse_move_pending_) {
232 if (!next_mouse_move_)
233 next_mouse_move_.reset(new MouseEventWithLatencyInfo(mouse_event));
234 else
235 next_mouse_move_->CoalesceWith(mouse_event);
236 return;
237 }
238 mouse_move_pending_ = true;
239 }
240
241 FilterAndSendWebInputEvent(mouse_event.event, mouse_event.latency, false);
242 }
243
SendTouchEventImmediately(const TouchEventWithLatencyInfo & touch_event)244 void InputRouterImpl::SendTouchEventImmediately(
245 const TouchEventWithLatencyInfo& touch_event) {
246 FilterAndSendWebInputEvent(touch_event.event, touch_event.latency, false);
247 }
248
SendGestureEventImmediately(const GestureEventWithLatencyInfo & gesture_event)249 void InputRouterImpl::SendGestureEventImmediately(
250 const GestureEventWithLatencyInfo& gesture_event) {
251 FilterAndSendWebInputEvent(gesture_event.event, gesture_event.latency, false);
252 }
253
GetLastKeyboardEvent() const254 const NativeWebKeyboardEvent* InputRouterImpl::GetLastKeyboardEvent() const {
255 if (key_queue_.empty())
256 return NULL;
257 return &key_queue_.front();
258 }
259
ShouldForwardTouchEvent() const260 bool InputRouterImpl::ShouldForwardTouchEvent() const {
261 // Always send a touch event if the renderer has a touch-event handler. It is
262 // possible that a renderer stops listening to touch-events while there are
263 // still events in the touch-queue. In such cases, the new events should still
264 // get into the queue.
265 return has_touch_handler_ || !touch_event_queue_->empty();
266 }
267
OnViewUpdated(int view_flags)268 void InputRouterImpl::OnViewUpdated(int view_flags) {
269 bool fixed_page_scale = (view_flags & FIXED_PAGE_SCALE) != 0;
270 bool mobile_viewport = (view_flags & MOBILE_VIEWPORT) != 0;
271 touch_event_queue_->SetAckTimeoutEnabled(
272 touch_ack_timeout_enabled_ && !(fixed_page_scale || mobile_viewport),
273 touch_ack_timeout_delay_ms_);
274 }
275
OnMessageReceived(const IPC::Message & message)276 bool InputRouterImpl::OnMessageReceived(const IPC::Message& message) {
277 bool handled = true;
278 bool message_is_ok = true;
279 IPC_BEGIN_MESSAGE_MAP_EX(InputRouterImpl, message, message_is_ok)
280 IPC_MESSAGE_HANDLER(InputHostMsg_HandleInputEvent_ACK, OnInputEventAck)
281 IPC_MESSAGE_HANDLER(ViewHostMsg_MoveCaret_ACK, OnMsgMoveCaretAck)
282 IPC_MESSAGE_HANDLER(ViewHostMsg_SelectRange_ACK, OnSelectRangeAck)
283 IPC_MESSAGE_HANDLER(ViewHostMsg_HasTouchEventHandlers,
284 OnHasTouchEventHandlers)
285 IPC_MESSAGE_HANDLER(InputHostMsg_SetTouchAction,
286 OnSetTouchAction)
287 IPC_MESSAGE_UNHANDLED(handled = false)
288 IPC_END_MESSAGE_MAP()
289
290 if (!message_is_ok)
291 ack_handler_->OnUnexpectedEventAck(InputAckHandler::BAD_ACK_MESSAGE);
292
293 return handled;
294 }
295
OnTouchEventAck(const TouchEventWithLatencyInfo & event,InputEventAckState ack_result)296 void InputRouterImpl::OnTouchEventAck(const TouchEventWithLatencyInfo& event,
297 InputEventAckState ack_result) {
298 ack_handler_->OnTouchEventAck(event, ack_result);
299 }
300
OnGestureEventAck(const GestureEventWithLatencyInfo & event,InputEventAckState ack_result)301 void InputRouterImpl::OnGestureEventAck(
302 const GestureEventWithLatencyInfo& event,
303 InputEventAckState ack_result) {
304 ProcessAckForOverscroll(event.event, ack_result);
305 ack_handler_->OnGestureEventAck(event, ack_result);
306 }
307
SendSelectRange(scoped_ptr<IPC::Message> message)308 bool InputRouterImpl::SendSelectRange(scoped_ptr<IPC::Message> message) {
309 DCHECK(message->type() == InputMsg_SelectRange::ID);
310 if (select_range_pending_) {
311 next_selection_range_ = message.Pass();
312 return true;
313 }
314
315 select_range_pending_ = true;
316 return Send(message.release());
317 }
318
SendMoveCaret(scoped_ptr<IPC::Message> message)319 bool InputRouterImpl::SendMoveCaret(scoped_ptr<IPC::Message> message) {
320 DCHECK(message->type() == InputMsg_MoveCaret::ID);
321 if (move_caret_pending_) {
322 next_move_caret_ = message.Pass();
323 return true;
324 }
325
326 move_caret_pending_ = true;
327 return Send(message.release());
328 }
329
Send(IPC::Message * message)330 bool InputRouterImpl::Send(IPC::Message* message) {
331 return sender_->Send(message);
332 }
333
FilterAndSendWebInputEvent(const WebInputEvent & input_event,const ui::LatencyInfo & latency_info,bool is_keyboard_shortcut)334 void InputRouterImpl::FilterAndSendWebInputEvent(
335 const WebInputEvent& input_event,
336 const ui::LatencyInfo& latency_info,
337 bool is_keyboard_shortcut) {
338 TRACE_EVENT1("input",
339 "InputRouterImpl::FilterAndSendWebInputEvent",
340 "type",
341 WebInputEventTraits::GetName(input_event.type));
342
343 // Transmit any pending wheel events on a non-wheel event. This ensures that
344 // final PhaseEnded wheel event is received, which is necessary to terminate
345 // rubber-banding, for example.
346 if (input_event.type != WebInputEvent::MouseWheel) {
347 WheelEventQueue mouse_wheel_events;
348 mouse_wheel_events.swap(coalesced_mouse_wheel_events_);
349 for (size_t i = 0; i < mouse_wheel_events.size(); ++i) {
350 OfferToHandlers(mouse_wheel_events[i].event,
351 mouse_wheel_events[i].latency,
352 false);
353 }
354 }
355
356 // Any input event cancels a pending mouse move event.
357 next_mouse_move_.reset();
358
359 OfferToHandlers(input_event, latency_info, is_keyboard_shortcut);
360 }
361
OfferToHandlers(const WebInputEvent & input_event,const ui::LatencyInfo & latency_info,bool is_keyboard_shortcut)362 void InputRouterImpl::OfferToHandlers(const WebInputEvent& input_event,
363 const ui::LatencyInfo& latency_info,
364 bool is_keyboard_shortcut) {
365 if (OfferToOverscrollController(input_event, latency_info))
366 return;
367
368 if (OfferToClient(input_event, latency_info))
369 return;
370
371 OfferToRenderer(input_event, latency_info, is_keyboard_shortcut);
372
373 // If we don't care about the ack disposition, send the ack immediately.
374 if (WebInputEventTraits::IgnoresAckDisposition(input_event.type)) {
375 ProcessInputEventAck(input_event.type,
376 INPUT_EVENT_ACK_STATE_IGNORED,
377 latency_info,
378 IGNORING_DISPOSITION);
379 }
380 }
381
OfferToOverscrollController(const WebInputEvent & input_event,const ui::LatencyInfo & latency_info)382 bool InputRouterImpl::OfferToOverscrollController(
383 const WebInputEvent& input_event,
384 const ui::LatencyInfo& latency_info) {
385 OverscrollController* controller = client_->GetOverscrollController();
386 if (!controller)
387 return false;
388
389 OverscrollController::Disposition disposition =
390 controller->DispatchEvent(input_event, latency_info);
391
392 bool consumed = disposition == OverscrollController::CONSUMED;
393
394 if (disposition == OverscrollController::SHOULD_FORWARD_TO_GESTURE_FILTER) {
395 DCHECK(WebInputEvent::isGestureEventType(input_event.type));
396 const blink::WebGestureEvent& gesture_event =
397 static_cast<const blink::WebGestureEvent&>(input_event);
398 // An ACK is expected for the event, so mark it as consumed.
399 consumed = !gesture_event_filter_->ShouldForward(
400 GestureEventWithLatencyInfo(gesture_event, latency_info));
401 }
402
403 if (consumed) {
404 InputEventAckState overscroll_ack =
405 WebInputEvent::isTouchEventType(input_event.type) ?
406 INPUT_EVENT_ACK_STATE_NOT_CONSUMED : INPUT_EVENT_ACK_STATE_CONSUMED;
407 ProcessInputEventAck(input_event.type,
408 overscroll_ack,
409 latency_info,
410 OVERSCROLL_CONTROLLER);
411 // WARNING: |this| may be deleted at this point.
412 }
413
414 return consumed;
415 }
416
OfferToClient(const WebInputEvent & input_event,const ui::LatencyInfo & latency_info)417 bool InputRouterImpl::OfferToClient(const WebInputEvent& input_event,
418 const ui::LatencyInfo& latency_info) {
419 bool consumed = false;
420
421 InputEventAckState filter_ack =
422 client_->FilterInputEvent(input_event, latency_info);
423 switch (filter_ack) {
424 case INPUT_EVENT_ACK_STATE_CONSUMED:
425 case INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS:
426 // Send the ACK and early exit.
427 next_mouse_move_.reset();
428 ProcessInputEventAck(input_event.type, filter_ack, latency_info, CLIENT);
429 // WARNING: |this| may be deleted at this point.
430 consumed = true;
431 break;
432 case INPUT_EVENT_ACK_STATE_UNKNOWN:
433 // Simply drop the event.
434 consumed = true;
435 break;
436 default:
437 break;
438 }
439
440 return consumed;
441 }
442
OfferToRenderer(const WebInputEvent & input_event,const ui::LatencyInfo & latency_info,bool is_keyboard_shortcut)443 bool InputRouterImpl::OfferToRenderer(const WebInputEvent& input_event,
444 const ui::LatencyInfo& latency_info,
445 bool is_keyboard_shortcut) {
446 input_event_start_time_ = TimeTicks::Now();
447 if (Send(new InputMsg_HandleInputEvent(
448 routing_id(), &input_event, latency_info, is_keyboard_shortcut))) {
449 // Only increment the event count if we require an ACK for |input_event|.
450 if (!WebInputEventTraits::IgnoresAckDisposition(input_event.type))
451 client_->IncrementInFlightEventCount();
452 return true;
453 }
454 return false;
455 }
456
OnInputEventAck(WebInputEvent::Type event_type,InputEventAckState ack_result,const ui::LatencyInfo & latency_info)457 void InputRouterImpl::OnInputEventAck(WebInputEvent::Type event_type,
458 InputEventAckState ack_result,
459 const ui::LatencyInfo& latency_info) {
460 // Log the time delta for processing an input event.
461 TimeDelta delta = TimeTicks::Now() - input_event_start_time_;
462 UMA_HISTOGRAM_TIMES("MPArch.IIR_InputEventDelta", delta);
463
464 // A synthetic ack will already have been sent for this event, and it will
465 // not have affected the in-flight event count.
466 if (WebInputEventTraits::IgnoresAckDisposition(event_type))
467 return;
468
469 client_->DecrementInFlightEventCount();
470
471 ProcessInputEventAck(event_type, ack_result, latency_info, RENDERER);
472 // WARNING: |this| may be deleted at this point.
473
474 // This is used only for testing, and the other end does not use the
475 // source object. On linux, specifying
476 // Source<RenderWidgetHost> results in a very strange
477 // runtime error in the epilogue of the enclosing
478 // (ProcessInputEventAck) method, but not on other platforms; using
479 // 'void' instead is just as safe (since NotificationSource
480 // is not actually typesafe) and avoids this error.
481 int type = static_cast<int>(event_type);
482 NotificationService::current()->Notify(
483 NOTIFICATION_RENDER_WIDGET_HOST_DID_RECEIVE_INPUT_EVENT_ACK,
484 Source<void>(this),
485 Details<int>(&type));
486 }
487
OnMsgMoveCaretAck()488 void InputRouterImpl::OnMsgMoveCaretAck() {
489 move_caret_pending_ = false;
490 if (next_move_caret_)
491 SendMoveCaret(next_move_caret_.Pass());
492 }
493
OnSelectRangeAck()494 void InputRouterImpl::OnSelectRangeAck() {
495 select_range_pending_ = false;
496 if (next_selection_range_)
497 SendSelectRange(next_selection_range_.Pass());
498 }
499
OnHasTouchEventHandlers(bool has_handlers)500 void InputRouterImpl::OnHasTouchEventHandlers(bool has_handlers) {
501 if (has_touch_handler_ == has_handlers)
502 return;
503 has_touch_handler_ = has_handlers;
504 if (!has_handlers)
505 touch_event_queue_->FlushQueue();
506 client_->OnHasTouchEventHandlers(has_handlers);
507 }
508
OnSetTouchAction(content::TouchAction touch_action)509 void InputRouterImpl::OnSetTouchAction(
510 content::TouchAction touch_action) {
511 // Synthetic touchstart events should get filtered out in RenderWidget.
512 DCHECK(touch_event_queue_->IsPendingAckTouchStart());
513
514 touch_action_filter_.OnSetTouchAction(touch_action);
515 }
516
ProcessInputEventAck(WebInputEvent::Type event_type,InputEventAckState ack_result,const ui::LatencyInfo & latency_info,AckSource ack_source)517 void InputRouterImpl::ProcessInputEventAck(
518 WebInputEvent::Type event_type,
519 InputEventAckState ack_result,
520 const ui::LatencyInfo& latency_info,
521 AckSource ack_source) {
522 TRACE_EVENT2("input", "InputRouterImpl::ProcessInputEventAck",
523 "type", WebInputEventTraits::GetName(event_type),
524 "ack", GetEventAckName(ack_result));
525
526 // Note: The keyboard ack must be treated carefully, as it may result in
527 // synchronous destruction of |this|. Handling immediately guards against
528 // future references to |this|, as with |auto_reset_current_ack_source| below.
529 if (WebInputEvent::isKeyboardEventType(event_type)) {
530 ProcessKeyboardAck(event_type, ack_result);
531 // WARNING: |this| may be deleted at this point.
532 return;
533 }
534
535 base::AutoReset<AckSource> auto_reset_current_ack_source(
536 ¤t_ack_source_, ack_source);
537
538 if (WebInputEvent::isMouseEventType(event_type)) {
539 ProcessMouseAck(event_type, ack_result);
540 } else if (event_type == WebInputEvent::MouseWheel) {
541 ProcessWheelAck(ack_result, latency_info);
542 } else if (WebInputEvent::isTouchEventType(event_type)) {
543 ProcessTouchAck(ack_result, latency_info);
544 } else if (WebInputEvent::isGestureEventType(event_type)) {
545 ProcessGestureAck(event_type, ack_result, latency_info);
546 } else if (event_type != WebInputEvent::Undefined) {
547 ack_handler_->OnUnexpectedEventAck(InputAckHandler::BAD_ACK_MESSAGE);
548 }
549 }
550
ProcessKeyboardAck(blink::WebInputEvent::Type type,InputEventAckState ack_result)551 void InputRouterImpl::ProcessKeyboardAck(blink::WebInputEvent::Type type,
552 InputEventAckState ack_result) {
553 if (key_queue_.empty()) {
554 ack_handler_->OnUnexpectedEventAck(InputAckHandler::UNEXPECTED_ACK);
555 } else if (key_queue_.front().type != type) {
556 // Something must be wrong. Clear the |key_queue_| and char event
557 // suppression so that we can resume from the error.
558 key_queue_.clear();
559 ack_handler_->OnUnexpectedEventAck(InputAckHandler::UNEXPECTED_EVENT_TYPE);
560 } else {
561 NativeWebKeyboardEvent front_item = key_queue_.front();
562 key_queue_.pop_front();
563
564 ack_handler_->OnKeyboardEventAck(front_item, ack_result);
565 // WARNING: This InputRouterImpl can be deallocated at this point
566 // (i.e. in the case of Ctrl+W, where the call to
567 // HandleKeyboardEvent destroys this InputRouterImpl).
568 // TODO(jdduke): crbug.com/274029 - Make ack-triggered shutdown async.
569 }
570 }
571
ProcessMouseAck(blink::WebInputEvent::Type type,InputEventAckState ack_result)572 void InputRouterImpl::ProcessMouseAck(blink::WebInputEvent::Type type,
573 InputEventAckState ack_result) {
574 if (type != WebInputEvent::MouseMove)
575 return;
576
577 mouse_move_pending_ = false;
578
579 if (next_mouse_move_) {
580 DCHECK(next_mouse_move_->event.type == WebInputEvent::MouseMove);
581 scoped_ptr<MouseEventWithLatencyInfo> next_mouse_move
582 = next_mouse_move_.Pass();
583 SendMouseEvent(*next_mouse_move);
584 }
585 }
586
ProcessWheelAck(InputEventAckState ack_result,const ui::LatencyInfo & latency)587 void InputRouterImpl::ProcessWheelAck(InputEventAckState ack_result,
588 const ui::LatencyInfo& latency) {
589 ProcessAckForOverscroll(current_wheel_event_.event, ack_result);
590
591 // TODO(miletus): Add renderer side latency to each uncoalesced mouse
592 // wheel event and add terminal component to each of them.
593 current_wheel_event_.latency.AddNewLatencyFrom(latency);
594 // Process the unhandled wheel event here before calling SendWheelEvent()
595 // since it will mutate current_wheel_event_.
596 ack_handler_->OnWheelEventAck(current_wheel_event_, ack_result);
597 mouse_wheel_pending_ = false;
598
599 // Now send the next (coalesced) mouse wheel event.
600 if (!coalesced_mouse_wheel_events_.empty()) {
601 MouseWheelEventWithLatencyInfo next_wheel_event =
602 coalesced_mouse_wheel_events_.front();
603 coalesced_mouse_wheel_events_.pop_front();
604 SendWheelEvent(next_wheel_event);
605 }
606 }
607
ProcessGestureAck(WebInputEvent::Type type,InputEventAckState ack_result,const ui::LatencyInfo & latency)608 void InputRouterImpl::ProcessGestureAck(WebInputEvent::Type type,
609 InputEventAckState ack_result,
610 const ui::LatencyInfo& latency) {
611 // If |ack_result| originated from the overscroll controller, only
612 // feed |gesture_event_filter_| the ack if it was expecting one.
613 if (current_ack_source_ == OVERSCROLL_CONTROLLER &&
614 !gesture_event_filter_->HasQueuedGestureEvents()) {
615 return;
616 }
617
618 // |gesture_event_filter_| will forward to OnGestureEventAck when appropriate.
619 gesture_event_filter_->ProcessGestureAck(ack_result, type, latency);
620 }
621
ProcessTouchAck(InputEventAckState ack_result,const ui::LatencyInfo & latency)622 void InputRouterImpl::ProcessTouchAck(
623 InputEventAckState ack_result,
624 const ui::LatencyInfo& latency) {
625 // |touch_event_queue_| will forward to OnTouchEventAck when appropriate.
626 touch_event_queue_->ProcessTouchAck(ack_result, latency);
627 }
628
ProcessAckForOverscroll(const WebInputEvent & event,InputEventAckState ack_result)629 void InputRouterImpl::ProcessAckForOverscroll(const WebInputEvent& event,
630 InputEventAckState ack_result) {
631 // Acks sent from the overscroll controller need not be fed back into the
632 // overscroll controller.
633 if (current_ack_source_ == OVERSCROLL_CONTROLLER)
634 return;
635
636 OverscrollController* controller = client_->GetOverscrollController();
637 if (!controller)
638 return;
639
640 controller->ReceivedEventACK(
641 event, (INPUT_EVENT_ACK_STATE_CONSUMED == ack_result));
642 }
643
SimulateTouchGestureWithMouse(const MouseEventWithLatencyInfo & event)644 void InputRouterImpl::SimulateTouchGestureWithMouse(
645 const MouseEventWithLatencyInfo& event) {
646 const WebMouseEvent& mouse_event = event.event;
647 int x = mouse_event.x, y = mouse_event.y;
648 float dx = mouse_event.movementX, dy = mouse_event.movementY;
649 static int startX = 0, startY = 0;
650
651 switch (mouse_event.button) {
652 case WebMouseEvent::ButtonLeft:
653 if (mouse_event.type == WebInputEvent::MouseDown) {
654 startX = x;
655 startY = y;
656 SendGestureEvent(MakeGestureEvent(
657 WebInputEvent::GestureScrollBegin, mouse_event.timeStampSeconds,
658 x, y, 0, event.latency));
659 }
660 if (dx != 0 || dy != 0) {
661 GestureEventWithLatencyInfo gesture_event = MakeGestureEvent(
662 WebInputEvent::GestureScrollUpdate, mouse_event.timeStampSeconds,
663 x, y, 0, event.latency);
664 gesture_event.event.data.scrollUpdate.deltaX = dx;
665 gesture_event.event.data.scrollUpdate.deltaY = dy;
666 SendGestureEvent(gesture_event);
667 }
668 if (mouse_event.type == WebInputEvent::MouseUp) {
669 SendGestureEvent(MakeGestureEvent(
670 WebInputEvent::GestureScrollEnd, mouse_event.timeStampSeconds,
671 x, y, 0, event.latency));
672 }
673 break;
674 case WebMouseEvent::ButtonMiddle:
675 if (mouse_event.type == WebInputEvent::MouseDown) {
676 startX = x;
677 startY = y;
678 SendGestureEvent(MakeGestureEvent(
679 WebInputEvent::GestureShowPress, mouse_event.timeStampSeconds,
680 x, y, 0, event.latency));
681 SendGestureEvent(MakeGestureEvent(
682 WebInputEvent::GestureTapDown, mouse_event.timeStampSeconds,
683 x, y, 0, event.latency));
684 }
685 if (mouse_event.type == WebInputEvent::MouseUp) {
686 SendGestureEvent(MakeGestureEvent(
687 WebInputEvent::GestureTap, mouse_event.timeStampSeconds,
688 x, y, 0, event.latency));
689 }
690 break;
691 case WebMouseEvent::ButtonRight:
692 if (mouse_event.type == WebInputEvent::MouseDown) {
693 startX = x;
694 startY = y;
695 SendGestureEvent(MakeGestureEvent(
696 WebInputEvent::GestureScrollBegin, mouse_event.timeStampSeconds,
697 x, y, 0, event.latency));
698 SendGestureEvent(MakeGestureEvent(
699 WebInputEvent::GesturePinchBegin, mouse_event.timeStampSeconds,
700 x, y, 0, event.latency));
701 }
702 if (dx != 0 || dy != 0) {
703 dx = pow(dy < 0 ? 0.998f : 1.002f, fabs(dy));
704 GestureEventWithLatencyInfo gesture_event = MakeGestureEvent(
705 WebInputEvent::GesturePinchUpdate, mouse_event.timeStampSeconds,
706 startX, startY, 0, event.latency);
707 gesture_event.event.data.pinchUpdate.scale = dx;
708 SendGestureEvent(gesture_event);
709 }
710 if (mouse_event.type == WebInputEvent::MouseUp) {
711 SendGestureEvent(MakeGestureEvent(
712 WebInputEvent::GesturePinchEnd, mouse_event.timeStampSeconds,
713 x, y, 0, event.latency));
714 SendGestureEvent(MakeGestureEvent(
715 WebInputEvent::GestureScrollEnd, mouse_event.timeStampSeconds,
716 x, y, 0, event.latency));
717 }
718 break;
719 case WebMouseEvent::ButtonNone:
720 break;
721 }
722 }
723
IsInOverscrollGesture() const724 bool InputRouterImpl::IsInOverscrollGesture() const {
725 OverscrollController* controller = client_->GetOverscrollController();
726 return controller && controller->overscroll_mode() != OVERSCROLL_NONE;
727 }
728
729 } // namespace content
730