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 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 |