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