| 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/renderer/pepper_plugin_delegate_impl.h" | |
| 6 | |
| 7 #include <cmath> | |
| 8 #include <queue> | |
| 9 | |
| 10 #include "app/surface/transport_dib.h" | |
| 11 #include "base/callback.h" | |
| 12 #include "base/file_path.h" | |
| 13 #include "base/logging.h" | |
| 14 #include "base/scoped_ptr.h" | |
| 15 #include "base/string_split.h" | |
| 16 #include "base/task.h" | |
| 17 #include "base/time.h" | |
| 18 #include "chrome/common/pepper_plugin_registry.h" | |
| 19 #include "chrome/common/render_messages.h" | |
| 20 #include "chrome/common/render_messages_params.h" | |
| 21 #include "chrome/renderer/pepper_platform_context_3d_impl.h" | |
| 22 #include "chrome/renderer/render_thread.h" | |
| 23 #include "chrome/renderer/render_view.h" | |
| 24 #include "content/common/child_process_messages.h" | |
| 25 #include "content/common/child_thread.h" | |
| 26 #include "content/common/file_system/file_system_dispatcher.h" | |
| 27 #include "content/common/pepper_file_messages.h" | |
| 28 #include "content/common/pepper_messages.h" | |
| 29 #include "content/renderer/audio_message_filter.h" | |
| 30 #include "content/renderer/command_buffer_proxy.h" | |
| 31 #include "content/renderer/ggl.h" | |
| 32 #include "content/renderer/gpu_channel_host.h" | |
| 33 #include "content/renderer/webgraphicscontext3d_command_buffer_impl.h" | |
| 34 #include "content/renderer/webplugin_delegate_proxy.h" | |
| 35 #include "grit/locale_settings.h" | |
| 36 #include "ipc/ipc_channel_handle.h" | |
| 37 #include "ppapi/c/dev/pp_video_dev.h" | |
| 38 #include "ppapi/c/pp_errors.h" | |
| 39 #include "ppapi/c/private/ppb_flash.h" | |
| 40 #include "ppapi/c/private/ppb_flash_net_connector.h" | |
| 41 #include "ppapi/proxy/host_dispatcher.h" | |
| 42 #include "third_party/WebKit/Source/WebKit/chromium/public/WebFileChooserComplet
ion.h" | |
| 43 #include "third_party/WebKit/Source/WebKit/chromium/public/WebFileChooserParams.
h" | |
| 44 #include "third_party/WebKit/Source/WebKit/chromium/public/WebPluginContainer.h" | |
| 45 #include "third_party/WebKit/Source/WebKit/chromium/public/WebScreenInfo.h" | |
| 46 #include "third_party/WebKit/Source/WebKit/chromium/public/WebView.h" | |
| 47 #include "ui/base/l10n/l10n_util.h" | |
| 48 #include "ui/gfx/size.h" | |
| 49 #include "webkit/fileapi/file_system_callback_dispatcher.h" | |
| 50 #include "webkit/glue/context_menu.h" | |
| 51 #include "webkit/plugins/npapi/webplugin.h" | |
| 52 #include "webkit/plugins/ppapi/file_path.h" | |
| 53 #include "webkit/plugins/ppapi/ppb_file_io_impl.h" | |
| 54 #include "webkit/plugins/ppapi/plugin_module.h" | |
| 55 #include "webkit/plugins/ppapi/ppapi_plugin_instance.h" | |
| 56 #include "webkit/plugins/ppapi/ppb_flash_impl.h" | |
| 57 #include "webkit/plugins/ppapi/ppb_flash_net_connector_impl.h" | |
| 58 | |
| 59 using WebKit::WebView; | |
| 60 | |
| 61 namespace { | |
| 62 | |
| 63 const int32 kDefaultCommandBufferSize = 1024 * 1024; | |
| 64 | |
| 65 // Implements the Image2D using a TransportDIB. | |
| 66 class PlatformImage2DImpl | |
| 67 : public webkit::ppapi::PluginDelegate::PlatformImage2D { | |
| 68 public: | |
| 69 // This constructor will take ownership of the dib pointer. | |
| 70 // On Mac, we assume that the dib is cached by the browser, so on destruction | |
| 71 // we'll tell the browser to free it. | |
| 72 PlatformImage2DImpl(int width, int height, TransportDIB* dib) | |
| 73 : width_(width), | |
| 74 height_(height), | |
| 75 dib_(dib) { | |
| 76 } | |
| 77 | |
| 78 #if defined(OS_MACOSX) | |
| 79 // On Mac, we have to tell the browser to free the transport DIB. | |
| 80 virtual ~PlatformImage2DImpl() { | |
| 81 if (dib_.get()) { | |
| 82 RenderThread::current()->Send( | |
| 83 new ViewHostMsg_FreeTransportDIB(dib_->id())); | |
| 84 } | |
| 85 } | |
| 86 #endif | |
| 87 | |
| 88 virtual skia::PlatformCanvas* Map() { | |
| 89 return dib_->GetPlatformCanvas(width_, height_); | |
| 90 } | |
| 91 | |
| 92 virtual intptr_t GetSharedMemoryHandle(uint32* byte_count) const { | |
| 93 *byte_count = dib_->size(); | |
| 94 #if defined(OS_WIN) | |
| 95 return reinterpret_cast<intptr_t>(dib_->handle()); | |
| 96 #elif defined(OS_MACOSX) | |
| 97 return static_cast<intptr_t>(dib_->handle().fd); | |
| 98 #elif defined(OS_LINUX) | |
| 99 return static_cast<intptr_t>(dib_->handle()); | |
| 100 #endif | |
| 101 } | |
| 102 | |
| 103 virtual TransportDIB* GetTransportDIB() const { | |
| 104 return dib_.get(); | |
| 105 } | |
| 106 | |
| 107 private: | |
| 108 int width_; | |
| 109 int height_; | |
| 110 scoped_ptr<TransportDIB> dib_; | |
| 111 | |
| 112 DISALLOW_COPY_AND_ASSIGN(PlatformImage2DImpl); | |
| 113 }; | |
| 114 | |
| 115 | |
| 116 class PlatformAudioImpl | |
| 117 : public webkit::ppapi::PluginDelegate::PlatformAudio, | |
| 118 public AudioMessageFilter::Delegate, | |
| 119 public base::RefCountedThreadSafe<PlatformAudioImpl> { | |
| 120 public: | |
| 121 explicit PlatformAudioImpl(scoped_refptr<AudioMessageFilter> filter) | |
| 122 : client_(NULL), filter_(filter), stream_id_(0), | |
| 123 main_message_loop_(MessageLoop::current()) { | |
| 124 DCHECK(filter_); | |
| 125 } | |
| 126 | |
| 127 virtual ~PlatformAudioImpl() { | |
| 128 // Make sure we have been shut down. Warning: this will usually happen on | |
| 129 // the I/O thread! | |
| 130 DCHECK_EQ(0, stream_id_); | |
| 131 DCHECK(!client_); | |
| 132 } | |
| 133 | |
| 134 // Initialize this audio context. StreamCreated() will be called when the | |
| 135 // stream is created. | |
| 136 bool Initialize(uint32_t sample_rate, uint32_t sample_count, | |
| 137 webkit::ppapi::PluginDelegate::PlatformAudio::Client* client); | |
| 138 | |
| 139 // PlatformAudio implementation (called on main thread). | |
| 140 virtual bool StartPlayback(); | |
| 141 virtual bool StopPlayback(); | |
| 142 virtual void ShutDown(); | |
| 143 | |
| 144 private: | |
| 145 // I/O thread backends to above functions. | |
| 146 void InitializeOnIOThread( | |
| 147 const ViewHostMsg_Audio_CreateStream_Params& params); | |
| 148 void StartPlaybackOnIOThread(); | |
| 149 void StopPlaybackOnIOThread(); | |
| 150 void ShutDownOnIOThread(); | |
| 151 | |
| 152 virtual void OnRequestPacket(AudioBuffersState buffers_state) { | |
| 153 LOG(FATAL) << "Should never get OnRequestPacket in PlatformAudioImpl"; | |
| 154 } | |
| 155 | |
| 156 virtual void OnStateChanged(const ViewMsg_AudioStreamState_Params& state) {} | |
| 157 | |
| 158 virtual void OnCreated(base::SharedMemoryHandle handle, uint32 length) { | |
| 159 LOG(FATAL) << "Should never get OnCreated in PlatformAudioImpl"; | |
| 160 } | |
| 161 | |
| 162 virtual void OnLowLatencyCreated(base::SharedMemoryHandle handle, | |
| 163 base::SyncSocket::Handle socket_handle, | |
| 164 uint32 length); | |
| 165 | |
| 166 virtual void OnVolume(double volume) {} | |
| 167 | |
| 168 // The client to notify when the stream is created. THIS MUST ONLY BE | |
| 169 // ACCESSED ON THE MAIN THREAD. | |
| 170 webkit::ppapi::PluginDelegate::PlatformAudio::Client* client_; | |
| 171 | |
| 172 // MessageFilter used to send/receive IPC. THIS MUST ONLY BE ACCESSED ON THE | |
| 173 // I/O thread except to send messages and get the message loop. | |
| 174 scoped_refptr<AudioMessageFilter> filter_; | |
| 175 | |
| 176 // Our ID on the MessageFilter. THIS MUST ONLY BE ACCESSED ON THE I/O THREAD | |
| 177 // or else you could race with the initialize function which sets it. | |
| 178 int32 stream_id_; | |
| 179 | |
| 180 MessageLoop* main_message_loop_; | |
| 181 | |
| 182 DISALLOW_COPY_AND_ASSIGN(PlatformAudioImpl); | |
| 183 }; | |
| 184 | |
| 185 bool PlatformAudioImpl::Initialize( | |
| 186 uint32_t sample_rate, uint32_t sample_count, | |
| 187 webkit::ppapi::PluginDelegate::PlatformAudio::Client* client) { | |
| 188 | |
| 189 DCHECK(client); | |
| 190 // Make sure we don't call init more than once. | |
| 191 DCHECK_EQ(0, stream_id_); | |
| 192 | |
| 193 client_ = client; | |
| 194 | |
| 195 ViewHostMsg_Audio_CreateStream_Params params; | |
| 196 params.params.format = AudioParameters::AUDIO_PCM_LINEAR; | |
| 197 params.params.channels = 2; | |
| 198 params.params.sample_rate = sample_rate; | |
| 199 params.params.bits_per_sample = 16; | |
| 200 params.params.samples_per_packet = sample_count; | |
| 201 | |
| 202 filter_->message_loop()->PostTask(FROM_HERE, | |
| 203 NewRunnableMethod(this, &PlatformAudioImpl::InitializeOnIOThread, | |
| 204 params)); | |
| 205 return true; | |
| 206 } | |
| 207 | |
| 208 bool PlatformAudioImpl::StartPlayback() { | |
| 209 if (filter_) { | |
| 210 filter_->message_loop()->PostTask(FROM_HERE, | |
| 211 NewRunnableMethod(this, &PlatformAudioImpl::StartPlaybackOnIOThread)); | |
| 212 return true; | |
| 213 } | |
| 214 return false; | |
| 215 } | |
| 216 | |
| 217 bool PlatformAudioImpl::StopPlayback() { | |
| 218 if (filter_) { | |
| 219 filter_->message_loop()->PostTask(FROM_HERE, | |
| 220 NewRunnableMethod(this, &PlatformAudioImpl::StopPlaybackOnIOThread)); | |
| 221 return true; | |
| 222 } | |
| 223 return false; | |
| 224 } | |
| 225 | |
| 226 void PlatformAudioImpl::ShutDown() { | |
| 227 // Called on the main thread to stop all audio callbacks. We must only change | |
| 228 // the client on the main thread, and the delegates from the I/O thread. | |
| 229 client_ = NULL; | |
| 230 filter_->message_loop()->PostTask(FROM_HERE, | |
| 231 NewRunnableMethod(this, &PlatformAudioImpl::ShutDownOnIOThread)); | |
| 232 } | |
| 233 | |
| 234 void PlatformAudioImpl::InitializeOnIOThread( | |
| 235 const ViewHostMsg_Audio_CreateStream_Params& params) { | |
| 236 stream_id_ = filter_->AddDelegate(this); | |
| 237 filter_->Send(new ViewHostMsg_CreateAudioStream(0, stream_id_, params, true)); | |
| 238 } | |
| 239 | |
| 240 void PlatformAudioImpl::StartPlaybackOnIOThread() { | |
| 241 if (stream_id_) | |
| 242 filter_->Send(new ViewHostMsg_PlayAudioStream(0, stream_id_)); | |
| 243 } | |
| 244 | |
| 245 void PlatformAudioImpl::StopPlaybackOnIOThread() { | |
| 246 if (stream_id_) | |
| 247 filter_->Send(new ViewHostMsg_PauseAudioStream(0, stream_id_)); | |
| 248 } | |
| 249 | |
| 250 void PlatformAudioImpl::ShutDownOnIOThread() { | |
| 251 // Make sure we don't call shutdown more than once. | |
| 252 if (!stream_id_) | |
| 253 return; | |
| 254 | |
| 255 filter_->Send(new ViewHostMsg_CloseAudioStream(0, stream_id_)); | |
| 256 filter_->RemoveDelegate(stream_id_); | |
| 257 stream_id_ = 0; | |
| 258 | |
| 259 Release(); // Release for the delegate, balances out the reference taken in | |
| 260 // PepperPluginDelegateImpl::CreateAudio. | |
| 261 } | |
| 262 | |
| 263 void PlatformAudioImpl::OnLowLatencyCreated( | |
| 264 base::SharedMemoryHandle handle, base::SyncSocket::Handle socket_handle, | |
| 265 uint32 length) { | |
| 266 #if defined(OS_WIN) | |
| 267 DCHECK(handle); | |
| 268 DCHECK(socket_handle); | |
| 269 #else | |
| 270 DCHECK_NE(-1, handle.fd); | |
| 271 DCHECK_NE(-1, socket_handle); | |
| 272 #endif | |
| 273 DCHECK(length); | |
| 274 | |
| 275 if (MessageLoop::current() == main_message_loop_) { | |
| 276 // Must dereference the client only on the main thread. Shutdown may have | |
| 277 // occurred while the request was in-flight, so we need to NULL check. | |
| 278 if (client_) | |
| 279 client_->StreamCreated(handle, length, socket_handle); | |
| 280 } else { | |
| 281 main_message_loop_->PostTask(FROM_HERE, | |
| 282 NewRunnableMethod(this, &PlatformAudioImpl::OnLowLatencyCreated, | |
| 283 handle, socket_handle, length)); | |
| 284 } | |
| 285 } | |
| 286 | |
| 287 // Implements the VideoDecoder. | |
| 288 class PlatformVideoDecoderImpl | |
| 289 : public webkit::ppapi::PluginDelegate::PlatformVideoDecoder { | |
| 290 public: | |
| 291 PlatformVideoDecoderImpl() | |
| 292 : input_buffer_size_(0), | |
| 293 next_dib_id_(0), | |
| 294 dib_(NULL) { | |
| 295 memset(&decoder_config_, 0, sizeof(decoder_config_)); | |
| 296 memset(&flush_callback_, 0, sizeof(flush_callback_)); | |
| 297 } | |
| 298 | |
| 299 virtual bool Init(const PP_VideoDecoderConfig_Dev& decoder_config) { | |
| 300 decoder_config_ = decoder_config; | |
| 301 input_buffer_size_ = 1024 << 4; | |
| 302 | |
| 303 // Allocate the transport DIB. | |
| 304 TransportDIB* dib = TransportDIB::Create(input_buffer_size_, | |
| 305 next_dib_id_++); | |
| 306 if (!dib) | |
| 307 return false; | |
| 308 | |
| 309 // TODO(wjia): Create video decoder in GPU process. | |
| 310 // Meanwhile, delete |dib| to free the resource. | |
| 311 delete dib; | |
| 312 | |
| 313 return true; | |
| 314 } | |
| 315 | |
| 316 virtual bool Decode(PP_VideoCompressedDataBuffer_Dev& input_buffer) { | |
| 317 // TODO(wjia): Implement me! | |
| 318 NOTIMPLEMENTED(); | |
| 319 | |
| 320 input_buffers_.push(&input_buffer); | |
| 321 | |
| 322 // Copy input data to dib_ and send it to GPU video decoder. | |
| 323 | |
| 324 return false; | |
| 325 } | |
| 326 | |
| 327 virtual int32_t Flush(PP_CompletionCallback& callback) { | |
| 328 // TODO(wjia): Implement me! | |
| 329 NOTIMPLEMENTED(); | |
| 330 | |
| 331 // Do nothing if there is a flush pending. | |
| 332 if (flush_callback_.func) | |
| 333 return PP_ERROR_BADARGUMENT; | |
| 334 | |
| 335 flush_callback_ = callback; | |
| 336 | |
| 337 // Call GPU video decoder to flush. | |
| 338 | |
| 339 return PP_ERROR_WOULDBLOCK; | |
| 340 } | |
| 341 | |
| 342 virtual bool ReturnUncompressedDataBuffer( | |
| 343 PP_VideoUncompressedDataBuffer_Dev& buffer) { | |
| 344 // TODO(wjia): Implement me! | |
| 345 NOTIMPLEMENTED(); | |
| 346 | |
| 347 // Deliver the buffer to GPU video decoder. | |
| 348 | |
| 349 return false; | |
| 350 } | |
| 351 | |
| 352 void OnFlushDone() { | |
| 353 if (!flush_callback_.func) | |
| 354 return; | |
| 355 | |
| 356 flush_callback_.func(flush_callback_.user_data, PP_OK); | |
| 357 flush_callback_.func = NULL; | |
| 358 } | |
| 359 | |
| 360 virtual intptr_t GetSharedMemoryHandle() const { | |
| 361 return reinterpret_cast<intptr_t>(dib_.get()); | |
| 362 } | |
| 363 | |
| 364 private: | |
| 365 size_t input_buffer_size_; | |
| 366 int next_dib_id_; | |
| 367 scoped_ptr<TransportDIB> dib_; | |
| 368 PP_VideoDecoderConfig_Dev decoder_config_; | |
| 369 std::queue<PP_VideoCompressedDataBuffer_Dev*> input_buffers_; | |
| 370 PP_CompletionCallback flush_callback_; | |
| 371 | |
| 372 DISALLOW_COPY_AND_ASSIGN(PlatformVideoDecoderImpl); | |
| 373 }; | |
| 374 | |
| 375 class DispatcherWrapper | |
| 376 : public webkit::ppapi::PluginDelegate::OutOfProcessProxy { | |
| 377 public: | |
| 378 DispatcherWrapper() {} | |
| 379 virtual ~DispatcherWrapper() {} | |
| 380 | |
| 381 bool Init(base::ProcessHandle plugin_process_handle, | |
| 382 IPC::ChannelHandle channel_handle, | |
| 383 PP_Module pp_module, | |
| 384 pp::proxy::Dispatcher::GetInterfaceFunc local_get_interface); | |
| 385 | |
| 386 // OutOfProcessProxy implementation. | |
| 387 virtual const void* GetProxiedInterface(const char* name) { | |
| 388 return dispatcher_->GetProxiedInterface(name); | |
| 389 } | |
| 390 virtual void AddInstance(PP_Instance instance) { | |
| 391 pp::proxy::HostDispatcher::SetForInstance(instance, dispatcher_.get()); | |
| 392 } | |
| 393 virtual void RemoveInstance(PP_Instance instance) { | |
| 394 pp::proxy::HostDispatcher::RemoveForInstance(instance); | |
| 395 } | |
| 396 | |
| 397 private: | |
| 398 scoped_ptr<pp::proxy::HostDispatcher> dispatcher_; | |
| 399 }; | |
| 400 | |
| 401 bool DispatcherWrapper::Init( | |
| 402 base::ProcessHandle plugin_process_handle, | |
| 403 IPC::ChannelHandle channel_handle, | |
| 404 PP_Module pp_module, | |
| 405 pp::proxy::Dispatcher::GetInterfaceFunc local_get_interface) { | |
| 406 dispatcher_.reset(new pp::proxy::HostDispatcher( | |
| 407 plugin_process_handle, pp_module, local_get_interface)); | |
| 408 | |
| 409 if (!dispatcher_->InitWithChannel(PepperPluginRegistry::GetInstance(), | |
| 410 channel_handle, true)) { | |
| 411 dispatcher_.reset(); | |
| 412 return false; | |
| 413 } | |
| 414 return true; | |
| 415 } | |
| 416 | |
| 417 } // namespace | |
| 418 | |
| 419 PepperPluginDelegateImpl::PepperPluginDelegateImpl(RenderView* render_view) | |
| 420 : render_view_(render_view), | |
| 421 has_saved_context_menu_action_(false), | |
| 422 saved_context_menu_action_(0), | |
| 423 id_generator_(0) { | |
| 424 } | |
| 425 | |
| 426 PepperPluginDelegateImpl::~PepperPluginDelegateImpl() { | |
| 427 } | |
| 428 | |
| 429 scoped_refptr<webkit::ppapi::PluginModule> | |
| 430 PepperPluginDelegateImpl::CreatePepperPlugin(const FilePath& path) { | |
| 431 // See if a module has already been loaded for this plugin. | |
| 432 scoped_refptr<webkit::ppapi::PluginModule> module = | |
| 433 PepperPluginRegistry::GetInstance()->GetLiveModule(path); | |
| 434 if (module) | |
| 435 return module; | |
| 436 | |
| 437 // In-process plugins will have always been created up-front to avoid the | |
| 438 // sandbox restrictions. So gettin here implies it doesn't exist or should | |
| 439 // be out of process. | |
| 440 const PepperPluginInfo* info = | |
| 441 PepperPluginRegistry::GetInstance()->GetInfoForPlugin(path); | |
| 442 if (!info || !info->is_out_of_process) | |
| 443 return module; // Return the NULL module. | |
| 444 | |
| 445 // Out of process: have the browser start the plugin process for us. | |
| 446 base::ProcessHandle plugin_process_handle = base::kNullProcessHandle; | |
| 447 IPC::ChannelHandle channel_handle; | |
| 448 render_view_->Send(new ViewHostMsg_OpenChannelToPepperPlugin( | |
| 449 path, &plugin_process_handle, &channel_handle)); | |
| 450 if (channel_handle.name.empty()) { | |
| 451 // Couldn't be initialized. | |
| 452 return scoped_refptr<webkit::ppapi::PluginModule>(); | |
| 453 } | |
| 454 | |
| 455 // Create a new HostDispatcher for the proxying, and hook it to a new | |
| 456 // PluginModule. Note that AddLiveModule must be called before any early | |
| 457 // returns since the module's destructor will remove itself. | |
| 458 module = new webkit::ppapi::PluginModule(info->name, | |
| 459 PepperPluginRegistry::GetInstance()); | |
| 460 PepperPluginRegistry::GetInstance()->AddLiveModule(path, module); | |
| 461 scoped_ptr<DispatcherWrapper> dispatcher(new DispatcherWrapper); | |
| 462 if (!dispatcher->Init( | |
| 463 plugin_process_handle, channel_handle, | |
| 464 module->pp_module(), | |
| 465 webkit::ppapi::PluginModule::GetLocalGetInterfaceFunc())) | |
| 466 return scoped_refptr<webkit::ppapi::PluginModule>(); | |
| 467 module->InitAsProxied(dispatcher.release()); | |
| 468 return module; | |
| 469 } | |
| 470 | |
| 471 void PepperPluginDelegateImpl::ViewInitiatedPaint() { | |
| 472 // Notify all of our instances that we started painting. This is used for | |
| 473 // internal bookkeeping only, so we know that the set can not change under | |
| 474 // us. | |
| 475 for (std::set<webkit::ppapi::PluginInstance*>::iterator i = | |
| 476 active_instances_.begin(); | |
| 477 i != active_instances_.end(); ++i) | |
| 478 (*i)->ViewInitiatedPaint(); | |
| 479 } | |
| 480 | |
| 481 void PepperPluginDelegateImpl::ViewFlushedPaint() { | |
| 482 // Notify all instances that we painted. This will call into the plugin, and | |
| 483 // we it may ask to close itself as a result. This will, in turn, modify our | |
| 484 // set, possibly invalidating the iterator. So we iterate on a copy that | |
| 485 // won't change out from under us. | |
| 486 std::set<webkit::ppapi::PluginInstance*> plugins = active_instances_; | |
| 487 for (std::set<webkit::ppapi::PluginInstance*>::iterator i = plugins.begin(); | |
| 488 i != plugins.end(); ++i) { | |
| 489 // The copy above makes sure our iterator is never invalid if some plugins | |
| 490 // are destroyed. But some plugin may decide to close all of its views in | |
| 491 // response to a paint in one of them, so we need to make sure each one is | |
| 492 // still "current" before using it. | |
| 493 // | |
| 494 // It's possible that a plugin was destroyed, but another one was created | |
| 495 // with the same address. In this case, we'll call ViewFlushedPaint on that | |
| 496 // new plugin. But that's OK for this particular case since we're just | |
| 497 // notifying all of our instances that the view flushed, and the new one is | |
| 498 // one of our instances. | |
| 499 // | |
| 500 // What about the case where a new one is created in a callback at a new | |
| 501 // address and we don't issue the callback? We're still OK since this | |
| 502 // callback is used for flush callbacks and we could not have possibly | |
| 503 // started a new paint (ViewInitiatedPaint) for the new plugin while | |
| 504 // processing a previous paint for an existing one. | |
| 505 if (active_instances_.find(*i) != active_instances_.end()) | |
| 506 (*i)->ViewFlushedPaint(); | |
| 507 } | |
| 508 } | |
| 509 | |
| 510 webkit::ppapi::PluginInstance* | |
| 511 PepperPluginDelegateImpl::GetBitmapForOptimizedPluginPaint( | |
| 512 const gfx::Rect& paint_bounds, | |
| 513 TransportDIB** dib, | |
| 514 gfx::Rect* location, | |
| 515 gfx::Rect* clip) { | |
| 516 for (std::set<webkit::ppapi::PluginInstance*>::iterator i = | |
| 517 active_instances_.begin(); | |
| 518 i != active_instances_.end(); ++i) { | |
| 519 webkit::ppapi::PluginInstance* instance = *i; | |
| 520 if (instance->GetBitmapForOptimizedPluginPaint( | |
| 521 paint_bounds, dib, location, clip)) | |
| 522 return *i; | |
| 523 } | |
| 524 return NULL; | |
| 525 } | |
| 526 | |
| 527 void PepperPluginDelegateImpl::InstanceCreated( | |
| 528 webkit::ppapi::PluginInstance* instance) { | |
| 529 active_instances_.insert(instance); | |
| 530 | |
| 531 // Set the initial focus. | |
| 532 instance->SetContentAreaFocus(render_view_->has_focus()); | |
| 533 } | |
| 534 | |
| 535 void PepperPluginDelegateImpl::InstanceDeleted( | |
| 536 webkit::ppapi::PluginInstance* instance) { | |
| 537 active_instances_.erase(instance); | |
| 538 } | |
| 539 | |
| 540 webkit::ppapi::PluginDelegate::PlatformImage2D* | |
| 541 PepperPluginDelegateImpl::CreateImage2D(int width, int height) { | |
| 542 uint32 buffer_size = width * height * 4; | |
| 543 | |
| 544 // Allocate the transport DIB and the PlatformCanvas pointing to it. | |
| 545 #if defined(OS_MACOSX) | |
| 546 // On the Mac, shared memory has to be created in the browser in order to | |
| 547 // work in the sandbox. Do this by sending a message to the browser | |
| 548 // requesting a TransportDIB (see also | |
| 549 // chrome/renderer/webplugin_delegate_proxy.cc, method | |
| 550 // WebPluginDelegateProxy::CreateBitmap() for similar code). The TransportDIB | |
| 551 // is cached in the browser, and is freed (in typical cases) by the | |
| 552 // PlatformImage2DImpl's destructor. | |
| 553 TransportDIB::Handle dib_handle; | |
| 554 IPC::Message* msg = new ViewHostMsg_AllocTransportDIB(buffer_size, | |
| 555 true, | |
| 556 &dib_handle); | |
| 557 if (!RenderThread::current()->Send(msg)) | |
| 558 return NULL; | |
| 559 if (!TransportDIB::is_valid(dib_handle)) | |
| 560 return NULL; | |
| 561 | |
| 562 TransportDIB* dib = TransportDIB::Map(dib_handle); | |
| 563 #else | |
| 564 static int next_dib_id = 0; | |
| 565 TransportDIB* dib = TransportDIB::Create(buffer_size, next_dib_id++); | |
| 566 if (!dib) | |
| 567 return NULL; | |
| 568 #endif | |
| 569 | |
| 570 return new PlatformImage2DImpl(width, height, dib); | |
| 571 } | |
| 572 | |
| 573 webkit::ppapi::PluginDelegate::PlatformContext3D* | |
| 574 PepperPluginDelegateImpl::CreateContext3D() { | |
| 575 #ifdef ENABLE_GPU | |
| 576 // If accelerated compositing of plugins is disabled, fail to create a 3D | |
| 577 // context, because it won't be visible. This allows graceful fallback in the | |
| 578 // modules. | |
| 579 if (!render_view_->webkit_preferences().accelerated_plugins_enabled) | |
| 580 return NULL; | |
| 581 WebGraphicsContext3DCommandBufferImpl* context = | |
| 582 static_cast<WebGraphicsContext3DCommandBufferImpl*>( | |
| 583 render_view_->webview()->graphicsContext3D()); | |
| 584 if (!context) | |
| 585 return NULL; | |
| 586 | |
| 587 ggl::Context* parent_context = context->context(); | |
| 588 if (!parent_context) | |
| 589 return NULL; | |
| 590 | |
| 591 return new PlatformContext3DImpl(parent_context); | |
| 592 #else | |
| 593 return NULL; | |
| 594 #endif | |
| 595 } | |
| 596 | |
| 597 webkit::ppapi::PluginDelegate::PlatformVideoDecoder* | |
| 598 PepperPluginDelegateImpl::CreateVideoDecoder( | |
| 599 const PP_VideoDecoderConfig_Dev& decoder_config) { | |
| 600 scoped_ptr<PlatformVideoDecoderImpl> decoder(new PlatformVideoDecoderImpl()); | |
| 601 | |
| 602 if (!decoder->Init(decoder_config)) | |
| 603 return NULL; | |
| 604 | |
| 605 return decoder.release(); | |
| 606 } | |
| 607 | |
| 608 void PepperPluginDelegateImpl::NumberOfFindResultsChanged(int identifier, | |
| 609 int total, | |
| 610 bool final_result) { | |
| 611 render_view_->reportFindInPageMatchCount(identifier, total, final_result); | |
| 612 } | |
| 613 | |
| 614 void PepperPluginDelegateImpl::SelectedFindResultChanged(int identifier, | |
| 615 int index) { | |
| 616 render_view_->reportFindInPageSelection( | |
| 617 identifier, index + 1, WebKit::WebRect()); | |
| 618 } | |
| 619 | |
| 620 webkit::ppapi::PluginDelegate::PlatformAudio* | |
| 621 PepperPluginDelegateImpl::CreateAudio( | |
| 622 uint32_t sample_rate, uint32_t sample_count, | |
| 623 webkit::ppapi::PluginDelegate::PlatformAudio::Client* client) { | |
| 624 scoped_refptr<PlatformAudioImpl> audio( | |
| 625 new PlatformAudioImpl(render_view_->audio_message_filter())); | |
| 626 if (audio->Initialize(sample_rate, sample_count, client)) { | |
| 627 // Balanced by Release invoked in PlatformAudioImpl::ShutDownOnIOThread(). | |
| 628 return audio.release(); | |
| 629 } else { | |
| 630 return NULL; | |
| 631 } | |
| 632 } | |
| 633 | |
| 634 bool PepperPluginDelegateImpl::RunFileChooser( | |
| 635 const WebKit::WebFileChooserParams& params, | |
| 636 WebKit::WebFileChooserCompletion* chooser_completion) { | |
| 637 return render_view_->runFileChooser(params, chooser_completion); | |
| 638 } | |
| 639 | |
| 640 bool PepperPluginDelegateImpl::AsyncOpenFile(const FilePath& path, | |
| 641 int flags, | |
| 642 AsyncOpenFileCallback* callback) { | |
| 643 int message_id = id_generator_++; | |
| 644 DCHECK(!messages_waiting_replies_.Lookup(message_id)); | |
| 645 messages_waiting_replies_.AddWithID(callback, message_id); | |
| 646 IPC::Message* msg = new ViewHostMsg_AsyncOpenFile( | |
| 647 render_view_->routing_id(), path, flags, message_id); | |
| 648 return render_view_->Send(msg); | |
| 649 } | |
| 650 | |
| 651 void PepperPluginDelegateImpl::OnAsyncFileOpened( | |
| 652 base::PlatformFileError error_code, | |
| 653 base::PlatformFile file, | |
| 654 int message_id) { | |
| 655 AsyncOpenFileCallback* callback = | |
| 656 messages_waiting_replies_.Lookup(message_id); | |
| 657 DCHECK(callback); | |
| 658 messages_waiting_replies_.Remove(message_id); | |
| 659 callback->Run(error_code, file); | |
| 660 delete callback; | |
| 661 } | |
| 662 | |
| 663 void PepperPluginDelegateImpl::OnSetFocus(bool has_focus) { | |
| 664 for (std::set<webkit::ppapi::PluginInstance*>::iterator i = | |
| 665 active_instances_.begin(); | |
| 666 i != active_instances_.end(); ++i) | |
| 667 (*i)->SetContentAreaFocus(has_focus); | |
| 668 } | |
| 669 | |
| 670 bool PepperPluginDelegateImpl::OpenFileSystem( | |
| 671 const GURL& url, | |
| 672 fileapi::FileSystemType type, | |
| 673 long long size, | |
| 674 fileapi::FileSystemCallbackDispatcher* dispatcher) { | |
| 675 FileSystemDispatcher* file_system_dispatcher = | |
| 676 ChildThread::current()->file_system_dispatcher(); | |
| 677 return file_system_dispatcher->OpenFileSystem( | |
| 678 url, type, size, true /* create */, dispatcher); | |
| 679 } | |
| 680 | |
| 681 bool PepperPluginDelegateImpl::MakeDirectory( | |
| 682 const FilePath& path, | |
| 683 bool recursive, | |
| 684 fileapi::FileSystemCallbackDispatcher* dispatcher) { | |
| 685 FileSystemDispatcher* file_system_dispatcher = | |
| 686 ChildThread::current()->file_system_dispatcher(); | |
| 687 return file_system_dispatcher->Create( | |
| 688 path, false, true, recursive, dispatcher); | |
| 689 } | |
| 690 | |
| 691 bool PepperPluginDelegateImpl::Query( | |
| 692 const FilePath& path, | |
| 693 fileapi::FileSystemCallbackDispatcher* dispatcher) { | |
| 694 FileSystemDispatcher* file_system_dispatcher = | |
| 695 ChildThread::current()->file_system_dispatcher(); | |
| 696 return file_system_dispatcher->ReadMetadata(path, dispatcher); | |
| 697 } | |
| 698 | |
| 699 bool PepperPluginDelegateImpl::Touch( | |
| 700 const FilePath& path, | |
| 701 const base::Time& last_access_time, | |
| 702 const base::Time& last_modified_time, | |
| 703 fileapi::FileSystemCallbackDispatcher* dispatcher) { | |
| 704 FileSystemDispatcher* file_system_dispatcher = | |
| 705 ChildThread::current()->file_system_dispatcher(); | |
| 706 return file_system_dispatcher->TouchFile(path, last_access_time, | |
| 707 last_modified_time, dispatcher); | |
| 708 } | |
| 709 | |
| 710 bool PepperPluginDelegateImpl::Delete( | |
| 711 const FilePath& path, | |
| 712 fileapi::FileSystemCallbackDispatcher* dispatcher) { | |
| 713 FileSystemDispatcher* file_system_dispatcher = | |
| 714 ChildThread::current()->file_system_dispatcher(); | |
| 715 return file_system_dispatcher->Remove(path, false /* recursive */, | |
| 716 dispatcher); | |
| 717 } | |
| 718 | |
| 719 bool PepperPluginDelegateImpl::Rename( | |
| 720 const FilePath& file_path, | |
| 721 const FilePath& new_file_path, | |
| 722 fileapi::FileSystemCallbackDispatcher* dispatcher) { | |
| 723 FileSystemDispatcher* file_system_dispatcher = | |
| 724 ChildThread::current()->file_system_dispatcher(); | |
| 725 return file_system_dispatcher->Move(file_path, new_file_path, dispatcher); | |
| 726 } | |
| 727 | |
| 728 bool PepperPluginDelegateImpl::ReadDirectory( | |
| 729 const FilePath& directory_path, | |
| 730 fileapi::FileSystemCallbackDispatcher* dispatcher) { | |
| 731 FileSystemDispatcher* file_system_dispatcher = | |
| 732 ChildThread::current()->file_system_dispatcher(); | |
| 733 return file_system_dispatcher->ReadDirectory(directory_path, dispatcher); | |
| 734 } | |
| 735 | |
| 736 base::PlatformFileError PepperPluginDelegateImpl::OpenFile( | |
| 737 const webkit::ppapi::PepperFilePath& path, | |
| 738 int flags, | |
| 739 base::PlatformFile* file) { | |
| 740 IPC::PlatformFileForTransit transit_file; | |
| 741 base::PlatformFileError error; | |
| 742 IPC::Message* msg = new PepperFileMsg_OpenFile( | |
| 743 path, flags, &error, &transit_file); | |
| 744 if (!render_view_->Send(msg)) { | |
| 745 *file = base::kInvalidPlatformFileValue; | |
| 746 return base::PLATFORM_FILE_ERROR_FAILED; | |
| 747 } | |
| 748 *file = IPC::PlatformFileForTransitToPlatformFile(transit_file); | |
| 749 return error; | |
| 750 } | |
| 751 | |
| 752 base::PlatformFileError PepperPluginDelegateImpl::RenameFile( | |
| 753 const webkit::ppapi::PepperFilePath& from_path, | |
| 754 const webkit::ppapi::PepperFilePath& to_path) { | |
| 755 base::PlatformFileError error; | |
| 756 IPC::Message* msg = new PepperFileMsg_RenameFile(from_path, to_path, &error); | |
| 757 if (!render_view_->Send(msg)) | |
| 758 return base::PLATFORM_FILE_ERROR_FAILED; | |
| 759 return error; | |
| 760 } | |
| 761 | |
| 762 base::PlatformFileError PepperPluginDelegateImpl::DeleteFileOrDir( | |
| 763 const webkit::ppapi::PepperFilePath& path, | |
| 764 bool recursive) { | |
| 765 base::PlatformFileError error; | |
| 766 IPC::Message* msg = new PepperFileMsg_DeleteFileOrDir( | |
| 767 path, recursive, &error); | |
| 768 if (!render_view_->Send(msg)) | |
| 769 return base::PLATFORM_FILE_ERROR_FAILED; | |
| 770 return error; | |
| 771 } | |
| 772 | |
| 773 base::PlatformFileError PepperPluginDelegateImpl::CreateDir( | |
| 774 const webkit::ppapi::PepperFilePath& path) { | |
| 775 base::PlatformFileError error; | |
| 776 IPC::Message* msg = new PepperFileMsg_CreateDir(path, &error); | |
| 777 if (!render_view_->Send(msg)) | |
| 778 return base::PLATFORM_FILE_ERROR_FAILED; | |
| 779 return error; | |
| 780 } | |
| 781 | |
| 782 base::PlatformFileError PepperPluginDelegateImpl::QueryFile( | |
| 783 const webkit::ppapi::PepperFilePath& path, | |
| 784 base::PlatformFileInfo* info) { | |
| 785 base::PlatformFileError error; | |
| 786 IPC::Message* msg = new PepperFileMsg_QueryFile(path, info, &error); | |
| 787 if (!render_view_->Send(msg)) | |
| 788 return base::PLATFORM_FILE_ERROR_FAILED; | |
| 789 return error; | |
| 790 } | |
| 791 | |
| 792 base::PlatformFileError PepperPluginDelegateImpl::GetDirContents( | |
| 793 const webkit::ppapi::PepperFilePath& path, | |
| 794 webkit::ppapi::DirContents* contents) { | |
| 795 base::PlatformFileError error; | |
| 796 IPC::Message* msg = new PepperFileMsg_GetDirContents(path, contents, &error); | |
| 797 if (!render_view_->Send(msg)) | |
| 798 return base::PLATFORM_FILE_ERROR_FAILED; | |
| 799 return error; | |
| 800 } | |
| 801 | |
| 802 scoped_refptr<base::MessageLoopProxy> | |
| 803 PepperPluginDelegateImpl::GetFileThreadMessageLoopProxy() { | |
| 804 return RenderThread::current()->GetFileThreadMessageLoopProxy(); | |
| 805 } | |
| 806 | |
| 807 int32_t PepperPluginDelegateImpl::ConnectTcp( | |
| 808 webkit::ppapi::PPB_Flash_NetConnector_Impl* connector, | |
| 809 const char* host, | |
| 810 uint16_t port) { | |
| 811 int request_id = pending_connect_tcps_.Add( | |
| 812 new scoped_refptr<webkit::ppapi::PPB_Flash_NetConnector_Impl>(connector)); | |
| 813 IPC::Message* msg = | |
| 814 new PepperMsg_ConnectTcp(render_view_->routing_id(), | |
| 815 request_id, | |
| 816 std::string(host), | |
| 817 port); | |
| 818 if (!render_view_->Send(msg)) { | |
| 819 pending_connect_tcps_.Remove(request_id); | |
| 820 return PP_ERROR_FAILED; | |
| 821 } | |
| 822 | |
| 823 return PP_ERROR_WOULDBLOCK; | |
| 824 } | |
| 825 | |
| 826 int32_t PepperPluginDelegateImpl::ConnectTcpAddress( | |
| 827 webkit::ppapi::PPB_Flash_NetConnector_Impl* connector, | |
| 828 const struct PP_Flash_NetAddress* addr) { | |
| 829 int request_id = pending_connect_tcps_.Add( | |
| 830 new scoped_refptr<webkit::ppapi::PPB_Flash_NetConnector_Impl>(connector)); | |
| 831 IPC::Message* msg = | |
| 832 new PepperMsg_ConnectTcpAddress(render_view_->routing_id(), | |
| 833 request_id, | |
| 834 *addr); | |
| 835 if (!render_view_->Send(msg)) { | |
| 836 pending_connect_tcps_.Remove(request_id); | |
| 837 return PP_ERROR_FAILED; | |
| 838 } | |
| 839 | |
| 840 return PP_ERROR_WOULDBLOCK; | |
| 841 } | |
| 842 | |
| 843 void PepperPluginDelegateImpl::OnConnectTcpACK( | |
| 844 int request_id, | |
| 845 base::PlatformFile socket, | |
| 846 const PP_Flash_NetAddress& local_addr, | |
| 847 const PP_Flash_NetAddress& remote_addr) { | |
| 848 scoped_refptr<webkit::ppapi::PPB_Flash_NetConnector_Impl> connector = | |
| 849 *pending_connect_tcps_.Lookup(request_id); | |
| 850 pending_connect_tcps_.Remove(request_id); | |
| 851 | |
| 852 connector->CompleteConnectTcp(socket, local_addr, remote_addr); | |
| 853 } | |
| 854 | |
| 855 int32_t PepperPluginDelegateImpl::ShowContextMenu( | |
| 856 webkit::ppapi::PPB_Flash_Menu_Impl* menu, | |
| 857 const gfx::Point& position) { | |
| 858 int request_id = pending_context_menus_.Add( | |
| 859 new scoped_refptr<webkit::ppapi::PPB_Flash_Menu_Impl>(menu)); | |
| 860 | |
| 861 ContextMenuParams params; | |
| 862 params.x = position.x(); | |
| 863 params.y = position.y(); | |
| 864 params.custom_context.is_pepper_menu = true; | |
| 865 params.custom_context.request_id = request_id; | |
| 866 params.custom_items = menu->menu_data(); | |
| 867 | |
| 868 IPC::Message* msg = new ViewHostMsg_ContextMenu(render_view_->routing_id(), | |
| 869 params); | |
| 870 if (!render_view_->Send(msg)) { | |
| 871 pending_context_menus_.Remove(request_id); | |
| 872 return PP_ERROR_FAILED; | |
| 873 } | |
| 874 | |
| 875 return PP_ERROR_WOULDBLOCK; | |
| 876 } | |
| 877 | |
| 878 void PepperPluginDelegateImpl::OnContextMenuClosed( | |
| 879 const webkit_glue::CustomContextMenuContext& custom_context) { | |
| 880 int request_id = custom_context.request_id; | |
| 881 scoped_refptr<webkit::ppapi::PPB_Flash_Menu_Impl> menu = | |
| 882 *pending_context_menus_.Lookup(request_id); | |
| 883 if (!menu) { | |
| 884 NOTREACHED() << "CompleteShowContextMenu() called twice for the same menu."; | |
| 885 return; | |
| 886 } | |
| 887 pending_context_menus_.Remove(request_id); | |
| 888 | |
| 889 if (has_saved_context_menu_action_) { | |
| 890 menu->CompleteShow(PP_OK, saved_context_menu_action_); | |
| 891 has_saved_context_menu_action_ = false; | |
| 892 saved_context_menu_action_ = 0; | |
| 893 } else { | |
| 894 menu->CompleteShow(PP_ERROR_USERCANCEL, 0); | |
| 895 } | |
| 896 } | |
| 897 | |
| 898 void PepperPluginDelegateImpl::OnCustomContextMenuAction( | |
| 899 const webkit_glue::CustomContextMenuContext& custom_context, | |
| 900 unsigned action) { | |
| 901 // Just save the action. | |
| 902 DCHECK(!has_saved_context_menu_action_); | |
| 903 has_saved_context_menu_action_ = true; | |
| 904 saved_context_menu_action_ = action; | |
| 905 } | |
| 906 | |
| 907 webkit::ppapi::FullscreenContainer* | |
| 908 PepperPluginDelegateImpl::CreateFullscreenContainer( | |
| 909 webkit::ppapi::PluginInstance* instance) { | |
| 910 return render_view_->CreatePepperFullscreenContainer(instance); | |
| 911 } | |
| 912 | |
| 913 gfx::Size PepperPluginDelegateImpl::GetScreenSize() { | |
| 914 WebKit::WebScreenInfo info = render_view_->screenInfo(); | |
| 915 return gfx::Size(info.rect.width, info.rect.height); | |
| 916 } | |
| 917 | |
| 918 std::string PepperPluginDelegateImpl::GetDefaultEncoding() { | |
| 919 // TODO(brettw) bug 56615: Somehow get the preference for the default | |
| 920 // encoding here rather than using the global default for the UI language. | |
| 921 return l10n_util::GetStringUTF8(IDS_DEFAULT_ENCODING); | |
| 922 } | |
| 923 | |
| 924 void PepperPluginDelegateImpl::ZoomLimitsChanged(double minimum_factor, | |
| 925 double maximum_factor) { | |
| 926 double minimum_level = WebView::zoomFactorToZoomLevel(minimum_factor); | |
| 927 double maximum_level = WebView::zoomFactorToZoomLevel(maximum_factor); | |
| 928 render_view_->webview()->zoomLimitsChanged(minimum_level, maximum_level); | |
| 929 } | |
| 930 | |
| 931 std::string PepperPluginDelegateImpl::ResolveProxy(const GURL& url) { | |
| 932 int net_error; | |
| 933 std::string proxy_result; | |
| 934 RenderThread::current()->Send( | |
| 935 new ChildProcessHostMsg_ResolveProxy(url, &net_error, &proxy_result)); | |
| 936 return proxy_result; | |
| 937 } | |
| 938 | |
| 939 void PepperPluginDelegateImpl::DidStartLoading() { | |
| 940 render_view_->DidStartLoadingForPlugin(); | |
| 941 } | |
| 942 | |
| 943 void PepperPluginDelegateImpl::DidStopLoading() { | |
| 944 render_view_->DidStopLoadingForPlugin(); | |
| 945 } | |
| 946 | |
| 947 void PepperPluginDelegateImpl::SetContentRestriction(int restrictions) { | |
| 948 render_view_->Send(new ViewHostMsg_UpdateContentRestrictions( | |
| 949 render_view_->routing_id(), restrictions)); | |
| 950 } | |
| 951 | |
| 952 void PepperPluginDelegateImpl::HasUnsupportedFeature() { | |
| 953 render_view_->Send(new ViewHostMsg_PDFHasUnsupportedFeature( | |
| 954 render_view_->routing_id())); | |
| 955 } | |
| 956 | |
| 957 P2PSocketDispatcher* PepperPluginDelegateImpl::GetP2PSocketDispatcher() { | |
| 958 return render_view_->p2p_socket_dispatcher(); | |
| 959 } | |
| OLD | NEW |