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*
GetForPPInstance(PP_Instance instance)35 RendererPpapiHost::GetForPPInstance(PP_Instance instance) {
36 return RendererPpapiHostImpl::GetForPPInstance(instance);
37 }
38
39 // Out-of-process constructor.
RendererPpapiHostImpl(PluginModule * module,ppapi::proxy::HostDispatcher * dispatcher,const ppapi::PpapiPermissions & permissions)40 RendererPpapiHostImpl::RendererPpapiHostImpl(
41 PluginModule* module,
42 ppapi::proxy::HostDispatcher* dispatcher,
43 const ppapi::PpapiPermissions& permissions)
44 : module_(module),
45 dispatcher_(dispatcher) {
46 // Hook the PpapiHost up to the dispatcher for out-of-process communication.
47 ppapi_host_.reset(
48 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.
RendererPpapiHostImpl(PluginModule * module,const ppapi::PpapiPermissions & permissions)56 RendererPpapiHostImpl::RendererPpapiHostImpl(
57 PluginModule* module,
58 const ppapi::PpapiPermissions& permissions)
59 : module_(module),
60 dispatcher_(NULL) {
61 // Hook the host up to the in-process router.
62 in_process_router_.reset(new PepperInProcessRouter(this));
63 ppapi_host_.reset(new ppapi::host::PpapiHost(
64 in_process_router_->GetRendererToPluginSender(), permissions));
65 ppapi_host_->AddHostFactoryFilter(scoped_ptr<ppapi::host::HostFactory>(
66 new ContentRendererPepperHostFactory(this)));
67 is_running_in_process_ = true;
68 }
69
~RendererPpapiHostImpl()70 RendererPpapiHostImpl::~RendererPpapiHostImpl() {
71 // Delete the host explicitly first. This shutdown will destroy the
72 // resources, which may want to do cleanup in their destructors and expect
73 // their pointers to us to be valid.
74 ppapi_host_.reset();
75 }
76
77 // static
CreateOnModuleForOutOfProcess(PluginModule * module,ppapi::proxy::HostDispatcher * dispatcher,const ppapi::PpapiPermissions & permissions)78 RendererPpapiHostImpl* RendererPpapiHostImpl::CreateOnModuleForOutOfProcess(
79 PluginModule* module,
80 ppapi::proxy::HostDispatcher* dispatcher,
81 const ppapi::PpapiPermissions& permissions) {
82 DCHECK(!module->renderer_ppapi_host());
83 RendererPpapiHostImpl* result = new RendererPpapiHostImpl(
84 module, dispatcher, permissions);
85
86 // Takes ownership of pointer.
87 module->SetRendererPpapiHost(scoped_ptr<RendererPpapiHostImpl>(result));
88
89 return result;
90 }
91
92 // static
CreateOnModuleForInProcess(PluginModule * module,const ppapi::PpapiPermissions & permissions)93 RendererPpapiHostImpl* RendererPpapiHostImpl::CreateOnModuleForInProcess(
94 PluginModule* module,
95 const ppapi::PpapiPermissions& permissions) {
96 DCHECK(!module->renderer_ppapi_host());
97 RendererPpapiHostImpl* result = new RendererPpapiHostImpl(
98 module, permissions);
99
100 // Takes ownership of pointer.
101 module->SetRendererPpapiHost(scoped_ptr<RendererPpapiHostImpl>(result));
102
103 return result;
104 }
105
106 // static
GetForPPInstance(PP_Instance pp_instance)107 RendererPpapiHostImpl* RendererPpapiHostImpl::GetForPPInstance(
108 PP_Instance pp_instance) {
109 PepperPluginInstanceImpl* instance =
110 HostGlobals::Get()->GetInstance(pp_instance);
111 if (!instance)
112 return NULL;
113
114 // All modules created by content will have their embedder state be the
115 // host impl.
116 return instance->module()->renderer_ppapi_host();
117 }
118
119 scoped_ptr<ppapi::thunk::ResourceCreationAPI>
CreateInProcessResourceCreationAPI(PepperPluginInstanceImpl * instance)120 RendererPpapiHostImpl::CreateInProcessResourceCreationAPI(
121 PepperPluginInstanceImpl* instance) {
122 return scoped_ptr<ppapi::thunk::ResourceCreationAPI>(
123 new PepperInProcessResourceCreation(this, instance));
124 }
125
GetPluginInstanceImpl(PP_Instance instance) const126 PepperPluginInstanceImpl* RendererPpapiHostImpl::GetPluginInstanceImpl(
127 PP_Instance instance) const {
128 return GetAndValidateInstance(instance);
129 }
130
GetPpapiHost()131 ppapi::host::PpapiHost* RendererPpapiHostImpl::GetPpapiHost() {
132 return ppapi_host_.get();
133 }
134
GetRenderFrameForInstance(PP_Instance instance) const135 RenderFrame* RendererPpapiHostImpl::GetRenderFrameForInstance(
136 PP_Instance instance) const {
137 PepperPluginInstanceImpl* instance_object = GetAndValidateInstance(instance);
138 if (!instance_object)
139 return NULL;
140
141 // Since we're the embedder, we can make assumptions about the helper on
142 // the instance and get back to our RenderFrame.
143 return instance_object->render_frame();
144 }
145
GetRenderViewForInstance(PP_Instance instance) const146 RenderView* RendererPpapiHostImpl::GetRenderViewForInstance(
147 PP_Instance instance) const {
148 PepperPluginInstanceImpl* instance_object = GetAndValidateInstance(instance);
149 if (!instance_object)
150 return NULL;
151
152 // Since we're the embedder, we can make assumptions about the helper on
153 // the instance and get back to our RenderView.
154 return instance_object->render_frame()->render_view();
155 }
156
IsValidInstance(PP_Instance instance) const157 bool RendererPpapiHostImpl::IsValidInstance(PP_Instance instance) const {
158 return !!GetAndValidateInstance(instance);
159 }
160
GetPluginInstance(PP_Instance instance) const161 PepperPluginInstance* RendererPpapiHostImpl::GetPluginInstance(
162 PP_Instance instance) const {
163 return GetAndValidateInstance(instance);
164 }
165
GetContainerForInstance(PP_Instance instance) const166 blink::WebPluginContainer* RendererPpapiHostImpl::GetContainerForInstance(
167 PP_Instance instance) const {
168 PepperPluginInstanceImpl* instance_object = GetAndValidateInstance(instance);
169 if (!instance_object)
170 return NULL;
171 return instance_object->container();
172 }
173
GetPluginPID() const174 base::ProcessId RendererPpapiHostImpl::GetPluginPID() const {
175 if (dispatcher_)
176 return dispatcher_->channel()->peer_pid();
177 return base::kNullProcessId;
178 }
179
HasUserGesture(PP_Instance instance) const180 bool RendererPpapiHostImpl::HasUserGesture(PP_Instance instance) const {
181 PepperPluginInstanceImpl* instance_object = GetAndValidateInstance(instance);
182 if (!instance_object)
183 return false;
184
185 if (instance_object->module()->permissions().HasPermission(
186 ppapi::PERMISSION_BYPASS_USER_GESTURE))
187 return true;
188 return instance_object->IsProcessingUserGesture();
189 }
190
GetRoutingIDForWidget(PP_Instance instance) const191 int RendererPpapiHostImpl::GetRoutingIDForWidget(PP_Instance instance) const {
192 PepperPluginInstanceImpl* plugin_instance = GetAndValidateInstance(instance);
193 if (!plugin_instance)
194 return 0;
195 if (plugin_instance->flash_fullscreen()) {
196 FullscreenContainer* container = plugin_instance->fullscreen_container();
197 return static_cast<RenderWidgetFullscreenPepper*>(container)->routing_id();
198 }
199 return GetRenderViewForInstance(instance)->GetRoutingID();
200 }
201
PluginPointToRenderFrame(PP_Instance instance,const gfx::Point & pt) const202 gfx::Point RendererPpapiHostImpl::PluginPointToRenderFrame(
203 PP_Instance instance,
204 const gfx::Point& pt) const {
205 PepperPluginInstanceImpl* plugin_instance = GetAndValidateInstance(instance);
206 if (!plugin_instance)
207 return pt;
208
209 RenderFrameImpl* render_frame = static_cast<RenderFrameImpl*>(
210 GetRenderFrameForInstance(instance));
211 if (plugin_instance->view_data().is_fullscreen ||
212 plugin_instance->flash_fullscreen()) {
213 blink::WebRect window_rect = render_frame->GetRenderWidget()->windowRect();
214 blink::WebRect screen_rect =
215 render_frame->GetRenderWidget()->screenInfo().rect;
216 return gfx::Point(pt.x() - window_rect.x + screen_rect.x,
217 pt.y() - window_rect.y + screen_rect.y);
218 }
219 return gfx::Point(pt.x() + plugin_instance->view_data().rect.point.x,
220 pt.y() + plugin_instance->view_data().rect.point.y);
221 }
222
ShareHandleWithRemote(base::PlatformFile handle,bool should_close_source)223 IPC::PlatformFileForTransit RendererPpapiHostImpl::ShareHandleWithRemote(
224 base::PlatformFile handle,
225 bool should_close_source) {
226 if (!dispatcher_) {
227 DCHECK(is_running_in_process_);
228 // Duplicate the file handle for in process mode so this function
229 // has the same semantics for both in process mode and out of
230 // process mode (i.e., the remote side must cloes the handle).
231 return BrokerGetFileHandleForProcess(handle,
232 base::GetCurrentProcId(),
233 should_close_source);
234 }
235 return dispatcher_->ShareHandleWithRemote(handle, should_close_source);
236 }
237
IsRunningInProcess() const238 bool RendererPpapiHostImpl::IsRunningInProcess() const {
239 return is_running_in_process_;
240 }
241
CreateBrowserResourceHosts(PP_Instance instance,const std::vector<IPC::Message> & nested_msgs,const base::Callback<void (const std::vector<int> &)> & callback) const242 void RendererPpapiHostImpl::CreateBrowserResourceHosts(
243 PP_Instance instance,
244 const std::vector<IPC::Message>& nested_msgs,
245 const base::Callback<void(const std::vector<int>&)>& callback) const {
246 RenderFrame* render_frame = GetRenderFrameForInstance(instance);
247 PepperBrowserConnection* browser_connection =
248 PepperBrowserConnection::Get(render_frame);
249 if (!browser_connection) {
250 base::MessageLoop::current()->PostTask(FROM_HERE,
251 base::Bind(callback, std::vector<int>(nested_msgs.size(), 0)));
252 } else {
253 browser_connection->SendBrowserCreate(module_->GetPluginChildId(),
254 instance,
255 nested_msgs,
256 callback);
257 }
258 }
259
GetDocumentURL(PP_Instance instance) const260 GURL RendererPpapiHostImpl::GetDocumentURL(PP_Instance instance) const {
261 PepperPluginInstanceImpl* instance_object = GetAndValidateInstance(instance);
262 if (!instance_object)
263 return GURL();
264
265 return instance_object->container()->element().document().url();
266 }
267
GetAndValidateInstance(PP_Instance pp_instance) const268 PepperPluginInstanceImpl* RendererPpapiHostImpl::GetAndValidateInstance(
269 PP_Instance pp_instance) const {
270 PepperPluginInstanceImpl* instance =
271 HostGlobals::Get()->GetInstance(pp_instance);
272 if (!instance)
273 return NULL;
274 if (!instance->IsValidInstanceOf(module_))
275 return NULL;
276 return instance;
277 }
278
279 } // namespace content
280