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

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: Fix popups 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_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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698