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" | |
7 #include "chrome/browser/ui/browser.h" | 6 #include "chrome/browser/ui/browser.h" |
8 #include "chrome/browser/ui/browser_window.h" | |
9 #include "chrome/browser/ui/tabs/tab_strip_model.h" | 7 #include "chrome/browser/ui/tabs/tab_strip_model.h" |
10 #include "chrome/test/base/in_process_browser_test.h" | 8 #include "chrome/test/base/in_process_browser_test.h" |
11 #include "chrome/test/base/interactive_test_utils.h" | |
12 #include "chrome/test/base/ui_test_utils.h" | 9 #include "chrome/test/base/ui_test_utils.h" |
13 #include "content/public/browser/render_frame_host.h" | 10 #include "content/public/browser/render_frame_host.h" |
14 #include "content/public/browser/render_widget_host_view.h" | |
15 #include "content/public/browser/web_contents.h" | 11 #include "content/public/browser/web_contents.h" |
16 #include "content/public/test/browser_test_utils.h" | 12 #include "content/public/test/browser_test_utils.h" |
17 #include "content/public/test/content_browser_test_utils.h" | 13 #include "content/public/test/content_browser_test_utils.h" |
18 #include "content/public/test/test_navigation_observer.h" | |
19 #include "content/public/test/test_utils.h" | 14 #include "content/public/test/test_utils.h" |
20 #include "net/dns/mock_host_resolver.h" | 15 #include "net/dns/mock_host_resolver.h" |
21 #include "net/test/embedded_test_server/embedded_test_server.h" | 16 #include "net/test/embedded_test_server/embedded_test_server.h" |
22 #include "ui/display/display.h" | |
23 #include "ui/display/screen.h" | |
24 #include "url/gurl.h" | 17 #include "url/gurl.h" |
25 | 18 |
26 class SitePerProcessInteractiveBrowserTest : public InProcessBrowserTest { | 19 class SitePerProcessInteractiveBrowserTest : public InProcessBrowserTest { |
27 public: | 20 public: |
28 SitePerProcessInteractiveBrowserTest() {} | 21 SitePerProcessInteractiveBrowserTest() {} |
29 ~SitePerProcessInteractiveBrowserTest() override {} | 22 ~SitePerProcessInteractiveBrowserTest() override {} |
30 | 23 |
31 void SetUpCommandLine(base::CommandLine* command_line) override { | 24 void SetUpCommandLine(base::CommandLine* command_line) override { |
32 content::IsolateAllSitesForTesting(command_line); | 25 content::IsolateAllSitesForTesting(command_line); |
33 } | 26 } |
34 | 27 |
35 void SetUpOnMainThread() override { | 28 void SetUpOnMainThread() override { |
36 host_resolver()->AddRule("*", "127.0.0.1"); | 29 host_resolver()->AddRule("*", "127.0.0.1"); |
37 | 30 |
38 // Add content/test/data for cross_site_iframe_factory.html | 31 // Add content/test/data for cross_site_iframe_factory.html |
39 embedded_test_server()->ServeFilesFromSourceDirectory("content/test/data"); | 32 embedded_test_server()->ServeFilesFromSourceDirectory("content/test/data"); |
40 | 33 |
41 ASSERT_TRUE(embedded_test_server()->Start()); | 34 ASSERT_TRUE(embedded_test_server()->Start()); |
42 } | 35 } |
43 | 36 |
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 | |
53 private: | 37 private: |
54 DISALLOW_COPY_AND_ASSIGN(SitePerProcessInteractiveBrowserTest); | 38 DISALLOW_COPY_AND_ASSIGN(SitePerProcessInteractiveBrowserTest); |
55 }; | 39 }; |
56 | 40 |
57 // Check that document.hasFocus() works properly with out-of-process iframes. | 41 // Check that document.hasFocus() works properly with out-of-process iframes. |
58 // The test builds a page with four cross-site frames and then focuses them one | 42 // The test builds a page with four cross-site frames and then focuses them one |
59 // by one, checking the value of document.hasFocus() in all frames. For any | 43 // by one, checking the value of document.hasFocus() in all frames. For any |
60 // given focused frame, document.hasFocus() should return true for that frame | 44 // given focused frame, document.hasFocus() should return true for that frame |
61 // and all its ancestor frames. | 45 // and all its ancestor frames. |
62 IN_PROC_BROWSER_TEST_F(SitePerProcessInteractiveBrowserTest, DocumentHasFocus) { | 46 IN_PROC_BROWSER_TEST_F(SitePerProcessInteractiveBrowserTest, DocumentHasFocus) { |
(...skipping 178 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
241 EXPECT_EQ("\"child2-focused-input2\"", press_tab_and_wait_for_message(true)); | 225 EXPECT_EQ("\"child2-focused-input2\"", press_tab_and_wait_for_message(true)); |
242 EXPECT_EQ(child2, web_contents->GetFocusedFrame()); | 226 EXPECT_EQ(child2, web_contents->GetFocusedFrame()); |
243 EXPECT_EQ("\"child2-focused-input1\"", press_tab_and_wait_for_message(true)); | 227 EXPECT_EQ("\"child2-focused-input1\"", press_tab_and_wait_for_message(true)); |
244 EXPECT_EQ("\"child1-focused-input2\"", press_tab_and_wait_for_message(true)); | 228 EXPECT_EQ("\"child1-focused-input2\"", press_tab_and_wait_for_message(true)); |
245 EXPECT_EQ(child1, web_contents->GetFocusedFrame()); | 229 EXPECT_EQ(child1, web_contents->GetFocusedFrame()); |
246 EXPECT_EQ("\"child1-focused-input1\"", press_tab_and_wait_for_message(true)); | 230 EXPECT_EQ("\"child1-focused-input1\"", press_tab_and_wait_for_message(true)); |
247 EXPECT_EQ("\"root-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(main_frame, web_contents->GetFocusedFrame()); | 232 EXPECT_EQ(main_frame, web_contents->GetFocusedFrame()); |
249 } | 233 } |
250 | 234 |
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 |