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 // When a child iframe is destroyed, consider its parent to be to be the | |
74 // most recent target, if possible. In some cases the parent might already | |
75 // have been destroyed, in which case the last target is cleared. | |
76 if (view != last_mouse_move_root_view_) | |
77 last_mouse_move_target_ = | |
78 static_cast<RenderWidgetHostViewChildFrame*>(last_mouse_move_target_) | |
Navid Zolghadr
2016/09/14 14:51:46
nit: I guess the ideal solution is that target sho
| |
79 ->GetParentView(); | |
80 else | |
81 last_mouse_move_target_ = nullptr; | |
82 | |
83 if (!last_mouse_move_target_) | |
84 last_mouse_move_root_view_ = nullptr; | |
85 } | |
67 } | 86 } |
68 | 87 |
69 void RenderWidgetHostInputEventRouter::ClearAllObserverRegistrations() { | 88 void RenderWidgetHostInputEventRouter::ClearAllObserverRegistrations() { |
70 for (auto entry : owner_map_) | 89 for (auto entry : owner_map_) |
71 entry.second->RemoveObserver(this); | 90 entry.second->RemoveObserver(this); |
72 owner_map_.clear(); | 91 owner_map_.clear(); |
73 } | 92 } |
74 | 93 |
75 RenderWidgetHostInputEventRouter::HittestDelegate::HittestDelegate( | 94 RenderWidgetHostInputEventRouter::HittestDelegate::HittestDelegate( |
76 const std::unordered_map<cc::SurfaceId, HittestData, cc::SurfaceIdHash>& | 95 const std::unordered_map<cc::SurfaceId, HittestData, cc::SurfaceIdHash>& |
(...skipping 12 matching lines...) Expand all Loading... | |
89 bool RenderWidgetHostInputEventRouter::HittestDelegate::AcceptHitTarget( | 108 bool RenderWidgetHostInputEventRouter::HittestDelegate::AcceptHitTarget( |
90 const cc::SurfaceDrawQuad* surface_quad, | 109 const cc::SurfaceDrawQuad* surface_quad, |
91 const gfx::Point& point_in_quad_space) { | 110 const gfx::Point& point_in_quad_space) { |
92 auto it = hittest_data_.find(surface_quad->surface_id); | 111 auto it = hittest_data_.find(surface_quad->surface_id); |
93 if (it != hittest_data_.end() && !it->second.ignored_for_hittest) | 112 if (it != hittest_data_.end() && !it->second.ignored_for_hittest) |
94 return true; | 113 return true; |
95 return false; | 114 return false; |
96 } | 115 } |
97 | 116 |
98 RenderWidgetHostInputEventRouter::RenderWidgetHostInputEventRouter() | 117 RenderWidgetHostInputEventRouter::RenderWidgetHostInputEventRouter() |
99 : active_touches_(0), | 118 : last_mouse_move_target_(nullptr), |
119 last_mouse_move_root_view_(nullptr), | |
120 active_touches_(0), | |
100 in_touchscreen_gesture_pinch_(false), | 121 in_touchscreen_gesture_pinch_(false), |
101 gesture_pinch_did_send_scroll_begin_(false) {} | 122 gesture_pinch_did_send_scroll_begin_(false) {} |
102 | 123 |
103 RenderWidgetHostInputEventRouter::~RenderWidgetHostInputEventRouter() { | 124 RenderWidgetHostInputEventRouter::~RenderWidgetHostInputEventRouter() { |
104 // We may be destroyed before some of the owners in the map, so we must | 125 // We may be destroyed before some of the owners in the map, so we must |
105 // remove ourself from their observer lists. | 126 // remove ourself from their observer lists. |
106 ClearAllObserverRegistrations(); | 127 ClearAllObserverRegistrations(); |
107 } | 128 } |
108 | 129 |
109 RenderWidgetHostViewBase* RenderWidgetHostInputEventRouter::FindEventTarget( | 130 RenderWidgetHostViewBase* RenderWidgetHostInputEventRouter::FindEventTarget( |
(...skipping 30 matching lines...) Expand all Loading... | |
140 | 161 |
141 void RenderWidgetHostInputEventRouter::RouteMouseEvent( | 162 void RenderWidgetHostInputEventRouter::RouteMouseEvent( |
142 RenderWidgetHostViewBase* root_view, | 163 RenderWidgetHostViewBase* root_view, |
143 blink::WebMouseEvent* event) { | 164 blink::WebMouseEvent* event) { |
144 gfx::Point transformed_point; | 165 gfx::Point transformed_point; |
145 RenderWidgetHostViewBase* target = FindEventTarget( | 166 RenderWidgetHostViewBase* target = FindEventTarget( |
146 root_view, gfx::Point(event->x, event->y), &transformed_point); | 167 root_view, gfx::Point(event->x, event->y), &transformed_point); |
147 if (!target) | 168 if (!target) |
148 return; | 169 return; |
149 | 170 |
171 // SendMouseEnterOrLeaveEvents is called with the original event | |
172 // coordinates, which are transformed independently for each view that will | |
173 // receive an event. | |
174 if ((event->type == blink::WebInputEvent::MouseLeave || | |
175 event->type == blink::WebInputEvent::MouseMove) && | |
176 target != last_mouse_move_target_) | |
177 SendMouseEnterOrLeaveEvents(event, target, root_view); | |
178 | |
150 event->x = transformed_point.x(); | 179 event->x = transformed_point.x(); |
151 event->y = transformed_point.y(); | 180 event->y = transformed_point.y(); |
152 // TODO(wjmaclean): Initialize latency info correctly for OOPIFs. | 181 // TODO(wjmaclean): Initialize latency info correctly for OOPIFs. |
153 // https://crbug.com/613628 | 182 // https://crbug.com/613628 |
154 ui::LatencyInfo latency_info; | 183 ui::LatencyInfo latency_info; |
155 target->ProcessMouseEvent(*event, latency_info); | 184 target->ProcessMouseEvent(*event, latency_info); |
156 } | 185 } |
157 | 186 |
158 void RenderWidgetHostInputEventRouter::RouteMouseWheelEvent( | 187 void RenderWidgetHostInputEventRouter::RouteMouseWheelEvent( |
159 RenderWidgetHostViewBase* root_view, | 188 RenderWidgetHostViewBase* root_view, |
(...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
279 TransformEventTouchPositions(event, touch_target_.delta); | 308 TransformEventTouchPositions(event, touch_target_.delta); |
280 touch_target_.target->ProcessTouchEvent(*event, latency); | 309 touch_target_.target->ProcessTouchEvent(*event, latency); |
281 if (!active_touches_) | 310 if (!active_touches_) |
282 touch_target_.target = nullptr; | 311 touch_target_.target = nullptr; |
283 break; | 312 break; |
284 default: | 313 default: |
285 NOTREACHED(); | 314 NOTREACHED(); |
286 } | 315 } |
287 } | 316 } |
288 | 317 |
318 void RenderWidgetHostInputEventRouter::SendMouseEnterOrLeaveEvents( | |
319 blink::WebMouseEvent* event, | |
320 RenderWidgetHostViewBase* target, | |
321 RenderWidgetHostViewBase* root_view) { | |
322 // This method treats RenderWidgetHostViews as a tree, where the mouse | |
323 // cursor is potentially leaving one node and entering another somewhere | |
324 // else in the tree. Since iframes are graphically self-contained (i.e. an | |
325 // iframe can't have a descendant that renders outside of its rect | |
326 // boundaries), all affected RenderWidgetHostViews are ancestors of either | |
327 // the node being exited or the node being entered. | |
328 // Approach: | |
329 // 1. Find lowest common ancestor (LCA) of the last view and current target | |
330 // view. | |
331 // 2. The last view, and its ancestors up to but not including the LCA, | |
332 // receive a MouseLeave. | |
333 // 3. The LCA itself, unless it is the new target, receives a MouseOut | |
334 // because the cursor has passed between elements within its bounds. | |
335 // 4. The new target view's ancestors, up to but not including the LCA, | |
336 // receive a MouseEnter. | |
337 // Ordering does not matter since these are handled asynchronously relative | |
338 // to each other. | |
339 | |
340 // If the mouse has moved onto a different root view (typically meaning it | |
341 // has crossed over a popup or context menu boundary), then we invalidate | |
342 // last_mouse_move_target_ because we have no reference for its coordinate | |
343 // space. | |
344 if (root_view != last_mouse_move_root_view_) | |
345 last_mouse_move_target_ = nullptr; | |
346 | |
347 // Finding the LCA uses a standard approach. We build vectors of the | |
348 // ancestors of each node up to the root, and then remove common ancestors. | |
349 std::vector<RenderWidgetHostViewBase*> entered_views; | |
350 std::vector<RenderWidgetHostViewBase*> exited_views; | |
351 RenderWidgetHostViewBase* cur_view = target; | |
352 entered_views.push_back(cur_view); | |
353 while (cur_view != root_view) { | |
354 // Non-root RWHVs are guaranteed to be RenderWidgetHostViewChildFrames. | |
355 cur_view = | |
356 static_cast<RenderWidgetHostViewChildFrame*>(cur_view)->GetParentView(); | |
357 // cur_view can possibly be nullptr for guestviews that are not currently | |
358 // connected to the webcontents tree. | |
359 if (!cur_view) | |
360 break; | |
361 entered_views.push_back(cur_view); | |
362 } | |
363 | |
364 cur_view = last_mouse_move_target_; | |
365 if (cur_view) { | |
366 exited_views.push_back(cur_view); | |
367 while (cur_view != root_view) { | |
368 cur_view = static_cast<RenderWidgetHostViewChildFrame*>(cur_view) | |
369 ->GetParentView(); | |
370 if (!cur_view) | |
371 break; | |
372 exited_views.push_back(cur_view); | |
373 } | |
374 } | |
375 | |
376 // This removes common ancestors from the root downward. | |
377 RenderWidgetHostViewBase* common_ancestor = nullptr; | |
378 while (entered_views.size() > 0 && exited_views.size() > 0 && | |
379 entered_views.back() == exited_views.back()) { | |
380 common_ancestor = entered_views.back(); | |
381 entered_views.pop_back(); | |
382 exited_views.pop_back(); | |
383 } | |
384 | |
385 gfx::Point transformed_point; | |
386 // Send MouseLeaves. | |
387 for (auto view : exited_views) { | |
388 blink::WebMouseEvent mouse_leave(*event); | |
389 mouse_leave.type = blink::WebInputEvent::MouseLeave; | |
390 transformed_point = root_view->TransformPointToCoordSpaceForView( | |
391 gfx::Point(event->x, event->y), view); | |
392 mouse_leave.x = transformed_point.x(); | |
393 mouse_leave.y = transformed_point.y(); | |
394 view->ProcessMouseEvent(mouse_leave, ui::LatencyInfo()); | |
395 } | |
396 | |
397 // The ancestor might need to trigger MouseOut handlers. | |
398 if (common_ancestor && common_ancestor != target) { | |
399 blink::WebMouseEvent mouse_move(*event); | |
400 mouse_move.type = blink::WebInputEvent::MouseMove; | |
401 transformed_point = root_view->TransformPointToCoordSpaceForView( | |
402 gfx::Point(event->x, event->y), common_ancestor); | |
403 mouse_move.x = transformed_point.x(); | |
404 mouse_move.y = transformed_point.y(); | |
405 common_ancestor->ProcessMouseEvent(mouse_move, ui::LatencyInfo()); | |
406 } | |
407 | |
408 // Send MouseMoves to trigger MouseEnter handlers. | |
409 for (auto view : entered_views) { | |
410 if (view == target) | |
411 continue; | |
412 blink::WebMouseEvent mouse_enter(*event); | |
413 mouse_enter.type = blink::WebInputEvent::MouseMove; | |
414 transformed_point = root_view->TransformPointToCoordSpaceForView( | |
415 gfx::Point(event->x, event->y), view); | |
416 mouse_enter.x = transformed_point.x(); | |
417 mouse_enter.y = transformed_point.y(); | |
418 view->ProcessMouseEvent(mouse_enter, ui::LatencyInfo()); | |
419 } | |
420 | |
421 last_mouse_move_target_ = target; | |
422 last_mouse_move_root_view_ = root_view; | |
423 } | |
424 | |
289 void RenderWidgetHostInputEventRouter::BubbleScrollEvent( | 425 void RenderWidgetHostInputEventRouter::BubbleScrollEvent( |
290 RenderWidgetHostViewBase* target_view, | 426 RenderWidgetHostViewBase* target_view, |
291 const blink::WebGestureEvent& event) { | 427 const blink::WebGestureEvent& event) { |
292 // TODO(kenrb, tdresser): This needs to be refactored when scroll latching | 428 // TODO(kenrb, tdresser): This needs to be refactored when scroll latching |
293 // is implemented (see https://crbug.com/526463). This design has some | 429 // is implemented (see https://crbug.com/526463). This design has some |
294 // race problems that can result in lost scroll delta, which are very | 430 // 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, | 431 // difficult to resolve until this is changed to do all scroll targeting, |
296 // including bubbling, based on GestureScrollBegin. | 432 // including bubbling, based on GestureScrollBegin. |
297 DCHECK(target_view); | 433 DCHECK(target_view); |
298 DCHECK(event.type == blink::WebInputEvent::GestureScrollUpdate || | 434 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) | 679 if (!touchpad_gesture_target_.target) |
544 return; | 680 return; |
545 | 681 |
546 // TODO(mohsen): Add tests to check event location. | 682 // TODO(mohsen): Add tests to check event location. |
547 event->x += touchpad_gesture_target_.delta.x(); | 683 event->x += touchpad_gesture_target_.delta.x(); |
548 event->y += touchpad_gesture_target_.delta.y(); | 684 event->y += touchpad_gesture_target_.delta.y(); |
549 touchpad_gesture_target_.target->ProcessGestureEvent(*event, latency); | 685 touchpad_gesture_target_.target->ProcessGestureEvent(*event, latency); |
550 } | 686 } |
551 | 687 |
552 } // namespace content | 688 } // namespace content |
OLD | NEW |