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 "ppapi/proxy/ppp_instance_proxy.h"
6
7 #include <algorithm>
8
9 #include "base/bind.h"
10 #include "ppapi/c/pp_var.h"
11 #include "ppapi/c/ppb_core.h"
12 #include "ppapi/c/ppb_fullscreen.h"
13 #include "ppapi/c/ppp_instance.h"
14 #include "ppapi/proxy/host_dispatcher.h"
15 #include "ppapi/proxy/plugin_dispatcher.h"
16 #include "ppapi/proxy/plugin_globals.h"
17 #include "ppapi/proxy/plugin_proxy_delegate.h"
18 #include "ppapi/proxy/plugin_resource_tracker.h"
19 #include "ppapi/proxy/ppapi_messages.h"
20 #include "ppapi/proxy/url_loader_resource.h"
21 #include "ppapi/shared_impl/ppapi_globals.h"
22 #include "ppapi/shared_impl/ppb_view_shared.h"
23 #include "ppapi/shared_impl/resource_tracker.h"
24 #include "ppapi/shared_impl/scoped_pp_resource.h"
25 #include "ppapi/thunk/enter.h"
26 #include "ppapi/thunk/ppb_flash_fullscreen_api.h"
27 #include "ppapi/thunk/ppb_view_api.h"
28
29 namespace ppapi {
30 namespace proxy {
31
32 using thunk::EnterInstanceAPINoLock;
33 using thunk::EnterInstanceNoLock;
34 using thunk::EnterResourceNoLock;
35 using thunk::PPB_Flash_Fullscreen_API;
36 using thunk::PPB_Instance_API;
37 using thunk::PPB_View_API;
38
39 namespace {
40
41 #if !defined(OS_NACL)
DidCreate(PP_Instance instance,uint32_t argc,const char * argn[],const char * argv[])42 PP_Bool DidCreate(PP_Instance instance,
43 uint32_t argc,
44 const char* argn[],
45 const char* argv[]) {
46 std::vector<std::string> argn_vect;
47 std::vector<std::string> argv_vect;
48 for (uint32_t i = 0; i < argc; i++) {
49 argn_vect.push_back(std::string(argn[i]));
50 argv_vect.push_back(std::string(argv[i]));
51 }
52
53 PP_Bool result = PP_FALSE;
54 HostDispatcher::GetForInstance(instance)->Send(
55 new PpapiMsg_PPPInstance_DidCreate(API_ID_PPP_INSTANCE, instance,
56 argn_vect, argv_vect, &result));
57 return result;
58 }
59
DidDestroy(PP_Instance instance)60 void DidDestroy(PP_Instance instance) {
61 HostDispatcher::GetForInstance(instance)->Send(
62 new PpapiMsg_PPPInstance_DidDestroy(API_ID_PPP_INSTANCE, instance));
63 }
64
DidChangeView(PP_Instance instance,PP_Resource view_resource)65 void DidChangeView(PP_Instance instance, PP_Resource view_resource) {
66 HostDispatcher* dispatcher = HostDispatcher::GetForInstance(instance);
67
68 EnterResourceNoLock<PPB_View_API> enter_view(view_resource, false);
69 if (enter_view.failed()) {
70 NOTREACHED();
71 return;
72 }
73
74 PP_Bool flash_fullscreen = PP_FALSE;
75 EnterInstanceNoLock enter_instance(instance);
76 if (!enter_instance.failed())
77 flash_fullscreen = enter_instance.functions()->FlashIsFullscreen(instance);
78 dispatcher->Send(new PpapiMsg_PPPInstance_DidChangeView(
79 API_ID_PPP_INSTANCE, instance, enter_view.object()->GetData(),
80 flash_fullscreen));
81 }
82
DidChangeFocus(PP_Instance instance,PP_Bool has_focus)83 void DidChangeFocus(PP_Instance instance, PP_Bool has_focus) {
84 HostDispatcher::GetForInstance(instance)->Send(
85 new PpapiMsg_PPPInstance_DidChangeFocus(API_ID_PPP_INSTANCE,
86 instance, has_focus));
87 }
88
HandleDocumentLoad(PP_Instance instance,PP_Resource url_loader)89 PP_Bool HandleDocumentLoad(PP_Instance instance, PP_Resource url_loader) {
90 // This should never get called. Out-of-process document loads are handled
91 // specially.
92 NOTREACHED();
93 return PP_FALSE;
94 }
95
96 static const PPP_Instance_1_1 instance_interface = {
97 &DidCreate,
98 &DidDestroy,
99 &DidChangeView,
100 &DidChangeFocus,
101 &HandleDocumentLoad
102 };
103 #endif // !defined(OS_NACL)
104
105 } // namespace
106
PPP_Instance_Proxy(Dispatcher * dispatcher)107 PPP_Instance_Proxy::PPP_Instance_Proxy(Dispatcher* dispatcher)
108 : InterfaceProxy(dispatcher) {
109 if (dispatcher->IsPlugin()) {
110 // The PPP_Instance proxy works by always proxying the 1.1 version of the
111 // interface, and then detecting in the plugin process which one to use.
112 // PPP_Instance_Combined handles dispatching to whatever interface is
113 // supported.
114 //
115 // This means that if the plugin supports either 1.0 or 1.1 version of
116 // the interface, we want to say it supports the 1.1 version since we'll
117 // convert it here. This magic conversion code is hardcoded into
118 // PluginDispatcher::OnMsgSupportsInterface.
119 combined_interface_.reset(PPP_Instance_Combined::Create(
120 base::Bind(dispatcher->local_get_interface())));
121 }
122 }
123
~PPP_Instance_Proxy()124 PPP_Instance_Proxy::~PPP_Instance_Proxy() {
125 }
126
127 #if !defined(OS_NACL)
128 // static
GetInstanceInterface()129 const PPP_Instance* PPP_Instance_Proxy::GetInstanceInterface() {
130 return &instance_interface;
131 }
132 #endif // !defined(OS_NACL)
133
OnMessageReceived(const IPC::Message & msg)134 bool PPP_Instance_Proxy::OnMessageReceived(const IPC::Message& msg) {
135 if (!dispatcher()->IsPlugin())
136 return false;
137
138 bool handled = true;
139 IPC_BEGIN_MESSAGE_MAP(PPP_Instance_Proxy, msg)
140 IPC_MESSAGE_HANDLER(PpapiMsg_PPPInstance_DidCreate,
141 OnPluginMsgDidCreate)
142 IPC_MESSAGE_HANDLER(PpapiMsg_PPPInstance_DidDestroy,
143 OnPluginMsgDidDestroy)
144 IPC_MESSAGE_HANDLER(PpapiMsg_PPPInstance_DidChangeView,
145 OnPluginMsgDidChangeView)
146 IPC_MESSAGE_HANDLER(PpapiMsg_PPPInstance_DidChangeFocus,
147 OnPluginMsgDidChangeFocus)
148 IPC_MESSAGE_HANDLER(PpapiMsg_PPPInstance_HandleDocumentLoad,
149 OnPluginMsgHandleDocumentLoad)
150 IPC_MESSAGE_UNHANDLED(handled = false)
151 IPC_END_MESSAGE_MAP()
152 return handled;
153 }
154
OnPluginMsgDidCreate(PP_Instance instance,const std::vector<std::string> & argn,const std::vector<std::string> & argv,PP_Bool * result)155 void PPP_Instance_Proxy::OnPluginMsgDidCreate(
156 PP_Instance instance,
157 const std::vector<std::string>& argn,
158 const std::vector<std::string>& argv,
159 PP_Bool* result) {
160 *result = PP_FALSE;
161 if (argn.size() != argv.size())
162 return;
163
164 // Set up the routing associating this new instance with the dispatcher we
165 // just got the message from. This must be done before calling into the
166 // plugin so it can in turn call PPAPI functions.
167 PluginDispatcher* plugin_dispatcher =
168 static_cast<PluginDispatcher*>(dispatcher());
169 plugin_dispatcher->DidCreateInstance(instance);
170 PpapiGlobals::Get()->GetResourceTracker()->DidCreateInstance(instance);
171
172 // Make sure the arrays always have at least one element so we can take the
173 // address below.
174 std::vector<const char*> argn_array(
175 std::max(static_cast<size_t>(1), argn.size()));
176 std::vector<const char*> argv_array(
177 std::max(static_cast<size_t>(1), argn.size()));
178 for (size_t i = 0; i < argn.size(); i++) {
179 argn_array[i] = argn[i].c_str();
180 argv_array[i] = argv[i].c_str();
181 }
182
183 DCHECK(combined_interface_.get());
184 *result = combined_interface_->DidCreate(instance,
185 static_cast<uint32_t>(argn.size()),
186 &argn_array[0], &argv_array[0]);
187 }
188
OnPluginMsgDidDestroy(PP_Instance instance)189 void PPP_Instance_Proxy::OnPluginMsgDidDestroy(PP_Instance instance) {
190 combined_interface_->DidDestroy(instance);
191
192 PpapiGlobals* globals = PpapiGlobals::Get();
193 globals->GetResourceTracker()->DidDeleteInstance(instance);
194 globals->GetVarTracker()->DidDeleteInstance(instance);
195
196 static_cast<PluginDispatcher*>(dispatcher())->DidDestroyInstance(instance);
197 }
198
OnPluginMsgDidChangeView(PP_Instance instance,const ViewData & new_data,PP_Bool flash_fullscreen)199 void PPP_Instance_Proxy::OnPluginMsgDidChangeView(
200 PP_Instance instance,
201 const ViewData& new_data,
202 PP_Bool flash_fullscreen) {
203 PluginDispatcher* dispatcher = PluginDispatcher::GetForInstance(instance);
204 if (!dispatcher)
205 return;
206 InstanceData* data = dispatcher->GetInstanceData(instance);
207 if (!data)
208 return;
209 data->view = new_data;
210
211 #if !defined(OS_NACL)
212 EnterInstanceAPINoLock<PPB_Flash_Fullscreen_API> enter(instance);
213 if (!enter.failed())
214 enter.functions()->SetLocalIsFullscreen(instance, flash_fullscreen);
215 #endif // !defined(OS_NACL)
216
217 ScopedPPResource resource(
218 ScopedPPResource::PassRef(),
219 (new PPB_View_Shared(OBJECT_IS_PROXY,
220 instance, new_data))->GetReference());
221
222 combined_interface_->DidChangeView(instance, resource,
223 &new_data.rect,
224 &new_data.clip_rect);
225 }
226
OnPluginMsgDidChangeFocus(PP_Instance instance,PP_Bool has_focus)227 void PPP_Instance_Proxy::OnPluginMsgDidChangeFocus(PP_Instance instance,
228 PP_Bool has_focus) {
229 combined_interface_->DidChangeFocus(instance, has_focus);
230 }
231
OnPluginMsgHandleDocumentLoad(PP_Instance instance,int pending_loader_host_id,const URLResponseInfoData & data)232 void PPP_Instance_Proxy::OnPluginMsgHandleDocumentLoad(
233 PP_Instance instance,
234 int pending_loader_host_id,
235 const URLResponseInfoData& data) {
236 PluginDispatcher* dispatcher = PluginDispatcher::GetForInstance(instance);
237 if (!dispatcher)
238 return;
239 Connection connection(PluginGlobals::Get()->GetBrowserSender(),
240 dispatcher);
241
242 scoped_refptr<URLLoaderResource> loader_resource(
243 new URLLoaderResource(connection, instance,
244 pending_loader_host_id, data));
245
246 PP_Resource loader_pp_resource = loader_resource->GetReference();
247 if (!combined_interface_->HandleDocumentLoad(instance, loader_pp_resource))
248 loader_resource->Close();
249 // We don't pass a ref into the plugin, if it wants one, it will have taken
250 // an additional one.
251 PpapiGlobals::Get()->GetResourceTracker()->ReleaseResource(
252 loader_pp_resource);
253 }
254
255 } // namespace proxy
256 } // namespace ppapi
257