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 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 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 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 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 118 InputRouterImpl::~InputRouterImpl() {} 119 120 void InputRouterImpl::Flush() {} 121 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 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 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 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 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 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. 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 244 void InputRouterImpl::SendTouchEventImmediately( 245 const TouchEventWithLatencyInfo& touch_event) { 246 FilterAndSendWebInputEvent(touch_event.event, touch_event.latency, false); 247 } 248 249 void InputRouterImpl::SendGestureEventImmediately( 250 const GestureEventWithLatencyInfo& gesture_event) { 251 FilterAndSendWebInputEvent(gesture_event.event, gesture_event.latency, false); 252 } 253 254 const NativeWebKeyboardEvent* InputRouterImpl::GetLastKeyboardEvent() const { 255 if (key_queue_.empty()) 256 return NULL; 257 return &key_queue_.front(); 258 } 259 260 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 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 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 296 void InputRouterImpl::OnTouchEventAck(const TouchEventWithLatencyInfo& event, 297 InputEventAckState ack_result) { 298 ack_handler_->OnTouchEventAck(event, ack_result); 299 } 300 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 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 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 330 bool InputRouterImpl::Send(IPC::Message* message) { 331 return sender_->Send(message); 332 } 333 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 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 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 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 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 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 488 void InputRouterImpl::OnMsgMoveCaretAck() { 489 move_caret_pending_ = false; 490 if (next_move_caret_) 491 SendMoveCaret(next_move_caret_.Pass()); 492 } 493 494 void InputRouterImpl::OnSelectRangeAck() { 495 select_range_pending_ = false; 496 if (next_selection_range_) 497 SendSelectRange(next_selection_range_.Pass()); 498 } 499 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 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 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 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 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 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 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 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 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 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 724 bool InputRouterImpl::IsInOverscrollGesture() const { 725 OverscrollController* controller = client_->GetOverscrollController(); 726 return controller && controller->overscroll_mode() != OVERSCROLL_NONE; 727 } 728 729 } // namespace content 730