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/debug/leak_annotations.h" 8 #include "base/files/file_path.h" 9 #include "base/memory/singleton.h" 10 #include "base/path_service.h" 11 #include "base/pickle.h" 12 #include "content/public/common/content_constants.h" 13 #include "content/public/renderer/content_renderer_client.h" 14 #include "content/renderer/browser_plugin/browser_plugin.h" 15 #include "content/renderer/browser_plugin/browser_plugin_manager_factory.h" 16 #include "content/renderer/browser_plugin/mock_browser_plugin.h" 17 #include "content/renderer/browser_plugin/mock_browser_plugin_manager.h" 18 #include "content/renderer/render_thread_impl.h" 19 #include "content/renderer/renderer_webkitplatformsupport_impl.h" 20 #include "skia/ext/platform_canvas.h" 21 #include "third_party/WebKit/public/platform/WebCursorInfo.h" 22 #include "third_party/WebKit/public/web/WebInputEvent.h" 23 #include "third_party/WebKit/public/web/WebLocalFrame.h" 24 #include "third_party/WebKit/public/web/WebScriptSource.h" 25 26 namespace content { 27 28 namespace { 29 const char kHTMLForBrowserPluginObject[] = 30 "<object id='browserplugin' width='640px' height='480px'" 31 " src='foo' type='%s'></object>" 32 "<script>document.querySelector('object').nonExistentAttribute;</script>"; 33 34 const char kHTMLForSourcelessPluginObject[] = 35 "<object id='browserplugin' width='640px' height='480px' type='%s'>"; 36 37 std::string GetHTMLForBrowserPluginObject() { 38 return base::StringPrintf(kHTMLForBrowserPluginObject, 39 kBrowserPluginMimeType); 40 } 41 42 } // namespace 43 44 // Test factory for creating test instances of BrowserPluginManager. 45 class TestBrowserPluginManagerFactory : public BrowserPluginManagerFactory { 46 public: 47 virtual MockBrowserPluginManager* CreateBrowserPluginManager( 48 RenderViewImpl* render_view) OVERRIDE { 49 return new MockBrowserPluginManager(render_view); 50 } 51 52 // Singleton getter. 53 static TestBrowserPluginManagerFactory* GetInstance() { 54 return Singleton<TestBrowserPluginManagerFactory>::get(); 55 } 56 57 protected: 58 TestBrowserPluginManagerFactory() {} 59 virtual ~TestBrowserPluginManagerFactory() {} 60 61 private: 62 // For Singleton. 63 friend struct DefaultSingletonTraits<TestBrowserPluginManagerFactory>; 64 65 DISALLOW_COPY_AND_ASSIGN(TestBrowserPluginManagerFactory); 66 }; 67 68 BrowserPluginTest::BrowserPluginTest() {} 69 70 BrowserPluginTest::~BrowserPluginTest() {} 71 72 void BrowserPluginTest::SetUp() { 73 BrowserPluginManager::set_factory_for_testing( 74 TestBrowserPluginManagerFactory::GetInstance()); 75 content::RenderViewTest::SetUp(); 76 } 77 78 void BrowserPluginTest::TearDown() { 79 BrowserPluginManager::set_factory_for_testing( 80 TestBrowserPluginManagerFactory::GetInstance()); 81 #if defined(LEAK_SANITIZER) 82 // Do this before shutting down V8 in RenderViewTest::TearDown(). 83 // http://crbug.com/328552 84 __lsan_do_leak_check(); 85 #endif 86 RenderViewTest::TearDown(); 87 } 88 89 std::string BrowserPluginTest::ExecuteScriptAndReturnString( 90 const std::string& script) { 91 v8::HandleScope handle_scope(v8::Isolate::GetCurrent()); 92 v8::Handle<v8::Value> value = GetMainFrame()->executeScriptAndReturnValue( 93 blink::WebScriptSource(blink::WebString::fromUTF8(script.c_str()))); 94 if (value.IsEmpty() || !value->IsString()) 95 return std::string(); 96 97 v8::Local<v8::String> v8_str = value->ToString(); 98 int length = v8_str->Utf8Length() + 1; 99 scoped_ptr<char[]> str(new char[length]); 100 v8_str->WriteUtf8(str.get(), length); 101 return str.get(); 102 } 103 104 int BrowserPluginTest::ExecuteScriptAndReturnInt( 105 const std::string& script) { 106 v8::HandleScope handle_scope(v8::Isolate::GetCurrent()); 107 v8::Handle<v8::Value> value = GetMainFrame()->executeScriptAndReturnValue( 108 blink::WebScriptSource(blink::WebString::fromUTF8(script.c_str()))); 109 if (value.IsEmpty() || !value->IsInt32()) 110 return 0; 111 112 return value->Int32Value(); 113 } 114 115 // A return value of false means that a value was not present. The return value 116 // of the script is stored in |result| 117 bool BrowserPluginTest::ExecuteScriptAndReturnBool( 118 const std::string& script, bool* result) { 119 v8::HandleScope handle_scope(v8::Isolate::GetCurrent()); 120 v8::Handle<v8::Value> value = GetMainFrame()->executeScriptAndReturnValue( 121 blink::WebScriptSource(blink::WebString::fromUTF8(script.c_str()))); 122 if (value.IsEmpty() || !value->IsBoolean()) 123 return false; 124 125 *result = value->BooleanValue(); 126 return true; 127 } 128 129 MockBrowserPlugin* BrowserPluginTest::GetCurrentPlugin() { 130 BrowserPluginHostMsg_Attach_Params params; 131 return GetCurrentPluginWithAttachParams(¶ms); 132 } 133 134 MockBrowserPlugin* BrowserPluginTest::GetCurrentPluginWithAttachParams( 135 BrowserPluginHostMsg_Attach_Params* params) { 136 MockBrowserPlugin* browser_plugin = static_cast<MockBrowserPluginManager*>( 137 browser_plugin_manager())->last_plugin(); 138 if (!browser_plugin) 139 return NULL; 140 141 browser_plugin->Attach(); 142 143 int instance_id = 0; 144 const IPC::Message* msg = 145 browser_plugin_manager()->sink().GetUniqueMessageMatching( 146 BrowserPluginHostMsg_Attach::ID); 147 if (!msg) 148 return NULL; 149 150 PickleIterator iter(*msg); 151 if (!iter.ReadInt(&instance_id)) 152 return NULL; 153 154 if (!IPC::ParamTraits<BrowserPluginHostMsg_Attach_Params>::Read( 155 msg, &iter, params)) { 156 return NULL; 157 } 158 159 browser_plugin->OnAttachACK(instance_id); 160 return browser_plugin; 161 } 162 163 // This test verifies that an initial resize occurs when we instantiate the 164 // browser plugin. 165 TEST_F(BrowserPluginTest, InitialResize) { 166 LoadHTML(GetHTMLForBrowserPluginObject().c_str()); 167 // Verify that the information in Attach is correct. 168 BrowserPluginHostMsg_Attach_Params params; 169 MockBrowserPlugin* browser_plugin = GetCurrentPluginWithAttachParams(¶ms); 170 171 EXPECT_EQ(640, params.resize_guest_params.view_size.width()); 172 EXPECT_EQ(480, params.resize_guest_params.view_size.height()); 173 ASSERT_TRUE(browser_plugin); 174 } 175 176 TEST_F(BrowserPluginTest, RemovePlugin) { 177 LoadHTML(GetHTMLForBrowserPluginObject().c_str()); 178 MockBrowserPlugin* browser_plugin = GetCurrentPlugin(); 179 ASSERT_TRUE(browser_plugin); 180 181 EXPECT_FALSE(browser_plugin_manager()->sink().GetUniqueMessageMatching( 182 BrowserPluginHostMsg_PluginDestroyed::ID)); 183 ExecuteJavaScript("x = document.getElementById('browserplugin'); " 184 "x.parentNode.removeChild(x);"); 185 ProcessPendingMessages(); 186 EXPECT_TRUE(browser_plugin_manager()->sink().GetUniqueMessageMatching( 187 BrowserPluginHostMsg_PluginDestroyed::ID)); 188 } 189 190 // This test verifies that PluginDestroyed messages do not get sent from a 191 // BrowserPlugin that has never navigated. 192 TEST_F(BrowserPluginTest, RemovePluginBeforeNavigation) { 193 std::string html = base::StringPrintf(kHTMLForSourcelessPluginObject, 194 kBrowserPluginMimeType); 195 LoadHTML(html.c_str()); 196 EXPECT_FALSE(browser_plugin_manager()->sink().GetUniqueMessageMatching( 197 BrowserPluginHostMsg_PluginDestroyed::ID)); 198 ExecuteJavaScript("x = document.getElementById('browserplugin'); " 199 "x.parentNode.removeChild(x);"); 200 ProcessPendingMessages(); 201 EXPECT_FALSE(browser_plugin_manager()->sink().GetUniqueMessageMatching( 202 BrowserPluginHostMsg_PluginDestroyed::ID)); 203 } 204 205 } // namespace content 206