// Copyright 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "base/command_line.h" #include "base/memory/singleton.h" #include "base/run_loop.h" #include "base/strings/string_split.h" #include "base/strings/string_util.h" #include "base/strings/utf_string_conversions.h" #include "base/test/test_timeouts.h" #include "content/browser/browser_plugin/browser_plugin_guest.h" #include "content/browser/browser_plugin/browser_plugin_host_factory.h" #include "content/browser/browser_plugin/test_browser_plugin_embedder.h" #include "content/browser/browser_plugin/test_browser_plugin_guest.h" #include "content/browser/browser_plugin/test_browser_plugin_guest_manager.h" #include "content/browser/child_process_security_policy_impl.h" #include "content/browser/renderer_host/render_view_host_impl.h" #include "content/browser/web_contents/web_contents_impl.h" #include "content/common/view_messages.h" #include "content/public/browser/notification_service.h" #include "content/public/browser/notification_types.h" #include "content/public/browser/render_view_host_observer.h" #include "content/public/browser/render_widget_host_view.h" #include "content/public/common/content_switches.h" #include "content/public/common/drop_data.h" #include "content/public/test/browser_test_utils.h" #include "content/public/test/test_utils.h" #include "content/shell/shell.h" #include "content/test/content_browser_test.h" #include "content/test/content_browser_test_utils.h" #include "net/base/net_util.h" #include "net/test/embedded_test_server/embedded_test_server.h" #include "net/test/embedded_test_server/http_request.h" #include "net/test/embedded_test_server/http_response.h" #include "net/test/spawned_test_server/spawned_test_server.h" #include "third_party/WebKit/public/web/WebInputEvent.h" using WebKit::WebInputEvent; using WebKit::WebMouseEvent; using content::BrowserPluginEmbedder; using content::BrowserPluginGuest; using content::BrowserPluginHostFactory; using content::WebContentsImpl; namespace { const char kHTMLForGuest[] = "data:text/html,hello world"; const char kHTMLForGuestBusyLoop[] = "data:text/html,"; const char kHTMLForGuestTouchHandler[] = "data:text/html,
With touch
" ""; const char kHTMLForGuestWithTitle[] = "data:text/html," "%s" "hello world" ""; const char kHTMLForGuestAcceptDrag[] = "data:text/html," "" "" ""; const char kHTMLForGuestWithSize[] = "data:text/html," "" "" "" "" ""; std::string GetHTMLForGuestWithTitle(const std::string& title) { return base::StringPrintf(kHTMLForGuestWithTitle, title.c_str()); } } // namespace namespace content { // Test factory for creating test instances of BrowserPluginEmbedder and // BrowserPluginGuest. class TestBrowserPluginHostFactory : public BrowserPluginHostFactory { public: virtual BrowserPluginGuestManager* CreateBrowserPluginGuestManager() OVERRIDE { guest_manager_instance_count_++; if (message_loop_runner_.get()) message_loop_runner_->Quit(); return new TestBrowserPluginGuestManager(); } virtual BrowserPluginGuest* CreateBrowserPluginGuest( int instance_id, WebContentsImpl* web_contents) OVERRIDE { return new TestBrowserPluginGuest(instance_id, web_contents); } // Also keeps track of number of instances created. virtual BrowserPluginEmbedder* CreateBrowserPluginEmbedder( WebContentsImpl* web_contents) OVERRIDE { return new TestBrowserPluginEmbedder(web_contents); } // Singleton getter. static TestBrowserPluginHostFactory* GetInstance() { return Singleton::get(); } // Waits for at least one embedder to be created in the test. Returns true if // we have a guest, false if waiting times out. void WaitForGuestManagerCreation() { // Check if already have created an instance. if (guest_manager_instance_count_ > 0) return; // Wait otherwise. message_loop_runner_ = new MessageLoopRunner(); message_loop_runner_->Run(); } protected: TestBrowserPluginHostFactory() : guest_manager_instance_count_(0) {} virtual ~TestBrowserPluginHostFactory() {} private: // For Singleton. friend struct DefaultSingletonTraits; scoped_refptr message_loop_runner_; int guest_manager_instance_count_; DISALLOW_COPY_AND_ASSIGN(TestBrowserPluginHostFactory); }; // Test factory class for browser plugin that creates guests with short hang // timeout. class TestShortHangTimeoutGuestFactory : public TestBrowserPluginHostFactory { public: virtual BrowserPluginGuest* CreateBrowserPluginGuest( int instance_id, WebContentsImpl* web_contents) OVERRIDE { BrowserPluginGuest* guest = new TestBrowserPluginGuest(instance_id, web_contents); guest->set_guest_hang_timeout_for_testing(TestTimeouts::tiny_timeout()); return guest; } // Singleton getter. static TestShortHangTimeoutGuestFactory* GetInstance() { return Singleton::get(); } protected: TestShortHangTimeoutGuestFactory() {} virtual ~TestShortHangTimeoutGuestFactory() {} private: // For Singleton. friend struct DefaultSingletonTraits; DISALLOW_COPY_AND_ASSIGN(TestShortHangTimeoutGuestFactory); }; // A transparent observer that can be used to verify that a RenderViewHost // received a specific message. class RenderViewHostMessageObserver : public RenderViewHostObserver { public: RenderViewHostMessageObserver(RenderViewHost* host, uint32 message_id) : RenderViewHostObserver(host), message_id_(message_id), message_received_(false) { } virtual ~RenderViewHostMessageObserver() {} void WaitUntilMessageReceived() { if (message_received_) return; message_loop_runner_ = new MessageLoopRunner(); message_loop_runner_->Run(); } void ResetState() { message_received_ = false; } // IPC::Listener implementation. virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE { if (message.type() == message_id_) { message_received_ = true; if (message_loop_runner_.get()) message_loop_runner_->Quit(); } return false; } private: scoped_refptr message_loop_runner_; uint32 message_id_; bool message_received_; DISALLOW_COPY_AND_ASSIGN(RenderViewHostMessageObserver); }; class BrowserPluginHostTest : public ContentBrowserTest { public: BrowserPluginHostTest() : test_embedder_(NULL), test_guest_(NULL), test_guest_manager_(NULL) {} virtual void SetUp() OVERRIDE { // Override factory to create tests instances of BrowserPlugin*. content::BrowserPluginEmbedder::set_factory_for_testing( TestBrowserPluginHostFactory::GetInstance()); content::BrowserPluginGuest::set_factory_for_testing( TestBrowserPluginHostFactory::GetInstance()); content::BrowserPluginGuestManager::set_factory_for_testing( TestBrowserPluginHostFactory::GetInstance()); // On legacy windows, the AcceptDragEvents test needs this to pass. #if defined(OS_WIN) && !defined(USE_AURA) UseRealGLBindings(); #endif ContentBrowserTest::SetUp(); } virtual void TearDown() OVERRIDE { content::BrowserPluginEmbedder::set_factory_for_testing(NULL); content::BrowserPluginGuest::set_factory_for_testing(NULL); ContentBrowserTest::TearDown(); } virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE { // Enable browser plugin in content_shell for running test. command_line->AppendSwitch(switches::kEnableBrowserPluginForAllViewTypes); } static void SimulateSpaceKeyPress(WebContents* web_contents) { SimulateKeyPress(web_contents, ui::VKEY_SPACE, false, // control. false, // shift. false, // alt. false); // command. } static void SimulateTabKeyPress(WebContents* web_contents) { SimulateKeyPress(web_contents, ui::VKEY_TAB, false, // control. false, // shift. false, // alt. false); // command. } // Executes the javascript synchronously and makes sure the returned value is // freed properly. void ExecuteSyncJSFunction(RenderViewHost* rvh, const std::string& jscript) { scoped_ptr value = content::ExecuteScriptAndGetValue(rvh, jscript); } bool IsAttributeNull(RenderViewHost* rvh, const std::string& attribute) { scoped_ptr value = content::ExecuteScriptAndGetValue(rvh, "document.getElementById('plugin').getAttribute('" + attribute + "');"); return value->GetType() == Value::TYPE_NULL; } // Removes all attributes in the comma-delimited string |attributes|. void RemoveAttributes(RenderViewHost* rvh, const std::string& attributes) { std::vector attributes_list; base::SplitString(attributes, ',', &attributes_list); std::vector::const_iterator itr; for (itr = attributes_list.begin(); itr != attributes_list.end(); ++itr) { ExecuteSyncJSFunction(rvh, "document.getElementById('plugin')" "." + *itr + " = null;"); } } // This helper method does the following: // 1. Start the test server and navigate the shell to |embedder_url|. // 2. Execute custom pre-navigation |embedder_code| if provided. // 3. Navigate the guest to the |guest_url|. // 4. Verify that the guest has been created and has completed loading. void StartBrowserPluginTest(const std::string& embedder_url, const std::string& guest_url, bool is_guest_data_url, const std::string& embedder_code) { ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady()); GURL test_url(embedded_test_server()->GetURL(embedder_url)); NavigateToURL(shell(), test_url); WebContentsImpl* embedder_web_contents = static_cast( shell()->web_contents()); RenderViewHostImpl* rvh = static_cast( embedder_web_contents->GetRenderViewHost()); // Focus the embedder. rvh->Focus(); // Activative IME. rvh->SetInputMethodActive(true); // Allow the test to do some operations on the embedder before we perform // the first navigation of the guest. if (!embedder_code.empty()) ExecuteSyncJSFunction(rvh, embedder_code); if (!is_guest_data_url) { test_url = embedded_test_server()->GetURL(guest_url); ExecuteSyncJSFunction( rvh, base::StringPrintf("SetSrc('%s');", test_url.spec().c_str())); } else { ExecuteSyncJSFunction( rvh, base::StringPrintf("SetSrc('%s');", guest_url.c_str())); } // Wait to make sure embedder is created/attached to WebContents. TestBrowserPluginHostFactory::GetInstance()->WaitForGuestManagerCreation(); test_embedder_ = static_cast( embedder_web_contents->GetBrowserPluginEmbedder()); ASSERT_TRUE(test_embedder_); test_guest_manager_ = static_cast( embedder_web_contents->GetBrowserPluginGuestManager()); ASSERT_TRUE(test_guest_manager_); test_guest_manager_->WaitForGuestAdded(); // Verify that we have exactly one guest. const TestBrowserPluginGuestManager::GuestInstanceMap& instance_map = test_guest_manager_->guest_web_contents_for_testing(); EXPECT_EQ(1u, instance_map.size()); WebContentsImpl* test_guest_web_contents = static_cast( instance_map.begin()->second); test_guest_ = static_cast( test_guest_web_contents->GetBrowserPluginGuest()); test_guest_->WaitForLoadStop(); } TestBrowserPluginEmbedder* test_embedder() const { return test_embedder_; } TestBrowserPluginGuest* test_guest() const { return test_guest_; } TestBrowserPluginGuestManager* test_guest_manager() const { return test_guest_manager_; } private: TestBrowserPluginEmbedder* test_embedder_; TestBrowserPluginGuest* test_guest_; TestBrowserPluginGuestManager* test_guest_manager_; DISALLOW_COPY_AND_ASSIGN(BrowserPluginHostTest); }; // This test ensures that if guest isn't there and we resize the guest (from // js), it remembers the size correctly. // // Initially we load an embedder with a guest without a src attribute (which has // dimension 640x480), resize it to 100x200, and then we set the source to a // sample guest. In the end we verify that the correct size has been set. IN_PROC_BROWSER_TEST_F(BrowserPluginHostTest, NavigateAfterResize) { const gfx::Size nxt_size = gfx::Size(100, 200); const std::string embedder_code = base::StringPrintf( "SetSize(%d, %d);", nxt_size.width(), nxt_size.height()); const char kEmbedderURL[] = "/browser_plugin_embedder.html"; StartBrowserPluginTest(kEmbedderURL, kHTMLForGuest, true, embedder_code); // Wait for the guest to receive a damage buffer of size 100x200. // This means the guest will be painted properly at that size. test_guest()->WaitForDamageBufferWithSize(nxt_size); } IN_PROC_BROWSER_TEST_F(BrowserPluginHostTest, AdvanceFocus) { const char kEmbedderURL[] = "/browser_plugin_focus.html"; const char* kGuestURL = "/browser_plugin_focus_child.html"; StartBrowserPluginTest(kEmbedderURL, kGuestURL, false, std::string()); SimulateMouseClick(test_embedder()->web_contents(), 0, WebKit::WebMouseEvent::ButtonLeft); BrowserPluginHostTest::SimulateTabKeyPress(test_embedder()->web_contents()); // Wait until we focus into the guest. test_guest()->WaitForFocus(); // TODO(fsamuel): A third Tab key press should not be necessary. // The browser plugin will take keyboard focus but it will not // focus an initial element. The initial element is dependent // upon tab direction which WebKit does not propagate to the plugin. // See http://crbug.com/147644. BrowserPluginHostTest::SimulateTabKeyPress(test_embedder()->web_contents()); BrowserPluginHostTest::SimulateTabKeyPress(test_embedder()->web_contents()); BrowserPluginHostTest::SimulateTabKeyPress(test_embedder()->web_contents()); test_guest()->WaitForAdvanceFocus(); } // This test opens a page in http and then opens another page in https, forcing // a RenderViewHost swap in the web_contents. We verify that the embedder in the // web_contents gets cleared properly. IN_PROC_BROWSER_TEST_F(BrowserPluginHostTest, EmbedderChangedAfterSwap) { net::SpawnedTestServer https_server( net::SpawnedTestServer::TYPE_HTTPS, net::SpawnedTestServer::kLocalhost, base::FilePath(FILE_PATH_LITERAL("content/test/data"))); ASSERT_TRUE(https_server.Start()); // 1. Load an embedder page with one guest in it. const char kEmbedderURL[] = "/browser_plugin_embedder.html"; StartBrowserPluginTest(kEmbedderURL, kHTMLForGuest, true, std::string()); // 2. Navigate to a URL in https, so we trigger a RenderViewHost swap. GURL test_https_url(https_server.GetURL( "files/browser_plugin_title_change.html")); content::WindowedNotificationObserver swap_observer( content::NOTIFICATION_WEB_CONTENTS_SWAPPED, content::Source(test_embedder()->web_contents())); NavigateToURL(shell(), test_https_url); swap_observer.Wait(); TestBrowserPluginEmbedder* test_embedder_after_swap = static_cast( static_cast(shell()->web_contents())-> GetBrowserPluginEmbedder()); // Verify we have a no embedder in web_contents (since the new page doesn't // have any browser plugin). ASSERT_TRUE(!test_embedder_after_swap); ASSERT_NE(test_embedder(), test_embedder_after_swap); } // This test opens two pages in http and there is no RenderViewHost swap, // therefore the embedder created on first page navigation stays the same in // web_contents. IN_PROC_BROWSER_TEST_F(BrowserPluginHostTest, EmbedderSameAfterNav) { const char kEmbedderURL[] = "/browser_plugin_embedder.html"; StartBrowserPluginTest(kEmbedderURL, kHTMLForGuest, true, std::string()); WebContentsImpl* embedder_web_contents = test_embedder()->web_contents(); // Navigate to another page in same host and port, so RenderViewHost swap // does not happen and existing embedder doesn't change in web_contents. GURL test_url_new(embedded_test_server()->GetURL( "/browser_plugin_title_change.html")); const string16 expected_title = ASCIIToUTF16("done"); content::TitleWatcher title_watcher(shell()->web_contents(), expected_title); NavigateToURL(shell(), test_url_new); LOG(INFO) << "Start waiting for title"; string16 actual_title = title_watcher.WaitAndGetTitle(); EXPECT_EQ(expected_title, actual_title); LOG(INFO) << "Done navigating to second page"; TestBrowserPluginEmbedder* test_embedder_after_nav = static_cast( embedder_web_contents->GetBrowserPluginEmbedder()); // Embedder must not change in web_contents. ASSERT_EQ(test_embedder_after_nav, test_embedder()); } // This test verifies that hiding the embedder also hides the guest. IN_PROC_BROWSER_TEST_F(BrowserPluginHostTest, BrowserPluginVisibilityChanged) { const char kEmbedderURL[] = "/browser_plugin_embedder.html"; StartBrowserPluginTest(kEmbedderURL, kHTMLForGuest, true, std::string()); // Hide the Browser Plugin. RenderViewHostImpl* rvh = static_cast( test_embedder()->web_contents()->GetRenderViewHost()); ExecuteSyncJSFunction( rvh, "document.getElementById('plugin').style.visibility = 'hidden'"); // Make sure that the guest is hidden. test_guest()->WaitUntilHidden(); } IN_PROC_BROWSER_TEST_F(BrowserPluginHostTest, EmbedderVisibilityChanged) { const char kEmbedderURL[] = "/browser_plugin_embedder.html"; StartBrowserPluginTest(kEmbedderURL, kHTMLForGuest, true, std::string()); // Hide the embedder. test_embedder()->web_contents()->WasHidden(); // Make sure that hiding the embedder also hides the guest. test_guest()->WaitUntilHidden(); } // Verifies that installing/uninstalling touch-event handlers in the guest // plugin correctly updates the touch-event handling state in the embedder. IN_PROC_BROWSER_TEST_F(BrowserPluginHostTest, AcceptTouchEvents) { const char kEmbedderURL[] = "/browser_plugin_embedder.html"; StartBrowserPluginTest( kEmbedderURL, kHTMLForGuestTouchHandler, true, std::string()); RenderViewHostImpl* rvh = static_cast( test_embedder()->web_contents()->GetRenderViewHost()); // The embedder should not have any touch event handlers at this point. EXPECT_FALSE(rvh->has_touch_handler()); // Install the touch handler in the guest. This should cause the embedder to // start listening for touch events too. RenderViewHostMessageObserver observer(rvh, ViewHostMsg_HasTouchEventHandlers::ID); ExecuteSyncJSFunction(test_guest()->web_contents()->GetRenderViewHost(), "InstallTouchHandler();"); observer.WaitUntilMessageReceived(); EXPECT_TRUE(rvh->has_touch_handler()); // Uninstalling the touch-handler in guest should cause the embedder to stop // listening for touch events. observer.ResetState(); ExecuteSyncJSFunction(test_guest()->web_contents()->GetRenderViewHost(), "UninstallTouchHandler();"); observer.WaitUntilMessageReceived(); EXPECT_FALSE(rvh->has_touch_handler()); } // This tests verifies that reloading the embedder does not crash the browser // and that the guest is reset. IN_PROC_BROWSER_TEST_F(BrowserPluginHostTest, ReloadEmbedder) { const char kEmbedderURL[] = "/browser_plugin_embedder.html"; StartBrowserPluginTest(kEmbedderURL, kHTMLForGuest, true, std::string()); RenderViewHostImpl* rvh = static_cast( test_embedder()->web_contents()->GetRenderViewHost()); // Change the title of the page to 'modified' so that we know that // the page has successfully reloaded when it goes back to 'embedder' // in the next step. { const string16 expected_title = ASCIIToUTF16("modified"); content::TitleWatcher title_watcher(test_embedder()->web_contents(), expected_title); ExecuteSyncJSFunction(rvh, base::StringPrintf("SetTitle('%s');", "modified")); string16 actual_title = title_watcher.WaitAndGetTitle(); EXPECT_EQ(expected_title, actual_title); } // Reload the embedder page, and verify that the reload was successful. // Then navigate the guest to verify that the browser process does not crash. { const string16 expected_title = ASCIIToUTF16("embedder"); content::TitleWatcher title_watcher(test_embedder()->web_contents(), expected_title); test_embedder()->web_contents()->GetController().Reload(false); string16 actual_title = title_watcher.WaitAndGetTitle(); EXPECT_EQ(expected_title, actual_title); ExecuteSyncJSFunction( test_embedder()->web_contents()->GetRenderViewHost(), base::StringPrintf("SetSrc('%s');", kHTMLForGuest)); test_guest_manager()->WaitForGuestAdded(); const TestBrowserPluginGuestManager::GuestInstanceMap& instance_map = test_guest_manager()->guest_web_contents_for_testing(); WebContentsImpl* test_guest_web_contents = static_cast( instance_map.begin()->second); TestBrowserPluginGuest* new_test_guest = static_cast( test_guest_web_contents->GetBrowserPluginGuest()); ASSERT_TRUE(new_test_guest != NULL); // Wait for the guest to send an UpdateRectMsg, meaning it is ready. new_test_guest->WaitForUpdateRectMsg(); } } // Always failing in the win7_aura try bot. See http://crbug.com/181107. #if defined(OS_WIN) && defined(USE_AURA) #define MAYBE_AcceptDragEvents DISABLED_AcceptDragEvents #else #define MAYBE_AcceptDragEvents AcceptDragEvents #endif // Tests that a drag-n-drop over the browser plugin in the embedder happens // correctly. IN_PROC_BROWSER_TEST_F(BrowserPluginHostTest, MAYBE_AcceptDragEvents) { const char kEmbedderURL[] = "/browser_plugin_dragging.html"; StartBrowserPluginTest( kEmbedderURL, kHTMLForGuestAcceptDrag, true, std::string()); RenderViewHostImpl* rvh = static_cast( test_embedder()->web_contents()->GetRenderViewHost()); // Get a location in the embedder outside of the plugin. base::ListValue *start, *end; scoped_ptr value = content::ExecuteScriptAndGetValue(rvh, "dragLocation()"); ASSERT_TRUE(value->GetAsList(&start) && start->GetSize() == 2); double start_x, start_y; ASSERT_TRUE(start->GetDouble(0, &start_x) && start->GetDouble(1, &start_y)); // Get a location in the embedder that falls inside the plugin. value = content::ExecuteScriptAndGetValue(rvh, "dropLocation()"); ASSERT_TRUE(value->GetAsList(&end) && end->GetSize() == 2); double end_x, end_y; ASSERT_TRUE(end->GetDouble(0, &end_x) && end->GetDouble(1, &end_y)); DropData drop_data; GURL url = GURL("https://www.domain.com/index.html"); drop_data.url = url; // Pretend that the URL is being dragged over the embedder. Start the drag // from outside the plugin, then move the drag inside the plugin and drop. // This should trigger appropriate messages from the embedder to the guest, // and end with a drop on the guest. The guest changes title when a drop // happens. const string16 expected_title = ASCIIToUTF16("DROPPED"); content::TitleWatcher title_watcher(test_guest()->web_contents(), expected_title); rvh->DragTargetDragEnter(drop_data, gfx::Point(start_x, start_y), gfx::Point(start_x, start_y), WebKit::WebDragOperationEvery, 0); rvh->DragTargetDragOver(gfx::Point(end_x, end_y), gfx::Point(end_x, end_y), WebKit::WebDragOperationEvery, 0); rvh->DragTargetDrop(gfx::Point(end_x, end_y), gfx::Point(end_x, end_y), 0); string16 actual_title = title_watcher.WaitAndGetTitle(); EXPECT_EQ(expected_title, actual_title); } // This test verifies that round trip postMessage works as expected. // 1. The embedder posts a message 'testing123' to the guest. // 2. The guest receives and replies to the message using the event object's // source object: event.source.postMessage('foobar', '*') // 3. The embedder receives the message and uses the event's source // object to do one final reply: 'stop' // 4. The guest receives the final 'stop' message. // 5. The guest acks the 'stop' message with a 'stop_ack' message. // 6. The embedder changes its title to 'main guest' when it sees the 'stop_ack' // message. IN_PROC_BROWSER_TEST_F(BrowserPluginHostTest, PostMessage) { const char* kTesting = "testing123"; const char* kEmbedderURL = "/browser_plugin_embedder.html"; const char* kGuestURL = "/browser_plugin_post_message_guest.html"; StartBrowserPluginTest(kEmbedderURL, kGuestURL, false, std::string()); RenderViewHostImpl* rvh = static_cast( test_embedder()->web_contents()->GetRenderViewHost()); { const string16 expected_title = ASCIIToUTF16("main guest"); content::TitleWatcher title_watcher(test_embedder()->web_contents(), expected_title); // By the time we get here 'contentWindow' should be ready because the // guest has completed loading. ExecuteSyncJSFunction( rvh, base::StringPrintf("PostMessage('%s, false');", kTesting)); // The title will be updated to "main guest" at the last stage of the // process described above. string16 actual_title = title_watcher.WaitAndGetTitle(); EXPECT_EQ(expected_title, actual_title); } } // This is the same as BrowserPluginHostTest.PostMessage but also // posts a message to an iframe. // TODO(fsamuel): This test should replace the previous test once postMessage // iframe targeting is fixed (see http://crbug.com/153701). IN_PROC_BROWSER_TEST_F(BrowserPluginHostTest, DISABLED_PostMessageToIFrame) { const char* kTesting = "testing123"; const char* kEmbedderURL = "/browser_plugin_embedder.html"; const char* kGuestURL = "/browser_plugin_post_message_guest.html"; StartBrowserPluginTest(kEmbedderURL, kGuestURL, false, std::string()); RenderViewHostImpl* rvh = static_cast( test_embedder()->web_contents()->GetRenderViewHost()); { const string16 expected_title = ASCIIToUTF16("main guest"); content::TitleWatcher title_watcher(test_embedder()->web_contents(), expected_title); ExecuteSyncJSFunction( rvh, base::StringPrintf("PostMessage('%s, false');", kTesting)); // The title will be updated to "main guest" at the last stage of the // process described above. string16 actual_title = title_watcher.WaitAndGetTitle(); EXPECT_EQ(expected_title, actual_title); } { content::TitleWatcher ready_watcher(test_embedder()->web_contents(), ASCIIToUTF16("ready")); RenderViewHostImpl* guest_rvh = static_cast( test_guest()->web_contents()->GetRenderViewHost()); GURL test_url = embedded_test_server()->GetURL( "/browser_plugin_post_message_guest.html"); ExecuteSyncJSFunction( guest_rvh, base::StringPrintf( "CreateChildFrame('%s');", test_url.spec().c_str())); string16 actual_title = ready_watcher.WaitAndGetTitle(); EXPECT_EQ(ASCIIToUTF16("ready"), actual_title); content::TitleWatcher iframe_watcher(test_embedder()->web_contents(), ASCIIToUTF16("iframe")); ExecuteSyncJSFunction( rvh, base::StringPrintf("PostMessage('%s', true);", kTesting)); // The title will be updated to "iframe" at the last stage of the // process described above. actual_title = iframe_watcher.WaitAndGetTitle(); EXPECT_EQ(ASCIIToUTF16("iframe"), actual_title); } } // This test verifies that if a browser plugin is hidden before navigation, // the guest starts off hidden. IN_PROC_BROWSER_TEST_F(BrowserPluginHostTest, HiddenBeforeNavigation) { const char* kEmbedderURL = "/browser_plugin_embedder.html"; const std::string embedder_code = "document.getElementById('plugin').style.visibility = 'hidden'"; StartBrowserPluginTest( kEmbedderURL, kHTMLForGuest, true, embedder_code); EXPECT_FALSE(test_guest()->visible()); } // This test verifies that if a browser plugin is focused before navigation then // the guest starts off focused. IN_PROC_BROWSER_TEST_F(BrowserPluginHostTest, FocusBeforeNavigation) { const char* kEmbedderURL = "/browser_plugin_embedder.html"; const std::string embedder_code = "document.getElementById('plugin').focus();"; StartBrowserPluginTest( kEmbedderURL, kHTMLForGuest, true, embedder_code); RenderViewHostImpl* guest_rvh = static_cast( test_guest()->web_contents()->GetRenderViewHost()); // Verify that the guest is focused. scoped_ptr value = content::ExecuteScriptAndGetValue(guest_rvh, "document.hasFocus()"); bool result = false; ASSERT_TRUE(value->GetAsBoolean(&result)); EXPECT_TRUE(result); } IN_PROC_BROWSER_TEST_F(BrowserPluginHostTest, FocusTracksEmbedder) { const char* kEmbedderURL = "/browser_plugin_embedder.html"; StartBrowserPluginTest(kEmbedderURL, kHTMLForGuest, true, std::string()); RenderViewHostImpl* rvh = static_cast( test_embedder()->web_contents()->GetRenderViewHost()); RenderViewHostImpl* guest_rvh = static_cast( test_guest()->web_contents()->GetRenderViewHost()); { // Focus the BrowserPlugin. This will have the effect of also focusing the // current guest. ExecuteSyncJSFunction(rvh, "document.getElementById('plugin').focus();"); // Verify that key presses go to the guest. SimulateSpaceKeyPress(test_embedder()->web_contents()); test_guest()->WaitForInput(); // Verify that the guest is focused. scoped_ptr value = content::ExecuteScriptAndGetValue(guest_rvh, "document.hasFocus()"); bool result = false; ASSERT_TRUE(value->GetAsBoolean(&result)); EXPECT_TRUE(result); } // Blur the embedder. test_embedder()->web_contents()->GetRenderViewHost()->Blur(); test_guest()->WaitForBlur(); } // Test for regression http://crbug.com/162961. IN_PROC_BROWSER_TEST_F(BrowserPluginHostTest, GetRenderViewHostAtPositionTest) { const char kEmbedderURL[] = "/browser_plugin_embedder.html"; const std::string embedder_code = base::StringPrintf("SetSize(%d, %d);", 100, 100); StartBrowserPluginTest(kEmbedderURL, kHTMLForGuestWithSize, true, embedder_code); // Check for render view host at position (150, 150) that is outside the // bounds of our guest, so this would respond with the render view host of the // embedder. test_embedder()->WaitForRenderViewHostAtPosition(150, 150); ASSERT_EQ(test_embedder()->web_contents()->GetRenderViewHost(), test_embedder()->last_rvh_at_position_response()); } // This test verifies that if IME is enabled in the embedder, it is also enabled // in the guest. IN_PROC_BROWSER_TEST_F(BrowserPluginHostTest, VerifyInputMethodActive) { const char* kEmbedderURL = "/browser_plugin_embedder.html"; StartBrowserPluginTest(kEmbedderURL, kHTMLForGuest, true, std::string()); RenderViewHostImpl* rvh = static_cast( test_guest()->web_contents()->GetRenderViewHost()); EXPECT_TRUE(rvh->input_method_active()); } } // namespace content