
Main changes: - Replace IS_CHROMEOS_ASH with the equivalent IS_CHROMEOS - Remove obsolete build flag includes/dependencies Bug: b:354842935 AX-Relnotes: n/a. Change-Id: I079b003a4664a7a3f7281905323611b6fc4fe3da Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6090635 Reviewed-by: Rakina Zata Amni <rakina@chromium.org> Reviewed-by: Tom Sepez <tsepez@chromium.org> Commit-Queue: Georg Neis <neis@chromium.org> Cr-Commit-Position: refs/heads/main@{#1397108}
934 lines
38 KiB
C++
934 lines
38 KiB
C++
// Copyright 2017 The Chromium Authors
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
#include "content/browser/pointer_lock_browsertest.h"
|
|
|
|
#include <string>
|
|
|
|
#include "base/memory/raw_ptr.h"
|
|
#include "base/test/scoped_feature_list.h"
|
|
#include "build/build_config.h"
|
|
#include "components/input/render_widget_host_input_event_router.h"
|
|
#include "content/browser/renderer_host/frame_tree.h"
|
|
#include "content/browser/renderer_host/render_widget_host_impl.h"
|
|
#include "content/browser/web_contents/web_contents_impl.h"
|
|
#include "content/common/features.h"
|
|
#include "content/public/browser/web_contents_delegate.h"
|
|
#include "content/public/test/browser_test.h"
|
|
#include "content/public/test/browser_test_utils.h"
|
|
#include "content/public/test/content_browser_test.h"
|
|
#include "content/public/test/content_browser_test_utils.h"
|
|
#include "content/public/test/hit_test_region_observer.h"
|
|
#include "content/public/test/test_utils.h"
|
|
#include "content/shell/browser/shell.h"
|
|
#include "content/test/content_browser_test_utils_internal.h"
|
|
#include "net/dns/mock_host_resolver.h"
|
|
#include "net/test/embedded_test_server/embedded_test_server.h"
|
|
#include "ui/base/ui_base_features.h"
|
|
|
|
#ifdef USE_AURA
|
|
#include "content/browser/renderer_host/render_widget_host_view_aura.h"
|
|
#include "content/browser/web_contents/web_contents_view_aura.h"
|
|
#endif // USE_AURA
|
|
|
|
namespace content {
|
|
|
|
class MockPointerLockWebContentsDelegate : public WebContentsDelegate {
|
|
public:
|
|
MockPointerLockWebContentsDelegate() {}
|
|
~MockPointerLockWebContentsDelegate() override {}
|
|
|
|
void RequestPointerLock(WebContents* web_contents,
|
|
bool user_gesture,
|
|
bool last_unlocked_by_target) override {
|
|
if (user_gesture)
|
|
web_contents->GotResponseToPointerLockRequest(
|
|
blink::mojom::PointerLockResult::kSuccess);
|
|
else
|
|
web_contents->GotResponseToPointerLockRequest(
|
|
blink::mojom::PointerLockResult::kRequiresUserGesture);
|
|
}
|
|
|
|
void LostPointerLock() override {}
|
|
};
|
|
|
|
#ifdef USE_AURA
|
|
class ScopedEnableUnadjustedMouseEventsForTesting
|
|
: public aura::ScopedEnableUnadjustedMouseEvents {
|
|
public:
|
|
explicit ScopedEnableUnadjustedMouseEventsForTesting() {}
|
|
~ScopedEnableUnadjustedMouseEventsForTesting() override {}
|
|
};
|
|
|
|
class MockPointerLockRenderWidgetHostView : public RenderWidgetHostViewAura {
|
|
public:
|
|
MockPointerLockRenderWidgetHostView(RenderWidgetHost* host)
|
|
: RenderWidgetHostViewAura(host),
|
|
host_(RenderWidgetHostImpl::From(host)) {}
|
|
~MockPointerLockRenderWidgetHostView() override {
|
|
if (IsPointerLocked()) {
|
|
UnlockPointer();
|
|
}
|
|
}
|
|
|
|
blink::mojom::PointerLockResult LockPointer(
|
|
bool request_unadjusted_movement) override {
|
|
event_handler()->mouse_locked_ = true;
|
|
event_handler()->mouse_locked_unadjusted_movement_ =
|
|
request_unadjusted_movement
|
|
? std::make_unique<ScopedEnableUnadjustedMouseEventsForTesting>()
|
|
: nullptr;
|
|
return blink::mojom::PointerLockResult::kSuccess;
|
|
}
|
|
|
|
void UnlockPointer() override {
|
|
host_->LostPointerLock();
|
|
event_handler()->mouse_locked_ = false;
|
|
event_handler()->mouse_locked_unadjusted_movement_.reset();
|
|
}
|
|
|
|
bool GetIsPointerLockedUnadjustedMovementForTesting() override {
|
|
return IsPointerLocked() &&
|
|
event_handler()->mouse_locked_unadjusted_movement_;
|
|
}
|
|
|
|
void OnWindowFocused(aura::Window* gained_focus,
|
|
aura::Window* lost_focus) override {
|
|
// Ignore window focus events.
|
|
}
|
|
|
|
bool IsPointerLocked() override { return event_handler()->mouse_locked(); }
|
|
|
|
bool HasFocus() override { return has_focus_; }
|
|
|
|
raw_ptr<RenderWidgetHostImpl> host_;
|
|
bool has_focus_ = true;
|
|
};
|
|
|
|
void InstallCreateHooksForPointerLockBrowserTests() {
|
|
WebContentsViewAura::InstallCreateHookForTests(
|
|
[](RenderWidgetHost* host) -> RenderWidgetHostViewAura* {
|
|
return new MockPointerLockRenderWidgetHostView(host);
|
|
});
|
|
}
|
|
#endif // USE_AURA
|
|
|
|
class PointerLockBrowserTest : public ContentBrowserTest {
|
|
public:
|
|
PointerLockBrowserTest() {}
|
|
|
|
protected:
|
|
void SetUpCommandLine(base::CommandLine* command_line) override {
|
|
IsolateAllSitesForTesting(command_line);
|
|
}
|
|
|
|
void SetUp() override {
|
|
InstallCreateHooksForPointerLockBrowserTests();
|
|
ContentBrowserTest::SetUp();
|
|
}
|
|
|
|
void SetUpOnMainThread() override {
|
|
host_resolver()->AddRule("*", "127.0.0.1");
|
|
SetupCrossSiteRedirector(embedded_test_server());
|
|
ASSERT_TRUE(embedded_test_server()->Start());
|
|
|
|
web_contents()->SetDelegate(&web_contents_delegate_);
|
|
}
|
|
|
|
WebContentsImpl* web_contents() const {
|
|
return static_cast<WebContentsImpl*>(shell()->web_contents());
|
|
}
|
|
|
|
protected:
|
|
MockPointerLockWebContentsDelegate web_contents_delegate_;
|
|
};
|
|
|
|
namespace {
|
|
class PointerLockHelper {
|
|
public:
|
|
// requestPointerLock is an asynchronous operation. This method returns when
|
|
// document.body.requestPointerLock() either succeeds or fails.
|
|
// Returns true if Pointer Lock on body was successful.
|
|
static EvalJsResult RequestPointerLockOnBody(
|
|
const ToRenderFrameHost& execution_target,
|
|
const int options = EXECUTE_SCRIPT_DEFAULT_OPTIONS) {
|
|
return EvalJs(execution_target,
|
|
set_pointer_lock_promise_ +
|
|
"document.body.requestPointerLock();" +
|
|
wait_for_pointer_lock_promise_,
|
|
options);
|
|
}
|
|
static EvalJsResult RequestPointerLockWithUnadjustedMovementOnBody(
|
|
const ToRenderFrameHost& execution_target,
|
|
const int options = EXECUTE_SCRIPT_DEFAULT_OPTIONS) {
|
|
return EvalJs(
|
|
execution_target,
|
|
set_pointer_lock_promise_ +
|
|
"document.body.requestPointerLock({unadjustedMovement:true});" +
|
|
wait_for_pointer_lock_promise_,
|
|
options);
|
|
}
|
|
// exitPointerLock is an asynchronous operation. This method returns when
|
|
// document.exitPointerLock() either succeeds or fails.
|
|
// Returns true if Exit Pointer Lock was successful
|
|
static EvalJsResult ExitPointerLock(
|
|
const ToRenderFrameHost& execution_target,
|
|
const int options = EXECUTE_SCRIPT_DEFAULT_OPTIONS) {
|
|
return EvalJs(execution_target,
|
|
set_pointer_lock_promise_ + "document.exitPointerLock();" +
|
|
wait_for_pointer_lock_promise_,
|
|
options);
|
|
}
|
|
static EvalJsResult IsPointerLockOnBody(
|
|
const ToRenderFrameHost& execution_target,
|
|
const int options = EXECUTE_SCRIPT_DEFAULT_OPTIONS) {
|
|
return EvalJs(execution_target,
|
|
"document.pointerLockElement === document.body", options);
|
|
}
|
|
|
|
private:
|
|
static const std::string set_pointer_lock_promise_;
|
|
static const std::string wait_for_pointer_lock_promise_;
|
|
};
|
|
|
|
// static
|
|
const std::string PointerLockHelper::set_pointer_lock_promise_ =
|
|
R"code(pointerLockPromise=new Promise(function (resolve, reject){
|
|
document.addEventListener('pointerlockchange', resolve);
|
|
document.addEventListener('pointerlockerror', reject);
|
|
});)code";
|
|
// static
|
|
const std::string PointerLockHelper::wait_for_pointer_lock_promise_ =
|
|
"(async()=> {return await pointerLockPromise.then(()=>true, "
|
|
"()=>false);})()";
|
|
} // namespace
|
|
|
|
IN_PROC_BROWSER_TEST_F(PointerLockBrowserTest, PointerLockBasic) {
|
|
GURL main_url(embedded_test_server()->GetURL(
|
|
"a.com", "/cross_site_iframe_factory.html?a(b)"));
|
|
EXPECT_TRUE(NavigateToURL(shell(), main_url));
|
|
|
|
FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root();
|
|
FrameTreeNode* child = root->child_at(0);
|
|
|
|
// Request a pointer lock on the root frame's body.
|
|
EXPECT_EQ(true, PointerLockHelper::RequestPointerLockOnBody(root));
|
|
EXPECT_EQ(true, PointerLockHelper::IsPointerLockOnBody(root));
|
|
|
|
// Request a pointer lock on the child frame's body.
|
|
EXPECT_EQ(false, PointerLockHelper::RequestPointerLockOnBody(child));
|
|
// Child frame should not be granted pointer lock since the root frame has it.
|
|
EXPECT_EQ(false, PointerLockHelper::IsPointerLockOnBody(child));
|
|
|
|
// Release pointer lock on root frame.
|
|
EXPECT_EQ(true, PointerLockHelper::ExitPointerLock(root));
|
|
|
|
// Request a pointer lock on the child frame's body.
|
|
EXPECT_EQ(true, PointerLockHelper::RequestPointerLockOnBody(child));
|
|
// ensure request finishes before moving on.
|
|
|
|
// Child frame should have been granted pointer lock.
|
|
EXPECT_EQ(true, PointerLockHelper::IsPointerLockOnBody(child));
|
|
}
|
|
|
|
IN_PROC_BROWSER_TEST_F(PointerLockBrowserTest, PointerLockAndUserActivation) {
|
|
GURL main_url(embedded_test_server()->GetURL(
|
|
"a.com", "/cross_site_iframe_factory.html?a(b(b))"));
|
|
EXPECT_TRUE(NavigateToURL(shell(), main_url));
|
|
|
|
FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root();
|
|
FrameTreeNode* child = root->child_at(0);
|
|
FrameTreeNode* grand_child = child->child_at(0);
|
|
|
|
// Without user activation, pointer lock request from any (child or
|
|
// grand_child) frame fails.
|
|
EXPECT_EQ(false, PointerLockHelper::RequestPointerLockOnBody(
|
|
child, EXECUTE_SCRIPT_NO_USER_GESTURE));
|
|
EXPECT_EQ(false, PointerLockHelper::IsPointerLockOnBody(
|
|
child, EXECUTE_SCRIPT_NO_USER_GESTURE));
|
|
|
|
EXPECT_EQ(false, PointerLockHelper::RequestPointerLockOnBody(
|
|
grand_child, EXECUTE_SCRIPT_NO_USER_GESTURE));
|
|
EXPECT_EQ(false, PointerLockHelper::IsPointerLockOnBody(
|
|
grand_child, EXECUTE_SCRIPT_NO_USER_GESTURE));
|
|
|
|
// Execute a empty (dummy) JS to activate the child frame.
|
|
EXPECT_TRUE(ExecJs(child, ""));
|
|
|
|
// With user activation in the child frame, pointer lock from the same frame
|
|
// succeeds.
|
|
EXPECT_EQ(true, PointerLockHelper::RequestPointerLockOnBody(
|
|
child, EXECUTE_SCRIPT_NO_USER_GESTURE));
|
|
EXPECT_EQ(true, PointerLockHelper::IsPointerLockOnBody(
|
|
child, EXECUTE_SCRIPT_NO_USER_GESTURE));
|
|
|
|
// But with user activation in the child frame, pointer lock from the
|
|
// grand_child frame fails.
|
|
EXPECT_EQ(false, PointerLockHelper::RequestPointerLockOnBody(
|
|
grand_child, EXECUTE_SCRIPT_NO_USER_GESTURE));
|
|
EXPECT_EQ(false, PointerLockHelper::IsPointerLockOnBody(
|
|
grand_child, EXECUTE_SCRIPT_NO_USER_GESTURE));
|
|
}
|
|
|
|
// crbug.com/1210940: flaky on Linux
|
|
#if BUILDFLAG(IS_LINUX)
|
|
#define MAYBE_PointerLockEventRouting DISABLED_PointerLockEventRouting
|
|
#else
|
|
#define MAYBE_PointerLockEventRouting PointerLockEventRouting
|
|
#endif
|
|
IN_PROC_BROWSER_TEST_F(PointerLockBrowserTest, MAYBE_PointerLockEventRouting) {
|
|
GURL main_url(embedded_test_server()->GetURL(
|
|
"a.com", "/cross_site_iframe_factory.html?a(b)"));
|
|
EXPECT_TRUE(NavigateToURL(shell(), main_url));
|
|
|
|
FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root();
|
|
FrameTreeNode* child = root->child_at(0);
|
|
input::RenderWidgetHostInputEventRouter* router =
|
|
web_contents()->GetInputEventRouter();
|
|
RenderWidgetHostViewBase* root_view = static_cast<RenderWidgetHostViewBase*>(
|
|
root->current_frame_host()->GetView());
|
|
RenderWidgetHostViewBase* child_view = static_cast<RenderWidgetHostViewBase*>(
|
|
child->current_frame_host()->GetView());
|
|
|
|
WaitForHitTestData(child->current_frame_host());
|
|
|
|
std::string set_mouse_move_event_listener = R"(
|
|
mouseMoveExecuted = new Promise(function (resolve, reject) {
|
|
mousemoveHandler = function(e) {
|
|
x = e.x;
|
|
y = e.y;
|
|
mX = e.movementX;
|
|
mY = e.movementY;
|
|
resolve();
|
|
};
|
|
document.addEventListener('mousemove', mousemoveHandler, {once: true});
|
|
});
|
|
true; // A promise is defined above, but do not wait.
|
|
)";
|
|
std::string define_variables = R"(
|
|
var x;
|
|
var y;
|
|
var mX;
|
|
var mY;
|
|
var mouseMoveExecuted;
|
|
var mousemoveHandler;
|
|
)";
|
|
// Add a mouse move event listener to the root frame.
|
|
EXPECT_TRUE(ExecJs(root, define_variables));
|
|
EXPECT_TRUE(ExecJs(root, set_mouse_move_event_listener));
|
|
|
|
// Send a mouse move to root frame before lock to set last mouse position.
|
|
blink::WebMouseEvent mouse_event(
|
|
blink::WebInputEvent::Type::kMouseMove,
|
|
blink::WebInputEvent::kNoModifiers,
|
|
blink::WebInputEvent::GetStaticTimeStampForTests());
|
|
mouse_event.pointer_type = blink::WebPointerProperties::PointerType::kMouse;
|
|
mouse_event.SetPositionInWidget(6, 7);
|
|
mouse_event.SetPositionInScreen(6, 7);
|
|
mouse_event.movement_x = 8;
|
|
mouse_event.movement_y = 9;
|
|
router->RouteMouseEvent(root_view, &mouse_event, ui::LatencyInfo());
|
|
|
|
// wait for mouse move to fire mouse move event
|
|
EXPECT_EQ(true, EvalJs(root,
|
|
"(async ()=> {return await "
|
|
"mouseMoveExecuted.then(()=>true);})();"));
|
|
EXPECT_EQ("[6,7,0,0]", EvalJs(root, "JSON.stringify([x,y,mX,mY])"));
|
|
EXPECT_EQ(true, PointerLockHelper::RequestPointerLockOnBody(root));
|
|
// Root frame should have been granted pointer lock.
|
|
EXPECT_EQ(true, PointerLockHelper::IsPointerLockOnBody(root));
|
|
EXPECT_TRUE(ExecJs(root, set_mouse_move_event_listener));
|
|
|
|
mouse_event.SetPositionInWidget(10, 12);
|
|
mouse_event.SetPositionInScreen(10, 12);
|
|
mouse_event.movement_x = 12;
|
|
mouse_event.movement_y = 13;
|
|
router->RouteMouseEvent(root_view, &mouse_event, ui::LatencyInfo());
|
|
|
|
EXPECT_EQ(true, EvalJs(root,
|
|
"(async ()=> {return await "
|
|
"mouseMoveExecuted.then(()=>true);})();"));
|
|
// Locked event has same coordinates as before locked.
|
|
EXPECT_EQ("[6,7,4,5]", EvalJs(root, "JSON.stringify([x,y,mX,mY])"));
|
|
|
|
EXPECT_EQ(true, PointerLockHelper::ExitPointerLock(root));
|
|
|
|
EXPECT_EQ(true, PointerLockHelper::RequestPointerLockOnBody(child));
|
|
|
|
// define all all global variables on the child
|
|
EXPECT_TRUE(ExecJs(child, define_variables));
|
|
// Child frame should have been granted pointer lock.
|
|
EXPECT_EQ(true, PointerLockHelper::IsPointerLockOnBody(child));
|
|
|
|
// Add a mouse move event listener to the child frame.
|
|
EXPECT_TRUE(ExecJs(child, set_mouse_move_event_listener));
|
|
|
|
gfx::PointF transformed_point;
|
|
root_view->TransformPointToCoordSpaceForView(gfx::PointF(0, 0), child_view,
|
|
&transformed_point);
|
|
mouse_event.SetPositionInWidget(-transformed_point.x() + 14,
|
|
-transformed_point.y() + 15);
|
|
mouse_event.SetPositionInScreen(-transformed_point.x() + 14,
|
|
-transformed_point.y() + 15);
|
|
mouse_event.movement_x = 16;
|
|
mouse_event.movement_y = 17;
|
|
// We use root_view intentionally as the RenderWidgetHostInputEventRouter is
|
|
// responsible for correctly routing the event to the child frame.
|
|
router->RouteMouseEvent(root_view, &mouse_event, ui::LatencyInfo());
|
|
|
|
EXPECT_EQ(true, EvalJs(child,
|
|
"(async ()=> {return await "
|
|
"mouseMoveExecuted.then(()=>true);})()"));
|
|
// This is the first event to child render, so the coordinates is (0, 0)
|
|
EXPECT_EQ("[0,0,0,0]", EvalJs(child, "JSON.stringify([x,y,mX,mY])"));
|
|
}
|
|
|
|
// Tests that the browser will not unlock the pointer if a RenderWidgetHostView
|
|
// that doesn't hold the pointer lock is destroyed
|
|
IN_PROC_BROWSER_TEST_F(PointerLockBrowserTest, PointerLockChildFrameDetached) {
|
|
GURL main_url(embedded_test_server()->GetURL(
|
|
"a.com", "/cross_site_iframe_factory.html?a(b)"));
|
|
EXPECT_TRUE(NavigateToURL(shell(), main_url));
|
|
|
|
FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root();
|
|
|
|
// Request a pointer lock on the root frame's body.
|
|
EXPECT_EQ(true, PointerLockHelper::RequestPointerLockOnBody(root));
|
|
// Root frame should have been granted pointer lock.
|
|
EXPECT_EQ(true, PointerLockHelper::IsPointerLockOnBody(root));
|
|
|
|
// Root (platform) RenderWidgetHostView should have the pointer locked.
|
|
EXPECT_TRUE(root->current_frame_host()->GetView()->IsPointerLocked());
|
|
EXPECT_EQ(root->current_frame_host()->GetRenderWidgetHost(),
|
|
web_contents()->GetPointerLockWidget());
|
|
|
|
// Detach the child frame.
|
|
EXPECT_TRUE(ExecJs(root, "document.querySelector('iframe').remove()"));
|
|
|
|
// Root (platform) RenderWidgetHostView should still have the pointer locked.
|
|
EXPECT_TRUE(root->current_frame_host()->GetView()->IsPointerLocked());
|
|
EXPECT_EQ(root->current_frame_host()->GetRenderWidgetHost(),
|
|
web_contents()->GetPointerLockWidget());
|
|
}
|
|
|
|
// Tests that the browser will unlock the pointer if a RenderWidgetHostView that
|
|
// holds the pointer lock crashes.
|
|
IN_PROC_BROWSER_TEST_F(PointerLockBrowserTest,
|
|
PointerLockInnerContentsCrashes) {
|
|
GURL main_url(embedded_test_server()->GetURL(
|
|
"a.com", "/cross_site_iframe_factory.html?a(b(b))"));
|
|
EXPECT_TRUE(NavigateToURL(shell(), main_url));
|
|
|
|
FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root();
|
|
|
|
// Attach an inner WebContents; it's owned by the FrameTree, so we obtain an
|
|
// observer to it.
|
|
WebContents* inner_contents = CreateAndAttachInnerContents(
|
|
root->child_at(0)->child_at(0)->current_frame_host());
|
|
WebContentsDestroyedWatcher inner_death_observer(inner_contents);
|
|
|
|
// Override the delegate so that we can stub out pointer lock events.
|
|
inner_contents->SetDelegate(&web_contents_delegate_);
|
|
|
|
// Navigate the inner webcontents to a page.
|
|
EXPECT_TRUE(NavigateToURLFromRenderer(
|
|
inner_contents, embedded_test_server()->GetURL(
|
|
"c.com", "/cross_site_iframe_factory.html?c(d)")));
|
|
|
|
// Request a pointer lock to the inner WebContents's document.body.
|
|
EXPECT_EQ(true, PointerLockHelper::RequestPointerLockOnBody(
|
|
inner_contents->GetPrimaryMainFrame()));
|
|
EXPECT_EQ(true, PointerLockHelper::IsPointerLockOnBody(
|
|
inner_contents->GetPrimaryMainFrame()));
|
|
|
|
// Root (platform) RenderWidgetHostView should have the pointer locked.
|
|
EXPECT_TRUE(root->current_frame_host()->GetView()->IsPointerLocked());
|
|
|
|
// The widget doing the lock is the one from the inner WebContents. A link
|
|
// to that RWH is saved into the outer webcontents.
|
|
RenderWidgetHost* expected_lock_widget =
|
|
inner_contents->GetPrimaryMainFrame()->GetView()->GetRenderWidgetHost();
|
|
EXPECT_EQ(expected_lock_widget, web_contents()->GetPointerLockWidget());
|
|
EXPECT_EQ(expected_lock_widget, web_contents()->pointer_lock_widget_);
|
|
EXPECT_EQ(
|
|
expected_lock_widget,
|
|
static_cast<WebContentsImpl*>(inner_contents)->pointer_lock_widget_);
|
|
|
|
// Crash the subframe process.
|
|
RenderProcessHost* crash_process =
|
|
root->child_at(0)->current_frame_host()->GetProcess();
|
|
RenderProcessHostWatcher crash_observer(
|
|
crash_process, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
|
|
crash_process->Shutdown(0);
|
|
crash_observer.Wait();
|
|
|
|
// Wait for destruction of |inner_contents|.
|
|
inner_death_observer.Wait();
|
|
inner_contents = nullptr;
|
|
|
|
// This should cancel the pointer lock.
|
|
EXPECT_EQ(nullptr, web_contents()->GetPointerLockWidget());
|
|
EXPECT_EQ(nullptr, web_contents()->pointer_lock_widget_.get());
|
|
EXPECT_FALSE(web_contents()->HasPointerLock(
|
|
root->current_frame_host()->GetRenderWidgetHost()));
|
|
}
|
|
|
|
IN_PROC_BROWSER_TEST_F(PointerLockBrowserTest, PointerLockOopifCrashes) {
|
|
// This test runs three times, testing a crash at each level of the frametree.
|
|
for (int crash_depth = 0; crash_depth < 3; crash_depth++) {
|
|
GURL main_url(embedded_test_server()->GetURL(
|
|
"a.com", "/cross_site_iframe_factory.html?a(b(c))"));
|
|
EXPECT_TRUE(NavigateToURL(shell(), main_url));
|
|
|
|
FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root();
|
|
FrameTreeNode* lock_node = root->child_at(0)->child_at(0);
|
|
|
|
// Pick which node to crash.
|
|
FrameTreeNode* crash_node = root;
|
|
for (int i = 0; i < crash_depth; i++)
|
|
crash_node = crash_node->child_at(0);
|
|
|
|
// Request a pointer lock to |lock_node|'s document.body.
|
|
EXPECT_EQ(true, PointerLockHelper::RequestPointerLockOnBody(lock_node));
|
|
EXPECT_EQ(true, PointerLockHelper::IsPointerLockOnBody(lock_node));
|
|
|
|
// Root (platform) RenderWidgetHostView should have the pointer locked.
|
|
EXPECT_TRUE(root->current_frame_host()->GetView()->IsPointerLocked());
|
|
EXPECT_EQ(lock_node->current_frame_host()->GetRenderWidgetHost(),
|
|
web_contents()->GetPointerLockWidget());
|
|
|
|
// Crash the process of |crash_node|.
|
|
RenderProcessHost* crash_process =
|
|
crash_node->current_frame_host()->GetProcess();
|
|
RenderProcessHostWatcher crash_observer(
|
|
crash_process, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
|
|
crash_process->Shutdown(0);
|
|
crash_observer.Wait();
|
|
|
|
// This should cancel the pointer lock.
|
|
EXPECT_EQ(nullptr, web_contents()->GetPointerLockWidget());
|
|
EXPECT_EQ(nullptr, web_contents()->pointer_lock_widget_.get());
|
|
EXPECT_FALSE(web_contents()->HasPointerLock(
|
|
root->current_frame_host()->GetRenderWidgetHost()));
|
|
if (crash_depth != 0)
|
|
EXPECT_FALSE(root->current_frame_host()->GetView()->IsPointerLocked());
|
|
else
|
|
EXPECT_EQ(nullptr, root->current_frame_host()->GetView());
|
|
}
|
|
}
|
|
|
|
#if BUILDFLAG(IS_LINUX)
|
|
#define MAYBE_PointerLockWheelEventRouting DISABLED_PointerLockWheelEventRouting
|
|
#else
|
|
#define MAYBE_PointerLockWheelEventRouting PointerLockWheelEventRouting
|
|
#endif
|
|
IN_PROC_BROWSER_TEST_F(PointerLockBrowserTest,
|
|
MAYBE_PointerLockWheelEventRouting) {
|
|
GURL main_url(embedded_test_server()->GetURL(
|
|
"a.com", "/cross_site_iframe_factory.html?a(b)"));
|
|
EXPECT_TRUE(NavigateToURL(shell(), main_url));
|
|
|
|
FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root();
|
|
FrameTreeNode* child = root->child_at(0);
|
|
input::RenderWidgetHostInputEventRouter* router =
|
|
web_contents()->GetInputEventRouter();
|
|
RenderWidgetHostViewBase* root_view = static_cast<RenderWidgetHostViewBase*>(
|
|
root->current_frame_host()->GetView());
|
|
RenderWidgetHostViewBase* child_view = static_cast<RenderWidgetHostViewBase*>(
|
|
child->current_frame_host()->GetView());
|
|
|
|
WaitForHitTestData(child->current_frame_host());
|
|
|
|
// Add a mouse move event listener to the root frame.
|
|
EXPECT_TRUE(ExecJs(
|
|
root,
|
|
"var x; var y; var dX; var dY; document.addEventListener('mousemove', "
|
|
"function(e) {x = e.x; y = e.y; mX = e.movementX; mY = e.movementY;});"));
|
|
|
|
// Send a mouse move to root frame before lock to set last mouse position.
|
|
blink::WebMouseEvent mouse_event(
|
|
blink::WebInputEvent::Type::kMouseMove,
|
|
blink::WebInputEvent::kNoModifiers,
|
|
blink::WebInputEvent::GetStaticTimeStampForTests());
|
|
mouse_event.pointer_type = blink::WebPointerProperties::PointerType::kMouse;
|
|
mouse_event.SetPositionInWidget(6, 7);
|
|
mouse_event.SetPositionInScreen(6, 7);
|
|
mouse_event.movement_x = 8;
|
|
mouse_event.movement_y = 9;
|
|
router->RouteMouseEvent(root_view, &mouse_event, ui::LatencyInfo());
|
|
|
|
// Make sure that the renderer handled the input event.
|
|
MainThreadFrameObserver root_observer(root_view->GetRenderWidgetHost());
|
|
root_observer.Wait();
|
|
|
|
EXPECT_EQ("[6,7,0,0]", EvalJs(root, "JSON.stringify([x,y,mX,mY])"));
|
|
|
|
EXPECT_EQ(true, PointerLockHelper::RequestPointerLockOnBody(root));
|
|
|
|
// Root frame should have been granted pointer lock.
|
|
EXPECT_EQ(true, PointerLockHelper::IsPointerLockOnBody(root));
|
|
|
|
// Add a mouse move wheel event listener to the root frame.
|
|
EXPECT_TRUE(ExecJs(
|
|
root,
|
|
"var x; var y; var dX; var dY; document.addEventListener('mousewheel', "
|
|
"function(e) {x = e.x; y = e.y; dX = e.deltaX; dY = e.deltaY;});"));
|
|
root_observer.Wait();
|
|
|
|
blink::WebMouseWheelEvent wheel_event(
|
|
blink::WebInputEvent::Type::kMouseWheel,
|
|
blink::WebInputEvent::kNoModifiers,
|
|
blink::WebInputEvent::GetStaticTimeStampForTests());
|
|
wheel_event.SetPositionInScreen(10, 11);
|
|
wheel_event.delta_x = -12;
|
|
wheel_event.delta_y = -13;
|
|
wheel_event.phase = blink::WebMouseWheelEvent::kPhaseBegan;
|
|
router->RouteMouseWheelEvent(root_view, &wheel_event, ui::LatencyInfo());
|
|
|
|
// Make sure that the renderer handled the input event.
|
|
root_observer.Wait();
|
|
|
|
// All wheel events during a scroll sequence will be sent to a single target.
|
|
// Send a wheel end event to the current target before sending wheel events to
|
|
// a new target.
|
|
wheel_event.delta_x = 0;
|
|
wheel_event.delta_y = 0;
|
|
wheel_event.phase = blink::WebMouseWheelEvent::kPhaseEnded;
|
|
router->RouteMouseWheelEvent(root_view, &wheel_event, ui::LatencyInfo());
|
|
|
|
// Make sure that the renderer handled the input event.
|
|
root_observer.Wait();
|
|
|
|
// Locked event has same coordinates as before locked.
|
|
EXPECT_EQ("[6,7,12,13]", EvalJs(root, "JSON.stringify([x, y, dX, dY])"));
|
|
|
|
EXPECT_EQ(true, PointerLockHelper::ExitPointerLock(root));
|
|
|
|
EXPECT_EQ(true, PointerLockHelper::RequestPointerLockOnBody(child));
|
|
|
|
// Child frame should have been granted pointer lock.
|
|
EXPECT_EQ(true, PointerLockHelper::IsPointerLockOnBody(child));
|
|
|
|
// Add a mouse move event listener to the child frame.
|
|
EXPECT_TRUE(ExecJs(
|
|
child,
|
|
"var x; var y; var dX; var dY; document.addEventListener('mousewheel', "
|
|
"function(e) {x = e.x; y = e.y; dX = e.deltaX; dY = e.deltaY;});"));
|
|
MainThreadFrameObserver child_observer(child_view->GetRenderWidgetHost());
|
|
child_observer.Wait();
|
|
|
|
gfx::PointF transformed_point;
|
|
root_view->TransformPointToCoordSpaceForView(gfx::PointF(0, 0), child_view,
|
|
&transformed_point);
|
|
|
|
wheel_event.SetPositionInWidget(-transformed_point.x() + 14,
|
|
-transformed_point.y() + 15);
|
|
wheel_event.SetPositionInScreen(-transformed_point.x() + 14,
|
|
-transformed_point.y() + 15);
|
|
wheel_event.delta_x = -16;
|
|
wheel_event.delta_y = -17;
|
|
wheel_event.phase = blink::WebMouseWheelEvent::kPhaseBegan;
|
|
// We use root_view intentionally as the RenderWidgetHostInputEventRouter is
|
|
// responsible for correctly routing the event to the child frame.
|
|
router->RouteMouseWheelEvent(root_view, &wheel_event, ui::LatencyInfo());
|
|
|
|
// Make sure that the renderer handled the input event.
|
|
child_observer.Wait();
|
|
|
|
// This is the first event to child render, so the coordinates is (0, 0)
|
|
EXPECT_EQ("[0,0,16,17]", EvalJs(child, "JSON.stringify([x, y, dX, dY])"));
|
|
}
|
|
|
|
IN_PROC_BROWSER_TEST_F(PointerLockBrowserTest, PointerLockWidgetHidden) {
|
|
GURL main_url(embedded_test_server()->GetURL(
|
|
"a.com", "/cross_site_iframe_factory.html?a(b)"));
|
|
EXPECT_TRUE(NavigateToURL(shell(), main_url));
|
|
|
|
FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root();
|
|
FrameTreeNode* child = root->child_at(0);
|
|
RenderWidgetHostViewBase* child_view = static_cast<RenderWidgetHostViewBase*>(
|
|
child->current_frame_host()->GetView());
|
|
|
|
WaitForHitTestData(child->current_frame_host());
|
|
|
|
// Request a pointer lock on the child frame's body.
|
|
EXPECT_EQ(true, PointerLockHelper::RequestPointerLockOnBody(child));
|
|
// Child frame should have been granted pointer lock.
|
|
EXPECT_EQ(true, PointerLockHelper::IsPointerLockOnBody(child));
|
|
|
|
EXPECT_TRUE(child_view->IsPointerLocked());
|
|
EXPECT_EQ(child_view->host(), web_contents()->GetPointerLockWidget());
|
|
|
|
child_view->Hide();
|
|
|
|
// Child frame should've released the mouse lock when hidden.
|
|
EXPECT_FALSE(child_view->IsPointerLocked());
|
|
EXPECT_EQ(nullptr, web_contents()->GetPointerLockWidget());
|
|
}
|
|
|
|
#ifdef USE_AURA
|
|
IN_PROC_BROWSER_TEST_F(PointerLockBrowserTest, PointerLockOutOfFocus) {
|
|
GURL main_url(embedded_test_server()->GetURL(
|
|
"a.com", "/cross_site_iframe_factory.html?a(b)"));
|
|
EXPECT_TRUE(NavigateToURL(shell(), main_url));
|
|
|
|
FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root();
|
|
MockPointerLockRenderWidgetHostView* root_view =
|
|
static_cast<MockPointerLockRenderWidgetHostView*>(
|
|
root->current_frame_host()->GetView());
|
|
|
|
root_view->has_focus_ = false;
|
|
// Request a pointer lock on the root frame's body.
|
|
EXPECT_EQ(false, PointerLockHelper::RequestPointerLockOnBody(root));
|
|
// Root frame should not have been granted pointer lock.
|
|
EXPECT_EQ(false, PointerLockHelper::IsPointerLockOnBody(root));
|
|
}
|
|
#endif
|
|
|
|
IN_PROC_BROWSER_TEST_F(PointerLockBrowserTest, PointerLockOnDroppedElem) {
|
|
GURL url = embedded_test_server()->GetURL(
|
|
"a.com", "/pointerlock_on_dropped_elem.html");
|
|
EXPECT_TRUE(NavigateToURL(shell(), url));
|
|
|
|
EXPECT_TRUE(ExecJs(shell(), "document.body.click();"));
|
|
|
|
// The second ExecJS() call here delays test termination so that the first
|
|
// call's async tasks get a chance to run.
|
|
EXPECT_TRUE(ExecJs(shell(), "", EXECUTE_SCRIPT_NO_USER_GESTURE));
|
|
}
|
|
|
|
IN_PROC_BROWSER_TEST_F(PointerLockBrowserTest,
|
|
PointerLockRequestUnadjustedMovement) {
|
|
GURL main_url(embedded_test_server()->GetURL(
|
|
"a.com", "/cross_site_iframe_factory.html?a(b)"));
|
|
EXPECT_TRUE(NavigateToURL(shell(), main_url));
|
|
|
|
FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root();
|
|
|
|
EXPECT_TRUE(ExecJs(root, "var pointerLockPromise;"));
|
|
std::string wait_for_pointer_lock_promise =
|
|
"(async ()=> {return await pointerLockPromise.then(()=>true, "
|
|
"()=>false);})()";
|
|
std::string set_pointer_lock_promise =
|
|
R"code(pointerLockPromise = new Promise( function(resolve, reject){
|
|
document.addEventListener('pointerlockchange', resolve);
|
|
document.addEventListener('pointerlockerror', reject)
|
|
});)code";
|
|
|
|
// Request a pointer lock.
|
|
EXPECT_EQ(true, PointerLockHelper::RequestPointerLockOnBody(root));
|
|
// Root frame should have been granted pointer lock.
|
|
EXPECT_EQ(true, PointerLockHelper::IsPointerLockOnBody(root));
|
|
// Mouse is locked and unadjusted_movement is not set.
|
|
EXPECT_TRUE(root->current_frame_host()->GetView()->IsPointerLocked());
|
|
|
|
// Release pointer lock.
|
|
EXPECT_EQ(true, PointerLockHelper::ExitPointerLock(root));
|
|
|
|
#if defined(USE_AURA) || BUILDFLAG(IS_MAC)
|
|
// Request a pointer lock with unadjustedMovement.
|
|
EXPECT_EQ(
|
|
true,
|
|
PointerLockHelper::RequestPointerLockWithUnadjustedMovementOnBody(root));
|
|
// Root frame should have been granted pointer lock.
|
|
EXPECT_EQ(true, PointerLockHelper::IsPointerLockOnBody(root));
|
|
|
|
// Mouse is locked and unadjusted_movement is set.
|
|
EXPECT_TRUE(root->current_frame_host()->GetView()->IsPointerLocked());
|
|
EXPECT_TRUE(root->current_frame_host()
|
|
->GetView()
|
|
->GetIsPointerLockedUnadjustedMovementForTesting());
|
|
|
|
// Release pointer lock, unadjusted_movement bit is reset.
|
|
EXPECT_EQ(true, PointerLockHelper::ExitPointerLock(root));
|
|
|
|
EXPECT_FALSE(root->current_frame_host()
|
|
->GetView()
|
|
->GetIsPointerLockedUnadjustedMovementForTesting());
|
|
#else
|
|
// Request a pointer lock with unadjustedMovement.
|
|
// On platform that does not support unadjusted movement yet, do not lock and
|
|
// a pointerlockerror event is dispatched.
|
|
EXPECT_EQ(
|
|
false,
|
|
PointerLockHelper::RequestPointerLockWithUnadjustedMovementOnBody(root));
|
|
EXPECT_EQ(false, PointerLockHelper::IsPointerLockOnBody(root));
|
|
EXPECT_FALSE(root->current_frame_host()->GetView()->IsPointerLocked());
|
|
#endif
|
|
}
|
|
|
|
#if defined(USE_AURA)
|
|
// Flaky on all platforms http://crbug.com/1198612.
|
|
IN_PROC_BROWSER_TEST_F(PointerLockBrowserTest, DISABLED_UnadjustedMovement) {
|
|
GURL main_url(embedded_test_server()->GetURL(
|
|
"a.com", "/cross_site_iframe_factory.html?a(b)"));
|
|
EXPECT_TRUE(NavigateToURL(shell(), main_url));
|
|
|
|
FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root();
|
|
input::RenderWidgetHostInputEventRouter* router =
|
|
web_contents()->GetInputEventRouter();
|
|
RenderWidgetHostViewBase* root_view = static_cast<RenderWidgetHostViewBase*>(
|
|
root->current_frame_host()->GetView());
|
|
|
|
// Add a mouse move event listener to the root frame.
|
|
EXPECT_TRUE(ExecJs(
|
|
root,
|
|
"var x; var y; var mX; var mY; document.addEventListener('mousemove', "
|
|
"function(e) {x = e.x; y = e.y; mX = e.movementX; mY = e.movementY;});"));
|
|
|
|
// Send a mouse move to root frame before lock.
|
|
blink::WebMouseEvent mouse_event(
|
|
blink::WebInputEvent::Type::kMouseMove,
|
|
blink::WebInputEvent::kNoModifiers,
|
|
blink::WebInputEvent::GetStaticTimeStampForTests());
|
|
mouse_event.pointer_type = blink::WebPointerProperties::PointerType::kMouse;
|
|
mouse_event.SetPositionInWidget(6, 7);
|
|
mouse_event.SetPositionInScreen(6, 7);
|
|
mouse_event.movement_x = 8;
|
|
mouse_event.movement_y = 9;
|
|
router->RouteMouseEvent(root_view, &mouse_event, ui::LatencyInfo());
|
|
|
|
// Make sure that the renderer handled the input event.
|
|
MainThreadFrameObserver root_observer(root_view->GetRenderWidgetHost());
|
|
root_observer.Wait();
|
|
|
|
EXPECT_EQ("[6,7,0,0]", EvalJs(root, "JSON.stringify([x,y,mX,mY])"));
|
|
|
|
// Request a pointer lock with unadjustedMovement.
|
|
EXPECT_EQ(
|
|
true,
|
|
PointerLockHelper::RequestPointerLockWithUnadjustedMovementOnBody(root));
|
|
|
|
// Root frame should have been granted pointer lock.
|
|
EXPECT_EQ(true, PointerLockHelper::IsPointerLockOnBody(root));
|
|
|
|
// Mouse is locked and unadjusted_movement is not set.
|
|
EXPECT_TRUE(root->current_frame_host()->GetView()->IsPointerLocked());
|
|
|
|
mouse_event.SetPositionInWidget(10, 10);
|
|
mouse_event.SetPositionInScreen(10, 10);
|
|
mouse_event.movement_x = 12;
|
|
mouse_event.movement_y = 9;
|
|
mouse_event.is_raw_movement_event = true;
|
|
router->RouteMouseEvent(root_view, &mouse_event, ui::LatencyInfo());
|
|
root_observer.Wait();
|
|
|
|
// Raw movement events movement value from WebMouseEvent.movement_x/y.
|
|
EXPECT_EQ("[6,7,12,9]", EvalJs(root, "JSON.stringify([x,y,mX,mY])"));
|
|
|
|
mouse_event.SetPositionInWidget(20, 21);
|
|
mouse_event.SetPositionInScreen(20, 21);
|
|
mouse_event.movement_x = 1;
|
|
mouse_event.movement_y = 2;
|
|
mouse_event.is_raw_movement_event = false;
|
|
router->RouteMouseEvent(root_view, &mouse_event, ui::LatencyInfo());
|
|
root_observer.Wait();
|
|
|
|
// Non-raw movement events movement value from screen pos - last screen pos.
|
|
EXPECT_EQ("[6,7,10,11]", EvalJs(root, "JSON.stringify([x,y,mX,mY])"));
|
|
}
|
|
#endif
|
|
|
|
#if defined(USE_AURA)
|
|
// TODO(crbug.com/40635377): Remove failure test when fully implemented
|
|
#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_CHROMEOS)
|
|
#define MAYBE_ChangeUnadjustedMovementFailure \
|
|
DISABLED_ChangeUnadjustedMovementFailure
|
|
#else
|
|
#define MAYBE_ChangeUnadjustedMovementFailure ChangeUnadjustedMovementFailure
|
|
#endif
|
|
// Tests that a subsequent request to RequestPointerLock with different
|
|
// options inside a Child view gets piped to the proper places and gives
|
|
// the proper unsupported error(this option is only supported on Windows
|
|
// This was prompted by this bug: https://crbug.com/1062702
|
|
IN_PROC_BROWSER_TEST_F(PointerLockBrowserTest,
|
|
MAYBE_ChangeUnadjustedMovementFailure) {
|
|
GURL main_url(embedded_test_server()->GetURL(
|
|
"a.com", "/cross_site_iframe_factory.html?a(b)"));
|
|
EXPECT_TRUE(NavigateToURL(shell(), main_url));
|
|
|
|
FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root();
|
|
FrameTreeNode* child = root->child_at(0);
|
|
RenderWidgetHostViewBase* child_view = static_cast<RenderWidgetHostViewBase*>(
|
|
child->current_frame_host()->GetView());
|
|
|
|
WaitForHitTestData(child->current_frame_host());
|
|
|
|
// Request a pointer lock on the child frame's body and wait for the promise
|
|
// to resolve.
|
|
EXPECT_EQ(true, PointerLockHelper::RequestPointerLockOnBody(child));
|
|
// Child frame should have been granted pointer lock.
|
|
EXPECT_EQ(true, PointerLockHelper::IsPointerLockOnBody(child));
|
|
|
|
EXPECT_TRUE(child_view->IsPointerLocked());
|
|
EXPECT_FALSE(root->current_frame_host()
|
|
->GetView()
|
|
->GetIsPointerLockedUnadjustedMovementForTesting());
|
|
EXPECT_EQ(child_view->host(), web_contents()->GetPointerLockWidget());
|
|
|
|
// Request to change pointer lock options and wait for return.
|
|
EXPECT_EQ(
|
|
"a JavaScript error: \"NotSupportedError: The options asked for in this "
|
|
"request are not supported on this platform.\"\n",
|
|
EvalJs(child,
|
|
"document.body.requestPointerLock({unadjustedMovement:true})")
|
|
.error);
|
|
|
|
// The change errored out but the original lock should still be in place.
|
|
EXPECT_TRUE(child_view->IsPointerLocked());
|
|
EXPECT_FALSE(root->current_frame_host()
|
|
->GetView()
|
|
->GetIsPointerLockedUnadjustedMovementForTesting());
|
|
EXPECT_EQ(child_view->host(), web_contents()->GetPointerLockWidget());
|
|
}
|
|
#endif
|
|
|
|
#if defined(USE_AURA)
|
|
#if BUILDFLAG(IS_WIN)
|
|
// Tests that a subsequent request to RequestPointerLock with different
|
|
// options inside a Child view gets piped to the proper places and updates
|
|
// the option(this option is only supported on Windows).
|
|
// This was prompted by this bug: https://crbug.com/1062702
|
|
IN_PROC_BROWSER_TEST_F(PointerLockBrowserTest,
|
|
ChangeUnadjustedMovementSuccess) {
|
|
GURL main_url(embedded_test_server()->GetURL(
|
|
"a.com", "/cross_site_iframe_factory.html?a(b)"));
|
|
EXPECT_TRUE(NavigateToURL(shell(), main_url));
|
|
|
|
FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root();
|
|
FrameTreeNode* child = root->child_at(0);
|
|
RenderWidgetHostViewBase* child_view = static_cast<RenderWidgetHostViewBase*>(
|
|
child->current_frame_host()->GetView());
|
|
|
|
WaitForHitTestData(child->current_frame_host());
|
|
|
|
// Request a pointer lock on the child frame's body and wait for the promise
|
|
// to resolve.
|
|
EXPECT_EQ(true, PointerLockHelper::RequestPointerLockOnBody(child));
|
|
// Child frame should have been granted pointer lock.
|
|
EXPECT_EQ(true, PointerLockHelper::IsPointerLockOnBody(child));
|
|
|
|
EXPECT_TRUE(child_view->IsPointerLocked());
|
|
EXPECT_FALSE(root->current_frame_host()
|
|
->GetView()
|
|
->GetIsPointerLockedUnadjustedMovementForTesting());
|
|
EXPECT_EQ(child_view->host(), web_contents()->GetPointerLockWidget());
|
|
|
|
// Request to change pointer lock options and wait for return.
|
|
EXPECT_EQ(
|
|
nullptr,
|
|
EvalJs(child,
|
|
"document.body.requestPointerLock({unadjustedMovement:true})"));
|
|
|
|
// The new changed lock should now be in place.
|
|
EXPECT_TRUE(child_view->IsPointerLocked());
|
|
EXPECT_TRUE(root->current_frame_host()
|
|
->GetView()
|
|
->GetIsPointerLockedUnadjustedMovementForTesting());
|
|
EXPECT_EQ(child_view->host(), web_contents()->GetPointerLockWidget());
|
|
}
|
|
#endif // WIN_OS
|
|
#endif // USE_AURA
|
|
} // namespace content
|