Commit 400c3bba 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.

The original CL
https://chromium-review.googlesource.com/c/chromium/src/+/1596840
was reverted due the added test being flaky. This CL is the same
as the original CL expect it has the same test with another
way of checking the logic.

TBR=sadrul@chromium.org

Bug: 804633
Change-Id: I46f15a2b694c3ad9d3574473c2a46ba13dcbfb79
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1641383Reviewed-by: default avatarNavid Zolghadr <nzolghadr@chromium.org>
Commit-Queue: Navid Zolghadr <nzolghadr@chromium.org>
Cr-Commit-Position: refs/heads/master@{#665601}
parent 7a1491ed
...@@ -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;
......
...@@ -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,11 +90,28 @@ class WebContentsViewAuraTest : public ContentBrowserTest { ...@@ -87,11 +90,28 @@ 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);
} }
void OnDropComplete(RenderWidgetHostImpl* target_rwh,
const DropData& drop_data,
const gfx::PointF& client_pt,
const gfx::PointF& screen_pt,
int key_modifiers,
bool drop_allowed) {
// Cache the data for verification.
drop_target_widget_ = target_rwh;
std::move(async_drop_closure_).Run();
}
void TestOverscrollNavigation(bool touch_handler) { void TestOverscrollNavigation(bool touch_handler) {
ASSERT_NO_FATAL_FAILURE(StartTestWithPage("/overscroll_navigation.html")); ASSERT_NO_FATAL_FAILURE(StartTestWithPage("/overscroll_navigation.html"));
WebContentsImpl* web_contents = WebContentsImpl* web_contents =
...@@ -231,6 +251,11 @@ class WebContentsViewAuraTest : public ContentBrowserTest { ...@@ -231,6 +251,11 @@ class WebContentsViewAuraTest : public ContentBrowserTest {
ContentBrowserTest::PostRunTestOnMainThread(); ContentBrowserTest::PostRunTestOnMainThread();
} }
RenderWidgetHostImpl* drop_target_widget_;
// A closure indicating that async drop operation has completed.
base::OnceClosure async_drop_closure_;
private: private:
std::unique_ptr<RenderFrameSubmissionObserver> frame_observer_; std::unique_ptr<RenderFrameSubmissionObserver> frame_observer_;
...@@ -487,6 +512,97 @@ IN_PROC_BROWSER_TEST_F(WebContentsViewAuraTest, ...@@ -487,6 +512,97 @@ 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;
// Drop on the root frame.
{
view->RegisterDropCallbackForTesting(base::BindOnce(
&WebContentsViewAuraTest::OnDropComplete, base::Unretained(this)));
base::RunLoop run_loop;
async_drop_closure_ = run_loop.QuitClosure();
gfx::PointF point = {10, 10};
ui::DropTargetEvent event(data, point, point, ui::DragDropTypes::DRAG_COPY);
view->OnDragEntered(event);
view->OnPerformDrop(event);
run_loop.Run();
EXPECT_EQ(drop_target_widget_,
RenderWidgetHostImpl::From(contents->GetFrameTree()
->root()
->current_frame_host()
->GetRenderWidgetHost()));
}
// Drop on the element in the root frame overlapping the embeded OOPIF.
{
view->RegisterDropCallbackForTesting(base::BindOnce(
&WebContentsViewAuraTest::OnDropComplete, base::Unretained(this)));
base::RunLoop run_loop;
async_drop_closure_ = run_loop.QuitClosure();
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);
view->OnDragEntered(event);
view->OnPerformDrop(event);
run_loop.Run();
EXPECT_EQ(drop_target_widget_,
RenderWidgetHostImpl::From(contents->GetFrameTree()
->root()
->current_frame_host()
->GetRenderWidgetHost()));
}
// Drop on the embedded OOPIF.
{
view->RegisterDropCallbackForTesting(base::BindOnce(
&WebContentsViewAuraTest::OnDropComplete, base::Unretained(this)));
base::RunLoop run_loop;
async_drop_closure_ = run_loop.QuitClosure();
int left =
EvalJs(contents,
"document.getElementById('iframe').getBoundingClientRect().left")
.ExtractInt();
int top =
EvalJs(contents,
"document.getElementById('iframe').getBoundingClientRect().top")
.ExtractInt();
gfx::PointF point = {left + 5, top + 5};
ui::DropTargetEvent event(data, point, point, ui::DragDropTypes::DRAG_COPY);
view->OnDragEntered(event);
view->OnPerformDrop(event);
run_loop.Run();
EXPECT_EQ(drop_target_widget_,
RenderWidgetHostImpl::From(contents->GetFrameTree()
->root()
->child_at(0)
->current_frame_host()
->GetRenderWidgetHost()));
}
}
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