OLD | NEW |
(Empty) | |
| 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/file_path.h" |
| 8 #include "base/file_util.h" |
| 9 #include "base/path_service.h" |
| 10 #include "content/common/browser_plugin_messages.h" |
| 11 #include "content/public/common/content_constants.h" |
| 12 #include "content/renderer/browser_plugin/browser_plugin.h" |
| 13 #include "content/renderer/browser_plugin/mock_browser_plugin.h" |
| 14 #include "content/renderer/browser_plugin/mock_browser_plugin_manager.h" |
| 15 #include "content/renderer/render_thread_impl.h" |
| 16 #include "content/renderer/renderer_webkitplatformsupport_impl.h" |
| 17 #include "content/shell/shell_main_delegate.h" |
| 18 #include "skia/ext/platform_canvas.h" |
| 19 #include "third_party/WebKit/Source/WebKit/chromium/public/WebCursorInfo.h" |
| 20 #include "third_party/WebKit/Source/WebKit/chromium/public/WebInputEvent.h" |
| 21 #include "third_party/WebKit/Source/WebKit/chromium/public/WebScriptSource.h" |
| 22 |
| 23 namespace { |
| 24 const char kHTMLForBrowserPluginObject[] = |
| 25 "<object id='browserplugin' width='640px' height='480px'" |
| 26 " src='foo' type='%s'>"; |
| 27 |
| 28 std::string GetHTMLForBrowserPluginObject() { |
| 29 return StringPrintf(kHTMLForBrowserPluginObject, |
| 30 content::kBrowserPluginNewMimeType); |
| 31 } |
| 32 |
| 33 } |
| 34 |
| 35 namespace content { |
| 36 |
| 37 BrowserPluginTest::BrowserPluginTest() {} |
| 38 |
| 39 BrowserPluginTest::~BrowserPluginTest() {} |
| 40 |
| 41 void BrowserPluginTest::SetUp() { |
| 42 GetContentClient()->set_renderer_for_testing(&content_renderer_client_); |
| 43 content::RenderViewTest::SetUp(); |
| 44 browser_plugin_manager_.reset(new MockBrowserPluginManager()); |
| 45 content::ShellMainDelegate::InitializeResourceBundle(); |
| 46 } |
| 47 |
| 48 void BrowserPluginTest::TearDown() { |
| 49 browser_plugin_manager_->Cleanup(); |
| 50 content::RenderViewTest::TearDown(); |
| 51 } |
| 52 |
| 53 std::string BrowserPluginTest::ExecuteScriptAndReturnString( |
| 54 const std::string& script) { |
| 55 v8::Handle<v8::Value> value = GetMainFrame()->executeScriptAndReturnValue( |
| 56 WebKit::WebScriptSource(WebKit::WebString::fromUTF8(script.c_str()))); |
| 57 if (value.IsEmpty() || !value->IsString()) |
| 58 return std::string(); |
| 59 |
| 60 v8::Local<v8::String> v8_str = value->ToString(); |
| 61 int length = v8_str->Utf8Length() + 1; |
| 62 scoped_array<char> str(new char[length]); |
| 63 v8_str->WriteUtf8(str.get(), length); |
| 64 return str.get(); |
| 65 } |
| 66 |
| 67 // This test verifies that an initial resize occurs when we instantiate the |
| 68 // browser plugin. This test also verifies that the browser plugin is waiting |
| 69 // for a BrowserPluginMsg_UpdateRect in response. We issue an UpdateRect, and |
| 70 // we observe an UpdateRect_ACK, with the resize_pending_ reset, indiciating |
| 71 // that the BrowserPlugin is not waiting for any more UpdateRects to |
| 72 // satisfy its resize request. |
| 73 TEST_F(BrowserPluginTest, InitialResize) { |
| 74 LoadHTML(GetHTMLForBrowserPluginObject().c_str()); |
| 75 // Verify that the information based on ResizeGuest is correct, and |
| 76 // use its TransportDIB::Id to paint. |
| 77 const IPC::Message* msg = |
| 78 browser_plugin_manager()->sink().GetUniqueMessageMatching( |
| 79 BrowserPluginHostMsg_ResizeGuest::ID); |
| 80 ASSERT_TRUE(msg); |
| 81 PickleIterator iter = IPC::SyncMessage::GetDataIterator(msg); |
| 82 BrowserPluginHostMsg_ResizeGuest::SendParam resize_params; |
| 83 ASSERT_TRUE(IPC::ReadParam(msg, &iter, &resize_params)); |
| 84 int instance_id = resize_params.a; |
| 85 BrowserPluginHostMsg_ResizeGuest_Params params(resize_params.b); |
| 86 EXPECT_EQ(640, params.width); |
| 87 EXPECT_EQ(480, params.height); |
| 88 // Verify that the browser plugin wasn't already waiting on a resize when this |
| 89 // resize happened. |
| 90 EXPECT_EQ(false, params.resize_pending); |
| 91 |
| 92 MockBrowserPlugin* browser_plugin = |
| 93 static_cast<MockBrowserPlugin*>( |
| 94 browser_plugin_manager()->GetBrowserPlugin(instance_id)); |
| 95 ASSERT_TRUE(browser_plugin); |
| 96 // Now the browser plugin is expecting a UpdateRect resize. |
| 97 EXPECT_TRUE(browser_plugin->resize_pending_); |
| 98 |
| 99 // Send the BrowserPlugin an UpdateRect equal to its container size. |
| 100 // That should clear the resize_pending_ flag. |
| 101 BrowserPluginMsg_UpdateRect_Params update_rect_params; |
| 102 update_rect_params.view_size = gfx::Size(640, 480); |
| 103 update_rect_params.scale_factor = 1.0f; |
| 104 update_rect_params.is_resize_ack = true; |
| 105 browser_plugin->UpdateRect(0, update_rect_params); |
| 106 EXPECT_FALSE(browser_plugin->resize_pending_); |
| 107 } |
| 108 |
| 109 // Verify that the src attribute on the browser plugin works as expected. |
| 110 TEST_F(BrowserPluginTest, SrcAttribute) { |
| 111 LoadHTML(GetHTMLForBrowserPluginObject().c_str()); |
| 112 // Verify that we're reporting the correct URL to navigate to based on the |
| 113 // src attribute. |
| 114 { |
| 115 const IPC::Message* msg = |
| 116 browser_plugin_manager()->sink().GetUniqueMessageMatching( |
| 117 BrowserPluginHostMsg_NavigateOrCreateGuest::ID); |
| 118 ASSERT_TRUE(msg); |
| 119 |
| 120 int instance_id; |
| 121 long long frame_id; |
| 122 std::string src; |
| 123 BrowserPluginHostMsg_NavigateOrCreateGuest::Read( |
| 124 msg, |
| 125 &instance_id, |
| 126 &frame_id, |
| 127 &src); |
| 128 EXPECT_EQ("foo", src); |
| 129 } |
| 130 |
| 131 browser_plugin_manager()->sink().ClearMessages(); |
| 132 // Navigate to bar and observe the associated |
| 133 // BrowserPluginHostMsg_NavigateOrCreateGuest message. |
| 134 // Verify that the src attribute is updated as well. |
| 135 ExecuteJavaScript("document.getElementById('browserplugin').src = 'bar'"); |
| 136 { |
| 137 const IPC::Message* msg = |
| 138 browser_plugin_manager()->sink().GetUniqueMessageMatching( |
| 139 BrowserPluginHostMsg_NavigateOrCreateGuest::ID); |
| 140 ASSERT_TRUE(msg); |
| 141 |
| 142 int instance_id; |
| 143 long long frame_id; |
| 144 std::string src; |
| 145 BrowserPluginHostMsg_NavigateOrCreateGuest::Read( |
| 146 msg, |
| 147 &instance_id, |
| 148 &frame_id, |
| 149 &src); |
| 150 EXPECT_EQ("bar", src); |
| 151 std::string src_value = |
| 152 ExecuteScriptAndReturnString( |
| 153 "document.getElementById('browserplugin').src"); |
| 154 EXPECT_EQ("bar", src_value); |
| 155 } |
| 156 } |
| 157 |
| 158 TEST_F(BrowserPluginTest, ResizeFlowControl) { |
| 159 LoadHTML(GetHTMLForBrowserPluginObject().c_str()); |
| 160 browser_plugin_manager()->sink().ClearMessages(); |
| 161 |
| 162 // Resize the browser plugin three times. |
| 163 ExecuteJavaScript("document.getElementById('browserplugin').width = '641px'"); |
| 164 ProcessPendingMessages(); |
| 165 ExecuteJavaScript("document.getElementById('browserplugin').width = '642px'"); |
| 166 ProcessPendingMessages(); |
| 167 ExecuteJavaScript("document.getElementById('browserplugin').width = '643px'"); |
| 168 ProcessPendingMessages(); |
| 169 |
| 170 // Expect to see three messsages in the sink. |
| 171 EXPECT_EQ(3u, browser_plugin_manager()->sink().message_count()); |
| 172 const IPC::Message* msg = |
| 173 browser_plugin_manager()->sink().GetFirstMessageMatching( |
| 174 BrowserPluginHostMsg_ResizeGuest::ID); |
| 175 ASSERT_TRUE(msg); |
| 176 PickleIterator iter = IPC::SyncMessage::GetDataIterator(msg); |
| 177 BrowserPluginHostMsg_ResizeGuest::SendParam resize_params; |
| 178 ASSERT_TRUE(IPC::ReadParam(msg, &iter, &resize_params)); |
| 179 int instance_id = resize_params.a; |
| 180 BrowserPluginHostMsg_ResizeGuest_Params params(resize_params.b); |
| 181 EXPECT_EQ(641, params.width); |
| 182 EXPECT_EQ(480, params.height); |
| 183 // This indicates that the BrowserPlugin has sent out a previous resize |
| 184 // request but has not yet received an UpdateRect for that request. |
| 185 // We send this resize regardless to update the damage buffer in the |
| 186 // browser process, so it's ready when the guest sends the appropriate |
| 187 // UpdateRect. |
| 188 EXPECT_TRUE(params.resize_pending); |
| 189 |
| 190 MockBrowserPlugin* browser_plugin = |
| 191 static_cast<MockBrowserPlugin*>( |
| 192 browser_plugin_manager()->GetBrowserPlugin(instance_id)); |
| 193 ASSERT_TRUE(browser_plugin); |
| 194 { |
| 195 // We send a stale UpdateRect to the BrowserPlugin. |
| 196 BrowserPluginMsg_UpdateRect_Params update_rect_params; |
| 197 update_rect_params.view_size = gfx::Size(640, 480); |
| 198 update_rect_params.scale_factor = 1.0f; |
| 199 update_rect_params.is_resize_ack = true; |
| 200 browser_plugin->UpdateRect(0, update_rect_params); |
| 201 // This tells us that the BrowserPlugin is still expecting another |
| 202 // UpdateRect with the most recent size. |
| 203 EXPECT_TRUE(browser_plugin->resize_pending_); |
| 204 } |
| 205 { |
| 206 BrowserPluginMsg_UpdateRect_Params update_rect_params; |
| 207 update_rect_params.view_size = gfx::Size(643, 480); |
| 208 update_rect_params.scale_factor = 1.0f; |
| 209 update_rect_params.is_resize_ack = true; |
| 210 browser_plugin->UpdateRect(0, update_rect_params); |
| 211 // The BrowserPlugin has finally received an UpdateRect that satisifes |
| 212 // its current size, and so it is happy. |
| 213 EXPECT_FALSE(browser_plugin->resize_pending_); |
| 214 } |
| 215 } |
| 216 |
| 217 TEST_F(BrowserPluginTest, GuestCrash) { |
| 218 LoadHTML(GetHTMLForBrowserPluginObject().c_str()); |
| 219 |
| 220 // Grab the BrowserPlugin's instance ID from its resize message. |
| 221 const IPC::Message* msg = |
| 222 browser_plugin_manager()->sink().GetFirstMessageMatching( |
| 223 BrowserPluginHostMsg_ResizeGuest::ID); |
| 224 ASSERT_TRUE(msg); |
| 225 PickleIterator iter = IPC::SyncMessage::GetDataIterator(msg); |
| 226 BrowserPluginHostMsg_ResizeGuest::SendParam resize_params; |
| 227 ASSERT_TRUE(IPC::ReadParam(msg, &iter, &resize_params)); |
| 228 int instance_id = resize_params.a; |
| 229 |
| 230 MockBrowserPlugin* browser_plugin = |
| 231 static_cast<MockBrowserPlugin*>( |
| 232 browser_plugin_manager()->GetBrowserPlugin(instance_id)); |
| 233 ASSERT_TRUE(browser_plugin); |
| 234 |
| 235 WebKit::WebCursorInfo cursor_info; |
| 236 // Send an event and verify that the event is deported. |
| 237 browser_plugin->handleInputEvent(WebKit::WebMouseEvent(), |
| 238 cursor_info); |
| 239 EXPECT_TRUE(browser_plugin_manager()->sink().GetUniqueMessageMatching( |
| 240 BrowserPluginHostMsg_HandleInputEvent::ID)); |
| 241 browser_plugin_manager()->sink().ClearMessages(); |
| 242 |
| 243 // Pretend that the guest has crashed |
| 244 browser_plugin->GuestCrashed(); |
| 245 // Send an event and verify that events are no longer deported. |
| 246 browser_plugin->handleInputEvent(WebKit::WebMouseEvent(), |
| 247 cursor_info); |
| 248 EXPECT_FALSE(browser_plugin_manager()->sink().GetUniqueMessageMatching( |
| 249 BrowserPluginHostMsg_HandleInputEvent::ID)); |
| 250 |
| 251 // Navigate and verify that the guest_crashed_ flag has been reset. |
| 252 browser_plugin->SetSrcAttribute("bar"); |
| 253 EXPECT_FALSE(browser_plugin->guest_crashed_); |
| 254 } |
| 255 |
| 256 TEST_F(BrowserPluginTest, RemovePlugin) { |
| 257 LoadHTML(GetHTMLForBrowserPluginObject().c_str()); |
| 258 EXPECT_FALSE(browser_plugin_manager()->sink().GetUniqueMessageMatching( |
| 259 BrowserPluginHostMsg_PluginDestroyed::ID)); |
| 260 ExecuteJavaScript("x = document.getElementById('browserplugin'); " |
| 261 "x.parentNode.removeChild(x);"); |
| 262 ProcessPendingMessages(); |
| 263 EXPECT_TRUE(browser_plugin_manager()->sink().GetUniqueMessageMatching( |
| 264 BrowserPluginHostMsg_PluginDestroyed::ID)); |
| 265 } |
| 266 |
| 267 TEST_F(BrowserPluginTest, CustomEvents) { |
| 268 const char* kAddEventListener = |
| 269 "var url;" |
| 270 "function nav(u) {" |
| 271 " url = u;" |
| 272 "}" |
| 273 "document.getElementById('browserplugin')." |
| 274 " addEventListener('navigation', nav);"; |
| 275 const char* kRemoveEventListener = |
| 276 "document.getElementById('browserplugin')." |
| 277 " removeEventListener('navigation', nav);"; |
| 278 const char* kGoogleURL = "http://www.google.com/"; |
| 279 const char* kGoogleNewsURL = "http://news.google.com/"; |
| 280 |
| 281 LoadHTML(GetHTMLForBrowserPluginObject().c_str()); |
| 282 ExecuteJavaScript(kAddEventListener); |
| 283 // Grab the BrowserPlugin's instance ID from its resize message. |
| 284 const IPC::Message* msg = |
| 285 browser_plugin_manager()->sink().GetFirstMessageMatching( |
| 286 BrowserPluginHostMsg_ResizeGuest::ID); |
| 287 ASSERT_TRUE(msg); |
| 288 PickleIterator iter = IPC::SyncMessage::GetDataIterator(msg); |
| 289 BrowserPluginHostMsg_ResizeGuest::SendParam resize_params; |
| 290 ASSERT_TRUE(IPC::ReadParam(msg, &iter, &resize_params)); |
| 291 int instance_id = resize_params.a; |
| 292 |
| 293 MockBrowserPlugin* browser_plugin = |
| 294 static_cast<MockBrowserPlugin*>( |
| 295 browser_plugin_manager()->GetBrowserPlugin(instance_id)); |
| 296 ASSERT_TRUE(browser_plugin); |
| 297 |
| 298 browser_plugin->DidNavigate(GURL(kGoogleURL)); |
| 299 EXPECT_EQ(kGoogleURL, ExecuteScriptAndReturnString("url")); |
| 300 |
| 301 ExecuteJavaScript(kRemoveEventListener); |
| 302 browser_plugin->DidNavigate(GURL(kGoogleNewsURL)); |
| 303 // The URL variable should not change because we've removed the event |
| 304 // listener. |
| 305 EXPECT_EQ(kGoogleURL, ExecuteScriptAndReturnString("url")); |
| 306 } |
| 307 |
| 308 } // namespace content |
OLD | NEW |