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 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: 60 TestContentRendererClient() : ContentRendererClient() { 61 } 62 virtual ~TestContentRendererClient() { 63 } 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: 74 virtual MockBrowserPluginManager* CreateBrowserPluginManager( 75 RenderViewImpl* render_view) OVERRIDE { 76 return new MockBrowserPluginManager(render_view); 77 } 78 79 // Singleton getter. 80 static TestBrowserPluginManagerFactory* GetInstance() { 81 return Singleton<TestBrowserPluginManagerFactory>::get(); 82 } 83 84 protected: 85 TestBrowserPluginManagerFactory() {} 86 virtual ~TestBrowserPluginManagerFactory() {} 87 88 private: 89 // For Singleton. 90 friend struct DefaultSingletonTraits<TestBrowserPluginManagerFactory>; 91 92 DISALLOW_COPY_AND_ASSIGN(TestBrowserPluginManagerFactory); 93 }; 94 95 BrowserPluginTest::BrowserPluginTest() {} 96 97 BrowserPluginTest::~BrowserPluginTest() {} 98 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 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 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 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| 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 154 MockBrowserPlugin* BrowserPluginTest::GetCurrentPlugin() { 155 BrowserPluginHostMsg_Attach_Params params; 156 return GetCurrentPluginWithAttachParams(¶ms); 157 } 158 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. 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. 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. 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 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 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. 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. 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. 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. 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 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