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 
InputEvent_HandleEvent(PP_Instance pp_instance,PP_Resource resource)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 
Instance_DidCreate(PP_Instance pp_instance,uint32_t argc,const char * argn[],const char * argv[])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 
Instance_DidDestroy(PP_Instance instance)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 
Instance_DidChangeView(PP_Instance pp_instance,PP_Resource view_resource)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 
Instance_DidChangeFocus(PP_Instance pp_instance,PP_Bool has_focus)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 
Instance_HandleDocumentLoad(PP_Instance pp_instance,PP_Resource pp_url_loader)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 
Messaging_HandleMessage(PP_Instance pp_instance,PP_Var var)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 
Module()150 Module::Module() : pp_module_(0), get_browser_interface_(NULL), core_(NULL) {
151 }
152 
~Module()153 Module::~Module() {
154   delete core_;
155   core_ = NULL;
156 }
157 
Init()158 bool Module::Init() {
159   return true;
160 }
161 
GetPluginInterface(const char * interface_name)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 
GetBrowserInterface(const char * interface_name)179 const void* Module::GetBrowserInterface(const char* interface_name) {
180   return get_browser_interface_(interface_name);
181 }
182 
InstanceForPPInstance(PP_Instance instance)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 
AddPluginInterface(const std::string & interface_name,const void * vtable)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 
InternalInit(PP_Module mod,PPB_GetInterface get_browser_interface)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*>(
211       GetBrowserInterface(PPB_CORE_INTERFACE_1_0));
212   if (!core)
213     return false;
214   core_ = new Core(core);
215 
216   return Init();
217 }
218 
219 }  // namespace pp
220