Commit e62845d4 authored by Alexandr Rakov's avatar Alexandr Rakov Committed by Commit Bot

Immediately found target when client disconnects.

This Cl fix page freeze when hit-test query send asynchronous
to the client and it disconnect before response.

Bug: 1079304
Change-Id: I0796df15b1e2c1354bd72fb84474e7b077db7d61
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2190693Reviewed-by: default avatarKen Buchanan <kenrb@chromium.org>
Reviewed-by: default avatarAdithya Srinivasan <adithyas@chromium.org>
Reviewed-by: default avatarSadrul Chowdhury <sadrul@chromium.org>
Commit-Queue: Adithya Srinivasan <adithyas@chromium.org>
Auto-Submit: Alexandr Rakov <alrakov@yandex-team.ru>
Cr-Commit-Position: refs/heads/master@{#780762}
parent 3f2a9796
...@@ -638,7 +638,7 @@ IN_PROC_BROWSER_TEST_F(PortalBrowserTest, AsyncEventTargetingIgnoresPortals) { ...@@ -638,7 +638,7 @@ IN_PROC_BROWSER_TEST_F(PortalBrowserTest, AsyncEventTargetingIgnoresPortals) {
WaitForHitTestData(portal_frame); WaitForHitTestData(portal_frame);
viz::mojom::InputTargetClient* target_client = viz::mojom::InputTargetClient* target_client =
main_frame->GetRenderWidgetHost()->input_target_client(); main_frame->GetRenderWidgetHost()->input_target_client().get();
ASSERT_TRUE(target_client); ASSERT_TRUE(target_client);
gfx::PointF root_location = gfx::PointF root_location =
......
...@@ -699,8 +699,8 @@ class CONTENT_EXPORT RenderWidgetHostImpl ...@@ -699,8 +699,8 @@ class CONTENT_EXPORT RenderWidgetHostImpl
// there are any queued messages belonging to it, they will be processed. // there are any queued messages belonging to it, they will be processed.
void DidProcessFrame(uint32_t frame_token); void DidProcessFrame(uint32_t frame_token);
viz::mojom::InputTargetClient* input_target_client() { mojo::Remote<viz::mojom::InputTargetClient>& input_target_client() {
return input_target_client_.get(); return input_target_client_;
} }
void SetInputTargetClient( void SetInputTargetClient(
......
...@@ -297,11 +297,11 @@ void RenderWidgetTargeter::QueryClient( ...@@ -297,11 +297,11 @@ void RenderWidgetTargeter::QueryClient(
RenderWidgetHostViewBase* last_request_target, RenderWidgetHostViewBase* last_request_target,
const gfx::PointF& last_target_location, const gfx::PointF& last_target_location,
TargetingRequest request) { TargetingRequest request) {
auto* target_client = target->host()->input_target_client(); auto& target_client = target->host()->input_target_client();
// |target_client| may not be set yet for this |target| on Mac, need to // |target_client| may not be set yet for this |target| on Mac, need to
// understand why this happens. https://crbug.com/859492. // understand why this happens. https://crbug.com/859492.
// We do not verify hit testing result under this circumstance. // We do not verify hit testing result under this circumstance.
if (!target_client) { if (!target_client.get() || !target_client.is_connected()) {
FoundTarget(target, target_location, false, &request); FoundTarget(target, target_location, false, &request);
return; return;
} }
...@@ -318,6 +318,10 @@ void RenderWidgetTargeter::QueryClient( ...@@ -318,6 +318,10 @@ void RenderWidgetTargeter::QueryClient(
last_target_location), last_target_location),
async_hit_test_timeout_delay_)); async_hit_test_timeout_delay_));
target_client.set_disconnect_handler(base::BindOnce(
&RenderWidgetTargeter::OnInputTargetDisconnect,
weak_ptr_factory_.GetWeakPtr(), target->GetWeakPtr(), target_location));
TRACE_EVENT_WITH_FLOW2( TRACE_EVENT_WITH_FLOW2(
"viz,benchmark", "Event.Pipeline", TRACE_ID_GLOBAL(trace_id_), "viz,benchmark", "Event.Pipeline", TRACE_ID_GLOBAL(trace_id_),
TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT, "step", TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT, "step",
...@@ -374,6 +378,8 @@ void RenderWidgetTargeter::FoundFrameSinkId( ...@@ -374,6 +378,8 @@ void RenderWidgetTargeter::FoundFrameSinkId(
request_in_flight_.reset(); request_in_flight_.reset();
async_hit_test_timeout_.reset(nullptr); async_hit_test_timeout_.reset(nullptr);
target->host()->input_target_client().set_disconnect_handler(
base::OnceClosure());
if (is_viz_hit_testing_debug_enabled_ && request.IsWebInputEventRequest() && if (is_viz_hit_testing_debug_enabled_ && request.IsWebInputEventRequest() &&
request.GetEvent()->GetType() == blink::WebInputEvent::Type::kMouseDown) { request.GetEvent()->GetType() == blink::WebInputEvent::Type::kMouseDown) {
...@@ -459,10 +465,16 @@ void RenderWidgetTargeter::AsyncHitTestTimedOut( ...@@ -459,10 +465,16 @@ void RenderWidgetTargeter::AsyncHitTestTimedOut(
if (!request.GetRootView()) if (!request.GetRootView())
return; return;
// Mark view as unresponsive so further events will not be sent to it. if (current_request_target) {
if (current_request_target) // Mark view as unresponsive so further events will not be sent to it.
unresponsive_views_.insert(current_request_target.get()); unresponsive_views_.insert(current_request_target.get());
// Reset disconnect handler for view.
current_request_target->host()
->input_target_client()
.set_disconnect_handler(base::OnceClosure());
}
if (request.GetRootView() == current_request_target.get()) { if (request.GetRootView() == current_request_target.get()) {
// When a request to the top-level frame times out then the event gets // When a request to the top-level frame times out then the event gets
// sent there anyway. It will trigger the hung renderer dialog if the // sent there anyway. It will trigger the hung renderer dialog if the
...@@ -475,4 +487,19 @@ void RenderWidgetTargeter::AsyncHitTestTimedOut( ...@@ -475,4 +487,19 @@ void RenderWidgetTargeter::AsyncHitTestTimedOut(
} }
} }
void RenderWidgetTargeter::OnInputTargetDisconnect(
base::WeakPtr<RenderWidgetHostViewBase> target,
const gfx::PointF& location) {
if (!async_hit_test_timeout_)
return;
async_hit_test_timeout_.reset(nullptr);
TargetingRequest request = std::move(request_in_flight_.value());
request_in_flight_.reset();
// Since we couldn't find the target frame among the child-frames
// we process the event in the current frame.
FoundTarget(target.get(), location, false, &request);
}
} // namespace content } // namespace content
...@@ -217,6 +217,9 @@ class RenderWidgetTargeter { ...@@ -217,6 +217,9 @@ class RenderWidgetTargeter {
base::WeakPtr<RenderWidgetHostViewBase> last_request_target, base::WeakPtr<RenderWidgetHostViewBase> last_request_target,
const gfx::PointF& last_target_location); const gfx::PointF& last_target_location);
void OnInputTargetDisconnect(base::WeakPtr<RenderWidgetHostViewBase> target,
const gfx::PointF& location);
HitTestResultsMatch GetHitTestResultsMatchBucket( HitTestResultsMatch GetHitTestResultsMatchBucket(
RenderWidgetHostViewBase* target, RenderWidgetHostViewBase* target,
TargetingRequest* request) const; TargetingRequest* request) const;
......
...@@ -3073,6 +3073,76 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessHitTestBrowserTest, ...@@ -3073,6 +3073,76 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessHitTestBrowserTest,
EXPECT_FALSE(child_frame_monitor.EventWasReceived()); EXPECT_FALSE(child_frame_monitor.EventWasReceived());
} }
// Verify that asynchronous hit test immediately handle
// when target client disconnects.
IN_PROC_BROWSER_TEST_F(SitePerProcessHitTestBrowserTest,
AsynchronousHitTestChildDisconnectClient) {
GURL main_url(embedded_test_server()->GetURL(
"/frame_tree/page_with_positioned_busy_frame.html"));
EXPECT_TRUE(NavigateToURL(shell(), main_url));
// It is safe to obtain the root frame tree node here, as it doesn't change.
FrameTreeNode* root = web_contents()->GetFrameTree()->root();
ASSERT_EQ(1U, root->child_count());
FrameTreeNode* child_node = root->child_at(0);
// Create listeners for mouse events.
RenderWidgetHostMouseEventMonitor main_frame_monitor(
root->current_frame_host()->GetRenderWidgetHost());
RenderWidgetHostMouseEventMonitor child_frame_monitor(
child_node->current_frame_host()->GetRenderWidgetHost());
EXPECT_EQ(
" Site A ------------ proxies for B C\n"
" +--Site B ------- proxies for A C\n"
" +--Site C -- proxies for A B\n"
"Where A = http://127.0.0.1/\n"
" B = http://baz.com/\n"
" C = http://bar.com/",
DepictFrameTree(root));
RenderWidgetHostInputEventRouter* router =
web_contents()->GetInputEventRouter();
WaitForHitTestData(child_node->current_frame_host());
RenderWidgetHostViewBase* root_view = static_cast<RenderWidgetHostViewBase*>(
root->current_frame_host()->GetRenderWidgetHost()->GetView());
// Target input event to child frame. It should get delivered to the main
// frame instead because the child frame main thread is non-responsive.
blink::WebMouseEvent child_event(
blink::WebInputEvent::Type::kMouseDown,
blink::WebInputEvent::kNoModifiers,
blink::WebInputEvent::GetStaticTimeStampForTests());
child_event.button = blink::WebPointerProperties::Button::kLeft;
SetWebEventPositions(&child_event, gfx::Point(75, 75), root_view);
child_event.click_count = 1;
main_frame_monitor.ResetEventReceived();
child_frame_monitor.ResetEventReceived();
{
InputEventAckWaiter waiter(root_view->GetRenderWidgetHost(),
child_event.GetType());
router->RouteMouseEvent(root_view, &child_event, ui::LatencyInfo());
// Raise error for call disconnect handler.
static_cast<RenderWidgetHostImpl*>(
root->current_frame_host()->GetRenderWidgetHost())
->input_target_client()
.internal_state()
->RaiseError();
waiter.Wait();
}
EXPECT_TRUE(main_frame_monitor.EventWasReceived());
EXPECT_NEAR(75, main_frame_monitor.event().PositionInWidget().x(),
kHitTestTolerance);
EXPECT_NEAR(75, main_frame_monitor.event().PositionInWidget().y(),
kHitTestTolerance);
EXPECT_FALSE(child_frame_monitor.EventWasReceived());
}
// Tooltips aren't used on Android, so no need to compile/run this test in that // Tooltips aren't used on Android, so no need to compile/run this test in that
// case. // case.
#if !defined(OS_ANDROID) #if !defined(OS_ANDROID)
......
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