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/plugin/webplugin_delegate_stub.h" 6 7 #include "build/build_config.h" 8 9 #include "base/bind.h" 10 #include "base/command_line.h" 11 #include "base/strings/string_number_conversions.h" 12 #include "content/child/npapi/plugin_instance.h" 13 #include "content/child/npapi/webplugin_delegate_impl.h" 14 #include "content/child/plugin_messages.h" 15 #include "content/plugin/plugin_channel.h" 16 #include "content/plugin/plugin_thread.h" 17 #include "content/plugin/webplugin_proxy.h" 18 #include "content/public/common/content_client.h" 19 #include "content/public/common/content_constants.h" 20 #include "content/public/common/content_switches.h" 21 #include "skia/ext/platform_device.h" 22 #include "third_party/WebKit/public/web/WebBindings.h" 23 #include "third_party/WebKit/public/web/WebCursorInfo.h" 24 #include "third_party/npapi/bindings/npapi.h" 25 #include "third_party/npapi/bindings/npruntime.h" 26 #include "webkit/common/cursors/webcursor.h" 27 28 using WebKit::WebBindings; 29 using WebKit::WebCursorInfo; 30 31 namespace content { 32 33 static void DestroyWebPluginAndDelegate( 34 base::WeakPtr<NPObjectStub> scriptable_object, 35 WebPluginDelegateImpl* delegate, 36 WebPlugin* webplugin) { 37 // The plugin may not expect us to try to release the scriptable object 38 // after calling NPP_Destroy on the instance, so delete the stub now. 39 if (scriptable_object.get()) 40 scriptable_object->DeleteSoon(); 41 42 if (delegate) { 43 // Save the object owner Id so we can unregister it as a valid owner 44 // after the instance has been destroyed. 45 NPP owner = delegate->GetPluginNPP(); 46 47 // WebPlugin must outlive WebPluginDelegate. 48 delegate->PluginDestroyed(); 49 50 // PluginDestroyed can call into script, so only unregister as an object 51 // owner after that has completed. 52 WebBindings::unregisterObjectOwner(owner); 53 } 54 55 delete webplugin; 56 } 57 58 WebPluginDelegateStub::WebPluginDelegateStub( 59 const std::string& mime_type, int instance_id, PluginChannel* channel) : 60 mime_type_(mime_type), 61 instance_id_(instance_id), 62 channel_(channel), 63 delegate_(NULL), 64 webplugin_(NULL), 65 in_destructor_(false) { 66 DCHECK(channel); 67 } 68 69 WebPluginDelegateStub::~WebPluginDelegateStub() { 70 in_destructor_ = true; 71 GetContentClient()->SetActiveURL(page_url_); 72 73 if (channel_->in_send()) { 74 // The delegate or an npobject is in the callstack, so don't delete it 75 // right away. 76 base::MessageLoop::current()->PostNonNestableTask( 77 FROM_HERE, 78 base::Bind(&DestroyWebPluginAndDelegate, 79 plugin_scriptable_object_, 80 delegate_, 81 webplugin_)); 82 } else { 83 // Safe to delete right away. 84 DestroyWebPluginAndDelegate( 85 plugin_scriptable_object_, delegate_, webplugin_); 86 } 87 88 // Remove the NPObject owner mapping for this instance. 89 channel_->RemoveMappingForNPObjectOwner(instance_id_); 90 } 91 92 bool WebPluginDelegateStub::OnMessageReceived(const IPC::Message& msg) { 93 GetContentClient()->SetActiveURL(page_url_); 94 95 // A plugin can execute a script to delete itself in any of its NPP methods. 96 // Hold an extra reference to ourself so that if this does occur and we're 97 // handling a sync message, we don't crash when attempting to send a reply. 98 // The exception to this is when we're already in the destructor. 99 if (!in_destructor_) 100 AddRef(); 101 102 bool handled = true; 103 IPC_BEGIN_MESSAGE_MAP(WebPluginDelegateStub, msg) 104 IPC_MESSAGE_HANDLER(PluginMsg_Init, OnInit) 105 IPC_MESSAGE_HANDLER(PluginMsg_WillSendRequest, OnWillSendRequest) 106 IPC_MESSAGE_HANDLER(PluginMsg_DidReceiveResponse, OnDidReceiveResponse) 107 IPC_MESSAGE_HANDLER(PluginMsg_DidReceiveData, OnDidReceiveData) 108 IPC_MESSAGE_HANDLER(PluginMsg_DidFinishLoading, OnDidFinishLoading) 109 IPC_MESSAGE_HANDLER(PluginMsg_DidFail, OnDidFail) 110 IPC_MESSAGE_HANDLER(PluginMsg_DidFinishLoadWithReason, 111 OnDidFinishLoadWithReason) 112 IPC_MESSAGE_HANDLER(PluginMsg_SetFocus, OnSetFocus) 113 IPC_MESSAGE_HANDLER(PluginMsg_HandleInputEvent, OnHandleInputEvent) 114 IPC_MESSAGE_HANDLER(PluginMsg_Paint, OnPaint) 115 IPC_MESSAGE_HANDLER(PluginMsg_DidPaint, OnDidPaint) 116 IPC_MESSAGE_HANDLER(PluginMsg_GetPluginScriptableObject, 117 OnGetPluginScriptableObject) 118 IPC_MESSAGE_HANDLER(PluginMsg_GetFormValue, OnGetFormValue) 119 IPC_MESSAGE_HANDLER(PluginMsg_UpdateGeometry, OnUpdateGeometry) 120 IPC_MESSAGE_HANDLER(PluginMsg_UpdateGeometrySync, OnUpdateGeometry) 121 IPC_MESSAGE_HANDLER(PluginMsg_SendJavaScriptStream, 122 OnSendJavaScriptStream) 123 IPC_MESSAGE_HANDLER(PluginMsg_SetContentAreaFocus, OnSetContentAreaFocus) 124 #if defined(OS_WIN) && !defined(USE_AURA) 125 IPC_MESSAGE_HANDLER(PluginMsg_ImeCompositionUpdated, 126 OnImeCompositionUpdated) 127 IPC_MESSAGE_HANDLER(PluginMsg_ImeCompositionCompleted, 128 OnImeCompositionCompleted) 129 #endif 130 #if defined(OS_MACOSX) 131 IPC_MESSAGE_HANDLER(PluginMsg_SetWindowFocus, OnSetWindowFocus) 132 IPC_MESSAGE_HANDLER(PluginMsg_ContainerHidden, OnContainerHidden) 133 IPC_MESSAGE_HANDLER(PluginMsg_ContainerShown, OnContainerShown) 134 IPC_MESSAGE_HANDLER(PluginMsg_WindowFrameChanged, OnWindowFrameChanged) 135 IPC_MESSAGE_HANDLER(PluginMsg_ImeCompositionCompleted, 136 OnImeCompositionCompleted) 137 #endif 138 IPC_MESSAGE_HANDLER(PluginMsg_DidReceiveManualResponse, 139 OnDidReceiveManualResponse) 140 IPC_MESSAGE_HANDLER(PluginMsg_DidReceiveManualData, OnDidReceiveManualData) 141 IPC_MESSAGE_HANDLER(PluginMsg_DidFinishManualLoading, 142 OnDidFinishManualLoading) 143 IPC_MESSAGE_HANDLER(PluginMsg_DidManualLoadFail, OnDidManualLoadFail) 144 IPC_MESSAGE_HANDLER(PluginMsg_HandleURLRequestReply, 145 OnHandleURLRequestReply) 146 IPC_MESSAGE_HANDLER(PluginMsg_HTTPRangeRequestReply, 147 OnHTTPRangeRequestReply) 148 IPC_MESSAGE_UNHANDLED(handled = false) 149 IPC_END_MESSAGE_MAP() 150 151 if (!in_destructor_) 152 Release(); 153 154 DCHECK(handled); 155 return handled; 156 } 157 158 bool WebPluginDelegateStub::Send(IPC::Message* msg) { 159 return channel_->Send(msg); 160 } 161 162 void WebPluginDelegateStub::OnInit(const PluginMsg_Init_Params& params, 163 bool* transparent, 164 bool* result) { 165 page_url_ = params.page_url; 166 GetContentClient()->SetActiveURL(page_url_); 167 168 *transparent = false; 169 *result = false; 170 if (params.arg_names.size() != params.arg_values.size()) { 171 NOTREACHED(); 172 return; 173 } 174 175 const CommandLine& command_line = *CommandLine::ForCurrentProcess(); 176 base::FilePath path = 177 command_line.GetSwitchValuePath(switches::kPluginPath); 178 179 webplugin_ = new WebPluginProxy(channel_.get(), 180 instance_id_, 181 page_url_, 182 params.host_render_view_routing_id); 183 delegate_ = WebPluginDelegateImpl::Create(path, mime_type_); 184 if (delegate_) { 185 if (delegate_->GetQuirks() & 186 WebPluginDelegateImpl::PLUGIN_QUIRK_DIE_AFTER_UNLOAD) { 187 PluginThread::current()->SetForcefullyTerminatePluginProcess(); 188 } 189 190 webplugin_->set_delegate(delegate_); 191 std::vector<std::string> arg_names = params.arg_names; 192 std::vector<std::string> arg_values = params.arg_values; 193 194 // Register the plugin as a valid object owner. 195 WebBindings::registerObjectOwner(delegate_->GetPluginNPP()); 196 197 // Add an NPObject owner mapping for this instance, to support ownership 198 // tracking in the renderer. 199 channel_->AddMappingForNPObjectOwner(instance_id_, 200 delegate_->GetPluginNPP()); 201 202 *result = delegate_->Initialize(params.url, 203 arg_names, 204 arg_values, 205 webplugin_, 206 params.load_manually); 207 *transparent = delegate_->instance()->transparent(); 208 } 209 } 210 211 void WebPluginDelegateStub::OnWillSendRequest(int id, const GURL& url, 212 int http_status_code) { 213 WebPluginResourceClient* client = webplugin_->GetResourceClient(id); 214 if (!client) 215 return; 216 217 client->WillSendRequest(url, http_status_code); 218 } 219 220 void WebPluginDelegateStub::OnDidReceiveResponse( 221 const PluginMsg_DidReceiveResponseParams& params) { 222 WebPluginResourceClient* client = webplugin_->GetResourceClient(params.id); 223 if (!client) 224 return; 225 226 client->DidReceiveResponse(params.mime_type, 227 params.headers, 228 params.expected_length, 229 params.last_modified, 230 params.request_is_seekable); 231 } 232 233 void WebPluginDelegateStub::OnDidReceiveData(int id, 234 const std::vector<char>& buffer, 235 int data_offset) { 236 WebPluginResourceClient* client = webplugin_->GetResourceClient(id); 237 if (!client) 238 return; 239 240 client->DidReceiveData(&buffer.front(), static_cast<int>(buffer.size()), 241 data_offset); 242 } 243 244 void WebPluginDelegateStub::OnDidFinishLoading(int id) { 245 WebPluginResourceClient* client = webplugin_->GetResourceClient(id); 246 if (!client) 247 return; 248 249 client->DidFinishLoading(id); 250 } 251 252 void WebPluginDelegateStub::OnDidFail(int id) { 253 WebPluginResourceClient* client = webplugin_->GetResourceClient(id); 254 if (!client) 255 return; 256 257 client->DidFail(id); 258 } 259 260 void WebPluginDelegateStub::OnDidFinishLoadWithReason( 261 const GURL& url, int reason, int notify_id) { 262 delegate_->DidFinishLoadWithReason(url, reason, notify_id); 263 } 264 265 void WebPluginDelegateStub::OnSetFocus(bool focused) { 266 delegate_->SetFocus(focused); 267 #if defined(OS_WIN) && !defined(USE_AURA) 268 if (focused) 269 webplugin_->UpdateIMEStatus(); 270 #endif 271 } 272 273 void WebPluginDelegateStub::OnHandleInputEvent( 274 const WebKit::WebInputEvent *event, 275 bool* handled, 276 WebCursor* cursor) { 277 WebCursor::CursorInfo cursor_info; 278 *handled = delegate_->HandleInputEvent(*event, &cursor_info); 279 cursor->InitFromCursorInfo(cursor_info); 280 } 281 282 void WebPluginDelegateStub::OnPaint(const gfx::Rect& damaged_rect) { 283 webplugin_->Paint(damaged_rect); 284 } 285 286 void WebPluginDelegateStub::OnDidPaint() { 287 webplugin_->DidPaint(); 288 } 289 290 void WebPluginDelegateStub::OnUpdateGeometry( 291 const PluginMsg_UpdateGeometry_Param& param) { 292 webplugin_->UpdateGeometry( 293 param.window_rect, param.clip_rect, 294 param.windowless_buffer0, param.windowless_buffer1, 295 param.windowless_buffer_index); 296 } 297 298 void WebPluginDelegateStub::OnGetPluginScriptableObject(int* route_id) { 299 NPObject* object = delegate_->GetPluginScriptableObject(); 300 if (!object) { 301 *route_id = MSG_ROUTING_NONE; 302 return; 303 } 304 305 *route_id = channel_->GenerateRouteID(); 306 // We will delete the stub immediately before calling PluginDestroyed on the 307 // delegate. It will delete itself sooner if the proxy tells it that it has 308 // been released, or if the channel to the proxy is closed. 309 NPObjectStub* scriptable_stub = new NPObjectStub( 310 object, channel_.get(), *route_id, 311 webplugin_->host_render_view_routing_id(), page_url_); 312 plugin_scriptable_object_ = scriptable_stub->AsWeakPtr(); 313 314 // Release ref added by GetPluginScriptableObject (our stub holds its own). 315 WebBindings::releaseObject(object); 316 } 317 318 void WebPluginDelegateStub::OnGetFormValue(string16* value, bool* success) { 319 *success = false; 320 if (!delegate_) 321 return; 322 *success = delegate_->GetFormValue(value); 323 } 324 325 void WebPluginDelegateStub::OnSendJavaScriptStream(const GURL& url, 326 const std::string& result, 327 bool success, 328 int notify_id) { 329 delegate_->SendJavaScriptStream(url, result, success, notify_id); 330 } 331 332 void WebPluginDelegateStub::OnSetContentAreaFocus(bool has_focus) { 333 if (delegate_) 334 delegate_->SetContentAreaHasFocus(has_focus); 335 } 336 337 #if defined(OS_WIN) && !defined(USE_AURA) 338 void WebPluginDelegateStub::OnImeCompositionUpdated( 339 const string16& text, 340 const std::vector<int>& clauses, 341 const std::vector<int>& target, 342 int cursor_position) { 343 if (delegate_) 344 delegate_->ImeCompositionUpdated(text, clauses, target, cursor_position); 345 #if defined(OS_WIN) && !defined(USE_AURA) 346 webplugin_->UpdateIMEStatus(); 347 #endif 348 } 349 350 void WebPluginDelegateStub::OnImeCompositionCompleted(const string16& text) { 351 if (delegate_) 352 delegate_->ImeCompositionCompleted(text); 353 } 354 #endif 355 356 #if defined(OS_MACOSX) 357 void WebPluginDelegateStub::OnSetWindowFocus(bool has_focus) { 358 if (delegate_) 359 delegate_->SetWindowHasFocus(has_focus); 360 } 361 362 void WebPluginDelegateStub::OnContainerHidden() { 363 if (delegate_) 364 delegate_->SetContainerVisibility(false); 365 } 366 367 void WebPluginDelegateStub::OnContainerShown(gfx::Rect window_frame, 368 gfx::Rect view_frame, 369 bool has_focus) { 370 if (delegate_) { 371 delegate_->WindowFrameChanged(window_frame, view_frame); 372 delegate_->SetContainerVisibility(true); 373 delegate_->SetWindowHasFocus(has_focus); 374 } 375 } 376 377 void WebPluginDelegateStub::OnWindowFrameChanged(const gfx::Rect& window_frame, 378 const gfx::Rect& view_frame) { 379 if (delegate_) 380 delegate_->WindowFrameChanged(window_frame, view_frame); 381 } 382 383 void WebPluginDelegateStub::OnImeCompositionCompleted(const string16& text) { 384 if (delegate_) 385 delegate_->ImeCompositionCompleted(text); 386 } 387 #endif // OS_MACOSX 388 389 void WebPluginDelegateStub::OnDidReceiveManualResponse( 390 const GURL& url, 391 const PluginMsg_DidReceiveResponseParams& params) { 392 delegate_->DidReceiveManualResponse(url, params.mime_type, params.headers, 393 params.expected_length, 394 params.last_modified); 395 } 396 397 void WebPluginDelegateStub::OnDidReceiveManualData( 398 const std::vector<char>& buffer) { 399 delegate_->DidReceiveManualData(&buffer.front(), 400 static_cast<int>(buffer.size())); 401 } 402 403 void WebPluginDelegateStub::OnDidFinishManualLoading() { 404 delegate_->DidFinishManualLoading(); 405 } 406 407 void WebPluginDelegateStub::OnDidManualLoadFail() { 408 delegate_->DidManualLoadFail(); 409 } 410 411 void WebPluginDelegateStub::OnHandleURLRequestReply( 412 unsigned long resource_id, const GURL& url, int notify_id) { 413 WebPluginResourceClient* resource_client = 414 delegate_->CreateResourceClient(resource_id, url, notify_id); 415 webplugin_->OnResourceCreated(resource_id, resource_client); 416 } 417 418 void WebPluginDelegateStub::OnHTTPRangeRequestReply( 419 unsigned long resource_id, int range_request_id) { 420 WebPluginResourceClient* resource_client = 421 delegate_->CreateSeekableResourceClient(resource_id, range_request_id); 422 webplugin_->OnResourceCreated(resource_id, resource_client); 423 } 424 425 } // namespace content 426