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.
4
5 #include "content/renderer/browser_plugin/browser_plugin_browsertest.h"
6
7 #include "base/files/file_path.h"
8 #include "base/memory/singleton.h"
9 #include "base/path_service.h"
10 #include "base/pickle.h"
11 #include "content/public/common/content_constants.h"
12 #include "content/renderer/browser_plugin/browser_plugin.h"
13 #include "content/renderer/browser_plugin/browser_plugin_manager_factory.h"
14 #include "content/renderer/browser_plugin/mock_browser_plugin.h"
15 #include "content/renderer/browser_plugin/mock_browser_plugin_manager.h"
16 #include "content/renderer/render_thread_impl.h"
17 #include "content/renderer/renderer_webkitplatformsupport_impl.h"
18 #include "skia/ext/platform_canvas.h"
19 #include "third_party/WebKit/public/platform/WebCursorInfo.h"
20 #include "third_party/WebKit/public/web/WebInputEvent.h"
21 #include "third_party/WebKit/public/web/WebScriptSource.h"
22
23 namespace {
24 const char kHTMLForBrowserPluginObject[] =
25 "<object id='browserplugin' width='640px' height='480px'"
26 " src='foo' type='%s'></object>"
27 "<script>document.querySelector('object').nonExistentAttribute;</script>";
28
29 const char kHTMLForBrowserPluginWithAllAttributes[] =
30 "<object id='browserplugin' width='640' height='480' type='%s'"
31 " autosize maxheight='600' maxwidth='800' minheight='240'"
32 " minwidth='320' name='Jim' partition='someid' src='foo'>";
33
34 const char kHTMLForSourcelessPluginObject[] =
35 "<object id='browserplugin' width='640px' height='480px' type='%s'>";
36
37 const char kHTMLForPartitionedPluginObject[] =
38 "<object id='browserplugin' width='640px' height='480px'"
39 " src='foo' type='%s' partition='someid'>";
40
41 const char kHTMLForInvalidPartitionedPluginObject[] =
42 "<object id='browserplugin' width='640px' height='480px'"
43 " type='%s' partition='persist:'>";
44
45 const char kHTMLForPartitionedPersistedPluginObject[] =
46 "<object id='browserplugin' width='640px' height='480px'"
47 " src='foo' type='%s' partition='persist:someid'>";
48
GetHTMLForBrowserPluginObject()49 std::string GetHTMLForBrowserPluginObject() {
50 return base::StringPrintf(kHTMLForBrowserPluginObject,
51 content::kBrowserPluginMimeType);
52 }
53
54 } // namespace
55
56 namespace content {
57
58 class TestContentRendererClient : public ContentRendererClient {
59 public:
TestContentRendererClient()60 TestContentRendererClient() : ContentRendererClient() {
61 }
~TestContentRendererClient()62 virtual ~TestContentRendererClient() {
63 }
AllowBrowserPlugin(blink::WebPluginContainer * container)64 virtual bool AllowBrowserPlugin(
65 blink::WebPluginContainer* container) OVERRIDE {
66 // Allow BrowserPlugin for tests.
67 return true;
68 }
69 };
70
71 // Test factory for creating test instances of BrowserPluginManager.
72 class TestBrowserPluginManagerFactory : public BrowserPluginManagerFactory {
73 public:
CreateBrowserPluginManager(RenderViewImpl * render_view)74 virtual MockBrowserPluginManager* CreateBrowserPluginManager(
75 RenderViewImpl* render_view) OVERRIDE {
76 return new MockBrowserPluginManager(render_view);
77 }
78
79 // Singleton getter.
GetInstance()80 static TestBrowserPluginManagerFactory* GetInstance() {
81 return Singleton<TestBrowserPluginManagerFactory>::get();
82 }
83
84 protected:
TestBrowserPluginManagerFactory()85 TestBrowserPluginManagerFactory() {}
~TestBrowserPluginManagerFactory()86 virtual ~TestBrowserPluginManagerFactory() {}
87
88 private:
89 // For Singleton.
90 friend struct DefaultSingletonTraits<TestBrowserPluginManagerFactory>;
91
92 DISALLOW_COPY_AND_ASSIGN(TestBrowserPluginManagerFactory);
93 };
94
BrowserPluginTest()95 BrowserPluginTest::BrowserPluginTest() {}
96
~BrowserPluginTest()97 BrowserPluginTest::~BrowserPluginTest() {}
98
SetUp()99 void BrowserPluginTest::SetUp() {
100 test_content_renderer_client_.reset(new TestContentRendererClient);
101 SetRendererClientForTesting(test_content_renderer_client_.get());
102 BrowserPluginManager::set_factory_for_testing(
103 TestBrowserPluginManagerFactory::GetInstance());
104 content::RenderViewTest::SetUp();
105 }
106
TearDown()107 void BrowserPluginTest::TearDown() {
108 BrowserPluginManager::set_factory_for_testing(
109 TestBrowserPluginManagerFactory::GetInstance());
110 content::RenderViewTest::TearDown();
111 test_content_renderer_client_.reset();
112 }
113
ExecuteScriptAndReturnString(const std::string & script)114 std::string BrowserPluginTest::ExecuteScriptAndReturnString(
115 const std::string& script) {
116 v8::HandleScope handle_scope(v8::Isolate::GetCurrent());
117 v8::Handle<v8::Value> value = GetMainFrame()->executeScriptAndReturnValue(
118 blink::WebScriptSource(blink::WebString::fromUTF8(script.c_str())));
119 if (value.IsEmpty() || !value->IsString())
120 return std::string();
121
122 v8::Local<v8::String> v8_str = value->ToString();
123 int length = v8_str->Utf8Length() + 1;
124 scoped_ptr<char[]> str(new char[length]);
125 v8_str->WriteUtf8(str.get(), length);
126 return str.get();
127 }
128
ExecuteScriptAndReturnInt(const std::string & script)129 int BrowserPluginTest::ExecuteScriptAndReturnInt(
130 const std::string& script) {
131 v8::HandleScope handle_scope(v8::Isolate::GetCurrent());
132 v8::Handle<v8::Value> value = GetMainFrame()->executeScriptAndReturnValue(
133 blink::WebScriptSource(blink::WebString::fromUTF8(script.c_str())));
134 if (value.IsEmpty() || !value->IsInt32())
135 return 0;
136
137 return value->Int32Value();
138 }
139
140 // A return value of false means that a value was not present. The return value
141 // of the script is stored in |result|
ExecuteScriptAndReturnBool(const std::string & script,bool * result)142 bool BrowserPluginTest::ExecuteScriptAndReturnBool(
143 const std::string& script, bool* result) {
144 v8::HandleScope handle_scope(v8::Isolate::GetCurrent());
145 v8::Handle<v8::Value> value = GetMainFrame()->executeScriptAndReturnValue(
146 blink::WebScriptSource(blink::WebString::fromUTF8(script.c_str())));
147 if (value.IsEmpty() || !value->IsBoolean())
148 return false;
149
150 *result = value->BooleanValue();
151 return true;
152 }
153
GetCurrentPlugin()154 MockBrowserPlugin* BrowserPluginTest::GetCurrentPlugin() {
155 BrowserPluginHostMsg_Attach_Params params;
156 return GetCurrentPluginWithAttachParams(¶ms);
157 }
158
GetCurrentPluginWithAttachParams(BrowserPluginHostMsg_Attach_Params * params)159 MockBrowserPlugin* BrowserPluginTest::GetCurrentPluginWithAttachParams(
160 BrowserPluginHostMsg_Attach_Params* params) {
161 int instance_id = 0;
162 const IPC::Message* msg =
163 browser_plugin_manager()->sink().GetUniqueMessageMatching(
164 BrowserPluginHostMsg_Attach::ID);
165 if (!msg)
166 return NULL;
167
168 PickleIterator iter(*msg);
169 if (!iter.ReadInt(&instance_id))
170 return NULL;
171
172 if (!IPC::ParamTraits<BrowserPluginHostMsg_Attach_Params>::Read(
173 msg, &iter, params))
174 return NULL;
175
176 MockBrowserPlugin* browser_plugin = static_cast<MockBrowserPlugin*>(
177 browser_plugin_manager()->GetBrowserPlugin(instance_id));
178
179 BrowserPluginMsg_Attach_ACK_Params attach_ack_params;
180 browser_plugin->OnAttachACK(instance_id, attach_ack_params);
181
182 return browser_plugin;
183 }
184
185 // This test verifies that an initial resize occurs when we instantiate the
186 // browser plugin. This test also verifies that the browser plugin is waiting
187 // for a BrowserPluginMsg_UpdateRect in response. We issue an UpdateRect, and
188 // we observe an UpdateRect_ACK, with the |pending_damage_buffer_| reset,
189 // indiciating that the BrowserPlugin is not waiting for any more UpdateRects to
190 // satisfy its resize request.
TEST_F(BrowserPluginTest,InitialResize)191 TEST_F(BrowserPluginTest, InitialResize) {
192 LoadHTML(GetHTMLForBrowserPluginObject().c_str());
193 // Verify that the information in Attach is correct.
194 BrowserPluginHostMsg_Attach_Params params;
195 MockBrowserPlugin* browser_plugin = GetCurrentPluginWithAttachParams(¶ms);
196
197 EXPECT_EQ(640, params.resize_guest_params.view_rect.width());
198 EXPECT_EQ(480, params.resize_guest_params.view_rect.height());
199 ASSERT_TRUE(browser_plugin);
200 // Now the browser plugin is expecting a UpdateRect resize.
201 int instance_id = browser_plugin->guest_instance_id();
202 EXPECT_TRUE(browser_plugin->pending_damage_buffer_.get());
203
204 // Send the BrowserPlugin an UpdateRect equal to its container size with
205 // the same damage buffer. That should clear |pending_damage_buffer_|.
206 BrowserPluginMsg_UpdateRect_Params update_rect_params;
207 update_rect_params.damage_buffer_sequence_id =
208 browser_plugin->damage_buffer_sequence_id_;
209 update_rect_params.view_size = gfx::Size(640, 480);
210 update_rect_params.scale_factor = 1.0f;
211 update_rect_params.is_resize_ack = true;
212 update_rect_params.needs_ack = true;
213 BrowserPluginMsg_UpdateRect msg(instance_id, update_rect_params);
214 browser_plugin->OnMessageReceived(msg);
215 EXPECT_FALSE(browser_plugin->pending_damage_buffer_.get());
216 }
217
218 // This test verifies that all attributes (present at the time of writing) are
219 // parsed on initialization. However, this test does minimal checking of
220 // correct behavior.
TEST_F(BrowserPluginTest,ParseAllAttributes)221 TEST_F(BrowserPluginTest, ParseAllAttributes) {
222 std::string html = base::StringPrintf(kHTMLForBrowserPluginWithAllAttributes,
223 content::kBrowserPluginMimeType);
224 LoadHTML(html.c_str());
225 bool result;
226 bool has_value = ExecuteScriptAndReturnBool(
227 "document.getElementById('browserplugin').autosize", &result);
228 EXPECT_TRUE(has_value);
229 EXPECT_TRUE(result);
230 int maxHeight = ExecuteScriptAndReturnInt(
231 "document.getElementById('browserplugin').maxheight");
232 EXPECT_EQ(600, maxHeight);
233 int maxWidth = ExecuteScriptAndReturnInt(
234 "document.getElementById('browserplugin').maxwidth");
235 EXPECT_EQ(800, maxWidth);
236 int minHeight = ExecuteScriptAndReturnInt(
237 "document.getElementById('browserplugin').minheight");
238 EXPECT_EQ(240, minHeight);
239 int minWidth = ExecuteScriptAndReturnInt(
240 "document.getElementById('browserplugin').minwidth");
241 EXPECT_EQ(320, minWidth);
242 std::string name = ExecuteScriptAndReturnString(
243 "document.getElementById('browserplugin').name");
244 EXPECT_STREQ("Jim", name.c_str());
245 std::string partition = ExecuteScriptAndReturnString(
246 "document.getElementById('browserplugin').partition");
247 EXPECT_STREQ("someid", partition.c_str());
248 std::string src = ExecuteScriptAndReturnString(
249 "document.getElementById('browserplugin').src");
250 EXPECT_STREQ("foo", src.c_str());
251 }
252
253 // Verify that the src attribute on the browser plugin works as expected.
TEST_F(BrowserPluginTest,SrcAttribute)254 TEST_F(BrowserPluginTest, SrcAttribute) {
255 LoadHTML(GetHTMLForBrowserPluginObject().c_str());
256 // Verify that we're reporting the correct URL to navigate to based on the
257 // src attribute.
258 {
259 BrowserPluginHostMsg_Attach_Params params;
260 MockBrowserPlugin* browser_plugin =
261 GetCurrentPluginWithAttachParams(¶ms);
262 ASSERT_TRUE(browser_plugin);
263 EXPECT_EQ("foo", params.src);
264 }
265
266 browser_plugin_manager()->sink().ClearMessages();
267 // Navigate to bar and observe the associated
268 // BrowserPluginHostMsg_NavigateGuest message.
269 // Verify that the src attribute is updated as well.
270 ExecuteJavaScript("document.getElementById('browserplugin').src = 'bar'");
271 {
272 // Verify that we do not get a Attach on subsequent navigations.
273 const IPC::Message* create_msg =
274 browser_plugin_manager()->sink().GetUniqueMessageMatching(
275 BrowserPluginHostMsg_Attach::ID);
276 ASSERT_FALSE(create_msg);
277
278 const IPC::Message* msg =
279 browser_plugin_manager()->sink().GetUniqueMessageMatching(
280 BrowserPluginHostMsg_NavigateGuest::ID);
281 ASSERT_TRUE(msg);
282
283 int instance_id = 0;
284 std::string src;
285 BrowserPluginHostMsg_NavigateGuest::Read(msg, &instance_id, &src);
286 EXPECT_EQ("bar", src);
287 std::string src_value =
288 ExecuteScriptAndReturnString(
289 "document.getElementById('browserplugin').src");
290 EXPECT_EQ("bar", src_value);
291 }
292 }
293
TEST_F(BrowserPluginTest,ResizeFlowControl)294 TEST_F(BrowserPluginTest, ResizeFlowControl) {
295 LoadHTML(GetHTMLForBrowserPluginObject().c_str());
296 MockBrowserPlugin* browser_plugin = GetCurrentPlugin();
297 ASSERT_TRUE(browser_plugin);
298 int instance_id = browser_plugin->guest_instance_id();
299 EXPECT_TRUE(browser_plugin->pending_damage_buffer_.get());
300 // Send an UpdateRect to the BrowserPlugin to make it use the pending damage
301 // buffer.
302 {
303 // We send a stale UpdateRect to the BrowserPlugin.
304 BrowserPluginMsg_UpdateRect_Params update_rect_params;
305 update_rect_params.view_size = gfx::Size(640, 480);
306 update_rect_params.scale_factor = 1.0f;
307 update_rect_params.is_resize_ack = true;
308 update_rect_params.needs_ack = true;
309 // By sending |damage_buffer_sequence_id| back to BrowserPlugin on
310 // UpdateRect, then the BrowserPlugin knows that the browser process has
311 // received and has begun to use the |pending_damage_buffer_|.
312 update_rect_params.damage_buffer_sequence_id =
313 browser_plugin->damage_buffer_sequence_id_;
314 BrowserPluginMsg_UpdateRect msg(instance_id, update_rect_params);
315 browser_plugin->OnMessageReceived(msg);
316 EXPECT_EQ(NULL, browser_plugin->pending_damage_buffer_.get());
317 }
318
319 browser_plugin_manager()->sink().ClearMessages();
320
321 // Resize the browser plugin three times.
322 ExecuteJavaScript("document.getElementById('browserplugin').width = '641px'");
323 ProcessPendingMessages();
324 ExecuteJavaScript("document.getElementById('browserplugin').width = '642px'");
325 ProcessPendingMessages();
326 ExecuteJavaScript("document.getElementById('browserplugin').width = '643px'");
327 ProcessPendingMessages();
328
329 // Expect to see one resize messsage in the sink. BrowserPlugin will not issue
330 // subsequent resize requests until the first request is satisfied by the
331 // guest. The rest of the messages could be
332 // BrowserPluginHostMsg_UpdateGeometry msgs.
333 EXPECT_LE(1u, browser_plugin_manager()->sink().message_count());
334 for (size_t i = 0; i < browser_plugin_manager()->sink().message_count();
335 ++i) {
336 const IPC::Message* msg = browser_plugin_manager()->sink().GetMessageAt(i);
337 if (msg->type() != BrowserPluginHostMsg_ResizeGuest::ID)
338 EXPECT_EQ(msg->type(), BrowserPluginHostMsg_UpdateGeometry::ID);
339 }
340 const IPC::Message* msg =
341 browser_plugin_manager()->sink().GetUniqueMessageMatching(
342 BrowserPluginHostMsg_ResizeGuest::ID);
343 ASSERT_TRUE(msg);
344 BrowserPluginHostMsg_ResizeGuest_Params params;
345 BrowserPluginHostMsg_ResizeGuest::Read(msg, &instance_id, ¶ms);
346 EXPECT_EQ(641, params.view_rect.width());
347 EXPECT_EQ(480, params.view_rect.height());
348 // This indicates that the BrowserPlugin has sent out a previous resize
349 // request but has not yet received an UpdateRect for that request.
350 EXPECT_TRUE(browser_plugin->pending_damage_buffer_.get());
351
352 {
353 // We send a stale UpdateRect to the BrowserPlugin.
354 BrowserPluginMsg_UpdateRect_Params update_rect_params;
355 update_rect_params.view_size = gfx::Size(641, 480);
356 update_rect_params.scale_factor = 1.0f;
357 update_rect_params.is_resize_ack = true;
358 update_rect_params.needs_ack = true;
359 update_rect_params.damage_buffer_sequence_id =
360 browser_plugin->damage_buffer_sequence_id_;
361 BrowserPluginMsg_UpdateRect msg(instance_id, update_rect_params);
362 browser_plugin->OnMessageReceived(msg);
363 // This tells us that the BrowserPlugin is still expecting another
364 // UpdateRect with the most recent size.
365 EXPECT_TRUE(browser_plugin->pending_damage_buffer_.get());
366 }
367 // Send the BrowserPlugin another UpdateRect, but this time with a size
368 // that matches the size of the container.
369 {
370 BrowserPluginMsg_UpdateRect_Params update_rect_params;
371 update_rect_params.view_size = gfx::Size(643, 480);
372 update_rect_params.scale_factor = 1.0f;
373 update_rect_params.is_resize_ack = true;
374 update_rect_params.needs_ack = true;
375 update_rect_params.damage_buffer_sequence_id =
376 browser_plugin->damage_buffer_sequence_id_;
377 BrowserPluginMsg_UpdateRect msg(instance_id, update_rect_params);
378 browser_plugin->OnMessageReceived(msg);
379 // The BrowserPlugin has finally received an UpdateRect that satisifes
380 // its current size, and so it is happy.
381 EXPECT_FALSE(browser_plugin->pending_damage_buffer_.get());
382 }
383 }
384
TEST_F(BrowserPluginTest,RemovePlugin)385 TEST_F(BrowserPluginTest, RemovePlugin) {
386 LoadHTML(GetHTMLForBrowserPluginObject().c_str());
387 EXPECT_FALSE(browser_plugin_manager()->sink().GetUniqueMessageMatching(
388 BrowserPluginHostMsg_PluginDestroyed::ID));
389 ExecuteJavaScript("x = document.getElementById('browserplugin'); "
390 "x.parentNode.removeChild(x);");
391 ProcessPendingMessages();
392 EXPECT_TRUE(browser_plugin_manager()->sink().GetUniqueMessageMatching(
393 BrowserPluginHostMsg_PluginDestroyed::ID));
394 }
395
396 // This test verifies that PluginDestroyed messages do not get sent from a
397 // BrowserPlugin that has never navigated.
TEST_F(BrowserPluginTest,RemovePluginBeforeNavigation)398 TEST_F(BrowserPluginTest, RemovePluginBeforeNavigation) {
399 std::string html = base::StringPrintf(kHTMLForSourcelessPluginObject,
400 content::kBrowserPluginMimeType);
401 LoadHTML(html.c_str());
402 EXPECT_FALSE(browser_plugin_manager()->sink().GetUniqueMessageMatching(
403 BrowserPluginHostMsg_PluginDestroyed::ID));
404 ExecuteJavaScript("x = document.getElementById('browserplugin'); "
405 "x.parentNode.removeChild(x);");
406 ProcessPendingMessages();
407 EXPECT_FALSE(browser_plugin_manager()->sink().GetUniqueMessageMatching(
408 BrowserPluginHostMsg_PluginDestroyed::ID));
409 }
410
411 // Verify that the 'partition' attribute on the browser plugin is parsed
412 // correctly.
TEST_F(BrowserPluginTest,PartitionAttribute)413 TEST_F(BrowserPluginTest, PartitionAttribute) {
414 std::string html = base::StringPrintf(kHTMLForPartitionedPluginObject,
415 content::kBrowserPluginMimeType);
416 LoadHTML(html.c_str());
417 std::string partition_value = ExecuteScriptAndReturnString(
418 "document.getElementById('browserplugin').partition");
419 EXPECT_STREQ("someid", partition_value.c_str());
420
421 html = base::StringPrintf(kHTMLForPartitionedPersistedPluginObject,
422 content::kBrowserPluginMimeType);
423 LoadHTML(html.c_str());
424 partition_value = ExecuteScriptAndReturnString(
425 "document.getElementById('browserplugin').partition");
426 EXPECT_STREQ("persist:someid", partition_value.c_str());
427
428 // Verify that once HTML has defined a source and partition, we cannot change
429 // the partition anymore.
430 ExecuteJavaScript(
431 "try {"
432 " document.getElementById('browserplugin').partition = 'foo';"
433 " document.title = 'success';"
434 "} catch (e) { document.title = e.message; }");
435 std::string title = ExecuteScriptAndReturnString("document.title");
436 EXPECT_STREQ(
437 "The object has already navigated, so its partition cannot be changed.",
438 title.c_str());
439
440 // Load a browser tag without 'src' defined.
441 html = base::StringPrintf(kHTMLForSourcelessPluginObject,
442 content::kBrowserPluginMimeType);
443 LoadHTML(html.c_str());
444
445 // Ensure we don't parse just "persist:" string and return exception.
446 ExecuteJavaScript(
447 "try {"
448 " document.getElementById('browserplugin').partition = 'persist:';"
449 " document.title = 'success';"
450 "} catch (e) { document.title = e.message; }");
451 title = ExecuteScriptAndReturnString("document.title");
452 EXPECT_STREQ("Invalid partition attribute.", title.c_str());
453 }
454
455 // This test verifies that BrowserPlugin enters an error state when the
456 // partition attribute is invalid.
TEST_F(BrowserPluginTest,InvalidPartition)457 TEST_F(BrowserPluginTest, InvalidPartition) {
458 std::string html = base::StringPrintf(kHTMLForInvalidPartitionedPluginObject,
459 content::kBrowserPluginMimeType);
460 LoadHTML(html.c_str());
461 // Attempt to navigate with an invalid partition.
462 {
463 ExecuteJavaScript(
464 "try {"
465 " document.getElementById('browserplugin').src = 'bar';"
466 " document.title = 'success';"
467 "} catch (e) { document.title = e.message; }");
468 std::string title = ExecuteScriptAndReturnString("document.title");
469 EXPECT_STREQ("Invalid partition attribute.", title.c_str());
470 // Verify that the 'src' attribute has not been updated.
471 EXPECT_EQ("", ExecuteScriptAndReturnString(
472 "document.getElementById('browserplugin').src"));
473 }
474
475 // Verify that the BrowserPlugin accepts changes to its src attribue after
476 // setting the partition to a valid value.
477 ExecuteJavaScript(
478 "document.getElementById('browserplugin').partition = 'persist:foo'");
479 ExecuteJavaScript("document.getElementById('browserplugin').src = 'bar'");
480 EXPECT_EQ("bar", ExecuteScriptAndReturnString(
481 "document.getElementById('browserplugin').src"));
482 ProcessPendingMessages();
483 // Verify that the BrowserPlugin does not 'deadlock': it can recover from
484 // the partition ID error state.
485 {
486 ExecuteJavaScript(
487 "try {"
488 " document.getElementById('browserplugin').partition = 'persist:1337';"
489 " document.title = 'success';"
490 "} catch (e) { document.title = e.message; }");
491 std::string title = ExecuteScriptAndReturnString("document.title");
492 EXPECT_STREQ(
493 "The object has already navigated, so its partition cannot be changed.",
494 title.c_str());
495 ExecuteJavaScript("document.getElementById('browserplugin').src = '42'");
496 EXPECT_EQ("42", ExecuteScriptAndReturnString(
497 "document.getElementById('browserplugin').src"));
498 }
499 }
500
501 // Test to verify that after the first navigation, the partition attribute
502 // cannot be modified.
TEST_F(BrowserPluginTest,ImmutableAttributesAfterNavigation)503 TEST_F(BrowserPluginTest, ImmutableAttributesAfterNavigation) {
504 std::string html = base::StringPrintf(kHTMLForSourcelessPluginObject,
505 content::kBrowserPluginMimeType);
506 LoadHTML(html.c_str());
507
508 ExecuteJavaScript(
509 "document.getElementById('browserplugin').partition = 'storage'");
510 std::string partition_value = ExecuteScriptAndReturnString(
511 "document.getElementById('browserplugin').partition");
512 EXPECT_STREQ("storage", partition_value.c_str());
513
514 std::string src_value = ExecuteScriptAndReturnString(
515 "document.getElementById('browserplugin').src");
516 EXPECT_STREQ("", src_value.c_str());
517
518 ExecuteJavaScript("document.getElementById('browserplugin').src = 'bar'");
519 ProcessPendingMessages();
520 {
521 BrowserPluginHostMsg_Attach_Params params;
522 MockBrowserPlugin* browser_plugin =
523 GetCurrentPluginWithAttachParams(¶ms);
524 ASSERT_TRUE(browser_plugin);
525
526 EXPECT_STREQ("storage", params.storage_partition_id.c_str());
527 EXPECT_FALSE(params.persist_storage);
528 EXPECT_STREQ("bar", params.src.c_str());
529 }
530
531 // Setting the partition should throw an exception and the value should not
532 // change.
533 ExecuteJavaScript(
534 "try {"
535 " document.getElementById('browserplugin').partition = 'someid';"
536 " document.title = 'success';"
537 "} catch (e) { document.title = e.message; }");
538
539 std::string title = ExecuteScriptAndReturnString("document.title");
540 EXPECT_STREQ(
541 "The object has already navigated, so its partition cannot be changed.",
542 title.c_str());
543
544 partition_value = ExecuteScriptAndReturnString(
545 "document.getElementById('browserplugin').partition");
546 EXPECT_STREQ("storage", partition_value.c_str());
547 }
548
TEST_F(BrowserPluginTest,AutoSizeAttributes)549 TEST_F(BrowserPluginTest, AutoSizeAttributes) {
550 std::string html = base::StringPrintf(kHTMLForSourcelessPluginObject,
551 content::kBrowserPluginMimeType);
552 LoadHTML(html.c_str());
553 const char* kSetAutoSizeParametersAndNavigate =
554 "var browserplugin = document.getElementById('browserplugin');"
555 "browserplugin.autosize = true;"
556 "browserplugin.minwidth = 42;"
557 "browserplugin.minheight = 43;"
558 "browserplugin.maxwidth = 1337;"
559 "browserplugin.maxheight = 1338;"
560 "browserplugin.src = 'foobar';";
561 const char* kDisableAutoSize =
562 "document.getElementById('browserplugin').removeAttribute('autosize');";
563
564 int instance_id = 0;
565 // Set some autosize parameters before navigating then navigate.
566 // Verify that the BrowserPluginHostMsg_Attach message contains
567 // the correct autosize parameters.
568 ExecuteJavaScript(kSetAutoSizeParametersAndNavigate);
569 ProcessPendingMessages();
570
571 BrowserPluginHostMsg_Attach_Params params;
572 MockBrowserPlugin* browser_plugin =
573 GetCurrentPluginWithAttachParams(¶ms);
574 ASSERT_TRUE(browser_plugin);
575
576 EXPECT_TRUE(params.auto_size_params.enable);
577 EXPECT_EQ(42, params.auto_size_params.min_size.width());
578 EXPECT_EQ(43, params.auto_size_params.min_size.height());
579 EXPECT_EQ(1337, params.auto_size_params.max_size.width());
580 EXPECT_EQ(1338, params.auto_size_params.max_size.height());
581
582 // Verify that we are waiting for the browser process to grab the new
583 // damage buffer.
584 EXPECT_TRUE(browser_plugin->pending_damage_buffer_.get());
585 // Disable autosize. AutoSize state will not be sent to the guest until
586 // the guest has responded to the last resize request.
587 ExecuteJavaScript(kDisableAutoSize);
588 ProcessPendingMessages();
589
590 const IPC::Message* auto_size_msg =
591 browser_plugin_manager()->sink().GetUniqueMessageMatching(
592 BrowserPluginHostMsg_SetAutoSize::ID);
593 EXPECT_FALSE(auto_size_msg);
594
595 // Send the BrowserPlugin an UpdateRect equal to its |max_size| with
596 // the same damage buffer.
597 BrowserPluginMsg_UpdateRect_Params update_rect_params;
598 update_rect_params.damage_buffer_sequence_id =
599 browser_plugin->damage_buffer_sequence_id_;
600 update_rect_params.view_size = gfx::Size(1337, 1338);
601 update_rect_params.scale_factor = 1.0f;
602 update_rect_params.is_resize_ack = true;
603 update_rect_params.needs_ack = true;
604 BrowserPluginMsg_UpdateRect msg(instance_id, update_rect_params);
605 browser_plugin->OnMessageReceived(msg);
606
607 // Verify that the autosize state has been updated.
608 {
609 const IPC::Message* auto_size_msg =
610 browser_plugin_manager()->sink().GetUniqueMessageMatching(
611 BrowserPluginHostMsg_UpdateRect_ACK::ID);
612 ASSERT_TRUE(auto_size_msg);
613
614 int instance_id = 0;
615 bool needs_ack = false;
616 BrowserPluginHostMsg_AutoSize_Params auto_size_params;
617 BrowserPluginHostMsg_ResizeGuest_Params resize_params;
618 BrowserPluginHostMsg_UpdateRect_ACK::Read(auto_size_msg,
619 &instance_id,
620 &needs_ack,
621 &auto_size_params,
622 &resize_params);
623 EXPECT_FALSE(auto_size_params.enable);
624 // These value are not populated (as an optimization) if autosize is
625 // disabled.
626 EXPECT_EQ(0, auto_size_params.min_size.width());
627 EXPECT_EQ(0, auto_size_params.min_size.height());
628 EXPECT_EQ(0, auto_size_params.max_size.width());
629 EXPECT_EQ(0, auto_size_params.max_size.height());
630 }
631 }
632
633 } // namespace content
634