ppp_instance_proxy.cc revision 2a99a7e74a7f215066514fe81d2bfa6639d9eddd
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_resource_tracker.h"
17#include "ppapi/proxy/ppapi_messages.h"
18#include "ppapi/proxy/ppb_url_loader_proxy.h"
19#include "ppapi/shared_impl/ppapi_globals.h"
20#include "ppapi/shared_impl/ppb_view_shared.h"
21#include "ppapi/shared_impl/scoped_pp_resource.h"
22#include "ppapi/thunk/enter.h"
23#include "ppapi/thunk/ppb_flash_fullscreen_api.h"
24#include "ppapi/thunk/ppb_view_api.h"
25
26namespace ppapi {
27namespace proxy {
28
29using thunk::EnterInstanceAPINoLock;
30using thunk::EnterInstanceNoLock;
31using thunk::EnterResourceNoLock;
32using thunk::PPB_Flash_Fullscreen_API;
33using thunk::PPB_Instance_API;
34using thunk::PPB_View_API;
35
36namespace {
37
38#if !defined(OS_NACL)
39PP_Bool DidCreate(PP_Instance instance,
40                  uint32_t argc,
41                  const char* argn[],
42                  const char* argv[]) {
43  std::vector<std::string> argn_vect;
44  std::vector<std::string> argv_vect;
45  for (uint32_t i = 0; i < argc; i++) {
46    argn_vect.push_back(std::string(argn[i]));
47    argv_vect.push_back(std::string(argv[i]));
48  }
49
50  PP_Bool result = PP_FALSE;
51  HostDispatcher::GetForInstance(instance)->Send(
52      new PpapiMsg_PPPInstance_DidCreate(API_ID_PPP_INSTANCE, instance,
53                                         argn_vect, argv_vect, &result));
54  return result;
55}
56
57void DidDestroy(PP_Instance instance) {
58  HostDispatcher::GetForInstance(instance)->Send(
59      new PpapiMsg_PPPInstance_DidDestroy(API_ID_PPP_INSTANCE, instance));
60}
61
62void DidChangeView(PP_Instance instance, PP_Resource view_resource) {
63  HostDispatcher* dispatcher = HostDispatcher::GetForInstance(instance);
64
65  EnterResourceNoLock<PPB_View_API> enter_view(view_resource, false);
66  if (enter_view.failed()) {
67    NOTREACHED();
68    return;
69  }
70
71  PP_Bool flash_fullscreen = PP_FALSE;
72  EnterInstanceNoLock enter_instance(instance);
73  if (!enter_instance.failed())
74    flash_fullscreen = enter_instance.functions()->FlashIsFullscreen(instance);
75  dispatcher->Send(new PpapiMsg_PPPInstance_DidChangeView(
76      API_ID_PPP_INSTANCE, instance, enter_view.object()->GetData(),
77      flash_fullscreen));
78}
79
80void DidChangeFocus(PP_Instance instance, PP_Bool has_focus) {
81  HostDispatcher::GetForInstance(instance)->Send(
82      new PpapiMsg_PPPInstance_DidChangeFocus(API_ID_PPP_INSTANCE,
83                                              instance, has_focus));
84}
85
86PP_Bool HandleDocumentLoad(PP_Instance instance,
87                           PP_Resource url_loader) {
88  PP_Bool result = PP_FALSE;
89  HostDispatcher* dispatcher = HostDispatcher::GetForInstance(instance);
90
91  // Set up the URLLoader for proxying.
92
93  PPB_URLLoader_Proxy* url_loader_proxy = static_cast<PPB_URLLoader_Proxy*>(
94      dispatcher->GetInterfaceProxy(API_ID_PPB_URL_LOADER));
95  url_loader_proxy->PrepareURLLoaderForSendingToPlugin(url_loader);
96
97  // PluginResourceTracker in the plugin process assumes that resources that it
98  // tracks have been addrefed on behalf of the plugin at the renderer side. So
99  // we explicitly do it for |url_loader| here.
100  //
101  // Please also see comments in PPP_Instance_Proxy::OnMsgHandleDocumentLoad()
102  // about releasing of this extra reference.
103  const PPB_Core* core = reinterpret_cast<const PPB_Core*>(
104      dispatcher->local_get_interface()(PPB_CORE_INTERFACE));
105  if (!core) {
106    NOTREACHED();
107    return PP_FALSE;
108  }
109  core->AddRefResource(url_loader);
110
111  HostResource serialized_loader;
112  serialized_loader.SetHostResource(instance, url_loader);
113  dispatcher->Send(new PpapiMsg_PPPInstance_HandleDocumentLoad(
114      API_ID_PPP_INSTANCE, instance, serialized_loader, &result));
115  return result;
116}
117
118static const PPP_Instance_1_1 instance_interface = {
119  &DidCreate,
120  &DidDestroy,
121  &DidChangeView,
122  &DidChangeFocus,
123  &HandleDocumentLoad
124};
125#endif  // !defined(OS_NACL)
126
127}  // namespace
128
129PPP_Instance_Proxy::PPP_Instance_Proxy(Dispatcher* dispatcher)
130    : InterfaceProxy(dispatcher) {
131  if (dispatcher->IsPlugin()) {
132    // The PPP_Instance proxy works by always proxying the 1.1 version of the
133    // interface, and then detecting in the plugin process which one to use.
134    // PPP_Instance_Combined handles dispatching to whatever interface is
135    // supported.
136    //
137    // This means that if the plugin supports either 1.0 or 1.1 version of
138    // the interface, we want to say it supports the 1.1 version since we'll
139    // convert it here. This magic conversion code is hardcoded into
140    // PluginDispatcher::OnMsgSupportsInterface.
141    combined_interface_.reset(PPP_Instance_Combined::Create(
142        base::Bind(dispatcher->local_get_interface())));
143  }
144}
145
146PPP_Instance_Proxy::~PPP_Instance_Proxy() {
147}
148
149#if !defined(OS_NACL)
150// static
151const PPP_Instance* PPP_Instance_Proxy::GetInstanceInterface() {
152  return &instance_interface;
153}
154#endif  // !defined(OS_NACL)
155
156bool PPP_Instance_Proxy::OnMessageReceived(const IPC::Message& msg) {
157  if (!dispatcher()->IsPlugin())
158    return false;
159
160  bool handled = true;
161  IPC_BEGIN_MESSAGE_MAP(PPP_Instance_Proxy, msg)
162    IPC_MESSAGE_HANDLER(PpapiMsg_PPPInstance_DidCreate,
163                        OnPluginMsgDidCreate)
164    IPC_MESSAGE_HANDLER(PpapiMsg_PPPInstance_DidDestroy,
165                        OnPluginMsgDidDestroy)
166    IPC_MESSAGE_HANDLER(PpapiMsg_PPPInstance_DidChangeView,
167                        OnPluginMsgDidChangeView)
168    IPC_MESSAGE_HANDLER(PpapiMsg_PPPInstance_DidChangeFocus,
169                        OnPluginMsgDidChangeFocus)
170    IPC_MESSAGE_HANDLER(PpapiMsg_PPPInstance_HandleDocumentLoad,
171                        OnPluginMsgHandleDocumentLoad)
172    IPC_MESSAGE_UNHANDLED(handled = false)
173  IPC_END_MESSAGE_MAP()
174  return handled;
175}
176
177void PPP_Instance_Proxy::OnPluginMsgDidCreate(
178    PP_Instance instance,
179    const std::vector<std::string>& argn,
180    const std::vector<std::string>& argv,
181    PP_Bool* result) {
182  *result = PP_FALSE;
183  if (argn.size() != argv.size())
184    return;
185
186  // Set up the routing associating this new instance with the dispatcher we
187  // just got the message from. This must be done before calling into the
188  // plugin so it can in turn call PPAPI functions.
189  PluginDispatcher* plugin_dispatcher =
190      static_cast<PluginDispatcher*>(dispatcher());
191  plugin_dispatcher->DidCreateInstance(instance);
192  PpapiGlobals::Get()->GetResourceTracker()->DidCreateInstance(instance);
193
194  // Make sure the arrays always have at least one element so we can take the
195  // address below.
196  std::vector<const char*> argn_array(
197      std::max(static_cast<size_t>(1), argn.size()));
198  std::vector<const char*> argv_array(
199      std::max(static_cast<size_t>(1), argn.size()));
200  for (size_t i = 0; i < argn.size(); i++) {
201    argn_array[i] = argn[i].c_str();
202    argv_array[i] = argv[i].c_str();
203  }
204
205  DCHECK(combined_interface_.get());
206  *result = combined_interface_->DidCreate(instance,
207                                           static_cast<uint32_t>(argn.size()),
208                                           &argn_array[0], &argv_array[0]);
209}
210
211void PPP_Instance_Proxy::OnPluginMsgDidDestroy(PP_Instance instance) {
212  combined_interface_->DidDestroy(instance);
213
214  PpapiGlobals* globals = PpapiGlobals::Get();
215  globals->GetResourceTracker()->DidDeleteInstance(instance);
216  globals->GetVarTracker()->DidDeleteInstance(instance);
217
218  static_cast<PluginDispatcher*>(dispatcher())->DidDestroyInstance(instance);
219}
220
221void PPP_Instance_Proxy::OnPluginMsgDidChangeView(
222    PP_Instance instance,
223    const ViewData& new_data,
224    PP_Bool flash_fullscreen) {
225  PluginDispatcher* dispatcher = PluginDispatcher::GetForInstance(instance);
226  if (!dispatcher)
227    return;
228  InstanceData* data = dispatcher->GetInstanceData(instance);
229  if (!data)
230    return;
231  data->view = new_data;
232
233#if !defined(OS_NACL)
234  EnterInstanceAPINoLock<PPB_Flash_Fullscreen_API> enter(instance);
235  if (!enter.failed())
236    enter.functions()->SetLocalIsFullscreen(instance, flash_fullscreen);
237#endif  // !defined(OS_NACL)
238
239  ScopedPPResource resource(
240      ScopedPPResource::PassRef(),
241      (new PPB_View_Shared(OBJECT_IS_PROXY,
242                           instance, new_data))->GetReference());
243
244  combined_interface_->DidChangeView(instance, resource,
245                                     &new_data.rect,
246                                     &new_data.clip_rect);
247}
248
249void PPP_Instance_Proxy::OnPluginMsgDidChangeFocus(PP_Instance instance,
250                                                   PP_Bool has_focus) {
251  combined_interface_->DidChangeFocus(instance, has_focus);
252}
253
254void PPP_Instance_Proxy::OnPluginMsgHandleDocumentLoad(
255    PP_Instance instance,
256    const HostResource& url_loader,
257    PP_Bool* result) {
258  PP_Resource plugin_loader =
259      PPB_URLLoader_Proxy::TrackPluginResource(url_loader);
260  *result = combined_interface_->HandleDocumentLoad(instance, plugin_loader);
261
262  // This balances the one reference that TrackPluginResource() initialized it
263  // with. The plugin will normally take an additional reference which will keep
264  // the resource alive in the plugin (and the one reference in the renderer
265  // representing all plugin references).
266  // Once all references at the plugin side are released, the renderer side will
267  // be notified and release the reference added in HandleDocumentLoad() above.
268  PpapiGlobals::Get()->GetResourceTracker()->ReleaseResource(plugin_loader);
269}
270
271}  // namespace proxy
272}  // namespace ppapi
273