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