| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2011 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 "chrome/plugin/webplugin_delegate_stub.h" | |
| 6 | |
| 7 #include "build/build_config.h" | |
| 8 | |
| 9 #include "base/command_line.h" | |
| 10 #include "chrome/plugin/npobject_stub.h" | |
| 11 #include "chrome/plugin/plugin_channel.h" | |
| 12 #include "chrome/plugin/plugin_thread.h" | |
| 13 #include "chrome/plugin/webplugin_proxy.h" | |
| 14 #include "content/common/content_client.h" | |
| 15 #include "content/common/content_switches.h" | |
| 16 #include "content/common/plugin_messages.h" | |
| 17 #include "third_party/npapi/bindings/npapi.h" | |
| 18 #include "third_party/npapi/bindings/npruntime.h" | |
| 19 #include "skia/ext/platform_device.h" | |
| 20 #include "third_party/WebKit/Source/WebKit/chromium/public/WebBindings.h" | |
| 21 #include "third_party/WebKit/Source/WebKit/chromium/public/WebCursorInfo.h" | |
| 22 #include "webkit/plugins/npapi/webplugin_delegate_impl.h" | |
| 23 #include "webkit/glue/webcursor.h" | |
| 24 | |
| 25 #if defined(OS_WIN) | |
| 26 #include "base/scoped_ptr.h" | |
| 27 #include "printing/native_metafile_factory.h" | |
| 28 #include "printing/native_metafile.h" | |
| 29 #endif // defined(OS_WIN) | |
| 30 | |
| 31 using WebKit::WebBindings; | |
| 32 using WebKit::WebCursorInfo; | |
| 33 using webkit::npapi::WebPlugin; | |
| 34 using webkit::npapi::WebPluginResourceClient; | |
| 35 | |
| 36 class FinishDestructionTask : public Task { | |
| 37 public: | |
| 38 FinishDestructionTask(webkit::npapi::WebPluginDelegateImpl* delegate, | |
| 39 WebPlugin* webplugin) | |
| 40 : delegate_(delegate), webplugin_(webplugin) { | |
| 41 } | |
| 42 | |
| 43 void Run() { | |
| 44 // WebPlugin must outlive WebPluginDelegate. | |
| 45 if (delegate_) | |
| 46 delegate_->PluginDestroyed(); | |
| 47 | |
| 48 delete webplugin_; | |
| 49 } | |
| 50 | |
| 51 private: | |
| 52 webkit::npapi::WebPluginDelegateImpl* delegate_; | |
| 53 webkit::npapi::WebPlugin* webplugin_; | |
| 54 }; | |
| 55 | |
| 56 WebPluginDelegateStub::WebPluginDelegateStub( | |
| 57 const std::string& mime_type, int instance_id, PluginChannel* channel) : | |
| 58 mime_type_(mime_type), | |
| 59 instance_id_(instance_id), | |
| 60 channel_(channel), | |
| 61 delegate_(NULL), | |
| 62 webplugin_(NULL), | |
| 63 in_destructor_(false) { | |
| 64 DCHECK(channel); | |
| 65 } | |
| 66 | |
| 67 WebPluginDelegateStub::~WebPluginDelegateStub() { | |
| 68 in_destructor_ = true; | |
| 69 content::GetContentClient()->SetActiveURL(page_url_); | |
| 70 | |
| 71 if (channel_->in_send()) { | |
| 72 // The delegate or an npobject is in the callstack, so don't delete it | |
| 73 // right away. | |
| 74 MessageLoop::current()->PostNonNestableTask(FROM_HERE, | |
| 75 new FinishDestructionTask(delegate_, webplugin_)); | |
| 76 } else { | |
| 77 // Safe to delete right away. | |
| 78 if (delegate_) | |
| 79 delegate_->PluginDestroyed(); | |
| 80 | |
| 81 delete webplugin_; | |
| 82 } | |
| 83 } | |
| 84 | |
| 85 bool WebPluginDelegateStub::OnMessageReceived(const IPC::Message& msg) { | |
| 86 content::GetContentClient()->SetActiveURL(page_url_); | |
| 87 | |
| 88 // A plugin can execute a script to delete itself in any of its NPP methods. | |
| 89 // Hold an extra reference to ourself so that if this does occur and we're | |
| 90 // handling a sync message, we don't crash when attempting to send a reply. | |
| 91 // The exception to this is when we're already in the destructor. | |
| 92 if (!in_destructor_) | |
| 93 AddRef(); | |
| 94 | |
| 95 bool handled = true; | |
| 96 IPC_BEGIN_MESSAGE_MAP(WebPluginDelegateStub, msg) | |
| 97 IPC_MESSAGE_HANDLER(PluginMsg_Init, OnInit) | |
| 98 IPC_MESSAGE_HANDLER(PluginMsg_WillSendRequest, OnWillSendRequest) | |
| 99 IPC_MESSAGE_HANDLER(PluginMsg_DidReceiveResponse, OnDidReceiveResponse) | |
| 100 IPC_MESSAGE_HANDLER(PluginMsg_DidReceiveData, OnDidReceiveData) | |
| 101 IPC_MESSAGE_HANDLER(PluginMsg_DidFinishLoading, OnDidFinishLoading) | |
| 102 IPC_MESSAGE_HANDLER(PluginMsg_DidFail, OnDidFail) | |
| 103 IPC_MESSAGE_HANDLER(PluginMsg_DidFinishLoadWithReason, | |
| 104 OnDidFinishLoadWithReason) | |
| 105 IPC_MESSAGE_HANDLER(PluginMsg_SetFocus, OnSetFocus) | |
| 106 IPC_MESSAGE_HANDLER(PluginMsg_HandleInputEvent, OnHandleInputEvent) | |
| 107 IPC_MESSAGE_HANDLER(PluginMsg_Paint, OnPaint) | |
| 108 IPC_MESSAGE_HANDLER(PluginMsg_DidPaint, OnDidPaint) | |
| 109 IPC_MESSAGE_HANDLER(PluginMsg_Print, OnPrint) | |
| 110 IPC_MESSAGE_HANDLER(PluginMsg_GetPluginScriptableObject, | |
| 111 OnGetPluginScriptableObject) | |
| 112 IPC_MESSAGE_HANDLER(PluginMsg_UpdateGeometry, OnUpdateGeometry) | |
| 113 IPC_MESSAGE_HANDLER(PluginMsg_UpdateGeometrySync, OnUpdateGeometry) | |
| 114 IPC_MESSAGE_HANDLER(PluginMsg_SendJavaScriptStream, | |
| 115 OnSendJavaScriptStream) | |
| 116 IPC_MESSAGE_HANDLER(PluginMsg_SetContentAreaFocus, OnSetContentAreaFocus) | |
| 117 #if defined(OS_MACOSX) | |
| 118 IPC_MESSAGE_HANDLER(PluginMsg_SetWindowFocus, OnSetWindowFocus) | |
| 119 IPC_MESSAGE_HANDLER(PluginMsg_ContainerHidden, OnContainerHidden) | |
| 120 IPC_MESSAGE_HANDLER(PluginMsg_ContainerShown, OnContainerShown) | |
| 121 IPC_MESSAGE_HANDLER(PluginMsg_WindowFrameChanged, OnWindowFrameChanged) | |
| 122 IPC_MESSAGE_HANDLER(PluginMsg_ImeCompositionCompleted, | |
| 123 OnImeCompositionCompleted) | |
| 124 #endif | |
| 125 IPC_MESSAGE_HANDLER(PluginMsg_DidReceiveManualResponse, | |
| 126 OnDidReceiveManualResponse) | |
| 127 IPC_MESSAGE_HANDLER(PluginMsg_DidReceiveManualData, OnDidReceiveManualData) | |
| 128 IPC_MESSAGE_HANDLER(PluginMsg_DidFinishManualLoading, | |
| 129 OnDidFinishManualLoading) | |
| 130 IPC_MESSAGE_HANDLER(PluginMsg_DidManualLoadFail, OnDidManualLoadFail) | |
| 131 IPC_MESSAGE_HANDLER(PluginMsg_InstallMissingPlugin, OnInstallMissingPlugin) | |
| 132 IPC_MESSAGE_HANDLER(PluginMsg_HandleURLRequestReply, | |
| 133 OnHandleURLRequestReply) | |
| 134 IPC_MESSAGE_HANDLER(PluginMsg_HTTPRangeRequestReply, | |
| 135 OnHTTPRangeRequestReply) | |
| 136 #if defined(OS_MACOSX) | |
| 137 IPC_MESSAGE_HANDLER(PluginMsg_SetFakeAcceleratedSurfaceWindowHandle, | |
| 138 OnSetFakeAcceleratedSurfaceWindowHandle) | |
| 139 #endif | |
| 140 IPC_MESSAGE_UNHANDLED(handled = false) | |
| 141 IPC_END_MESSAGE_MAP() | |
| 142 | |
| 143 if (!in_destructor_) | |
| 144 Release(); | |
| 145 | |
| 146 DCHECK(handled); | |
| 147 return handled; | |
| 148 } | |
| 149 | |
| 150 bool WebPluginDelegateStub::Send(IPC::Message* msg) { | |
| 151 return channel_->Send(msg); | |
| 152 } | |
| 153 | |
| 154 void WebPluginDelegateStub::OnInit(const PluginMsg_Init_Params& params, | |
| 155 bool* result) { | |
| 156 page_url_ = params.page_url; | |
| 157 content::GetContentClient()->SetActiveURL(page_url_); | |
| 158 | |
| 159 *result = false; | |
| 160 if (params.arg_names.size() != params.arg_values.size()) { | |
| 161 NOTREACHED(); | |
| 162 return; | |
| 163 } | |
| 164 | |
| 165 const CommandLine& command_line = *CommandLine::ForCurrentProcess(); | |
| 166 FilePath path = | |
| 167 command_line.GetSwitchValuePath(switches::kPluginPath); | |
| 168 | |
| 169 gfx::PluginWindowHandle parent = gfx::kNullPluginWindow; | |
| 170 #if defined(OS_WIN) | |
| 171 parent = gfx::NativeViewFromId(params.containing_window); | |
| 172 #elif defined(OS_LINUX) | |
| 173 // This code is disabled, See issue 17110. | |
| 174 // The problem is that the XID can change at arbitrary times (e.g. when the | |
| 175 // tab is detached then reattached), so we need to be able to track these | |
| 176 // changes, and let the PluginInstance know. | |
| 177 // PluginThread::current()->Send(new PluginProcessHostMsg_MapNativeViewId( | |
| 178 // params.containing_window, &parent)); | |
| 179 #endif | |
| 180 | |
| 181 webplugin_ = new WebPluginProxy( | |
| 182 channel_, instance_id_, page_url_, params.containing_window, | |
| 183 params.host_render_view_routing_id); | |
| 184 delegate_ = webkit::npapi::WebPluginDelegateImpl::Create( | |
| 185 path, mime_type_, parent); | |
| 186 if (delegate_) { | |
| 187 webplugin_->set_delegate(delegate_); | |
| 188 *result = delegate_->Initialize(params.url, | |
| 189 params.arg_names, | |
| 190 params.arg_values, | |
| 191 webplugin_, | |
| 192 params.load_manually); | |
| 193 } | |
| 194 } | |
| 195 | |
| 196 void WebPluginDelegateStub::OnWillSendRequest(int id, const GURL& url, | |
| 197 int http_status_code) { | |
| 198 WebPluginResourceClient* client = webplugin_->GetResourceClient(id); | |
| 199 if (!client) | |
| 200 return; | |
| 201 | |
| 202 client->WillSendRequest(url, http_status_code); | |
| 203 } | |
| 204 | |
| 205 void WebPluginDelegateStub::OnDidReceiveResponse( | |
| 206 const PluginMsg_DidReceiveResponseParams& params) { | |
| 207 WebPluginResourceClient* client = webplugin_->GetResourceClient(params.id); | |
| 208 if (!client) | |
| 209 return; | |
| 210 | |
| 211 client->DidReceiveResponse(params.mime_type, | |
| 212 params.headers, | |
| 213 params.expected_length, | |
| 214 params.last_modified, | |
| 215 params.request_is_seekable); | |
| 216 } | |
| 217 | |
| 218 void WebPluginDelegateStub::OnDidReceiveData(int id, | |
| 219 const std::vector<char>& buffer, | |
| 220 int data_offset) { | |
| 221 WebPluginResourceClient* client = webplugin_->GetResourceClient(id); | |
| 222 if (!client) | |
| 223 return; | |
| 224 | |
| 225 client->DidReceiveData(&buffer.front(), static_cast<int>(buffer.size()), | |
| 226 data_offset); | |
| 227 } | |
| 228 | |
| 229 void WebPluginDelegateStub::OnDidFinishLoading(int id) { | |
| 230 WebPluginResourceClient* client = webplugin_->GetResourceClient(id); | |
| 231 if (!client) | |
| 232 return; | |
| 233 | |
| 234 client->DidFinishLoading(); | |
| 235 } | |
| 236 | |
| 237 void WebPluginDelegateStub::OnDidFail(int id) { | |
| 238 WebPluginResourceClient* client = webplugin_->GetResourceClient(id); | |
| 239 if (!client) | |
| 240 return; | |
| 241 | |
| 242 client->DidFail(); | |
| 243 } | |
| 244 | |
| 245 void WebPluginDelegateStub::OnDidFinishLoadWithReason( | |
| 246 const GURL& url, int reason, int notify_id) { | |
| 247 delegate_->DidFinishLoadWithReason(url, reason, notify_id); | |
| 248 } | |
| 249 | |
| 250 void WebPluginDelegateStub::OnSetFocus(bool focused) { | |
| 251 delegate_->SetFocus(focused); | |
| 252 } | |
| 253 | |
| 254 void WebPluginDelegateStub::OnHandleInputEvent( | |
| 255 const WebKit::WebInputEvent *event, | |
| 256 bool* handled, | |
| 257 WebCursor* cursor) { | |
| 258 WebCursorInfo cursor_info; | |
| 259 *handled = delegate_->HandleInputEvent(*event, &cursor_info); | |
| 260 cursor->InitFromCursorInfo(cursor_info); | |
| 261 } | |
| 262 | |
| 263 void WebPluginDelegateStub::OnPaint(const gfx::Rect& damaged_rect) { | |
| 264 webplugin_->Paint(damaged_rect); | |
| 265 } | |
| 266 | |
| 267 void WebPluginDelegateStub::OnDidPaint() { | |
| 268 webplugin_->DidPaint(); | |
| 269 } | |
| 270 | |
| 271 void WebPluginDelegateStub::OnPrint(base::SharedMemoryHandle* shared_memory, | |
| 272 uint32* size) { | |
| 273 #if defined(OS_WIN) | |
| 274 scoped_ptr<printing::NativeMetafile> metafile( | |
| 275 printing::NativeMetafileFactory::CreateMetafile()); | |
| 276 if (!metafile->CreateDc(NULL, NULL)) { | |
| 277 NOTREACHED(); | |
| 278 return; | |
| 279 } | |
| 280 HDC hdc = metafile->context(); | |
| 281 skia::PlatformDevice::InitializeDC(hdc); | |
| 282 delegate_->Print(hdc); | |
| 283 if (!metafile->Close()) { | |
| 284 NOTREACHED(); | |
| 285 return; | |
| 286 } | |
| 287 | |
| 288 *size = metafile->GetDataSize(); | |
| 289 DCHECK(*size); | |
| 290 base::SharedMemory shared_buf; | |
| 291 CreateSharedBuffer(*size, &shared_buf, shared_memory); | |
| 292 | |
| 293 // Retrieve a copy of the data. | |
| 294 bool success = metafile->GetData(shared_buf.memory(), *size); | |
| 295 DCHECK(success); | |
| 296 #else | |
| 297 // TODO(port): plugin printing. | |
| 298 NOTIMPLEMENTED(); | |
| 299 #endif | |
| 300 } | |
| 301 | |
| 302 void WebPluginDelegateStub::OnUpdateGeometry( | |
| 303 const PluginMsg_UpdateGeometry_Param& param) { | |
| 304 webplugin_->UpdateGeometry( | |
| 305 param.window_rect, param.clip_rect, | |
| 306 param.windowless_buffer, param.background_buffer, | |
| 307 param.transparent | |
| 308 #if defined(OS_MACOSX) | |
| 309 , | |
| 310 param.ack_key | |
| 311 #endif | |
| 312 ); | |
| 313 } | |
| 314 | |
| 315 void WebPluginDelegateStub::OnGetPluginScriptableObject(int* route_id) { | |
| 316 NPObject* object = delegate_->GetPluginScriptableObject(); | |
| 317 if (!object) { | |
| 318 *route_id = MSG_ROUTING_NONE; | |
| 319 return; | |
| 320 } | |
| 321 | |
| 322 *route_id = channel_->GenerateRouteID(); | |
| 323 // The stub will delete itself when the proxy tells it that it's released, or | |
| 324 // otherwise when the channel is closed. | |
| 325 new NPObjectStub( | |
| 326 object, channel_.get(), *route_id, webplugin_->containing_window(), | |
| 327 page_url_); | |
| 328 | |
| 329 // Release ref added by GetPluginScriptableObject (our stub holds its own). | |
| 330 WebBindings::releaseObject(object); | |
| 331 } | |
| 332 | |
| 333 void WebPluginDelegateStub::OnSendJavaScriptStream(const GURL& url, | |
| 334 const std::string& result, | |
| 335 bool success, | |
| 336 int notify_id) { | |
| 337 delegate_->SendJavaScriptStream(url, result, success, notify_id); | |
| 338 } | |
| 339 | |
| 340 void WebPluginDelegateStub::OnSetContentAreaFocus(bool has_focus) { | |
| 341 if (delegate_) | |
| 342 delegate_->SetContentAreaHasFocus(has_focus); | |
| 343 } | |
| 344 | |
| 345 #if defined(OS_MACOSX) | |
| 346 void WebPluginDelegateStub::OnSetWindowFocus(bool has_focus) { | |
| 347 if (delegate_) | |
| 348 delegate_->SetWindowHasFocus(has_focus); | |
| 349 } | |
| 350 | |
| 351 void WebPluginDelegateStub::OnContainerHidden() { | |
| 352 if (delegate_) | |
| 353 delegate_->SetContainerVisibility(false); | |
| 354 } | |
| 355 | |
| 356 void WebPluginDelegateStub::OnContainerShown(gfx::Rect window_frame, | |
| 357 gfx::Rect view_frame, | |
| 358 bool has_focus) { | |
| 359 if (delegate_) { | |
| 360 delegate_->WindowFrameChanged(window_frame, view_frame); | |
| 361 delegate_->SetContainerVisibility(true); | |
| 362 delegate_->SetWindowHasFocus(has_focus); | |
| 363 } | |
| 364 } | |
| 365 | |
| 366 void WebPluginDelegateStub::OnWindowFrameChanged(const gfx::Rect& window_frame, | |
| 367 const gfx::Rect& view_frame) { | |
| 368 if (delegate_) | |
| 369 delegate_->WindowFrameChanged(window_frame, view_frame); | |
| 370 } | |
| 371 | |
| 372 void WebPluginDelegateStub::OnImeCompositionCompleted(const string16& text) { | |
| 373 if (delegate_) | |
| 374 delegate_->ImeCompositionCompleted(text); | |
| 375 } | |
| 376 #endif // OS_MACOSX | |
| 377 | |
| 378 void WebPluginDelegateStub::OnDidReceiveManualResponse( | |
| 379 const GURL& url, | |
| 380 const PluginMsg_DidReceiveResponseParams& params) { | |
| 381 delegate_->DidReceiveManualResponse(url, params.mime_type, params.headers, | |
| 382 params.expected_length, | |
| 383 params.last_modified); | |
| 384 } | |
| 385 | |
| 386 void WebPluginDelegateStub::OnDidReceiveManualData( | |
| 387 const std::vector<char>& buffer) { | |
| 388 delegate_->DidReceiveManualData(&buffer.front(), | |
| 389 static_cast<int>(buffer.size())); | |
| 390 } | |
| 391 | |
| 392 void WebPluginDelegateStub::OnDidFinishManualLoading() { | |
| 393 delegate_->DidFinishManualLoading(); | |
| 394 } | |
| 395 | |
| 396 void WebPluginDelegateStub::OnDidManualLoadFail() { | |
| 397 delegate_->DidManualLoadFail(); | |
| 398 } | |
| 399 | |
| 400 void WebPluginDelegateStub::OnInstallMissingPlugin() { | |
| 401 delegate_->InstallMissingPlugin(); | |
| 402 } | |
| 403 | |
| 404 void WebPluginDelegateStub::CreateSharedBuffer( | |
| 405 uint32 size, | |
| 406 base::SharedMemory* shared_buf, | |
| 407 base::SharedMemoryHandle* remote_handle) { | |
| 408 if (!shared_buf->CreateAndMapAnonymous(size)) { | |
| 409 NOTREACHED(); | |
| 410 shared_buf->Close(); | |
| 411 return; | |
| 412 } | |
| 413 | |
| 414 #if defined(OS_WIN) | |
| 415 BOOL result = DuplicateHandle(GetCurrentProcess(), | |
| 416 shared_buf->handle(), | |
| 417 channel_->renderer_handle(), | |
| 418 remote_handle, 0, FALSE, | |
| 419 DUPLICATE_SAME_ACCESS); | |
| 420 DCHECK_NE(result, 0); | |
| 421 | |
| 422 // If the calling function's shared_buf is on the stack, its destructor will | |
| 423 // close the shared memory buffer handle. This is fine since we already | |
| 424 // duplicated the handle to the renderer process so it will stay "alive". | |
| 425 #else | |
| 426 // TODO(port): this should use TransportDIB. | |
| 427 NOTIMPLEMENTED(); | |
| 428 #endif | |
| 429 } | |
| 430 | |
| 431 void WebPluginDelegateStub::OnHandleURLRequestReply( | |
| 432 unsigned long resource_id, const GURL& url, int notify_id) { | |
| 433 WebPluginResourceClient* resource_client = | |
| 434 delegate_->CreateResourceClient(resource_id, url, notify_id); | |
| 435 webplugin_->OnResourceCreated(resource_id, resource_client); | |
| 436 } | |
| 437 | |
| 438 void WebPluginDelegateStub::OnHTTPRangeRequestReply( | |
| 439 unsigned long resource_id, int range_request_id) { | |
| 440 WebPluginResourceClient* resource_client = | |
| 441 delegate_->CreateSeekableResourceClient(resource_id, range_request_id); | |
| 442 webplugin_->OnResourceCreated(resource_id, resource_client); | |
| 443 } | |
| 444 | |
| 445 #if defined(OS_MACOSX) | |
| 446 void WebPluginDelegateStub::OnSetFakeAcceleratedSurfaceWindowHandle( | |
| 447 gfx::PluginWindowHandle window) { | |
| 448 delegate_->set_windowed_handle(window); | |
| 449 } | |
| 450 #endif | |
| 451 | |
| OLD | NEW |