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 26namespace content { 27 28namespace { 29const char kHTMLForBrowserPluginObject[] = 30 "<object id='browserplugin' width='640px' height='480px'" 31 " src='foo' type='%s'></object>" 32 "<script>document.querySelector('object').nonExistentAttribute;</script>"; 33 34const char kHTMLForSourcelessPluginObject[] = 35 "<object id='browserplugin' width='640px' height='480px' type='%s'>"; 36 37std::string GetHTMLForBrowserPluginObject() { 38 return base::StringPrintf(kHTMLForBrowserPluginObject, 39 kBrowserPluginMimeType); 40} 41 42} // namespace 43 44// Test factory for creating test instances of BrowserPluginManager. 45class 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 68BrowserPluginTest::BrowserPluginTest() {} 69 70BrowserPluginTest::~BrowserPluginTest() {} 71 72void BrowserPluginTest::SetUp() { 73 BrowserPluginManager::set_factory_for_testing( 74 TestBrowserPluginManagerFactory::GetInstance()); 75 content::RenderViewTest::SetUp(); 76} 77 78void 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 89std::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 104int 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| 117bool 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 129MockBrowserPlugin* BrowserPluginTest::GetCurrentPlugin() { 130 BrowserPluginHostMsg_Attach_Params params; 131 return GetCurrentPluginWithAttachParams(¶ms); 132} 133 134MockBrowserPlugin* 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. 165TEST_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 176TEST_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. 192TEST_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