Home | History | Annotate | Download | only in browser_plugin
      1 // Copyright 2012 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "base/command_line.h"
      6 #include "base/memory/singleton.h"
      7 #include "base/run_loop.h"
      8 #include "base/strings/string_split.h"
      9 #include "base/strings/string_util.h"
     10 #include "base/strings/utf_string_conversions.h"
     11 #include "base/test/test_timeouts.h"
     12 #include "content/browser/browser_plugin/browser_plugin_guest.h"
     13 #include "content/browser/browser_plugin/browser_plugin_host_factory.h"
     14 #include "content/browser/browser_plugin/test_browser_plugin_embedder.h"
     15 #include "content/browser/browser_plugin/test_browser_plugin_guest.h"
     16 #include "content/browser/browser_plugin/test_browser_plugin_guest_manager.h"
     17 #include "content/browser/child_process_security_policy_impl.h"
     18 #include "content/browser/renderer_host/render_view_host_impl.h"
     19 #include "content/browser/web_contents/web_contents_impl.h"
     20 #include "content/common/view_messages.h"
     21 #include "content/public/browser/notification_service.h"
     22 #include "content/public/browser/notification_types.h"
     23 #include "content/public/browser/render_view_host_observer.h"
     24 #include "content/public/browser/render_widget_host_view.h"
     25 #include "content/public/common/content_switches.h"
     26 #include "content/public/common/drop_data.h"
     27 #include "content/public/test/browser_test_utils.h"
     28 #include "content/public/test/test_utils.h"
     29 #include "content/shell/shell.h"
     30 #include "content/test/content_browser_test.h"
     31 #include "content/test/content_browser_test_utils.h"
     32 #include "net/base/net_util.h"
     33 #include "net/test/embedded_test_server/embedded_test_server.h"
     34 #include "net/test/embedded_test_server/http_request.h"
     35 #include "net/test/embedded_test_server/http_response.h"
     36 #include "net/test/spawned_test_server/spawned_test_server.h"
     37 #include "third_party/WebKit/public/web/WebInputEvent.h"
     38 
     39 using WebKit::WebInputEvent;
     40 using WebKit::WebMouseEvent;
     41 using content::BrowserPluginEmbedder;
     42 using content::BrowserPluginGuest;
     43 using content::BrowserPluginHostFactory;
     44 using content::WebContentsImpl;
     45 
     46 namespace {
     47 
     48 const char kHTMLForGuest[] =
     49     "data:text/html,<html><body>hello world</body></html>";
     50 const char kHTMLForGuestBusyLoop[] =
     51     "data:text/html,<html><head><script type=\"text/javascript\">"
     52     "function PauseMs(timems) {"
     53     "  document.title = \"start\";"
     54     "  var date = new Date();"
     55     "  var currDate = null;"
     56     "  do {"
     57     "    currDate = new Date();"
     58     "  } while (currDate - date < timems)"
     59     "}"
     60     "function StartPauseMs(timems) {"
     61     "  setTimeout(function() { PauseMs(timems); }, 0);"
     62     "}"
     63     "</script></head><body></body></html>";
     64 const char kHTMLForGuestTouchHandler[] =
     65     "data:text/html,<html><body><div id=\"touch\">With touch</div></body>"
     66     "<script type=\"text/javascript\">"
     67     "function handler() {}"
     68     "function InstallTouchHandler() { "
     69     "  document.getElementById(\"touch\").addEventListener(\"touchstart\", "
     70     "     handler);"
     71     "}"
     72     "function UninstallTouchHandler() { "
     73     "  document.getElementById(\"touch\").removeEventListener(\"touchstart\", "
     74     "     handler);"
     75     "}"
     76     "</script></html>";
     77 const char kHTMLForGuestWithTitle[] =
     78     "data:text/html,"
     79     "<html><head><title>%s</title></head>"
     80     "<body>hello world</body>"
     81     "</html>";
     82 const char kHTMLForGuestAcceptDrag[] =
     83     "data:text/html,<html><body>"
     84     "<script>"
     85     "function dropped() {"
     86     "  document.title = \"DROPPED\";"
     87     "}"
     88     "</script>"
     89     "<textarea id=\"text\" style=\"width:100%; height: 100%\""
     90     "    ondrop=\"dropped();\">"
     91     "</textarea>"
     92     "</body></html>";
     93 const char kHTMLForGuestWithSize[] =
     94     "data:text/html,"
     95     "<html>"
     96     "<body style=\"margin: 0px;\">"
     97     "<img style=\"width: 100%; height: 400px;\"/>"
     98     "</body>"
     99     "</html>";
    100 
    101 std::string GetHTMLForGuestWithTitle(const std::string& title) {
    102   return base::StringPrintf(kHTMLForGuestWithTitle, title.c_str());
    103 }
    104 
    105 }  // namespace
    106 
    107 namespace content {
    108 
    109 // Test factory for creating test instances of BrowserPluginEmbedder and
    110 // BrowserPluginGuest.
    111 class TestBrowserPluginHostFactory : public BrowserPluginHostFactory {
    112  public:
    113   virtual BrowserPluginGuestManager*
    114       CreateBrowserPluginGuestManager() OVERRIDE {
    115     guest_manager_instance_count_++;
    116     if (message_loop_runner_.get())
    117       message_loop_runner_->Quit();
    118     return new TestBrowserPluginGuestManager();
    119   }
    120 
    121   virtual BrowserPluginGuest* CreateBrowserPluginGuest(
    122       int instance_id,
    123       WebContentsImpl* web_contents) OVERRIDE {
    124     return new TestBrowserPluginGuest(instance_id, web_contents);
    125   }
    126 
    127   // Also keeps track of number of instances created.
    128   virtual BrowserPluginEmbedder* CreateBrowserPluginEmbedder(
    129       WebContentsImpl* web_contents) OVERRIDE {
    130 
    131     return new TestBrowserPluginEmbedder(web_contents);
    132   }
    133 
    134   // Singleton getter.
    135   static TestBrowserPluginHostFactory* GetInstance() {
    136     return Singleton<TestBrowserPluginHostFactory>::get();
    137   }
    138 
    139   // Waits for at least one embedder to be created in the test. Returns true if
    140   // we have a guest, false if waiting times out.
    141   void WaitForGuestManagerCreation() {
    142     // Check if already have created an instance.
    143     if (guest_manager_instance_count_ > 0)
    144       return;
    145     // Wait otherwise.
    146     message_loop_runner_ = new MessageLoopRunner();
    147     message_loop_runner_->Run();
    148   }
    149 
    150  protected:
    151   TestBrowserPluginHostFactory() : guest_manager_instance_count_(0) {}
    152   virtual ~TestBrowserPluginHostFactory() {}
    153 
    154  private:
    155   // For Singleton.
    156   friend struct DefaultSingletonTraits<TestBrowserPluginHostFactory>;
    157 
    158   scoped_refptr<MessageLoopRunner> message_loop_runner_;
    159   int guest_manager_instance_count_;
    160 
    161   DISALLOW_COPY_AND_ASSIGN(TestBrowserPluginHostFactory);
    162 };
    163 
    164 // Test factory class for browser plugin that creates guests with short hang
    165 // timeout.
    166 class TestShortHangTimeoutGuestFactory : public TestBrowserPluginHostFactory {
    167  public:
    168   virtual BrowserPluginGuest* CreateBrowserPluginGuest(
    169       int instance_id, WebContentsImpl* web_contents) OVERRIDE {
    170     BrowserPluginGuest* guest =
    171         new TestBrowserPluginGuest(instance_id, web_contents);
    172     guest->set_guest_hang_timeout_for_testing(TestTimeouts::tiny_timeout());
    173     return guest;
    174   }
    175 
    176   // Singleton getter.
    177   static TestShortHangTimeoutGuestFactory* GetInstance() {
    178     return Singleton<TestShortHangTimeoutGuestFactory>::get();
    179   }
    180 
    181  protected:
    182   TestShortHangTimeoutGuestFactory() {}
    183   virtual ~TestShortHangTimeoutGuestFactory() {}
    184 
    185  private:
    186   // For Singleton.
    187   friend struct DefaultSingletonTraits<TestShortHangTimeoutGuestFactory>;
    188 
    189   DISALLOW_COPY_AND_ASSIGN(TestShortHangTimeoutGuestFactory);
    190 };
    191 
    192 // A transparent observer that can be used to verify that a RenderViewHost
    193 // received a specific message.
    194 class RenderViewHostMessageObserver : public RenderViewHostObserver {
    195  public:
    196   RenderViewHostMessageObserver(RenderViewHost* host,
    197                                 uint32 message_id)
    198       : RenderViewHostObserver(host),
    199         message_id_(message_id),
    200         message_received_(false) {
    201   }
    202 
    203   virtual ~RenderViewHostMessageObserver() {}
    204 
    205   void WaitUntilMessageReceived() {
    206     if (message_received_)
    207       return;
    208     message_loop_runner_ = new MessageLoopRunner();
    209     message_loop_runner_->Run();
    210   }
    211 
    212   void ResetState() {
    213     message_received_ = false;
    214   }
    215 
    216   // IPC::Listener implementation.
    217   virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE {
    218     if (message.type() == message_id_) {
    219       message_received_ = true;
    220       if (message_loop_runner_.get())
    221         message_loop_runner_->Quit();
    222     }
    223     return false;
    224   }
    225 
    226  private:
    227   scoped_refptr<MessageLoopRunner> message_loop_runner_;
    228   uint32 message_id_;
    229   bool message_received_;
    230 
    231   DISALLOW_COPY_AND_ASSIGN(RenderViewHostMessageObserver);
    232 };
    233 
    234 class BrowserPluginHostTest : public ContentBrowserTest {
    235  public:
    236   BrowserPluginHostTest()
    237       : test_embedder_(NULL),
    238         test_guest_(NULL),
    239         test_guest_manager_(NULL) {}
    240 
    241   virtual void SetUp() OVERRIDE {
    242     // Override factory to create tests instances of BrowserPlugin*.
    243     content::BrowserPluginEmbedder::set_factory_for_testing(
    244         TestBrowserPluginHostFactory::GetInstance());
    245     content::BrowserPluginGuest::set_factory_for_testing(
    246         TestBrowserPluginHostFactory::GetInstance());
    247     content::BrowserPluginGuestManager::set_factory_for_testing(
    248         TestBrowserPluginHostFactory::GetInstance());
    249 
    250     // On legacy windows, the AcceptDragEvents test needs this to pass.
    251 #if defined(OS_WIN) && !defined(USE_AURA)
    252     UseRealGLBindings();
    253 #endif
    254 
    255     ContentBrowserTest::SetUp();
    256   }
    257   virtual void TearDown() OVERRIDE {
    258     content::BrowserPluginEmbedder::set_factory_for_testing(NULL);
    259     content::BrowserPluginGuest::set_factory_for_testing(NULL);
    260 
    261     ContentBrowserTest::TearDown();
    262   }
    263 
    264   virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
    265     // Enable browser plugin in content_shell for running test.
    266     command_line->AppendSwitch(switches::kEnableBrowserPluginForAllViewTypes);
    267   }
    268 
    269   static void SimulateSpaceKeyPress(WebContents* web_contents) {
    270     SimulateKeyPress(web_contents,
    271                      ui::VKEY_SPACE,
    272                      false,   // control.
    273                      false,   // shift.
    274                      false,   // alt.
    275                      false);  // command.
    276   }
    277 
    278   static void SimulateTabKeyPress(WebContents* web_contents) {
    279     SimulateKeyPress(web_contents,
    280                      ui::VKEY_TAB,
    281                      false,   // control.
    282                      false,   // shift.
    283                      false,   // alt.
    284                      false);  // command.
    285   }
    286 
    287   // Executes the javascript synchronously and makes sure the returned value is
    288   // freed properly.
    289   void ExecuteSyncJSFunction(RenderViewHost* rvh, const std::string& jscript) {
    290     scoped_ptr<base::Value> value =
    291         content::ExecuteScriptAndGetValue(rvh, jscript);
    292   }
    293 
    294   bool IsAttributeNull(RenderViewHost* rvh, const std::string& attribute) {
    295     scoped_ptr<base::Value> value = content::ExecuteScriptAndGetValue(rvh,
    296         "document.getElementById('plugin').getAttribute('" + attribute + "');");
    297     return value->GetType() == Value::TYPE_NULL;
    298   }
    299 
    300   // Removes all attributes in the comma-delimited string |attributes|.
    301   void RemoveAttributes(RenderViewHost* rvh, const std::string& attributes) {
    302     std::vector<std::string> attributes_list;
    303     base::SplitString(attributes, ',', &attributes_list);
    304     std::vector<std::string>::const_iterator itr;
    305     for (itr = attributes_list.begin(); itr != attributes_list.end(); ++itr) {
    306       ExecuteSyncJSFunction(rvh, "document.getElementById('plugin')"
    307                                  "." + *itr + " = null;");
    308     }
    309   }
    310 
    311   // This helper method does the following:
    312   // 1. Start the test server and navigate the shell to |embedder_url|.
    313   // 2. Execute custom pre-navigation |embedder_code| if provided.
    314   // 3. Navigate the guest to the |guest_url|.
    315   // 4. Verify that the guest has been created and has completed loading.
    316   void StartBrowserPluginTest(const std::string& embedder_url,
    317                               const std::string& guest_url,
    318                               bool is_guest_data_url,
    319                               const std::string& embedder_code) {
    320     ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
    321     GURL test_url(embedded_test_server()->GetURL(embedder_url));
    322     NavigateToURL(shell(), test_url);
    323 
    324     WebContentsImpl* embedder_web_contents = static_cast<WebContentsImpl*>(
    325         shell()->web_contents());
    326     RenderViewHostImpl* rvh = static_cast<RenderViewHostImpl*>(
    327         embedder_web_contents->GetRenderViewHost());
    328     // Focus the embedder.
    329     rvh->Focus();
    330     // Activative IME.
    331     rvh->SetInputMethodActive(true);
    332 
    333     // Allow the test to do some operations on the embedder before we perform
    334     // the first navigation of the guest.
    335     if (!embedder_code.empty())
    336       ExecuteSyncJSFunction(rvh, embedder_code);
    337 
    338     if (!is_guest_data_url) {
    339       test_url = embedded_test_server()->GetURL(guest_url);
    340       ExecuteSyncJSFunction(
    341           rvh, base::StringPrintf("SetSrc('%s');", test_url.spec().c_str()));
    342     } else {
    343       ExecuteSyncJSFunction(
    344           rvh, base::StringPrintf("SetSrc('%s');", guest_url.c_str()));
    345     }
    346 
    347     // Wait to make sure embedder is created/attached to WebContents.
    348     TestBrowserPluginHostFactory::GetInstance()->WaitForGuestManagerCreation();
    349 
    350     test_embedder_ = static_cast<TestBrowserPluginEmbedder*>(
    351         embedder_web_contents->GetBrowserPluginEmbedder());
    352     ASSERT_TRUE(test_embedder_);
    353 
    354     test_guest_manager_ = static_cast<TestBrowserPluginGuestManager*>(
    355         embedder_web_contents->GetBrowserPluginGuestManager());
    356     ASSERT_TRUE(test_guest_manager_);
    357 
    358     test_guest_manager_->WaitForGuestAdded();
    359 
    360     // Verify that we have exactly one guest.
    361     const TestBrowserPluginGuestManager::GuestInstanceMap& instance_map =
    362         test_guest_manager_->guest_web_contents_for_testing();
    363     EXPECT_EQ(1u, instance_map.size());
    364 
    365     WebContentsImpl* test_guest_web_contents = static_cast<WebContentsImpl*>(
    366         instance_map.begin()->second);
    367     test_guest_ = static_cast<TestBrowserPluginGuest*>(
    368         test_guest_web_contents->GetBrowserPluginGuest());
    369     test_guest_->WaitForLoadStop();
    370   }
    371 
    372   TestBrowserPluginEmbedder* test_embedder() const { return test_embedder_; }
    373   TestBrowserPluginGuest* test_guest() const { return test_guest_; }
    374   TestBrowserPluginGuestManager* test_guest_manager() const {
    375     return test_guest_manager_;
    376   }
    377 
    378  private:
    379   TestBrowserPluginEmbedder* test_embedder_;
    380   TestBrowserPluginGuest* test_guest_;
    381   TestBrowserPluginGuestManager* test_guest_manager_;
    382   DISALLOW_COPY_AND_ASSIGN(BrowserPluginHostTest);
    383 };
    384 
    385 // This test ensures that if guest isn't there and we resize the guest (from
    386 // js), it remembers the size correctly.
    387 //
    388 // Initially we load an embedder with a guest without a src attribute (which has
    389 // dimension 640x480), resize it to 100x200, and then we set the source to a
    390 // sample guest. In the end we verify that the correct size has been set.
    391 IN_PROC_BROWSER_TEST_F(BrowserPluginHostTest, NavigateAfterResize) {
    392   const gfx::Size nxt_size = gfx::Size(100, 200);
    393   const std::string embedder_code = base::StringPrintf(
    394       "SetSize(%d, %d);", nxt_size.width(), nxt_size.height());
    395   const char kEmbedderURL[] = "/browser_plugin_embedder.html";
    396   StartBrowserPluginTest(kEmbedderURL, kHTMLForGuest, true, embedder_code);
    397 
    398   // Wait for the guest to receive a damage buffer of size 100x200.
    399   // This means the guest will be painted properly at that size.
    400   test_guest()->WaitForDamageBufferWithSize(nxt_size);
    401 }
    402 
    403 IN_PROC_BROWSER_TEST_F(BrowserPluginHostTest, AdvanceFocus) {
    404   const char kEmbedderURL[] = "/browser_plugin_focus.html";
    405   const char* kGuestURL = "/browser_plugin_focus_child.html";
    406   StartBrowserPluginTest(kEmbedderURL, kGuestURL, false, std::string());
    407 
    408   SimulateMouseClick(test_embedder()->web_contents(), 0,
    409       WebKit::WebMouseEvent::ButtonLeft);
    410   BrowserPluginHostTest::SimulateTabKeyPress(test_embedder()->web_contents());
    411   // Wait until we focus into the guest.
    412   test_guest()->WaitForFocus();
    413 
    414   // TODO(fsamuel): A third Tab key press should not be necessary.
    415   // The browser plugin will take keyboard focus but it will not
    416   // focus an initial element. The initial element is dependent
    417   // upon tab direction which WebKit does not propagate to the plugin.
    418   // See http://crbug.com/147644.
    419   BrowserPluginHostTest::SimulateTabKeyPress(test_embedder()->web_contents());
    420   BrowserPluginHostTest::SimulateTabKeyPress(test_embedder()->web_contents());
    421   BrowserPluginHostTest::SimulateTabKeyPress(test_embedder()->web_contents());
    422   test_guest()->WaitForAdvanceFocus();
    423 }
    424 
    425 // This test opens a page in http and then opens another page in https, forcing
    426 // a RenderViewHost swap in the web_contents. We verify that the embedder in the
    427 // web_contents gets cleared properly.
    428 IN_PROC_BROWSER_TEST_F(BrowserPluginHostTest, EmbedderChangedAfterSwap) {
    429   net::SpawnedTestServer https_server(
    430       net::SpawnedTestServer::TYPE_HTTPS,
    431       net::SpawnedTestServer::kLocalhost,
    432       base::FilePath(FILE_PATH_LITERAL("content/test/data")));
    433   ASSERT_TRUE(https_server.Start());
    434 
    435   // 1. Load an embedder page with one guest in it.
    436   const char kEmbedderURL[] = "/browser_plugin_embedder.html";
    437   StartBrowserPluginTest(kEmbedderURL, kHTMLForGuest, true, std::string());
    438 
    439   // 2. Navigate to a URL in https, so we trigger a RenderViewHost swap.
    440   GURL test_https_url(https_server.GetURL(
    441       "files/browser_plugin_title_change.html"));
    442   content::WindowedNotificationObserver swap_observer(
    443       content::NOTIFICATION_WEB_CONTENTS_SWAPPED,
    444       content::Source<WebContents>(test_embedder()->web_contents()));
    445   NavigateToURL(shell(), test_https_url);
    446   swap_observer.Wait();
    447 
    448   TestBrowserPluginEmbedder* test_embedder_after_swap =
    449       static_cast<TestBrowserPluginEmbedder*>(
    450           static_cast<WebContentsImpl*>(shell()->web_contents())->
    451               GetBrowserPluginEmbedder());
    452   // Verify we have a no embedder in web_contents (since the new page doesn't
    453   // have any browser plugin).
    454   ASSERT_TRUE(!test_embedder_after_swap);
    455   ASSERT_NE(test_embedder(), test_embedder_after_swap);
    456 }
    457 
    458 // This test opens two pages in http and there is no RenderViewHost swap,
    459 // therefore the embedder created on first page navigation stays the same in
    460 // web_contents.
    461 IN_PROC_BROWSER_TEST_F(BrowserPluginHostTest, EmbedderSameAfterNav) {
    462   const char kEmbedderURL[] = "/browser_plugin_embedder.html";
    463   StartBrowserPluginTest(kEmbedderURL, kHTMLForGuest, true, std::string());
    464   WebContentsImpl* embedder_web_contents = test_embedder()->web_contents();
    465 
    466   // Navigate to another page in same host and port, so RenderViewHost swap
    467   // does not happen and existing embedder doesn't change in web_contents.
    468   GURL test_url_new(embedded_test_server()->GetURL(
    469       "/browser_plugin_title_change.html"));
    470   const string16 expected_title = ASCIIToUTF16("done");
    471   content::TitleWatcher title_watcher(shell()->web_contents(), expected_title);
    472   NavigateToURL(shell(), test_url_new);
    473   LOG(INFO) << "Start waiting for title";
    474   string16 actual_title = title_watcher.WaitAndGetTitle();
    475   EXPECT_EQ(expected_title, actual_title);
    476   LOG(INFO) << "Done navigating to second page";
    477 
    478   TestBrowserPluginEmbedder* test_embedder_after_nav =
    479       static_cast<TestBrowserPluginEmbedder*>(
    480           embedder_web_contents->GetBrowserPluginEmbedder());
    481   // Embedder must not change in web_contents.
    482   ASSERT_EQ(test_embedder_after_nav, test_embedder());
    483 }
    484 
    485 // This test verifies that hiding the embedder also hides the guest.
    486 IN_PROC_BROWSER_TEST_F(BrowserPluginHostTest, BrowserPluginVisibilityChanged) {
    487   const char kEmbedderURL[] = "/browser_plugin_embedder.html";
    488   StartBrowserPluginTest(kEmbedderURL, kHTMLForGuest, true, std::string());
    489 
    490   // Hide the Browser Plugin.
    491   RenderViewHostImpl* rvh = static_cast<RenderViewHostImpl*>(
    492       test_embedder()->web_contents()->GetRenderViewHost());
    493   ExecuteSyncJSFunction(
    494       rvh, "document.getElementById('plugin').style.visibility = 'hidden'");
    495 
    496   // Make sure that the guest is hidden.
    497   test_guest()->WaitUntilHidden();
    498 }
    499 
    500 IN_PROC_BROWSER_TEST_F(BrowserPluginHostTest, EmbedderVisibilityChanged) {
    501   const char kEmbedderURL[] = "/browser_plugin_embedder.html";
    502   StartBrowserPluginTest(kEmbedderURL, kHTMLForGuest, true, std::string());
    503 
    504   // Hide the embedder.
    505   test_embedder()->web_contents()->WasHidden();
    506 
    507   // Make sure that hiding the embedder also hides the guest.
    508   test_guest()->WaitUntilHidden();
    509 }
    510 
    511 // Verifies that installing/uninstalling touch-event handlers in the guest
    512 // plugin correctly updates the touch-event handling state in the embedder.
    513 IN_PROC_BROWSER_TEST_F(BrowserPluginHostTest, AcceptTouchEvents) {
    514   const char kEmbedderURL[] = "/browser_plugin_embedder.html";
    515   StartBrowserPluginTest(
    516       kEmbedderURL, kHTMLForGuestTouchHandler, true, std::string());
    517 
    518   RenderViewHostImpl* rvh = static_cast<RenderViewHostImpl*>(
    519       test_embedder()->web_contents()->GetRenderViewHost());
    520   // The embedder should not have any touch event handlers at this point.
    521   EXPECT_FALSE(rvh->has_touch_handler());
    522 
    523   // Install the touch handler in the guest. This should cause the embedder to
    524   // start listening for touch events too.
    525   RenderViewHostMessageObserver observer(rvh,
    526       ViewHostMsg_HasTouchEventHandlers::ID);
    527   ExecuteSyncJSFunction(test_guest()->web_contents()->GetRenderViewHost(),
    528                         "InstallTouchHandler();");
    529   observer.WaitUntilMessageReceived();
    530   EXPECT_TRUE(rvh->has_touch_handler());
    531 
    532   // Uninstalling the touch-handler in guest should cause the embedder to stop
    533   // listening for touch events.
    534   observer.ResetState();
    535   ExecuteSyncJSFunction(test_guest()->web_contents()->GetRenderViewHost(),
    536                         "UninstallTouchHandler();");
    537   observer.WaitUntilMessageReceived();
    538   EXPECT_FALSE(rvh->has_touch_handler());
    539 }
    540 
    541 // This tests verifies that reloading the embedder does not crash the browser
    542 // and that the guest is reset.
    543 IN_PROC_BROWSER_TEST_F(BrowserPluginHostTest, ReloadEmbedder) {
    544   const char kEmbedderURL[] = "/browser_plugin_embedder.html";
    545   StartBrowserPluginTest(kEmbedderURL, kHTMLForGuest, true, std::string());
    546   RenderViewHostImpl* rvh = static_cast<RenderViewHostImpl*>(
    547       test_embedder()->web_contents()->GetRenderViewHost());
    548 
    549   // Change the title of the page to 'modified' so that we know that
    550   // the page has successfully reloaded when it goes back to 'embedder'
    551   // in the next step.
    552   {
    553     const string16 expected_title = ASCIIToUTF16("modified");
    554     content::TitleWatcher title_watcher(test_embedder()->web_contents(),
    555                                         expected_title);
    556 
    557     ExecuteSyncJSFunction(rvh,
    558                           base::StringPrintf("SetTitle('%s');", "modified"));
    559 
    560     string16 actual_title = title_watcher.WaitAndGetTitle();
    561     EXPECT_EQ(expected_title, actual_title);
    562   }
    563 
    564   // Reload the embedder page, and verify that the reload was successful.
    565   // Then navigate the guest to verify that the browser process does not crash.
    566   {
    567     const string16 expected_title = ASCIIToUTF16("embedder");
    568     content::TitleWatcher title_watcher(test_embedder()->web_contents(),
    569                                         expected_title);
    570 
    571     test_embedder()->web_contents()->GetController().Reload(false);
    572     string16 actual_title = title_watcher.WaitAndGetTitle();
    573     EXPECT_EQ(expected_title, actual_title);
    574 
    575     ExecuteSyncJSFunction(
    576         test_embedder()->web_contents()->GetRenderViewHost(),
    577         base::StringPrintf("SetSrc('%s');", kHTMLForGuest));
    578     test_guest_manager()->WaitForGuestAdded();
    579 
    580     const TestBrowserPluginGuestManager::GuestInstanceMap& instance_map =
    581         test_guest_manager()->guest_web_contents_for_testing();
    582     WebContentsImpl* test_guest_web_contents = static_cast<WebContentsImpl*>(
    583         instance_map.begin()->second);
    584     TestBrowserPluginGuest* new_test_guest =
    585         static_cast<TestBrowserPluginGuest*>(
    586           test_guest_web_contents->GetBrowserPluginGuest());
    587     ASSERT_TRUE(new_test_guest != NULL);
    588 
    589     // Wait for the guest to send an UpdateRectMsg, meaning it is ready.
    590     new_test_guest->WaitForUpdateRectMsg();
    591   }
    592 }
    593 
    594 // Always failing in the win7_aura try bot.  See http://crbug.com/181107.
    595 #if defined(OS_WIN) && defined(USE_AURA)
    596 #define MAYBE_AcceptDragEvents DISABLED_AcceptDragEvents
    597 #else
    598 #define MAYBE_AcceptDragEvents AcceptDragEvents
    599 #endif
    600 
    601 // Tests that a drag-n-drop over the browser plugin in the embedder happens
    602 // correctly.
    603 IN_PROC_BROWSER_TEST_F(BrowserPluginHostTest, MAYBE_AcceptDragEvents) {
    604   const char kEmbedderURL[] = "/browser_plugin_dragging.html";
    605   StartBrowserPluginTest(
    606       kEmbedderURL, kHTMLForGuestAcceptDrag, true, std::string());
    607 
    608   RenderViewHostImpl* rvh = static_cast<RenderViewHostImpl*>(
    609       test_embedder()->web_contents()->GetRenderViewHost());
    610 
    611   // Get a location in the embedder outside of the plugin.
    612   base::ListValue *start, *end;
    613   scoped_ptr<base::Value> value =
    614       content::ExecuteScriptAndGetValue(rvh, "dragLocation()");
    615   ASSERT_TRUE(value->GetAsList(&start) && start->GetSize() == 2);
    616   double start_x, start_y;
    617   ASSERT_TRUE(start->GetDouble(0, &start_x) && start->GetDouble(1, &start_y));
    618 
    619   // Get a location in the embedder that falls inside the plugin.
    620   value = content::ExecuteScriptAndGetValue(rvh, "dropLocation()");
    621   ASSERT_TRUE(value->GetAsList(&end) && end->GetSize() == 2);
    622   double end_x, end_y;
    623   ASSERT_TRUE(end->GetDouble(0, &end_x) && end->GetDouble(1, &end_y));
    624 
    625   DropData drop_data;
    626   GURL url = GURL("https://www.domain.com/index.html");
    627   drop_data.url = url;
    628 
    629   // Pretend that the URL is being dragged over the embedder. Start the drag
    630   // from outside the plugin, then move the drag inside the plugin and drop.
    631   // This should trigger appropriate messages from the embedder to the guest,
    632   // and end with a drop on the guest. The guest changes title when a drop
    633   // happens.
    634   const string16 expected_title = ASCIIToUTF16("DROPPED");
    635   content::TitleWatcher title_watcher(test_guest()->web_contents(),
    636       expected_title);
    637 
    638   rvh->DragTargetDragEnter(drop_data, gfx::Point(start_x, start_y),
    639       gfx::Point(start_x, start_y), WebKit::WebDragOperationEvery, 0);
    640   rvh->DragTargetDragOver(gfx::Point(end_x, end_y), gfx::Point(end_x, end_y),
    641       WebKit::WebDragOperationEvery, 0);
    642   rvh->DragTargetDrop(gfx::Point(end_x, end_y), gfx::Point(end_x, end_y), 0);
    643 
    644   string16 actual_title = title_watcher.WaitAndGetTitle();
    645   EXPECT_EQ(expected_title, actual_title);
    646 }
    647 
    648 // This test verifies that round trip postMessage works as expected.
    649 // 1. The embedder posts a message 'testing123' to the guest.
    650 // 2. The guest receives and replies to the message using the event object's
    651 // source object: event.source.postMessage('foobar', '*')
    652 // 3. The embedder receives the message and uses the event's source
    653 // object to do one final reply: 'stop'
    654 // 4. The guest receives the final 'stop' message.
    655 // 5. The guest acks the 'stop' message with a 'stop_ack' message.
    656 // 6. The embedder changes its title to 'main guest' when it sees the 'stop_ack'
    657 // message.
    658 IN_PROC_BROWSER_TEST_F(BrowserPluginHostTest, PostMessage) {
    659   const char* kTesting = "testing123";
    660   const char* kEmbedderURL = "/browser_plugin_embedder.html";
    661   const char* kGuestURL = "/browser_plugin_post_message_guest.html";
    662   StartBrowserPluginTest(kEmbedderURL, kGuestURL, false, std::string());
    663   RenderViewHostImpl* rvh = static_cast<RenderViewHostImpl*>(
    664       test_embedder()->web_contents()->GetRenderViewHost());
    665   {
    666     const string16 expected_title = ASCIIToUTF16("main guest");
    667     content::TitleWatcher title_watcher(test_embedder()->web_contents(),
    668                                         expected_title);
    669 
    670     // By the time we get here 'contentWindow' should be ready because the
    671     // guest has completed loading.
    672     ExecuteSyncJSFunction(
    673         rvh, base::StringPrintf("PostMessage('%s, false');", kTesting));
    674 
    675     // The title will be updated to "main guest" at the last stage of the
    676     // process described above.
    677     string16 actual_title = title_watcher.WaitAndGetTitle();
    678     EXPECT_EQ(expected_title, actual_title);
    679   }
    680 }
    681 
    682 // This is the same as BrowserPluginHostTest.PostMessage but also
    683 // posts a message to an iframe.
    684 // TODO(fsamuel): This test should replace the previous test once postMessage
    685 // iframe targeting is fixed (see http://crbug.com/153701).
    686 IN_PROC_BROWSER_TEST_F(BrowserPluginHostTest, DISABLED_PostMessageToIFrame) {
    687   const char* kTesting = "testing123";
    688   const char* kEmbedderURL = "/browser_plugin_embedder.html";
    689   const char* kGuestURL = "/browser_plugin_post_message_guest.html";
    690   StartBrowserPluginTest(kEmbedderURL, kGuestURL, false, std::string());
    691   RenderViewHostImpl* rvh = static_cast<RenderViewHostImpl*>(
    692       test_embedder()->web_contents()->GetRenderViewHost());
    693   {
    694     const string16 expected_title = ASCIIToUTF16("main guest");
    695     content::TitleWatcher title_watcher(test_embedder()->web_contents(),
    696                                         expected_title);
    697 
    698     ExecuteSyncJSFunction(
    699         rvh, base::StringPrintf("PostMessage('%s, false');", kTesting));
    700 
    701     // The title will be updated to "main guest" at the last stage of the
    702     // process described above.
    703     string16 actual_title = title_watcher.WaitAndGetTitle();
    704     EXPECT_EQ(expected_title, actual_title);
    705   }
    706   {
    707     content::TitleWatcher ready_watcher(test_embedder()->web_contents(),
    708                                         ASCIIToUTF16("ready"));
    709 
    710     RenderViewHostImpl* guest_rvh = static_cast<RenderViewHostImpl*>(
    711         test_guest()->web_contents()->GetRenderViewHost());
    712     GURL test_url = embedded_test_server()->GetURL(
    713         "/browser_plugin_post_message_guest.html");
    714     ExecuteSyncJSFunction(
    715         guest_rvh,
    716         base::StringPrintf(
    717             "CreateChildFrame('%s');", test_url.spec().c_str()));
    718 
    719     string16 actual_title = ready_watcher.WaitAndGetTitle();
    720     EXPECT_EQ(ASCIIToUTF16("ready"), actual_title);
    721 
    722     content::TitleWatcher iframe_watcher(test_embedder()->web_contents(),
    723                                         ASCIIToUTF16("iframe"));
    724     ExecuteSyncJSFunction(
    725         rvh, base::StringPrintf("PostMessage('%s', true);", kTesting));
    726 
    727     // The title will be updated to "iframe" at the last stage of the
    728     // process described above.
    729     actual_title = iframe_watcher.WaitAndGetTitle();
    730     EXPECT_EQ(ASCIIToUTF16("iframe"), actual_title);
    731   }
    732 }
    733 
    734 // This test verifies that if a browser plugin is hidden before navigation,
    735 // the guest starts off hidden.
    736 IN_PROC_BROWSER_TEST_F(BrowserPluginHostTest, HiddenBeforeNavigation) {
    737   const char* kEmbedderURL = "/browser_plugin_embedder.html";
    738   const std::string embedder_code =
    739       "document.getElementById('plugin').style.visibility = 'hidden'";
    740   StartBrowserPluginTest(
    741       kEmbedderURL, kHTMLForGuest, true, embedder_code);
    742   EXPECT_FALSE(test_guest()->visible());
    743 }
    744 
    745 // This test verifies that if a browser plugin is focused before navigation then
    746 // the guest starts off focused.
    747 IN_PROC_BROWSER_TEST_F(BrowserPluginHostTest, FocusBeforeNavigation) {
    748   const char* kEmbedderURL = "/browser_plugin_embedder.html";
    749   const std::string embedder_code =
    750       "document.getElementById('plugin').focus();";
    751   StartBrowserPluginTest(
    752       kEmbedderURL, kHTMLForGuest, true, embedder_code);
    753   RenderViewHostImpl* guest_rvh = static_cast<RenderViewHostImpl*>(
    754       test_guest()->web_contents()->GetRenderViewHost());
    755   // Verify that the guest is focused.
    756   scoped_ptr<base::Value> value =
    757       content::ExecuteScriptAndGetValue(guest_rvh, "document.hasFocus()");
    758   bool result = false;
    759   ASSERT_TRUE(value->GetAsBoolean(&result));
    760   EXPECT_TRUE(result);
    761 }
    762 
    763 IN_PROC_BROWSER_TEST_F(BrowserPluginHostTest, FocusTracksEmbedder) {
    764   const char* kEmbedderURL = "/browser_plugin_embedder.html";
    765   StartBrowserPluginTest(kEmbedderURL, kHTMLForGuest, true, std::string());
    766   RenderViewHostImpl* rvh = static_cast<RenderViewHostImpl*>(
    767       test_embedder()->web_contents()->GetRenderViewHost());
    768   RenderViewHostImpl* guest_rvh = static_cast<RenderViewHostImpl*>(
    769       test_guest()->web_contents()->GetRenderViewHost());
    770   {
    771     // Focus the BrowserPlugin. This will have the effect of also focusing the
    772     // current guest.
    773     ExecuteSyncJSFunction(rvh, "document.getElementById('plugin').focus();");
    774     // Verify that key presses go to the guest.
    775     SimulateSpaceKeyPress(test_embedder()->web_contents());
    776     test_guest()->WaitForInput();
    777     // Verify that the guest is focused.
    778     scoped_ptr<base::Value> value =
    779         content::ExecuteScriptAndGetValue(guest_rvh, "document.hasFocus()");
    780     bool result = false;
    781     ASSERT_TRUE(value->GetAsBoolean(&result));
    782     EXPECT_TRUE(result);
    783   }
    784   // Blur the embedder.
    785   test_embedder()->web_contents()->GetRenderViewHost()->Blur();
    786   test_guest()->WaitForBlur();
    787 }
    788 
    789 // This test verifies that if a browser plugin is in autosize mode before
    790 // navigation then the guest starts auto-sized.
    791 IN_PROC_BROWSER_TEST_F(BrowserPluginHostTest, AutoSizeBeforeNavigation) {
    792   const char* kEmbedderURL = "/browser_plugin_embedder.html";
    793   const std::string embedder_code =
    794       "document.getElementById('plugin').minwidth = 300;"
    795       "document.getElementById('plugin').minheight = 200;"
    796       "document.getElementById('plugin').maxwidth = 600;"
    797       "document.getElementById('plugin').maxheight = 400;"
    798       "document.getElementById('plugin').autosize = true;";
    799   StartBrowserPluginTest(
    800       kEmbedderURL, kHTMLForGuestWithSize, true, embedder_code);
    801   // Verify that the guest has been auto-sized.
    802   test_guest()->WaitForViewSize(gfx::Size(300, 400));
    803 }
    804 
    805 // This test verifies that enabling autosize resizes the guest and triggers
    806 // a 'sizechanged' event.
    807 IN_PROC_BROWSER_TEST_F(BrowserPluginHostTest, AutoSizeAfterNavigation) {
    808   const char* kEmbedderURL = "/browser_plugin_embedder.html";
    809   StartBrowserPluginTest(
    810       kEmbedderURL, kHTMLForGuestWithSize, true, std::string());
    811   RenderViewHostImpl* rvh = static_cast<RenderViewHostImpl*>(
    812       test_embedder()->web_contents()->GetRenderViewHost());
    813 
    814   {
    815     const string16 expected_title = ASCIIToUTF16("AutoSize(300, 400)");
    816     content::TitleWatcher title_watcher(test_embedder()->web_contents(),
    817                                         expected_title);
    818     ExecuteSyncJSFunction(
    819         rvh,
    820         "document.getElementById('plugin').minwidth = 300;"
    821         "document.getElementById('plugin').minheight = 200;"
    822         "document.getElementById('plugin').maxwidth = 600;"
    823         "document.getElementById('plugin').maxheight = 400;"
    824         "document.getElementById('plugin').autosize = true;");
    825     string16 actual_title = title_watcher.WaitAndGetTitle();
    826     EXPECT_EQ(expected_title, actual_title);
    827   }
    828   {
    829     // Change the minwidth and verify that it causes relayout.
    830     const string16 expected_title = ASCIIToUTF16("AutoSize(350, 400)");
    831     content::TitleWatcher title_watcher(test_embedder()->web_contents(),
    832                                         expected_title);
    833     ExecuteSyncJSFunction(
    834         rvh, "document.getElementById('plugin').minwidth = 350;");
    835     string16 actual_title = title_watcher.WaitAndGetTitle();
    836     EXPECT_EQ(expected_title, actual_title);
    837   }
    838   {
    839     // Turn off autoSize and verify that the guest resizes to fit the container.
    840     ExecuteSyncJSFunction(
    841         rvh, "document.getElementById('plugin').autosize = null;");
    842     test_guest()->WaitForViewSize(gfx::Size(640, 480));
    843   }
    844 }
    845 
    846 // Test for regression http://crbug.com/162961.
    847 IN_PROC_BROWSER_TEST_F(BrowserPluginHostTest, GetRenderViewHostAtPositionTest) {
    848   const char kEmbedderURL[] = "/browser_plugin_embedder.html";
    849   const std::string embedder_code =
    850       base::StringPrintf("SetSize(%d, %d);", 100, 100);
    851   StartBrowserPluginTest(kEmbedderURL, kHTMLForGuestWithSize, true,
    852                          embedder_code);
    853   // Check for render view host at position (150, 150) that is outside the
    854   // bounds of our guest, so this would respond with the render view host of the
    855   // embedder.
    856   test_embedder()->WaitForRenderViewHostAtPosition(150, 150);
    857   ASSERT_EQ(test_embedder()->web_contents()->GetRenderViewHost(),
    858             test_embedder()->last_rvh_at_position_response());
    859 }
    860 
    861 // This test verifies that all autosize attributes can be removed
    862 // without crashing the plugin, or throwing errors.
    863 IN_PROC_BROWSER_TEST_F(BrowserPluginHostTest, RemoveAutosizeAttributes) {
    864   const char* kEmbedderURL = "/browser_plugin_embedder.html";
    865   const std::string embedder_code =
    866       "document.getElementById('plugin').minwidth = 300;"
    867       "document.getElementById('plugin').minheight = 200;"
    868       "document.getElementById('plugin').maxwidth = 600;"
    869       "document.getElementById('plugin').maxheight = 400;"
    870       "document.getElementById('plugin').name = 'name';"
    871       "document.getElementById('plugin').src = 'foo';"
    872       "document.getElementById('plugin').autosize = '';";
    873   StartBrowserPluginTest(
    874       kEmbedderURL, kHTMLForGuestWithSize, true, embedder_code);
    875   RenderViewHostImpl* rvh = static_cast<RenderViewHostImpl*>(
    876       test_embedder()->web_contents()->GetRenderViewHost());
    877   RemoveAttributes(rvh, "maxheight, maxwidth, minheight, minwidth, autosize");
    878 
    879   // Verify that the guest resizes to fit the container (and hasn't crashed).
    880   test_guest()->WaitForViewSize(gfx::Size(640, 480));
    881   EXPECT_TRUE(IsAttributeNull(rvh, "maxheight"));
    882   EXPECT_TRUE(IsAttributeNull(rvh, "maxwidth"));
    883   EXPECT_TRUE(IsAttributeNull(rvh, "minheight"));
    884   EXPECT_TRUE(IsAttributeNull(rvh, "minwidth"));
    885   EXPECT_TRUE(IsAttributeNull(rvh, "autosize"));
    886 }
    887 
    888 // This test verifies that autosize works when some of the parameters are unset.
    889 IN_PROC_BROWSER_TEST_F(BrowserPluginHostTest, PartialAutosizeAttributes) {
    890   const char* kEmbedderURL = "/browser_plugin_embedder.html";
    891   const std::string embedder_code =
    892       "document.getElementById('plugin').minwidth = 300;"
    893       "document.getElementById('plugin').minheight = 200;"
    894       "document.getElementById('plugin').maxwidth = 700;"
    895       "document.getElementById('plugin').maxheight = 600;"
    896       "document.getElementById('plugin').autosize = '';";
    897   StartBrowserPluginTest(
    898       kEmbedderURL, kHTMLForGuestWithSize, true, embedder_code);
    899   RenderViewHostImpl* rvh = static_cast<RenderViewHostImpl*>(
    900       test_embedder()->web_contents()->GetRenderViewHost());
    901   {
    902     // Remove an autosize attribute and verify that it causes relayout.
    903     const string16 expected_title = ASCIIToUTF16("AutoSize(640, 400)");
    904     content::TitleWatcher title_watcher(test_embedder()->web_contents(),
    905                                         expected_title);
    906     RemoveAttributes(rvh, "minwidth");
    907     string16 actual_title = title_watcher.WaitAndGetTitle();
    908     EXPECT_EQ(expected_title, actual_title);
    909   }
    910   {
    911     // Remove an autosize attribute and verify that it causes relayout.
    912     // Also tests that when minwidth > maxwidth, minwidth = maxwidth.
    913     const string16 expected_title = ASCIIToUTF16("AutoSize(700, 480)");
    914     content::TitleWatcher title_watcher(test_embedder()->web_contents(),
    915                                         expected_title);
    916     RemoveAttributes(rvh, "maxheight");
    917     ExecuteSyncJSFunction(
    918         rvh, "document.getElementById('plugin').minwidth = 800;"
    919              "document.getElementById('plugin').minheight = 800;");
    920     string16 actual_title = title_watcher.WaitAndGetTitle();
    921     EXPECT_EQ(expected_title, actual_title);
    922   }
    923   {
    924     // Remove maxwidth and make sure the size returns to plugin size.
    925     const string16 expected_title = ASCIIToUTF16("AutoSize(640, 480)");
    926     content::TitleWatcher title_watcher(test_embedder()->web_contents(),
    927                                         expected_title);
    928     RemoveAttributes(rvh, "maxwidth");
    929     string16 actual_title = title_watcher.WaitAndGetTitle();
    930     EXPECT_EQ(expected_title, actual_title);
    931   }
    932 }
    933 
    934 // This test verifies that if IME is enabled in the embedder, it is also enabled
    935 // in the guest.
    936 IN_PROC_BROWSER_TEST_F(BrowserPluginHostTest, VerifyInputMethodActive) {
    937   const char* kEmbedderURL = "/browser_plugin_embedder.html";
    938   StartBrowserPluginTest(kEmbedderURL, kHTMLForGuest, true, std::string());
    939   RenderViewHostImpl* rvh = static_cast<RenderViewHostImpl*>(
    940       test_guest()->web_contents()->GetRenderViewHost());
    941   EXPECT_TRUE(rvh->input_method_active());
    942 }
    943 
    944 }  // namespace content
    945