webplugin_delegate_stub.cc revision f2477e01787aa58f445919b809d89e252beef54f
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 29using blink::WebBindings; 30using blink::WebCursorInfo; 31 32namespace content { 33 34static 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 59WebPluginDelegateStub::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 70WebPluginDelegateStub::~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 94bool 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 161bool WebPluginDelegateStub::Send(IPC::Message* msg) { 162 return channel_->Send(msg); 163} 164 165void 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 213void 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 222void 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 235void 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 246void WebPluginDelegateStub::OnDidFinishLoading(int id) { 247 WebPluginResourceClient* client = webplugin_->GetResourceClient(id); 248 if (!client) 249 return; 250 251 client->DidFinishLoading(id); 252} 253 254void WebPluginDelegateStub::OnDidFail(int id) { 255 WebPluginResourceClient* client = webplugin_->GetResourceClient(id); 256 if (!client) 257 return; 258 259 client->DidFail(id); 260} 261 262void WebPluginDelegateStub::OnDidFinishLoadWithReason( 263 const GURL& url, int reason, int notify_id) { 264 delegate_->DidFinishLoadWithReason(url, reason, notify_id); 265} 266 267void 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 275void 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 284void WebPluginDelegateStub::OnPaint(const gfx::Rect& damaged_rect) { 285 webplugin_->Paint(damaged_rect); 286} 287 288void WebPluginDelegateStub::OnDidPaint() { 289 webplugin_->DidPaint(); 290} 291 292void 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 300void 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 320void WebPluginDelegateStub::OnGetFormValue(string16* value, bool* success) { 321 *success = false; 322 if (!delegate_) 323 return; 324 *success = delegate_->GetFormValue(value); 325} 326 327void WebPluginDelegateStub::OnSendJavaScriptStream(const GURL& url, 328 const std::string& result, 329 bool success, 330 int notify_id) { 331 delegate_->SendJavaScriptStream(url, result, success, notify_id); 332} 333 334void WebPluginDelegateStub::OnSetContentAreaFocus(bool has_focus) { 335 if (delegate_) 336 delegate_->SetContentAreaHasFocus(has_focus); 337} 338 339#if defined(OS_WIN) && !defined(USE_AURA) 340void WebPluginDelegateStub::OnImeCompositionUpdated( 341 const string16& text, 342 const std::vector<int>& clauses, 343 const std::vector<int>& target, 344 int cursor_position) { 345 if (delegate_) 346 delegate_->ImeCompositionUpdated(text, clauses, target, cursor_position); 347#if defined(OS_WIN) && !defined(USE_AURA) 348 webplugin_->UpdateIMEStatus(); 349#endif 350} 351 352void WebPluginDelegateStub::OnImeCompositionCompleted(const string16& text) { 353 if (delegate_) 354 delegate_->ImeCompositionCompleted(text); 355} 356#endif 357 358#if defined(OS_MACOSX) 359void WebPluginDelegateStub::OnSetWindowFocus(bool has_focus) { 360 if (delegate_) 361 delegate_->SetWindowHasFocus(has_focus); 362} 363 364void WebPluginDelegateStub::OnContainerHidden() { 365 if (delegate_) 366 delegate_->SetContainerVisibility(false); 367} 368 369void WebPluginDelegateStub::OnContainerShown(gfx::Rect window_frame, 370 gfx::Rect view_frame, 371 bool has_focus) { 372 if (delegate_) { 373 delegate_->WindowFrameChanged(window_frame, view_frame); 374 delegate_->SetContainerVisibility(true); 375 delegate_->SetWindowHasFocus(has_focus); 376 } 377} 378 379void WebPluginDelegateStub::OnWindowFrameChanged(const gfx::Rect& window_frame, 380 const gfx::Rect& view_frame) { 381 if (delegate_) 382 delegate_->WindowFrameChanged(window_frame, view_frame); 383} 384 385void WebPluginDelegateStub::OnImeCompositionCompleted(const string16& text) { 386 if (delegate_) 387 delegate_->ImeCompositionCompleted(text); 388} 389#endif // OS_MACOSX 390 391void WebPluginDelegateStub::OnDidReceiveManualResponse( 392 const GURL& url, 393 const PluginMsg_DidReceiveResponseParams& params) { 394 delegate_->DidReceiveManualResponse(url, params.mime_type, params.headers, 395 params.expected_length, 396 params.last_modified); 397} 398 399void WebPluginDelegateStub::OnDidReceiveManualData( 400 const std::vector<char>& buffer) { 401 delegate_->DidReceiveManualData(&buffer.front(), 402 static_cast<int>(buffer.size())); 403} 404 405void WebPluginDelegateStub::OnDidFinishManualLoading() { 406 delegate_->DidFinishManualLoading(); 407} 408 409void WebPluginDelegateStub::OnDidManualLoadFail() { 410 delegate_->DidManualLoadFail(); 411} 412 413void WebPluginDelegateStub::OnHandleURLRequestReply( 414 unsigned long resource_id, const GURL& url, int notify_id) { 415 WebPluginResourceClient* resource_client = 416 delegate_->CreateResourceClient(resource_id, url, notify_id); 417 webplugin_->OnResourceCreated(resource_id, resource_client); 418} 419 420void WebPluginDelegateStub::OnHTTPRangeRequestReply( 421 unsigned long resource_id, int range_request_id) { 422 WebPluginResourceClient* resource_client = 423 delegate_->CreateSeekableResourceClient(resource_id, range_request_id); 424 webplugin_->OnResourceCreated(resource_id, resource_client); 425} 426 427void WebPluginDelegateStub::OnFetchURL( 428 const PluginMsg_FetchURL_Params& params) { 429 const char* data = NULL; 430 if (params.post_data.size()) 431 data = ¶ms.post_data[0]; 432 433 delegate_->FetchURL(params.resource_id, 434 params.notify_id, 435 params.url, 436 params.first_party_for_cookies, 437 params.method, 438 data, 439 static_cast<unsigned int>(params.post_data.size()), 440 params.referrer, 441 params.notify_redirect, 442 params.is_plugin_src_load, 443 channel_->renderer_id(), 444 params.render_view_id); 445} 446 447} // namespace content 448