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

Unified 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 side-by-side diff with in-line comments
Download patch
Index: content/browser/renderer_host/render_widget_host_input_event_router.cc
diff --git a/content/browser/renderer_host/render_widget_host_input_event_router.cc b/content/browser/renderer_host/render_widget_host_input_event_router.cc
index 3710a90df7f9d578833047c019537275a9ee9b4b..bd6e588018495a015ffd9b83122dd740d2c8d220 100644
--- a/content/browser/renderer_host/render_widget_host_input_event_router.cc
+++ b/content/browser/renderer_host/render_widget_host_input_event_router.cc
@@ -4,10 +4,14 @@
#include "content/browser/renderer_host/render_widget_host_input_event_router.h"
+#include <vector>
+
#include "base/metrics/histogram_macros.h"
+
#include "cc/quads/surface_draw_quad.h"
#include "cc/surfaces/surface_id_allocator.h"
#include "cc/surfaces/surface_manager.h"
+#include "content/browser/frame_host/render_widget_host_view_child_frame.h"
#include "content/browser/renderer_host/render_widget_host_impl.h"
#include "content/browser/renderer_host/render_widget_host_view_base.h"
#include "content/common/frame_messages.h"
@@ -64,6 +68,11 @@ void RenderWidgetHostInputEventRouter::OnRenderWidgetHostViewBaseDestroyed(
bubbling_gesture_scroll_target_.target = nullptr;
first_bubbling_scroll_target_.target = nullptr;
}
+
+ if (view == last_mouse_move_target_) {
+ last_mouse_move_target_ = nullptr;
+ last_mouse_move_root_view_ = nullptr;
+ }
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
}
void RenderWidgetHostInputEventRouter::ClearAllObserverRegistrations() {
@@ -96,7 +105,9 @@ bool RenderWidgetHostInputEventRouter::HittestDelegate::AcceptHitTarget(
}
RenderWidgetHostInputEventRouter::RenderWidgetHostInputEventRouter()
- : active_touches_(0),
+ : last_mouse_move_target_(nullptr),
+ last_mouse_move_root_view_(nullptr),
+ active_touches_(0),
in_touchscreen_gesture_pinch_(false),
gesture_pinch_did_send_scroll_begin_(false) {}
@@ -147,6 +158,14 @@ void RenderWidgetHostInputEventRouter::RouteMouseEvent(
if (!target)
return;
+ // SendMouseEnterOrLeaveEvents is called with the original event
+ // coordinates, which are transformed independently for each view that will
+ // receive an event.
+ if ((event->type == blink::WebInputEvent::MouseLeave ||
+ event->type == blink::WebInputEvent::MouseMove) &&
+ target != last_mouse_move_target_)
+ SendMouseEnterOrLeaveEvents(event, target, root_view);
+
event->x = transformed_point.x();
event->y = transformed_point.y();
// TODO(wjmaclean): Initialize latency info correctly for OOPIFs.
@@ -286,6 +305,119 @@ void RenderWidgetHostInputEventRouter::RouteTouchEvent(
}
}
+void RenderWidgetHostInputEventRouter::SendMouseEnterOrLeaveEvents(
+ blink::WebMouseEvent* event,
+ RenderWidgetHostViewBase* target,
+ RenderWidgetHostViewBase* root_view) {
+ // This method treats RenderWidgetHostViews as a tree, where the mouse
+ // cursor is potentially leaving one node and entering another somewhere
+ // else in the tree. Since iframes are graphically self-contained (i.e. an
+ // iframe can't have a descendant that renders outside of its rect
+ // boundaries), all affected RenderWidgetHostViews are ancestors of either
+ // the node being exited or the node being entered.
+ // Approach:
+ // 1. Find lowest common ancestor (LCA) of the last view and current target
+ // view.
+ // 2. The last view, and its ancestors up to but not including the LCA,
+ // receive a MouseLeave.
+ // 3. The LCA itself, unless it is the new target, receives a MouseOut
+ // because the cursor has passed between elements within its bounds.
+ // 4. The new target view's ancestors, up to but not including the LCA,
+ // receive a MouseEnter.
+ // Ordering does not matter since these are handled asynchronously relative
+ // to each other.
+
+ // If the mouse has moved onto a different root view (typically meaning it
+ // has crossed over a popup or context menu boundary), then we invalidate
+ // last_mouse_move_target_ because we have no reference for its coordinate
+ // space.
+ if (root_view != last_mouse_move_root_view_)
+ last_mouse_move_target_ = nullptr;
+
+ // Finding the LCA uses a standard approach. We build vectors of the
+ // ancestors of each node up to the root, and then remove common ancestors.
+ std::vector<RenderWidgetHostViewBase*> entered_views;
+ std::vector<RenderWidgetHostViewBase*> exited_views;
+ RenderWidgetHostViewBase* cur_view = target;
+ entered_views.push_back(cur_view);
+ while (cur_view != root_view) {
+ // Non-root RWHVs are guaranteed to be RenderWidgetHostViewChildFrames.
+ cur_view =
+ static_cast<RenderWidgetHostViewChildFrame*>(cur_view)->GetParentView();
+ // cur_view can possibly be nullptr for guestviews that are not currently
+ // connected to the webcontents tree.
+ if (!cur_view)
+ break;
+ entered_views.push_back(cur_view);
+ }
+
+ cur_view = last_mouse_move_target_;
+ if (cur_view) {
+ exited_views.push_back(cur_view);
+ while (cur_view != root_view) {
+ cur_view = static_cast<RenderWidgetHostViewChildFrame*>(cur_view)
+ ->GetParentView();
+ if (!cur_view)
+ break;
+ exited_views.push_back(cur_view);
+ }
+ }
+
+ // This removes common ancestors from the root downward.
+ RenderWidgetHostViewBase* common_ancestor = nullptr;
+ while (entered_views.size() > 0 &&
+ exited_views.size() > 0 &&
+ entered_views.back() == exited_views.back()) {
+ common_ancestor = entered_views.back();
+ entered_views.pop_back();
+ exited_views.pop_back();
+ }
+
+ gfx::Point transformed_point;
+ // Send MouseLeaves.
+ for (auto view : exited_views) {
+ blink::WebMouseEvent mouse_leave(*event);
+ mouse_leave.type = blink::WebInputEvent::MouseLeave;
+ transformed_point = root_view->TransformPointToCoordSpaceForView(
+ gfx::Point(event->x, event->y), view);
+ mouse_leave.x = transformed_point.x();
+ mouse_leave.y = transformed_point.y();
+ view->ProcessMouseEvent(mouse_leave, ui::LatencyInfo());
+ }
+
+ // TODO(kenrb): The ancestor might need to trigger MouseOut handlers.
+ // Unfortunately there isn't a way to get Blink to do this, so we send a
+ // MouseLeave for now. See bug https://crbug.com/638364.
+ if (common_ancestor && common_ancestor != target) {
+ blink::WebMouseEvent mouse_out(*event);
+ mouse_out.type = blink::WebInputEvent::MouseLeave;
+ 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.
+ gfx::Point(event->x, event->y), common_ancestor);
+ mouse_out.x = transformed_point.x();
+ mouse_out.y = transformed_point.y();
+ common_ancestor->ProcessMouseEvent(mouse_out, ui::LatencyInfo());
+ }
+
+ // Send MouseEnters.
+ for (auto view : entered_views) {
+ if (view == target)
+ continue;
+ blink::WebMouseEvent mouse_enter(*event);
+ // TODO(kenrb): Blink doesn't expect a MouseEnter to come from the browser
+ // process, so we send a MouseMove, which can cause event handlers to fire
+ // 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
+ mouse_enter.type = blink::WebInputEvent::MouseMove;
+ transformed_point = root_view->TransformPointToCoordSpaceForView(
+ gfx::Point(event->x, event->y), view);
+ mouse_enter.x = transformed_point.x();
+ mouse_enter.y = transformed_point.y();
+ view->ProcessMouseEvent(mouse_enter, ui::LatencyInfo());
+ }
+
+ last_mouse_move_target_ = target;
+ last_mouse_move_root_view_ = root_view;
+}
+
void RenderWidgetHostInputEventRouter::BubbleScrollEvent(
RenderWidgetHostViewBase* target_view,
const blink::WebGestureEvent& event) {
« 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