Commit ef0975b0 authored by Navid Zolghadr's avatar Navid Zolghadr Committed by Commit Bot

Use async targeting to find drag and drop targets

Add callback supports to the RenderWidgetTargeter
and use the async targetting in drag and drop code
and register a callback to send drag events using
the callback. Note that since drag and drop events
aren't WebInputEvent it is not possible to use
FindTargetAndDispatch function of RenderWidgetTargeter
at this time.

Bug: 804633
Change-Id: I2ecea2b70d7ea619169685a3a7b531355ddc0d59
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1596840
Commit-Queue: Navid Zolghadr <nzolghadr@chromium.org>
Reviewed-by: default avatarSadrul Chowdhury <sadrul@chromium.org>
Cr-Commit-Position: refs/heads/master@{#665239}
parent 678c372a
...@@ -1389,6 +1389,13 @@ RenderWidgetHostInputEventRouter::GetRenderWidgetHostAtPoint( ...@@ -1389,6 +1389,13 @@ RenderWidgetHostInputEventRouter::GetRenderWidgetHostAtPoint(
.view->GetRenderWidgetHost()); .view->GetRenderWidgetHost());
} }
void RenderWidgetHostInputEventRouter::GetRenderWidgetHostAtPointAsynchronously(
RenderWidgetHostViewBase* root_view,
const gfx::PointF& point,
RenderWidgetTargeter::RenderWidgetHostAtPointCallback callback) {
event_targeter_->FindTargetAndCallback(root_view, point, std::move(callback));
}
RenderWidgetTargetResult RenderWidgetTargetResult
RenderWidgetHostInputEventRouter::FindTouchscreenGestureEventTarget( RenderWidgetHostInputEventRouter::FindTouchscreenGestureEventTarget(
RenderWidgetHostViewBase* root_view, RenderWidgetHostViewBase* root_view,
...@@ -1770,6 +1777,15 @@ RenderWidgetHostInputEventRouter::GetRenderWidgetTargeterForTests() { ...@@ -1770,6 +1777,15 @@ RenderWidgetHostInputEventRouter::GetRenderWidgetTargeterForTests() {
return event_targeter_.get(); return event_targeter_.get();
} }
RenderWidgetTargetResult
RenderWidgetHostInputEventRouter::FindTargetSynchronouslyAtLocation(
RenderWidgetHostViewBase* root_view,
const gfx::PointF& location) {
gfx::PointF transformed_pt; // This is already in the result
return FindViewAtLocation(root_view, location, gfx::PointF() /* not used */,
viz::EventSource::MOUSE, &transformed_pt);
}
RenderWidgetTargetResult RenderWidgetTargetResult
RenderWidgetHostInputEventRouter::FindTargetSynchronously( RenderWidgetHostInputEventRouter::FindTargetSynchronously(
RenderWidgetHostViewBase* root_view, RenderWidgetHostViewBase* root_view,
......
...@@ -135,6 +135,17 @@ class CONTENT_EXPORT RenderWidgetHostInputEventRouter ...@@ -135,6 +135,17 @@ class CONTENT_EXPORT RenderWidgetHostInputEventRouter
const gfx::PointF& point, const gfx::PointF& point,
gfx::PointF* transformed_point); gfx::PointF* transformed_point);
// Finds the RenderWidgetHostImpl inside the |root_view| at |point| where
// |point| is with respect to |root_view|'s coordinates. If a RWHI is found,
// it is passed along with the coordinate of the point with
// respect to the RWHI's coordinates to the callback function. If
// |root_view| is nullptr or RWHI is not found, the callback is called with
// nullptr and no location.
void GetRenderWidgetHostAtPointAsynchronously(
RenderWidgetHostViewBase* root_view,
const gfx::PointF& point,
RenderWidgetTargeter::RenderWidgetHostAtPointCallback callback);
// RenderWidgetTargeter::Delegate: // RenderWidgetTargeter::Delegate:
RenderWidgetHostViewBase* FindViewFromFrameSinkId( RenderWidgetHostViewBase* FindViewFromFrameSinkId(
const viz::FrameSinkId& frame_sink_id) const override; const viz::FrameSinkId& frame_sink_id) const override;
...@@ -312,6 +323,10 @@ class CONTENT_EXPORT RenderWidgetHostInputEventRouter ...@@ -312,6 +323,10 @@ class CONTENT_EXPORT RenderWidgetHostInputEventRouter
const RenderWidgetHostViewBase* view); const RenderWidgetHostViewBase* view);
// RenderWidgetTargeter::Delegate: // RenderWidgetTargeter::Delegate:
RenderWidgetTargetResult FindTargetSynchronouslyAtLocation(
RenderWidgetHostViewBase* root_view,
const gfx::PointF& location) override;
RenderWidgetTargetResult FindTargetSynchronously( RenderWidgetTargetResult FindTargetSynchronously(
RenderWidgetHostViewBase* root_view, RenderWidgetHostViewBase* root_view,
const blink::WebInputEvent& event) override; const blink::WebInputEvent& event) override;
......
...@@ -22,17 +22,6 @@ namespace content { ...@@ -22,17 +22,6 @@ namespace content {
namespace { namespace {
bool MergeEventIfPossible(const blink::WebInputEvent& event,
ui::WebScopedInputEvent* blink_event) {
if (!blink::WebInputEvent::IsTouchEventType(event.GetType()) &&
!blink::WebInputEvent::IsGestureEventType(event.GetType()) &&
ui::CanCoalesce(event, **blink_event)) {
ui::Coalesce(event, blink_event->get());
return true;
}
return false;
}
gfx::PointF ComputeEventLocation(const blink::WebInputEvent& event) { gfx::PointF ComputeEventLocation(const blink::WebInputEvent& event) {
if (blink::WebInputEvent::IsMouseEventType(event.GetType()) || if (blink::WebInputEvent::IsMouseEventType(event.GetType()) ||
event.GetType() == blink::WebInputEvent::kMouseWheel) { event.GetType() == blink::WebInputEvent::kMouseWheel) {
...@@ -118,7 +107,24 @@ RenderWidgetTargetResult::RenderWidgetTargetResult( ...@@ -118,7 +107,24 @@ RenderWidgetTargetResult::RenderWidgetTargetResult(
RenderWidgetTargetResult::~RenderWidgetTargetResult() = default; RenderWidgetTargetResult::~RenderWidgetTargetResult() = default;
RenderWidgetTargeter::TargetingRequest::TargetingRequest() = default; RenderWidgetTargeter::TargetingRequest::TargetingRequest(
base::WeakPtr<RenderWidgetHostViewBase> root_view,
const blink::WebInputEvent& event,
const ui::LatencyInfo& latency) {
this->root_view = std::move(root_view);
this->location = ComputeEventLocation(event);
this->event = ui::WebInputEventTraits::Clone(event);
this->latency = latency;
}
RenderWidgetTargeter::TargetingRequest::TargetingRequest(
base::WeakPtr<RenderWidgetHostViewBase> root_view,
const gfx::PointF& location,
RenderWidgetHostAtPointCallback callback) {
this->root_view = std::move(root_view);
this->location = location;
this->callback = std::move(callback);
}
RenderWidgetTargeter::TargetingRequest::TargetingRequest( RenderWidgetTargeter::TargetingRequest::TargetingRequest(
TargetingRequest&& request) = default; TargetingRequest&& request) = default;
...@@ -128,6 +134,68 @@ operator=(TargetingRequest&&) = default; ...@@ -128,6 +134,68 @@ operator=(TargetingRequest&&) = default;
RenderWidgetTargeter::TargetingRequest::~TargetingRequest() = default; RenderWidgetTargeter::TargetingRequest::~TargetingRequest() = default;
void RenderWidgetTargeter::TargetingRequest::RunCallback(
RenderWidgetHostViewBase* target,
base::Optional<gfx::PointF> point) {
if (!callback.is_null()) {
std::move(callback).Run(target ? target->GetWeakPtr() : nullptr, point);
}
}
bool RenderWidgetTargeter::TargetingRequest::MergeEventIfPossible(
const blink::WebInputEvent& new_event) {
if (event && !blink::WebInputEvent::IsTouchEventType(new_event.GetType()) &&
!blink::WebInputEvent::IsGestureEventType(new_event.GetType()) &&
ui::CanCoalesce(new_event, *event.get())) {
ui::Coalesce(new_event, event.get());
return true;
}
return false;
}
void RenderWidgetTargeter::TargetingRequest::StartQueueingTimeTracker() {
tracker =
std::make_unique<TracingUmaTracker>("Event.AsyncTargeting.TimeInQueue");
}
void RenderWidgetTargeter::TargetingRequest::StopQueueingTimeTracker() {
if (tracker)
tracker->Stop();
}
bool RenderWidgetTargeter::TargetingRequest::IsWebInputEventRequest() const {
return !!event;
}
const blink::WebInputEvent& RenderWidgetTargeter::TargetingRequest::GetEvent()
const {
return *event.get();
}
RenderWidgetHostViewBase* RenderWidgetTargeter::TargetingRequest::GetRootView()
const {
return root_view.get();
}
gfx::PointF RenderWidgetTargeter::TargetingRequest::GetLocation() const {
return location;
}
viz::FrameSinkId
RenderWidgetTargeter::TargetingRequest::GetExpectedFrameSinkId() const {
return expected_frame_sink_id;
}
void RenderWidgetTargeter::TargetingRequest::SetExpectedFrameSinkId(
const viz::FrameSinkId& id) {
expected_frame_sink_id = id;
}
const ui::LatencyInfo& RenderWidgetTargeter::TargetingRequest::GetLatency()
const {
return latency;
}
RenderWidgetTargeter::RenderWidgetTargeter(Delegate* delegate) RenderWidgetTargeter::RenderWidgetTargeter(Delegate* delegate)
: trace_id_(base::RandUint64()), : trace_id_(base::RandUint64()),
is_viz_hit_testing_debug_enabled_( is_viz_hit_testing_debug_enabled_(
...@@ -152,35 +220,48 @@ void RenderWidgetTargeter::FindTargetAndDispatch( ...@@ -152,35 +220,48 @@ void RenderWidgetTargeter::FindTargetAndDispatch(
static_cast<const blink::WebGestureEvent&>(event).SourceDevice() == static_cast<const blink::WebGestureEvent&>(event).SourceDevice() ==
blink::WebGestureDevice::kTouchpad))); blink::WebGestureDevice::kTouchpad)));
if (!requests_.empty()) {
auto& request = requests_.back();
if (request.MergeEventIfPossible(event))
return;
}
TargetingRequest request(root_view->GetWeakPtr(), event, latency);
ResolveTargetingRequest(std::move(request));
}
void RenderWidgetTargeter::FindTargetAndCallback(
RenderWidgetHostViewBase* root_view,
const gfx::PointF& point,
RenderWidgetHostAtPointCallback callback) {
TargetingRequest request(root_view->GetWeakPtr(), point, std::move(callback));
ResolveTargetingRequest(std::move(request));
}
void RenderWidgetTargeter::ResolveTargetingRequest(TargetingRequest request) {
if (request_in_flight_) { if (request_in_flight_) {
if (!requests_.empty()) { request.StartQueueingTimeTracker();
auto& request = requests_.back();
if (MergeEventIfPossible(event, &request.event))
return;
}
TargetingRequest request;
request.root_view = root_view->GetWeakPtr();
request.event = ui::WebInputEventTraits::Clone(event);
request.latency = latency;
request.tracker =
std::make_unique<TracingUmaTracker>("Event.AsyncTargeting.TimeInQueue");
requests_.push(std::move(request)); requests_.push(std::move(request));
return; return;
} }
RenderWidgetTargetResult result = RenderWidgetTargetResult result;
delegate_->FindTargetSynchronously(root_view, event); if (request.IsWebInputEventRequest()) {
result = delegate_->FindTargetSynchronously(request.GetRootView(),
const gfx::PointF event_location = ComputeEventLocation(event); request.GetEvent());
} else {
result = delegate_->FindTargetSynchronouslyAtLocation(
request.GetRootView(), request.GetLocation());
}
RenderWidgetHostViewBase* target = result.view; RenderWidgetHostViewBase* target = result.view;
auto* event_ptr = &event;
async_depth_ = 0; async_depth_ = 0;
if (result.should_query_view) { if (result.should_query_view) {
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_OUT, "step", "QueryClient(Start)", TRACE_EVENT_FLAG_FLOW_OUT, "step", "QueryClient(Start)",
"event_location", event_location.ToString()); "event_location", request.GetLocation().ToString());
// TODO(kenrb, sadrul): When all event types support asynchronous hit // TODO(kenrb, sadrul): When all event types support asynchronous hit
// testing, we should be able to have FindTargetSynchronously return the // testing, we should be able to have FindTargetSynchronously return the
...@@ -190,17 +271,15 @@ void RenderWidgetTargeter::FindTargetAndDispatch( ...@@ -190,17 +271,15 @@ void RenderWidgetTargeter::FindTargetAndDispatch(
// root_view and the original event location for the initial query. // root_view and the original event location for the initial query.
// Do not compare hit test results if we are forced to do async hit testing // Do not compare hit test results if we are forced to do async hit testing
// by HitTestQuery. // by HitTestQuery.
QueryClient(root_view, root_view, *event_ptr, latency, event_location, QueryClient(std::move(request));
nullptr, gfx::PointF());
} else { } else {
FoundTarget(root_view, target, *event_ptr, latency, result.target_location, FoundTarget(target, result.target_location, result.latched_target,
result.latched_target, viz::FrameSinkId()); &request);
// Verify the event targeting results from surface layer viz hit testing if // Verify the event targeting results from surface layer viz hit testing if
// --use-viz-hit-test-surface-layer is enabled. // --use-viz-hit-test-surface-layer is enabled.
if (result.should_verify_result && !target->IsRenderWidgetHostViewGuest()) { if (result.should_verify_result && !target->IsRenderWidgetHostViewGuest()) {
QueryAndVerifyClient(root_view, root_view, *event_ptr, latency, request.SetExpectedFrameSinkId(target->GetFrameSinkId());
event_location, nullptr, gfx::PointF(), QueryAndVerifyClient(std::move(request));
target->GetFrameSinkId());
} }
} }
} }
...@@ -214,17 +293,14 @@ bool RenderWidgetTargeter::HasEventsPendingDispatch() const { ...@@ -214,17 +293,14 @@ bool RenderWidgetTargeter::HasEventsPendingDispatch() const {
} }
void RenderWidgetTargeter::QueryClientInternal( void RenderWidgetTargeter::QueryClientInternal(
RenderWidgetHostViewBase* root_view,
RenderWidgetHostViewBase* target, RenderWidgetHostViewBase* target,
const blink::WebInputEvent& event,
const ui::LatencyInfo& latency,
const gfx::PointF& target_location, const gfx::PointF& target_location,
RenderWidgetHostViewBase* last_request_target, RenderWidgetHostViewBase* last_request_target,
const gfx::PointF& last_target_location, const gfx::PointF& last_target_location,
const viz::FrameSinkId& expected_frame_sink_id) { TargetingRequest request) {
// Async event targeting and verifying use two different queues, so they don't // Async event targeting and verifying use two different queues, so they don't
// block each other. // block each other.
bool is_verifying = expected_frame_sink_id.is_valid(); bool is_verifying = request.GetExpectedFrameSinkId().is_valid();
DCHECK((!is_verifying && !request_in_flight_) || DCHECK((!is_verifying && !request_in_flight_) ||
(is_verifying && !verify_request_in_flight_)); (is_verifying && !verify_request_in_flight_));
...@@ -233,15 +309,14 @@ void RenderWidgetTargeter::QueryClientInternal( ...@@ -233,15 +309,14 @@ void RenderWidgetTargeter::QueryClientInternal(
// 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) {
FoundTarget(root_view, target, event, latency, target_location, false, FoundTarget(target, target_location, false, &request);
viz::FrameSinkId());
return; return;
} }
if (is_verifying) { if (is_verifying) {
verify_request_in_flight_ = true; verify_request_in_flight_ = std::move(request);
} else { } else {
request_in_flight_ = true; request_in_flight_ = std::move(request);
async_depth_++; async_depth_++;
} }
TracingUmaTracker tracker("Event.AsyncTargeting.ResponseTime"); TracingUmaTracker tracker("Event.AsyncTargeting.ResponseTime");
...@@ -250,67 +325,46 @@ void RenderWidgetTargeter::QueryClientInternal( ...@@ -250,67 +325,46 @@ void RenderWidgetTargeter::QueryClientInternal(
hit_test_timeout.reset(new OneShotTimeoutMonitor( hit_test_timeout.reset(new OneShotTimeoutMonitor(
base::BindOnce( base::BindOnce(
&RenderWidgetTargeter::AsyncHitTestTimedOut, &RenderWidgetTargeter::AsyncHitTestTimedOut,
weak_ptr_factory_.GetWeakPtr(), root_view->GetWeakPtr(), weak_ptr_factory_.GetWeakPtr(), target->GetWeakPtr(), target_location,
target->GetWeakPtr(), target_location,
last_request_target ? last_request_target->GetWeakPtr() : nullptr, last_request_target ? last_request_target->GetWeakPtr() : nullptr,
last_target_location, ui::WebInputEventTraits::Clone(event), latency, last_target_location, is_verifying),
expected_frame_sink_id),
async_hit_test_timeout_delay_)); async_hit_test_timeout_delay_));
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",
"QueryClient", "event", blink::WebInputEvent::GetName(event.GetType())); "QueryClient", "event_location", request.GetLocation().ToString());
target_client->FrameSinkIdAt( target_client->FrameSinkIdAt(
target_location, trace_id_, target_location, trace_id_,
base::BindOnce( base::BindOnce(
&RenderWidgetTargeter::FoundFrameSinkId, &RenderWidgetTargeter::FoundFrameSinkId,
weak_ptr_factory_.GetWeakPtr(), root_view->GetWeakPtr(), weak_ptr_factory_.GetWeakPtr(), target->GetWeakPtr(),
target->GetWeakPtr(), ui::WebInputEventTraits::Clone(event), latency,
is_verifying ? ++last_verify_request_id_ : ++last_request_id_, is_verifying ? ++last_verify_request_id_ : ++last_request_id_,
target_location, std::move(tracker), expected_frame_sink_id)); target_location, std::move(tracker), is_verifying));
} }
void RenderWidgetTargeter::QueryClient( void RenderWidgetTargeter::QueryClient(TargetingRequest request) {
RenderWidgetHostViewBase* root_view, auto* target = request.GetRootView();
RenderWidgetHostViewBase* target, auto target_location = request.GetLocation();
const blink::WebInputEvent& event, QueryClientInternal(target, target_location, nullptr, gfx::PointF(),
const ui::LatencyInfo& latency, std::move(request));
const gfx::PointF& target_location,
RenderWidgetHostViewBase* last_request_target,
const gfx::PointF& last_target_location) {
QueryClientInternal(root_view, target, event, latency, target_location,
last_request_target, last_target_location,
viz::FrameSinkId());
} }
void RenderWidgetTargeter::QueryAndVerifyClient( void RenderWidgetTargeter::QueryAndVerifyClient(TargetingRequest request) {
RenderWidgetHostViewBase* root_view,
RenderWidgetHostViewBase* target,
const blink::WebInputEvent& event,
const ui::LatencyInfo& latency,
const gfx::PointF& target_location,
RenderWidgetHostViewBase* last_request_target,
const gfx::PointF& last_target_location,
const viz::FrameSinkId& expected_frame_sink_id) {
if (verify_request_in_flight_) { if (verify_request_in_flight_) {
TargetingRequest request;
request.root_view = root_view->GetWeakPtr();
request.event = ui::WebInputEventTraits::Clone(event);
request.latency = latency;
request.expected_frame_sink_id = expected_frame_sink_id;
verify_requests_.push(std::move(request)); verify_requests_.push(std::move(request));
return; return;
} }
QueryClientInternal(root_view, target, event, latency, target_location, auto* target = request.GetRootView();
last_request_target, last_target_location, auto target_location = request.GetLocation();
expected_frame_sink_id); QueryClientInternal(target, target_location, nullptr, gfx::PointF(),
std::move(request));
} }
void RenderWidgetTargeter::FlushEventQueue(bool is_verifying) { void RenderWidgetTargeter::FlushEventQueue(bool is_verifying) {
bool events_being_flushed = false; bool events_being_flushed = false;
bool& request_in_flight = base::Optional<TargetingRequest>& request_in_flight =
is_verifying ? verify_request_in_flight_ : request_in_flight_; is_verifying ? verify_request_in_flight_ : request_in_flight_;
auto* requests = is_verifying ? &verify_requests_ : &requests_; auto* requests = is_verifying ? &verify_requests_ : &requests_;
while (!request_in_flight && !requests->empty()) { while (!request_in_flight && !requests->empty()) {
...@@ -318,11 +372,10 @@ void RenderWidgetTargeter::FlushEventQueue(bool is_verifying) { ...@@ -318,11 +372,10 @@ void RenderWidgetTargeter::FlushEventQueue(bool is_verifying) {
requests->pop(); requests->pop();
// The root-view has gone away. Ignore this event, and try to process the // The root-view has gone away. Ignore this event, and try to process the
// next event. // next event.
if (!request.root_view) { if (!request.GetRootView()) {
continue; continue;
} }
if (request.tracker) request.StopQueueingTimeTracker();
request.tracker->Stop();
// Only notify the delegate once that the current event queue is being // Only notify the delegate once that the current event queue is being
// flushed. Once all the events are flushed, notify the delegate again. // flushed. Once all the events are flushed, notify the delegate again.
if (!is_verifying && !events_being_flushed) { if (!is_verifying && !events_being_flushed) {
...@@ -330,13 +383,9 @@ void RenderWidgetTargeter::FlushEventQueue(bool is_verifying) { ...@@ -330,13 +383,9 @@ void RenderWidgetTargeter::FlushEventQueue(bool is_verifying) {
events_being_flushed = true; events_being_flushed = true;
} }
if (is_verifying) { if (is_verifying) {
QueryAndVerifyClient(request.root_view.get(), request.root_view.get(), QueryAndVerifyClient(std::move(request));
*request.event, request.latency,
ComputeEventLocation(*request.event), nullptr,
gfx::PointF(), request.expected_frame_sink_id);
} else { } else {
FindTargetAndDispatch(request.root_view.get(), *request.event, ResolveTargetingRequest(std::move(request));
request.latency);
} }
} }
if (!is_verifying) if (!is_verifying)
...@@ -344,25 +393,24 @@ void RenderWidgetTargeter::FlushEventQueue(bool is_verifying) { ...@@ -344,25 +393,24 @@ void RenderWidgetTargeter::FlushEventQueue(bool is_verifying) {
} }
void RenderWidgetTargeter::FoundFrameSinkId( void RenderWidgetTargeter::FoundFrameSinkId(
base::WeakPtr<RenderWidgetHostViewBase> root_view,
base::WeakPtr<RenderWidgetHostViewBase> target, base::WeakPtr<RenderWidgetHostViewBase> target,
ui::WebScopedInputEvent event,
const ui::LatencyInfo& latency,
uint32_t request_id, uint32_t request_id,
const gfx::PointF& target_location, const gfx::PointF& target_location,
TracingUmaTracker tracker, TracingUmaTracker tracker,
const viz::FrameSinkId& expected_frame_sink_id, const bool is_verification_request,
const viz::FrameSinkId& frame_sink_id, const viz::FrameSinkId& frame_sink_id,
const gfx::PointF& transformed_location) { const gfx::PointF& transformed_location) {
if (expected_frame_sink_id.is_valid()) { if (is_verification_request) {
tracker.Stop(); tracker.Stop();
} else { } else {
tracker.StopAndRecord(); tracker.StopAndRecord();
} }
uint32_t last_id = expected_frame_sink_id.is_valid() ? last_verify_request_id_
: last_request_id_; uint32_t last_id =
bool in_flight = expected_frame_sink_id.is_valid() ? verify_request_in_flight_ is_verification_request ? last_verify_request_id_ : last_request_id_;
: request_in_flight_; bool in_flight = is_verification_request
? verify_request_in_flight_.has_value()
: request_in_flight_.has_value();
if (request_id != last_id || !in_flight) { if (request_id != last_id || !in_flight) {
// This is a response to a request that already timed out, so the event // This is a response to a request that already timed out, so the event
// should have already been dispatched. Mark the renderer as responsive // should have already been dispatched. Mark the renderer as responsive
...@@ -371,15 +419,20 @@ void RenderWidgetTargeter::FoundFrameSinkId( ...@@ -371,15 +419,20 @@ void RenderWidgetTargeter::FoundFrameSinkId(
return; return;
} }
if (expected_frame_sink_id.is_valid()) { TargetingRequest request = is_verification_request
verify_request_in_flight_ = false; ? std::move(verify_request_in_flight_.value())
: std::move(request_in_flight_.value());
if (request.GetExpectedFrameSinkId().is_valid()) {
verify_request_in_flight_.reset();
async_verify_hit_test_timeout_.reset(nullptr); async_verify_hit_test_timeout_.reset(nullptr);
} else { } else {
request_in_flight_ = false; request_in_flight_.reset();
async_hit_test_timeout_.reset(nullptr); async_hit_test_timeout_.reset(nullptr);
if (is_viz_hit_testing_debug_enabled_ && if (is_viz_hit_testing_debug_enabled_ && request.IsWebInputEventRequest() &&
event->GetType() == blink::WebInputEvent::Type::kMouseDown) { request.GetEvent().GetType() ==
blink::WebInputEvent::Type::kMouseDown) {
hit_test_async_queried_debug_queue_.push_back(target->GetFrameSinkId()); hit_test_async_queried_debug_queue_.push_back(target->GetFrameSinkId());
} }
} }
...@@ -400,46 +453,45 @@ void RenderWidgetTargeter::FoundFrameSinkId( ...@@ -400,46 +453,45 @@ void RenderWidgetTargeter::FoundFrameSinkId(
TRACE_EVENT_FLAG_FLOW_IN, "step", "FoundTarget"); TRACE_EVENT_FLAG_FLOW_IN, "step", "FoundTarget");
} }
FoundTarget(root_view.get(), view, *event, latency, transformed_location, FoundTarget(view, transformed_location, false, &request);
false, expected_frame_sink_id);
} else { } else {
QueryClientInternal(root_view.get(), view, *event, latency, QueryClientInternal(view, transformed_location, target.get(),
transformed_location, target.get(), target_location, target_location, std::move(request));
expected_frame_sink_id);
} }
} }
void RenderWidgetTargeter::FoundTarget( void RenderWidgetTargeter::FoundTarget(
RenderWidgetHostViewBase* root_view,
RenderWidgetHostViewBase* target, RenderWidgetHostViewBase* target,
const blink::WebInputEvent& event,
const ui::LatencyInfo& latency,
const base::Optional<gfx::PointF>& target_location, const base::Optional<gfx::PointF>& target_location,
bool latched_target, bool latched_target,
const viz::FrameSinkId& expected_frame_sink_id) { TargetingRequest* request) {
DCHECK(request);
if (SiteIsolationPolicy::UseDedicatedProcessesForAllSites() && if (SiteIsolationPolicy::UseDedicatedProcessesForAllSites() &&
!latched_target && !expected_frame_sink_id.is_valid()) { !latched_target && !request->GetExpectedFrameSinkId().is_valid()) {
UMA_HISTOGRAM_COUNTS_100("Event.AsyncTargeting.AsyncClientDepth", UMA_HISTOGRAM_COUNTS_100("Event.AsyncTargeting.AsyncClientDepth",
async_depth_); async_depth_);
} }
// RenderWidgetHostViewMac can be deleted asynchronously, in which case the // RenderWidgetHostViewMac can be deleted asynchronously, in which case the
// View will be valid but there will no longer be a RenderWidgetHostImpl. // View will be valid but there will no longer be a RenderWidgetHostImpl.
if (!root_view || !root_view->GetRenderWidgetHost()) if (!request->GetRootView() || !request->GetRootView()->GetRenderWidgetHost())
return; return;
if (is_viz_hit_testing_debug_enabled_ && if (is_viz_hit_testing_debug_enabled_ &&
!hit_test_async_queried_debug_queue_.empty()) { !hit_test_async_queried_debug_queue_.empty()) {
GetHostFrameSinkManager()->SetHitTestAsyncQueriedDebugRegions( GetHostFrameSinkManager()->SetHitTestAsyncQueriedDebugRegions(
root_view->GetRootFrameSinkId(), hit_test_async_queried_debug_queue_); request->GetRootView()->GetRootFrameSinkId(),
hit_test_async_queried_debug_queue_);
hit_test_async_queried_debug_queue_.clear(); hit_test_async_queried_debug_queue_.clear();
} }
if (features::IsVizHitTestingSurfaceLayerEnabled() && if (features::IsVizHitTestingSurfaceLayerEnabled() &&
expected_frame_sink_id.is_valid()) { request->GetExpectedFrameSinkId().is_valid()) {
static const char* kResultsMatchHistogramName = static const char* kResultsMatchHistogramName =
"Event.VizHitTestSurfaceLayer.ResultsMatch"; "Event.VizHitTestSurfaceLayer.ResultsMatch";
bool results_match = target->GetFrameSinkId() == expected_frame_sink_id; bool results_match =
target->GetFrameSinkId() == request->GetExpectedFrameSinkId();
HitTestResultsMatch match_result = HitTestResultsMatch match_result =
HitTestResultsMatch::kHitTestResultChanged; HitTestResultsMatch::kHitTestResultChanged;
if (results_match) { if (results_match) {
...@@ -448,10 +500,17 @@ void RenderWidgetTargeter::FoundTarget( ...@@ -448,10 +500,17 @@ void RenderWidgetTargeter::FoundTarget(
// If the results do not match, it is possible that the hit test data // If the results do not match, it is possible that the hit test data
// changed during verification. We do synchronous hit test again to make // changed during verification. We do synchronous hit test again to make
// sure the result is reliable. // sure the result is reliable.
RenderWidgetTargetResult result = RenderWidgetTargetResult result;
delegate_->FindTargetSynchronously(root_view, event); if (request->IsWebInputEventRequest()) {
result = delegate_->FindTargetSynchronously(request->GetRootView(),
request->GetEvent());
} else {
result = delegate_->FindTargetSynchronouslyAtLocation(
request->GetRootView(), request->GetLocation());
}
if (!result.should_query_view && result.view && if (!result.should_query_view && result.view &&
expected_frame_sink_id == result.view->GetFrameSinkId()) { request->GetExpectedFrameSinkId() == result.view->GetFrameSinkId()) {
// If the result did not change, it is likely that viz hit test finds // If the result did not change, it is likely that viz hit test finds
// the wrong target. // the wrong target.
match_result = HitTestResultsMatch::kDoNotMatch; match_result = HitTestResultsMatch::kDoNotMatch;
...@@ -465,48 +524,53 @@ void RenderWidgetTargeter::FoundTarget( ...@@ -465,48 +524,53 @@ void RenderWidgetTargeter::FoundTarget(
FlushEventQueue(true); FlushEventQueue(true);
return; return;
} }
delegate_->DispatchEventToTarget(root_view, target, event, latency, if (request->IsWebInputEventRequest()) {
target_location); delegate_->DispatchEventToTarget(request->GetRootView(), target,
request->GetEvent(), request->GetLatency(),
target_location);
} else {
request->RunCallback(target, target_location);
}
FlushEventQueue(false); FlushEventQueue(false);
} }
void RenderWidgetTargeter::AsyncHitTestTimedOut( void RenderWidgetTargeter::AsyncHitTestTimedOut(
base::WeakPtr<RenderWidgetHostViewBase> current_request_root_view,
base::WeakPtr<RenderWidgetHostViewBase> current_request_target, base::WeakPtr<RenderWidgetHostViewBase> current_request_target,
const gfx::PointF& current_target_location, const gfx::PointF& current_target_location,
base::WeakPtr<RenderWidgetHostViewBase> last_request_target, base::WeakPtr<RenderWidgetHostViewBase> last_request_target,
const gfx::PointF& last_target_location, const gfx::PointF& last_target_location,
ui::WebScopedInputEvent event, const bool is_verification_request) {
const ui::LatencyInfo& latency,
const viz::FrameSinkId& expected_frame_sink_id) {
DCHECK(request_in_flight_ || verify_request_in_flight_); DCHECK(request_in_flight_ || verify_request_in_flight_);
TargetingRequest request = is_verification_request
? std::move(verify_request_in_flight_.value())
: std::move(request_in_flight_.value());
// If we time out during a verification, we early out to avoid dispatching // If we time out during a verification, we early out to avoid dispatching
// event to root frame. // event to root frame.
if (expected_frame_sink_id.is_valid()) { if (request.GetExpectedFrameSinkId().is_valid()) {
verify_request_in_flight_ = false; verify_request_in_flight_.reset();
return; return;
} else { } else {
request_in_flight_ = false; request_in_flight_.reset();
} }
if (!current_request_root_view) if (!request.GetRootView())
return; return;
// Mark view as unresponsive so further events will not be sent to it. // Mark view as unresponsive so further events will not be sent to it.
if (current_request_target) if (current_request_target)
unresponsive_views_.insert(current_request_target.get()); unresponsive_views_.insert(current_request_target.get());
if (current_request_root_view.get() == 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
// renderer fails to process it. // renderer fails to process it.
FoundTarget(current_request_root_view.get(), FoundTarget(current_request_target.get(), current_target_location, false,
current_request_root_view.get(), *event, latency, &request);
current_target_location, false, viz::FrameSinkId());
} else { } else {
FoundTarget(current_request_root_view.get(), last_request_target.get(), FoundTarget(last_request_target.get(), last_target_location, false,
*event, latency, last_target_location, false, &request);
viz::FrameSinkId());
} }
} }
......
...@@ -6,12 +6,12 @@ ...@@ -6,12 +6,12 @@
#define CONTENT_BROWSER_RENDERER_HOST_RENDER_WIDGET_TARGETER_H_ #define CONTENT_BROWSER_RENDERER_HOST_RENDER_WIDGET_TARGETER_H_
#include <queue> #include <queue>
#include <unordered_set>
#include "base/memory/weak_ptr.h" #include "base/memory/weak_ptr.h"
#include "base/optional.h" #include "base/optional.h"
#include "base/time/time.h" #include "base/time/time.h"
#include "components/viz/common/surfaces/frame_sink_id.h" #include "components/viz/common/surfaces/frame_sink_id.h"
#include "content/browser/renderer_host/render_widget_host_view_base.h"
#include "content/common/content_constants_internal.h" #include "content/common/content_constants_internal.h"
#include "content/common/content_export.h" #include "content/common/content_export.h"
#include "ui/events/blink/web_input_event_traits.h" #include "ui/events/blink/web_input_event_traits.h"
...@@ -60,10 +60,18 @@ class TracingUmaTracker; ...@@ -60,10 +60,18 @@ class TracingUmaTracker;
class RenderWidgetTargeter { class RenderWidgetTargeter {
public: public:
using RenderWidgetHostAtPointCallback =
base::OnceCallback<void(base::WeakPtr<RenderWidgetHostViewBase>,
base::Optional<gfx::PointF>)>;
class Delegate { class Delegate {
public: public:
virtual ~Delegate() {} virtual ~Delegate() {}
virtual RenderWidgetTargetResult FindTargetSynchronouslyAtLocation(
RenderWidgetHostViewBase* root_view,
const gfx::PointF& location) = 0;
virtual RenderWidgetTargetResult FindTargetSynchronously( virtual RenderWidgetTargetResult FindTargetSynchronously(
RenderWidgetHostViewBase* root_view, RenderWidgetHostViewBase* root_view,
const blink::WebInputEvent& event) = 0; const blink::WebInputEvent& event) = 0;
...@@ -97,6 +105,13 @@ class RenderWidgetTargeter { ...@@ -97,6 +105,13 @@ class RenderWidgetTargeter {
const blink::WebInputEvent& event, const blink::WebInputEvent& event,
const ui::LatencyInfo& latency); const ui::LatencyInfo& latency);
// Finds the appropriate target inside |root_view| for |point|, and passes the
// target along with the transformed coordinates of the point with respect to
// the target's coordinates.
void FindTargetAndCallback(RenderWidgetHostViewBase* root_view,
const gfx::PointF& point,
RenderWidgetHostAtPointCallback callback);
void ViewWillBeDestroyed(RenderWidgetHostViewBase* view); void ViewWillBeDestroyed(RenderWidgetHostViewBase* view);
bool HasEventsPendingDispatch() const; bool HasEventsPendingDispatch() const;
...@@ -107,9 +122,65 @@ class RenderWidgetTargeter { ...@@ -107,9 +122,65 @@ class RenderWidgetTargeter {
} }
size_t num_requests_in_queue_for_testing() { return requests_.size(); } size_t num_requests_in_queue_for_testing() { return requests_.size(); }
bool is_request_in_flight_for_testing() { return request_in_flight_; } bool is_request_in_flight_for_testing() {
return request_in_flight_.has_value();
}
private: private:
class TargetingRequest {
public:
TargetingRequest(base::WeakPtr<RenderWidgetHostViewBase>,
const blink::WebInputEvent&,
const ui::LatencyInfo&);
TargetingRequest(base::WeakPtr<RenderWidgetHostViewBase>,
const gfx::PointF&,
RenderWidgetHostAtPointCallback);
TargetingRequest(TargetingRequest&& request);
TargetingRequest& operator=(TargetingRequest&& other);
~TargetingRequest();
void RunCallback(RenderWidgetHostViewBase* target,
base::Optional<gfx::PointF> point);
bool MergeEventIfPossible(const blink::WebInputEvent& event);
bool IsWebInputEventRequest() const;
const blink::WebInputEvent& GetEvent() const;
RenderWidgetHostViewBase* GetRootView() const;
gfx::PointF GetLocation() const;
const ui::LatencyInfo& GetLatency() const;
// Queued TragetingRequest
void StartQueueingTimeTracker();
void StopQueueingTimeTracker();
// Verification TargetingRequest
viz::FrameSinkId GetExpectedFrameSinkId() const;
void SetExpectedFrameSinkId(const viz::FrameSinkId& id);
private:
base::WeakPtr<RenderWidgetHostViewBase> root_view;
RenderWidgetHostAtPointCallback callback;
// |location| is in the coordinate space of |root_view| which is
// either set directly when event is null or calculated from the event.
gfx::PointF location;
// |event| if set is in the coordinate space of |root_view|.
ui::WebScopedInputEvent event;
ui::LatencyInfo latency;
// |expected_frame_sink_id| is only valid if the request is for
// verification.
viz::FrameSinkId expected_frame_sink_id;
// To track how long the request has been queued.
std::unique_ptr<TracingUmaTracker> tracker;
DISALLOW_COPY_AND_ASSIGN(TargetingRequest);
};
void ResolveTargetingRequest(TargetingRequest);
// Attempts to target and dispatch all events in the queue. It stops if it has // Attempts to target and dispatch all events in the queue. It stops if it has
// to query a client, or if the queue becomes empty. // to query a client, or if the queue becomes empty.
void FlushEventQueue(bool is_verifying); void FlushEventQueue(bool is_verifying);
...@@ -127,33 +198,17 @@ class RenderWidgetTargeter { ...@@ -127,33 +198,17 @@ class RenderWidgetTargeter {
// correctly. // correctly.
// TODO(sunxd): Remove |expected_frame_sink_id| after verifying synchronous // TODO(sunxd): Remove |expected_frame_sink_id| after verifying synchronous
// hit testing correctness. See https://crbug.com/871996. // hit testing correctness. See https://crbug.com/871996.
void QueryClientInternal(RenderWidgetHostViewBase* root_view, void QueryClientInternal(RenderWidgetHostViewBase* target,
RenderWidgetHostViewBase* target,
const blink::WebInputEvent& event,
const ui::LatencyInfo& latency,
const gfx::PointF& target_location, const gfx::PointF& target_location,
RenderWidgetHostViewBase* last_request_target, RenderWidgetHostViewBase* last_request_target,
const gfx::PointF& last_target_location, const gfx::PointF& last_target_location,
const viz::FrameSinkId& expected_frame_sink_id); TargetingRequest request);
void QueryClient(RenderWidgetHostViewBase* root_view, void QueryClient(TargetingRequest request);
RenderWidgetHostViewBase* target,
const blink::WebInputEvent& event, void QueryAndVerifyClient(TargetingRequest request);
const ui::LatencyInfo& latency,
const gfx::PointF& target_location, // |target_location|, if
RenderWidgetHostViewBase* last_request_target,
const gfx::PointF& last_target_location);
void QueryAndVerifyClient(RenderWidgetHostViewBase* root_view,
RenderWidgetHostViewBase* target,
const blink::WebInputEvent& event,
const ui::LatencyInfo& latency,
const gfx::PointF& target_location,
RenderWidgetHostViewBase* last_request_target,
const gfx::PointF& last_target_location,
const viz::FrameSinkId& expected_frame_sink_id);
// |event| is in the coordinate space of |root_view|. |target_location|, if
// set, is the location in |target|'s coordinate space. // set, is the location in |target|'s coordinate space.
// |target| is the current target that will be queried using its // |target| is the current target that will be queried using its
// InputTargetClient interface. // InputTargetClient interface.
...@@ -162,66 +217,44 @@ class RenderWidgetTargeter { ...@@ -162,66 +217,44 @@ class RenderWidgetTargeter {
// that new target's coordinate space. // that new target's coordinate space.
// |expected_frame_sink_id| is the expected hit test result based on // |expected_frame_sink_id| is the expected hit test result based on
// synchronous event targeting with cc generated data. // synchronous event targeting with cc generated data.
void FoundFrameSinkId(base::WeakPtr<RenderWidgetHostViewBase> root_view, void FoundFrameSinkId(base::WeakPtr<RenderWidgetHostViewBase> target,
base::WeakPtr<RenderWidgetHostViewBase> target,
ui::WebScopedInputEvent event,
const ui::LatencyInfo& latency,
uint32_t request_id, uint32_t request_id,
const gfx::PointF& target_location, const gfx::PointF& target_location,
TracingUmaTracker tracker, TracingUmaTracker tracker,
const viz::FrameSinkId& expected_frame_sink_id, const bool is_verification_request,
const viz::FrameSinkId& frame_sink_id, const viz::FrameSinkId& frame_sink_id,
const gfx::PointF& transformed_location); const gfx::PointF& transformed_location);
// |event| is in the coordinate space of |root_view|. |target_location|, if // |target_location|, if
// set, is the location in |target|'s coordinate space. If |latched_target| is // set, is the location in |target|'s coordinate space. If |latched_target| is
// false, we explicitly did hit-testing for this event, instead of using a // false, we explicitly did hit-testing for this event, instead of using a
// known target. // known target.
void FoundTarget(RenderWidgetHostViewBase* root_view, void FoundTarget(RenderWidgetHostViewBase* target,
RenderWidgetHostViewBase* target,
const blink::WebInputEvent& event,
const ui::LatencyInfo& latency,
const base::Optional<gfx::PointF>& target_location, const base::Optional<gfx::PointF>& target_location,
bool latched_target, bool latched_target,
const viz::FrameSinkId& expected_frame_sink_id); TargetingRequest* request);
// Callback when the hit testing timer fires, to resume event processing // Callback when the hit testing timer fires, to resume event processing
// without further waiting for a response to the last targeting request. // without further waiting for a response to the last targeting request.
void AsyncHitTestTimedOut( void AsyncHitTestTimedOut(
base::WeakPtr<RenderWidgetHostViewBase> current_request_root_view,
base::WeakPtr<RenderWidgetHostViewBase> current_request_target, base::WeakPtr<RenderWidgetHostViewBase> current_request_target,
const gfx::PointF& current_target_location, const gfx::PointF& current_target_location,
base::WeakPtr<RenderWidgetHostViewBase> last_request_target, base::WeakPtr<RenderWidgetHostViewBase> last_request_target,
const gfx::PointF& last_target_location, const gfx::PointF& last_target_location,
ui::WebScopedInputEvent event, const bool is_verification_request);
const ui::LatencyInfo& latency,
const viz::FrameSinkId& expected_frame_sink_id);
base::TimeDelta async_hit_test_timeout_delay() { base::TimeDelta async_hit_test_timeout_delay() {
return async_hit_test_timeout_delay_; return async_hit_test_timeout_delay_;
} }
struct TargetingRequest { base::Optional<TargetingRequest> request_in_flight_;
TargetingRequest();
TargetingRequest(TargetingRequest&& request);
TargetingRequest& operator=(TargetingRequest&& other);
~TargetingRequest();
base::WeakPtr<RenderWidgetHostViewBase> root_view;
ui::WebScopedInputEvent event;
ui::LatencyInfo latency;
viz::FrameSinkId expected_frame_sink_id;
std::unique_ptr<TracingUmaTracker> tracker;
};
bool request_in_flight_ = false;
uint32_t last_request_id_ = 0; uint32_t last_request_id_ = 0;
std::queue<TargetingRequest> requests_; std::queue<TargetingRequest> requests_;
// With viz-hit-testing-surface-layer being enabled, we do async hit testing // With viz-hit-testing-surface-layer being enabled, we do async hit testing
// for already dispatched events for verification. These verification requests // for already dispatched events for verification. These verification requests
// should not block normal hit testing requests. // should not block normal hit testing requests.
bool verify_request_in_flight_ = false; base::Optional<TargetingRequest> verify_request_in_flight_;
uint32_t last_verify_request_id_ = 0; uint32_t last_verify_request_id_ = 0;
std::queue<TargetingRequest> verify_requests_; std::queue<TargetingRequest> verify_requests_;
......
...@@ -1232,25 +1232,22 @@ void WebContentsViewAura::OnMouseEvent(ui::MouseEvent* event) { ...@@ -1232,25 +1232,22 @@ void WebContentsViewAura::OnMouseEvent(ui::MouseEvent* event) {
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// WebContentsViewAura, aura::client::DragDropDelegate implementation: // WebContentsViewAura, aura::client::DragDropDelegate implementation:
void WebContentsViewAura::OnDragEntered(const ui::DropTargetEvent& event) { void WebContentsViewAura::DragEnteredCallback(
#if defined(OS_WIN) const ui::DropTargetEvent& event,
async_drop_navigation_observer_.reset(); std::unique_ptr<DropData> drop_data,
#endif base::WeakPtr<RenderWidgetHostViewBase> target,
base::Optional<gfx::PointF> transformed_pt) {
gfx::PointF transformed_pt; if (!target)
return;
RenderWidgetHostImpl* target_rwh = RenderWidgetHostImpl* target_rwh =
web_contents_->GetInputEventRouter()->GetRenderWidgetHostAtPoint( RenderWidgetHostImpl::From(target->GetRenderWidgetHost());
web_contents_->GetRenderViewHost()->GetWidget()->GetView(),
event.location_f(), &transformed_pt);
if (!IsValidDragTarget(target_rwh)) if (!IsValidDragTarget(target_rwh))
return; return;
current_rwh_for_drag_ = target_rwh->GetWeakPtr(); current_rwh_for_drag_ = target_rwh->GetWeakPtr();
current_rvh_for_drag_ = current_rvh_for_drag_ =
GetRenderViewHostID(web_contents_->GetRenderViewHost()); GetRenderViewHostID(web_contents_->GetRenderViewHost());
current_drop_data_.reset(new DropData()); current_drop_data_.reset(drop_data.release());
PrepareDropData(current_drop_data_.get(), event.data());
current_rwh_for_drag_->FilterDropData(current_drop_data_.get()); current_rwh_for_drag_->FilterDropData(current_drop_data_.get());
blink::WebDragOperationsMask op = ConvertToWeb(event.source_operations()); blink::WebDragOperationsMask op = ConvertToWeb(event.source_operations());
...@@ -1266,26 +1263,50 @@ void WebContentsViewAura::OnDragEntered(const ui::DropTargetEvent& event) { ...@@ -1266,26 +1263,50 @@ void WebContentsViewAura::OnDragEntered(const ui::DropTargetEvent& event) {
if (drag_dest_delegate_) if (drag_dest_delegate_)
drag_dest_delegate_->DragInitialize(web_contents_); drag_dest_delegate_->DragInitialize(web_contents_);
DCHECK(transformed_pt.has_value());
gfx::PointF screen_pt(display::Screen::GetScreen()->GetCursorScreenPoint()); gfx::PointF screen_pt(display::Screen::GetScreen()->GetCursorScreenPoint());
current_rwh_for_drag_->DragTargetDragEnter( current_rwh_for_drag_->DragTargetDragEnter(
*current_drop_data_, transformed_pt, screen_pt, op, *current_drop_data_, transformed_pt.value(), screen_pt, op,
ui::EventFlagsToWebEventModifiers(event.flags())); ui::EventFlagsToWebEventModifiers(event.flags()));
if (drag_dest_delegate_) { if (drag_dest_delegate_) {
drag_dest_delegate_->OnReceiveDragData(event.data());
drag_dest_delegate_->OnDragEnter(); drag_dest_delegate_->OnDragEnter();
} }
} }
int WebContentsViewAura::OnDragUpdated(const ui::DropTargetEvent& event) { void WebContentsViewAura::OnDragEntered(const ui::DropTargetEvent& event) {
gfx::PointF transformed_pt; #if defined(OS_WIN)
RenderWidgetHostImpl* target_rwh = async_drop_navigation_observer_.reset();
web_contents_->GetInputEventRouter()->GetRenderWidgetHostAtPoint( #endif
std::unique_ptr<DropData> drop_data = std::make_unique<DropData>();
// Calling this here as event.data might become invalid inside the callback.
PrepareDropData(drop_data.get(), event.data());
if (drag_dest_delegate_) {
drag_dest_delegate_->OnReceiveDragData(event.data());
}
web_contents_->GetInputEventRouter()
->GetRenderWidgetHostAtPointAsynchronously(
web_contents_->GetRenderViewHost()->GetWidget()->GetView(), web_contents_->GetRenderViewHost()->GetWidget()->GetView(),
event.location_f(), &transformed_pt); event.location_f(),
base::BindOnce(&WebContentsViewAura::DragEnteredCallback,
weak_ptr_factory_.GetWeakPtr(), event,
std::move(drop_data)));
}
void WebContentsViewAura::DragUpdatedCallback(
const ui::DropTargetEvent& event,
std::unique_ptr<DropData> drop_data,
base::WeakPtr<RenderWidgetHostViewBase> target,
base::Optional<gfx::PointF> transformed_pt) {
if (!target)
return;
RenderWidgetHostImpl* target_rwh =
RenderWidgetHostImpl::From(target->GetRenderWidgetHost());
if (!IsValidDragTarget(target_rwh)) if (!IsValidDragTarget(target_rwh))
return ui::DragDropTypes::DRAG_NONE; return;
aura::Window* root_window = GetNativeView()->GetRootWindow(); aura::Window* root_window = GetNativeView()->GetRootWindow();
aura::client::ScreenPositionClient* screen_position_client = aura::client::ScreenPositionClient* screen_position_client =
...@@ -1307,20 +1328,35 @@ int WebContentsViewAura::OnDragUpdated(const ui::DropTargetEvent& event) { ...@@ -1307,20 +1328,35 @@ int WebContentsViewAura::OnDragUpdated(const ui::DropTargetEvent& event) {
current_rwh_for_drag_->DragTargetDragLeave(transformed_leave_point, current_rwh_for_drag_->DragTargetDragLeave(transformed_leave_point,
screen_pt); screen_pt);
} }
OnDragEntered(event); DragEnteredCallback(event, std::move(drop_data), target, transformed_pt);
} }
if (!current_drop_data_) if (!current_drop_data_) {
return ui::DragDropTypes::DRAG_NONE; return;
}
DCHECK(transformed_pt.has_value());
blink::WebDragOperationsMask op = ConvertToWeb(event.source_operations()); blink::WebDragOperationsMask op = ConvertToWeb(event.source_operations());
target_rwh->DragTargetDragOver( target_rwh->DragTargetDragOver(
transformed_pt, screen_pt, op, transformed_pt.value(), screen_pt, op,
ui::EventFlagsToWebEventModifiers(event.flags())); ui::EventFlagsToWebEventModifiers(event.flags()));
if (drag_dest_delegate_) if (drag_dest_delegate_)
drag_dest_delegate_->OnDragOver(); drag_dest_delegate_->OnDragOver();
}
int WebContentsViewAura::OnDragUpdated(const ui::DropTargetEvent& event) {
std::unique_ptr<DropData> drop_data = std::make_unique<DropData>();
// Calling this here as event.data might become invalid inside the callback.
PrepareDropData(drop_data.get(), event.data());
web_contents_->GetInputEventRouter()
->GetRenderWidgetHostAtPointAsynchronously(
web_contents_->GetRenderViewHost()->GetWidget()->GetView(),
event.location_f(),
base::BindOnce(&WebContentsViewAura::DragUpdatedCallback,
weak_ptr_factory_.GetWeakPtr(), event,
std::move(drop_data)));
return ConvertFromWeb(current_drag_op_); return ConvertFromWeb(current_drag_op_);
} }
...@@ -1342,25 +1378,31 @@ void WebContentsViewAura::OnDragExited() { ...@@ -1342,25 +1378,31 @@ void WebContentsViewAura::OnDragExited() {
current_drop_data_.reset(); current_drop_data_.reset();
} }
int WebContentsViewAura::OnPerformDrop(const ui::DropTargetEvent& event) { void WebContentsViewAura::PerformDropCallback(
gfx::PointF transformed_pt; const ui::DropTargetEvent& event,
std::unique_ptr<DropData> drop_data,
base::WeakPtr<RenderWidgetHostViewBase> target,
base::Optional<gfx::PointF> transformed_pt) {
if (!target)
return;
RenderWidgetHostImpl* target_rwh = RenderWidgetHostImpl* target_rwh =
web_contents_->GetInputEventRouter()->GetRenderWidgetHostAtPoint( RenderWidgetHostImpl::From(target->GetRenderWidgetHost());
web_contents_->GetRenderViewHost()->GetWidget()->GetView(),
event.location_f(), &transformed_pt);
if (!IsValidDragTarget(target_rwh)) if (!IsValidDragTarget(target_rwh))
return ui::DragDropTypes::DRAG_NONE; return;
DCHECK(transformed_pt.has_value());
gfx::PointF screen_pt(display::Screen::GetScreen()->GetCursorScreenPoint()); gfx::PointF screen_pt(display::Screen::GetScreen()->GetCursorScreenPoint());
if (target_rwh != current_rwh_for_drag_.get()) { if (target_rwh != current_rwh_for_drag_.get()) {
if (current_rwh_for_drag_) if (current_rwh_for_drag_)
current_rwh_for_drag_->DragTargetDragLeave(transformed_pt, screen_pt); current_rwh_for_drag_->DragTargetDragLeave(transformed_pt.value(),
OnDragEntered(event); screen_pt);
DragEnteredCallback(event, std::move(drop_data), target, transformed_pt);
} }
if (!current_drop_data_) if (!current_drop_data_) {
return ui::DragDropTypes::DRAG_NONE; return;
}
const int key_modifiers = ui::EventFlagsToWebEventModifiers(event.flags()); const int key_modifiers = ui::EventFlagsToWebEventModifiers(event.flags());
#if defined(OS_WIN) #if defined(OS_WIN)
...@@ -1386,16 +1428,29 @@ int WebContentsViewAura::OnPerformDrop(const ui::DropTargetEvent& event) { ...@@ -1386,16 +1428,29 @@ int WebContentsViewAura::OnPerformDrop(const ui::DropTargetEvent& event) {
async_drop_navigation_observer_ = async_drop_navigation_observer_ =
std::make_unique<AsyncDropNavigationObserver>( std::make_unique<AsyncDropNavigationObserver>(
web_contents_, std::move(current_drop_data_), target_rwh, web_contents_, std::move(current_drop_data_), target_rwh,
transformed_pt, screen_pt, key_modifiers); transformed_pt.value(), screen_pt, key_modifiers);
return;
return ConvertFromWeb(current_drag_op_);
} }
} }
#endif #endif
CompleteDrop(target_rwh, *current_drop_data_, transformed_pt, screen_pt, CompleteDrop(target_rwh, *current_drop_data_, transformed_pt.value(),
key_modifiers); screen_pt, key_modifiers);
current_drop_data_.reset(); current_drop_data_.reset();
}
int WebContentsViewAura::OnPerformDrop(const ui::DropTargetEvent& event) {
std::unique_ptr<DropData> drop_data = std::make_unique<DropData>();
// Calling this here as event.data might become invalid inside the callback.
PrepareDropData(drop_data.get(), event.data());
web_contents_->GetInputEventRouter()
->GetRenderWidgetHostAtPointAsynchronously(
web_contents_->GetRenderViewHost()->GetWidget()->GetView(),
event.location_f(),
base::BindOnce(&WebContentsViewAura::PerformDropCallback,
weak_ptr_factory_.GetWeakPtr(), event,
std::move(drop_data)));
return ConvertFromWeb(current_drag_op_); return ConvertFromWeb(current_drag_op_);
} }
......
...@@ -73,6 +73,7 @@ class CONTENT_EXPORT WebContentsViewAura ...@@ -73,6 +73,7 @@ class CONTENT_EXPORT WebContentsViewAura
FRIEND_TEST_ALL_PREFIXES(WebContentsViewAuraTest, FRIEND_TEST_ALL_PREFIXES(WebContentsViewAuraTest,
DragDropVirtualFilesOriginateFromRenderer); DragDropVirtualFilesOriginateFromRenderer);
FRIEND_TEST_ALL_PREFIXES(WebContentsViewAuraTest, DragDropUrlData); FRIEND_TEST_ALL_PREFIXES(WebContentsViewAuraTest, DragDropUrlData);
FRIEND_TEST_ALL_PREFIXES(WebContentsViewAuraTest, DragDropOnOopif);
class WindowObserver; class WindowObserver;
...@@ -193,6 +194,19 @@ class CONTENT_EXPORT WebContentsViewAura ...@@ -193,6 +194,19 @@ class CONTENT_EXPORT WebContentsViewAura
void OnDragExited() override; void OnDragExited() override;
int OnPerformDrop(const ui::DropTargetEvent& event) override; int OnPerformDrop(const ui::DropTargetEvent& event) override;
void DragEnteredCallback(const ui::DropTargetEvent& event,
std::unique_ptr<DropData> drop_data,
base::WeakPtr<RenderWidgetHostViewBase> target,
base::Optional<gfx::PointF> transformed_pt);
void DragUpdatedCallback(const ui::DropTargetEvent& event,
std::unique_ptr<DropData> drop_data,
base::WeakPtr<RenderWidgetHostViewBase> target,
base::Optional<gfx::PointF> transformed_pt);
void PerformDropCallback(const ui::DropTargetEvent& event,
std::unique_ptr<DropData> drop_data,
base::WeakPtr<RenderWidgetHostViewBase> target,
base::Optional<gfx::PointF> transformed_pt);
// Completes a drop operation by communicating the drop data to the renderer // Completes a drop operation by communicating the drop data to the renderer
// process. // process.
void CompleteDrop(RenderWidgetHostImpl* target_rwh, void CompleteDrop(RenderWidgetHostImpl* target_rwh,
...@@ -270,11 +284,9 @@ class CONTENT_EXPORT WebContentsViewAura ...@@ -270,11 +284,9 @@ class CONTENT_EXPORT WebContentsViewAura
bool init_rwhv_with_null_parent_for_testing_; bool init_rwhv_with_null_parent_for_testing_;
#if defined(OS_WIN) // Used to ensure the drag and drop callbacks bound to this
// Used to ensure that the virtual files retrieval callback bound to this
// object is canceled when this object is destroyed. // object is canceled when this object is destroyed.
base::WeakPtrFactory<WebContentsViewAura> weak_ptr_factory_{this}; base::WeakPtrFactory<WebContentsViewAura> weak_ptr_factory_{this};
#endif
DISALLOW_COPY_AND_ASSIGN(WebContentsViewAura); DISALLOW_COPY_AND_ASSIGN(WebContentsViewAura);
}; };
......
...@@ -41,9 +41,12 @@ ...@@ -41,9 +41,12 @@
#include "content/public/test/test_renderer_host.h" #include "content/public/test/test_renderer_host.h"
#include "content/public/test/test_utils.h" #include "content/public/test/test_utils.h"
#include "content/shell/browser/shell.h" #include "content/shell/browser/shell.h"
#include "net/dns/mock_host_resolver.h"
#include "net/test/embedded_test_server/embedded_test_server.h" #include "net/test/embedded_test_server/embedded_test_server.h"
#include "ui/aura/window.h" #include "ui/aura/window.h"
#include "ui/aura/window_tree_host.h" #include "ui/aura/window_tree_host.h"
#include "ui/base/dragdrop/drop_target_event.h"
#include "ui/base/dragdrop/os_exchange_data.h"
#include "ui/compositor/scoped_animation_duration_scale_mode.h" #include "ui/compositor/scoped_animation_duration_scale_mode.h"
#include "ui/events/base_event_utils.h" #include "ui/events/base_event_utils.h"
#include "ui/events/event_sink.h" #include "ui/events/event_sink.h"
...@@ -87,6 +90,12 @@ class WebContentsViewAuraTest : public ContentBrowserTest { ...@@ -87,6 +90,12 @@ class WebContentsViewAuraTest : public ContentBrowserTest {
shell()->web_contents()); shell()->web_contents());
} }
void SetUpOnMainThread() override {
// Setup the server to allow serving separate sites, so we can perform
// cross-process navigation.
host_resolver()->AddRule("*", "127.0.0.1");
}
void SetUpCommandLine(base::CommandLine* cmd) override { void SetUpCommandLine(base::CommandLine* cmd) override {
cmd->AppendSwitchASCII(switches::kTouchEventFeatureDetection, cmd->AppendSwitchASCII(switches::kTouchEventFeatureDetection,
switches::kTouchEventFeatureDetectionEnabled); switches::kTouchEventFeatureDetectionEnabled);
...@@ -487,6 +496,59 @@ IN_PROC_BROWSER_TEST_F(WebContentsViewAuraTest, ...@@ -487,6 +496,59 @@ IN_PROC_BROWSER_TEST_F(WebContentsViewAuraTest,
window->AddChild(shell()->web_contents()->GetContentNativeView()); window->AddChild(shell()->web_contents()->GetContentNativeView());
} }
IN_PROC_BROWSER_TEST_F(WebContentsViewAuraTest, DragDropOnOopif) {
ASSERT_TRUE(embedded_test_server()->Start());
GURL url = embedded_test_server()->GetURL(
"a.com", "/overlapping_cross_site_iframe.html");
EXPECT_TRUE(NavigateToURL(shell(), url));
WebContentsImpl* contents =
static_cast<WebContentsImpl*>(shell()->web_contents());
WebContentsViewAura* view =
static_cast<WebContentsViewAura*>(contents->GetView());
ui::OSExchangeData data;
{
gfx::PointF point = {10, 10};
ui::DropTargetEvent event(data, point, point, ui::DragDropTypes::DRAG_COPY);
// Simulate drag enter on a surface that is handled by synchronous
// hittesting.
EXPECT_EQ(nullptr, view->current_drop_data_);
view->OnDragEntered(event);
ASSERT_NE(nullptr, view->current_drop_data_);
view->OnPerformDrop(event);
EXPECT_EQ(nullptr, view->current_drop_data_);
}
{
int left =
EvalJs(contents,
"document.getElementById('target').getBoundingClientRect().left")
.ExtractInt();
int top =
EvalJs(contents,
"document.getElementById('target').getBoundingClientRect().top")
.ExtractInt();
gfx::PointF point = {left + 5, top + 5};
ui::DropTargetEvent event(data, point, point, ui::DragDropTypes::DRAG_COPY);
// Simulate drag enter on a surface that is handled by asynchronous
// hittesting.
EXPECT_EQ(nullptr, view->current_drop_data_);
view->OnDragEntered(event);
// Immediately after the function call the drop data on the target view
// should still be null as we need to wait for the blink hittest callback.
EXPECT_EQ(nullptr, view->current_drop_data_);
while (!view->current_drop_data_)
GiveItSomeTime();
view->OnPerformDrop(event);
// Immediately after the function call the drop operation is not done as we
// need to wait for the blink hittest callback.
EXPECT_NE(nullptr, view->current_drop_data_);
while (view->current_drop_data_)
GiveItSomeTime();
}
}
IN_PROC_BROWSER_TEST_F(WebContentsViewAuraTest, ContentWindowClose) { IN_PROC_BROWSER_TEST_F(WebContentsViewAuraTest, ContentWindowClose) {
ASSERT_NO_FATAL_FAILURE(StartTestWithPage("/overscroll_navigation.html")); ASSERT_NO_FATAL_FAILURE(StartTestWithPage("/overscroll_navigation.html"));
......
<html>
<title>Overlapping cross site iframe</title>
This is the main body content.
<iframe id="iframe" style="width:300px; height:300px; position:absolute; left:100px; top:100px"></iframe>
<div id="target" style="background-color: yellow; position: absolute; top: 120px; left: 120px; width: 100px; height: 100px"></div>
<script>
var url = window.location.protocol + '//b.com';
if (window.location.port)
url += ':' + window.location.port;
url += "/cross_site_iframe_factory.html?b()";
document.getElementById('iframe').src = url;
</script>
</html>
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