| // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "content/renderer/pepper/pepper_plugin_delegate_impl.h" |
| |
| #include <cmath> |
| #include <cstddef> |
| #include <map> |
| #include <queue> |
| |
| #include "base/bind.h" |
| #include "base/callback.h" |
| #include "base/command_line.h" |
| #include "base/file_path.h" |
| #include "base/file_util_proxy.h" |
| #include "base/logging.h" |
| #include "base/string_split.h" |
| #include "base/sync_socket.h" |
| #include "base/time.h" |
| #include "content/common/child_process.h" |
| #include "content/common/child_process_messages.h" |
| #include "content/common/child_thread.h" |
| #include "content/common/fileapi/file_system_dispatcher.h" |
| #include "content/common/fileapi/file_system_messages.h" |
| #include "content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.h" |
| #include "content/common/pepper_messages.h" |
| #include "content/common/pepper_plugin_registry.h" |
| #include "content/common/quota_dispatcher.h" |
| #include "content/common/view_messages.h" |
| #include "content/public/common/content_switches.h" |
| #include "content/public/common/context_menu_params.h" |
| #include "content/public/common/media_stream_request.h" |
| #include "content/public/common/referrer.h" |
| #include "content/public/renderer/content_renderer_client.h" |
| #include "content/public/renderer/renderer_restrict_dispatch_group.h" |
| #include "content/renderer/browser_plugin/old/browser_plugin_constants.h" |
| #include "content/renderer/browser_plugin/old/browser_plugin_registry.h" |
| #include "content/renderer/gamepad_shared_memory_reader.h" |
| #include "content/renderer/media/audio_hardware.h" |
| #include "content/renderer/media/media_stream_dispatcher.h" |
| #include "content/renderer/media/pepper_platform_video_decoder_impl.h" |
| #include "content/renderer/p2p/socket_dispatcher.h" |
| #include "content/renderer/pepper/content_renderer_pepper_host_factory.h" |
| #include "content/renderer/pepper/pepper_broker_impl.h" |
| #include "content/renderer/pepper/pepper_device_enumeration_event_handler.h" |
| #include "content/renderer/pepper/pepper_hung_plugin_filter.h" |
| #include "content/renderer/pepper/pepper_in_process_resource_creation.h" |
| #include "content/renderer/pepper/pepper_platform_audio_input_impl.h" |
| #include "content/renderer/pepper/pepper_platform_audio_output_impl.h" |
| #include "content/renderer/pepper/pepper_platform_context_3d_impl.h" |
| #include "content/renderer/pepper/pepper_platform_image_2d_impl.h" |
| #include "content/renderer/pepper/pepper_platform_video_capture_impl.h" |
| #include "content/renderer/pepper/pepper_proxy_channel_delegate_impl.h" |
| #include "content/renderer/pepper/renderer_ppapi_host_impl.h" |
| #include "content/renderer/render_thread_impl.h" |
| #include "content/renderer/render_view_impl.h" |
| #include "content/renderer/render_widget_fullscreen_pepper.h" |
| #include "content/renderer/renderer_clipboard_client.h" |
| #include "content/renderer/webplugin_delegate_proxy.h" |
| #include "googleurl/src/gurl.h" |
| #include "ipc/ipc_channel_handle.h" |
| #include "media/video/capture/video_capture_proxy.h" |
| #include "ppapi/c/dev/pp_video_dev.h" |
| #include "ppapi/c/pp_errors.h" |
| #include "ppapi/c/private/ppb_flash.h" |
| #include "ppapi/host/ppapi_host.h" |
| #include "ppapi/proxy/host_dispatcher.h" |
| #include "ppapi/proxy/pepper_file_messages.h" |
| #include "ppapi/proxy/ppapi_messages.h" |
| #include "ppapi/shared_impl/file_path.h" |
| #include "ppapi/shared_impl/platform_file.h" |
| #include "ppapi/shared_impl/ppapi_permissions.h" |
| #include "ppapi/shared_impl/ppapi_preferences.h" |
| #include "ppapi/shared_impl/ppb_device_ref_shared.h" |
| #include "ppapi/thunk/enter.h" |
| #include "ppapi/thunk/ppb_tcp_server_socket_private_api.h" |
| #include "third_party/WebKit/Source/WebKit/chromium/public/WebCursorInfo.h" |
| #include "third_party/WebKit/Source/WebKit/chromium/public/WebDocument.h" |
| #include "third_party/WebKit/Source/WebKit/chromium/public/WebFrame.h" |
| #include "third_party/WebKit/Source/WebKit/chromium/public/WebInputEvent.h" |
| #include "third_party/WebKit/Source/WebKit/chromium/public/WebPluginContainer.h" |
| #include "third_party/WebKit/Source/WebKit/chromium/public/WebScreenInfo.h" |
| #include "third_party/WebKit/Source/WebKit/chromium/public/WebView.h" |
| #include "ui/gfx/size.h" |
| #include "webkit/fileapi/file_system_callback_dispatcher.h" |
| #include "webkit/plugins/npapi/webplugin.h" |
| #include "webkit/plugins/ppapi/plugin_module.h" |
| #include "webkit/plugins/ppapi/ppapi_plugin_instance.h" |
| #include "webkit/plugins/ppapi/ppb_file_io_impl.h" |
| #include "webkit/plugins/ppapi/ppb_flash_impl.h" |
| #include "webkit/plugins/ppapi/ppb_tcp_server_socket_private_impl.h" |
| #include "webkit/plugins/ppapi/ppb_tcp_socket_private_impl.h" |
| #include "webkit/plugins/ppapi/ppb_udp_socket_private_impl.h" |
| #include "webkit/plugins/ppapi/resource_helper.h" |
| #include "webkit/plugins/webplugininfo.h" |
| |
| using WebKit::WebView; |
| using WebKit::WebFrame; |
| |
| namespace content { |
| |
| namespace { |
| |
| // This class wraps a dispatcher and has the same lifetime. A dispatcher has |
| // the same lifetime as a plugin module, which is longer than any particular |
| // RenderView or plugin instance. |
| class HostDispatcherWrapper |
| : public webkit::ppapi::PluginDelegate::OutOfProcessProxy { |
| public: |
| HostDispatcherWrapper(webkit::ppapi::PluginModule* module, |
| int plugin_child_id, |
| const ppapi::PpapiPermissions& perms) |
| : module_(module), |
| plugin_child_id_(plugin_child_id), |
| permissions_(perms) { |
| } |
| virtual ~HostDispatcherWrapper() {} |
| |
| bool Init(const IPC::ChannelHandle& channel_handle, |
| PP_GetInterface_Func local_get_interface, |
| const ppapi::Preferences& preferences, |
| const ppapi::PpapiPermissions& permissions, |
| PepperHungPluginFilter* filter) { |
| if (channel_handle.name.empty()) |
| return false; |
| |
| #if defined(OS_POSIX) |
| DCHECK_NE(-1, channel_handle.socket.fd); |
| if (channel_handle.socket.fd == -1) |
| return false; |
| #endif |
| |
| dispatcher_delegate_.reset(new PepperProxyChannelDelegateImpl); |
| dispatcher_.reset(new ppapi::proxy::HostDispatcher( |
| module_->pp_module(), local_get_interface, filter)); |
| |
| if (!dispatcher_->InitHostWithChannel(dispatcher_delegate_.get(), |
| channel_handle, |
| true, // Client. |
| preferences)) { |
| dispatcher_.reset(); |
| dispatcher_delegate_.reset(); |
| return false; |
| } |
| dispatcher_->channel()->SetRestrictDispatchChannelGroup( |
| content::kRendererRestrictDispatchGroup_Pepper); |
| return true; |
| } |
| |
| // OutOfProcessProxy implementation. |
| virtual const void* GetProxiedInterface(const char* name) { |
| return dispatcher_->GetProxiedInterface(name); |
| } |
| virtual void AddInstance(PP_Instance instance) { |
| ppapi::proxy::HostDispatcher::SetForInstance(instance, dispatcher_.get()); |
| |
| RendererPpapiHostImpl* host = |
| RendererPpapiHostImpl::GetForPPInstance(instance); |
| // TODO(brettw) remove this null check when the old-style pepper-based |
| // browser tag is removed from this file. Getting this notification should |
| // always give us an instance we can find in the map otherwise, but that |
| // isn't true for browser tag support. |
| if (host) { |
| RenderView* render_view = host->GetRenderViewForInstance(instance); |
| render_view->Send(new ViewHostMsg_DidCreateOutOfProcessPepperInstance( |
| plugin_child_id_, |
| instance, |
| render_view->GetRoutingID())); |
| } |
| } |
| virtual void RemoveInstance(PP_Instance instance) { |
| ppapi::proxy::HostDispatcher::RemoveForInstance(instance); |
| |
| RendererPpapiHostImpl* host = |
| RendererPpapiHostImpl::GetForPPInstance(instance); |
| // TODO(brettw) remove null check as described in AddInstance. |
| if (host) { |
| RenderView* render_view = host->GetRenderViewForInstance(instance); |
| render_view->Send(new ViewHostMsg_DidDeleteOutOfProcessPepperInstance( |
| plugin_child_id_, |
| instance)); |
| } |
| } |
| |
| ppapi::proxy::HostDispatcher* dispatcher() { return dispatcher_.get(); } |
| |
| private: |
| webkit::ppapi::PluginModule* module_; |
| |
| // ID that the browser process uses to idetify the child process for the |
| // plugin. This isn't directly useful from our process (the renderer) except |
| // in messages to the browser to disambiguate plugins. |
| int plugin_child_id_; |
| |
| ppapi::PpapiPermissions permissions_; |
| |
| scoped_ptr<ppapi::proxy::HostDispatcher> dispatcher_; |
| scoped_ptr<ppapi::proxy::ProxyChannel::Delegate> dispatcher_delegate_; |
| }; |
| |
| class QuotaCallbackTranslator : public QuotaDispatcher::Callback { |
| public: |
| typedef webkit::ppapi::PluginDelegate::AvailableSpaceCallback PluginCallback; |
| explicit QuotaCallbackTranslator(const PluginCallback& cb) : callback_(cb) {} |
| virtual void DidQueryStorageUsageAndQuota(int64 usage, int64 quota) OVERRIDE { |
| callback_.Run(std::max(static_cast<int64>(0), quota - usage)); |
| } |
| virtual void DidGrantStorageQuota(int64 granted_quota) OVERRIDE { |
| NOTREACHED(); |
| } |
| virtual void DidFail(quota::QuotaStatusCode error) OVERRIDE { |
| callback_.Run(0); |
| } |
| private: |
| PluginCallback callback_; |
| }; |
| |
| class PluginInstanceLockTarget : public MouseLockDispatcher::LockTarget { |
| public: |
| PluginInstanceLockTarget(webkit::ppapi::PluginInstance* plugin) |
| : plugin_(plugin) {} |
| |
| virtual void OnLockMouseACK(bool succeeded) OVERRIDE { |
| plugin_->OnLockMouseACK(succeeded); |
| } |
| |
| virtual void OnMouseLockLost() OVERRIDE { |
| plugin_->OnMouseLockLost(); |
| } |
| |
| virtual bool HandleMouseLockedInputEvent( |
| const WebKit::WebMouseEvent &event) OVERRIDE { |
| plugin_->HandleMouseLockedInputEvent(event); |
| return true; |
| } |
| |
| private: |
| webkit::ppapi::PluginInstance* plugin_; |
| }; |
| |
| class AsyncOpenFileSystemURLCallbackTranslator |
| : public fileapi::FileSystemCallbackDispatcher { |
| public: |
| AsyncOpenFileSystemURLCallbackTranslator( |
| const webkit::ppapi::PluginDelegate::AsyncOpenFileSystemURLCallback& |
| callback, |
| const webkit::ppapi::PluginDelegate::NotifyCloseFileCallback& |
| close_file_callback) |
| : callback_(callback), |
| close_file_callback_(close_file_callback) { |
| } |
| |
| virtual ~AsyncOpenFileSystemURLCallbackTranslator() {} |
| |
| virtual void DidSucceed() { |
| NOTREACHED(); |
| } |
| virtual void DidReadMetadata( |
| const base::PlatformFileInfo& file_info, |
| const FilePath& platform_path) { |
| NOTREACHED(); |
| } |
| virtual void DidReadDirectory( |
| const std::vector<base::FileUtilProxy::Entry>& entries, |
| bool has_more) { |
| NOTREACHED(); |
| } |
| virtual void DidOpenFileSystem(const std::string& name, |
| const GURL& root) { |
| NOTREACHED(); |
| } |
| |
| virtual void DidFail(base::PlatformFileError error_code) { |
| base::PlatformFile invalid_file = base::kInvalidPlatformFileValue; |
| callback_.Run(error_code, |
| base::PassPlatformFile(&invalid_file), |
| webkit::ppapi::PluginDelegate::NotifyCloseFileCallback()); |
| } |
| |
| virtual void DidWrite(int64 bytes, bool complete) { |
| NOTREACHED(); |
| } |
| |
| virtual void DidOpenFile(base::PlatformFile file) { |
| callback_.Run(base::PLATFORM_FILE_OK, |
| base::PassPlatformFile(&file), |
| close_file_callback_); |
| // Make sure we won't leak file handle if the requester has died. |
| if (file != base::kInvalidPlatformFileValue) { |
| base::FileUtilProxy::Close( |
| RenderThreadImpl::current()->GetFileThreadMessageLoopProxy(), file, |
| close_file_callback_); |
| } |
| } |
| |
| private: |
| webkit::ppapi::PluginDelegate::AsyncOpenFileSystemURLCallback callback_; |
| webkit::ppapi::PluginDelegate::NotifyCloseFileCallback close_file_callback_; |
| }; |
| |
| void DoNotifyCloseFile(const GURL& path, base::PlatformFileError /* unused */) { |
| ChildThread::current()->file_system_dispatcher()->NotifyCloseFile(path); |
| } |
| |
| void CreateHostForInProcessModule(RenderViewImpl* render_view, |
| webkit::ppapi::PluginModule* module, |
| const webkit::WebPluginInfo& webplugin_info) { |
| // First time an in-process plugin was used, make a host for it. |
| const PepperPluginInfo* info = |
| PepperPluginRegistry::GetInstance()->GetInfoForPlugin(webplugin_info); |
| DCHECK(!info->is_out_of_process); |
| |
| ppapi::PpapiPermissions perms( |
| PepperPluginRegistry::GetInstance()->GetInfoForPlugin( |
| webplugin_info)->permissions); |
| RendererPpapiHostImpl* host_impl = |
| content::RendererPpapiHostImpl::CreateOnModuleForInProcess( |
| module, perms); |
| render_view->PpapiPluginCreated(host_impl); |
| } |
| |
| } // namespace |
| |
| PepperPluginDelegateImpl::PepperPluginDelegateImpl(RenderViewImpl* render_view) |
| : RenderViewObserver(render_view), |
| render_view_(render_view), |
| has_saved_context_menu_action_(false), |
| saved_context_menu_action_(0), |
| focused_plugin_(NULL), |
| last_mouse_event_target_(NULL), |
| device_enumeration_event_handler_( |
| new PepperDeviceEnumerationEventHandler()) { |
| } |
| |
| PepperPluginDelegateImpl::~PepperPluginDelegateImpl() { |
| DCHECK(mouse_lock_instances_.empty()); |
| } |
| |
| scoped_refptr<webkit::ppapi::PluginModule> |
| PepperPluginDelegateImpl::CreatePepperPluginModule( |
| const webkit::WebPluginInfo& webplugin_info, |
| bool* pepper_plugin_was_registered) { |
| *pepper_plugin_was_registered = true; |
| |
| // See if a module has already been loaded for this plugin. |
| FilePath path(webplugin_info.path); |
| scoped_refptr<webkit::ppapi::PluginModule> module = |
| PepperPluginRegistry::GetInstance()->GetLiveModule(path); |
| if (module) { |
| if (!module->GetEmbedderState()) { |
| // If the module exists and no embedder state was associated with it, |
| // then the module was one of the ones preloaded and is an in-process |
| // plugin. We need to associate our host state with it. |
| CreateHostForInProcessModule(render_view_, module, webplugin_info); |
| } |
| return module; |
| } |
| |
| // In-process plugins will have always been created up-front to avoid the |
| // sandbox restrictions. So getting here implies it doesn't exist or should |
| // be out of process. |
| const PepperPluginInfo* info = |
| PepperPluginRegistry::GetInstance()->GetInfoForPlugin(webplugin_info); |
| if (!info) { |
| *pepper_plugin_was_registered = false; |
| return scoped_refptr<webkit::ppapi::PluginModule>(); |
| } else if (!info->is_out_of_process) { |
| // In-process plugin not preloaded, it probably couldn't be initialized. |
| return scoped_refptr<webkit::ppapi::PluginModule>(); |
| } |
| ppapi::PpapiPermissions permissions(info->permissions); |
| |
| // Out of process: have the browser start the plugin process for us. |
| IPC::ChannelHandle channel_handle; |
| int plugin_child_id = 0; |
| render_view_->Send(new ViewHostMsg_OpenChannelToPepperPlugin( |
| path, &channel_handle, &plugin_child_id)); |
| if (channel_handle.name.empty()) { |
| // Couldn't be initialized. |
| return scoped_refptr<webkit::ppapi::PluginModule>(); |
| } |
| |
| scoped_refptr<PepperHungPluginFilter> hung_filter( |
| new PepperHungPluginFilter(path, render_view_->routing_id(), |
| plugin_child_id)); |
| |
| // Create a new HostDispatcher for the proxying, and hook it to a new |
| // PluginModule. Note that AddLiveModule must be called before any early |
| // returns since the module's destructor will remove itself. |
| module = new webkit::ppapi::PluginModule( |
| info->name, path, |
| PepperPluginRegistry::GetInstance(), |
| permissions); |
| PepperPluginRegistry::GetInstance()->AddLiveModule(path, module); |
| scoped_ptr<HostDispatcherWrapper> dispatcher( |
| new HostDispatcherWrapper(module, plugin_child_id, permissions)); |
| if (!dispatcher->Init( |
| channel_handle, |
| webkit::ppapi::PluginModule::GetLocalGetInterfaceFunc(), |
| GetPreferences(), |
| permissions, |
| hung_filter.get())) |
| return scoped_refptr<webkit::ppapi::PluginModule>(); |
| |
| RendererPpapiHostImpl* host_impl = |
| content::RendererPpapiHostImpl::CreateOnModuleForOutOfProcess( |
| module, dispatcher->dispatcher(), permissions); |
| render_view_->PpapiPluginCreated(host_impl); |
| |
| module->InitAsProxied(dispatcher.release()); |
| return module; |
| } |
| |
| scoped_refptr<webkit::ppapi::PluginModule> |
| PepperPluginDelegateImpl::CreateBrowserPluginModule( |
| const IPC::ChannelHandle& channel_handle, |
| int guest_process_id) { |
| content::old::BrowserPluginRegistry* registry = |
| RenderThreadImpl::current()->browser_plugin_registry(); |
| scoped_refptr<webkit::ppapi::PluginModule> module = |
| registry->GetModule(guest_process_id); |
| if (module) |
| return module; |
| |
| ppapi::PpapiPermissions permissions; |
| |
| FilePath path(kBrowserPluginPath); |
| scoped_refptr<PepperHungPluginFilter> hung_filter( |
| new PepperHungPluginFilter(path, |
| render_view_->routing_id(), |
| guest_process_id)); |
| // Create a new HostDispatcher for the proxying, and hook it to a new |
| // PluginModule. |
| module = new webkit::ppapi::PluginModule(kBrowserPluginName, |
| path, |
| registry, |
| permissions); |
| RenderThreadImpl::current()->browser_plugin_registry()->AddModule( |
| guest_process_id, module); |
| scoped_ptr<HostDispatcherWrapper> dispatcher( |
| new HostDispatcherWrapper(module, 0, permissions)); |
| if (!dispatcher->Init( |
| channel_handle, |
| webkit::ppapi::PluginModule::GetLocalGetInterfaceFunc(), |
| GetPreferences(), |
| permissions, |
| hung_filter.get())) |
| return scoped_refptr<webkit::ppapi::PluginModule>(); |
| module->InitAsProxied(dispatcher.release()); |
| return module; |
| } |
| |
| scoped_refptr<PepperBrokerImpl> PepperPluginDelegateImpl::CreateBroker( |
| webkit::ppapi::PluginModule* plugin_module) { |
| DCHECK(plugin_module); |
| DCHECK(!plugin_module->GetBroker()); |
| |
| // The broker path is the same as the plugin. |
| const FilePath& broker_path = plugin_module->path(); |
| |
| scoped_refptr<PepperBrokerImpl> broker = |
| new PepperBrokerImpl(plugin_module, this); |
| |
| int request_id = |
| pending_connect_broker_.Add(new scoped_refptr<PepperBrokerImpl>(broker)); |
| |
| // Have the browser start the broker process for us. |
| IPC::Message* msg = |
| new ViewHostMsg_OpenChannelToPpapiBroker(render_view_->routing_id(), |
| request_id, |
| broker_path); |
| if (!render_view_->Send(msg)) { |
| pending_connect_broker_.Remove(request_id); |
| return scoped_refptr<PepperBrokerImpl>(); |
| } |
| |
| return broker; |
| } |
| |
| void PepperPluginDelegateImpl::OnPpapiBrokerChannelCreated( |
| int request_id, |
| const IPC::ChannelHandle& handle) { |
| scoped_refptr<PepperBrokerImpl>* broker_ptr = |
| pending_connect_broker_.Lookup(request_id); |
| if (broker_ptr) { |
| scoped_refptr<PepperBrokerImpl> broker = *broker_ptr; |
| pending_connect_broker_.Remove(request_id); |
| broker->OnBrokerChannelConnected(handle); |
| } else { |
| // There is no broker waiting for this channel. Close it so the broker can |
| // clean up and possibly exit. |
| // The easiest way to clean it up is to just put it in an object |
| // and then close them. This failure case is not performance critical. |
| PepperBrokerDispatcherWrapper temp_dispatcher; |
| temp_dispatcher.Init(handle); |
| } |
| } |
| |
| // Iterates through pending_connect_broker_ to find the broker. |
| // Cannot use Lookup() directly because pending_connect_broker_ does not store |
| // the raw pointer to the broker. Assumes maximum of one copy of broker exists. |
| bool PepperPluginDelegateImpl::StopWaitingForBrokerConnection( |
| PepperBrokerImpl* broker) { |
| for (BrokerMap::iterator i(&pending_connect_broker_); |
| !i.IsAtEnd(); i.Advance()) { |
| if (i.GetCurrentValue()->get() == broker) { |
| pending_connect_broker_.Remove(i.GetCurrentKey()); |
| return true; |
| } |
| } |
| |
| return false; |
| } |
| |
| void PepperPluginDelegateImpl::ViewWillInitiatePaint() { |
| // Notify all of our instances that we started painting. This is used for |
| // internal bookkeeping only, so we know that the set can not change under |
| // us. |
| for (std::set<webkit::ppapi::PluginInstance*>::iterator i = |
| active_instances_.begin(); |
| i != active_instances_.end(); ++i) |
| (*i)->ViewWillInitiatePaint(); |
| } |
| |
| void PepperPluginDelegateImpl::ViewInitiatedPaint() { |
| // Notify all instances that we painted. The same caveats apply as for |
| // ViewFlushedPaint regarding instances closing themselves, so we take |
| // similar precautions. |
| std::set<webkit::ppapi::PluginInstance*> plugins = active_instances_; |
| for (std::set<webkit::ppapi::PluginInstance*>::iterator i = plugins.begin(); |
| i != plugins.end(); ++i) { |
| if (active_instances_.find(*i) != active_instances_.end()) |
| (*i)->ViewInitiatedPaint(); |
| } |
| } |
| |
| void PepperPluginDelegateImpl::ViewFlushedPaint() { |
| // Notify all instances that we flushed. This will call into the plugin, and |
| // we it may ask to close itself as a result. This will, in turn, modify our |
| // set, possibly invalidating the iterator. So we iterate on a copy that |
| // won't change out from under us. |
| std::set<webkit::ppapi::PluginInstance*> plugins = active_instances_; |
| for (std::set<webkit::ppapi::PluginInstance*>::iterator i = plugins.begin(); |
| i != plugins.end(); ++i) { |
| // The copy above makes sure our iterator is never invalid if some plugins |
| // are destroyed. But some plugin may decide to close all of its views in |
| // response to a paint in one of them, so we need to make sure each one is |
| // still "current" before using it. |
| // |
| // It's possible that a plugin was destroyed, but another one was created |
| // with the same address. In this case, we'll call ViewFlushedPaint on that |
| // new plugin. But that's OK for this particular case since we're just |
| // notifying all of our instances that the view flushed, and the new one is |
| // one of our instances. |
| // |
| // What about the case where a new one is created in a callback at a new |
| // address and we don't issue the callback? We're still OK since this |
| // callback is used for flush callbacks and we could not have possibly |
| // started a new paint (ViewWillInitiatePaint) for the new plugin while |
| // processing a previous paint for an existing one. |
| if (active_instances_.find(*i) != active_instances_.end()) |
| (*i)->ViewFlushedPaint(); |
| } |
| } |
| |
| webkit::ppapi::PluginInstance* |
| PepperPluginDelegateImpl::GetBitmapForOptimizedPluginPaint( |
| const gfx::Rect& paint_bounds, |
| TransportDIB** dib, |
| gfx::Rect* location, |
| gfx::Rect* clip, |
| float* scale_factor) { |
| for (std::set<webkit::ppapi::PluginInstance*>::iterator i = |
| active_instances_.begin(); |
| i != active_instances_.end(); ++i) { |
| webkit::ppapi::PluginInstance* instance = *i; |
| // In Flash fullscreen , the plugin contents should be painted onto the |
| // fullscreen widget instead of the web page. |
| if (!instance->FlashIsFullscreenOrPending() && |
| instance->GetBitmapForOptimizedPluginPaint(paint_bounds, dib, location, |
| clip, scale_factor)) |
| return *i; |
| } |
| return NULL; |
| } |
| |
| void PepperPluginDelegateImpl::PluginFocusChanged( |
| webkit::ppapi::PluginInstance* instance, |
| bool focused) { |
| if (focused) |
| focused_plugin_ = instance; |
| else if (focused_plugin_ == instance) |
| focused_plugin_ = NULL; |
| if (render_view_) |
| render_view_->PpapiPluginFocusChanged(); |
| } |
| |
| void PepperPluginDelegateImpl::PluginTextInputTypeChanged( |
| webkit::ppapi::PluginInstance* instance) { |
| if (focused_plugin_ == instance && render_view_) |
| render_view_->PpapiPluginTextInputTypeChanged(); |
| } |
| |
| void PepperPluginDelegateImpl::PluginCaretPositionChanged( |
| webkit::ppapi::PluginInstance* instance) { |
| if (focused_plugin_ == instance && render_view_) |
| render_view_->PpapiPluginCaretPositionChanged(); |
| } |
| |
| void PepperPluginDelegateImpl::PluginRequestedCancelComposition( |
| webkit::ppapi::PluginInstance* instance) { |
| if (focused_plugin_ == instance && render_view_) |
| render_view_->PpapiPluginCancelComposition(); |
| } |
| |
| void PepperPluginDelegateImpl::PluginSelectionChanged( |
| webkit::ppapi::PluginInstance* instance) { |
| if (focused_plugin_ == instance && render_view_) |
| render_view_->PpapiPluginSelectionChanged(); |
| } |
| |
| void PepperPluginDelegateImpl::SimulateImeSetComposition( |
| const string16& text, |
| const std::vector<WebKit::WebCompositionUnderline>& underlines, |
| int selection_start, |
| int selection_end) { |
| if (render_view_) { |
| render_view_->SimulateImeSetComposition( |
| text, underlines, selection_start, selection_end); |
| } |
| } |
| |
| void PepperPluginDelegateImpl::SimulateImeConfirmComposition( |
| const string16& text) { |
| if (render_view_) |
| render_view_->SimulateImeConfirmComposition(text, ui::Range()); |
| } |
| |
| void PepperPluginDelegateImpl::OnImeSetComposition( |
| const string16& text, |
| const std::vector<WebKit::WebCompositionUnderline>& underlines, |
| int selection_start, |
| int selection_end) { |
| if (!IsPluginAcceptingCompositionEvents()) { |
| composition_text_ = text; |
| } else { |
| // TODO(kinaba) currently all composition events are sent directly to |
| // plugins. Use DOM event mechanism after WebKit is made aware about |
| // plugins that support composition. |
| // The code below mimics the behavior of WebCore::Editor::setComposition. |
| |
| // Empty -> nonempty: composition started. |
| if (composition_text_.empty() && !text.empty()) |
| focused_plugin_->HandleCompositionStart(string16()); |
| // Nonempty -> empty: composition canceled. |
| if (!composition_text_.empty() && text.empty()) |
| focused_plugin_->HandleCompositionEnd(string16()); |
| composition_text_ = text; |
| // Nonempty: composition is ongoing. |
| if (!composition_text_.empty()) { |
| focused_plugin_->HandleCompositionUpdate(composition_text_, underlines, |
| selection_start, selection_end); |
| } |
| } |
| } |
| |
| void PepperPluginDelegateImpl::OnImeConfirmComposition(const string16& text) { |
| // Here, text.empty() has a special meaning. It means to commit the last |
| // update of composition text (see RenderWidgetHost::ImeConfirmComposition()). |
| const string16& last_text = text.empty() ? composition_text_ : text; |
| |
| // last_text is empty only when both text and composition_text_ is. Ignore it. |
| if (last_text.empty()) |
| return; |
| |
| if (!IsPluginAcceptingCompositionEvents()) { |
| for (size_t i = 0; i < text.size(); ++i) { |
| WebKit::WebKeyboardEvent char_event; |
| char_event.type = WebKit::WebInputEvent::Char; |
| char_event.timeStampSeconds = base::Time::Now().ToDoubleT(); |
| char_event.modifiers = 0; |
| char_event.windowsKeyCode = last_text[i]; |
| char_event.nativeKeyCode = last_text[i]; |
| char_event.text[0] = last_text[i]; |
| char_event.unmodifiedText[0] = last_text[i]; |
| if (render_view_->webwidget()) |
| render_view_->webwidget()->handleInputEvent(char_event); |
| } |
| } else { |
| // Mimics the order of events sent by WebKit. |
| // See WebCore::Editor::setComposition() for the corresponding code. |
| focused_plugin_->HandleCompositionEnd(last_text); |
| focused_plugin_->HandleTextInput(last_text); |
| } |
| composition_text_.clear(); |
| } |
| |
| gfx::Rect PepperPluginDelegateImpl::GetCaretBounds() const { |
| if (!focused_plugin_) |
| return gfx::Rect(0, 0, 0, 0); |
| return focused_plugin_->GetCaretBounds(); |
| } |
| |
| ui::TextInputType PepperPluginDelegateImpl::GetTextInputType() const { |
| if (!focused_plugin_) |
| return ui::TEXT_INPUT_TYPE_NONE; |
| return focused_plugin_->text_input_type(); |
| } |
| |
| void PepperPluginDelegateImpl::GetSurroundingText(string16* text, |
| ui::Range* range) const { |
| if (!focused_plugin_) |
| return; |
| return focused_plugin_->GetSurroundingText(text, range); |
| } |
| |
| bool PepperPluginDelegateImpl::IsPluginAcceptingCompositionEvents() const { |
| if (!focused_plugin_) |
| return false; |
| return focused_plugin_->IsPluginAcceptingCompositionEvents(); |
| } |
| |
| bool PepperPluginDelegateImpl::CanComposeInline() const { |
| return IsPluginAcceptingCompositionEvents(); |
| } |
| |
| void PepperPluginDelegateImpl::PluginCrashed( |
| webkit::ppapi::PluginInstance* instance) { |
| render_view_->PluginCrashed(instance->module()->path()); |
| UnSetAndDeleteLockTargetAdapter(instance); |
| } |
| |
| void PepperPluginDelegateImpl::InstanceCreated( |
| webkit::ppapi::PluginInstance* instance) { |
| active_instances_.insert(instance); |
| |
| // Set the initial focus. |
| instance->SetContentAreaFocus(render_view_->has_focus()); |
| } |
| |
| void PepperPluginDelegateImpl::InstanceDeleted( |
| webkit::ppapi::PluginInstance* instance) { |
| active_instances_.erase(instance); |
| UnSetAndDeleteLockTargetAdapter(instance); |
| |
| if (last_mouse_event_target_ == instance) |
| last_mouse_event_target_ = NULL; |
| if (focused_plugin_ == instance) |
| PluginFocusChanged(instance, false); |
| } |
| |
| scoped_ptr< ::ppapi::thunk::ResourceCreationAPI> |
| PepperPluginDelegateImpl::CreateResourceCreationAPI( |
| webkit::ppapi::PluginInstance* instance) { |
| RendererPpapiHostImpl* host_impl = static_cast<RendererPpapiHostImpl*>( |
| instance->module()->GetEmbedderState()); |
| return host_impl->CreateInProcessResourceCreationAPI(instance); |
| } |
| |
| SkBitmap* PepperPluginDelegateImpl::GetSadPluginBitmap() { |
| return GetContentClient()->renderer()->GetSadPluginBitmap(); |
| } |
| |
| WebKit::WebPlugin* PepperPluginDelegateImpl::CreatePluginReplacement( |
| const FilePath& file_path) { |
| return GetContentClient()->renderer()->CreatePluginReplacement( |
| render_view_, file_path); |
| } |
| |
| webkit::ppapi::PluginDelegate::PlatformImage2D* |
| PepperPluginDelegateImpl::CreateImage2D(int width, int height) { |
| return PepperPlatformImage2DImpl::Create(width, height); |
| } |
| |
| webkit::ppapi::PluginDelegate::PlatformContext3D* |
| PepperPluginDelegateImpl::CreateContext3D() { |
| #ifdef ENABLE_GPU |
| // If accelerated compositing of plugins is disabled, fail to create a 3D |
| // context, because it won't be visible. This allows graceful fallback in the |
| // modules. |
| if (!render_view_->webkit_preferences().accelerated_plugins_enabled) |
| return NULL; |
| return new PlatformContext3DImpl(this); |
| #else |
| return NULL; |
| #endif |
| } |
| |
| void PepperPluginDelegateImpl::ReparentContext( |
| webkit::ppapi::PluginDelegate::PlatformContext3D* context) { |
| static_cast<PlatformContext3DImpl*>(context)->SetParentContext(this); |
| } |
| |
| webkit::ppapi::PluginDelegate::PlatformVideoCapture* |
| PepperPluginDelegateImpl::CreateVideoCapture( |
| const std::string& device_id, |
| PlatformVideoCaptureEventHandler* handler) { |
| return new PepperPlatformVideoCaptureImpl(AsWeakPtr(), device_id, handler); |
| } |
| |
| webkit::ppapi::PluginDelegate::PlatformVideoDecoder* |
| PepperPluginDelegateImpl::CreateVideoDecoder( |
| media::VideoDecodeAccelerator::Client* client, |
| int32 command_buffer_route_id) { |
| return new PlatformVideoDecoderImpl(client, command_buffer_route_id); |
| } |
| |
| void PepperPluginDelegateImpl::NumberOfFindResultsChanged(int identifier, |
| int total, |
| bool final_result) { |
| render_view_->reportFindInPageMatchCount(identifier, total, final_result); |
| } |
| |
| void PepperPluginDelegateImpl::SelectedFindResultChanged(int identifier, |
| int index) { |
| render_view_->reportFindInPageSelection( |
| identifier, index + 1, WebKit::WebRect()); |
| } |
| |
| uint32_t PepperPluginDelegateImpl::GetAudioHardwareOutputSampleRate() { |
| return static_cast<uint32_t>(audio_hardware::GetOutputSampleRate()); |
| } |
| |
| uint32_t PepperPluginDelegateImpl::GetAudioHardwareOutputBufferSize() { |
| return static_cast<uint32_t>(audio_hardware::GetOutputBufferSize()); |
| } |
| |
| webkit::ppapi::PluginDelegate::PlatformAudioOutput* |
| PepperPluginDelegateImpl::CreateAudioOutput( |
| uint32_t sample_rate, |
| uint32_t sample_count, |
| webkit::ppapi::PluginDelegate::PlatformAudioOutputClient* client) { |
| return PepperPlatformAudioOutputImpl::Create( |
| static_cast<int>(sample_rate), static_cast<int>(sample_count), client); |
| } |
| |
| webkit::ppapi::PluginDelegate::PlatformAudioInput* |
| PepperPluginDelegateImpl::CreateAudioInput( |
| const std::string& device_id, |
| uint32_t sample_rate, |
| uint32_t sample_count, |
| webkit::ppapi::PluginDelegate::PlatformAudioInputClient* client) { |
| return PepperPlatformAudioInputImpl::Create( |
| AsWeakPtr(), device_id, static_cast<int>(sample_rate), |
| static_cast<int>(sample_count), client); |
| } |
| |
| // If a broker has not already been created for this plugin, creates one. |
| webkit::ppapi::PluginDelegate::Broker* |
| PepperPluginDelegateImpl::ConnectToBroker( |
| webkit::ppapi::PPB_Broker_Impl* client) { |
| DCHECK(client); |
| |
| webkit::ppapi::PluginModule* plugin_module = |
| webkit::ppapi::ResourceHelper::GetPluginModule(client); |
| if (!plugin_module) |
| return NULL; |
| |
| scoped_refptr<PepperBrokerImpl> broker = |
| static_cast<PepperBrokerImpl*>(plugin_module->GetBroker()); |
| if (!broker.get()) { |
| broker = CreateBroker(plugin_module); |
| if (!broker.get()) |
| return NULL; |
| } |
| |
| int request_id = pending_permission_requests_.Add( |
| new base::WeakPtr<webkit::ppapi::PPB_Broker_Impl>(client->AsWeakPtr())); |
| if (!render_view_->Send( |
| new ViewHostMsg_RequestPpapiBrokerPermission( |
| render_view_->routing_id(), |
| request_id, |
| client->GetDocumentUrl(), |
| plugin_module->path()))) { |
| return NULL; |
| } |
| |
| // Adds a reference, ensuring that the broker is not deleted when |
| // |broker| goes out of scope. |
| broker->AddPendingConnect(client); |
| |
| return broker; |
| } |
| |
| void PepperPluginDelegateImpl::OnPpapiBrokerPermissionResult( |
| int request_id, |
| bool result) { |
| scoped_ptr<base::WeakPtr<webkit::ppapi::PPB_Broker_Impl> > client_ptr( |
| pending_permission_requests_.Lookup(request_id)); |
| DCHECK(client_ptr.get()); |
| pending_permission_requests_.Remove(request_id); |
| base::WeakPtr<webkit::ppapi::PPB_Broker_Impl> client = *client_ptr; |
| if (!client) |
| return; |
| |
| webkit::ppapi::PluginModule* plugin_module = |
| webkit::ppapi::ResourceHelper::GetPluginModule(client); |
| if (!plugin_module) |
| return; |
| |
| PepperBrokerImpl* broker = |
| static_cast<PepperBrokerImpl*>(plugin_module->GetBroker()); |
| broker->OnBrokerPermissionResult(client, result); |
| } |
| |
| bool PepperPluginDelegateImpl::AsyncOpenFile( |
| const FilePath& path, |
| int flags, |
| const AsyncOpenFileCallback& callback) { |
| int message_id = pending_async_open_files_.Add( |
| new AsyncOpenFileCallback(callback)); |
| IPC::Message* msg = new ViewHostMsg_AsyncOpenFile( |
| render_view_->routing_id(), path, flags, message_id); |
| return render_view_->Send(msg); |
| } |
| |
| void PepperPluginDelegateImpl::OnAsyncFileOpened( |
| base::PlatformFileError error_code, |
| base::PlatformFile file, |
| int message_id) { |
| AsyncOpenFileCallback* callback = |
| pending_async_open_files_.Lookup(message_id); |
| DCHECK(callback); |
| pending_async_open_files_.Remove(message_id); |
| callback->Run(error_code, base::PassPlatformFile(&file)); |
| // Make sure we won't leak file handle if the requester has died. |
| if (file != base::kInvalidPlatformFileValue) |
| base::FileUtilProxy::Close(GetFileThreadMessageLoopProxy(), file, |
| base::FileUtilProxy::StatusCallback()); |
| delete callback; |
| } |
| |
| void PepperPluginDelegateImpl::OnSetFocus(bool has_focus) { |
| for (std::set<webkit::ppapi::PluginInstance*>::iterator i = |
| active_instances_.begin(); |
| i != active_instances_.end(); ++i) |
| (*i)->SetContentAreaFocus(has_focus); |
| } |
| |
| void PepperPluginDelegateImpl::PageVisibilityChanged(bool is_visible) { |
| for (std::set<webkit::ppapi::PluginInstance*>::iterator i = |
| active_instances_.begin(); |
| i != active_instances_.end(); ++i) |
| (*i)->PageVisibilityChanged(is_visible); |
| } |
| |
| bool PepperPluginDelegateImpl::IsPluginFocused() const { |
| return focused_plugin_ != NULL; |
| } |
| |
| void PepperPluginDelegateImpl::WillHandleMouseEvent() { |
| // This method is called for every mouse event that the render view receives. |
| // And then the mouse event is forwarded to WebKit, which dispatches it to the |
| // event target. Potentially a Pepper plugin will receive the event. |
| // In order to tell whether a plugin gets the last mouse event and which it |
| // is, we set |last_mouse_event_target_| to NULL here. If a plugin gets the |
| // event, it will notify us via DidReceiveMouseEvent() and set itself as |
| // |last_mouse_event_target_|. |
| last_mouse_event_target_ = NULL; |
| } |
| |
| bool PepperPluginDelegateImpl::OpenFileSystem( |
| const GURL& origin_url, |
| fileapi::FileSystemType type, |
| long long size, |
| fileapi::FileSystemCallbackDispatcher* dispatcher) { |
| FileSystemDispatcher* file_system_dispatcher = |
| ChildThread::current()->file_system_dispatcher(); |
| return file_system_dispatcher->OpenFileSystem( |
| origin_url, type, size, true /* create */, dispatcher); |
| } |
| |
| bool PepperPluginDelegateImpl::MakeDirectory( |
| const GURL& path, |
| bool recursive, |
| fileapi::FileSystemCallbackDispatcher* dispatcher) { |
| FileSystemDispatcher* file_system_dispatcher = |
| ChildThread::current()->file_system_dispatcher(); |
| return file_system_dispatcher->Create( |
| path, false, true, recursive, dispatcher); |
| } |
| |
| bool PepperPluginDelegateImpl::Query( |
| const GURL& path, |
| fileapi::FileSystemCallbackDispatcher* dispatcher) { |
| FileSystemDispatcher* file_system_dispatcher = |
| ChildThread::current()->file_system_dispatcher(); |
| return file_system_dispatcher->ReadMetadata(path, dispatcher); |
| } |
| |
| bool PepperPluginDelegateImpl::Touch( |
| const GURL& path, |
| const base::Time& last_access_time, |
| const base::Time& last_modified_time, |
| fileapi::FileSystemCallbackDispatcher* dispatcher) { |
| FileSystemDispatcher* file_system_dispatcher = |
| ChildThread::current()->file_system_dispatcher(); |
| return file_system_dispatcher->TouchFile(path, last_access_time, |
| last_modified_time, dispatcher); |
| } |
| |
| bool PepperPluginDelegateImpl::Delete( |
| const GURL& path, |
| fileapi::FileSystemCallbackDispatcher* dispatcher) { |
| FileSystemDispatcher* file_system_dispatcher = |
| ChildThread::current()->file_system_dispatcher(); |
| return file_system_dispatcher->Remove(path, false /* recursive */, |
| dispatcher); |
| } |
| |
| bool PepperPluginDelegateImpl::Rename( |
| const GURL& file_path, |
| const GURL& new_file_path, |
| fileapi::FileSystemCallbackDispatcher* dispatcher) { |
| FileSystemDispatcher* file_system_dispatcher = |
| ChildThread::current()->file_system_dispatcher(); |
| return file_system_dispatcher->Move(file_path, new_file_path, dispatcher); |
| } |
| |
| bool PepperPluginDelegateImpl::ReadDirectory( |
| const GURL& directory_path, |
| fileapi::FileSystemCallbackDispatcher* dispatcher) { |
| FileSystemDispatcher* file_system_dispatcher = |
| ChildThread::current()->file_system_dispatcher(); |
| return file_system_dispatcher->ReadDirectory(directory_path, dispatcher); |
| } |
| |
| void PepperPluginDelegateImpl::QueryAvailableSpace( |
| const GURL& origin, quota::StorageType type, |
| const AvailableSpaceCallback& callback) { |
| ChildThread::current()->quota_dispatcher()->QueryStorageUsageAndQuota( |
| origin, type, new QuotaCallbackTranslator(callback)); |
| } |
| |
| void PepperPluginDelegateImpl::WillUpdateFile(const GURL& path) { |
| ChildThread::current()->Send(new FileSystemHostMsg_WillUpdate(path)); |
| } |
| |
| void PepperPluginDelegateImpl::DidUpdateFile(const GURL& path, int64_t delta) { |
| ChildThread::current()->Send(new FileSystemHostMsg_DidUpdate(path, delta)); |
| } |
| |
| bool PepperPluginDelegateImpl::AsyncOpenFileSystemURL( |
| const GURL& path, |
| int flags, |
| const AsyncOpenFileSystemURLCallback& callback) { |
| |
| FileSystemDispatcher* file_system_dispatcher = |
| ChildThread::current()->file_system_dispatcher(); |
| return file_system_dispatcher->OpenFile(path, flags, |
| new AsyncOpenFileSystemURLCallbackTranslator( |
| callback, |
| base::Bind(&DoNotifyCloseFile, path))); |
| } |
| |
| base::PlatformFileError PepperPluginDelegateImpl::OpenFile( |
| const ppapi::PepperFilePath& path, |
| int flags, |
| base::PlatformFile* file) { |
| IPC::PlatformFileForTransit transit_file; |
| base::PlatformFileError error; |
| IPC::Message* msg = new PepperFileMsg_OpenFile( |
| path, flags, &error, &transit_file); |
| if (!render_view_->Send(msg)) { |
| *file = base::kInvalidPlatformFileValue; |
| return base::PLATFORM_FILE_ERROR_FAILED; |
| } |
| *file = IPC::PlatformFileForTransitToPlatformFile(transit_file); |
| return error; |
| } |
| |
| base::PlatformFileError PepperPluginDelegateImpl::RenameFile( |
| const ppapi::PepperFilePath& from_path, |
| const ppapi::PepperFilePath& to_path) { |
| base::PlatformFileError error; |
| IPC::Message* msg = new PepperFileMsg_RenameFile(from_path, to_path, &error); |
| if (!render_view_->Send(msg)) |
| return base::PLATFORM_FILE_ERROR_FAILED; |
| return error; |
| } |
| |
| base::PlatformFileError PepperPluginDelegateImpl::DeleteFileOrDir( |
| const ppapi::PepperFilePath& path, |
| bool recursive) { |
| base::PlatformFileError error; |
| IPC::Message* msg = new PepperFileMsg_DeleteFileOrDir( |
| path, recursive, &error); |
| if (!render_view_->Send(msg)) |
| return base::PLATFORM_FILE_ERROR_FAILED; |
| return error; |
| } |
| |
| base::PlatformFileError PepperPluginDelegateImpl::CreateDir( |
| const ppapi::PepperFilePath& path) { |
| base::PlatformFileError error; |
| IPC::Message* msg = new PepperFileMsg_CreateDir(path, &error); |
| if (!render_view_->Send(msg)) |
| return base::PLATFORM_FILE_ERROR_FAILED; |
| return error; |
| } |
| |
| base::PlatformFileError PepperPluginDelegateImpl::QueryFile( |
| const ppapi::PepperFilePath& path, |
| base::PlatformFileInfo* info) { |
| base::PlatformFileError error; |
| IPC::Message* msg = new PepperFileMsg_QueryFile(path, info, &error); |
| if (!render_view_->Send(msg)) |
| return base::PLATFORM_FILE_ERROR_FAILED; |
| return error; |
| } |
| |
| base::PlatformFileError PepperPluginDelegateImpl::GetDirContents( |
| const ppapi::PepperFilePath& path, |
| ppapi::DirContents* contents) { |
| base::PlatformFileError error; |
| IPC::Message* msg = new PepperFileMsg_GetDirContents(path, contents, &error); |
| if (!render_view_->Send(msg)) |
| return base::PLATFORM_FILE_ERROR_FAILED; |
| return error; |
| } |
| |
| base::PlatformFileError PepperPluginDelegateImpl::CreateTemporaryFile( |
| base::PlatformFile* file) { |
| IPC::PlatformFileForTransit transit_file; |
| base::PlatformFileError error; |
| IPC::Message* msg = new PepperFileMsg_CreateTemporaryFile(&error, |
| &transit_file); |
| if (!render_view_->Send(msg)) { |
| *file = base::kInvalidPlatformFileValue; |
| return base::PLATFORM_FILE_ERROR_FAILED; |
| } |
| *file = IPC::PlatformFileForTransitToPlatformFile(transit_file); |
| return error; |
| } |
| |
| void PepperPluginDelegateImpl::SyncGetFileSystemPlatformPath( |
| const GURL& url, FilePath* platform_path) { |
| RenderThreadImpl::current()->Send(new FileSystemHostMsg_SyncGetPlatformPath( |
| url, platform_path)); |
| } |
| |
| scoped_refptr<base::MessageLoopProxy> |
| PepperPluginDelegateImpl::GetFileThreadMessageLoopProxy() { |
| return RenderThreadImpl::current()->GetFileThreadMessageLoopProxy(); |
| } |
| |
| uint32 PepperPluginDelegateImpl::TCPSocketCreate() { |
| uint32 socket_id = 0; |
| render_view_->Send(new PpapiHostMsg_PPBTCPSocket_Create( |
| render_view_->routing_id(), 0, &socket_id)); |
| return socket_id; |
| } |
| |
| void PepperPluginDelegateImpl::TCPSocketConnect( |
| webkit::ppapi::PPB_TCPSocket_Private_Impl* socket, |
| uint32 socket_id, |
| const std::string& host, |
| uint16_t port) { |
| RegisterTCPSocket(socket, socket_id); |
| render_view_->Send( |
| new PpapiHostMsg_PPBTCPSocket_Connect( |
| render_view_->routing_id(), socket_id, host, port)); |
| } |
| |
| void PepperPluginDelegateImpl::TCPSocketConnectWithNetAddress( |
| webkit::ppapi::PPB_TCPSocket_Private_Impl* socket, |
| uint32 socket_id, |
| const PP_NetAddress_Private& addr) { |
| RegisterTCPSocket(socket, socket_id); |
| render_view_->Send( |
| new PpapiHostMsg_PPBTCPSocket_ConnectWithNetAddress( |
| render_view_->routing_id(), socket_id, addr)); |
| } |
| |
| void PepperPluginDelegateImpl::TCPSocketSSLHandshake( |
| uint32 socket_id, |
| const std::string& server_name, |
| uint16_t server_port, |
| const std::vector<std::vector<char> >& trusted_certs, |
| const std::vector<std::vector<char> >& untrusted_certs) { |
| DCHECK(tcp_sockets_.Lookup(socket_id)); |
| render_view_->Send(new PpapiHostMsg_PPBTCPSocket_SSLHandshake( |
| socket_id, server_name, server_port, trusted_certs, untrusted_certs)); |
| } |
| |
| void PepperPluginDelegateImpl::TCPSocketRead(uint32 socket_id, |
| int32_t bytes_to_read) { |
| DCHECK(tcp_sockets_.Lookup(socket_id)); |
| render_view_->Send( |
| new PpapiHostMsg_PPBTCPSocket_Read(socket_id, bytes_to_read)); |
| } |
| |
| void PepperPluginDelegateImpl::TCPSocketWrite(uint32 socket_id, |
| const std::string& buffer) { |
| DCHECK(tcp_sockets_.Lookup(socket_id)); |
| render_view_->Send(new PpapiHostMsg_PPBTCPSocket_Write(socket_id, buffer)); |
| } |
| |
| void PepperPluginDelegateImpl::TCPSocketDisconnect(uint32 socket_id) { |
| // There are no DCHECK(tcp_sockets_.Lookup(socket_id)) because it |
| // can be called before |
| // TCPSocketConnect/TCPSocketConnectWithNetAddress is called. |
| render_view_->Send(new PpapiHostMsg_PPBTCPSocket_Disconnect(socket_id)); |
| if (tcp_sockets_.Lookup(socket_id)) |
| tcp_sockets_.Remove(socket_id); |
| } |
| |
| void PepperPluginDelegateImpl::RegisterTCPSocket( |
| webkit::ppapi::PPB_TCPSocket_Private_Impl* socket, |
| uint32 socket_id) { |
| tcp_sockets_.AddWithID(socket, socket_id); |
| } |
| |
| uint32 PepperPluginDelegateImpl::UDPSocketCreate() { |
| uint32 socket_id = 0; |
| render_view_->Send(new PpapiHostMsg_PPBUDPSocket_Create( |
| render_view_->routing_id(), 0, &socket_id)); |
| return socket_id; |
| } |
| |
| void PepperPluginDelegateImpl::UDPSocketSetBoolSocketFeature( |
| webkit::ppapi::PPB_UDPSocket_Private_Impl* socket, |
| uint32 socket_id, |
| int32_t name, |
| bool value) { |
| render_view_->Send( |
| new PpapiHostMsg_PPBUDPSocket_SetBoolSocketFeature( |
| render_view_->routing_id(), socket_id, name, value)); |
| } |
| |
| void PepperPluginDelegateImpl::UDPSocketBind( |
| webkit::ppapi::PPB_UDPSocket_Private_Impl* socket, |
| uint32 socket_id, |
| const PP_NetAddress_Private& addr) { |
| if (!udp_sockets_.Lookup(socket_id)) |
| udp_sockets_.AddWithID(socket, socket_id); |
| render_view_->Send(new PpapiHostMsg_PPBUDPSocket_Bind( |
| render_view_->routing_id(), socket_id, addr)); |
| } |
| |
| void PepperPluginDelegateImpl::UDPSocketRecvFrom(uint32 socket_id, |
| int32_t num_bytes) { |
| DCHECK(udp_sockets_.Lookup(socket_id)); |
| render_view_->Send( |
| new PpapiHostMsg_PPBUDPSocket_RecvFrom(socket_id, num_bytes)); |
| } |
| |
| void PepperPluginDelegateImpl::UDPSocketSendTo( |
| uint32 socket_id, |
| const std::string& buffer, |
| const PP_NetAddress_Private& net_addr) { |
| DCHECK(udp_sockets_.Lookup(socket_id)); |
| render_view_->Send( |
| new PpapiHostMsg_PPBUDPSocket_SendTo(socket_id, buffer, net_addr)); |
| } |
| |
| void PepperPluginDelegateImpl::UDPSocketClose(uint32 socket_id) { |
| // There are no DCHECK(udp_sockets_.Lookup(socket_id)) because it |
| // can be called before UDPSocketBind is called. |
| render_view_->Send(new PpapiHostMsg_PPBUDPSocket_Close(socket_id)); |
| if (udp_sockets_.Lookup(socket_id)) |
| udp_sockets_.Remove(socket_id); |
| } |
| |
| void PepperPluginDelegateImpl::TCPServerSocketListen( |
| PP_Resource socket_resource, |
| const PP_NetAddress_Private& addr, |
| int32_t backlog) { |
| render_view_->Send( |
| new PpapiHostMsg_PPBTCPServerSocket_Listen( |
| render_view_->routing_id(), 0, socket_resource, addr, backlog)); |
| } |
| |
| void PepperPluginDelegateImpl::TCPServerSocketAccept(uint32 server_socket_id) { |
| DCHECK(tcp_server_sockets_.Lookup(server_socket_id)); |
| render_view_->Send(new PpapiHostMsg_PPBTCPServerSocket_Accept( |
| render_view_->routing_id(), server_socket_id)); |
| } |
| |
| void PepperPluginDelegateImpl::TCPServerSocketStopListening( |
| PP_Resource socket_resource, |
| uint32 socket_id) { |
| if (socket_id != 0) { |
| render_view_->Send(new PpapiHostMsg_PPBTCPServerSocket_Destroy(socket_id)); |
| tcp_server_sockets_.Remove(socket_id); |
| } |
| } |
| |
| void PepperPluginDelegateImpl::RegisterHostResolver( |
| ppapi::PPB_HostResolver_Shared* host_resolver, |
| uint32 host_resolver_id) { |
| host_resolvers_.AddWithID(host_resolver, host_resolver_id); |
| } |
| |
| void PepperPluginDelegateImpl::HostResolverResolve( |
| uint32 host_resolver_id, |
| const ::ppapi::HostPortPair& host_port, |
| const PP_HostResolver_Private_Hint* hint) { |
| DCHECK(host_resolvers_.Lookup(host_resolver_id)); |
| if (!hint) { |
| PP_HostResolver_Private_Hint empty_hint; |
| empty_hint.family = PP_NETADDRESSFAMILY_UNSPECIFIED; |
| empty_hint.flags = static_cast<PP_HostResolver_Private_Flags>(0); |
| render_view_->Send( |
| new PpapiHostMsg_PPBHostResolver_Resolve( |
| GetRoutingID(), |
| 0, |
| host_resolver_id, |
| host_port, |
| empty_hint)); |
| } else { |
| render_view_->Send( |
| new PpapiHostMsg_PPBHostResolver_Resolve( |
| GetRoutingID(), |
| 0, |
| host_resolver_id, |
| host_port, |
| *hint)); |
| } |
| } |
| |
| void PepperPluginDelegateImpl::UnregisterHostResolver(uint32 host_resolver_id) { |
| host_resolvers_.Remove(host_resolver_id); |
| } |
| |
| bool PepperPluginDelegateImpl::AddNetworkListObserver( |
| webkit_glue::NetworkListObserver* observer) { |
| #if defined(ENABLE_WEBRTC) |
| P2PSocketDispatcher* socket_dispatcher = |
| RenderThreadImpl::current()->p2p_socket_dispatcher(); |
| if (!socket_dispatcher) { |
| return false; |
| } |
| socket_dispatcher->AddNetworkListObserver(observer); |
| return true; |
| #else |
| return false; |
| #endif |
| } |
| |
| void PepperPluginDelegateImpl::RemoveNetworkListObserver( |
| webkit_glue::NetworkListObserver* observer) { |
| #if defined(ENABLE_WEBRTC) |
| P2PSocketDispatcher* socket_dispatcher = |
| RenderThreadImpl::current()->p2p_socket_dispatcher(); |
| if (socket_dispatcher) |
| socket_dispatcher->RemoveNetworkListObserver(observer); |
| #endif |
| } |
| |
| bool PepperPluginDelegateImpl::X509CertificateParseDER( |
| const std::vector<char>& der, |
| ppapi::PPB_X509Certificate_Fields* fields) { |
| bool succeeded = false; |
| render_view_->Send( |
| new PpapiHostMsg_PPBX509Certificate_ParseDER(der, &succeeded, fields)); |
| return succeeded; |
| } |
| |
| int32_t PepperPluginDelegateImpl::ShowContextMenu( |
| webkit::ppapi::PluginInstance* instance, |
| webkit::ppapi::PPB_Flash_Menu_Impl* menu, |
| const gfx::Point& position) { |
| int32 render_widget_id = render_view_->routing_id(); |
| if (instance->flash_fullscreen()) { |
| webkit::ppapi::FullscreenContainer* container = |
| instance->fullscreen_container(); |
| DCHECK(container); |
| render_widget_id = |
| static_cast<RenderWidgetFullscreenPepper*>(container)->routing_id(); |
| } |
| |
| int request_id = pending_context_menus_.Add( |
| new scoped_refptr<webkit::ppapi::PPB_Flash_Menu_Impl>(menu)); |
| |
| ContextMenuParams params; |
| params.x = position.x(); |
| params.y = position.y(); |
| params.custom_context.is_pepper_menu = true; |
| params.custom_context.request_id = request_id; |
| params.custom_context.render_widget_id = render_widget_id; |
| params.custom_items = menu->menu_data(); |
| |
| // Transform the position to be in render view's coordinates. |
| if (instance->view_data().is_fullscreen || instance->flash_fullscreen()) { |
| WebKit::WebRect window_rect = render_view_->windowRect(); |
| WebKit::WebRect screen_rect = render_view_->screenInfo().rect; |
| params.x = params.x - window_rect.x + screen_rect.x; |
| params.y = params.y - window_rect.y + screen_rect.y; |
| } else { |
| params.x += instance->view_data().rect.point.x; |
| params.y += instance->view_data().rect.point.y; |
| } |
| |
| IPC::Message* msg = new ViewHostMsg_ContextMenu(render_view_->routing_id(), |
| params); |
| if (!render_view_->Send(msg)) { |
| pending_context_menus_.Remove(request_id); |
| return PP_ERROR_FAILED; |
| } |
| |
| return PP_OK_COMPLETIONPENDING; |
| } |
| |
| void PepperPluginDelegateImpl::OnContextMenuClosed( |
| const CustomContextMenuContext& custom_context) { |
| int request_id = custom_context.request_id; |
| scoped_refptr<webkit::ppapi::PPB_Flash_Menu_Impl>* menu_ptr = |
| pending_context_menus_.Lookup(request_id); |
| if (!menu_ptr) { |
| NOTREACHED() << "CompleteShowContextMenu() called twice for the same menu."; |
| return; |
| } |
| scoped_refptr<webkit::ppapi::PPB_Flash_Menu_Impl> menu = *menu_ptr; |
| DCHECK(menu.get()); |
| pending_context_menus_.Remove(request_id); |
| |
| if (has_saved_context_menu_action_) { |
| menu->CompleteShow(PP_OK, saved_context_menu_action_); |
| has_saved_context_menu_action_ = false; |
| saved_context_menu_action_ = 0; |
| } else { |
| menu->CompleteShow(PP_ERROR_USERCANCEL, 0); |
| } |
| } |
| |
| void PepperPluginDelegateImpl::OnCustomContextMenuAction( |
| const CustomContextMenuContext& custom_context, |
| unsigned action) { |
| // Just save the action. |
| DCHECK(!has_saved_context_menu_action_); |
| has_saved_context_menu_action_ = true; |
| saved_context_menu_action_ = action; |
| } |
| |
| webkit::ppapi::FullscreenContainer* |
| PepperPluginDelegateImpl::CreateFullscreenContainer( |
| webkit::ppapi::PluginInstance* instance) { |
| return render_view_->CreatePepperFullscreenContainer(instance); |
| } |
| |
| gfx::Size PepperPluginDelegateImpl::GetScreenSize() { |
| WebKit::WebScreenInfo info = render_view_->screenInfo(); |
| return gfx::Size(info.rect.width, info.rect.height); |
| } |
| |
| std::string PepperPluginDelegateImpl::GetDefaultEncoding() { |
| return render_view_->webkit_preferences().default_encoding; |
| } |
| |
| void PepperPluginDelegateImpl::ZoomLimitsChanged(double minimum_factor, |
| double maximum_factor) { |
| double minimum_level = WebView::zoomFactorToZoomLevel(minimum_factor); |
| double maximum_level = WebView::zoomFactorToZoomLevel(maximum_factor); |
| render_view_->webview()->zoomLimitsChanged(minimum_level, maximum_level); |
| } |
| |
| std::string PepperPluginDelegateImpl::ResolveProxy(const GURL& url) { |
| bool result; |
| std::string proxy_result; |
| RenderThreadImpl::current()->Send( |
| new ViewHostMsg_ResolveProxy(url, &result, &proxy_result)); |
| return proxy_result; |
| } |
| |
| void PepperPluginDelegateImpl::DidStartLoading() { |
| render_view_->DidStartLoadingForPlugin(); |
| } |
| |
| void PepperPluginDelegateImpl::DidStopLoading() { |
| render_view_->DidStopLoadingForPlugin(); |
| } |
| |
| void PepperPluginDelegateImpl::SetContentRestriction(int restrictions) { |
| render_view_->Send(new ViewHostMsg_UpdateContentRestrictions( |
| render_view_->routing_id(), restrictions)); |
| } |
| |
| void PepperPluginDelegateImpl::SaveURLAs(const GURL& url) { |
| WebFrame* frame = render_view_->webview()->mainFrame(); |
| content::Referrer referrer(frame->document().url(), |
| frame->document().referrerPolicy()); |
| render_view_->Send(new ViewHostMsg_SaveURLAs( |
| render_view_->routing_id(), url, referrer)); |
| } |
| |
| double PepperPluginDelegateImpl::GetLocalTimeZoneOffset(base::Time t) { |
| double result = 0.0; |
| render_view_->Send(new PepperMsg_GetLocalTimeZoneOffset( |
| t, &result)); |
| return result; |
| } |
| |
| std::string PepperPluginDelegateImpl::GetDeviceID() { |
| std::string result; |
| render_view_->Send(new PepperMsg_GetDeviceID(&result)); |
| return result; |
| } |
| |
| PP_FlashLSORestrictions PepperPluginDelegateImpl::GetLocalDataRestrictions( |
| const GURL& document_url, |
| const GURL& plugin_url) { |
| PP_FlashLSORestrictions restrictions = PP_FLASHLSORESTRICTIONS_NONE; |
| render_view_->Send( |
| new PepperMsg_GetLocalDataRestrictions(document_url, plugin_url, |
| &restrictions)); |
| return restrictions; |
| } |
| |
| base::SharedMemory* PepperPluginDelegateImpl::CreateAnonymousSharedMemory( |
| uint32_t size) { |
| if (size == 0) |
| return NULL; |
| base::SharedMemoryHandle handle; |
| if (!render_view_->Send( |
| new ChildProcessHostMsg_SyncAllocateSharedMemory(size, &handle))) { |
| DLOG(WARNING) << "Browser allocation request message failed"; |
| return NULL; |
| } |
| if (!base::SharedMemory::IsHandleValid(handle)) { |
| DLOG(WARNING) << "Browser failed to allocate shared memory"; |
| return NULL; |
| } |
| return new base::SharedMemory(handle, false); |
| } |
| |
| ppapi::Preferences PepperPluginDelegateImpl::GetPreferences() { |
| return ppapi::Preferences(render_view_->webkit_preferences()); |
| } |
| |
| bool PepperPluginDelegateImpl::LockMouse( |
| webkit::ppapi::PluginInstance* instance) { |
| return GetMouseLockDispatcher(instance)->LockMouse( |
| GetOrCreateLockTargetAdapter(instance)); |
| } |
| |
| void PepperPluginDelegateImpl::UnlockMouse( |
| webkit::ppapi::PluginInstance* instance) { |
| GetMouseLockDispatcher(instance)->UnlockMouse( |
| GetOrCreateLockTargetAdapter(instance)); |
| } |
| |
| bool PepperPluginDelegateImpl::IsMouseLocked( |
| webkit::ppapi::PluginInstance* instance) { |
| return GetMouseLockDispatcher(instance)->IsMouseLockedTo( |
| GetOrCreateLockTargetAdapter(instance)); |
| } |
| |
| void PepperPluginDelegateImpl::DidChangeCursor( |
| webkit::ppapi::PluginInstance* instance, |
| const WebKit::WebCursorInfo& cursor) { |
| // Update the cursor appearance immediately if the requesting plugin is the |
| // one which receives the last mouse event. Otherwise, the new cursor won't be |
| // picked up until the plugin gets the next input event. That is bad if, e.g., |
| // the plugin would like to set an invisible cursor when there isn't any user |
| // input for a while. |
| if (instance == last_mouse_event_target_) |
| render_view_->didChangeCursor(cursor); |
| } |
| |
| void PepperPluginDelegateImpl::DidReceiveMouseEvent( |
| webkit::ppapi::PluginInstance* instance) { |
| last_mouse_event_target_ = instance; |
| } |
| |
| bool PepperPluginDelegateImpl::IsInFullscreenMode() { |
| return render_view_->is_fullscreen(); |
| } |
| |
| void PepperPluginDelegateImpl::SampleGamepads(WebKit::WebGamepads* data) { |
| if (!gamepad_shared_memory_reader_.get()) |
| gamepad_shared_memory_reader_.reset(new GamepadSharedMemoryReader); |
| gamepad_shared_memory_reader_->SampleGamepads(*data); |
| } |
| |
| bool PepperPluginDelegateImpl::IsPageVisible() const { |
| return !render_view_->is_hidden(); |
| } |
| |
| int PepperPluginDelegateImpl::EnumerateDevices( |
| PP_DeviceType_Dev type, |
| const EnumerateDevicesCallback& callback) { |
| int request_id = |
| device_enumeration_event_handler_->RegisterEnumerateDevicesCallback( |
| callback); |
| |
| #if defined(ENABLE_WEBRTC) |
| render_view_->media_stream_dispatcher()->EnumerateDevices( |
| request_id, device_enumeration_event_handler_.get()->AsWeakPtr(), |
| PepperDeviceEnumerationEventHandler::FromPepperDeviceType(type), |
| GURL()); |
| #else |
| MessageLoop::current()->PostTask( |
| FROM_HERE, |
| base::Bind( |
| &PepperDeviceEnumerationEventHandler::OnDevicesEnumerationFailed, |
| device_enumeration_event_handler_->AsWeakPtr(), request_id)); |
| #endif |
| |
| return request_id; |
| } |
| |
| void PepperPluginDelegateImpl::StopEnumerateDevices(int request_id) { |
| #if defined(ENABLE_WEBRTC) |
| // Need to post task since this function might be called inside the callback |
| // of EnumerateDevices. |
| MessageLoop::current()->PostTask( |
| FROM_HERE, |
| base::Bind( |
| &MediaStreamDispatcher::StopEnumerateDevices, |
| render_view_->media_stream_dispatcher()->AsWeakPtr(), |
| request_id, device_enumeration_event_handler_.get()->AsWeakPtr())); |
| #endif |
| } |
| |
| bool PepperPluginDelegateImpl::OnMessageReceived(const IPC::Message& message) { |
| bool handled = true; |
| IPC_BEGIN_MESSAGE_MAP(PepperPluginDelegateImpl, message) |
| IPC_MESSAGE_HANDLER(PpapiMsg_PPBTCPSocket_ConnectACK, |
| OnTCPSocketConnectACK) |
| IPC_MESSAGE_HANDLER(PpapiMsg_PPBTCPSocket_SSLHandshakeACK, |
| OnTCPSocketSSLHandshakeACK) |
| IPC_MESSAGE_HANDLER(PpapiMsg_PPBTCPSocket_ReadACK, OnTCPSocketReadACK) |
| IPC_MESSAGE_HANDLER(PpapiMsg_PPBTCPSocket_WriteACK, OnTCPSocketWriteACK) |
| IPC_MESSAGE_HANDLER(PpapiMsg_PPBUDPSocket_BindACK, OnUDPSocketBindACK) |
| IPC_MESSAGE_HANDLER(PpapiMsg_PPBUDPSocket_RecvFromACK, |
| OnUDPSocketRecvFromACK) |
| IPC_MESSAGE_HANDLER(PpapiMsg_PPBUDPSocket_SendToACK, OnUDPSocketSendToACK) |
| IPC_MESSAGE_HANDLER(PpapiMsg_PPBTCPServerSocket_ListenACK, |
| OnTCPServerSocketListenACK) |
| IPC_MESSAGE_HANDLER(PpapiMsg_PPBTCPServerSocket_AcceptACK, |
| OnTCPServerSocketAcceptACK) |
| IPC_MESSAGE_HANDLER(PpapiMsg_PPBHostResolver_ResolveACK, |
| OnHostResolverResolveACK) |
| IPC_MESSAGE_UNHANDLED(handled = false) |
| IPC_END_MESSAGE_MAP() |
| return handled; |
| } |
| |
| void PepperPluginDelegateImpl::OnDestruct() { |
| // Nothing to do here. Default implementation in RenderViewObserver does |
| // 'delete this' but it's not suitable for PepperPluginDelegateImpl because |
| // it's non-pointer member in RenderViewImpl. |
| } |
| |
| void PepperPluginDelegateImpl::OnTCPSocketConnectACK( |
| uint32 plugin_dispatcher_id, |
| uint32 socket_id, |
| bool succeeded, |
| const PP_NetAddress_Private& local_addr, |
| const PP_NetAddress_Private& remote_addr) { |
| webkit::ppapi::PPB_TCPSocket_Private_Impl* socket = |
| tcp_sockets_.Lookup(socket_id); |
| if (socket) |
| socket->OnConnectCompleted(succeeded, local_addr, remote_addr); |
| if (!succeeded) |
| tcp_sockets_.Remove(socket_id); |
| } |
| |
| void PepperPluginDelegateImpl::OnTCPSocketSSLHandshakeACK( |
| uint32 plugin_dispatcher_id, |
| uint32 socket_id, |
| bool succeeded, |
| const ppapi::PPB_X509Certificate_Fields& certificate_fields) { |
| webkit::ppapi::PPB_TCPSocket_Private_Impl* socket = |
| tcp_sockets_.Lookup(socket_id); |
| if (socket) |
| socket->OnSSLHandshakeCompleted(succeeded, certificate_fields); |
| } |
| |
| void PepperPluginDelegateImpl::OnTCPSocketReadACK(uint32 plugin_dispatcher_id, |
| uint32 socket_id, |
| bool succeeded, |
| const std::string& data) { |
| webkit::ppapi::PPB_TCPSocket_Private_Impl* socket = |
| tcp_sockets_.Lookup(socket_id); |
| if (socket) |
| socket->OnReadCompleted(succeeded, data); |
| } |
| |
| void PepperPluginDelegateImpl::OnTCPSocketWriteACK(uint32 plugin_dispatcher_id, |
| uint32 socket_id, |
| bool succeeded, |
| int32_t bytes_written) { |
| webkit::ppapi::PPB_TCPSocket_Private_Impl* socket = |
| tcp_sockets_.Lookup(socket_id); |
| if (socket) |
| socket->OnWriteCompleted(succeeded, bytes_written); |
| } |
| |
| void PepperPluginDelegateImpl::OnUDPSocketBindACK( |
| uint32 plugin_dispatcher_id, |
| uint32 socket_id, |
| bool succeeded, |
| const PP_NetAddress_Private& addr) { |
| webkit::ppapi::PPB_UDPSocket_Private_Impl* socket = |
| udp_sockets_.Lookup(socket_id); |
| if (socket) |
| socket->OnBindCompleted(succeeded, addr); |
| if (!succeeded) |
| udp_sockets_.Remove(socket_id); |
| } |
| |
| void PepperPluginDelegateImpl::OnUDPSocketRecvFromACK( |
| uint32 plugin_dispatcher_id, |
| uint32 socket_id, |
| bool succeeded, |
| const std::string& data, |
| const PP_NetAddress_Private& remote_addr) { |
| webkit::ppapi::PPB_UDPSocket_Private_Impl* socket = |
| udp_sockets_.Lookup(socket_id); |
| if (socket) |
| socket->OnRecvFromCompleted(succeeded, data, remote_addr); |
| } |
| |
| void PepperPluginDelegateImpl::OnUDPSocketSendToACK(uint32 plugin_dispatcher_id, |
| uint32 socket_id, |
| bool succeeded, |
| int32_t bytes_written) { |
| webkit::ppapi::PPB_UDPSocket_Private_Impl* socket = |
| udp_sockets_.Lookup(socket_id); |
| if (socket) |
| socket->OnSendToCompleted(succeeded, bytes_written); |
| } |
| |
| void PepperPluginDelegateImpl::OnTCPServerSocketListenACK( |
| uint32 plugin_dispatcher_id, |
| PP_Resource socket_resource, |
| uint32 socket_id, |
| int32_t status) { |
| ppapi::thunk::EnterResource<ppapi::thunk::PPB_TCPServerSocket_Private_API> |
| enter(socket_resource, true); |
| if (enter.succeeded()) { |
| ppapi::PPB_TCPServerSocket_Shared* socket = |
| static_cast<ppapi::PPB_TCPServerSocket_Shared*>(enter.object()); |
| if (status == PP_OK) |
| tcp_server_sockets_.AddWithID(socket, socket_id); |
| socket->OnListenCompleted(socket_id, status); |
| } else if (socket_id != 0 && status == PP_OK) { |
| // StopListening was called before completion of Listen. |
| render_view_->Send(new PpapiHostMsg_PPBTCPServerSocket_Destroy(socket_id)); |
| } |
| } |
| |
| void PepperPluginDelegateImpl::OnTCPServerSocketAcceptACK( |
| uint32 plugin_dispatcher_id, |
| uint32 server_socket_id, |
| uint32 accepted_socket_id, |
| const PP_NetAddress_Private& local_addr, |
| const PP_NetAddress_Private& remote_addr) { |
| ppapi::PPB_TCPServerSocket_Shared* socket = |
| tcp_server_sockets_.Lookup(server_socket_id); |
| if (socket) { |
| bool succeeded = (accepted_socket_id != 0); |
| socket->OnAcceptCompleted(succeeded, |
| accepted_socket_id, |
| local_addr, |
| remote_addr); |
| } else if (accepted_socket_id != 0) { |
| render_view_->Send( |
| new PpapiHostMsg_PPBTCPSocket_Disconnect(accepted_socket_id)); |
| } |
| } |
| |
| void PepperPluginDelegateImpl::OnHostResolverResolveACK( |
| uint32 plugin_dispatcher_id, |
| uint32 host_resolver_id, |
| bool succeeded, |
| const std::string& canonical_name, |
| const std::vector<PP_NetAddress_Private>& net_address_list) { |
| ppapi::PPB_HostResolver_Shared* host_resolver = |
| host_resolvers_.Lookup(host_resolver_id); |
| if (host_resolver) { |
| host_resolver->OnResolveCompleted(succeeded, |
| canonical_name, |
| net_address_list); |
| } |
| } |
| |
| int PepperPluginDelegateImpl::GetRoutingID() const { |
| return render_view_->routing_id(); |
| } |
| |
| int PepperPluginDelegateImpl::OpenDevice(PP_DeviceType_Dev type, |
| const std::string& device_id, |
| const OpenDeviceCallback& callback) { |
| int request_id = |
| device_enumeration_event_handler_->RegisterOpenDeviceCallback(callback); |
| |
| #if defined(ENABLE_WEBRTC) |
| render_view_->media_stream_dispatcher()->OpenDevice( |
| request_id, |
| device_enumeration_event_handler_.get()->AsWeakPtr(), |
| device_id, |
| PepperDeviceEnumerationEventHandler::FromPepperDeviceType(type), |
| GURL()); |
| #else |
| MessageLoop::current()->PostTask( |
| FROM_HERE, |
| base::Bind(&PepperDeviceEnumerationEventHandler::OnDeviceOpenFailed, |
| device_enumeration_event_handler_->AsWeakPtr(), request_id)); |
| #endif |
| |
| return request_id; |
| } |
| |
| void PepperPluginDelegateImpl::CloseDevice(const std::string& label) { |
| #if defined(ENABLE_WEBRTC) |
| render_view_->media_stream_dispatcher()->CloseDevice(label); |
| #endif |
| } |
| |
| int PepperPluginDelegateImpl::GetSessionID(PP_DeviceType_Dev type, |
| const std::string& label) { |
| #if defined(ENABLE_WEBRTC) |
| switch (type) { |
| case PP_DEVICETYPE_DEV_AUDIOCAPTURE: |
| return render_view_->media_stream_dispatcher()->audio_session_id(label, |
| 0); |
| case PP_DEVICETYPE_DEV_VIDEOCAPTURE: |
| return render_view_->media_stream_dispatcher()->video_session_id(label, |
| 0); |
| default: |
| NOTREACHED(); |
| return 0; |
| } |
| #else |
| return 0; |
| #endif |
| } |
| |
| WebGraphicsContext3DCommandBufferImpl* |
| PepperPluginDelegateImpl::GetParentContextForPlatformContext3D() { |
| WebGraphicsContext3DCommandBufferImpl* context = |
| static_cast<WebGraphicsContext3DCommandBufferImpl*>( |
| render_view_->webview()->sharedGraphicsContext3D()); |
| if (!context) |
| return NULL; |
| if (!context->makeContextCurrent() || context->isContextLost()) |
| return NULL; |
| |
| return context; |
| } |
| |
| MouseLockDispatcher::LockTarget* |
| PepperPluginDelegateImpl::GetOrCreateLockTargetAdapter( |
| webkit::ppapi::PluginInstance* instance) { |
| MouseLockDispatcher::LockTarget* target = mouse_lock_instances_[instance]; |
| if (target) |
| return target; |
| |
| return mouse_lock_instances_[instance] = |
| new PluginInstanceLockTarget(instance); |
| } |
| |
| void PepperPluginDelegateImpl::UnSetAndDeleteLockTargetAdapter( |
| webkit::ppapi::PluginInstance* instance) { |
| LockTargetMap::iterator it = mouse_lock_instances_.find(instance); |
| if (it != mouse_lock_instances_.end()) { |
| MouseLockDispatcher::LockTarget* target = it->second; |
| GetMouseLockDispatcher(instance)->OnLockTargetDestroyed(target); |
| delete target; |
| mouse_lock_instances_.erase(it); |
| } |
| } |
| |
| MouseLockDispatcher* PepperPluginDelegateImpl::GetMouseLockDispatcher( |
| webkit::ppapi::PluginInstance* instance) { |
| if (instance->flash_fullscreen()) |
| return instance->fullscreen_container()->GetMouseLockDispatcher(); |
| else |
| return render_view_->mouse_lock_dispatcher(); |
| } |
| |
| webkit_glue::ClipboardClient* |
| PepperPluginDelegateImpl::CreateClipboardClient() const { |
| return new RendererClipboardClient; |
| } |
| |
| } // namespace content |