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*>(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