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

Side by Side Diff: content/browser/renderer_host/render_widget_host_view_event_handler.cc

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

Powered by Google App Engine
This is Rietveld 408576698