OLD | NEW |
(Empty) | |
| 1 // Copyright 2017 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include "content/browser/pointer_lock_browsertest.h" |
| 6 |
| 7 #include "content/browser/frame_host/frame_tree.h" |
| 8 #include "content/browser/renderer_host/render_widget_host_impl.h" |
| 9 #include "content/browser/renderer_host/render_widget_host_input_event_router.h" |
| 10 #include "content/browser/web_contents/web_contents_impl.h" |
| 11 #include "content/public/browser/web_contents_delegate.h" |
| 12 #include "content/public/test/browser_test_utils.h" |
| 13 #include "content/public/test/content_browser_test.h" |
| 14 #include "content/public/test/content_browser_test_utils.h" |
| 15 #include "content/public/test/test_utils.h" |
| 16 #include "content/shell/browser/shell.h" |
| 17 #include "content/test/content_browser_test_utils_internal.h" |
| 18 #include "net/dns/mock_host_resolver.h" |
| 19 #include "net/test/embedded_test_server/embedded_test_server.h" |
| 20 |
| 21 #ifdef USE_AURA |
| 22 #include "content/browser/renderer_host/render_widget_host_view_aura.h" |
| 23 #include "content/browser/web_contents/web_contents_view_aura.h" |
| 24 #endif // USE_AURA |
| 25 |
| 26 namespace content { |
| 27 |
| 28 namespace { |
| 29 |
| 30 #ifdef USE_AURA |
| 31 class MockRenderWidgetHostView : public RenderWidgetHostViewAura { |
| 32 public: |
| 33 MockRenderWidgetHostView(RenderWidgetHost* host, bool is_guest_view_hack) |
| 34 : RenderWidgetHostViewAura(host, is_guest_view_hack), |
| 35 host_(RenderWidgetHostImpl::From(host)) {} |
| 36 ~MockRenderWidgetHostView() override { |
| 37 if (mouse_locked_) |
| 38 UnlockMouse(); |
| 39 } |
| 40 |
| 41 bool LockMouse() override { |
| 42 mouse_locked_ = true; |
| 43 return true; |
| 44 } |
| 45 |
| 46 void UnlockMouse() override { |
| 47 host_->LostMouseLock(); |
| 48 mouse_locked_ = false; |
| 49 } |
| 50 |
| 51 bool IsMouseLocked() override { return mouse_locked_; } |
| 52 |
| 53 bool HasFocus() const override { return true; } |
| 54 |
| 55 void OnWindowFocused(aura::Window* gained_focus, |
| 56 aura::Window* lost_focus) override { |
| 57 // Ignore window focus events. |
| 58 } |
| 59 |
| 60 RenderWidgetHostImpl* host_; |
| 61 }; |
| 62 #endif // USE_AURA |
| 63 |
| 64 } // namespace |
| 65 |
| 66 class MockPointerLockWebContentsDelegate : public WebContentsDelegate { |
| 67 public: |
| 68 MockPointerLockWebContentsDelegate() {} |
| 69 ~MockPointerLockWebContentsDelegate() override {} |
| 70 |
| 71 void RequestToLockMouse(WebContents* web_contents, |
| 72 bool user_gesture, |
| 73 bool last_unlocked_by_target) override { |
| 74 web_contents->GotResponseToLockMouseRequest(true); |
| 75 } |
| 76 |
| 77 void LostMouseLock() override {} |
| 78 }; |
| 79 |
| 80 #ifdef USE_AURA |
| 81 void InstallCreateHooksForPointerLockBrowserTests() { |
| 82 WebContentsViewAura::InstallCreateHookForTests( |
| 83 [](RenderWidgetHost* host, |
| 84 bool is_guest_view_hack) -> RenderWidgetHostViewAura* { |
| 85 return new MockRenderWidgetHostView(host, is_guest_view_hack); |
| 86 }); |
| 87 } |
| 88 #endif // USE_AURA |
| 89 |
| 90 class PointerLockBrowserTest : public ContentBrowserTest { |
| 91 public: |
| 92 PointerLockBrowserTest() {} |
| 93 |
| 94 protected: |
| 95 void SetUpCommandLine(base::CommandLine* command_line) override { |
| 96 IsolateAllSitesForTesting(command_line); |
| 97 } |
| 98 |
| 99 void SetUp() override { |
| 100 InstallCreateHooksForPointerLockBrowserTests(); |
| 101 ContentBrowserTest::SetUp(); |
| 102 } |
| 103 |
| 104 void SetUpOnMainThread() override { |
| 105 host_resolver()->AddRule("*", "127.0.0.1"); |
| 106 SetupCrossSiteRedirector(embedded_test_server()); |
| 107 ASSERT_TRUE(embedded_test_server()->Start()); |
| 108 |
| 109 web_contents()->SetDelegate(&web_contents_delegate_); |
| 110 } |
| 111 |
| 112 WebContentsImpl* web_contents() const { |
| 113 return static_cast<WebContentsImpl*>(shell()->web_contents()); |
| 114 } |
| 115 |
| 116 private: |
| 117 MockPointerLockWebContentsDelegate web_contents_delegate_; |
| 118 }; |
| 119 |
| 120 IN_PROC_BROWSER_TEST_F(PointerLockBrowserTest, PointerLock) { |
| 121 GURL main_url(embedded_test_server()->GetURL( |
| 122 "a.com", "/cross_site_iframe_factory.html?a(b)")); |
| 123 EXPECT_TRUE(NavigateToURL(shell(), main_url)); |
| 124 |
| 125 FrameTreeNode* root = web_contents()->GetFrameTree()->root(); |
| 126 FrameTreeNode* child = root->child_at(0); |
| 127 |
| 128 // Request a pointer lock on the root frame's body. |
| 129 EXPECT_TRUE(ExecuteScript(root, "document.body.requestPointerLock()")); |
| 130 |
| 131 // Root frame should have been granted pointer lock. |
| 132 bool locked = false; |
| 133 EXPECT_TRUE(ExecuteScriptAndExtractBool(root, |
| 134 "window.domAutomationController.send(" |
| 135 "document.pointerLockElement == " |
| 136 "document.body);", |
| 137 &locked)); |
| 138 EXPECT_TRUE(locked); |
| 139 |
| 140 // Request a pointer lock on the child frame's body. |
| 141 EXPECT_TRUE(ExecuteScript(child, "document.body.requestPointerLock()")); |
| 142 |
| 143 // Child frame should not be granted pointer lock since the root frame has it. |
| 144 EXPECT_TRUE(ExecuteScriptAndExtractBool(child, |
| 145 "window.domAutomationController.send(" |
| 146 "document.pointerLockElement == " |
| 147 "document.body);", |
| 148 &locked)); |
| 149 EXPECT_FALSE(locked); |
| 150 |
| 151 // Release pointer lock on root frame. |
| 152 EXPECT_TRUE(ExecuteScript(root, "document.exitPointerLock()")); |
| 153 |
| 154 // Request a pointer lock on the child frame's body. |
| 155 EXPECT_TRUE(ExecuteScript(child, "document.body.requestPointerLock()")); |
| 156 |
| 157 // Child frame should have been granted pointer lock. |
| 158 EXPECT_TRUE(ExecuteScriptAndExtractBool(child, |
| 159 "window.domAutomationController.send(" |
| 160 "document.pointerLockElement == " |
| 161 "document.body);", |
| 162 &locked)); |
| 163 EXPECT_TRUE(locked); |
| 164 } |
| 165 |
| 166 IN_PROC_BROWSER_TEST_F(PointerLockBrowserTest, PointerLockEventRouting) { |
| 167 GURL main_url(embedded_test_server()->GetURL( |
| 168 "a.com", "/cross_site_iframe_factory.html?a(b)")); |
| 169 EXPECT_TRUE(NavigateToURL(shell(), main_url)); |
| 170 |
| 171 FrameTreeNode* root = web_contents()->GetFrameTree()->root(); |
| 172 FrameTreeNode* child = root->child_at(0); |
| 173 RenderWidgetHostInputEventRouter* router = |
| 174 web_contents()->GetInputEventRouter(); |
| 175 RenderWidgetHostViewBase* root_view = static_cast<RenderWidgetHostViewBase*>( |
| 176 root->current_frame_host()->GetView()); |
| 177 RenderWidgetHostViewBase* child_view = static_cast<RenderWidgetHostViewBase*>( |
| 178 child->current_frame_host()->GetView()); |
| 179 |
| 180 // Request a pointer lock on the root frame's body. |
| 181 EXPECT_TRUE(ExecuteScript(root, "document.body.requestPointerLock()")); |
| 182 |
| 183 // Root frame should have been granted pointer lock. |
| 184 bool locked = false; |
| 185 EXPECT_TRUE(ExecuteScriptAndExtractBool(root, |
| 186 "window.domAutomationController.send(" |
| 187 "document.pointerLockElement == " |
| 188 "document.body);", |
| 189 &locked)); |
| 190 EXPECT_TRUE(locked); |
| 191 |
| 192 // Add a mouse move event listener to the root frame. |
| 193 EXPECT_TRUE(ExecuteScript( |
| 194 root, |
| 195 "var x; var y; var mX; var mY; document.addEventListener('mousemove', " |
| 196 "function(e) {x = e.x; y = e.y; mX = e.movementX; mY = e.movementY;});")); |
| 197 |
| 198 blink::WebMouseEvent mouse_event(blink::WebInputEvent::MouseMove, |
| 199 blink::WebInputEvent::NoModifiers, |
| 200 blink::WebInputEvent::TimeStampForTesting); |
| 201 mouse_event.x = 10; |
| 202 mouse_event.y = 11; |
| 203 mouse_event.movementX = 12; |
| 204 mouse_event.movementY = 13; |
| 205 router->RouteMouseEvent(root_view, &mouse_event, ui::LatencyInfo()); |
| 206 |
| 207 // Make sure that the renderer handled the input event. |
| 208 MainThreadFrameObserver root_observer(root_view->GetRenderWidgetHost()); |
| 209 root_observer.Wait(); |
| 210 |
| 211 int x, y, movementX, movementY; |
| 212 EXPECT_TRUE(ExecuteScriptAndExtractInt( |
| 213 root, "window.domAutomationController.send(x);", &x)); |
| 214 EXPECT_TRUE(ExecuteScriptAndExtractInt( |
| 215 root, "window.domAutomationController.send(y);", &y)); |
| 216 EXPECT_TRUE(ExecuteScriptAndExtractInt( |
| 217 root, "window.domAutomationController.send(mX);", &movementX)); |
| 218 EXPECT_TRUE(ExecuteScriptAndExtractInt( |
| 219 root, "window.domAutomationController.send(mY);", &movementY)); |
| 220 EXPECT_EQ(10, x); |
| 221 EXPECT_EQ(11, y); |
| 222 EXPECT_EQ(12, movementX); |
| 223 EXPECT_EQ(13, movementY); |
| 224 |
| 225 // Release pointer lock on root frame. |
| 226 EXPECT_TRUE(ExecuteScript(root, "document.exitPointerLock()")); |
| 227 |
| 228 // Request a pointer lock on the child frame's body. |
| 229 EXPECT_TRUE(ExecuteScript(child, "document.body.requestPointerLock()")); |
| 230 |
| 231 // Child frame should have been granted pointer lock. |
| 232 EXPECT_TRUE(ExecuteScriptAndExtractBool(child, |
| 233 "window.domAutomationController.send(" |
| 234 "document.pointerLockElement == " |
| 235 "document.body);", |
| 236 &locked)); |
| 237 EXPECT_TRUE(locked); |
| 238 |
| 239 // Add a mouse move event listener to the child frame. |
| 240 EXPECT_TRUE(ExecuteScript( |
| 241 child, |
| 242 "var x; var y; var mX; var mY; document.addEventListener('mousemove', " |
| 243 "function(e) {x = e.x; y = e.y; mX = e.movementX; mY = e.movementY;});")); |
| 244 |
| 245 gfx::Point transformed_point; |
| 246 root_view->TransformPointToCoordSpaceForView(gfx::Point(0, 0), child_view, |
| 247 &transformed_point); |
| 248 |
| 249 mouse_event.x = -transformed_point.x() + 14; |
| 250 mouse_event.y = -transformed_point.y() + 15; |
| 251 mouse_event.movementX = 16; |
| 252 mouse_event.movementY = 17; |
| 253 // We use root_view intentionally as the RenderWidgetHostInputEventRouter is |
| 254 // responsible for correctly routing the event to the child frame. |
| 255 router->RouteMouseEvent(root_view, &mouse_event, ui::LatencyInfo()); |
| 256 |
| 257 // Make sure that the renderer handled the input event. |
| 258 MainThreadFrameObserver child_observer(child_view->GetRenderWidgetHost()); |
| 259 child_observer.Wait(); |
| 260 |
| 261 EXPECT_TRUE(ExecuteScriptAndExtractInt( |
| 262 child, "window.domAutomationController.send(x);", &x)); |
| 263 EXPECT_TRUE(ExecuteScriptAndExtractInt( |
| 264 child, "window.domAutomationController.send(y);", &y)); |
| 265 EXPECT_TRUE(ExecuteScriptAndExtractInt( |
| 266 child, "window.domAutomationController.send(mX);", &movementX)); |
| 267 EXPECT_TRUE(ExecuteScriptAndExtractInt( |
| 268 child, "window.domAutomationController.send(mY);", &movementY)); |
| 269 EXPECT_EQ(14, x); |
| 270 EXPECT_EQ(15, y); |
| 271 EXPECT_EQ(16, movementX); |
| 272 EXPECT_EQ(17, movementY); |
| 273 } |
| 274 |
| 275 } // namespace content |
OLD | NEW |