Home | History | Annotate | Download | only in proxy
      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)
     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 
     60 void DidDestroy(PP_Instance instance) {
     61   HostDispatcher::GetForInstance(instance)->Send(
     62       new PpapiMsg_PPPInstance_DidDestroy(API_ID_PPP_INSTANCE, instance));
     63 }
     64 
     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 
     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 
     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 
    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 
    124 PPP_Instance_Proxy::~PPP_Instance_Proxy() {
    125 }
    126 
    127 #if !defined(OS_NACL)
    128 // static
    129 const PPP_Instance* PPP_Instance_Proxy::GetInstanceInterface() {
    130   return &instance_interface;
    131 }
    132 #endif  // !defined(OS_NACL)
    133 
    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 
    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 
    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 
    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 
    227 void PPP_Instance_Proxy::OnPluginMsgDidChangeFocus(PP_Instance instance,
    228                                                    PP_Bool has_focus) {
    229   combined_interface_->DidChangeFocus(instance, has_focus);
    230 }
    231 
    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