1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "content/renderer/pepper/renderer_ppapi_host_impl.h" 6 7 #include "base/bind.h" 8 #include "base/files/file_path.h" 9 #include "base/logging.h" 10 #include "base/message_loop/message_loop.h" 11 #include "base/process/process_handle.h" 12 #include "content/common/sandbox_util.h" 13 #include "content/renderer/pepper/fullscreen_container.h" 14 #include "content/renderer/pepper/host_globals.h" 15 #include "content/renderer/pepper/pepper_browser_connection.h" 16 #include "content/renderer/pepper/pepper_graphics_2d_host.h" 17 #include "content/renderer/pepper/pepper_in_process_resource_creation.h" 18 #include "content/renderer/pepper/pepper_in_process_router.h" 19 #include "content/renderer/pepper/pepper_plugin_instance_impl.h" 20 #include "content/renderer/pepper/plugin_module.h" 21 #include "content/renderer/render_view_impl.h" 22 #include "content/renderer/render_widget_fullscreen_pepper.h" 23 #include "ipc/ipc_message.h" 24 #include "ppapi/host/ppapi_host.h" 25 #include "ppapi/proxy/host_dispatcher.h" 26 #include "third_party/WebKit/public/platform/WebRect.h" 27 #include "third_party/WebKit/public/web/WebDocument.h" 28 #include "third_party/WebKit/public/web/WebElement.h" 29 #include "third_party/WebKit/public/web/WebPluginContainer.h" 30 #include "ui/gfx/point.h" 31 32 namespace content { 33 // static 34 CONTENT_EXPORT RendererPpapiHost* RendererPpapiHost::GetForPPInstance( 35 PP_Instance instance) { 36 return RendererPpapiHostImpl::GetForPPInstance(instance); 37 } 38 39 // Out-of-process constructor. 40 RendererPpapiHostImpl::RendererPpapiHostImpl( 41 PluginModule* module, 42 ppapi::proxy::HostDispatcher* dispatcher, 43 const ppapi::PpapiPermissions& permissions) 44 : module_(module), 45 dispatcher_(dispatcher), 46 is_external_plugin_host_(false) { 47 // Hook the PpapiHost up to the dispatcher for out-of-process communication. 48 ppapi_host_.reset(new ppapi::host::PpapiHost(dispatcher, permissions)); 49 ppapi_host_->AddHostFactoryFilter(scoped_ptr<ppapi::host::HostFactory>( 50 new ContentRendererPepperHostFactory(this))); 51 dispatcher->AddFilter(ppapi_host_.get()); 52 is_running_in_process_ = false; 53 } 54 55 // In-process constructor. 56 RendererPpapiHostImpl::RendererPpapiHostImpl( 57 PluginModule* module, 58 const ppapi::PpapiPermissions& permissions) 59 : module_(module), dispatcher_(NULL), is_external_plugin_host_(false) { 60 // Hook the host up to the in-process router. 61 in_process_router_.reset(new PepperInProcessRouter(this)); 62 ppapi_host_.reset(new ppapi::host::PpapiHost( 63 in_process_router_->GetRendererToPluginSender(), permissions)); 64 ppapi_host_->AddHostFactoryFilter(scoped_ptr<ppapi::host::HostFactory>( 65 new ContentRendererPepperHostFactory(this))); 66 is_running_in_process_ = true; 67 } 68 69 RendererPpapiHostImpl::~RendererPpapiHostImpl() { 70 // Delete the host explicitly first. This shutdown will destroy the 71 // resources, which may want to do cleanup in their destructors and expect 72 // their pointers to us to be valid. 73 ppapi_host_.reset(); 74 } 75 76 // static 77 RendererPpapiHostImpl* RendererPpapiHostImpl::CreateOnModuleForOutOfProcess( 78 PluginModule* module, 79 ppapi::proxy::HostDispatcher* dispatcher, 80 const ppapi::PpapiPermissions& permissions) { 81 DCHECK(!module->renderer_ppapi_host()); 82 RendererPpapiHostImpl* result = 83 new RendererPpapiHostImpl(module, dispatcher, permissions); 84 85 // Takes ownership of pointer. 86 module->SetRendererPpapiHost(scoped_ptr<RendererPpapiHostImpl>(result)); 87 88 return result; 89 } 90 91 // static 92 RendererPpapiHostImpl* RendererPpapiHostImpl::CreateOnModuleForInProcess( 93 PluginModule* module, 94 const ppapi::PpapiPermissions& permissions) { 95 DCHECK(!module->renderer_ppapi_host()); 96 RendererPpapiHostImpl* result = 97 new RendererPpapiHostImpl(module, permissions); 98 99 // Takes ownership of pointer. 100 module->SetRendererPpapiHost(scoped_ptr<RendererPpapiHostImpl>(result)); 101 102 return result; 103 } 104 105 // static 106 RendererPpapiHostImpl* RendererPpapiHostImpl::GetForPPInstance( 107 PP_Instance pp_instance) { 108 PepperPluginInstanceImpl* instance = 109 HostGlobals::Get()->GetInstance(pp_instance); 110 if (!instance) 111 return NULL; 112 113 // All modules created by content will have their embedder state be the 114 // host impl. 115 return instance->module()->renderer_ppapi_host(); 116 } 117 118 scoped_ptr<ppapi::thunk::ResourceCreationAPI> 119 RendererPpapiHostImpl::CreateInProcessResourceCreationAPI( 120 PepperPluginInstanceImpl* instance) { 121 return scoped_ptr<ppapi::thunk::ResourceCreationAPI>( 122 new PepperInProcessResourceCreation(this, instance)); 123 } 124 125 PepperPluginInstanceImpl* RendererPpapiHostImpl::GetPluginInstanceImpl( 126 PP_Instance instance) const { 127 return GetAndValidateInstance(instance); 128 } 129 130 bool RendererPpapiHostImpl::IsExternalPluginHost() const { 131 return is_external_plugin_host_; 132 } 133 134 ppapi::host::PpapiHost* RendererPpapiHostImpl::GetPpapiHost() { 135 return ppapi_host_.get(); 136 } 137 138 RenderFrame* RendererPpapiHostImpl::GetRenderFrameForInstance( 139 PP_Instance instance) const { 140 PepperPluginInstanceImpl* instance_object = GetAndValidateInstance(instance); 141 if (!instance_object) 142 return NULL; 143 144 // Since we're the embedder, we can make assumptions about the helper on 145 // the instance and get back to our RenderFrame. 146 return instance_object->render_frame(); 147 } 148 149 RenderView* RendererPpapiHostImpl::GetRenderViewForInstance( 150 PP_Instance instance) const { 151 PepperPluginInstanceImpl* instance_object = GetAndValidateInstance(instance); 152 if (!instance_object) 153 return NULL; 154 155 // Since we're the embedder, we can make assumptions about the helper on 156 // the instance and get back to our RenderView. 157 return instance_object->render_frame()->render_view(); 158 } 159 160 bool RendererPpapiHostImpl::IsValidInstance(PP_Instance instance) const { 161 return !!GetAndValidateInstance(instance); 162 } 163 164 PepperPluginInstance* RendererPpapiHostImpl::GetPluginInstance( 165 PP_Instance instance) const { 166 return GetAndValidateInstance(instance); 167 } 168 169 blink::WebPluginContainer* RendererPpapiHostImpl::GetContainerForInstance( 170 PP_Instance instance) const { 171 PepperPluginInstanceImpl* instance_object = GetAndValidateInstance(instance); 172 if (!instance_object) 173 return NULL; 174 return instance_object->container(); 175 } 176 177 base::ProcessId RendererPpapiHostImpl::GetPluginPID() const { 178 if (dispatcher_) 179 return dispatcher_->channel()->GetPeerPID(); 180 return base::kNullProcessId; 181 } 182 183 bool RendererPpapiHostImpl::HasUserGesture(PP_Instance instance) const { 184 PepperPluginInstanceImpl* instance_object = GetAndValidateInstance(instance); 185 if (!instance_object) 186 return false; 187 188 if (instance_object->module()->permissions().HasPermission( 189 ppapi::PERMISSION_BYPASS_USER_GESTURE)) 190 return true; 191 return instance_object->IsProcessingUserGesture(); 192 } 193 194 int RendererPpapiHostImpl::GetRoutingIDForWidget(PP_Instance instance) const { 195 PepperPluginInstanceImpl* plugin_instance = GetAndValidateInstance(instance); 196 if (!plugin_instance) 197 return 0; 198 if (plugin_instance->flash_fullscreen()) { 199 FullscreenContainer* container = plugin_instance->fullscreen_container(); 200 return static_cast<RenderWidgetFullscreenPepper*>(container)->routing_id(); 201 } 202 return GetRenderViewForInstance(instance)->GetRoutingID(); 203 } 204 205 gfx::Point RendererPpapiHostImpl::PluginPointToRenderFrame( 206 PP_Instance instance, 207 const gfx::Point& pt) const { 208 PepperPluginInstanceImpl* plugin_instance = GetAndValidateInstance(instance); 209 if (!plugin_instance || plugin_instance->flash_fullscreen()) { 210 // Flash fullscreen is special in that it renders into its own separate, 211 // dedicated window. So, do not offset the point. 212 return pt; 213 } 214 return gfx::Point(pt.x() + plugin_instance->view_data().rect.point.x, 215 pt.y() + plugin_instance->view_data().rect.point.y); 216 } 217 218 IPC::PlatformFileForTransit RendererPpapiHostImpl::ShareHandleWithRemote( 219 base::PlatformFile handle, 220 bool should_close_source) { 221 if (!dispatcher_) { 222 DCHECK(is_running_in_process_); 223 // Duplicate the file handle for in process mode so this function 224 // has the same semantics for both in process mode and out of 225 // process mode (i.e., the remote side must cloes the handle). 226 return BrokerGetFileHandleForProcess( 227 handle, base::GetCurrentProcId(), should_close_source); 228 } 229 return dispatcher_->ShareHandleWithRemote(handle, should_close_source); 230 } 231 232 bool RendererPpapiHostImpl::IsRunningInProcess() const { 233 return is_running_in_process_; 234 } 235 236 std::string RendererPpapiHostImpl::GetPluginName() const { 237 return module_->name(); 238 } 239 240 void RendererPpapiHostImpl::SetToExternalPluginHost() { 241 is_external_plugin_host_ = true; 242 } 243 244 void RendererPpapiHostImpl::CreateBrowserResourceHosts( 245 PP_Instance instance, 246 const std::vector<IPC::Message>& nested_msgs, 247 const base::Callback<void(const std::vector<int>&)>& callback) const { 248 RenderFrame* render_frame = GetRenderFrameForInstance(instance); 249 PepperBrowserConnection* browser_connection = 250 PepperBrowserConnection::Get(render_frame); 251 if (!browser_connection) { 252 base::MessageLoop::current()->PostTask( 253 FROM_HERE, 254 base::Bind(callback, std::vector<int>(nested_msgs.size(), 0))); 255 } else { 256 browser_connection->SendBrowserCreate( 257 module_->GetPluginChildId(), instance, nested_msgs, callback); 258 } 259 } 260 261 GURL RendererPpapiHostImpl::GetDocumentURL(PP_Instance instance) const { 262 PepperPluginInstanceImpl* instance_object = GetAndValidateInstance(instance); 263 if (!instance_object) 264 return GURL(); 265 266 return instance_object->container()->element().document().url(); 267 } 268 269 PepperPluginInstanceImpl* RendererPpapiHostImpl::GetAndValidateInstance( 270 PP_Instance pp_instance) const { 271 PepperPluginInstanceImpl* instance = 272 HostGlobals::Get()->GetInstance(pp_instance); 273 if (!instance) 274 return NULL; 275 if (!instance->IsValidInstanceOf(module_)) 276 return NULL; 277 return instance; 278 } 279 280 } // namespace content 281