Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / content / browser / browser_plugin / browser_plugin_host_browsertest.cc
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_delegate.h"
17 #include "content/browser/browser_plugin/test_browser_plugin_guest_manager.h"
18 #include "content/browser/child_process_security_policy_impl.h"
19 #include "content/browser/frame_host/render_widget_host_view_guest.h"
20 #include "content/browser/renderer_host/render_view_host_impl.h"
21 #include "content/browser/web_contents/web_contents_impl.h"
22 #include "content/common/browser_plugin/browser_plugin_messages.h"
23 #include "content/common/view_messages.h"
24 #include "content/public/browser/notification_service.h"
25 #include "content/public/browser/notification_types.h"
26 #include "content/public/browser/render_widget_host_view.h"
27 #include "content/public/browser/web_contents_observer.h"
28 #include "content/public/common/content_switches.h"
29 #include "content/public/common/drop_data.h"
30 #include "content/public/common/url_constants.h"
31 #include "content/public/test/browser_test_utils.h"
32 #include "content/public/test/test_utils.h"
33 #include "content/shell/browser/shell.h"
34 #include "content/test/content_browser_test.h"
35 #include "content/test/content_browser_test_utils.h"
36 #include "net/base/net_util.h"
37 #include "net/test/embedded_test_server/embedded_test_server.h"
38 #include "net/test/embedded_test_server/http_request.h"
39 #include "net/test/embedded_test_server/http_response.h"
40 #include "net/test/spawned_test_server/spawned_test_server.h"
41 #include "third_party/WebKit/public/web/WebInputEvent.h"
42
43 using base::ASCIIToUTF16;
44 using blink::WebInputEvent;
45 using blink::WebMouseEvent;
46 using content::BrowserPluginEmbedder;
47 using content::BrowserPluginGuest;
48 using content::BrowserPluginHostFactory;
49 using content::WebContentsImpl;
50
51 const char kHTMLForGuest[] =
52     "data:text/html,<html><body>hello world</body></html>";
53
54 const char kHTMLForGuestTouchHandler[] =
55     "data:text/html,<html><body><div id=\"touch\">With touch</div></body>"
56     "<script type=\"text/javascript\">"
57     "function handler() {}"
58     "function InstallTouchHandler() { "
59     "  document.getElementById(\"touch\").addEventListener(\"touchstart\", "
60     "     handler);"
61     "}"
62     "function UninstallTouchHandler() { "
63     "  document.getElementById(\"touch\").removeEventListener(\"touchstart\", "
64     "     handler);"
65     "}"
66     "</script></html>";
67
68 const char kHTMLForGuestAcceptDrag[] =
69     "data:text/html,<html><body>"
70     "<script>"
71     "function dropped() {"
72     "  document.title = \"DROPPED\";"
73     "}"
74     "</script>"
75     "<textarea id=\"text\" style=\"width:100%; height: 100%\""
76     "    ondrop=\"dropped();\">"
77     "</textarea>"
78     "</body></html>";
79
80 const char kHTMLForGuestWithSize[] =
81     "data:text/html,"
82     "<html>"
83     "<body style=\"margin: 0px;\">"
84     "<img style=\"width: 100%; height: 400px;\"/>"
85     "</body>"
86     "</html>";
87
88 namespace content {
89
90 // Test factory for creating test instances of BrowserPluginEmbedder and
91 // BrowserPluginGuest.
92 class TestBrowserPluginHostFactory : public BrowserPluginHostFactory {
93  public:
94   virtual BrowserPluginGuestManager*
95       CreateBrowserPluginGuestManager() OVERRIDE {
96     guest_manager_instance_count_++;
97     if (message_loop_runner_.get())
98       message_loop_runner_->Quit();
99     return new TestBrowserPluginGuestManager();
100   }
101
102   virtual BrowserPluginGuest* CreateBrowserPluginGuest(
103       int instance_id,
104       WebContentsImpl* web_contents) OVERRIDE {
105     return new TestBrowserPluginGuest(instance_id, web_contents);
106   }
107
108   // Also keeps track of number of instances created.
109   virtual BrowserPluginEmbedder* CreateBrowserPluginEmbedder(
110       WebContentsImpl* web_contents) OVERRIDE {
111
112     return new TestBrowserPluginEmbedder(web_contents);
113   }
114
115   // Singleton getter.
116   static TestBrowserPluginHostFactory* GetInstance() {
117     return Singleton<TestBrowserPluginHostFactory>::get();
118   }
119
120   // Waits for at least one embedder to be created in the test. Returns true if
121   // we have a guest, false if waiting times out.
122   void WaitForGuestManagerCreation() {
123     // Check if already have created an instance.
124     if (guest_manager_instance_count_ > 0)
125       return;
126     // Wait otherwise.
127     message_loop_runner_ = new MessageLoopRunner();
128     message_loop_runner_->Run();
129   }
130
131  protected:
132   TestBrowserPluginHostFactory() : guest_manager_instance_count_(0) {}
133   virtual ~TestBrowserPluginHostFactory() {}
134
135  private:
136   // For Singleton.
137   friend struct DefaultSingletonTraits<TestBrowserPluginHostFactory>;
138
139   scoped_refptr<MessageLoopRunner> message_loop_runner_;
140   int guest_manager_instance_count_;
141
142   DISALLOW_COPY_AND_ASSIGN(TestBrowserPluginHostFactory);
143 };
144
145 // Test factory class for browser plugin that creates guests with short hang
146 // timeout.
147 class TestShortHangTimeoutGuestFactory : public TestBrowserPluginHostFactory {
148  public:
149   virtual BrowserPluginGuest* CreateBrowserPluginGuest(
150       int instance_id, WebContentsImpl* web_contents) OVERRIDE {
151     TestBrowserPluginGuest* guest =
152         new TestBrowserPluginGuest(instance_id, web_contents);
153     guest->set_guest_hang_timeout(TestTimeouts::tiny_timeout());
154     return guest;
155   }
156
157   // Singleton getter.
158   static TestShortHangTimeoutGuestFactory* GetInstance() {
159     return Singleton<TestShortHangTimeoutGuestFactory>::get();
160   }
161
162  protected:
163   TestShortHangTimeoutGuestFactory() {}
164   virtual ~TestShortHangTimeoutGuestFactory() {}
165
166  private:
167   // For Singleton.
168   friend struct DefaultSingletonTraits<TestShortHangTimeoutGuestFactory>;
169
170   DISALLOW_COPY_AND_ASSIGN(TestShortHangTimeoutGuestFactory);
171 };
172
173 // A transparent observer that can be used to verify that a RenderViewHost
174 // received a specific message.
175 class MessageObserver : public WebContentsObserver {
176  public:
177   MessageObserver(WebContents* web_contents, uint32 message_id)
178       : WebContentsObserver(web_contents),
179         message_id_(message_id),
180         message_received_(false) {
181   }
182
183   virtual ~MessageObserver() {}
184
185   void WaitUntilMessageReceived() {
186     if (message_received_)
187       return;
188     message_loop_runner_ = new MessageLoopRunner();
189     message_loop_runner_->Run();
190   }
191
192   void ResetState() {
193     message_received_ = false;
194   }
195
196   // IPC::Listener implementation.
197   virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE {
198     if (message.type() == message_id_) {
199       message_received_ = true;
200       if (message_loop_runner_.get())
201         message_loop_runner_->Quit();
202     }
203     return false;
204   }
205
206  private:
207   scoped_refptr<MessageLoopRunner> message_loop_runner_;
208   uint32 message_id_;
209   bool message_received_;
210
211   DISALLOW_COPY_AND_ASSIGN(MessageObserver);
212 };
213
214 class BrowserPluginHostTest : public ContentBrowserTest {
215  public:
216   BrowserPluginHostTest()
217       : test_embedder_(NULL),
218         test_guest_(NULL),
219         test_guest_manager_(NULL) {}
220
221   virtual void SetUp() OVERRIDE {
222     // Override factory to create tests instances of BrowserPlugin*.
223     content::BrowserPluginEmbedder::set_factory_for_testing(
224         TestBrowserPluginHostFactory::GetInstance());
225     content::BrowserPluginGuest::set_factory_for_testing(
226         TestBrowserPluginHostFactory::GetInstance());
227     content::BrowserPluginGuestManager::set_factory_for_testing(
228         TestBrowserPluginHostFactory::GetInstance());
229     ContentBrowserTest::SetUp();
230   }
231   virtual void TearDown() OVERRIDE {
232     content::BrowserPluginEmbedder::set_factory_for_testing(NULL);
233     content::BrowserPluginGuest::set_factory_for_testing(NULL);
234
235     ContentBrowserTest::TearDown();
236   }
237
238   virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
239     // Enable browser plugin in content_shell for running test.
240     command_line->AppendSwitch(switches::kEnableBrowserPluginForAllViewTypes);
241   }
242
243   static void SimulateSpaceKeyPress(WebContents* web_contents) {
244     SimulateKeyPress(web_contents,
245                      ui::VKEY_SPACE,
246                      false,   // control.
247                      false,   // shift.
248                      false,   // alt.
249                      false);  // command.
250   }
251
252   static void SimulateTabKeyPress(WebContents* web_contents) {
253     SimulateKeyPress(web_contents,
254                      ui::VKEY_TAB,
255                      false,   // control.
256                      false,   // shift.
257                      false,   // alt.
258                      false);  // command.
259   }
260
261   // Executes the javascript synchronously and makes sure the returned value is
262   // freed properly.
263   void ExecuteSyncJSFunction(RenderViewHost* rvh, const std::string& jscript) {
264     scoped_ptr<base::Value> value =
265         content::ExecuteScriptAndGetValue(rvh, jscript);
266   }
267
268   bool IsAttributeNull(RenderViewHost* rvh, const std::string& attribute) {
269     scoped_ptr<base::Value> value = content::ExecuteScriptAndGetValue(rvh,
270         "document.getElementById('plugin').getAttribute('" + attribute + "');");
271     return value->GetType() == base::Value::TYPE_NULL;
272   }
273
274   // Removes all attributes in the comma-delimited string |attributes|.
275   void RemoveAttributes(RenderViewHost* rvh, const std::string& attributes) {
276     std::vector<std::string> attributes_list;
277     base::SplitString(attributes, ',', &attributes_list);
278     std::vector<std::string>::const_iterator itr;
279     for (itr = attributes_list.begin(); itr != attributes_list.end(); ++itr) {
280       ExecuteSyncJSFunction(rvh, "document.getElementById('plugin')"
281                                  "." + *itr + " = null;");
282     }
283   }
284
285   // This helper method does the following:
286   // 1. Start the test server and navigate the shell to |embedder_url|.
287   // 2. Execute custom pre-navigation |embedder_code| if provided.
288   // 3. Navigate the guest to the |guest_url|.
289   // 4. Verify that the guest has been created and has completed loading.
290   void StartBrowserPluginTest(const std::string& embedder_url,
291                               const std::string& guest_url,
292                               bool is_guest_data_url,
293                               const std::string& embedder_code) {
294     ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
295     GURL test_url(embedded_test_server()->GetURL(embedder_url));
296     NavigateToURL(shell(), test_url);
297
298     WebContentsImpl* embedder_web_contents = static_cast<WebContentsImpl*>(
299         shell()->web_contents());
300     RenderViewHostImpl* rvh = static_cast<RenderViewHostImpl*>(
301         embedder_web_contents->GetRenderViewHost());
302     // Focus the embedder.
303     rvh->Focus();
304     // Activative IME.
305     rvh->SetInputMethodActive(true);
306
307     // Allow the test to do some operations on the embedder before we perform
308     // the first navigation of the guest.
309     if (!embedder_code.empty())
310       ExecuteSyncJSFunction(rvh, embedder_code);
311
312     if (!is_guest_data_url) {
313       test_url = embedded_test_server()->GetURL(guest_url);
314       ExecuteSyncJSFunction(
315           rvh, base::StringPrintf("SetSrc('%s');", test_url.spec().c_str()));
316     } else {
317       ExecuteSyncJSFunction(
318           rvh, base::StringPrintf("SetSrc('%s');", guest_url.c_str()));
319     }
320
321     // Wait to make sure embedder is created/attached to WebContents.
322     TestBrowserPluginHostFactory::GetInstance()->WaitForGuestManagerCreation();
323
324     test_embedder_ = static_cast<TestBrowserPluginEmbedder*>(
325         embedder_web_contents->GetBrowserPluginEmbedder());
326     ASSERT_TRUE(test_embedder_);
327
328     test_guest_manager_ = static_cast<TestBrowserPluginGuestManager*>(
329         embedder_web_contents->GetBrowserPluginGuestManager());
330     ASSERT_TRUE(test_guest_manager_);
331
332     test_guest_manager_->WaitForGuestAdded();
333
334     // Verify that we have exactly one guest.
335     const TestBrowserPluginGuestManager::GuestInstanceMap& instance_map =
336         test_guest_manager_->guest_web_contents_for_testing();
337     EXPECT_EQ(1u, instance_map.size());
338
339     WebContentsImpl* test_guest_web_contents = static_cast<WebContentsImpl*>(
340         instance_map.begin()->second);
341     test_guest_ = static_cast<TestBrowserPluginGuest*>(
342         test_guest_web_contents->GetBrowserPluginGuest());
343     test_guest_->WaitForLoadStop();
344   }
345
346   TestBrowserPluginEmbedder* test_embedder() const { return test_embedder_; }
347   TestBrowserPluginGuest* test_guest() const { return test_guest_; }
348   TestBrowserPluginGuestManager* test_guest_manager() const {
349     return test_guest_manager_;
350   }
351
352  private:
353   TestBrowserPluginEmbedder* test_embedder_;
354   TestBrowserPluginGuest* test_guest_;
355   TestBrowserPluginGuestManager* test_guest_manager_;
356   DISALLOW_COPY_AND_ASSIGN(BrowserPluginHostTest);
357 };
358
359 // This test ensures that if guest isn't there and we resize the guest (from
360 // js), it remembers the size correctly.
361 //
362 // Initially we load an embedder with a guest without a src attribute (which has
363 // dimension 640x480), resize it to 100x200, and then we set the source to a
364 // sample guest. In the end we verify that the correct size has been set.
365 IN_PROC_BROWSER_TEST_F(BrowserPluginHostTest, NavigateAfterResize) {
366   const gfx::Size nxt_size = gfx::Size(100, 200);
367   const std::string embedder_code = base::StringPrintf(
368       "SetSize(%d, %d);", nxt_size.width(), nxt_size.height());
369   const char kEmbedderURL[] = "/browser_plugin_embedder.html";
370   StartBrowserPluginTest(kEmbedderURL, kHTMLForGuest, true, embedder_code);
371
372   // Wait for the guest to receive a damage buffer of size 100x200.
373   // This means the guest will be painted properly at that size.
374   test_guest()->WaitForDamageBufferWithSize(nxt_size);
375 }
376
377 IN_PROC_BROWSER_TEST_F(BrowserPluginHostTest, AdvanceFocus) {
378   const char kEmbedderURL[] = "/browser_plugin_focus.html";
379   const char* kGuestURL = "/browser_plugin_focus_child.html";
380   StartBrowserPluginTest(kEmbedderURL, kGuestURL, false, std::string());
381
382   SimulateMouseClick(test_embedder()->web_contents(), 0,
383       blink::WebMouseEvent::ButtonLeft);
384   BrowserPluginHostTest::SimulateTabKeyPress(test_embedder()->web_contents());
385   // Wait until we focus into the guest.
386   test_guest()->WaitForFocus();
387
388   // TODO(fsamuel): A third Tab key press should not be necessary.
389   // The browser plugin will take keyboard focus but it will not
390   // focus an initial element. The initial element is dependent
391   // upon tab direction which WebKit does not propagate to the plugin.
392   // See http://crbug.com/147644.
393   BrowserPluginHostTest::SimulateTabKeyPress(test_embedder()->web_contents());
394   BrowserPluginHostTest::SimulateTabKeyPress(test_embedder()->web_contents());
395   BrowserPluginHostTest::SimulateTabKeyPress(test_embedder()->web_contents());
396   test_guest()->WaitForAdvanceFocus();
397 }
398
399 // This test opens a page in http and then opens another page in https, forcing
400 // a RenderViewHost swap in the web_contents. We verify that the embedder in the
401 // web_contents gets cleared properly.
402 IN_PROC_BROWSER_TEST_F(BrowserPluginHostTest, EmbedderChangedAfterSwap) {
403   net::SpawnedTestServer https_server(
404       net::SpawnedTestServer::TYPE_HTTPS,
405       net::SpawnedTestServer::kLocalhost,
406       base::FilePath(FILE_PATH_LITERAL("content/test/data")));
407   ASSERT_TRUE(https_server.Start());
408
409   // 1. Load an embedder page with one guest in it.
410   const char kEmbedderURL[] = "/browser_plugin_embedder.html";
411   StartBrowserPluginTest(kEmbedderURL, kHTMLForGuest, true, std::string());
412
413   // 2. Navigate to a URL in https, so we trigger a RenderViewHost swap.
414   GURL test_https_url(https_server.GetURL(
415       "files/browser_plugin_title_change.html"));
416   content::WindowedNotificationObserver swap_observer(
417       content::NOTIFICATION_RENDER_VIEW_HOST_CHANGED,
418       content::Source<WebContents>(test_embedder()->web_contents()));
419   NavigateToURL(shell(), test_https_url);
420   swap_observer.Wait();
421
422   TestBrowserPluginEmbedder* test_embedder_after_swap =
423       static_cast<TestBrowserPluginEmbedder*>(
424           static_cast<WebContentsImpl*>(shell()->web_contents())->
425               GetBrowserPluginEmbedder());
426   // Verify we have a no embedder in web_contents (since the new page doesn't
427   // have any browser plugin).
428   ASSERT_TRUE(!test_embedder_after_swap);
429   ASSERT_NE(test_embedder(), test_embedder_after_swap);
430 }
431
432 // This test opens two pages in http and there is no RenderViewHost swap,
433 // therefore the embedder created on first page navigation stays the same in
434 // web_contents.
435 // Failing flakily on Windows: crbug.com/308405
436 #if defined(OS_WIN)
437 #define MAYBE_EmbedderSameAfterNav DISABLED_EmbedderSameAfterNav
438 #else
439 #define MAYBE_EmbedderSameAfterNav EmbedderSameAfterNav
440 #endif
441 IN_PROC_BROWSER_TEST_F(BrowserPluginHostTest, MAYBE_EmbedderSameAfterNav) {
442   const char kEmbedderURL[] = "/browser_plugin_embedder.html";
443   StartBrowserPluginTest(kEmbedderURL, kHTMLForGuest, true, std::string());
444   WebContentsImpl* embedder_web_contents = test_embedder()->web_contents();
445
446   // Navigate to another page in same host and port, so RenderViewHost swap
447   // does not happen and existing embedder doesn't change in web_contents.
448   GURL test_url_new(embedded_test_server()->GetURL(
449       "/browser_plugin_title_change.html"));
450   const base::string16 expected_title = ASCIIToUTF16("done");
451   content::TitleWatcher title_watcher(shell()->web_contents(), expected_title);
452   NavigateToURL(shell(), test_url_new);
453   VLOG(0) << "Start waiting for title";
454   base::string16 actual_title = title_watcher.WaitAndGetTitle();
455   EXPECT_EQ(expected_title, actual_title);
456   VLOG(0) << "Done navigating to second page";
457
458   TestBrowserPluginEmbedder* test_embedder_after_nav =
459       static_cast<TestBrowserPluginEmbedder*>(
460           embedder_web_contents->GetBrowserPluginEmbedder());
461   // Embedder must not change in web_contents.
462   ASSERT_EQ(test_embedder_after_nav, test_embedder());
463 }
464
465 // This test verifies that hiding the embedder also hides the guest.
466 IN_PROC_BROWSER_TEST_F(BrowserPluginHostTest, BrowserPluginVisibilityChanged) {
467   const char kEmbedderURL[] = "/browser_plugin_embedder.html";
468   StartBrowserPluginTest(kEmbedderURL, kHTMLForGuest, true, std::string());
469
470   // Hide the Browser Plugin.
471   RenderViewHostImpl* rvh = static_cast<RenderViewHostImpl*>(
472       test_embedder()->web_contents()->GetRenderViewHost());
473   ExecuteSyncJSFunction(
474       rvh, "document.getElementById('plugin').style.visibility = 'hidden'");
475
476   // Make sure that the guest is hidden.
477   test_guest()->WaitUntilHidden();
478 }
479
480 IN_PROC_BROWSER_TEST_F(BrowserPluginHostTest, EmbedderVisibilityChanged) {
481   const char kEmbedderURL[] = "/browser_plugin_embedder.html";
482   StartBrowserPluginTest(kEmbedderURL, kHTMLForGuest, true, std::string());
483
484   // Hide the embedder.
485   test_embedder()->web_contents()->WasHidden();
486
487   // Make sure that hiding the embedder also hides the guest.
488   test_guest()->WaitUntilHidden();
489 }
490
491 // Verifies that installing/uninstalling touch-event handlers in the guest
492 // plugin correctly updates the touch-event handling state in the embedder.
493 IN_PROC_BROWSER_TEST_F(BrowserPluginHostTest, AcceptTouchEvents) {
494   const char kEmbedderURL[] = "/browser_plugin_embedder.html";
495   StartBrowserPluginTest(
496       kEmbedderURL, kHTMLForGuestTouchHandler, true, std::string());
497
498   RenderViewHostImpl* rvh = static_cast<RenderViewHostImpl*>(
499       test_embedder()->web_contents()->GetRenderViewHost());
500   // The embedder should not have any touch event handlers at this point.
501   EXPECT_FALSE(rvh->has_touch_handler());
502
503   // Install the touch handler in the guest. This should cause the embedder to
504   // start listening for touch events too.
505   MessageObserver observer(test_embedder()->web_contents(),
506                            ViewHostMsg_HasTouchEventHandlers::ID);
507   ExecuteSyncJSFunction(test_guest()->web_contents()->GetRenderViewHost(),
508                         "InstallTouchHandler();");
509   observer.WaitUntilMessageReceived();
510   EXPECT_TRUE(rvh->has_touch_handler());
511
512   // Uninstalling the touch-handler in guest should cause the embedder to stop
513   // listening for touch events.
514   observer.ResetState();
515   ExecuteSyncJSFunction(test_guest()->web_contents()->GetRenderViewHost(),
516                         "UninstallTouchHandler();");
517   observer.WaitUntilMessageReceived();
518   EXPECT_FALSE(rvh->has_touch_handler());
519 }
520
521 // This tests verifies that reloading the embedder does not crash the browser
522 // and that the guest is reset.
523 IN_PROC_BROWSER_TEST_F(BrowserPluginHostTest, DISABLED_ReloadEmbedder) {
524   const char kEmbedderURL[] = "/browser_plugin_embedder.html";
525   StartBrowserPluginTest(kEmbedderURL, kHTMLForGuest, true, std::string());
526   RenderViewHostImpl* rvh = static_cast<RenderViewHostImpl*>(
527       test_embedder()->web_contents()->GetRenderViewHost());
528
529   // Change the title of the page to 'modified' so that we know that
530   // the page has successfully reloaded when it goes back to 'embedder'
531   // in the next step.
532   {
533     const base::string16 expected_title = ASCIIToUTF16("modified");
534     content::TitleWatcher title_watcher(test_embedder()->web_contents(),
535                                         expected_title);
536
537     ExecuteSyncJSFunction(rvh,
538                           base::StringPrintf("SetTitle('%s');", "modified"));
539
540     base::string16 actual_title = title_watcher.WaitAndGetTitle();
541     EXPECT_EQ(expected_title, actual_title);
542   }
543
544   // Reload the embedder page, and verify that the reload was successful.
545   // Then navigate the guest to verify that the browser process does not crash.
546   {
547     const base::string16 expected_title = ASCIIToUTF16("embedder");
548     content::TitleWatcher title_watcher(test_embedder()->web_contents(),
549                                         expected_title);
550
551     test_embedder()->web_contents()->GetController().Reload(false);
552     base::string16 actual_title = title_watcher.WaitAndGetTitle();
553     EXPECT_EQ(expected_title, actual_title);
554
555     ExecuteSyncJSFunction(
556         test_embedder()->web_contents()->GetRenderViewHost(),
557         base::StringPrintf("SetSrc('%s');", kHTMLForGuest));
558     test_guest_manager()->WaitForGuestAdded();
559
560     const TestBrowserPluginGuestManager::GuestInstanceMap& instance_map =
561         test_guest_manager()->guest_web_contents_for_testing();
562     WebContentsImpl* test_guest_web_contents = static_cast<WebContentsImpl*>(
563         instance_map.begin()->second);
564     TestBrowserPluginGuest* new_test_guest =
565         static_cast<TestBrowserPluginGuest*>(
566           test_guest_web_contents->GetBrowserPluginGuest());
567     ASSERT_TRUE(new_test_guest != NULL);
568
569     // Wait for the guest to send an UpdateRectMsg, meaning it is ready.
570     new_test_guest->WaitForUpdateRectMsg();
571   }
572 }
573
574 // Always failing in the win7 try bot. See http://crbug.com/181107.
575 // Times out on the Mac. See http://crbug.com/297576.
576 #if defined(OS_WIN) || defined(OS_MACOSX)
577 #define MAYBE_AcceptDragEvents DISABLED_AcceptDragEvents
578 #else
579 #define MAYBE_AcceptDragEvents AcceptDragEvents
580 #endif
581
582 // Tests that a drag-n-drop over the browser plugin in the embedder happens
583 // correctly.
584 IN_PROC_BROWSER_TEST_F(BrowserPluginHostTest, MAYBE_AcceptDragEvents) {
585   const char kEmbedderURL[] = "/browser_plugin_dragging.html";
586   StartBrowserPluginTest(
587       kEmbedderURL, kHTMLForGuestAcceptDrag, true, std::string());
588
589   RenderViewHostImpl* rvh = static_cast<RenderViewHostImpl*>(
590       test_embedder()->web_contents()->GetRenderViewHost());
591
592   // Get a location in the embedder outside of the plugin.
593   base::ListValue *start, *end;
594   scoped_ptr<base::Value> value =
595       content::ExecuteScriptAndGetValue(rvh, "dragLocation()");
596   ASSERT_TRUE(value->GetAsList(&start) && start->GetSize() == 2);
597   double start_x, start_y;
598   ASSERT_TRUE(start->GetDouble(0, &start_x) && start->GetDouble(1, &start_y));
599
600   // Get a location in the embedder that falls inside the plugin.
601   value = content::ExecuteScriptAndGetValue(rvh, "dropLocation()");
602   ASSERT_TRUE(value->GetAsList(&end) && end->GetSize() == 2);
603   double end_x, end_y;
604   ASSERT_TRUE(end->GetDouble(0, &end_x) && end->GetDouble(1, &end_y));
605
606   DropData drop_data;
607   GURL url = GURL("https://www.domain.com/index.html");
608   drop_data.url = url;
609
610   // Pretend that the URL is being dragged over the embedder. Start the drag
611   // from outside the plugin, then move the drag inside the plugin and drop.
612   // This should trigger appropriate messages from the embedder to the guest,
613   // and end with a drop on the guest. The guest changes title when a drop
614   // happens.
615   const base::string16 expected_title = ASCIIToUTF16("DROPPED");
616   content::TitleWatcher title_watcher(test_guest()->web_contents(),
617       expected_title);
618
619   rvh->DragTargetDragEnter(drop_data, gfx::Point(start_x, start_y),
620       gfx::Point(start_x, start_y), blink::WebDragOperationEvery, 0);
621   rvh->DragTargetDragOver(gfx::Point(end_x, end_y), gfx::Point(end_x, end_y),
622       blink::WebDragOperationEvery, 0);
623   rvh->DragTargetDrop(gfx::Point(end_x, end_y), gfx::Point(end_x, end_y), 0);
624
625   base::string16 actual_title = title_watcher.WaitAndGetTitle();
626   EXPECT_EQ(expected_title, actual_title);
627 }
628
629 // This test verifies that round trip postMessage works as expected.
630 // 1. The embedder posts a message 'testing123' to the guest.
631 // 2. The guest receives and replies to the message using the event object's
632 // source object: event.source.postMessage('foobar', '*')
633 // 3. The embedder receives the message and uses the event's source
634 // object to do one final reply: 'stop'
635 // 4. The guest receives the final 'stop' message.
636 // 5. The guest acks the 'stop' message with a 'stop_ack' message.
637 // 6. The embedder changes its title to 'main guest' when it sees the 'stop_ack'
638 // message.
639 IN_PROC_BROWSER_TEST_F(BrowserPluginHostTest, PostMessage) {
640   const char* kTesting = "testing123";
641   const char* kEmbedderURL = "/browser_plugin_embedder.html";
642   const char* kGuestURL = "/browser_plugin_post_message_guest.html";
643   StartBrowserPluginTest(kEmbedderURL, kGuestURL, false, std::string());
644   RenderViewHostImpl* rvh = static_cast<RenderViewHostImpl*>(
645       test_embedder()->web_contents()->GetRenderViewHost());
646   {
647     const base::string16 expected_title = ASCIIToUTF16("main guest");
648     content::TitleWatcher title_watcher(test_embedder()->web_contents(),
649                                         expected_title);
650
651     // By the time we get here 'contentWindow' should be ready because the
652     // guest has completed loading.
653     ExecuteSyncJSFunction(
654         rvh, base::StringPrintf("PostMessage('%s, false');", kTesting));
655
656     // The title will be updated to "main guest" at the last stage of the
657     // process described above.
658     base::string16 actual_title = title_watcher.WaitAndGetTitle();
659     EXPECT_EQ(expected_title, actual_title);
660   }
661 }
662
663 // This is the same as BrowserPluginHostTest.PostMessage but also
664 // posts a message to an iframe.
665 // TODO(fsamuel): This test should replace the previous test once postMessage
666 // iframe targeting is fixed (see http://crbug.com/153701).
667 IN_PROC_BROWSER_TEST_F(BrowserPluginHostTest, DISABLED_PostMessageToIFrame) {
668   const char* kTesting = "testing123";
669   const char* kEmbedderURL = "/browser_plugin_embedder.html";
670   const char* kGuestURL = "/browser_plugin_post_message_guest.html";
671   StartBrowserPluginTest(kEmbedderURL, kGuestURL, false, std::string());
672   RenderViewHostImpl* rvh = static_cast<RenderViewHostImpl*>(
673       test_embedder()->web_contents()->GetRenderViewHost());
674   {
675     const base::string16 expected_title = ASCIIToUTF16("main guest");
676     content::TitleWatcher title_watcher(test_embedder()->web_contents(),
677                                         expected_title);
678
679     ExecuteSyncJSFunction(
680         rvh, base::StringPrintf("PostMessage('%s, false');", kTesting));
681
682     // The title will be updated to "main guest" at the last stage of the
683     // process described above.
684     base::string16 actual_title = title_watcher.WaitAndGetTitle();
685     EXPECT_EQ(expected_title, actual_title);
686   }
687   {
688     content::TitleWatcher ready_watcher(test_embedder()->web_contents(),
689                                         ASCIIToUTF16("ready"));
690
691     RenderViewHostImpl* guest_rvh = static_cast<RenderViewHostImpl*>(
692         test_guest()->web_contents()->GetRenderViewHost());
693     GURL test_url = embedded_test_server()->GetURL(
694         "/browser_plugin_post_message_guest.html");
695     ExecuteSyncJSFunction(
696         guest_rvh,
697         base::StringPrintf(
698             "CreateChildFrame('%s');", test_url.spec().c_str()));
699
700     base::string16 actual_title = ready_watcher.WaitAndGetTitle();
701     EXPECT_EQ(ASCIIToUTF16("ready"), actual_title);
702
703     content::TitleWatcher iframe_watcher(test_embedder()->web_contents(),
704                                         ASCIIToUTF16("iframe"));
705     ExecuteSyncJSFunction(
706         rvh, base::StringPrintf("PostMessage('%s', true);", kTesting));
707
708     // The title will be updated to "iframe" at the last stage of the
709     // process described above.
710     actual_title = iframe_watcher.WaitAndGetTitle();
711     EXPECT_EQ(ASCIIToUTF16("iframe"), actual_title);
712   }
713 }
714
715 // This test verifies that if a browser plugin is hidden before navigation,
716 // the guest starts off hidden.
717 IN_PROC_BROWSER_TEST_F(BrowserPluginHostTest, HiddenBeforeNavigation) {
718   const char* kEmbedderURL = "/browser_plugin_embedder.html";
719   const std::string embedder_code =
720       "document.getElementById('plugin').style.visibility = 'hidden'";
721   StartBrowserPluginTest(
722       kEmbedderURL, kHTMLForGuest, true, embedder_code);
723   EXPECT_FALSE(test_guest()->visible());
724 }
725
726 // This test verifies that if a browser plugin is focused before navigation then
727 // the guest starts off focused.
728 IN_PROC_BROWSER_TEST_F(BrowserPluginHostTest, FocusBeforeNavigation) {
729   const char* kEmbedderURL = "/browser_plugin_embedder.html";
730   const std::string embedder_code =
731       "document.getElementById('plugin').focus();";
732   StartBrowserPluginTest(
733       kEmbedderURL, kHTMLForGuest, true, embedder_code);
734   RenderViewHostImpl* guest_rvh = static_cast<RenderViewHostImpl*>(
735       test_guest()->web_contents()->GetRenderViewHost());
736   // Verify that the guest is focused.
737   scoped_ptr<base::Value> value =
738       content::ExecuteScriptAndGetValue(guest_rvh, "document.hasFocus()");
739   bool result = false;
740   ASSERT_TRUE(value->GetAsBoolean(&result));
741   EXPECT_TRUE(result);
742 }
743
744 IN_PROC_BROWSER_TEST_F(BrowserPluginHostTest, FocusTracksEmbedder) {
745   const char* kEmbedderURL = "/browser_plugin_embedder.html";
746   StartBrowserPluginTest(kEmbedderURL, kHTMLForGuest, true, std::string());
747   // Blur the embedder.
748   test_embedder()->web_contents()->GetRenderViewHost()->Blur();
749   // Ensure that the guest is also blurred.
750   test_guest()->WaitForBlur();
751 }
752
753 // Test for regression http://crbug.com/162961.
754 IN_PROC_BROWSER_TEST_F(BrowserPluginHostTest, GetRenderViewHostAtPositionTest) {
755   const char kEmbedderURL[] = "/browser_plugin_embedder.html";
756   const std::string embedder_code =
757       base::StringPrintf("SetSize(%d, %d);", 100, 100);
758   StartBrowserPluginTest(kEmbedderURL, kHTMLForGuestWithSize, true,
759                          embedder_code);
760   // Check for render view host at position (150, 150) that is outside the
761   // bounds of our guest, so this would respond with the render view host of the
762   // embedder.
763   test_embedder()->WaitForRenderViewHostAtPosition(150, 150);
764   ASSERT_EQ(test_embedder()->web_contents()->GetRenderViewHost(),
765             test_embedder()->last_rvh_at_position_response());
766 }
767
768 // This test verifies that if IME is enabled in the embedder, it is also enabled
769 // in the guest.
770 IN_PROC_BROWSER_TEST_F(BrowserPluginHostTest, VerifyInputMethodActive) {
771   const char* kEmbedderURL = "/browser_plugin_embedder.html";
772   StartBrowserPluginTest(kEmbedderURL, kHTMLForGuest, true, std::string());
773   RenderViewHostImpl* rvh = static_cast<RenderViewHostImpl*>(
774       test_guest()->web_contents()->GetRenderViewHost());
775   EXPECT_TRUE(rvh->input_method_active());
776 }
777
778 // Verify that navigating to an invalid URL (e.g. 'http:') doesn't cause
779 // a crash.
780 IN_PROC_BROWSER_TEST_F(BrowserPluginHostTest, DoNotCrashOnInvalidNavigation) {
781   const char kEmbedderURL[] = "/browser_plugin_embedder.html";
782   StartBrowserPluginTest(kEmbedderURL, kHTMLForGuest, true, std::string());
783   TestBrowserPluginGuestDelegate* delegate =
784       new TestBrowserPluginGuestDelegate();
785   test_guest()->SetDelegate(delegate);
786
787   const char kValidSchemeWithEmptyURL[] = "http:";
788   ExecuteSyncJSFunction(
789       test_embedder()->web_contents()->GetRenderViewHost(),
790       base::StringPrintf("SetSrc('%s');", kValidSchemeWithEmptyURL));
791   EXPECT_TRUE(delegate->load_aborted());
792   EXPECT_FALSE(delegate->load_aborted_url().is_valid());
793   EXPECT_EQ(kValidSchemeWithEmptyURL,
794             delegate->load_aborted_url().possibly_invalid_spec());
795
796   delegate->ResetStates();
797
798   // Attempt a navigation to chrome-guest://abc123, which is a valid URL. But it
799   // should be blocked because the scheme isn't web-safe or a pseudo-scheme.
800   ExecuteSyncJSFunction(
801       test_embedder()->web_contents()->GetRenderViewHost(),
802       base::StringPrintf("SetSrc('%s://abc123');", kGuestScheme));
803   EXPECT_TRUE(delegate->load_aborted());
804   EXPECT_TRUE(delegate->load_aborted_url().is_valid());
805 }
806
807 // Tests involving the threaded compositor.
808 class BrowserPluginThreadedCompositorTest : public BrowserPluginHostTest {
809  public:
810   BrowserPluginThreadedCompositorTest() {}
811   virtual ~BrowserPluginThreadedCompositorTest() {}
812
813  protected:
814   virtual void SetUpCommandLine(CommandLine* cmd) OVERRIDE {
815     BrowserPluginHostTest::SetUpCommandLine(cmd);
816     cmd->AppendSwitch(switches::kEnableThreadedCompositing);
817   }
818 };
819
820 class BrowserPluginThreadedCompositorPixelTest
821     : public BrowserPluginThreadedCompositorTest {
822  protected:
823   virtual void SetUp() OVERRIDE {
824     EnablePixelOutput();
825     BrowserPluginThreadedCompositorTest::SetUp();
826   }
827
828   virtual void SetUpCommandLine(CommandLine* cmd) OVERRIDE {
829     BrowserPluginThreadedCompositorTest::SetUpCommandLine(cmd);
830     // http://crbug.com/327035
831     cmd->AppendSwitch(switches::kDisableDelegatedRenderer);
832   }
833 };
834
835 static void CompareSkBitmaps(const SkBitmap& expected_bitmap,
836                              const SkBitmap& bitmap) {
837   EXPECT_EQ(expected_bitmap.width(), bitmap.width());
838   if (expected_bitmap.width() != bitmap.width())
839     return;
840   EXPECT_EQ(expected_bitmap.height(), bitmap.height());
841   if (expected_bitmap.height() != bitmap.height())
842     return;
843   EXPECT_EQ(expected_bitmap.config(), bitmap.config());
844   if (expected_bitmap.config() != bitmap.config())
845     return;
846
847   SkAutoLockPixels expected_bitmap_lock(expected_bitmap);
848   SkAutoLockPixels bitmap_lock(bitmap);
849   int fails = 0;
850   const int kAllowableError = 2;
851   for (int i = 0; i < bitmap.width() && fails < 10; ++i) {
852     for (int j = 0; j < bitmap.height() && fails < 10; ++j) {
853       SkColor expected_color = expected_bitmap.getColor(i, j);
854       SkColor color = bitmap.getColor(i, j);
855       int expected_alpha = SkColorGetA(expected_color);
856       int alpha = SkColorGetA(color);
857       int expected_red = SkColorGetR(expected_color);
858       int red = SkColorGetR(color);
859       int expected_green = SkColorGetG(expected_color);
860       int green = SkColorGetG(color);
861       int expected_blue = SkColorGetB(expected_color);
862       int blue = SkColorGetB(color);
863       EXPECT_NEAR(expected_alpha, alpha, kAllowableError)
864           << "expected_color: " << std::hex << expected_color
865           << " color: " <<  color
866           << " Failed at " << std::dec << i << ", " << j
867           << " Failure " << ++fails;
868       EXPECT_NEAR(expected_red, red, kAllowableError)
869           << "expected_color: " << std::hex << expected_color
870           << " color: " <<  color
871           << " Failed at " << std::dec << i << ", " << j
872           << " Failure " << ++fails;
873       EXPECT_NEAR(expected_green, green, kAllowableError)
874           << "expected_color: " << std::hex << expected_color
875           << " color: " <<  color
876           << " Failed at " << std::dec << i << ", " << j
877           << " Failure " << ++fails;
878       EXPECT_NEAR(expected_blue, blue, kAllowableError)
879           << "expected_color: " << std::hex << expected_color
880           << " color: " <<  color
881           << " Failed at " << std::dec << i << ", " << j
882           << " Failure " << ++fails;
883     }
884   }
885   EXPECT_LT(fails, 10);
886 }
887
888 static void CompareSkBitmapAndRun(const base::Closure& callback,
889                                   const SkBitmap& expected_bitmap,
890                                   bool *result,
891                                   bool succeed,
892                                   const SkBitmap& bitmap) {
893   *result = succeed;
894   if (succeed)
895     CompareSkBitmaps(expected_bitmap, bitmap);
896   callback.Run();
897 }
898
899 // http://crbug.com/171744
900 #if defined(OS_MACOSX)
901 #define MAYBE_GetBackingStore DISABLED_GetBackingStore
902 #else
903 #define MAYBE_GetBackingStore GetBackingStore
904 #endif
905 IN_PROC_BROWSER_TEST_F(BrowserPluginThreadedCompositorPixelTest,
906                        MAYBE_GetBackingStore) {
907   const char kEmbedderURL[] = "/browser_plugin_embedder.html";
908   const char kHTMLForGuest[] =
909       "data:text/html,<html><style>body { background-color: red; }</style>"
910       "<body></body></html>";
911   StartBrowserPluginTest(kEmbedderURL, kHTMLForGuest, true,
912                          std::string("SetSize(50, 60);"));
913
914   WebContentsImpl* guest_contents = test_guest()->web_contents();
915   RenderWidgetHostImpl* guest_widget_host =
916       RenderWidgetHostImpl::From(guest_contents->GetRenderViewHost());
917
918   SkBitmap expected_bitmap;
919   expected_bitmap.setConfig(SkBitmap::kARGB_8888_Config, 50, 60);
920   expected_bitmap.allocPixels();
921   expected_bitmap.eraseARGB(255, 255, 0, 0);  // #f00
922   bool result = false;
923   while (!result) {
924     base::RunLoop loop;
925     guest_widget_host->CopyFromBackingStore(gfx::Rect(),
926         guest_widget_host->GetView()->GetViewBounds().size(),
927         base::Bind(&CompareSkBitmapAndRun, loop.QuitClosure(), expected_bitmap,
928                    &result));
929     loop.Run();
930   }
931 }
932
933 // This test exercises the following scenario:
934 // 1. An <input> in guest has focus.
935 // 2. User takes focus to embedder by clicking e.g. an <input> in embedder.
936 // 3. User brings back the focus directly to the <input> in #1.
937 //
938 // Now we need to make sure TextInputTypeChange fires properly for the guest's
939 // view (RenderWidgetHostViewGuest) upon step #3. This test ensures that,
940 // otherwise IME doesn't work after step #3.
941 IN_PROC_BROWSER_TEST_F(BrowserPluginHostTest, FocusRestored) {
942   const char kEmbedderURL[] = "/browser_plugin_embedder.html";
943   const char kGuestHTML[] = "data:text/html,"
944       "<html><body><input id=\"input1\"></body>"
945       "<script>"
946       "var i = document.getElementById(\"input1\");"
947       "document.body.addEventListener(\"click\", function(e) {"
948       "  i.focus();"
949       "});"
950       "i.addEventListener(\"focus\", function(e) {"
951       "  document.title = \"FOCUS\";"
952       "});"
953       "i.addEventListener(\"blur\", function(e) {"
954       "  document.title = \"BLUR\";"
955       "});"
956       "</script>"
957       "</html>";
958   StartBrowserPluginTest(kEmbedderURL, kGuestHTML, true,
959                          "document.getElementById(\"plugin\").focus();");
960
961   ASSERT_TRUE(test_embedder());
962   const char *kTitles[3] = {"FOCUS", "BLUR", "FOCUS"};
963   gfx::Point kClickPoints[3] = {
964     gfx::Point(20, 20), gfx::Point(700, 20), gfx::Point(20, 20)
965   };
966
967   for (int i = 0; i < 3; ++i) {
968     base::string16 expected_title = base::UTF8ToUTF16(kTitles[i]);
969     content::TitleWatcher title_watcher(test_guest()->web_contents(),
970                                         expected_title);
971     SimulateMouseClickAt(test_embedder()->web_contents(), 0,
972         blink::WebMouseEvent::ButtonLeft,
973         kClickPoints[i]);
974     base::string16 actual_title = title_watcher.WaitAndGetTitle();
975     EXPECT_EQ(expected_title, actual_title);
976   }
977   TestBrowserPluginGuest* guest = test_guest();
978   ASSERT_TRUE(guest);
979   ui::TextInputType text_input_type = guest->last_text_input_type();
980   ASSERT_TRUE(text_input_type != ui::TEXT_INPUT_TYPE_NONE);
981 }
982
983 // Tests input method.
984 IN_PROC_BROWSER_TEST_F(BrowserPluginHostTest, InputMethod) {
985   const char kEmbedderURL[] = "/browser_plugin_embedder.html";
986   const char kGuestHTML[] = "data:text/html,"
987       "<html><body><input id=\"input1\">"
988       "<input id=\"input2\"></body>"
989       "<script>"
990       "var i = document.getElementById(\"input1\");"
991       "i.oninput = function() {"
992       "  document.title = i.value;"
993       "}"
994       "</script>"
995       "</html>";
996   StartBrowserPluginTest(kEmbedderURL, kGuestHTML, true,
997                          "document.getElementById(\"plugin\").focus();");
998
999   RenderViewHostImpl* embedder_rvh = static_cast<RenderViewHostImpl*>(
1000       test_embedder()->web_contents()->GetRenderViewHost());
1001   RenderViewHostImpl* guest_rvh = static_cast<RenderViewHostImpl*>(
1002       test_guest()->web_contents()->GetRenderViewHost());
1003
1004   std::vector<blink::WebCompositionUnderline> underlines;
1005
1006   // An input field in browser plugin guest gets focus and given some user
1007   // input via IME.
1008   {
1009     ExecuteSyncJSFunction(guest_rvh,
1010                           "document.getElementById('input1').focus();");
1011     base::string16 expected_title = base::UTF8ToUTF16("InputTest123");
1012     content::TitleWatcher title_watcher(test_guest()->web_contents(),
1013                                         expected_title);
1014     embedder_rvh->Send(
1015         new ViewMsg_ImeSetComposition(
1016             test_embedder()->web_contents()->GetRoutingID(),
1017             expected_title,
1018             underlines,
1019             12, 12));
1020     base::string16 actual_title = title_watcher.WaitAndGetTitle();
1021     EXPECT_EQ(expected_title, actual_title);
1022   }
1023   // A composition is committed via IME.
1024   {
1025     base::string16 expected_title = base::UTF8ToUTF16("InputTest456");
1026     content::TitleWatcher title_watcher(test_guest()->web_contents(),
1027                                         expected_title);
1028     embedder_rvh->Send(
1029         new ViewMsg_ImeConfirmComposition(
1030             test_embedder()->web_contents()->GetRoutingID(),
1031             expected_title,
1032             gfx::Range(),
1033             true));
1034     base::string16 actual_title = title_watcher.WaitAndGetTitle();
1035     EXPECT_EQ(expected_title, actual_title);
1036   }
1037   // IME composition starts, but focus moves out, then the composition will
1038   // be committed and get cancel msg.
1039   {
1040     ExecuteSyncJSFunction(guest_rvh,
1041                           "document.getElementById('input1').value = '';");
1042     base::string16 composition = base::UTF8ToUTF16("InputTest789");
1043     content::TitleWatcher title_watcher(test_guest()->web_contents(),
1044                                         composition);
1045     embedder_rvh->Send(
1046         new ViewMsg_ImeSetComposition(
1047             test_embedder()->web_contents()->GetRoutingID(),
1048             composition,
1049             underlines,
1050             12, 12));
1051     base::string16 actual_title = title_watcher.WaitAndGetTitle();
1052     EXPECT_EQ(composition, actual_title);
1053     // Moving focus causes IME cancel, and the composition will be committed
1054     // in input1, not in input2.
1055     ExecuteSyncJSFunction(guest_rvh,
1056                           "document.getElementById('input2').focus();");
1057     test_guest()->WaitForImeCancel();
1058     scoped_ptr<base::Value> value =
1059         content::ExecuteScriptAndGetValue(
1060             guest_rvh, "document.getElementById('input1').value");
1061     std::string result;
1062     ASSERT_TRUE(value->GetAsString(&result));
1063     EXPECT_EQ(base::UTF16ToUTF8(composition), result);
1064   }
1065   // Tests ExtendSelectionAndDelete message works in browser_plugin.
1066   {
1067     // Set 'InputTestABC' in input1 and put caret at 6 (after 'T').
1068     ExecuteSyncJSFunction(guest_rvh,
1069                           "var i = document.getElementById('input1');"
1070                           "i.focus();"
1071                           "i.value = 'InputTestABC';"
1072                           "i.selectionStart=6;"
1073                           "i.selectionEnd=6;");
1074     base::string16 expected_value = base::UTF8ToUTF16("InputABC");
1075     content::TitleWatcher title_watcher(test_guest()->web_contents(),
1076                                         expected_value);
1077     // Delete 'Test' in 'InputTestABC', as the caret is after 'T':
1078     // delete before 1 character ('T') and after 3 characters ('est').
1079     embedder_rvh->Send(
1080         new ViewMsg_ExtendSelectionAndDelete(
1081             test_embedder()->web_contents()->GetRoutingID(),
1082             1, 3));
1083     base::string16 actual_title = title_watcher.WaitAndGetTitle();
1084     EXPECT_EQ(expected_value, actual_title);
1085     scoped_ptr<base::Value> value =
1086         content::ExecuteScriptAndGetValue(
1087             guest_rvh, "document.getElementById('input1').value");
1088     std::string actual_value;
1089     ASSERT_TRUE(value->GetAsString(&actual_value));
1090     EXPECT_EQ(base::UTF16ToUTF8(expected_value), actual_value);
1091   }
1092 }
1093
1094 }  // namespace content