OLD | NEW |
---|---|
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 |
OLD | NEW |