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

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

Issue 2229463004: Generate MouseEnter/MouseLeave events between processes. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Next fix attempt 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
1 // Copyright 2015 The Chromium Authors. All rights reserved. 1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "content/browser/renderer_host/render_widget_host_input_event_router.h" 5 #include "content/browser/renderer_host/render_widget_host_input_event_router.h"
6 6
7 #include <vector>
8
7 #include "base/metrics/histogram_macros.h" 9 #include "base/metrics/histogram_macros.h"
10
8 #include "cc/quads/surface_draw_quad.h" 11 #include "cc/quads/surface_draw_quad.h"
9 #include "cc/surfaces/surface_id_allocator.h" 12 #include "cc/surfaces/surface_id_allocator.h"
10 #include "cc/surfaces/surface_manager.h" 13 #include "cc/surfaces/surface_manager.h"
14 #include "content/browser/frame_host/render_widget_host_view_child_frame.h"
11 #include "content/browser/renderer_host/render_widget_host_impl.h" 15 #include "content/browser/renderer_host/render_widget_host_impl.h"
12 #include "content/browser/renderer_host/render_widget_host_view_base.h" 16 #include "content/browser/renderer_host/render_widget_host_view_base.h"
13 #include "content/common/frame_messages.h" 17 #include "content/common/frame_messages.h"
14 #include "third_party/WebKit/public/web/WebInputEvent.h" 18 #include "third_party/WebKit/public/web/WebInputEvent.h"
15 19
16 namespace { 20 namespace {
17 21
18 void TransformEventTouchPositions(blink::WebTouchEvent* event, 22 void TransformEventTouchPositions(blink::WebTouchEvent* event,
19 const gfx::Vector2d& delta) { 23 const gfx::Vector2d& delta) {
20 for (unsigned i = 0; i < event->touchesLength; ++i) { 24 for (unsigned i = 0; i < event->touchesLength; ++i) {
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
57 touchscreen_gesture_target_.target = nullptr; 61 touchscreen_gesture_target_.target = nullptr;
58 62
59 if (view == touchpad_gesture_target_.target) 63 if (view == touchpad_gesture_target_.target)
60 touchpad_gesture_target_.target = nullptr; 64 touchpad_gesture_target_.target = nullptr;
61 65
62 if (view == bubbling_gesture_scroll_target_.target || 66 if (view == bubbling_gesture_scroll_target_.target ||
63 view == first_bubbling_scroll_target_.target) { 67 view == first_bubbling_scroll_target_.target) {
64 bubbling_gesture_scroll_target_.target = nullptr; 68 bubbling_gesture_scroll_target_.target = nullptr;
65 first_bubbling_scroll_target_.target = nullptr; 69 first_bubbling_scroll_target_.target = nullptr;
66 } 70 }
71
72 if (view == last_mouse_move_target_) {
73 last_mouse_move_target_ = nullptr;
74 last_mouse_move_root_view_ = nullptr;
75 }
Navid Zolghadr 2016/09/09 14:27:41 When do we call this destructor? Is it when the if
kenrb 2016/09/12 17:44:46 Yes. This is called when a RenderWidgetHostView i
67 } 76 }
68 77
69 void RenderWidgetHostInputEventRouter::ClearAllObserverRegistrations() { 78 void RenderWidgetHostInputEventRouter::ClearAllObserverRegistrations() {
70 for (auto entry : owner_map_) 79 for (auto entry : owner_map_)
71 entry.second->RemoveObserver(this); 80 entry.second->RemoveObserver(this);
72 owner_map_.clear(); 81 owner_map_.clear();
73 } 82 }
74 83
75 RenderWidgetHostInputEventRouter::HittestDelegate::HittestDelegate( 84 RenderWidgetHostInputEventRouter::HittestDelegate::HittestDelegate(
76 const std::unordered_map<cc::SurfaceId, HittestData, cc::SurfaceIdHash>& 85 const std::unordered_map<cc::SurfaceId, HittestData, cc::SurfaceIdHash>&
(...skipping 12 matching lines...) Expand all
89 bool RenderWidgetHostInputEventRouter::HittestDelegate::AcceptHitTarget( 98 bool RenderWidgetHostInputEventRouter::HittestDelegate::AcceptHitTarget(
90 const cc::SurfaceDrawQuad* surface_quad, 99 const cc::SurfaceDrawQuad* surface_quad,
91 const gfx::Point& point_in_quad_space) { 100 const gfx::Point& point_in_quad_space) {
92 auto it = hittest_data_.find(surface_quad->surface_id); 101 auto it = hittest_data_.find(surface_quad->surface_id);
93 if (it != hittest_data_.end() && !it->second.ignored_for_hittest) 102 if (it != hittest_data_.end() && !it->second.ignored_for_hittest)
94 return true; 103 return true;
95 return false; 104 return false;
96 } 105 }
97 106
98 RenderWidgetHostInputEventRouter::RenderWidgetHostInputEventRouter() 107 RenderWidgetHostInputEventRouter::RenderWidgetHostInputEventRouter()
99 : active_touches_(0), 108 : last_mouse_move_target_(nullptr),
109 last_mouse_move_root_view_(nullptr),
110 active_touches_(0),
100 in_touchscreen_gesture_pinch_(false), 111 in_touchscreen_gesture_pinch_(false),
101 gesture_pinch_did_send_scroll_begin_(false) {} 112 gesture_pinch_did_send_scroll_begin_(false) {}
102 113
103 RenderWidgetHostInputEventRouter::~RenderWidgetHostInputEventRouter() { 114 RenderWidgetHostInputEventRouter::~RenderWidgetHostInputEventRouter() {
104 // We may be destroyed before some of the owners in the map, so we must 115 // We may be destroyed before some of the owners in the map, so we must
105 // remove ourself from their observer lists. 116 // remove ourself from their observer lists.
106 ClearAllObserverRegistrations(); 117 ClearAllObserverRegistrations();
107 } 118 }
108 119
109 RenderWidgetHostViewBase* RenderWidgetHostInputEventRouter::FindEventTarget( 120 RenderWidgetHostViewBase* RenderWidgetHostInputEventRouter::FindEventTarget(
(...skipping 30 matching lines...) Expand all
140 151
141 void RenderWidgetHostInputEventRouter::RouteMouseEvent( 152 void RenderWidgetHostInputEventRouter::RouteMouseEvent(
142 RenderWidgetHostViewBase* root_view, 153 RenderWidgetHostViewBase* root_view,
143 blink::WebMouseEvent* event) { 154 blink::WebMouseEvent* event) {
144 gfx::Point transformed_point; 155 gfx::Point transformed_point;
145 RenderWidgetHostViewBase* target = FindEventTarget( 156 RenderWidgetHostViewBase* target = FindEventTarget(
146 root_view, gfx::Point(event->x, event->y), &transformed_point); 157 root_view, gfx::Point(event->x, event->y), &transformed_point);
147 if (!target) 158 if (!target)
148 return; 159 return;
149 160
161 // SendMouseEnterOrLeaveEvents is called with the original event
162 // coordinates, which are transformed independently for each view that will
163 // receive an event.
164 if ((event->type == blink::WebInputEvent::MouseLeave ||
165 event->type == blink::WebInputEvent::MouseMove) &&
166 target != last_mouse_move_target_)
167 SendMouseEnterOrLeaveEvents(event, target, root_view);
168
150 event->x = transformed_point.x(); 169 event->x = transformed_point.x();
151 event->y = transformed_point.y(); 170 event->y = transformed_point.y();
152 // TODO(wjmaclean): Initialize latency info correctly for OOPIFs. 171 // TODO(wjmaclean): Initialize latency info correctly for OOPIFs.
153 // https://crbug.com/613628 172 // https://crbug.com/613628
154 ui::LatencyInfo latency_info; 173 ui::LatencyInfo latency_info;
155 target->ProcessMouseEvent(*event, latency_info); 174 target->ProcessMouseEvent(*event, latency_info);
156 } 175 }
157 176
158 void RenderWidgetHostInputEventRouter::RouteMouseWheelEvent( 177 void RenderWidgetHostInputEventRouter::RouteMouseWheelEvent(
159 RenderWidgetHostViewBase* root_view, 178 RenderWidgetHostViewBase* root_view,
(...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after
279 TransformEventTouchPositions(event, touch_target_.delta); 298 TransformEventTouchPositions(event, touch_target_.delta);
280 touch_target_.target->ProcessTouchEvent(*event, latency); 299 touch_target_.target->ProcessTouchEvent(*event, latency);
281 if (!active_touches_) 300 if (!active_touches_)
282 touch_target_.target = nullptr; 301 touch_target_.target = nullptr;
283 break; 302 break;
284 default: 303 default:
285 NOTREACHED(); 304 NOTREACHED();
286 } 305 }
287 } 306 }
288 307
308 void RenderWidgetHostInputEventRouter::SendMouseEnterOrLeaveEvents(
309 blink::WebMouseEvent* event,
310 RenderWidgetHostViewBase* target,
311 RenderWidgetHostViewBase* root_view) {
312 // This method treats RenderWidgetHostViews as a tree, where the mouse
313 // cursor is potentially leaving one node and entering another somewhere
314 // else in the tree. Since iframes are graphically self-contained (i.e. an
315 // iframe can't have a descendant that renders outside of its rect
316 // boundaries), all affected RenderWidgetHostViews are ancestors of either
317 // the node being exited or the node being entered.
318 // Approach:
319 // 1. Find lowest common ancestor (LCA) of the last view and current target
320 // view.
321 // 2. The last view, and its ancestors up to but not including the LCA,
322 // receive a MouseLeave.
323 // 3. The LCA itself, unless it is the new target, receives a MouseOut
324 // because the cursor has passed between elements within its bounds.
325 // 4. The new target view's ancestors, up to but not including the LCA,
326 // receive a MouseEnter.
327 // Ordering does not matter since these are handled asynchronously relative
328 // to each other.
329
330 // If the mouse has moved onto a different root view (typically meaning it
331 // has crossed over a popup or context menu boundary), then we invalidate
332 // last_mouse_move_target_ because we have no reference for its coordinate
333 // space.
334 if (root_view != last_mouse_move_root_view_)
335 last_mouse_move_target_ = nullptr;
336
337 // Finding the LCA uses a standard approach. We build vectors of the
338 // ancestors of each node up to the root, and then remove common ancestors.
339 std::vector<RenderWidgetHostViewBase*> entered_views;
340 std::vector<RenderWidgetHostViewBase*> exited_views;
341 RenderWidgetHostViewBase* cur_view = target;
342 entered_views.push_back(cur_view);
343 while (cur_view != root_view) {
344 // Non-root RWHVs are guaranteed to be RenderWidgetHostViewChildFrames.
345 cur_view =
346 static_cast<RenderWidgetHostViewChildFrame*>(cur_view)->GetParentView();
347 // cur_view can possibly be nullptr for guestviews that are not currently
348 // connected to the webcontents tree.
349 if (!cur_view)
350 break;
351 entered_views.push_back(cur_view);
352 }
353
354 cur_view = last_mouse_move_target_;
355 if (cur_view) {
356 exited_views.push_back(cur_view);
357 while (cur_view != root_view) {
358 cur_view = static_cast<RenderWidgetHostViewChildFrame*>(cur_view)
359 ->GetParentView();
360 if (!cur_view)
361 break;
362 exited_views.push_back(cur_view);
363 }
364 }
365
366 // This removes common ancestors from the root downward.
367 RenderWidgetHostViewBase* common_ancestor = nullptr;
368 while (entered_views.size() > 0 &&
369 exited_views.size() > 0 &&
370 entered_views.back() == exited_views.back()) {
371 common_ancestor = entered_views.back();
372 entered_views.pop_back();
373 exited_views.pop_back();
374 }
375
376 gfx::Point transformed_point;
377 // Send MouseLeaves.
378 for (auto view : exited_views) {
379 blink::WebMouseEvent mouse_leave(*event);
380 mouse_leave.type = blink::WebInputEvent::MouseLeave;
381 transformed_point = root_view->TransformPointToCoordSpaceForView(
382 gfx::Point(event->x, event->y), view);
383 mouse_leave.x = transformed_point.x();
384 mouse_leave.y = transformed_point.y();
385 view->ProcessMouseEvent(mouse_leave, ui::LatencyInfo());
386 }
387
388 // TODO(kenrb): The ancestor might need to trigger MouseOut handlers.
389 // Unfortunately there isn't a way to get Blink to do this, so we send a
390 // MouseLeave for now. See bug https://crbug.com/638364.
391 if (common_ancestor && common_ancestor != target) {
392 blink::WebMouseEvent mouse_out(*event);
393 mouse_out.type = blink::WebInputEvent::MouseLeave;
394 transformed_point = root_view->TransformPointToCoordSpaceForView(
Navid Zolghadr 2016/09/09 14:27:41 From the perspective of the common ancestor mouse
kenrb 2016/09/12 17:44:46 Changed.
395 gfx::Point(event->x, event->y), common_ancestor);
396 mouse_out.x = transformed_point.x();
397 mouse_out.y = transformed_point.y();
398 common_ancestor->ProcessMouseEvent(mouse_out, ui::LatencyInfo());
399 }
400
401 // Send MouseEnters.
402 for (auto view : entered_views) {
403 if (view == target)
404 continue;
405 blink::WebMouseEvent mouse_enter(*event);
406 // TODO(kenrb): Blink doesn't expect a MouseEnter to come from the browser
407 // process, so we send a MouseMove, which can cause event handlers to fire
408 // incorrectly. See bug https://crbug.com/638364.
Navid Zolghadr 2016/09/09 14:27:41 I did a few tests myself. I believe sending a mous
kenrb 2016/09/12 17:44:46 Okay, this seems reasonable and I have changed the
409 mouse_enter.type = blink::WebInputEvent::MouseMove;
410 transformed_point = root_view->TransformPointToCoordSpaceForView(
411 gfx::Point(event->x, event->y), view);
412 mouse_enter.x = transformed_point.x();
413 mouse_enter.y = transformed_point.y();
414 view->ProcessMouseEvent(mouse_enter, ui::LatencyInfo());
415 }
416
417 last_mouse_move_target_ = target;
418 last_mouse_move_root_view_ = root_view;
419 }
420
289 void RenderWidgetHostInputEventRouter::BubbleScrollEvent( 421 void RenderWidgetHostInputEventRouter::BubbleScrollEvent(
290 RenderWidgetHostViewBase* target_view, 422 RenderWidgetHostViewBase* target_view,
291 const blink::WebGestureEvent& event) { 423 const blink::WebGestureEvent& event) {
292 // TODO(kenrb, tdresser): This needs to be refactored when scroll latching 424 // TODO(kenrb, tdresser): This needs to be refactored when scroll latching
293 // is implemented (see https://crbug.com/526463). This design has some 425 // is implemented (see https://crbug.com/526463). This design has some
294 // race problems that can result in lost scroll delta, which are very 426 // race problems that can result in lost scroll delta, which are very
295 // difficult to resolve until this is changed to do all scroll targeting, 427 // difficult to resolve until this is changed to do all scroll targeting,
296 // including bubbling, based on GestureScrollBegin. 428 // including bubbling, based on GestureScrollBegin.
297 DCHECK(target_view); 429 DCHECK(target_view);
298 DCHECK(event.type == blink::WebInputEvent::GestureScrollUpdate || 430 DCHECK(event.type == blink::WebInputEvent::GestureScrollUpdate ||
(...skipping 244 matching lines...) Expand 10 before | Expand all | Expand 10 after
543 if (!touchpad_gesture_target_.target) 675 if (!touchpad_gesture_target_.target)
544 return; 676 return;
545 677
546 // TODO(mohsen): Add tests to check event location. 678 // TODO(mohsen): Add tests to check event location.
547 event->x += touchpad_gesture_target_.delta.x(); 679 event->x += touchpad_gesture_target_.delta.x();
548 event->y += touchpad_gesture_target_.delta.y(); 680 event->y += touchpad_gesture_target_.delta.y();
549 touchpad_gesture_target_.target->ProcessGestureEvent(*event, latency); 681 touchpad_gesture_target_.target->ProcessGestureEvent(*event, latency);
550 } 682 }
551 683
552 } // namespace content 684 } // namespace content
OLDNEW
« no previous file with comments | « content/browser/renderer_host/render_widget_host_input_event_router.h ('k') | content/browser/site_per_process_browsertest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698