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