• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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       &current_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