Home | History | Annotate | Download | only in cpp
      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 // Note that the single accessor, Module::Get(), is not actually implemented
      6 // in this file.  This is an intentional hook that allows users of ppapi's
      7 // C++ wrapper objects to provide different semantics for how the singleton
      8 // object is accessed.
      9 //
     10 // In general, users of ppapi will also link in ppp_entrypoints.cc, which
     11 // provides a simple default implementation of Module::Get().
     12 //
     13 // A notable exception where the default ppp_entrypoints will not work is
     14 // when implementing "internal plugins" that are statically linked into the
     15 // browser. In this case, the process may actually have multiple Modules
     16 // loaded at once making a traditional "singleton" unworkable.  To get around
     17 // this, the users of ppapi need to get creative about how to properly
     18 // implement the Module::Get() so that ppapi's C++ wrappers can find the
     19 // right Module object.  One example solution is to use thread local storage
     20 // to change the Module* returned based on which thread is invoking the
     21 // function. Leaving Module::Get() unimplemented provides a hook for
     22 // implementing such behavior.
     23 
     24 #include "ppapi/cpp/module.h"
     25 
     26 #include <string.h>
     27 
     28 #include "ppapi/c/pp_instance.h"
     29 #include "ppapi/c/pp_var.h"
     30 #include "ppapi/c/ppp_input_event.h"
     31 #include "ppapi/c/ppp_instance.h"
     32 #include "ppapi/c/ppp_messaging.h"
     33 #include "ppapi/cpp/input_event.h"
     34 #include "ppapi/cpp/instance.h"
     35 #include "ppapi/cpp/rect.h"
     36 #include "ppapi/cpp/resource.h"
     37 #include "ppapi/cpp/url_loader.h"
     38 #include "ppapi/cpp/var.h"
     39 #include "ppapi/cpp/view.h"
     40 
     41 namespace pp {
     42 
     43 // PPP_InputEvent implementation -----------------------------------------------
     44 
     45 PP_Bool InputEvent_HandleEvent(PP_Instance pp_instance, PP_Resource resource) {
     46   Module* module_singleton = Module::Get();
     47   if (!module_singleton)
     48     return PP_FALSE;
     49   Instance* instance = module_singleton->InstanceForPPInstance(pp_instance);
     50   if (!instance)
     51     return PP_FALSE;
     52 
     53   return PP_FromBool(instance->HandleInputEvent(InputEvent(resource)));
     54 }
     55 
     56 const PPP_InputEvent input_event_interface = {
     57   &InputEvent_HandleEvent
     58 };
     59 
     60 // PPP_Instance implementation -------------------------------------------------
     61 
     62 PP_Bool Instance_DidCreate(PP_Instance pp_instance,
     63                            uint32_t argc,
     64                            const char* argn[],
     65                            const char* argv[]) {
     66   Module* module_singleton = Module::Get();
     67   if (!module_singleton)
     68     return PP_FALSE;
     69 
     70   Instance* instance = module_singleton->CreateInstance(pp_instance);
     71   if (!instance)
     72     return PP_FALSE;
     73   module_singleton->current_instances_[pp_instance] = instance;
     74   return PP_FromBool(instance->Init(argc, argn, argv));
     75 }
     76 
     77 void Instance_DidDestroy(PP_Instance instance) {
     78   Module* module_singleton = Module::Get();
     79   if (!module_singleton)
     80     return;
     81   Module::InstanceMap::iterator found =
     82       module_singleton->current_instances_.find(instance);
     83   if (found == module_singleton->current_instances_.end())
     84     return;
     85 
     86   // Remove it from the map before deleting to try to catch reentrancy.
     87   Instance* obj = found->second;
     88   module_singleton->current_instances_.erase(found);
     89   delete obj;
     90 }
     91 
     92 void Instance_DidChangeView(PP_Instance pp_instance,
     93                             PP_Resource view_resource) {
     94   Module* module_singleton = Module::Get();
     95   if (!module_singleton)
     96     return;
     97   Instance* instance = module_singleton->InstanceForPPInstance(pp_instance);
     98   if (!instance)
     99     return;
    100   instance->DidChangeView(View(view_resource));
    101 }
    102 
    103 void Instance_DidChangeFocus(PP_Instance pp_instance, PP_Bool has_focus) {
    104   Module* module_singleton = Module::Get();
    105   if (!module_singleton)
    106     return;
    107   Instance* instance = module_singleton->InstanceForPPInstance(pp_instance);
    108   if (!instance)
    109     return;
    110   instance->DidChangeFocus(PP_ToBool(has_focus));
    111 }
    112 
    113 PP_Bool Instance_HandleDocumentLoad(PP_Instance pp_instance,
    114                                     PP_Resource pp_url_loader) {
    115   Module* module_singleton = Module::Get();
    116   if (!module_singleton)
    117     return PP_FALSE;
    118   Instance* instance = module_singleton->InstanceForPPInstance(pp_instance);
    119   if (!instance)
    120     return PP_FALSE;
    121   return PP_FromBool(instance->HandleDocumentLoad(URLLoader(pp_url_loader)));
    122 }
    123 
    124 static PPP_Instance instance_interface = {
    125   &Instance_DidCreate,
    126   &Instance_DidDestroy,
    127   &Instance_DidChangeView,
    128   &Instance_DidChangeFocus,
    129   &Instance_HandleDocumentLoad
    130 };
    131 
    132 // PPP_Messaging implementation ------------------------------------------------
    133 
    134 void Messaging_HandleMessage(PP_Instance pp_instance, PP_Var var) {
    135   Module* module_singleton = Module::Get();
    136   if (!module_singleton)
    137     return;
    138   Instance* instance = module_singleton->InstanceForPPInstance(pp_instance);
    139   if (!instance)
    140     return;
    141   instance->HandleMessage(Var(PASS_REF, var));
    142 }
    143 
    144 static PPP_Messaging instance_messaging_interface = {
    145   &Messaging_HandleMessage
    146 };
    147 
    148 // Module ----------------------------------------------------------------------
    149 
    150 Module::Module() : pp_module_(0), get_browser_interface_(NULL), core_(NULL) {
    151 }
    152 
    153 Module::~Module() {
    154   delete core_;
    155   core_ = NULL;
    156 }
    157 
    158 bool Module::Init() {
    159   return true;
    160 }
    161 
    162 const void* Module::GetPluginInterface(const char* interface_name) {
    163   if (strcmp(interface_name, PPP_INPUT_EVENT_INTERFACE) == 0)
    164     return &input_event_interface;
    165   if (strcmp(interface_name, PPP_INSTANCE_INTERFACE) == 0)
    166     return &instance_interface;
    167   if (strcmp(interface_name, PPP_MESSAGING_INTERFACE) == 0)
    168     return &instance_messaging_interface;
    169 
    170   // Now see if anything was dynamically registered.
    171   InterfaceMap::const_iterator found = additional_interfaces_.find(
    172       std::string(interface_name));
    173   if (found != additional_interfaces_.end())
    174     return found->second;
    175 
    176   return NULL;
    177 }
    178 
    179 const void* Module::GetBrowserInterface(const char* interface_name) {
    180   return get_browser_interface_(interface_name);
    181 }
    182 
    183 Instance* Module::InstanceForPPInstance(PP_Instance instance) {
    184   InstanceMap::iterator found = current_instances_.find(instance);
    185   if (found == current_instances_.end())
    186     return NULL;
    187   return found->second;
    188 }
    189 
    190 void Module::AddPluginInterface(const std::string& interface_name,
    191                                 const void* vtable) {
    192   // Verify that we're not trying to register an interface that's already
    193   // handled, and if it is, that we're re-registering with the same vtable.
    194   // Calling GetPluginInterface rather than looking it up in the map allows
    195   // us to also catch "internal" ones in addition to just previously added ones.
    196   const void* existing_interface = GetPluginInterface(interface_name.c_str());
    197   if (existing_interface) {
    198     PP_DCHECK(vtable == existing_interface);
    199     return;
    200   }
    201   additional_interfaces_[interface_name] = vtable;
    202 }
    203 
    204 bool Module::InternalInit(PP_Module mod,
    205                           PPB_GetInterface get_browser_interface) {
    206   pp_module_ = mod;
    207   get_browser_interface_ = get_browser_interface;
    208 
    209   // Get the core interface which we require to run.
    210   const PPB_Core* core = reinterpret_cast<const PPB_Core*>(GetBrowserInterface(
    211       PPB_CORE_INTERFACE));
    212   if (!core)
    213     return false;
    214   core_ = new Core(core);
    215 
    216   return Init();
    217 }
    218 
    219 }  // namespace pp
    220