Commit 374e16d6 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

Change-Id: I95ac25a554a2964c3c5a0ebeee97b4d041d74a24
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1642979Reviewed-by: default avatarNavid Zolghadr <nzolghadr@chromium.org>
Commit-Queue: Navid Zolghadr <nzolghadr@chromium.org>
Cr-Commit-Position: refs/heads/master@{#666334}
parent 32cb6996
......@@ -1389,6 +1389,13 @@ RenderWidgetHostInputEventRouter::GetRenderWidgetHostAtPoint(
.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
RenderWidgetHostInputEventRouter::FindTouchscreenGestureEventTarget(
RenderWidgetHostViewBase* root_view,
......@@ -1770,6 +1777,15 @@ RenderWidgetHostInputEventRouter::GetRenderWidgetTargeterForTests() {
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
RenderWidgetHostInputEventRouter::FindTargetSynchronously(
RenderWidgetHostViewBase* root_view,
......
......@@ -135,6 +135,17 @@ class CONTENT_EXPORT RenderWidgetHostInputEventRouter
const gfx::PointF& 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:
RenderWidgetHostViewBase* FindViewFromFrameSinkId(
const viz::FrameSinkId& frame_sink_id) const override;
......@@ -312,6 +323,10 @@ class CONTENT_EXPORT RenderWidgetHostInputEventRouter
const RenderWidgetHostViewBase* view);
// RenderWidgetTargeter::Delegate:
RenderWidgetTargetResult FindTargetSynchronouslyAtLocation(
RenderWidgetHostViewBase* root_view,
const gfx::PointF& location) override;
RenderWidgetTargetResult FindTargetSynchronously(
RenderWidgetHostViewBase* root_view,
const blink::WebInputEvent& event) override;
......
......@@ -6,12 +6,12 @@
#define CONTENT_BROWSER_RENDERER_HOST_RENDER_WIDGET_TARGETER_H_
#include <queue>
#include <unordered_set>
#include "base/memory/weak_ptr.h"
#include "base/optional.h"
#include "base/time/time.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_export.h"
#include "ui/events/blink/web_input_event_traits.h"
......@@ -60,10 +60,18 @@ class TracingUmaTracker;
class RenderWidgetTargeter {
public:
using RenderWidgetHostAtPointCallback =
base::OnceCallback<void(base::WeakPtr<RenderWidgetHostViewBase>,
base::Optional<gfx::PointF>)>;
class Delegate {
public:
virtual ~Delegate() {}
virtual RenderWidgetTargetResult FindTargetSynchronouslyAtLocation(
RenderWidgetHostViewBase* root_view,
const gfx::PointF& location) = 0;
virtual RenderWidgetTargetResult FindTargetSynchronously(
RenderWidgetHostViewBase* root_view,
const blink::WebInputEvent& event) = 0;
......@@ -97,6 +105,13 @@ class RenderWidgetTargeter {
const blink::WebInputEvent& event,
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);
bool HasEventsPendingDispatch() const;
......@@ -107,9 +122,65 @@ class RenderWidgetTargeter {
}
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:
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
// to query a client, or if the queue becomes empty.
void FlushEventQueue(bool is_verifying);
......@@ -127,33 +198,17 @@ class RenderWidgetTargeter {
// correctly.
// TODO(sunxd): Remove |expected_frame_sink_id| after verifying synchronous
// hit testing correctness. See https://crbug.com/871996.
void QueryClientInternal(RenderWidgetHostViewBase* root_view,
RenderWidgetHostViewBase* target,
const blink::WebInputEvent& event,
const ui::LatencyInfo& latency,
void QueryClientInternal(RenderWidgetHostViewBase* target,
const gfx::PointF& target_location,
RenderWidgetHostViewBase* last_request_target,
const gfx::PointF& last_target_location,
const viz::FrameSinkId& expected_frame_sink_id);
void QueryClient(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);
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
TargetingRequest request);
void QueryClient(TargetingRequest request);
void QueryAndVerifyClient(TargetingRequest request);
// |target_location|, if
// set, is the location in |target|'s coordinate space.
// |target| is the current target that will be queried using its
// InputTargetClient interface.
......@@ -162,66 +217,44 @@ class RenderWidgetTargeter {
// that new target's coordinate space.
// |expected_frame_sink_id| is the expected hit test result based on
// synchronous event targeting with cc generated data.
void FoundFrameSinkId(base::WeakPtr<RenderWidgetHostViewBase> root_view,
base::WeakPtr<RenderWidgetHostViewBase> target,
ui::WebScopedInputEvent event,
const ui::LatencyInfo& latency,
void FoundFrameSinkId(base::WeakPtr<RenderWidgetHostViewBase> target,
uint32_t request_id,
const gfx::PointF& target_location,
TracingUmaTracker tracker,
const viz::FrameSinkId& expected_frame_sink_id,
const bool is_verification_request,
const viz::FrameSinkId& frame_sink_id,
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
// false, we explicitly did hit-testing for this event, instead of using a
// known target.
void FoundTarget(RenderWidgetHostViewBase* root_view,
RenderWidgetHostViewBase* target,
const blink::WebInputEvent& event,
const ui::LatencyInfo& latency,
void FoundTarget(RenderWidgetHostViewBase* target,
const base::Optional<gfx::PointF>& target_location,
bool latched_target,
const viz::FrameSinkId& expected_frame_sink_id);
TargetingRequest* request);
// Callback when the hit testing timer fires, to resume event processing
// without further waiting for a response to the last targeting request.
void AsyncHitTestTimedOut(
base::WeakPtr<RenderWidgetHostViewBase> current_request_root_view,
base::WeakPtr<RenderWidgetHostViewBase> current_request_target,
const gfx::PointF& current_target_location,
base::WeakPtr<RenderWidgetHostViewBase> last_request_target,
const gfx::PointF& last_target_location,
ui::WebScopedInputEvent event,
const ui::LatencyInfo& latency,
const viz::FrameSinkId& expected_frame_sink_id);
const bool is_verification_request);
base::TimeDelta async_hit_test_timeout_delay() {
return async_hit_test_timeout_delay_;
}
struct TargetingRequest {
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;
base::Optional<TargetingRequest> request_in_flight_;
uint32_t last_request_id_ = 0;
std::queue<TargetingRequest> requests_;
// With viz-hit-testing-surface-layer being enabled, we do async hit testing
// for already dispatched events for verification. These verification 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;
std::queue<TargetingRequest> verify_requests_;
......
......@@ -1232,25 +1232,22 @@ void WebContentsViewAura::OnMouseEvent(ui::MouseEvent* event) {
////////////////////////////////////////////////////////////////////////////////
// WebContentsViewAura, aura::client::DragDropDelegate implementation:
void WebContentsViewAura::OnDragEntered(const ui::DropTargetEvent& event) {
#if defined(OS_WIN)
async_drop_navigation_observer_.reset();
#endif
gfx::PointF transformed_pt;
void WebContentsViewAura::DragEnteredCallback(
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 =
web_contents_->GetInputEventRouter()->GetRenderWidgetHostAtPoint(
web_contents_->GetRenderViewHost()->GetWidget()->GetView(),
event.location_f(), &transformed_pt);
RenderWidgetHostImpl::From(target->GetRenderWidgetHost());
if (!IsValidDragTarget(target_rwh))
return;
current_rwh_for_drag_ = target_rwh->GetWeakPtr();
current_rvh_for_drag_ =
GetRenderViewHostID(web_contents_->GetRenderViewHost());
current_drop_data_.reset(new DropData());
PrepareDropData(current_drop_data_.get(), event.data());
current_drop_data_.reset(drop_data.release());
current_rwh_for_drag_->FilterDropData(current_drop_data_.get());
blink::WebDragOperationsMask op = ConvertToWeb(event.source_operations());
......@@ -1266,26 +1263,50 @@ void WebContentsViewAura::OnDragEntered(const ui::DropTargetEvent& event) {
if (drag_dest_delegate_)
drag_dest_delegate_->DragInitialize(web_contents_);
DCHECK(transformed_pt.has_value());
gfx::PointF screen_pt(display::Screen::GetScreen()->GetCursorScreenPoint());
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()));
if (drag_dest_delegate_) {
drag_dest_delegate_->OnReceiveDragData(event.data());
drag_dest_delegate_->OnDragEnter();
}
}
int WebContentsViewAura::OnDragUpdated(const ui::DropTargetEvent& event) {
gfx::PointF transformed_pt;
RenderWidgetHostImpl* target_rwh =
web_contents_->GetInputEventRouter()->GetRenderWidgetHostAtPoint(
void WebContentsViewAura::OnDragEntered(const ui::DropTargetEvent& event) {
#if defined(OS_WIN)
async_drop_navigation_observer_.reset();
#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(),
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))
return ui::DragDropTypes::DRAG_NONE;
return;
aura::Window* root_window = GetNativeView()->GetRootWindow();
aura::client::ScreenPositionClient* screen_position_client =
......@@ -1307,20 +1328,35 @@ int WebContentsViewAura::OnDragUpdated(const ui::DropTargetEvent& event) {
current_rwh_for_drag_->DragTargetDragLeave(transformed_leave_point,
screen_pt);
}
OnDragEntered(event);
DragEnteredCallback(event, std::move(drop_data), target, transformed_pt);
}
if (!current_drop_data_)
return ui::DragDropTypes::DRAG_NONE;
if (!current_drop_data_) {
return;
}
DCHECK(transformed_pt.has_value());
blink::WebDragOperationsMask op = ConvertToWeb(event.source_operations());
target_rwh->DragTargetDragOver(
transformed_pt, screen_pt, op,
transformed_pt.value(), screen_pt, op,
ui::EventFlagsToWebEventModifiers(event.flags()));
if (drag_dest_delegate_)
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_);
}
......@@ -1342,25 +1378,31 @@ void WebContentsViewAura::OnDragExited() {
current_drop_data_.reset();
}
int WebContentsViewAura::OnPerformDrop(const ui::DropTargetEvent& event) {
gfx::PointF transformed_pt;
void WebContentsViewAura::PerformDropCallback(
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 =
web_contents_->GetInputEventRouter()->GetRenderWidgetHostAtPoint(
web_contents_->GetRenderViewHost()->GetWidget()->GetView(),
event.location_f(), &transformed_pt);
RenderWidgetHostImpl::From(target->GetRenderWidgetHost());
if (!IsValidDragTarget(target_rwh))
return ui::DragDropTypes::DRAG_NONE;
return;
DCHECK(transformed_pt.has_value());
gfx::PointF screen_pt(display::Screen::GetScreen()->GetCursorScreenPoint());
if (target_rwh != current_rwh_for_drag_.get()) {
if (current_rwh_for_drag_)
current_rwh_for_drag_->DragTargetDragLeave(transformed_pt, screen_pt);
OnDragEntered(event);
current_rwh_for_drag_->DragTargetDragLeave(transformed_pt.value(),
screen_pt);
DragEnteredCallback(event, std::move(drop_data), target, transformed_pt);
}
if (!current_drop_data_)
return ui::DragDropTypes::DRAG_NONE;
if (!current_drop_data_) {
return;
}
const int key_modifiers = ui::EventFlagsToWebEventModifiers(event.flags());
#if defined(OS_WIN)
......@@ -1386,16 +1428,29 @@ int WebContentsViewAura::OnPerformDrop(const ui::DropTargetEvent& event) {
async_drop_navigation_observer_ =
std::make_unique<AsyncDropNavigationObserver>(
web_contents_, std::move(current_drop_data_), target_rwh,
transformed_pt, screen_pt, key_modifiers);
return ConvertFromWeb(current_drag_op_);
transformed_pt.value(), screen_pt, key_modifiers);
return;
}
}
#endif
CompleteDrop(target_rwh, *current_drop_data_, transformed_pt, screen_pt,
key_modifiers);
CompleteDrop(target_rwh, *current_drop_data_, transformed_pt.value(),
screen_pt, key_modifiers);
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_);
}
......
......@@ -73,6 +73,7 @@ class CONTENT_EXPORT WebContentsViewAura
FRIEND_TEST_ALL_PREFIXES(WebContentsViewAuraTest,
DragDropVirtualFilesOriginateFromRenderer);
FRIEND_TEST_ALL_PREFIXES(WebContentsViewAuraTest, DragDropUrlData);
FRIEND_TEST_ALL_PREFIXES(WebContentsViewAuraTest, DragDropOnOopif);
class WindowObserver;
......@@ -193,6 +194,19 @@ class CONTENT_EXPORT WebContentsViewAura
void OnDragExited() 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
// process.
void CompleteDrop(RenderWidgetHostImpl* target_rwh,
......@@ -270,11 +284,9 @@ class CONTENT_EXPORT WebContentsViewAura
bool init_rwhv_with_null_parent_for_testing_;
#if defined(OS_WIN)
// Used to ensure that the virtual files retrieval callback bound to this
// Used to ensure the drag and drop callbacks bound to this
// object is canceled when this object is destroyed.
base::WeakPtrFactory<WebContentsViewAura> weak_ptr_factory_{this};
#endif
DISALLOW_COPY_AND_ASSIGN(WebContentsViewAura);
};
......
......@@ -41,9 +41,12 @@
#include "content/public/test/test_renderer_host.h"
#include "content/public/test/test_utils.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 "ui/aura/window.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/events/base_event_utils.h"
#include "ui/events/event_sink.h"
......@@ -87,11 +90,28 @@ class WebContentsViewAuraTest : public ContentBrowserTest {
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 {
cmd->AppendSwitchASCII(switches::kTouchEventFeatureDetection,
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) {
ASSERT_NO_FATAL_FAILURE(StartTestWithPage("/overscroll_navigation.html"));
WebContentsImpl* web_contents =
......@@ -231,6 +251,11 @@ class WebContentsViewAuraTest : public ContentBrowserTest {
ContentBrowserTest::PostRunTestOnMainThread();
}
RenderWidgetHostImpl* drop_target_widget_;
// A closure indicating that async drop operation has completed.
base::OnceClosure async_drop_closure_;
private:
std::unique_ptr<RenderFrameSubmissionObserver> frame_observer_;
......@@ -487,6 +512,68 @@ IN_PROC_BROWSER_TEST_F(WebContentsViewAuraTest,
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()));
}
}
IN_PROC_BROWSER_TEST_F(WebContentsViewAuraTest, ContentWindowClose) {
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