Commit 293bb860 authored by Navid Zolghadr's avatar Navid Zolghadr Committed by Commit Bot

Reset last known cursor on mouse leave

Reset last known cursor in RenderWidgetInputHandler
upon receiving a mouse leave event so the very next
set cursor command in this widget always sets the
cursor.

This change originally failed
CursorUpdateReceivedFromCrossSiteIframe
test and fixes were added to EventHandler to stop
sending set cursor message when mouse is on a
remote embedded iframe by the embedder.

Bug: 899525
Change-Id: I0a7114bccc7c3087b4993a212e5d5a8c1b39a03b
Reviewed-on: https://chromium-review.googlesource.com/c/1365085
Commit-Queue: Navid Zolghadr <nzolghadr@chromium.org>
Reviewed-by: default avatarDave Tapuska <dtapuska@chromium.org>
Reviewed-by: default avatarCharlie Reis <creis@chromium.org>
Cr-Commit-Position: refs/heads/master@{#615964}
parent a164e645
...@@ -3310,7 +3310,7 @@ void CursorUpdateReceivedFromCrossSiteIframeHelper( ...@@ -3310,7 +3310,7 @@ void CursorUpdateReceivedFromCrossSiteIframeHelper(
} // namespace } // namespace
#if defined(OS_WIN) #if defined(USE_AURA)
// https://crbug.com/882458 // https://crbug.com/882458
#define MAYBE_CursorUpdateReceivedFromCrossSiteIframe \ #define MAYBE_CursorUpdateReceivedFromCrossSiteIframe \
DISABLED_CursorUpdateReceivedFromCrossSiteIframe DISABLED_CursorUpdateReceivedFromCrossSiteIframe
......
...@@ -350,6 +350,11 @@ void RenderWidgetInputHandler::HandleInputEvent( ...@@ -350,6 +350,11 @@ void RenderWidgetInputHandler::HandleInputEvent(
mouse_event.PositionInWidget().x, "y", mouse_event.PositionInWidget().x, "y",
mouse_event.PositionInWidget().y); mouse_event.PositionInWidget().y);
prevent_default = delegate_->WillHandleMouseEvent(mouse_event); prevent_default = delegate_->WillHandleMouseEvent(mouse_event);
// Reset the last known cursor if mouse has left this widget. So next
// time that the mouse enters we always set the cursor accordingly.
if (mouse_event.GetType() == WebInputEvent::kMouseLeave)
current_cursor_.reset();
} }
if (WebInputEvent::IsKeyboardEventType(input_event.GetType())) { if (WebInputEvent::IsKeyboardEventType(input_event.GetType())) {
...@@ -495,6 +500,14 @@ void RenderWidgetInputHandler::DidOverscrollFromBlink( ...@@ -495,6 +500,14 @@ void RenderWidgetInputHandler::DidOverscrollFromBlink(
delegate_->OnDidOverscroll(*params); delegate_->OnDidOverscroll(*params);
} }
bool RenderWidgetInputHandler::DidChangeCursor(const WebCursor& cursor) {
if (!current_cursor_ || !current_cursor_->IsEqual(cursor)) {
current_cursor_ = cursor;
return true;
}
return false;
}
bool RenderWidgetInputHandler::ProcessTouchAction( bool RenderWidgetInputHandler::ProcessTouchAction(
cc::TouchAction touch_action) { cc::TouchAction touch_action) {
// Ignore setTouchAction calls that result from synthetic touch events (eg. // Ignore setTouchAction calls that result from synthetic touch events (eg.
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#include "base/macros.h" #include "base/macros.h"
#include "base/time/time.h" #include "base/time/time.h"
#include "content/common/cursors/webcursor.h"
#include "content/common/input/input_event_ack.h" #include "content/common/input/input_event_ack.h"
#include "content/common/input/input_event_dispatch_type.h" #include "content/common/input/input_event_dispatch_type.h"
#include "content/renderer/input/main_thread_event_queue.h" #include "content/renderer/input/main_thread_event_queue.h"
...@@ -74,6 +75,10 @@ class CONTENT_EXPORT RenderWidgetInputHandler { ...@@ -74,6 +75,10 @@ class CONTENT_EXPORT RenderWidgetInputHandler {
// to the browser. // to the browser.
bool ProcessTouchAction(cc::TouchAction touch_action); bool ProcessTouchAction(cc::TouchAction touch_action);
// Process the new cursor and returns true if it has changed from the last
// cursor.
bool DidChangeCursor(const WebCursor& cursor);
private: private:
blink::WebInputEventResult HandleTouchEvent( blink::WebInputEventResult HandleTouchEvent(
const blink::WebCoalescedInputEvent& coalesced_event); const blink::WebCoalescedInputEvent& coalesced_event);
...@@ -85,6 +90,10 @@ class CONTENT_EXPORT RenderWidgetInputHandler { ...@@ -85,6 +90,10 @@ class CONTENT_EXPORT RenderWidgetInputHandler {
// Are we currently handling an input event? // Are we currently handling an input event?
bool handling_input_event_; bool handling_input_event_;
// We store the current cursor object so we can avoid spamming SetCursor
// messages.
base::Optional<WebCursor> current_cursor_;
// Used to intercept overscroll notifications while an event is being // Used to intercept overscroll notifications while an event is being
// handled. If the event causes overscroll, the overscroll metadata can be // handled. If the event causes overscroll, the overscroll metadata can be
// bundled in the event ack, saving an IPC. Note that we must continue // bundled in the event ack, saving an IPC. Note that we must continue
......
...@@ -1515,10 +1515,8 @@ void RenderWidget::DidChangeCursor(const WebCursorInfo& cursor_info) { ...@@ -1515,10 +1515,8 @@ void RenderWidget::DidChangeCursor(const WebCursorInfo& cursor_info) {
WebCursor cursor; WebCursor cursor;
InitializeCursorFromWebCursorInfo(&cursor, cursor_info); InitializeCursorFromWebCursorInfo(&cursor, cursor_info);
// Only send a SetCursor message if we need to make a change. // Only send a SetCursor message if we need to make a change.
if (!current_cursor_.IsEqual(cursor)) { if (input_handler_->DidChangeCursor(cursor))
current_cursor_ = cursor;
Send(new WidgetHostMsg_SetCursor(routing_id_, cursor)); Send(new WidgetHostMsg_SetCursor(routing_id_, cursor));
}
} }
void RenderWidget::AutoscrollStart(const blink::WebFloatPoint& point) { void RenderWidget::AutoscrollStart(const blink::WebFloatPoint& point) {
......
...@@ -799,10 +799,6 @@ class CONTENT_EXPORT RenderWidget ...@@ -799,10 +799,6 @@ class CONTENT_EXPORT RenderWidget
// The rect where this view should be initially shown. // The rect where this view should be initially shown.
gfx::Rect initial_rect_; gfx::Rect initial_rect_;
// We store the current cursor object so we can avoid spamming SetCursor
// messages.
WebCursor current_cursor_;
base::Optional<float> device_scale_factor_for_testing_; base::Optional<float> device_scale_factor_for_testing_;
// The size of the RenderWidget in DIPs. This may differ from // The size of the RenderWidget in DIPs. This may differ from
......
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
#include "content/common/input_messages.h" #include "content/common/input_messages.h"
#include "content/common/view_messages.h" #include "content/common/view_messages.h"
#include "content/common/visual_properties.h" #include "content/common/visual_properties.h"
#include "content/common/widget_messages.h"
#include "content/public/common/content_features.h" #include "content/public/common/content_features.h"
#include "content/public/test/mock_render_thread.h" #include "content/public/test/mock_render_thread.h"
#include "content/renderer/compositor/layer_tree_view.h" #include "content/renderer/compositor/layer_tree_view.h"
...@@ -266,6 +267,30 @@ class RenderWidgetUnittest : public testing::Test { ...@@ -266,6 +267,30 @@ class RenderWidgetUnittest : public testing::Test {
DISALLOW_COPY_AND_ASSIGN(RenderWidgetUnittest); DISALLOW_COPY_AND_ASSIGN(RenderWidgetUnittest);
}; };
TEST_F(RenderWidgetUnittest, CursorChange) {
blink::WebCursorInfo cursor_info;
cursor_info.type = blink::WebCursorInfo::Type::kTypePointer;
widget()->DidChangeCursor(cursor_info);
EXPECT_EQ(widget()->sink()->message_count(), 1U);
EXPECT_EQ(widget()->sink()->GetMessageAt(0)->type(),
WidgetHostMsg_SetCursor::ID);
widget()->sink()->ClearMessages();
widget()->DidChangeCursor(cursor_info);
EXPECT_EQ(widget()->sink()->message_count(), 0U);
widget()->SendInputEvent(SyntheticWebMouseEventBuilder::Build(
blink::WebInputEvent::Type::kMouseLeave),
HandledEventCallback());
EXPECT_EQ(widget()->sink()->message_count(), 0U);
widget()->DidChangeCursor(cursor_info);
EXPECT_EQ(widget()->sink()->message_count(), 1U);
EXPECT_EQ(widget()->sink()->GetMessageAt(0)->type(),
WidgetHostMsg_SetCursor::ID);
}
TEST_F(RenderWidgetUnittest, EventOverscroll) { TEST_F(RenderWidgetUnittest, EventOverscroll) {
widget()->set_always_overscroll(true); widget()->set_always_overscroll(true);
......
...@@ -632,7 +632,7 @@ WebInputEventResult EventHandler::HandleMousePressEvent( ...@@ -632,7 +632,7 @@ WebInputEventResult EventHandler::HandleMousePressEvent(
frame_->GetDocument()->SetSequentialFocusNavigationStartingPoint( frame_->GetDocument()->SetSequentialFocusNavigationStartingPoint(
mev.InnerNode()); mev.InnerNode());
LocalFrame* subframe = event_handling_util::SubframeForHitTestResult(mev); LocalFrame* subframe = event_handling_util::GetTargetSubframe(mev);
if (subframe) { if (subframe) {
WebInputEventResult result = PassMousePressEventToSubframe(mev, subframe); WebInputEventResult result = PassMousePressEventToSubframe(mev, subframe);
// Start capturing future events for this frame. We only do this if we // Start capturing future events for this frame. We only do this if we
...@@ -824,7 +824,6 @@ WebInputEventResult EventHandler::HandleMouseMoveOrLeaveEvent( ...@@ -824,7 +824,6 @@ WebInputEventResult EventHandler::HandleMouseMoveOrLeaveEvent(
bool force_leave) { bool force_leave) {
DCHECK(frame_); DCHECK(frame_);
DCHECK(frame_->View()); DCHECK(frame_->View());
mouse_event_manager_->SetLastKnownMousePosition(mouse_event); mouse_event_manager_->SetLastKnownMousePosition(mouse_event);
hover_timer_.Stop(); hover_timer_.Stop();
...@@ -924,11 +923,9 @@ WebInputEventResult EventHandler::HandleMouseMoveOrLeaveEvent( ...@@ -924,11 +923,9 @@ WebInputEventResult EventHandler::HandleMouseMoveOrLeaveEvent(
} }
WebInputEventResult event_result = WebInputEventResult::kNotHandled; WebInputEventResult event_result = WebInputEventResult::kNotHandled;
LocalFrame* new_subframe = bool is_remote_frame = false;
capturing_mouse_events_node_.Get() LocalFrame* new_subframe = event_handling_util::GetTargetSubframe(
? event_handling_util::SubframeForTargetNode( mev, capturing_mouse_events_node_.Get(), &is_remote_frame);
capturing_mouse_events_node_.Get())
: event_handling_util::SubframeForHitTestResult(mev);
// We want mouseouts to happen first, from the inside out. First send a // We want mouseouts to happen first, from the inside out. First send a
// move event to the last subframe so that it will fire mouseouts. // move event to the last subframe so that it will fire mouseouts.
...@@ -961,7 +958,8 @@ WebInputEventResult EventHandler::HandleMouseMoveOrLeaveEvent( ...@@ -961,7 +958,8 @@ WebInputEventResult EventHandler::HandleMouseMoveOrLeaveEvent(
// scrollbar hovering. // scrollbar hovering.
scrollbar->MouseMoved(mev.Event()); scrollbar->MouseMoved(mev.Event());
} }
if (LocalFrameView* view = frame_->View()) { LocalFrameView* view = frame_->View();
if (!is_remote_frame && view) {
EventHandler::OptionalCursor optional_cursor = EventHandler::OptionalCursor optional_cursor =
SelectCursor(mev.GetHitTestLocation(), mev.GetHitTestResult()); SelectCursor(mev.GetHitTestLocation(), mev.GetHitTestResult());
if (optional_cursor.IsCursorChange()) { if (optional_cursor.IsCursorChange()) {
...@@ -1040,11 +1038,8 @@ WebInputEventResult EventHandler::HandleMouseReleaseEvent( ...@@ -1040,11 +1038,8 @@ WebInputEventResult EventHandler::HandleMouseReleaseEvent(
event_handling_util::PerformMouseEventHitTest(frame_, request, event_handling_util::PerformMouseEventHitTest(frame_, request,
mouse_event); mouse_event);
Element* mouse_release_target = mev.InnerElement(); Element* mouse_release_target = mev.InnerElement();
LocalFrame* subframe = LocalFrame* subframe = event_handling_util::GetTargetSubframe(
capturing_mouse_events_node_.Get() mev, capturing_mouse_events_node_.Get());
? event_handling_util::SubframeForTargetNode(
capturing_mouse_events_node_.Get())
: event_handling_util::SubframeForHitTestResult(mev);
if (event_handler_will_reset_capturing_mouse_events_node_) if (event_handler_will_reset_capturing_mouse_events_node_)
capturing_mouse_events_node_ = nullptr; capturing_mouse_events_node_ = nullptr;
if (subframe) if (subframe)
......
...@@ -129,7 +129,7 @@ MouseEventWithHitTestResults PerformMouseEventHitTest( ...@@ -129,7 +129,7 @@ MouseEventWithHitTestResults PerformMouseEventHitTest(
mev); mev);
} }
LocalFrame* SubframeForTargetNode(Node* node) { LocalFrame* SubframeForTargetNode(Node* node, bool* is_remote_frame) {
if (!node) if (!node)
return nullptr; return nullptr;
...@@ -141,17 +141,28 @@ LocalFrame* SubframeForTargetNode(Node* node) { ...@@ -141,17 +141,28 @@ LocalFrame* SubframeForTargetNode(Node* node) {
ToLayoutEmbeddedContent(layout_object)->ChildFrameView(); ToLayoutEmbeddedContent(layout_object)->ChildFrameView();
if (!frame_view) if (!frame_view)
return nullptr; return nullptr;
if (!frame_view->IsLocalFrameView()) if (!frame_view->IsLocalFrameView()) {
if (is_remote_frame)
*is_remote_frame = true;
return nullptr; return nullptr;
}
return &ToLocalFrameView(frame_view)->GetFrame(); return &ToLocalFrameView(frame_view)->GetFrame();
} }
LocalFrame* SubframeForHitTestResult( LocalFrame* GetTargetSubframe(
const MouseEventWithHitTestResults& hit_test_result) { const MouseEventWithHitTestResults& hit_test_result,
Node* capturing_node,
bool* is_remote_frame) {
if (capturing_node) {
return event_handling_util::SubframeForTargetNode(capturing_node,
is_remote_frame);
}
if (!hit_test_result.IsOverEmbeddedContentView()) if (!hit_test_result.IsOverEmbeddedContentView())
return nullptr; return nullptr;
return SubframeForTargetNode(hit_test_result.InnerNode());
return SubframeForTargetNode(hit_test_result.InnerNode(), is_remote_frame);
} }
} // namespace event_handling_util } // namespace event_handling_util
......
...@@ -46,9 +46,11 @@ MouseEventWithHitTestResults PerformMouseEventHitTest(LocalFrame*, ...@@ -46,9 +46,11 @@ MouseEventWithHitTestResults PerformMouseEventHitTest(LocalFrame*,
const HitTestRequest&, const HitTestRequest&,
const WebMouseEvent&); const WebMouseEvent&);
LocalFrame* SubframeForHitTestResult(const MouseEventWithHitTestResults&); LocalFrame* GetTargetSubframe(const MouseEventWithHitTestResults&,
Node* capturing_node = nullptr,
bool* is_remote_frame = nullptr);
LocalFrame* SubframeForTargetNode(Node*); LocalFrame* SubframeForTargetNode(Node*, bool* is_remote_frame = nullptr);
class PointerEventTarget { class PointerEventTarget {
DISALLOW_NEW(); DISALLOW_NEW();
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment