1 // Copyright (c) 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 "content/renderer/browser_plugin/browser_plugin_browsertest.h"
7 #include "base/debug/leak_annotations.h"
8 #include "base/files/file_path.h"
9 #include "base/memory/singleton.h"
10 #include "base/path_service.h"
11 #include "base/pickle.h"
12 #include "content/public/common/content_constants.h"
13 #include "content/public/renderer/content_renderer_client.h"
14 #include "content/renderer/browser_plugin/browser_plugin.h"
15 #include "content/renderer/browser_plugin/browser_plugin_manager_factory.h"
16 #include "content/renderer/browser_plugin/mock_browser_plugin.h"
17 #include "content/renderer/browser_plugin/mock_browser_plugin_manager.h"
18 #include "content/renderer/render_thread_impl.h"
19 #include "content/renderer/renderer_webkitplatformsupport_impl.h"
20 #include "skia/ext/platform_canvas.h"
21 #include "third_party/WebKit/public/platform/WebCursorInfo.h"
22 #include "third_party/WebKit/public/web/WebInputEvent.h"
23 #include "third_party/WebKit/public/web/WebLocalFrame.h"
24 #include "third_party/WebKit/public/web/WebScriptSource.h"
29 const char kHTMLForBrowserPluginObject
[] =
30 "<object id='browserplugin' width='640px' height='480px'"
31 " src='foo' type='%s'></object>"
32 "<script>document.querySelector('object').nonExistentAttribute;</script>";
34 const char kHTMLForSourcelessPluginObject
[] =
35 "<object id='browserplugin' width='640px' height='480px' type='%s'>";
37 std::string
GetHTMLForBrowserPluginObject() {
38 return base::StringPrintf(kHTMLForBrowserPluginObject
,
39 kBrowserPluginMimeType
);
44 // Test factory for creating test instances of BrowserPluginManager.
45 class TestBrowserPluginManagerFactory
: public BrowserPluginManagerFactory
{
47 virtual MockBrowserPluginManager
* CreateBrowserPluginManager(
48 RenderViewImpl
* render_view
) OVERRIDE
{
49 return new MockBrowserPluginManager(render_view
);
53 static TestBrowserPluginManagerFactory
* GetInstance() {
54 return Singleton
<TestBrowserPluginManagerFactory
>::get();
58 TestBrowserPluginManagerFactory() {}
59 virtual ~TestBrowserPluginManagerFactory() {}
63 friend struct DefaultSingletonTraits
<TestBrowserPluginManagerFactory
>;
65 DISALLOW_COPY_AND_ASSIGN(TestBrowserPluginManagerFactory
);
68 BrowserPluginTest::BrowserPluginTest() {}
70 BrowserPluginTest::~BrowserPluginTest() {}
72 void BrowserPluginTest::SetUp() {
73 BrowserPluginManager::set_factory_for_testing(
74 TestBrowserPluginManagerFactory::GetInstance());
75 content::RenderViewTest::SetUp();
78 void BrowserPluginTest::TearDown() {
79 BrowserPluginManager::set_factory_for_testing(
80 TestBrowserPluginManagerFactory::GetInstance());
81 #if defined(LEAK_SANITIZER)
82 // Do this before shutting down V8 in RenderViewTest::TearDown().
83 // http://crbug.com/328552
84 __lsan_do_leak_check();
86 RenderViewTest::TearDown();
89 std::string
BrowserPluginTest::ExecuteScriptAndReturnString(
90 const std::string
& script
) {
91 v8::HandleScope
handle_scope(v8::Isolate::GetCurrent());
92 v8::Handle
<v8::Value
> value
= GetMainFrame()->executeScriptAndReturnValue(
93 blink::WebScriptSource(blink::WebString::fromUTF8(script
.c_str())));
94 if (value
.IsEmpty() || !value
->IsString())
97 v8::Local
<v8::String
> v8_str
= value
->ToString();
98 int length
= v8_str
->Utf8Length() + 1;
99 scoped_ptr
<char[]> str(new char[length
]);
100 v8_str
->WriteUtf8(str
.get(), length
);
104 int BrowserPluginTest::ExecuteScriptAndReturnInt(
105 const std::string
& script
) {
106 v8::HandleScope
handle_scope(v8::Isolate::GetCurrent());
107 v8::Handle
<v8::Value
> value
= GetMainFrame()->executeScriptAndReturnValue(
108 blink::WebScriptSource(blink::WebString::fromUTF8(script
.c_str())));
109 if (value
.IsEmpty() || !value
->IsInt32())
112 return value
->Int32Value();
115 // A return value of false means that a value was not present. The return value
116 // of the script is stored in |result|
117 bool BrowserPluginTest::ExecuteScriptAndReturnBool(
118 const std::string
& script
, bool* result
) {
119 v8::HandleScope
handle_scope(v8::Isolate::GetCurrent());
120 v8::Handle
<v8::Value
> value
= GetMainFrame()->executeScriptAndReturnValue(
121 blink::WebScriptSource(blink::WebString::fromUTF8(script
.c_str())));
122 if (value
.IsEmpty() || !value
->IsBoolean())
125 *result
= value
->BooleanValue();
129 MockBrowserPlugin
* BrowserPluginTest::GetCurrentPlugin() {
130 BrowserPluginHostMsg_Attach_Params params
;
131 return GetCurrentPluginWithAttachParams(¶ms
);
134 MockBrowserPlugin
* BrowserPluginTest::GetCurrentPluginWithAttachParams(
135 BrowserPluginHostMsg_Attach_Params
* params
) {
136 MockBrowserPlugin
* browser_plugin
= static_cast<MockBrowserPluginManager
*>(
137 browser_plugin_manager())->last_plugin();
141 browser_plugin
->Attach();
144 const IPC::Message
* msg
=
145 browser_plugin_manager()->sink().GetUniqueMessageMatching(
146 BrowserPluginHostMsg_Attach::ID
);
150 PickleIterator
iter(*msg
);
151 if (!iter
.ReadInt(&instance_id
))
154 if (!IPC::ParamTraits
<BrowserPluginHostMsg_Attach_Params
>::Read(
155 msg
, &iter
, params
)) {
159 browser_plugin
->OnAttachACK(instance_id
);
160 return browser_plugin
;
163 // This test verifies that an initial resize occurs when we instantiate the
165 TEST_F(BrowserPluginTest
, InitialResize
) {
166 LoadHTML(GetHTMLForBrowserPluginObject().c_str());
167 // Verify that the information in Attach is correct.
168 BrowserPluginHostMsg_Attach_Params params
;
169 MockBrowserPlugin
* browser_plugin
= GetCurrentPluginWithAttachParams(¶ms
);
171 EXPECT_EQ(640, params
.resize_guest_params
.view_size
.width());
172 EXPECT_EQ(480, params
.resize_guest_params
.view_size
.height());
173 ASSERT_TRUE(browser_plugin
);
176 TEST_F(BrowserPluginTest
, ResizeFlowControl
) {
177 LoadHTML(GetHTMLForBrowserPluginObject().c_str());
178 MockBrowserPlugin
* browser_plugin
= GetCurrentPlugin();
179 ASSERT_TRUE(browser_plugin
);
180 int instance_id
= browser_plugin
->browser_plugin_instance_id();
181 // Send an UpdateRect to the BrowserPlugin to make sure the browser sees a
182 // resize related (SetAutoSize) message.
184 // We send a stale UpdateRect to the BrowserPlugin.
185 BrowserPluginMsg_UpdateRect_Params update_rect_params
;
186 update_rect_params
.view_size
= gfx::Size(640, 480);
187 update_rect_params
.scale_factor
= 1.0f
;
188 update_rect_params
.is_resize_ack
= true;
189 BrowserPluginMsg_UpdateRect
msg(instance_id
, update_rect_params
);
190 browser_plugin
->OnMessageReceived(msg
);
193 browser_plugin_manager()->sink().ClearMessages();
195 // Resize the browser plugin three times.
197 ExecuteJavaScript("document.getElementById('browserplugin').width = '641px'");
198 GetMainFrame()->view()->layout();
199 ProcessPendingMessages();
201 ExecuteJavaScript("document.getElementById('browserplugin').width = '642px'");
202 GetMainFrame()->view()->layout();
203 ProcessPendingMessages();
205 ExecuteJavaScript("document.getElementById('browserplugin').width = '643px'");
206 GetMainFrame()->view()->layout();
207 ProcessPendingMessages();
209 // Expect to see one resize messsage in the sink. BrowserPlugin will not issue
210 // subsequent resize requests until the first request is satisfied by the
211 // guest. The rest of the messages could be
212 // BrowserPluginHostMsg_UpdateGeometry msgs.
213 EXPECT_LE(1u, browser_plugin_manager()->sink().message_count());
214 for (size_t i
= 0; i
< browser_plugin_manager()->sink().message_count();
216 const IPC::Message
* msg
= browser_plugin_manager()->sink().GetMessageAt(i
);
217 if (msg
->type() != BrowserPluginHostMsg_ResizeGuest::ID
)
218 EXPECT_EQ(msg
->type(), BrowserPluginHostMsg_UpdateGeometry::ID
);
220 const IPC::Message
* msg
=
221 browser_plugin_manager()->sink().GetUniqueMessageMatching(
222 BrowserPluginHostMsg_ResizeGuest::ID
);
224 BrowserPluginHostMsg_ResizeGuest::Param param
;
225 BrowserPluginHostMsg_ResizeGuest::Read(msg
, ¶m
);
226 instance_id
= param
.a
;
227 BrowserPluginHostMsg_ResizeGuest_Params params
= param
.b
;
228 EXPECT_EQ(641, params
.view_size
.width());
229 EXPECT_EQ(480, params
.view_size
.height());
232 // We send a stale UpdateRect to the BrowserPlugin.
233 BrowserPluginMsg_UpdateRect_Params update_rect_params
;
234 update_rect_params
.view_size
= gfx::Size(641, 480);
235 update_rect_params
.scale_factor
= 1.0f
;
236 update_rect_params
.is_resize_ack
= true;
237 BrowserPluginMsg_UpdateRect
msg(instance_id
, update_rect_params
);
238 browser_plugin
->OnMessageReceived(msg
);
240 // Send the BrowserPlugin another UpdateRect, but this time with a size
241 // that matches the size of the container.
243 BrowserPluginMsg_UpdateRect_Params update_rect_params
;
244 update_rect_params
.view_size
= gfx::Size(643, 480);
245 update_rect_params
.scale_factor
= 1.0f
;
246 update_rect_params
.is_resize_ack
= true;
247 BrowserPluginMsg_UpdateRect
msg(instance_id
, update_rect_params
);
248 browser_plugin
->OnMessageReceived(msg
);
252 TEST_F(BrowserPluginTest
, RemovePlugin
) {
253 LoadHTML(GetHTMLForBrowserPluginObject().c_str());
254 MockBrowserPlugin
* browser_plugin
= GetCurrentPlugin();
255 ASSERT_TRUE(browser_plugin
);
257 EXPECT_FALSE(browser_plugin_manager()->sink().GetUniqueMessageMatching(
258 BrowserPluginHostMsg_PluginDestroyed::ID
));
259 ExecuteJavaScript("x = document.getElementById('browserplugin'); "
260 "x.parentNode.removeChild(x);");
261 ProcessPendingMessages();
262 EXPECT_TRUE(browser_plugin_manager()->sink().GetUniqueMessageMatching(
263 BrowserPluginHostMsg_PluginDestroyed::ID
));
266 // This test verifies that PluginDestroyed messages do not get sent from a
267 // BrowserPlugin that has never navigated.
268 TEST_F(BrowserPluginTest
, RemovePluginBeforeNavigation
) {
269 std::string html
= base::StringPrintf(kHTMLForSourcelessPluginObject
,
270 kBrowserPluginMimeType
);
271 LoadHTML(html
.c_str());
272 EXPECT_FALSE(browser_plugin_manager()->sink().GetUniqueMessageMatching(
273 BrowserPluginHostMsg_PluginDestroyed::ID
));
274 ExecuteJavaScript("x = document.getElementById('browserplugin'); "
275 "x.parentNode.removeChild(x);");
276 ProcessPendingMessages();
277 EXPECT_FALSE(browser_plugin_manager()->sink().GetUniqueMessageMatching(
278 BrowserPluginHostMsg_PluginDestroyed::ID
));
281 } // namespace content