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.
5 #include "base/memory/singleton.h"
6 #include "base/run_loop.h"
7 #include "base/strings/string_split.h"
8 #include "base/strings/string_util.h"
9 #include "base/strings/utf_string_conversions.h"
10 #include "content/browser/browser_plugin/browser_plugin_embedder.h"
11 #include "content/browser/browser_plugin/browser_plugin_guest.h"
12 #include "content/browser/browser_plugin/browser_plugin_host_factory.h"
13 #include "content/browser/browser_plugin/test_browser_plugin_guest.h"
14 #include "content/browser/browser_plugin/test_guest_manager.h"
15 #include "content/browser/child_process_security_policy_impl.h"
16 #include "content/browser/renderer_host/render_view_host_impl.h"
17 #include "content/browser/web_contents/web_contents_impl.h"
18 #include "content/common/browser_plugin/browser_plugin_messages.h"
19 #include "content/common/view_messages.h"
20 #include "content/public/browser/notification_service.h"
21 #include "content/public/browser/notification_types.h"
22 #include "content/public/browser/render_frame_host.h"
23 #include "content/public/browser/render_widget_host_view.h"
24 #include "content/public/browser/web_contents_observer.h"
25 #include "content/public/common/drop_data.h"
26 #include "content/public/common/url_constants.h"
27 #include "content/public/test/browser_test_utils.h"
28 #include "content/public/test/content_browser_test.h"
29 #include "content/public/test/content_browser_test_utils.h"
30 #include "content/public/test/test_utils.h"
31 #include "content/shell/browser/shell.h"
32 #include "content/shell/browser/shell_browser_context.h"
33 #include "net/base/net_util.h"
34 #include "net/test/embedded_test_server/embedded_test_server.h"
35 #include "net/test/embedded_test_server/http_request.h"
36 #include "net/test/embedded_test_server/http_response.h"
37 #include "net/test/spawned_test_server/spawned_test_server.h"
38 #include "third_party/WebKit/public/web/WebInputEvent.h"
40 using base::ASCIIToUTF16
;
41 using blink::WebInputEvent
;
42 using blink::WebMouseEvent
;
43 using content::BrowserPluginEmbedder
;
44 using content::BrowserPluginGuest
;
45 using content::BrowserPluginHostFactory
;
46 using content::WebContentsImpl
;
48 const char kHTMLForGuest
[] =
49 "data:text/html,<html><body>hello world</body></html>";
51 const char kHTMLForGuestAcceptDrag
[] =
52 "data:text/html,<html><body>"
54 "function dropped() {"
55 " document.title = \"DROPPED\";"
58 "<textarea id=\"text\" style=\"width:100%; height: 100%\""
59 " ondrop=\"dropped();\">"
65 class TestBrowserPluginEmbedder
: public BrowserPluginEmbedder
{
67 TestBrowserPluginEmbedder(WebContentsImpl
* web_contents
)
68 : BrowserPluginEmbedder(web_contents
) {
71 virtual ~TestBrowserPluginEmbedder() {}
73 WebContentsImpl
* web_contents() const {
74 return static_cast<WebContentsImpl
*>(BrowserPluginEmbedder::web_contents());
78 DISALLOW_COPY_AND_ASSIGN(TestBrowserPluginEmbedder
);
81 // Test factory for creating test instances of BrowserPluginEmbedder and
82 // BrowserPluginGuest.
83 class TestBrowserPluginHostFactory
: public BrowserPluginHostFactory
{
85 virtual BrowserPluginGuest
* CreateBrowserPluginGuest(
87 WebContentsImpl
* web_contents
) OVERRIDE
{
88 return new TestBrowserPluginGuest(instance_id
, web_contents
);
91 // Also keeps track of number of instances created.
92 virtual BrowserPluginEmbedder
* CreateBrowserPluginEmbedder(
93 WebContentsImpl
* web_contents
) OVERRIDE
{
95 return new TestBrowserPluginEmbedder(web_contents
);
99 static TestBrowserPluginHostFactory
* GetInstance() {
100 return Singleton
<TestBrowserPluginHostFactory
>::get();
104 TestBrowserPluginHostFactory() {}
105 virtual ~TestBrowserPluginHostFactory() {}
109 friend struct DefaultSingletonTraits
<TestBrowserPluginHostFactory
>;
111 scoped_refptr
<MessageLoopRunner
> message_loop_runner_
;
113 DISALLOW_COPY_AND_ASSIGN(TestBrowserPluginHostFactory
);
116 class BrowserPluginHostTest
: public ContentBrowserTest
{
118 BrowserPluginHostTest()
119 : test_embedder_(NULL
),
121 test_guest_manager_(NULL
) {}
123 virtual void SetUp() OVERRIDE
{
124 // Override factory to create tests instances of BrowserPlugin*.
125 BrowserPluginEmbedder::set_factory_for_testing(
126 TestBrowserPluginHostFactory::GetInstance());
127 BrowserPluginGuest::set_factory_for_testing(
128 TestBrowserPluginHostFactory::GetInstance());
129 ContentBrowserTest::SetUp();
131 virtual void TearDown() OVERRIDE
{
132 BrowserPluginEmbedder::set_factory_for_testing(NULL
);
133 BrowserPluginGuest::set_factory_for_testing(NULL
);
135 ContentBrowserTest::TearDown();
138 static void SimulateSpaceKeyPress(WebContents
* web_contents
) {
139 SimulateKeyPress(web_contents
,
147 static void SimulateTabKeyPress(WebContents
* web_contents
) {
148 SimulateKeyPress(web_contents
,
156 // Executes the JavaScript synchronously and makes sure the returned value is
158 void ExecuteSyncJSFunction(RenderFrameHost
* rfh
, const std::string
& jscript
) {
159 scoped_ptr
<base::Value
> value
=
160 content::ExecuteScriptAndGetValue(rfh
, jscript
);
163 // This helper method does the following:
164 // 1. Start the test server and navigate the shell to |embedder_url|.
165 // 2. Execute custom pre-navigation |embedder_code| if provided.
166 // 3. Navigate the guest to the |guest_url|.
167 // 4. Verify that the guest has been created and has completed loading.
168 void StartBrowserPluginTest(const std::string
& embedder_url
,
169 const std::string
& guest_url
,
170 bool is_guest_data_url
,
171 const std::string
& embedder_code
) {
172 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
173 GURL
test_url(embedded_test_server()->GetURL(embedder_url
));
174 NavigateToURL(shell(), test_url
);
176 WebContentsImpl
* embedder_web_contents
= static_cast<WebContentsImpl
*>(
177 shell()->web_contents());
178 static_cast<ShellBrowserContext
*>(
179 embedder_web_contents
->GetBrowserContext())->
180 set_guest_manager_for_testing(
181 TestGuestManager::GetInstance());
182 RenderViewHostImpl
* rvh
= static_cast<RenderViewHostImpl
*>(
183 embedder_web_contents
->GetRenderViewHost());
184 RenderFrameHost
* rfh
= embedder_web_contents
->GetMainFrame();
185 // Focus the embedder.
188 rvh
->SetInputMethodActive(true);
190 // Allow the test to do some operations on the embedder before we perform
191 // the first navigation of the guest.
192 if (!embedder_code
.empty())
193 ExecuteSyncJSFunction(rfh
, embedder_code
);
195 if (!is_guest_data_url
) {
196 test_url
= embedded_test_server()->GetURL(guest_url
);
197 ExecuteSyncJSFunction(
198 rfh
, base::StringPrintf("SetSrc('%s');", test_url
.spec().c_str()));
200 ExecuteSyncJSFunction(
201 rfh
, base::StringPrintf("SetSrc('%s');", guest_url
.c_str()));
204 test_embedder_
= static_cast<TestBrowserPluginEmbedder
*>(
205 embedder_web_contents
->GetBrowserPluginEmbedder());
206 ASSERT_TRUE(test_embedder_
);
208 test_guest_manager_
=
209 static_cast<TestGuestManager
*>(
210 embedder_web_contents
->GetBrowserContext()->GetGuestManager());
212 WebContentsImpl
* test_guest_web_contents
=
213 test_guest_manager_
->WaitForGuestAdded();
215 test_guest_
= static_cast<TestBrowserPluginGuest
*>(
216 test_guest_web_contents
->GetBrowserPluginGuest());
217 test_guest_
->WaitForLoadStop();
220 TestBrowserPluginEmbedder
* test_embedder() const { return test_embedder_
; }
221 TestBrowserPluginGuest
* test_guest() const { return test_guest_
; }
222 TestGuestManager
* test_guest_manager() const {
223 return test_guest_manager_
;
227 TestBrowserPluginEmbedder
* test_embedder_
;
228 TestBrowserPluginGuest
* test_guest_
;
229 TestGuestManager
* test_guest_manager_
;
230 DISALLOW_COPY_AND_ASSIGN(BrowserPluginHostTest
);
233 IN_PROC_BROWSER_TEST_F(BrowserPluginHostTest
, AdvanceFocus
) {
234 const char kEmbedderURL
[] = "/browser_plugin_focus.html";
235 const char* kGuestURL
= "/browser_plugin_focus_child.html";
236 StartBrowserPluginTest(kEmbedderURL
, kGuestURL
, false, std::string());
238 SimulateMouseClick(test_embedder()->web_contents(), 0,
239 blink::WebMouseEvent::ButtonLeft
);
240 BrowserPluginHostTest::SimulateTabKeyPress(test_embedder()->web_contents());
241 // Wait until we focus into the guest.
242 test_guest()->WaitForFocus();
244 // TODO(fsamuel): A third Tab key press should not be necessary.
245 // The browser plugin will take keyboard focus but it will not
246 // focus an initial element. The initial element is dependent
247 // upon tab direction which WebKit does not propagate to the plugin.
248 // See http://crbug.com/147644.
249 BrowserPluginHostTest::SimulateTabKeyPress(test_embedder()->web_contents());
250 BrowserPluginHostTest::SimulateTabKeyPress(test_embedder()->web_contents());
251 BrowserPluginHostTest::SimulateTabKeyPress(test_embedder()->web_contents());
252 test_guest()->WaitForAdvanceFocus();
255 // This test opens a page in http and then opens another page in https, forcing
256 // a RenderViewHost swap in the web_contents. We verify that the embedder in the
257 // web_contents gets cleared properly.
258 IN_PROC_BROWSER_TEST_F(BrowserPluginHostTest
, EmbedderChangedAfterSwap
) {
259 net::SpawnedTestServer
https_server(
260 net::SpawnedTestServer::TYPE_HTTPS
,
261 net::SpawnedTestServer::kLocalhost
,
262 base::FilePath(FILE_PATH_LITERAL("content/test/data")));
263 ASSERT_TRUE(https_server
.Start());
265 // 1. Load an embedder page with one guest in it.
266 const char kEmbedderURL
[] = "/browser_plugin_embedder.html";
267 StartBrowserPluginTest(kEmbedderURL
, kHTMLForGuest
, true, std::string());
269 // 2. Navigate to a URL in https, so we trigger a RenderViewHost swap.
270 GURL
test_https_url(https_server
.GetURL(
271 "files/browser_plugin_title_change.html"));
272 content::WindowedNotificationObserver
swap_observer(
273 content::NOTIFICATION_RENDER_VIEW_HOST_CHANGED
,
274 content::Source
<WebContents
>(test_embedder()->web_contents()));
275 NavigateToURL(shell(), test_https_url
);
276 swap_observer
.Wait();
278 TestBrowserPluginEmbedder
* test_embedder_after_swap
=
279 static_cast<TestBrowserPluginEmbedder
*>(
280 static_cast<WebContentsImpl
*>(shell()->web_contents())->
281 GetBrowserPluginEmbedder());
282 // Verify we have a no embedder in web_contents (since the new page doesn't
283 // have any browser plugin).
284 ASSERT_TRUE(!test_embedder_after_swap
);
285 ASSERT_NE(test_embedder(), test_embedder_after_swap
);
288 // This test opens two pages in http and there is no RenderViewHost swap,
289 // therefore the embedder created on first page navigation stays the same in
291 // Failing flakily on Windows: crbug.com/308405
293 #define MAYBE_EmbedderSameAfterNav DISABLED_EmbedderSameAfterNav
295 #define MAYBE_EmbedderSameAfterNav EmbedderSameAfterNav
297 IN_PROC_BROWSER_TEST_F(BrowserPluginHostTest
, MAYBE_EmbedderSameAfterNav
) {
298 const char kEmbedderURL
[] = "/browser_plugin_embedder.html";
299 StartBrowserPluginTest(kEmbedderURL
, kHTMLForGuest
, true, std::string());
300 WebContentsImpl
* embedder_web_contents
= test_embedder()->web_contents();
302 // Navigate to another page in same host and port, so RenderViewHost swap
303 // does not happen and existing embedder doesn't change in web_contents.
304 GURL
test_url_new(embedded_test_server()->GetURL(
305 "/browser_plugin_title_change.html"));
306 const base::string16 expected_title
= ASCIIToUTF16("done");
307 content::TitleWatcher
title_watcher(shell()->web_contents(), expected_title
);
308 NavigateToURL(shell(), test_url_new
);
309 VLOG(0) << "Start waiting for title";
310 base::string16 actual_title
= title_watcher
.WaitAndGetTitle();
311 EXPECT_EQ(expected_title
, actual_title
);
312 VLOG(0) << "Done navigating to second page";
314 TestBrowserPluginEmbedder
* test_embedder_after_nav
=
315 static_cast<TestBrowserPluginEmbedder
*>(
316 embedder_web_contents
->GetBrowserPluginEmbedder());
317 // Embedder must not change in web_contents.
318 ASSERT_EQ(test_embedder_after_nav
, test_embedder());
321 // This tests verifies that reloading the embedder does not crash the browser
322 // and that the guest is reset.
323 IN_PROC_BROWSER_TEST_F(BrowserPluginHostTest
, DISABLED_ReloadEmbedder
) {
324 const char kEmbedderURL
[] = "/browser_plugin_embedder.html";
325 StartBrowserPluginTest(kEmbedderURL
, kHTMLForGuest
, true, std::string());
326 RenderFrameHost
* rfh
= test_embedder()->web_contents()->GetMainFrame();
328 // Change the title of the page to 'modified' so that we know that
329 // the page has successfully reloaded when it goes back to 'embedder'
332 const base::string16 expected_title
= ASCIIToUTF16("modified");
333 content::TitleWatcher
title_watcher(test_embedder()->web_contents(),
336 ExecuteSyncJSFunction(rfh
,
337 base::StringPrintf("SetTitle('%s');", "modified"));
339 base::string16 actual_title
= title_watcher
.WaitAndGetTitle();
340 EXPECT_EQ(expected_title
, actual_title
);
343 // Reload the embedder page, and verify that the reload was successful.
344 // Then navigate the guest to verify that the browser process does not crash.
346 const base::string16 expected_title
= ASCIIToUTF16("embedder");
347 content::TitleWatcher
title_watcher(test_embedder()->web_contents(),
350 test_embedder()->web_contents()->GetController().Reload(false);
351 base::string16 actual_title
= title_watcher
.WaitAndGetTitle();
352 EXPECT_EQ(expected_title
, actual_title
);
354 ExecuteSyncJSFunction(
355 test_embedder()->web_contents()->GetMainFrame(),
356 base::StringPrintf("SetSrc('%s');", kHTMLForGuest
));
358 WebContentsImpl
* test_guest_web_contents
= static_cast<WebContentsImpl
*>(
359 test_guest_manager()->WaitForGuestAdded());
360 TestBrowserPluginGuest
* new_test_guest
=
361 static_cast<TestBrowserPluginGuest
*>(
362 test_guest_web_contents
->GetBrowserPluginGuest());
363 ASSERT_TRUE(new_test_guest
!= NULL
);
365 // Wait for the guest to send an UpdateRectMsg, meaning it is ready.
366 new_test_guest
->WaitForUpdateRectMsg();
370 // Always failing in the win7 try bot. See http://crbug.com/181107.
371 // Times out on the Mac. See http://crbug.com/297576.
372 #if defined(OS_WIN) || defined(OS_MACOSX)
373 #define MAYBE_AcceptDragEvents DISABLED_AcceptDragEvents
375 #define MAYBE_AcceptDragEvents AcceptDragEvents
378 // Tests that a drag-n-drop over the browser plugin in the embedder happens
380 IN_PROC_BROWSER_TEST_F(BrowserPluginHostTest
, MAYBE_AcceptDragEvents
) {
381 const char kEmbedderURL
[] = "/browser_plugin_dragging.html";
382 StartBrowserPluginTest(
383 kEmbedderURL
, kHTMLForGuestAcceptDrag
, true, std::string());
385 RenderViewHostImpl
* rvh
= static_cast<RenderViewHostImpl
*>(
386 test_embedder()->web_contents()->GetRenderViewHost());
387 RenderFrameHost
* rfh
= test_embedder()->web_contents()->GetMainFrame();
389 // Get a location in the embedder outside of the plugin.
390 base::ListValue
*start
, *end
;
391 scoped_ptr
<base::Value
> value
=
392 content::ExecuteScriptAndGetValue(rfh
, "dragLocation()");
393 ASSERT_TRUE(value
->GetAsList(&start
) && start
->GetSize() == 2);
394 double start_x
, start_y
;
395 ASSERT_TRUE(start
->GetDouble(0, &start_x
) && start
->GetDouble(1, &start_y
));
397 // Get a location in the embedder that falls inside the plugin.
398 value
= content::ExecuteScriptAndGetValue(rfh
, "dropLocation()");
399 ASSERT_TRUE(value
->GetAsList(&end
) && end
->GetSize() == 2);
401 ASSERT_TRUE(end
->GetDouble(0, &end_x
) && end
->GetDouble(1, &end_y
));
404 GURL url
= GURL("https://www.domain.com/index.html");
407 // Pretend that the URL is being dragged over the embedder. Start the drag
408 // from outside the plugin, then move the drag inside the plugin and drop.
409 // This should trigger appropriate messages from the embedder to the guest,
410 // and end with a drop on the guest. The guest changes title when a drop
412 const base::string16 expected_title
= ASCIIToUTF16("DROPPED");
413 content::TitleWatcher
title_watcher(test_guest()->web_contents(),
416 rvh
->DragTargetDragEnter(drop_data
, gfx::Point(start_x
, start_y
),
417 gfx::Point(start_x
, start_y
), blink::WebDragOperationEvery
, 0);
418 rvh
->DragTargetDragOver(gfx::Point(end_x
, end_y
), gfx::Point(end_x
, end_y
),
419 blink::WebDragOperationEvery
, 0);
420 rvh
->DragTargetDrop(gfx::Point(end_x
, end_y
), gfx::Point(end_x
, end_y
), 0);
422 base::string16 actual_title
= title_watcher
.WaitAndGetTitle();
423 EXPECT_EQ(expected_title
, actual_title
);
426 // This test verifies that round trip postMessage works as expected.
427 // 1. The embedder posts a message 'testing123' to the guest.
428 // 2. The guest receives and replies to the message using the event object's
429 // source object: event.source.postMessage('foobar', '*')
430 // 3. The embedder receives the message and uses the event's source
431 // object to do one final reply: 'stop'
432 // 4. The guest receives the final 'stop' message.
433 // 5. The guest acks the 'stop' message with a 'stop_ack' message.
434 // 6. The embedder changes its title to 'main guest' when it sees the 'stop_ack'
436 IN_PROC_BROWSER_TEST_F(BrowserPluginHostTest
, PostMessage
) {
437 const char* kTesting
= "testing123";
438 const char* kEmbedderURL
= "/browser_plugin_embedder.html";
439 const char* kGuestURL
= "/browser_plugin_post_message_guest.html";
440 StartBrowserPluginTest(kEmbedderURL
, kGuestURL
, false, std::string());
441 RenderFrameHost
* rfh
= test_embedder()->web_contents()->GetMainFrame();
443 const base::string16 expected_title
= ASCIIToUTF16("main guest");
444 content::TitleWatcher
title_watcher(test_embedder()->web_contents(),
447 // By the time we get here 'contentWindow' should be ready because the
448 // guest has completed loading.
449 ExecuteSyncJSFunction(
450 rfh
, base::StringPrintf("PostMessage('%s, false');", kTesting
));
452 // The title will be updated to "main guest" at the last stage of the
453 // process described above.
454 base::string16 actual_title
= title_watcher
.WaitAndGetTitle();
455 EXPECT_EQ(expected_title
, actual_title
);
459 // This is the same as BrowserPluginHostTest.PostMessage but also
460 // posts a message to an iframe.
461 // TODO(fsamuel): This test should replace the previous test once postMessage
462 // iframe targeting is fixed (see http://crbug.com/153701).
463 IN_PROC_BROWSER_TEST_F(BrowserPluginHostTest
, DISABLED_PostMessageToIFrame
) {
464 const char* kTesting
= "testing123";
465 const char* kEmbedderURL
= "/browser_plugin_embedder.html";
466 const char* kGuestURL
= "/browser_plugin_post_message_guest.html";
467 StartBrowserPluginTest(kEmbedderURL
, kGuestURL
, false, std::string());
468 RenderFrameHost
* rfh
= test_embedder()->web_contents()->GetMainFrame();
470 const base::string16 expected_title
= ASCIIToUTF16("main guest");
471 content::TitleWatcher
title_watcher(test_embedder()->web_contents(),
474 ExecuteSyncJSFunction(
475 rfh
, base::StringPrintf("PostMessage('%s, false');", kTesting
));
477 // The title will be updated to "main guest" at the last stage of the
478 // process described above.
479 base::string16 actual_title
= title_watcher
.WaitAndGetTitle();
480 EXPECT_EQ(expected_title
, actual_title
);
483 content::TitleWatcher
ready_watcher(test_embedder()->web_contents(),
484 ASCIIToUTF16("ready"));
486 RenderFrameHost
* guest_rfh
=
487 test_guest()->web_contents()->GetMainFrame();
488 GURL test_url
= embedded_test_server()->GetURL(
489 "/browser_plugin_post_message_guest.html");
490 ExecuteSyncJSFunction(
493 "CreateChildFrame('%s');", test_url
.spec().c_str()));
495 base::string16 actual_title
= ready_watcher
.WaitAndGetTitle();
496 EXPECT_EQ(ASCIIToUTF16("ready"), actual_title
);
498 content::TitleWatcher
iframe_watcher(test_embedder()->web_contents(),
499 ASCIIToUTF16("iframe"));
500 ExecuteSyncJSFunction(
501 rfh
, base::StringPrintf("PostMessage('%s', true);", kTesting
));
503 // The title will be updated to "iframe" at the last stage of the
504 // process described above.
505 actual_title
= iframe_watcher
.WaitAndGetTitle();
506 EXPECT_EQ(ASCIIToUTF16("iframe"), actual_title
);
510 // This test verifies that if a browser plugin is hidden before navigation,
511 // the guest starts off hidden.
512 IN_PROC_BROWSER_TEST_F(BrowserPluginHostTest
, HiddenBeforeNavigation
) {
513 const char* kEmbedderURL
= "/browser_plugin_embedder.html";
514 const std::string embedder_code
=
515 "document.getElementById('plugin').style.visibility = 'hidden'";
516 StartBrowserPluginTest(
517 kEmbedderURL
, kHTMLForGuest
, true, embedder_code
);
518 EXPECT_FALSE(test_guest()->visible());
521 // This test verifies that if a browser plugin is focused before navigation then
522 // the guest starts off focused.
523 IN_PROC_BROWSER_TEST_F(BrowserPluginHostTest
, FocusBeforeNavigation
) {
524 const char* kEmbedderURL
= "/browser_plugin_embedder.html";
525 const std::string embedder_code
=
526 "document.getElementById('plugin').focus();";
527 StartBrowserPluginTest(
528 kEmbedderURL
, kHTMLForGuest
, true, embedder_code
);
529 RenderFrameHost
* guest_rfh
= test_guest()->web_contents()->GetMainFrame();
530 // Verify that the guest is focused.
531 scoped_ptr
<base::Value
> value
=
532 content::ExecuteScriptAndGetValue(guest_rfh
, "document.hasFocus()");
534 ASSERT_TRUE(value
->GetAsBoolean(&result
));
538 IN_PROC_BROWSER_TEST_F(BrowserPluginHostTest
, FocusTracksEmbedder
) {
539 const char* kEmbedderURL
= "/browser_plugin_embedder.html";
540 StartBrowserPluginTest(kEmbedderURL
, kHTMLForGuest
, true, std::string());
541 // Blur the embedder.
542 test_embedder()->web_contents()->GetRenderViewHost()->Blur();
543 // Ensure that the guest is also blurred.
544 test_guest()->WaitForBlur();
547 // This test verifies that if IME is enabled in the embedder, it is also enabled
549 IN_PROC_BROWSER_TEST_F(BrowserPluginHostTest
, VerifyInputMethodActive
) {
550 const char* kEmbedderURL
= "/browser_plugin_embedder.html";
551 StartBrowserPluginTest(kEmbedderURL
, kHTMLForGuest
, true, std::string());
552 RenderViewHostImpl
* rvh
= static_cast<RenderViewHostImpl
*>(
553 test_guest()->web_contents()->GetRenderViewHost());
554 EXPECT_TRUE(rvh
->input_method_active());
557 // This test exercises the following scenario:
558 // 1. An <input> in guest has focus.
559 // 2. User takes focus to embedder by clicking e.g. an <input> in embedder.
560 // 3. User brings back the focus directly to the <input> in #1.
562 // Now we need to make sure TextInputTypeChange fires properly for the guest's
563 // view (RenderWidgetHostViewGuest) upon step #3. This test ensures that,
564 // otherwise IME doesn't work after step #3.
565 IN_PROC_BROWSER_TEST_F(BrowserPluginHostTest
, FocusRestored
) {
566 const char kEmbedderURL
[] = "/browser_plugin_embedder.html";
567 const char kGuestHTML
[] = "data:text/html,"
568 "<html><body><input id=\"input1\"></body>"
570 "var i = document.getElementById(\"input1\");"
571 "document.body.addEventListener(\"click\", function(e) {"
574 "i.addEventListener(\"focus\", function(e) {"
575 " document.title = \"FOCUS\";"
577 "i.addEventListener(\"blur\", function(e) {"
578 " document.title = \"BLUR\";"
582 StartBrowserPluginTest(kEmbedderURL
, kGuestHTML
, true,
583 "document.getElementById(\"plugin\").focus();");
585 ASSERT_TRUE(test_embedder());
586 const char *kTitles
[3] = {"FOCUS", "BLUR", "FOCUS"};
587 gfx::Point kClickPoints
[3] = {
588 gfx::Point(20, 20), gfx::Point(700, 20), gfx::Point(20, 20)
591 for (int i
= 0; i
< 3; ++i
) {
592 base::string16 expected_title
= base::UTF8ToUTF16(kTitles
[i
]);
593 content::TitleWatcher
title_watcher(test_guest()->web_contents(),
595 SimulateMouseClickAt(test_embedder()->web_contents(), 0,
596 blink::WebMouseEvent::ButtonLeft
,
598 base::string16 actual_title
= title_watcher
.WaitAndGetTitle();
599 EXPECT_EQ(expected_title
, actual_title
);
601 TestBrowserPluginGuest
* guest
= test_guest();
603 ui::TextInputType text_input_type
= guest
->last_text_input_type();
604 ASSERT_TRUE(text_input_type
!= ui::TEXT_INPUT_TYPE_NONE
);
607 // Tests input method.
608 IN_PROC_BROWSER_TEST_F(BrowserPluginHostTest
, InputMethod
) {
609 const char kEmbedderURL
[] = "/browser_plugin_embedder.html";
610 const char kGuestHTML
[] = "data:text/html,"
611 "<html><body><input id=\"input1\">"
612 "<input id=\"input2\"></body>"
614 "var i = document.getElementById(\"input1\");"
615 "i.oninput = function() {"
616 " document.title = i.value;"
620 StartBrowserPluginTest(kEmbedderURL
, kGuestHTML
, true,
621 "document.getElementById(\"plugin\").focus();");
623 RenderViewHostImpl
* embedder_rvh
= static_cast<RenderViewHostImpl
*>(
624 test_embedder()->web_contents()->GetRenderViewHost());
625 RenderFrameHost
* guest_rfh
= test_guest()->web_contents()->GetMainFrame();
627 std::vector
<blink::WebCompositionUnderline
> underlines
;
629 // An input field in browser plugin guest gets focus and given some user
632 ExecuteSyncJSFunction(guest_rfh
,
633 "document.getElementById('input1').focus();");
634 base::string16 expected_title
= base::UTF8ToUTF16("InputTest123");
635 content::TitleWatcher
title_watcher(test_guest()->web_contents(),
638 new ViewMsg_ImeSetComposition(
639 test_embedder()->web_contents()->GetRoutingID(),
643 base::string16 actual_title
= title_watcher
.WaitAndGetTitle();
644 EXPECT_EQ(expected_title
, actual_title
);
646 // A composition is committed via IME.
648 base::string16 expected_title
= base::UTF8ToUTF16("InputTest456");
649 content::TitleWatcher
title_watcher(test_guest()->web_contents(),
652 new ViewMsg_ImeConfirmComposition(
653 test_embedder()->web_contents()->GetRoutingID(),
657 base::string16 actual_title
= title_watcher
.WaitAndGetTitle();
658 EXPECT_EQ(expected_title
, actual_title
);
660 // IME composition starts, but focus moves out, then the composition will
661 // be committed and get cancel msg.
663 ExecuteSyncJSFunction(guest_rfh
,
664 "document.getElementById('input1').value = '';");
665 base::string16 composition
= base::UTF8ToUTF16("InputTest789");
666 content::TitleWatcher
title_watcher(test_guest()->web_contents(),
669 new ViewMsg_ImeSetComposition(
670 test_embedder()->web_contents()->GetRoutingID(),
674 base::string16 actual_title
= title_watcher
.WaitAndGetTitle();
675 EXPECT_EQ(composition
, actual_title
);
676 // Moving focus causes IME cancel, and the composition will be committed
677 // in input1, not in input2.
678 ExecuteSyncJSFunction(guest_rfh
,
679 "document.getElementById('input2').focus();");
680 test_guest()->WaitForImeCancel();
681 scoped_ptr
<base::Value
> value
=
682 content::ExecuteScriptAndGetValue(
683 guest_rfh
, "document.getElementById('input1').value");
685 ASSERT_TRUE(value
->GetAsString(&result
));
686 EXPECT_EQ(base::UTF16ToUTF8(composition
), result
);
688 // Tests ExtendSelectionAndDelete message works in browser_plugin.
690 // Set 'InputTestABC' in input1 and put caret at 6 (after 'T').
691 ExecuteSyncJSFunction(guest_rfh
,
692 "var i = document.getElementById('input1');"
694 "i.value = 'InputTestABC';"
695 "i.selectionStart=6;"
696 "i.selectionEnd=6;");
697 base::string16 expected_value
= base::UTF8ToUTF16("InputABC");
698 content::TitleWatcher
title_watcher(test_guest()->web_contents(),
700 // Delete 'Test' in 'InputTestABC', as the caret is after 'T':
701 // delete before 1 character ('T') and after 3 characters ('est').
702 RenderFrameHostImpl
* rfh
= static_cast<RenderFrameHostImpl
*>(
703 test_embedder()->web_contents()->GetFocusedFrame());
704 rfh
->ExtendSelectionAndDelete(1, 3);
705 base::string16 actual_title
= title_watcher
.WaitAndGetTitle();
706 EXPECT_EQ(expected_value
, actual_title
);
707 scoped_ptr
<base::Value
> value
=
708 content::ExecuteScriptAndGetValue(
709 guest_rfh
, "document.getElementById('input1').value");
710 std::string actual_value
;
711 ASSERT_TRUE(value
->GetAsString(&actual_value
));
712 EXPECT_EQ(base::UTF16ToUTF8(expected_value
), actual_value
);
716 } // namespace content