Chromium Code Reviews| 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 |