OLD | NEW |
1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "base/command_line.h" | 5 #include "base/command_line.h" |
| 6 #include "base/strings/string_number_conversions.h" |
6 #include "chrome/browser/ui/browser.h" | 7 #include "chrome/browser/ui/browser.h" |
| 8 #include "chrome/browser/ui/browser_window.h" |
7 #include "chrome/browser/ui/tabs/tab_strip_model.h" | 9 #include "chrome/browser/ui/tabs/tab_strip_model.h" |
8 #include "chrome/test/base/in_process_browser_test.h" | 10 #include "chrome/test/base/in_process_browser_test.h" |
| 11 #include "chrome/test/base/interactive_test_utils.h" |
9 #include "chrome/test/base/ui_test_utils.h" | 12 #include "chrome/test/base/ui_test_utils.h" |
10 #include "content/public/browser/render_frame_host.h" | 13 #include "content/public/browser/render_frame_host.h" |
| 14 #include "content/public/browser/render_widget_host_view.h" |
11 #include "content/public/browser/web_contents.h" | 15 #include "content/public/browser/web_contents.h" |
12 #include "content/public/test/browser_test_utils.h" | 16 #include "content/public/test/browser_test_utils.h" |
13 #include "content/public/test/content_browser_test_utils.h" | 17 #include "content/public/test/content_browser_test_utils.h" |
| 18 #include "content/public/test/test_navigation_observer.h" |
14 #include "content/public/test/test_utils.h" | 19 #include "content/public/test/test_utils.h" |
15 #include "net/dns/mock_host_resolver.h" | 20 #include "net/dns/mock_host_resolver.h" |
16 #include "net/test/embedded_test_server/embedded_test_server.h" | 21 #include "net/test/embedded_test_server/embedded_test_server.h" |
| 22 #include "ui/display/display.h" |
| 23 #include "ui/display/screen.h" |
17 #include "url/gurl.h" | 24 #include "url/gurl.h" |
18 | 25 |
19 class SitePerProcessInteractiveBrowserTest : public InProcessBrowserTest { | 26 class SitePerProcessInteractiveBrowserTest : public InProcessBrowserTest { |
20 public: | 27 public: |
21 SitePerProcessInteractiveBrowserTest() {} | 28 SitePerProcessInteractiveBrowserTest() {} |
22 ~SitePerProcessInteractiveBrowserTest() override {} | 29 ~SitePerProcessInteractiveBrowserTest() override {} |
23 | 30 |
24 void SetUpCommandLine(base::CommandLine* command_line) override { | 31 void SetUpCommandLine(base::CommandLine* command_line) override { |
25 content::IsolateAllSitesForTesting(command_line); | 32 content::IsolateAllSitesForTesting(command_line); |
26 } | 33 } |
27 | 34 |
28 void SetUpOnMainThread() override { | 35 void SetUpOnMainThread() override { |
29 host_resolver()->AddRule("*", "127.0.0.1"); | 36 host_resolver()->AddRule("*", "127.0.0.1"); |
30 | 37 |
31 // Add content/test/data for cross_site_iframe_factory.html | 38 // Add content/test/data for cross_site_iframe_factory.html |
32 embedded_test_server()->ServeFilesFromSourceDirectory("content/test/data"); | 39 embedded_test_server()->ServeFilesFromSourceDirectory("content/test/data"); |
33 | 40 |
34 ASSERT_TRUE(embedded_test_server()->Start()); | 41 ASSERT_TRUE(embedded_test_server()->Start()); |
35 } | 42 } |
36 | 43 |
| 44 gfx::Size GetScreenSize() { |
| 45 content::WebContents* web_contents = |
| 46 browser()->tab_strip_model()->GetActiveWebContents(); |
| 47 const display::Display display = |
| 48 display::Screen::GetScreen()->GetDisplayNearestWindow( |
| 49 web_contents->GetRenderWidgetHostView()->GetNativeView()); |
| 50 return display.bounds().size(); |
| 51 } |
| 52 |
37 private: | 53 private: |
38 DISALLOW_COPY_AND_ASSIGN(SitePerProcessInteractiveBrowserTest); | 54 DISALLOW_COPY_AND_ASSIGN(SitePerProcessInteractiveBrowserTest); |
39 }; | 55 }; |
40 | 56 |
41 // Check that document.hasFocus() works properly with out-of-process iframes. | 57 // Check that document.hasFocus() works properly with out-of-process iframes. |
42 // The test builds a page with four cross-site frames and then focuses them one | 58 // The test builds a page with four cross-site frames and then focuses them one |
43 // by one, checking the value of document.hasFocus() in all frames. For any | 59 // by one, checking the value of document.hasFocus() in all frames. For any |
44 // given focused frame, document.hasFocus() should return true for that frame | 60 // given focused frame, document.hasFocus() should return true for that frame |
45 // and all its ancestor frames. | 61 // and all its ancestor frames. |
46 IN_PROC_BROWSER_TEST_F(SitePerProcessInteractiveBrowserTest, DocumentHasFocus) { | 62 IN_PROC_BROWSER_TEST_F(SitePerProcessInteractiveBrowserTest, DocumentHasFocus) { |
(...skipping 178 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
225 EXPECT_EQ("\"child2-focused-input2\"", press_tab_and_wait_for_message(true)); | 241 EXPECT_EQ("\"child2-focused-input2\"", press_tab_and_wait_for_message(true)); |
226 EXPECT_EQ(child2, web_contents->GetFocusedFrame()); | 242 EXPECT_EQ(child2, web_contents->GetFocusedFrame()); |
227 EXPECT_EQ("\"child2-focused-input1\"", press_tab_and_wait_for_message(true)); | 243 EXPECT_EQ("\"child2-focused-input1\"", press_tab_and_wait_for_message(true)); |
228 EXPECT_EQ("\"child1-focused-input2\"", press_tab_and_wait_for_message(true)); | 244 EXPECT_EQ("\"child1-focused-input2\"", press_tab_and_wait_for_message(true)); |
229 EXPECT_EQ(child1, web_contents->GetFocusedFrame()); | 245 EXPECT_EQ(child1, web_contents->GetFocusedFrame()); |
230 EXPECT_EQ("\"child1-focused-input1\"", press_tab_and_wait_for_message(true)); | 246 EXPECT_EQ("\"child1-focused-input1\"", press_tab_and_wait_for_message(true)); |
231 EXPECT_EQ("\"root-focused-input1\"", press_tab_and_wait_for_message(true)); | 247 EXPECT_EQ("\"root-focused-input1\"", press_tab_and_wait_for_message(true)); |
232 EXPECT_EQ(main_frame, web_contents->GetFocusedFrame()); | 248 EXPECT_EQ(main_frame, web_contents->GetFocusedFrame()); |
233 } | 249 } |
234 | 250 |
| 251 namespace { |
| 252 |
| 253 // Helper to retrieve the frame's (window.innerWidth, window.innerHeight). |
| 254 gfx::Size GetFrameSize(content::RenderFrameHost* frame) { |
| 255 int width = 0; |
| 256 EXPECT_TRUE(ExecuteScriptAndExtractInt( |
| 257 frame, "domAutomationController.send(window.innerWidth);", &width)); |
| 258 |
| 259 int height = 0; |
| 260 EXPECT_TRUE(ExecuteScriptAndExtractInt( |
| 261 frame, "domAutomationController.send(window.innerHeight);", &height)); |
| 262 |
| 263 return gfx::Size(width, height); |
| 264 } |
| 265 |
| 266 // Helper to check |frame|'s document.webkitFullscreenElement and return its ID |
| 267 // if it's defined (which is the case when |frame| is in fullscreen mode), or |
| 268 // "none" otherwise. |
| 269 std::string GetFullscreenElementId(content::RenderFrameHost* frame) { |
| 270 std::string fullscreen_element; |
| 271 EXPECT_TRUE(ExecuteScriptAndExtractString( |
| 272 frame, |
| 273 "domAutomationController.send(" |
| 274 " document.webkitFullscreenElement ? " |
| 275 " document.webkitFullscreenElement.id : 'none')", |
| 276 &fullscreen_element)); |
| 277 return fullscreen_element; |
| 278 } |
| 279 |
| 280 // Helper to check if an element with ID |element_id| has the |
| 281 // :-webkit-full-screen style. |
| 282 bool ElementHasFullscreenStyle(content::RenderFrameHost* frame, |
| 283 const std::string& element_id) { |
| 284 bool has_style = false; |
| 285 std::string script = base::StringPrintf( |
| 286 "domAutomationController.send(" |
| 287 " document.querySelectorAll('#%s:-webkit-full-screen').length == 1)", |
| 288 element_id.c_str()); |
| 289 EXPECT_TRUE(ExecuteScriptAndExtractBool(frame, script, &has_style)); |
| 290 return has_style; |
| 291 } |
| 292 |
| 293 // Helper to check if an element with ID |element_id| has the |
| 294 // :-webkit-full-screen-ancestor style. |
| 295 bool ElementHasFullscreenAncestorStyle(content::RenderFrameHost* host, |
| 296 const std::string& element_id) { |
| 297 bool has_style = false; |
| 298 std::string script = base::StringPrintf( |
| 299 "domAutomationController.send(" |
| 300 " document.querySelectorAll(" |
| 301 " '#%s:-webkit-full-screen-ancestor').length == 1)", |
| 302 element_id.c_str()); |
| 303 EXPECT_TRUE(ExecuteScriptAndExtractBool(host, script, &has_style)); |
| 304 return has_style; |
| 305 } |
| 306 |
| 307 // Set the allowFullscreen attribute on the <iframe> element identified by |
| 308 // |frame_id|. |
| 309 void SetAllowFullscreenForFrame(content::RenderFrameHost* host, |
| 310 const std::string& frame_id) { |
| 311 EXPECT_TRUE(ExecuteScript( |
| 312 host, base::StringPrintf( |
| 313 "document.getElementById('%s').allowFullscreen = true;", |
| 314 frame_id.c_str()))); |
| 315 } |
| 316 |
| 317 // Add a listener that will send back a message whenever the (prefixed) |
| 318 // fullscreenchange event fires. The message will be "fullscreenchange", |
| 319 // followed by a space and the provided |id|. |
| 320 void AddFullscreenChangeListener(content::RenderFrameHost* frame, |
| 321 const std::string& id) { |
| 322 std::string script = base::StringPrintf( |
| 323 "document.addEventListener('webkitfullscreenchange', function() {" |
| 324 " domAutomationController.setAutomationId(0);" |
| 325 " domAutomationController.send('fullscreenchange %s');});", |
| 326 id.c_str()); |
| 327 EXPECT_TRUE(ExecuteScript(frame, script)); |
| 328 } |
| 329 |
| 330 // Helper to add a listener that will send back a "resize" message when the |
| 331 // target |frame| is resized to |expected_size|. |
| 332 void AddResizeListener(content::RenderFrameHost* frame, |
| 333 const gfx::Size& expected_size) { |
| 334 std::string script = |
| 335 base::StringPrintf("addResizeListener(%d, %d);", |
| 336 expected_size.width(), expected_size.height()); |
| 337 EXPECT_TRUE(ExecuteScript(frame, script)); |
| 338 } |
| 339 |
| 340 // Helper to wait for a toggle fullscreen operation to complete in all affected |
| 341 // frames. This means waiting for: |
| 342 // 1. All fullscreenchange events with id's matching the list in |
| 343 // |expected_fullscreen_event_ids|. Typically the list will correspond to |
| 344 // events from the actual fullscreen element and all of its ancestor |
| 345 // <iframe> elements. |
| 346 // 2. A resize event. This will verify that the frame containing the |
| 347 // fullscreen element is properly resized. This assumes that the expected |
| 348 // size is already registered via AddResizeListener(). |
| 349 void WaitForMultipleFullscreenEvents( |
| 350 const std::set<std::string>& expected_fullscreen_event_ids, |
| 351 content::DOMMessageQueue& queue) { |
| 352 std::set<std::string> remaining_events(expected_fullscreen_event_ids); |
| 353 bool resize_validated = false; |
| 354 std::string response; |
| 355 while (queue.WaitForMessage(&response)) { |
| 356 base::TrimString(response, "\"", &response); |
| 357 std::vector<std::string> response_params = base::SplitString( |
| 358 response, " ", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL); |
| 359 if (response_params[0] == "fullscreenchange") { |
| 360 EXPECT_TRUE(ContainsKey(remaining_events, response_params[1])); |
| 361 remaining_events.erase(response_params[1]); |
| 362 } else if (response_params[0] == "resize") { |
| 363 resize_validated = true; |
| 364 } |
| 365 if (remaining_events.empty() && resize_validated) |
| 366 break; |
| 367 } |
| 368 } |
| 369 |
| 370 } // namespace |
| 371 |
| 372 // Check that an element in a cross-process subframe can enter and exit |
| 373 // fullscreen. The test will verify that: |
| 374 // - the subframe is properly resized |
| 375 // - the WebContents properly enters/exits fullscreen. |
| 376 // - document.webkitFullscreenElement is correctly updated in both frames. |
| 377 // - fullscreenchange events fire in both frames. |
| 378 // - fullscreen CSS is applied correctly in both frames. |
| 379 IN_PROC_BROWSER_TEST_F(SitePerProcessInteractiveBrowserTest, |
| 380 FullscreenElementInSubframe) { |
| 381 // Start on a page with one subframe (id "child-0") that has |
| 382 // "allowfullscreen" enabled. |
| 383 GURL main_url(embedded_test_server()->GetURL( |
| 384 "a.com", "/page_with_allowfullscreen_frame.html")); |
| 385 ui_test_utils::NavigateToURL(browser(), main_url); |
| 386 content::WebContents* web_contents = |
| 387 browser()->tab_strip_model()->GetActiveWebContents(); |
| 388 |
| 389 // Navigate the subframe cross-site to a page with a fullscreenable <div>. |
| 390 GURL frame_url( |
| 391 embedded_test_server()->GetURL("b.com", "/fullscreen_frame.html")); |
| 392 EXPECT_TRUE(NavigateIframeToURL(web_contents, "child-0", frame_url)); |
| 393 |
| 394 content::RenderFrameHost* main_frame = web_contents->GetMainFrame(); |
| 395 content::RenderFrameHost* child = ChildFrameAt(main_frame, 0); |
| 396 gfx::Size original_child_size = GetFrameSize(child); |
| 397 |
| 398 // Fullscreen the <div> inside the cross-site child frame. Wait until: |
| 399 // (1) the fullscreenchange events in main frame and child send a response, |
| 400 // (2) the child frame is resized to fill the whole screen. |
| 401 AddFullscreenChangeListener(main_frame, "main_frame"); |
| 402 AddFullscreenChangeListener(child, "child"); |
| 403 std::set<std::string> expected_events = {"main_frame", "child"}; |
| 404 AddResizeListener(child, GetScreenSize()); |
| 405 { |
| 406 content::DOMMessageQueue queue; |
| 407 EXPECT_TRUE(ExecuteScript(child, "activateFullscreen()")); |
| 408 WaitForMultipleFullscreenEvents(expected_events, queue); |
| 409 } |
| 410 |
| 411 // Verify that the browser has entered fullscreen for the current tab. |
| 412 EXPECT_TRUE(browser()->window()->IsFullscreen()); |
| 413 EXPECT_TRUE(browser()->exclusive_access_manager() |
| 414 ->fullscreen_controller() |
| 415 ->IsFullscreenForTabOrPending(web_contents)); |
| 416 |
| 417 // Verify that the <div> has fullscreen style (:-webkit-full-screen) in the |
| 418 // subframe. |
| 419 EXPECT_TRUE(ElementHasFullscreenStyle(child, "fullscreen-div")); |
| 420 |
| 421 // Verify that the main frame has applied proper fullscreen styles to the |
| 422 // <iframe> element (:-webkit-full-screen and :-webkit-full-screen-ancestor). |
| 423 // This is what causes the <iframe> to stretch and fill the whole viewport. |
| 424 EXPECT_TRUE(ElementHasFullscreenStyle(main_frame, "child-0")); |
| 425 EXPECT_TRUE(ElementHasFullscreenAncestorStyle(main_frame, "child-0")); |
| 426 |
| 427 // Check document.webkitFullscreenElement. For main frame, it should point |
| 428 // to the subframe, and for subframe, it should point to the fullscreened |
| 429 // <div>. |
| 430 EXPECT_EQ("child-0", GetFullscreenElementId(main_frame)); |
| 431 EXPECT_EQ("fullscreen-div", GetFullscreenElementId(child)); |
| 432 |
| 433 // Now exit fullscreen from the subframe. Wait for two fullscreenchange |
| 434 // events from both frames, and also for the child to be resized to its |
| 435 // original size. |
| 436 AddResizeListener(child, original_child_size); |
| 437 { |
| 438 content::DOMMessageQueue queue; |
| 439 EXPECT_TRUE(ExecuteScript(child, "exitFullscreen()")); |
| 440 WaitForMultipleFullscreenEvents(expected_events, queue); |
| 441 } |
| 442 |
| 443 EXPECT_FALSE(browser()->window()->IsFullscreen()); |
| 444 |
| 445 // Verify that the fullscreen styles were removed from the <div> and its |
| 446 // container <iframe>. |
| 447 EXPECT_FALSE(ElementHasFullscreenStyle(child, "fullscreen-div")); |
| 448 EXPECT_FALSE(ElementHasFullscreenStyle(main_frame, "child-0")); |
| 449 EXPECT_FALSE(ElementHasFullscreenAncestorStyle(main_frame, "child-0")); |
| 450 |
| 451 // Check that both frames cleared their document.webkitFullscreenElement. |
| 452 EXPECT_EQ("none", GetFullscreenElementId(main_frame)); |
| 453 EXPECT_EQ("none", GetFullscreenElementId(child)); |
| 454 } |
| 455 |
| 456 // Check that on a page with A-embed-B-embed-A frame hierarchy, an element in |
| 457 // the bottom frame can enter and exit fullscreen. |
| 458 // |
| 459 // TODO(alexmos): For now, the test will verify sizing and fullscreen CSS |
| 460 // styles, but additional refactoring of Blink's Fullscreen class is required |
| 461 // to fully handle fullscreenchange events and webkitFullscreenElement in the |
| 462 // main frame. |
| 463 IN_PROC_BROWSER_TEST_F(SitePerProcessInteractiveBrowserTest, |
| 464 FullscreenElementInABA) { |
| 465 GURL main_url(embedded_test_server()->GetURL( |
| 466 "a.com", "/cross_site_iframe_factory.html?a(b(a))")); |
| 467 ui_test_utils::NavigateToURL(browser(), main_url); |
| 468 content::WebContents* web_contents = |
| 469 browser()->tab_strip_model()->GetActiveWebContents(); |
| 470 |
| 471 content::RenderFrameHost* main_frame = web_contents->GetMainFrame(); |
| 472 content::RenderFrameHost* child = ChildFrameAt(main_frame, 0); |
| 473 content::RenderFrameHost* grandchild = ChildFrameAt(child, 0); |
| 474 |
| 475 // Navigate the bottom frame to a page that has a fullscreenable <div>. |
| 476 content::TestNavigationObserver observer(web_contents); |
| 477 EXPECT_TRUE( |
| 478 ExecuteScript(grandchild, "location.href = '/fullscreen_frame.html'")); |
| 479 observer.Wait(); |
| 480 EXPECT_EQ(embedded_test_server()->GetURL("a.com", "/fullscreen_frame.html"), |
| 481 grandchild->GetLastCommittedURL()); |
| 482 |
| 483 // Add allowFullscreen attribute to both <iframe> elements. |
| 484 SetAllowFullscreenForFrame(main_frame, "child-0"); |
| 485 SetAllowFullscreenForFrame(child, "child-0"); |
| 486 |
| 487 // Make fullscreenchange events in all three frames send a message. |
| 488 AddFullscreenChangeListener(main_frame, "main_frame"); |
| 489 AddFullscreenChangeListener(child, "child"); |
| 490 AddFullscreenChangeListener(grandchild, "grandchild"); |
| 491 |
| 492 // Add a resize event handler that will send a message when the grandchild |
| 493 // frame is resized to the screen size. Also save its original size. |
| 494 AddResizeListener(grandchild, GetScreenSize()); |
| 495 gfx::Size original_grandchild_size = GetFrameSize(grandchild); |
| 496 |
| 497 // Fullscreen a <div> inside the bottom subframe. This will block until |
| 498 // (1) the fullscreenchange events in all frames send a response, and |
| 499 // (2) the frame is resized to fill the whole screen. |
| 500 // |
| 501 // TODO(alexmos): Also wait for "main_frame" once |
| 502 // blink::Fullscreen::requestFullscreen() and exitFullscreen() are fixed to |
| 503 // process all local ancestors. |
| 504 std::set<std::string> expected_events = {"child", "grandchild"}; |
| 505 { |
| 506 content::DOMMessageQueue queue; |
| 507 EXPECT_TRUE(ExecuteScript(grandchild, "activateFullscreen()")); |
| 508 WaitForMultipleFullscreenEvents(expected_events, queue); |
| 509 } |
| 510 |
| 511 // Verify that the browser has entered fullscreen for the current tab. |
| 512 EXPECT_TRUE(browser()->window()->IsFullscreen()); |
| 513 EXPECT_TRUE(browser()->exclusive_access_manager() |
| 514 ->fullscreen_controller() |
| 515 ->IsFullscreenForTabOrPending(web_contents)); |
| 516 |
| 517 // Verify that the <div> has fullscreen style in the bottom frame, and that |
| 518 // the proper <iframe> elements have fullscreen style in its ancestor frames. |
| 519 EXPECT_TRUE(ElementHasFullscreenStyle(grandchild, "fullscreen-div")); |
| 520 EXPECT_TRUE(ElementHasFullscreenStyle(child, "child-0")); |
| 521 EXPECT_TRUE(ElementHasFullscreenAncestorStyle(child, "child-0")); |
| 522 EXPECT_TRUE(ElementHasFullscreenStyle(main_frame, "child-0")); |
| 523 EXPECT_TRUE(ElementHasFullscreenAncestorStyle(main_frame, "child-0")); |
| 524 |
| 525 // Check document.webkitFullscreenElement in all frames. |
| 526 EXPECT_EQ("child-0", GetFullscreenElementId(child)); |
| 527 EXPECT_EQ("fullscreen-div", GetFullscreenElementId(grandchild)); |
| 528 // TODO(alexmos): Also check that |main_frame|'s webkitFullscreenElement is |
| 529 // "child-0" once blink::Fullscreen::requestFullscreen() is fixed to handle |
| 530 // all local ancestors. |
| 531 |
| 532 // Now exit fullscreen from the subframe. |
| 533 AddResizeListener(grandchild, original_grandchild_size); |
| 534 { |
| 535 content::DOMMessageQueue queue; |
| 536 EXPECT_TRUE(ExecuteScript(grandchild, "exitFullscreen()")); |
| 537 WaitForMultipleFullscreenEvents(expected_events, queue); |
| 538 } |
| 539 |
| 540 EXPECT_FALSE(browser()->window()->IsFullscreen()); |
| 541 |
| 542 // Verify that the fullscreen styles were removed from the <div> and its |
| 543 // container <iframe>'s. |
| 544 EXPECT_FALSE(ElementHasFullscreenStyle(grandchild, "fullscreen-div")); |
| 545 EXPECT_FALSE(ElementHasFullscreenStyle(child, "child-0")); |
| 546 EXPECT_FALSE(ElementHasFullscreenAncestorStyle(child, "child-0")); |
| 547 EXPECT_FALSE(ElementHasFullscreenStyle(main_frame, "child-0")); |
| 548 EXPECT_FALSE(ElementHasFullscreenAncestorStyle(main_frame, "child-0")); |
| 549 |
| 550 // Check that document.webkitFullscreenElement was cleared in all three |
| 551 // frames. |
| 552 EXPECT_EQ("none", GetFullscreenElementId(main_frame)); |
| 553 EXPECT_EQ("none", GetFullscreenElementId(child)); |
| 554 EXPECT_EQ("none", GetFullscreenElementId(grandchild)); |
| 555 } |
| 556 |
| 557 // Check that fullscreen works on a more complex page hierarchy with multiple |
| 558 // local and remote ancestors. The test uses this frame tree: |
| 559 // |
| 560 // A (a_top) |
| 561 // | |
| 562 // A (a_bottom) |
| 563 // / \ . |
| 564 // (b_first) B B (b_second) |
| 565 // | |
| 566 // C (c_top) |
| 567 // | |
| 568 // C (c_middle) <- fullscreen target |
| 569 // | |
| 570 // C (c_bottom) |
| 571 // |
| 572 // The c_middle frame will trigger fullscreen for its <div> element. The test |
| 573 // verifies that its ancestor chain is properly updated for fullscreen, and |
| 574 // that the b_first node that's not on the chain is not affected. |
| 575 // |
| 576 // The test also exits fullscreen by simulating pressing ESC rather than using |
| 577 // document.webkitExitFullscreen(), which tests the browser-initiated |
| 578 // fullscreen exit path. |
| 579 IN_PROC_BROWSER_TEST_F(SitePerProcessInteractiveBrowserTest, |
| 580 FullscreenElementInMultipleSubframes) { |
| 581 GURL main_url(embedded_test_server()->GetURL( |
| 582 "a.com", "/cross_site_iframe_factory.html?a(a(b,b(c(c))))")); |
| 583 ui_test_utils::NavigateToURL(browser(), main_url); |
| 584 content::WebContents* web_contents = |
| 585 browser()->tab_strip_model()->GetActiveWebContents(); |
| 586 |
| 587 content::RenderFrameHost* a_top = web_contents->GetMainFrame(); |
| 588 content::RenderFrameHost* a_bottom = ChildFrameAt(a_top, 0); |
| 589 content::RenderFrameHost* b_first = ChildFrameAt(a_bottom, 0); |
| 590 content::RenderFrameHost* b_second = ChildFrameAt(a_bottom, 1); |
| 591 content::RenderFrameHost* c_top = ChildFrameAt(b_second, 0); |
| 592 content::RenderFrameHost* c_middle = ChildFrameAt(c_top, 0); |
| 593 |
| 594 // Allow fullscreen in all iframes descending to |c_middle|. This relies on |
| 595 // IDs that cross_site_iframe_factory assigns to child frames. |
| 596 SetAllowFullscreenForFrame(a_top, "child-0"); |
| 597 SetAllowFullscreenForFrame(a_bottom, "child-1"); |
| 598 SetAllowFullscreenForFrame(b_second, "child-0"); |
| 599 SetAllowFullscreenForFrame(c_top, "child-0"); |
| 600 |
| 601 // Navigate |c_middle| to a page that has a fullscreenable <div> and another |
| 602 // frame. |
| 603 content::TestNavigationObserver observer(web_contents); |
| 604 EXPECT_TRUE( |
| 605 ExecuteScript(c_middle, "location.href = '/fullscreen_frame.html'")); |
| 606 observer.Wait(); |
| 607 EXPECT_EQ(embedded_test_server()->GetURL("c.com", "/fullscreen_frame.html"), |
| 608 c_middle->GetLastCommittedURL()); |
| 609 content::RenderFrameHost* c_bottom = ChildFrameAt(c_middle, 0); |
| 610 |
| 611 // Save the size of the frame to be fullscreened. |
| 612 gfx::Size c_middle_original_size = GetFrameSize(c_middle); |
| 613 |
| 614 // Add fullscreenchange and resize event handlers to all frames. |
| 615 AddFullscreenChangeListener(a_top, "a_top"); |
| 616 AddFullscreenChangeListener(a_bottom, "a_bottom"); |
| 617 AddFullscreenChangeListener(b_first, "b_first"); |
| 618 AddFullscreenChangeListener(b_second, "b_second"); |
| 619 AddFullscreenChangeListener(c_top, "c_top"); |
| 620 AddFullscreenChangeListener(c_middle, "c_middle"); |
| 621 AddFullscreenChangeListener(c_bottom, "c_bottom"); |
| 622 AddResizeListener(c_middle, GetScreenSize()); |
| 623 |
| 624 // Note that expected fullscreenchange events do NOT include |b_first| and |
| 625 // |c_bottom|, which aren't on the ancestor chain of |c_middle|. |
| 626 // WaitForMultipleFullscreenEvents() below will fail if it hears an |
| 627 // unexpected fullscreenchange from one of these frames. |
| 628 std::set<std::string> expected_events = {"a_top", "a_bottom", "b_second", |
| 629 "c_top", "c_middle"}; |
| 630 |
| 631 // Fullscreen a <div> inside |c_middle|. Block until (1) the |
| 632 // fullscreenchange events in |c_middle| and all its ancestors send a |
| 633 // response, and (2) |c_middle| is resized to fill the whole screen. |
| 634 { |
| 635 content::DOMMessageQueue queue; |
| 636 EXPECT_TRUE(ExecuteScript(c_middle, "activateFullscreen()")); |
| 637 WaitForMultipleFullscreenEvents(expected_events, queue); |
| 638 } |
| 639 |
| 640 // Verify that the browser has entered fullscreen for the current tab. |
| 641 EXPECT_TRUE(browser()->window()->IsFullscreen()); |
| 642 EXPECT_TRUE(browser()->exclusive_access_manager() |
| 643 ->fullscreen_controller() |
| 644 ->IsFullscreenForTabOrPending(web_contents)); |
| 645 |
| 646 // Check document.webkitFullscreenElement. It should point to corresponding |
| 647 // <iframe> element IDs on |c_middle|'s ancestor chain, and it should be null |
| 648 // in b_first and c_bottom. |
| 649 EXPECT_EQ("child-0", GetFullscreenElementId(a_top)); |
| 650 EXPECT_EQ("child-1", GetFullscreenElementId(a_bottom)); |
| 651 EXPECT_EQ("child-0", GetFullscreenElementId(b_second)); |
| 652 EXPECT_EQ("child-0", GetFullscreenElementId(c_top)); |
| 653 EXPECT_EQ("fullscreen-div", GetFullscreenElementId(c_middle)); |
| 654 EXPECT_EQ("none", GetFullscreenElementId(b_first)); |
| 655 EXPECT_EQ("none", GetFullscreenElementId(c_bottom)); |
| 656 |
| 657 // Verify that the fullscreen element and all <iframe> elements on its |
| 658 // ancestor chain have fullscreen style, but other frames do not. |
| 659 EXPECT_TRUE(ElementHasFullscreenStyle(a_top, "child-0")); |
| 660 EXPECT_FALSE(ElementHasFullscreenStyle(a_bottom, "child-0")); |
| 661 EXPECT_TRUE(ElementHasFullscreenStyle(a_bottom, "child-1")); |
| 662 EXPECT_TRUE(ElementHasFullscreenStyle(b_second, "child-0")); |
| 663 EXPECT_TRUE(ElementHasFullscreenStyle(c_top, "child-0")); |
| 664 EXPECT_TRUE(ElementHasFullscreenStyle(c_middle, "fullscreen-div")); |
| 665 EXPECT_FALSE(ElementHasFullscreenStyle(c_middle, "child-0")); |
| 666 |
| 667 // Now exit fullscreen by pressing escape. Wait for all fullscreenchange |
| 668 // events fired for fullscreen exit and verify that the bottom frame was |
| 669 // resized back to its original size. |
| 670 AddResizeListener(c_middle, c_middle_original_size); |
| 671 { |
| 672 content::DOMMessageQueue queue; |
| 673 ASSERT_TRUE(ui_test_utils::SendKeyPressSync(browser(), ui::VKEY_ESCAPE, |
| 674 false, false, false, false)); |
| 675 WaitForMultipleFullscreenEvents(expected_events, queue); |
| 676 } |
| 677 |
| 678 EXPECT_FALSE(browser()->window()->IsFullscreen()); |
| 679 |
| 680 // Check that document.webkitFullscreenElement has been cleared in all |
| 681 // frames. |
| 682 EXPECT_EQ("none", GetFullscreenElementId(a_top)); |
| 683 EXPECT_EQ("none", GetFullscreenElementId(a_bottom)); |
| 684 EXPECT_EQ("none", GetFullscreenElementId(b_first)); |
| 685 EXPECT_EQ("none", GetFullscreenElementId(b_second)); |
| 686 EXPECT_EQ("none", GetFullscreenElementId(c_top)); |
| 687 EXPECT_EQ("none", GetFullscreenElementId(c_middle)); |
| 688 EXPECT_EQ("none", GetFullscreenElementId(c_bottom)); |
| 689 |
| 690 // Verify that all fullscreen styles have been cleared. |
| 691 EXPECT_FALSE(ElementHasFullscreenStyle(a_top, "child-0")); |
| 692 EXPECT_FALSE(ElementHasFullscreenStyle(a_bottom, "child-0")); |
| 693 EXPECT_FALSE(ElementHasFullscreenStyle(a_bottom, "child-1")); |
| 694 EXPECT_FALSE(ElementHasFullscreenStyle(b_second, "child-0")); |
| 695 EXPECT_FALSE(ElementHasFullscreenStyle(c_top, "child-0")); |
| 696 EXPECT_FALSE(ElementHasFullscreenStyle(c_middle, "fullscreen-div")); |
| 697 EXPECT_FALSE(ElementHasFullscreenStyle(c_middle, "child-0")); |
| 698 } |
| 699 |
OLD | NEW |