Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright 2016 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/render_widget_host_view_event_handler.h" | |
| 6 | |
| 7 #include "base/metrics/user_metrics_action.h" | |
| 8 #include "content/browser/renderer_host/input/touch_selection_controller_client_ aura.h" | |
| 9 #include "content/browser/renderer_host/overscroll_controller.h" | |
| 10 #include "content/browser/renderer_host/render_view_host_delegate.h" | |
| 11 #include "content/browser/renderer_host/render_view_host_delegate_view.h" | |
| 12 #include "content/browser/renderer_host/render_widget_host_input_event_router.h" | |
| 13 #include "content/browser/renderer_host/render_widget_host_view_aura.h" | |
| 14 #include "content/common/content_switches_internal.h" | |
| 15 #include "content/common/site_isolation_policy.h" | |
| 16 #include "content/public/browser/render_view_host.h" | |
| 17 #include "content/public/browser/render_widget_host.h" | |
| 18 #include "content/public/browser/user_metrics.h" | |
| 19 #include "ui/aura/client/cursor_client.h" | |
| 20 #include "ui/aura/client/focus_client.h" | |
| 21 #include "ui/aura/client/screen_position_client.h" | |
| 22 #include "ui/aura/window.h" | |
| 23 #include "ui/events/blink/blink_event_util.h" | |
| 24 #include "ui/events/blink/web_input_event.h" | |
| 25 #include "ui/touch_selection/touch_selection_controller.h" | |
| 26 #include "ui/wm/public/scoped_tooltip_disabler.h" | |
| 27 | |
| 28 #if defined(OS_WIN) | |
| 29 #include "content/browser/frame_host/render_frame_host_impl.h" | |
| 30 #include "content/public/common/context_menu_params.h" | |
| 31 #include "ui/aura/window_tree_host.h" | |
| 32 #include "ui/display/screen.h" | |
| 33 #endif // defined(OS_WIN) | |
| 34 | |
| 35 namespace { | |
| 36 | |
| 37 // In mouse lock mode, we need to prevent the (invisible) cursor from hitting | |
| 38 // the border of the view, in order to get valid movement information. However, | |
| 39 // forcing the cursor back to the center of the view after each mouse move | |
| 40 // doesn't work well. It reduces the frequency of useful mouse move messages | |
| 41 // significantly. Therefore, we move the cursor to the center of the view only | |
| 42 // if it approaches the border. |kMouseLockBorderPercentage| specifies the width | |
| 43 // of the border area, in percentage of the corresponding dimension. | |
| 44 const int kMouseLockBorderPercentage = 15; | |
| 45 | |
| 46 #if defined(OS_WIN) | |
| 47 // A callback function for EnumThreadWindows to enumerate and dismiss | |
| 48 // any owned popup windows. | |
| 49 BOOL CALLBACK DismissOwnedPopups(HWND window, LPARAM arg) { | |
| 50 const HWND toplevel_hwnd = reinterpret_cast<HWND>(arg); | |
| 51 | |
| 52 if (::IsWindowVisible(window)) { | |
| 53 const HWND owner = ::GetWindow(window, GW_OWNER); | |
| 54 if (toplevel_hwnd == owner) { | |
| 55 ::PostMessage(window, WM_CANCELMODE, 0, 0); | |
| 56 } | |
| 57 } | |
| 58 | |
| 59 return TRUE; | |
| 60 } | |
| 61 #endif // defined(OS_WIN) | |
| 62 | |
| 63 gfx::Point GetScreenLocationFromEvent(const ui::LocatedEvent& event) { | |
| 64 aura::Window* root = | |
| 65 static_cast<aura::Window*>(event.target())->GetRootWindow(); | |
| 66 aura::client::ScreenPositionClient* spc = | |
| 67 aura::client::GetScreenPositionClient(root); | |
| 68 if (!spc) | |
| 69 return event.root_location(); | |
| 70 | |
| 71 gfx::Point screen_location(event.root_location()); | |
| 72 spc->ConvertPointToScreen(root, &screen_location); | |
| 73 return screen_location; | |
| 74 } | |
| 75 | |
| 76 bool IsFractionalScaleFactor(float scale_factor) { | |
| 77 return (scale_factor - static_cast<int>(scale_factor)) > 0; | |
| 78 } | |
| 79 | |
| 80 // We don't mark these as handled so that they're sent back to the | |
| 81 // DefWindowProc so it can generate WM_APPCOMMAND as necessary. | |
| 82 bool IsXButtonUpEvent(const ui::MouseEvent* event) { | |
| 83 #if defined(OS_WIN) | |
| 84 switch (event->native_event().message) { | |
| 85 case WM_XBUTTONUP: | |
| 86 case WM_NCXBUTTONUP: | |
| 87 return true; | |
| 88 } | |
| 89 #endif | |
| 90 return false; | |
| 91 } | |
| 92 | |
| 93 // Reset unchanged touch point to StateStationary for touchmove and | |
| 94 // touchcancel. | |
| 95 void MarkUnchangedTouchPointsAsStationary(blink::WebTouchEvent* event, | |
| 96 int changed_touch_id) { | |
| 97 if (event->type == blink::WebInputEvent::TouchMove || | |
| 98 event->type == blink::WebInputEvent::TouchCancel) { | |
| 99 for (size_t i = 0; i < event->touchesLength; ++i) { | |
| 100 if (event->touches[i].id != changed_touch_id) | |
| 101 event->touches[i].state = blink::WebTouchPoint::StateStationary; | |
| 102 } | |
| 103 } | |
| 104 } | |
| 105 | |
| 106 bool NeedsInputGrab(content::RenderWidgetHostViewAura* view) { | |
| 107 if (!view) | |
| 108 return false; | |
| 109 return view->popup_type() == blink::WebPopupTypePage; | |
| 110 } | |
| 111 | |
| 112 } // namespace | |
| 113 | |
| 114 namespace content { | |
| 115 | |
| 116 RenderWidgetHostViewEventHandler::RenderWidgetHostViewEventHandler( | |
| 117 RenderWidgetHostImpl* host, | |
| 118 RenderWidgetHostViewAura* host_view) | |
| 119 : accept_return_character_(false), | |
| 120 disable_input_event_router_for_testing_(false), | |
| 121 mouse_locked_(false), | |
| 122 pinch_zoom_enabled_(content::IsPinchToZoomEnabled()), | |
| 123 set_focus_on_mouse_down_or_key_event_(false), | |
| 124 synthetic_move_sent_(false), | |
| 125 host_(RenderWidgetHostImpl::From(host)), | |
| 126 host_view_(host_view), | |
| 127 popup_child_host_view_(nullptr), | |
| 128 window_(nullptr) {} | |
| 129 | |
| 130 RenderWidgetHostViewEventHandler::~RenderWidgetHostViewEventHandler() {} | |
| 131 | |
| 132 void RenderWidgetHostViewEventHandler::SetPopupChildHostView( | |
| 133 RenderWidgetHostViewAura* popup_child_host_view) { | |
| 134 popup_child_host_view_ = popup_child_host_view; | |
| 135 } | |
| 136 | |
| 137 void RenderWidgetHostViewEventHandler::TrackHost( | |
| 138 aura::Window* reference_window) { | |
| 139 if (!reference_window) | |
| 140 return; | |
| 141 host_tracker_.reset(new aura::WindowTracker); | |
| 142 host_tracker_->Add(reference_window); | |
| 143 } | |
| 144 | |
| 145 #if defined(OS_WIN) | |
| 146 void RenderWidgetHostViewEventHandler::SetContextMenuParams( | |
| 147 const ContextMenuParams& params) { | |
| 148 last_context_menu_params_.reset(); | |
| 149 if (params.source_type == ui::MENU_SOURCE_LONG_PRESS) { | |
| 150 last_context_menu_params_.reset(new ContextMenuParams); | |
| 151 *last_context_menu_params_ = params; | |
| 152 } | |
| 153 } | |
| 154 | |
| 155 void RenderWidgetHostViewEventHandler::UpdateMouseLockRegion() { | |
| 156 RECT window_rect = | |
| 157 display::Screen::GetScreen() | |
| 158 ->DIPToScreenRectInWindow(window_, window_->GetBoundsInScreen()) | |
| 159 .ToRECT(); | |
| 160 ::ClipCursor(&window_rect); | |
| 161 } | |
| 162 #endif | |
| 163 | |
| 164 bool RenderWidgetHostViewEventHandler::LockMouse() { | |
| 165 aura::Window* root_window = window_->GetRootWindow(); | |
| 166 if (!root_window) | |
| 167 return false; | |
| 168 | |
| 169 if (mouse_locked_) | |
| 170 return true; | |
| 171 | |
| 172 mouse_locked_ = true; | |
| 173 #if !defined(OS_WIN) | |
| 174 window_->SetCapture(); | |
| 175 #else | |
| 176 UpdateMouseLockRegion(); | |
| 177 #endif | |
| 178 aura::client::CursorClient* cursor_client = | |
| 179 aura::client::GetCursorClient(root_window); | |
| 180 if (cursor_client) { | |
| 181 cursor_client->HideCursor(); | |
| 182 cursor_client->LockCursor(); | |
| 183 } | |
| 184 | |
| 185 if (ShouldMoveToCenter()) { | |
| 186 synthetic_move_sent_ = true; | |
| 187 window_->MoveCursorTo(gfx::Rect(window_->bounds().size()).CenterPoint()); | |
| 188 } | |
| 189 tooltip_disabler_.reset(new aura::client::ScopedTooltipDisabler(root_window)); | |
| 190 return true; | |
| 191 } | |
| 192 | |
| 193 void RenderWidgetHostViewEventHandler::UnlockMouse() { | |
| 194 tooltip_disabler_.reset(); | |
| 195 | |
| 196 aura::Window* root_window = window_->GetRootWindow(); | |
| 197 if (!mouse_locked_ || !root_window) | |
| 198 return; | |
| 199 | |
| 200 mouse_locked_ = false; | |
| 201 | |
| 202 if (window_->HasCapture()) | |
| 203 window_->ReleaseCapture(); | |
| 204 | |
| 205 #if defined(OS_WIN) | |
| 206 ::ClipCursor(NULL); | |
| 207 #endif | |
| 208 | |
| 209 // Ensure that the global mouse position is updated here to its original | |
| 210 // value. If we don't do this then the synthesized mouse move which is posted | |
| 211 // after the cursor is moved ends up getting a large movement delta which is | |
| 212 // not what sites expect. The delta is computed in the | |
| 213 // ModifyEventMovementAndCoords function. | |
| 214 global_mouse_position_ = unlocked_global_mouse_position_; | |
| 215 window_->MoveCursorTo(unlocked_mouse_position_); | |
| 216 | |
| 217 aura::client::CursorClient* cursor_client = | |
| 218 aura::client::GetCursorClient(root_window); | |
| 219 if (cursor_client) { | |
| 220 cursor_client->UnlockCursor(); | |
| 221 cursor_client->ShowCursor(); | |
| 222 } | |
| 223 host_->LostMouseLock(); | |
| 224 } | |
| 225 | |
| 226 void RenderWidgetHostViewEventHandler::OnKeyEvent(ui::KeyEvent* event) { | |
| 227 TRACE_EVENT0("input", "RenderWidgetHostViewAura::OnKeyEvent"); | |
| 228 | |
| 229 if (NeedsInputGrab(popup_child_host_view_)) { | |
| 230 popup_child_host_view_->OnKeyEvent(event); | |
| 231 if (event->handled()) | |
| 232 return; | |
| 233 } | |
| 234 | |
| 235 // We need to handle the Escape key for Pepper Flash. | |
| 236 if (host_view_->is_fullscreen() && event->key_code() == ui::VKEY_ESCAPE) { | |
| 237 // Focus the window we were created from. | |
| 238 if (host_tracker_.get() && !host_tracker_->windows().empty()) { | |
| 239 aura::Window* host = *(host_tracker_->windows().begin()); | |
| 240 aura::client::FocusClient* client = aura::client::GetFocusClient(host); | |
| 241 if (client) { | |
| 242 // Calling host->Focus() may delete |this|. We create a local observer | |
| 243 // for that. In that case we exit without further access to any members. | |
| 244 aura::WindowTracker tracker; | |
| 245 aura::Window* window = window_; | |
| 246 tracker.Add(window); | |
| 247 host->Focus(); | |
| 248 if (!tracker.Contains(window)) { | |
| 249 event->SetHandled(); | |
| 250 return; | |
| 251 } | |
| 252 } | |
| 253 } | |
| 254 host_view_->Shutdown(); | |
| 255 } else { | |
| 256 if (event->key_code() == ui::VKEY_RETURN) { | |
| 257 // Do not forward return key release events if no press event was handled. | |
| 258 if (event->type() == ui::ET_KEY_RELEASED && !accept_return_character_) | |
| 259 return; | |
| 260 // Accept return key character events between press and release events. | |
| 261 accept_return_character_ = event->type() == ui::ET_KEY_PRESSED; | |
| 262 } | |
| 263 | |
| 264 // Call SetKeyboardFocus() for not only ET_KEY_PRESSED but also | |
| 265 // ET_KEY_RELEASED. If a user closed the hotdog menu with ESC key press, | |
| 266 // we need to notify focus to Blink on ET_KEY_RELEASED for ESC key. | |
| 267 SetKeyboardFocus(); | |
| 268 // We don't have to communicate with an input method here. | |
| 269 NativeWebKeyboardEvent webkit_event(*event); | |
| 270 host_view_->ForwardKeyboardEvent(webkit_event); | |
| 271 } | |
| 272 event->SetHandled(); | |
| 273 } | |
| 274 | |
| 275 void RenderWidgetHostViewEventHandler::OnMouseEvent(ui::MouseEvent* event) { | |
| 276 TRACE_EVENT0("input", "RenderWidgetHostViewAura::OnMouseEvent"); | |
| 277 ForwardMouseEventToParent(event); | |
| 278 // TODO(mgiuca): Return if event->handled() returns true. This currently | |
| 279 // breaks drop-down lists which means something is incorrectly setting | |
| 280 // event->handled to true (http://crbug.com/577983). | |
| 281 | |
| 282 if (mouse_locked_) { | |
| 283 aura::client::CursorClient* cursor_client = | |
| 284 aura::client::GetCursorClient(window_->GetRootWindow()); | |
| 285 | |
| 286 DCHECK(!cursor_client || !cursor_client->IsCursorVisible()); | |
| 287 | |
| 288 if (event->type() == ui::ET_MOUSEWHEEL) { | |
| 289 blink::WebMouseWheelEvent mouse_wheel_event = | |
| 290 ui::MakeWebMouseWheelEvent(static_cast<ui::MouseWheelEvent&>(*event), | |
| 291 base::Bind(&GetScreenLocationFromEvent)); | |
| 292 if (mouse_wheel_event.deltaX != 0 || mouse_wheel_event.deltaY != 0) | |
| 293 host_->ForwardWheelEvent(mouse_wheel_event); | |
| 294 return; | |
| 295 } | |
| 296 | |
| 297 gfx::Point center(gfx::Rect(window_->bounds().size()).CenterPoint()); | |
| 298 | |
| 299 // If we receive non client mouse messages while we are in the locked state | |
| 300 // it probably means that the mouse left the borders of our window and | |
| 301 // needs to be moved back to the center. | |
| 302 if (event->flags() & ui::EF_IS_NON_CLIENT) { | |
| 303 synthetic_move_sent_ = true; | |
| 304 window_->MoveCursorTo(center); | |
| 305 return; | |
| 306 } | |
| 307 | |
| 308 blink::WebMouseEvent mouse_event = | |
| 309 ui::MakeWebMouseEvent(*event, base::Bind(&GetScreenLocationFromEvent)); | |
| 310 | |
| 311 bool is_move_to_center_event = (event->type() == ui::ET_MOUSE_MOVED || | |
| 312 event->type() == ui::ET_MOUSE_DRAGGED) && | |
| 313 mouse_event.x == center.x() && | |
| 314 mouse_event.y == center.y(); | |
| 315 | |
| 316 // For fractional scale factors, the conversion from pixels to dip and | |
| 317 // vice versa could result in off by 1 or 2 errors which hurts us because | |
| 318 // we want to avoid sending the artificial move to center event to the | |
| 319 // renderer. Sending the move to center to the renderer cause the cursor | |
| 320 // to bounce around the center of the screen leading to the lock operation | |
| 321 // not working correctly. | |
| 322 // Workaround is to treat a mouse move or drag event off by at most 2 px | |
| 323 // from the center as a move to center event. | |
| 324 if (synthetic_move_sent_ && | |
| 325 IsFractionalScaleFactor(host_view_->current_device_scale_factor())) { | |
| 326 if (event->type() == ui::ET_MOUSE_MOVED || | |
| 327 event->type() == ui::ET_MOUSE_DRAGGED) { | |
| 328 if ((abs(mouse_event.x - center.x()) <= 2) && | |
| 329 (abs(mouse_event.y - center.y()) <= 2)) { | |
| 330 is_move_to_center_event = true; | |
| 331 } | |
| 332 } | |
| 333 } | |
| 334 | |
| 335 ModifyEventMovementAndCoords(&mouse_event); | |
| 336 | |
| 337 bool should_not_forward = is_move_to_center_event && synthetic_move_sent_; | |
| 338 if (should_not_forward) { | |
| 339 synthetic_move_sent_ = false; | |
| 340 } else { | |
| 341 // Check if the mouse has reached the border and needs to be centered. | |
| 342 if (ShouldMoveToCenter()) { | |
| 343 synthetic_move_sent_ = true; | |
| 344 window_->MoveCursorTo(center); | |
| 345 } | |
| 346 bool is_selection_popup = NeedsInputGrab(popup_child_host_view_); | |
| 347 // Forward event to renderer. | |
| 348 if (CanRendererHandleEvent(event, mouse_locked_, is_selection_popup) && | |
| 349 !(event->flags() & ui::EF_FROM_TOUCH)) { | |
| 350 host_->ForwardMouseEvent(mouse_event); | |
| 351 // Ensure that we get keyboard focus on mouse down as a plugin window | |
| 352 // may have grabbed keyboard focus. | |
| 353 if (event->type() == ui::ET_MOUSE_PRESSED) | |
| 354 SetKeyboardFocus(); | |
| 355 } | |
| 356 } | |
| 357 return; | |
| 358 } | |
| 359 | |
| 360 // As the overscroll is handled during scroll events from the trackpad, the | |
| 361 // RWHVA window is transformed by the overscroll controller. This transform | |
| 362 // triggers a synthetic mouse-move event to be generated (by the aura | |
| 363 // RootWindow). But this event interferes with the overscroll gesture. So, | |
| 364 // ignore such synthetic mouse-move events if an overscroll gesture is in | |
| 365 // progress. | |
| 366 OverscrollController* overscroll_controller = | |
| 367 host_view_->overscroll_controller(); | |
| 368 if (overscroll_controller && | |
| 369 overscroll_controller->overscroll_mode() != OVERSCROLL_NONE && | |
| 370 event->flags() & ui::EF_IS_SYNTHESIZED && | |
| 371 (event->type() == ui::ET_MOUSE_ENTERED || | |
| 372 event->type() == ui::ET_MOUSE_EXITED || | |
| 373 event->type() == ui::ET_MOUSE_MOVED)) { | |
| 374 event->StopPropagation(); | |
| 375 return; | |
| 376 } | |
| 377 | |
| 378 if (event->type() == ui::ET_MOUSEWHEEL) { | |
| 379 #if defined(OS_WIN) | |
| 380 // We get mouse wheel/scroll messages even if we are not in the foreground. | |
| 381 // So here we check if we have any owned popup windows in the foreground and | |
| 382 // dismiss them. | |
| 383 aura::WindowTreeHost* host = window_->GetHost(); | |
| 384 if (host) { | |
| 385 HWND parent = host->GetAcceleratedWidget(); | |
| 386 HWND toplevel_hwnd = ::GetAncestor(parent, GA_ROOT); | |
| 387 EnumThreadWindows(GetCurrentThreadId(), DismissOwnedPopups, | |
| 388 reinterpret_cast<LPARAM>(toplevel_hwnd)); | |
| 389 } | |
| 390 #endif | |
| 391 blink::WebMouseWheelEvent mouse_wheel_event = | |
| 392 ui::MakeWebMouseWheelEvent(static_cast<ui::MouseWheelEvent&>(*event), | |
| 393 base::Bind(&GetScreenLocationFromEvent)); | |
| 394 if (mouse_wheel_event.deltaX != 0 || mouse_wheel_event.deltaY != 0) { | |
| 395 if (ShouldRouteEvent(event)) { | |
| 396 host_->delegate()->GetInputEventRouter()->RouteMouseWheelEvent( | |
| 397 host_view_, &mouse_wheel_event); | |
| 398 } else { | |
| 399 ProcessMouseWheelEvent(mouse_wheel_event, *event->latency()); | |
| 400 } | |
| 401 } | |
| 402 } else { | |
| 403 bool is_selection_popup = NeedsInputGrab(popup_child_host_view_); | |
| 404 if (CanRendererHandleEvent(event, mouse_locked_, is_selection_popup) && | |
| 405 !(event->flags() & ui::EF_FROM_TOUCH)) { | |
| 406 // Confirm existing composition text on mouse press, to make sure | |
| 407 // the input caret won't be moved with an ongoing composition text. | |
| 408 if (event->type() == ui::ET_MOUSE_PRESSED) | |
| 409 FinishImeCompositionSession(); | |
| 410 | |
| 411 blink::WebMouseEvent mouse_event = ui::MakeWebMouseEvent( | |
| 412 *event, base::Bind(&GetScreenLocationFromEvent)); | |
| 413 ModifyEventMovementAndCoords(&mouse_event); | |
| 414 if (ShouldRouteEvent(event)) { | |
| 415 host_->delegate()->GetInputEventRouter()->RouteMouseEvent(host_view_, | |
| 416 &mouse_event); | |
| 417 } else { | |
| 418 ProcessMouseEvent(mouse_event, *event->latency()); | |
| 419 } | |
| 420 | |
| 421 // Ensure that we get keyboard focus on mouse down as a plugin window may | |
| 422 // have grabbed keyboard focus. | |
| 423 if (event->type() == ui::ET_MOUSE_PRESSED) | |
| 424 SetKeyboardFocus(); | |
| 425 } | |
| 426 } | |
| 427 | |
| 428 switch (event->type()) { | |
| 429 case ui::ET_MOUSE_PRESSED: | |
| 430 window_->SetCapture(); | |
| 431 break; | |
| 432 case ui::ET_MOUSE_RELEASED: | |
| 433 if (!host_view_->NeedsMouseCapture()) | |
| 434 window_->ReleaseCapture(); | |
| 435 break; | |
| 436 default: | |
| 437 break; | |
| 438 } | |
| 439 | |
| 440 if (!IsXButtonUpEvent(event)) | |
| 441 event->SetHandled(); | |
| 442 } | |
|
sadrul
2016/09/13 15:39:46
This is a very long function. While you are here,
jonross
2016/09/15 16:39:59
Done.
| |
| 443 | |
| 444 void RenderWidgetHostViewEventHandler::OnScrollEvent(ui::ScrollEvent* event) { | |
| 445 TRACE_EVENT0("input", "RenderWidgetHostViewAura::OnScrollEvent"); | |
| 446 | |
| 447 if (event->type() == ui::ET_SCROLL) { | |
| 448 #if !defined(OS_WIN) | |
| 449 // TODO(ananta) | |
| 450 // Investigate if this is true for Windows 8 Metro ASH as well. | |
| 451 if (event->finger_count() != 2) | |
| 452 return; | |
| 453 #endif | |
| 454 blink::WebGestureEvent gesture_event = ui::MakeWebGestureEventFlingCancel(); | |
| 455 // Coordinates need to be transferred to the fling cancel gesture only | |
| 456 // for Surface-targeting to ensure that it is targeted to the correct | |
| 457 // RenderWidgetHost. | |
| 458 gesture_event.x = event->x(); | |
| 459 gesture_event.y = event->y(); | |
| 460 blink::WebMouseWheelEvent mouse_wheel_event = ui::MakeWebMouseWheelEvent( | |
| 461 *event, base::Bind(&GetScreenLocationFromEvent)); | |
| 462 if (ShouldRouteEvent(event)) { | |
| 463 host_->delegate()->GetInputEventRouter()->RouteGestureEvent( | |
| 464 host_view_, &gesture_event, ui::LatencyInfo()); | |
| 465 host_->delegate()->GetInputEventRouter()->RouteMouseWheelEvent( | |
| 466 host_view_, &mouse_wheel_event); | |
| 467 } else { | |
| 468 host_->ForwardGestureEvent(gesture_event); | |
| 469 host_->ForwardWheelEventWithLatencyInfo(mouse_wheel_event, | |
| 470 *event->latency()); | |
| 471 } | |
| 472 RecordAction(base::UserMetricsAction("TrackpadScroll")); | |
| 473 } else if (event->type() == ui::ET_SCROLL_FLING_START || | |
| 474 event->type() == ui::ET_SCROLL_FLING_CANCEL) { | |
| 475 blink::WebGestureEvent gesture_event = ui::MakeWebGestureEvent( | |
| 476 *event, base::Bind(&GetScreenLocationFromEvent)); | |
| 477 if (ShouldRouteEvent(event)) { | |
| 478 host_->delegate()->GetInputEventRouter()->RouteGestureEvent( | |
| 479 host_view_, &gesture_event, ui::LatencyInfo()); | |
| 480 } else { | |
| 481 host_->ForwardGestureEvent(gesture_event); | |
| 482 } | |
| 483 if (event->type() == ui::ET_SCROLL_FLING_START) | |
| 484 RecordAction(base::UserMetricsAction("TrackpadScrollFling")); | |
| 485 } | |
| 486 | |
| 487 event->SetHandled(); | |
| 488 } | |
| 489 | |
| 490 void RenderWidgetHostViewEventHandler::OnTouchEvent(ui::TouchEvent* event) { | |
| 491 TRACE_EVENT0("input", "RenderWidgetHostViewAura::OnTouchEvent"); | |
| 492 | |
| 493 bool had_no_pointer = !pointer_state_.GetPointerCount(); | |
| 494 | |
| 495 // Update the touch event first. | |
| 496 if (!pointer_state_.OnTouch(*event)) { | |
| 497 event->StopPropagation(); | |
| 498 return; | |
| 499 } | |
| 500 | |
| 501 blink::WebTouchEvent touch_event; | |
| 502 bool handled = | |
| 503 host_view_->selection_controller()->WillHandleTouchEvent(pointer_state_); | |
| 504 if (handled) { | |
| 505 event->SetHandled(); | |
| 506 } else { | |
| 507 touch_event = ui::CreateWebTouchEventFromMotionEvent( | |
| 508 pointer_state_, event->may_cause_scrolling()); | |
| 509 } | |
| 510 pointer_state_.CleanupRemovedTouchPoints(*event); | |
| 511 | |
| 512 if (handled) | |
| 513 return; | |
| 514 | |
| 515 if (had_no_pointer) | |
| 516 host_view_->selection_controller_client()->OnTouchDown(); | |
| 517 if (!pointer_state_.GetPointerCount()) | |
| 518 host_view_->selection_controller_client()->OnTouchUp(); | |
| 519 | |
| 520 // It is important to always mark events as being handled asynchronously when | |
| 521 // they are forwarded. This ensures that the current event does not get | |
| 522 // processed by the gesture recognizer before events currently awaiting | |
| 523 // dispatch in the touch queue. | |
| 524 event->DisableSynchronousHandling(); | |
| 525 | |
| 526 // Set unchanged touch point to StateStationary for touchmove and | |
| 527 // touchcancel to make sure only send one ack per WebTouchEvent. | |
| 528 MarkUnchangedTouchPointsAsStationary(&touch_event, event->touch_id()); | |
| 529 if (ShouldRouteEvent(event)) { | |
| 530 host_->delegate()->GetInputEventRouter()->RouteTouchEvent( | |
| 531 host_view_, &touch_event, *event->latency()); | |
| 532 } else { | |
| 533 ProcessTouchEvent(touch_event, *event->latency()); | |
| 534 } | |
| 535 } | |
| 536 | |
| 537 void RenderWidgetHostViewEventHandler::OnGestureEvent(ui::GestureEvent* event) { | |
| 538 TRACE_EVENT0("input", "RenderWidgetHostViewAura::OnGestureEvent"); | |
| 539 | |
| 540 if ((event->type() == ui::ET_GESTURE_PINCH_BEGIN || | |
| 541 event->type() == ui::ET_GESTURE_PINCH_UPDATE || | |
| 542 event->type() == ui::ET_GESTURE_PINCH_END) && | |
| 543 !pinch_zoom_enabled_) { | |
| 544 event->SetHandled(); | |
| 545 return; | |
| 546 } | |
| 547 | |
| 548 HandleGestureForTouchSelection(event); | |
| 549 if (event->handled()) | |
| 550 return; | |
| 551 | |
| 552 // Confirm existing composition text on TAP gesture, to make sure the input | |
| 553 // caret won't be moved with an ongoing composition text. | |
| 554 if (event->type() == ui::ET_GESTURE_TAP) | |
| 555 FinishImeCompositionSession(); | |
| 556 | |
| 557 blink::WebGestureEvent gesture = | |
| 558 ui::MakeWebGestureEvent(*event, base::Bind(&GetScreenLocationFromEvent)); | |
| 559 if (event->type() == ui::ET_GESTURE_TAP_DOWN) { | |
| 560 // Webkit does not stop a fling-scroll on tap-down. So explicitly send an | |
| 561 // event to stop any in-progress flings. | |
| 562 blink::WebGestureEvent fling_cancel = gesture; | |
| 563 fling_cancel.type = blink::WebInputEvent::GestureFlingCancel; | |
| 564 fling_cancel.sourceDevice = blink::WebGestureDeviceTouchscreen; | |
| 565 if (ShouldRouteEvent(event)) { | |
| 566 host_->delegate()->GetInputEventRouter()->RouteGestureEvent( | |
| 567 host_view_, &fling_cancel, ui::LatencyInfo()); | |
| 568 } else { | |
| 569 host_->ForwardGestureEvent(fling_cancel); | |
| 570 } | |
| 571 } | |
| 572 | |
| 573 if (gesture.type != blink::WebInputEvent::Undefined) { | |
| 574 if (ShouldRouteEvent(event)) { | |
| 575 host_->delegate()->GetInputEventRouter()->RouteGestureEvent( | |
| 576 host_view_, &gesture, *event->latency()); | |
| 577 } else { | |
| 578 host_->ForwardGestureEventWithLatencyInfo(gesture, *event->latency()); | |
| 579 } | |
| 580 | |
| 581 if (event->type() == ui::ET_GESTURE_SCROLL_BEGIN || | |
| 582 event->type() == ui::ET_GESTURE_SCROLL_UPDATE || | |
| 583 event->type() == ui::ET_GESTURE_SCROLL_END) { | |
| 584 RecordAction(base::UserMetricsAction("TouchscreenScroll")); | |
| 585 } else if (event->type() == ui::ET_SCROLL_FLING_START) { | |
| 586 RecordAction(base::UserMetricsAction("TouchscreenScrollFling")); | |
| 587 } | |
| 588 } | |
| 589 | |
| 590 // If a gesture is not processed by the webpage, then WebKit processes it | |
| 591 // (e.g. generates synthetic mouse events). | |
| 592 event->SetHandled(); | |
| 593 } | |
| 594 | |
| 595 bool RenderWidgetHostViewEventHandler::CanRendererHandleEvent( | |
| 596 const ui::MouseEvent* event, | |
| 597 bool mouse_locked, | |
| 598 bool selection_popup) const { | |
| 599 if (event->type() == ui::ET_MOUSE_CAPTURE_CHANGED) | |
| 600 return false; | |
| 601 | |
| 602 if (event->type() == ui::ET_MOUSE_EXITED) { | |
| 603 if (mouse_locked || selection_popup) | |
| 604 return false; | |
| 605 #if defined(OS_WIN) | |
| 606 // Don't forward the mouse leave message which is received when the context | |
| 607 // menu is displayed by the page. This confuses the page and causes state | |
| 608 // changes. | |
| 609 if (host_view_->IsShowingContextMenu()) | |
| 610 return false; | |
| 611 #endif | |
| 612 return true; | |
| 613 } | |
| 614 | |
| 615 #if defined(OS_WIN) | |
| 616 // Renderer cannot handle WM_XBUTTON or NC events. | |
| 617 switch (event->native_event().message) { | |
| 618 case WM_XBUTTONDOWN: | |
| 619 case WM_XBUTTONUP: | |
| 620 case WM_XBUTTONDBLCLK: | |
| 621 case WM_NCMOUSELEAVE: | |
| 622 case WM_NCMOUSEMOVE: | |
| 623 case WM_NCLBUTTONDOWN: | |
| 624 case WM_NCLBUTTONUP: | |
| 625 case WM_NCLBUTTONDBLCLK: | |
| 626 case WM_NCRBUTTONDOWN: | |
| 627 case WM_NCRBUTTONUP: | |
| 628 case WM_NCRBUTTONDBLCLK: | |
| 629 case WM_NCMBUTTONDOWN: | |
| 630 case WM_NCMBUTTONUP: | |
| 631 case WM_NCMBUTTONDBLCLK: | |
| 632 case WM_NCXBUTTONDOWN: | |
| 633 case WM_NCXBUTTONUP: | |
| 634 case WM_NCXBUTTONDBLCLK: | |
| 635 return false; | |
| 636 default: | |
| 637 break; | |
| 638 } | |
| 639 #elif defined(USE_X11) | |
| 640 // Renderer only supports standard mouse buttons, so ignore programmable | |
| 641 // buttons. | |
| 642 switch (event->type()) { | |
| 643 case ui::ET_MOUSE_PRESSED: | |
| 644 case ui::ET_MOUSE_RELEASED: { | |
| 645 const int kAllowedButtons = ui::EF_LEFT_MOUSE_BUTTON | | |
| 646 ui::EF_MIDDLE_MOUSE_BUTTON | | |
| 647 ui::EF_RIGHT_MOUSE_BUTTON; | |
| 648 return (event->flags() & kAllowedButtons) != 0; | |
| 649 } | |
| 650 default: | |
| 651 break; | |
| 652 } | |
| 653 #endif | |
| 654 return true; | |
| 655 } | |
| 656 | |
| 657 void RenderWidgetHostViewEventHandler::FinishImeCompositionSession() { | |
| 658 if (!host_view_->HasCompositionText()) | |
| 659 return; | |
| 660 | |
| 661 TextInputManager* text_input_manager = host_view_->GetTextInputManager(); | |
| 662 if (!!text_input_manager && !!text_input_manager->GetActiveWidget()) { | |
| 663 text_input_manager->GetActiveWidget()->ImeConfirmComposition( | |
| 664 base::string16(), gfx::Range::InvalidRange(), false); | |
| 665 } | |
| 666 host_view_->ImeCancelComposition(); | |
| 667 } | |
| 668 | |
| 669 void RenderWidgetHostViewEventHandler::ForwardMouseEventToParent( | |
| 670 ui::MouseEvent* event) { | |
| 671 // Needed to propagate mouse event to |window_->parent()->delegate()|, but | |
| 672 // note that it might be something other than a WebContentsViewAura instance. | |
| 673 // TODO(pkotwicz): Find a better way of doing this. | |
| 674 // In fullscreen mode which is typically used by flash, don't forward | |
| 675 // the mouse events to the parent. The renderer and the plugin process | |
| 676 // handle these events. | |
| 677 if (host_view_->is_fullscreen()) | |
| 678 return; | |
| 679 | |
| 680 if (event->flags() & ui::EF_FROM_TOUCH) | |
| 681 return; | |
| 682 | |
| 683 if (!window_->parent() || !window_->parent()->delegate()) | |
| 684 return; | |
| 685 | |
| 686 // Take a copy of |event|, to avoid ConvertLocationToTarget mutating the | |
| 687 // event. | |
| 688 std::unique_ptr<ui::Event> event_copy = ui::Event::Clone(*event); | |
| 689 ui::MouseEvent* mouse_event = static_cast<ui::MouseEvent*>(event_copy.get()); | |
| 690 mouse_event->ConvertLocationToTarget(window_, window_->parent()); | |
| 691 window_->parent()->delegate()->OnMouseEvent(mouse_event); | |
| 692 if (mouse_event->handled()) | |
| 693 event->SetHandled(); | |
| 694 } | |
| 695 | |
| 696 RenderViewHostDelegateView* | |
| 697 RenderWidgetHostViewEventHandler::GetRenderViewHostDelegateView() { | |
| 698 // Use RenderViewHostDelegate to get to the WebContentsViewAura, which will | |
| 699 // actually show the disambiguation popup. | |
| 700 RenderViewHost* rvh = RenderViewHost::From(host_); | |
| 701 if (!rvh) | |
| 702 return nullptr; | |
| 703 | |
| 704 RenderViewHostDelegate* delegate = rvh->GetDelegate(); | |
| 705 if (!delegate) | |
| 706 return nullptr; | |
| 707 | |
| 708 return delegate->GetDelegateView(); | |
| 709 } | |
| 710 | |
| 711 void RenderWidgetHostViewEventHandler::HandleGestureForTouchSelection( | |
| 712 ui::GestureEvent* event) { | |
| 713 switch (event->type()) { | |
| 714 case ui::ET_GESTURE_LONG_PRESS: | |
| 715 if (host_view_->selection_controller()->WillHandleLongPressEvent( | |
| 716 event->time_stamp(), event->location_f())) { | |
| 717 event->SetHandled(); | |
| 718 } | |
| 719 break; | |
| 720 case ui::ET_GESTURE_TAP: | |
| 721 if (host_view_->selection_controller()->WillHandleTapEvent( | |
| 722 event->location_f(), event->details().tap_count())) { | |
| 723 event->SetHandled(); | |
| 724 } | |
| 725 break; | |
| 726 case ui::ET_GESTURE_SCROLL_BEGIN: | |
| 727 host_view_->selection_controller_client()->OnScrollStarted(); | |
| 728 break; | |
| 729 case ui::ET_GESTURE_SCROLL_END: | |
| 730 host_view_->selection_controller_client()->OnScrollCompleted(); | |
| 731 break; | |
| 732 #if defined(OS_WIN) | |
| 733 case ui::ET_GESTURE_LONG_TAP: { | |
| 734 if (!last_context_menu_params_) | |
| 735 break; | |
| 736 | |
| 737 std::unique_ptr<ContextMenuParams> context_menu_params = | |
| 738 std::move(last_context_menu_params_); | |
| 739 | |
| 740 // On Windows we want to display the context menu when the long press | |
| 741 // gesture is released. To achieve that, we switch the saved context | |
| 742 // menu params source type to MENU_SOURCE_TOUCH. This is to ensure that | |
| 743 // the RenderWidgetHostViewAura::OnShowContextMenu function which is | |
| 744 // called from the ShowContextMenu call below, does not treat it as | |
| 745 // a context menu request coming in from the long press gesture. | |
| 746 DCHECK(context_menu_params->source_type == ui::MENU_SOURCE_LONG_PRESS); | |
| 747 context_menu_params->source_type = ui::MENU_SOURCE_TOUCH; | |
| 748 | |
| 749 RenderViewHostDelegateView* delegate_view = | |
| 750 GetRenderViewHostDelegateView(); | |
| 751 if (delegate_view) | |
| 752 delegate_view->ShowContextMenu(host_view_->GetFocusedFrame(), | |
| 753 *context_menu_params); | |
| 754 | |
| 755 event->SetHandled(); | |
| 756 // WARNING: we may have been deleted during the call to ShowContextMenu(). | |
| 757 break; | |
| 758 } | |
| 759 #endif | |
| 760 default: | |
| 761 break; | |
| 762 } | |
| 763 } | |
| 764 | |
| 765 void RenderWidgetHostViewEventHandler::ModifyEventMovementAndCoords( | |
| 766 blink::WebMouseEvent* event) { | |
| 767 // If the mouse has just entered, we must report zero movementX/Y. Hence we | |
| 768 // reset any global_mouse_position set previously. | |
| 769 if (event->type == blink::WebInputEvent::MouseEnter || | |
| 770 event->type == blink::WebInputEvent::MouseLeave) | |
| 771 global_mouse_position_.SetPoint(event->globalX, event->globalY); | |
| 772 | |
| 773 // Movement is computed by taking the difference of the new cursor position | |
| 774 // and the previous. Under mouse lock the cursor will be warped back to the | |
| 775 // center so that we are not limited by clipping boundaries. | |
| 776 // We do not measure movement as the delta from cursor to center because | |
| 777 // we may receive more mouse movement events before our warp has taken | |
| 778 // effect. | |
| 779 event->movementX = event->globalX - global_mouse_position_.x(); | |
| 780 event->movementY = event->globalY - global_mouse_position_.y(); | |
| 781 | |
| 782 global_mouse_position_.SetPoint(event->globalX, event->globalY); | |
| 783 | |
| 784 // Under mouse lock, coordinates of mouse are locked to what they were when | |
| 785 // mouse lock was entered. | |
| 786 if (mouse_locked_) { | |
| 787 event->x = unlocked_mouse_position_.x(); | |
| 788 event->y = unlocked_mouse_position_.y(); | |
| 789 event->windowX = unlocked_mouse_position_.x(); | |
| 790 event->windowY = unlocked_mouse_position_.y(); | |
| 791 event->globalX = unlocked_global_mouse_position_.x(); | |
| 792 event->globalY = unlocked_global_mouse_position_.y(); | |
| 793 } else { | |
| 794 unlocked_mouse_position_.SetPoint(event->x, event->y); | |
| 795 unlocked_global_mouse_position_.SetPoint(event->globalX, event->globalY); | |
| 796 } | |
| 797 } | |
| 798 | |
| 799 void RenderWidgetHostViewEventHandler::SetKeyboardFocus() { | |
| 800 #if defined(OS_WIN) | |
| 801 if (host_view_->CanFocus()) { | |
| 802 aura::WindowTreeHost* host = window_->GetHost(); | |
| 803 if (host) { | |
| 804 gfx::AcceleratedWidget hwnd = host->GetAcceleratedWidget(); | |
| 805 if (!(::GetWindowLong(hwnd, GWL_EXSTYLE) & WS_EX_NOACTIVATE)) | |
| 806 ::SetFocus(hwnd); | |
| 807 } | |
| 808 } | |
| 809 #endif | |
| 810 // TODO(wjmaclean): can host_ ever be null? | |
| 811 if (host_ && set_focus_on_mouse_down_or_key_event_) { | |
| 812 set_focus_on_mouse_down_or_key_event_ = false; | |
| 813 host_->Focus(); | |
| 814 } | |
| 815 } | |
| 816 | |
| 817 bool RenderWidgetHostViewEventHandler::ShouldMoveToCenter() { | |
| 818 gfx::Rect rect = window_->bounds(); | |
| 819 rect = host_view_->ConvertRectToScreen(rect); | |
| 820 int border_x = rect.width() * kMouseLockBorderPercentage / 100; | |
| 821 int border_y = rect.height() * kMouseLockBorderPercentage / 100; | |
| 822 | |
| 823 return global_mouse_position_.x() < rect.x() + border_x || | |
| 824 global_mouse_position_.x() > rect.right() - border_x || | |
| 825 global_mouse_position_.y() < rect.y() + border_y || | |
| 826 global_mouse_position_.y() > rect.bottom() - border_y; | |
| 827 } | |
| 828 | |
| 829 bool RenderWidgetHostViewEventHandler::ShouldRouteEvent( | |
| 830 const ui::Event* event) const { | |
| 831 // We should route an event in two cases: | |
| 832 // 1) Mouse events are routed only if cross-process frames are possible. | |
| 833 // 2) Touch events are always routed. In the absence of a BrowserPlugin | |
| 834 // we expect the routing to always send the event to this view. If | |
| 835 // one or more BrowserPlugins are present, then the event may be targeted | |
| 836 // to one of them, or this view. This allows GuestViews to have access to | |
| 837 // them while still forcing pinch-zoom to be handled by the top-level | |
| 838 // frame. TODO(wjmaclean): At present, this doesn't work for OOPIF, but | |
| 839 // it should be a simple extension to modify RenderWidgetHostViewChildFrame | |
| 840 // in a similar manner to RenderWidgetHostViewGuest. | |
| 841 bool result = host_->delegate() && host_->delegate()->GetInputEventRouter() && | |
| 842 !disable_input_event_router_for_testing_; | |
| 843 // ScrollEvents get transformed into MouseWheel events, and so are treated | |
| 844 // the same as mouse events for routing purposes. | |
| 845 if (event->IsMouseEvent() || event->type() == ui::ET_SCROLL) | |
| 846 result = result && SiteIsolationPolicy::AreCrossProcessFramesPossible(); | |
| 847 return result; | |
| 848 } | |
| 849 | |
| 850 void RenderWidgetHostViewEventHandler::ProcessMouseEvent( | |
| 851 const blink::WebMouseEvent& event, | |
| 852 const ui::LatencyInfo& latency) { | |
| 853 host_->ForwardMouseEventWithLatencyInfo(event, latency); | |
| 854 } | |
| 855 | |
| 856 void RenderWidgetHostViewEventHandler::ProcessMouseWheelEvent( | |
| 857 const blink::WebMouseWheelEvent& event, | |
| 858 const ui::LatencyInfo& latency) { | |
| 859 host_->ForwardWheelEventWithLatencyInfo(event, latency); | |
| 860 } | |
| 861 | |
| 862 void RenderWidgetHostViewEventHandler::ProcessTouchEvent( | |
| 863 const blink::WebTouchEvent& event, | |
| 864 const ui::LatencyInfo& latency) { | |
| 865 host_->ForwardTouchEventWithLatencyInfo(event, latency); | |
| 866 } | |
| 867 | |
| 868 } // namespace content | |
| OLD | NEW |