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