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.
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
10 // In general, users of ppapi will also link in ppp_entrypoints.cc, which
11 // provides a simple default implementation of Module::Get().
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.
24 #include "ppapi/cpp/module.h"
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"
43 // PPP_InputEvent implementation -----------------------------------------------
45 PP_Bool
InputEvent_HandleEvent(PP_Instance pp_instance
, PP_Resource resource
) {
46 Module
* module_singleton
= Module::Get();
47 if (!module_singleton
)
49 Instance
* instance
= module_singleton
->InstanceForPPInstance(pp_instance
);
53 return PP_FromBool(instance
->HandleInputEvent(InputEvent(resource
)));
56 const PPP_InputEvent input_event_interface
= {
57 &InputEvent_HandleEvent
60 // PPP_Instance implementation -------------------------------------------------
62 PP_Bool
Instance_DidCreate(PP_Instance pp_instance
,
66 Module
* module_singleton
= Module::Get();
67 if (!module_singleton
)
70 Instance
* instance
= module_singleton
->CreateInstance(pp_instance
);
73 module_singleton
->current_instances_
[pp_instance
] = instance
;
74 return PP_FromBool(instance
->Init(argc
, argn
, argv
));
77 void Instance_DidDestroy(PP_Instance instance
) {
78 Module
* module_singleton
= Module::Get();
79 if (!module_singleton
)
81 Module::InstanceMap::iterator found
=
82 module_singleton
->current_instances_
.find(instance
);
83 if (found
== module_singleton
->current_instances_
.end())
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
);
92 void Instance_DidChangeView(PP_Instance pp_instance
,
93 PP_Resource view_resource
) {
94 Module
* module_singleton
= Module::Get();
95 if (!module_singleton
)
97 Instance
* instance
= module_singleton
->InstanceForPPInstance(pp_instance
);
100 instance
->DidChangeView(View(view_resource
));
103 void Instance_DidChangeFocus(PP_Instance pp_instance
, PP_Bool has_focus
) {
104 Module
* module_singleton
= Module::Get();
105 if (!module_singleton
)
107 Instance
* instance
= module_singleton
->InstanceForPPInstance(pp_instance
);
110 instance
->DidChangeFocus(PP_ToBool(has_focus
));
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
)
118 Instance
* instance
= module_singleton
->InstanceForPPInstance(pp_instance
);
121 return PP_FromBool(instance
->HandleDocumentLoad(URLLoader(pp_url_loader
)));
124 static PPP_Instance instance_interface
= {
126 &Instance_DidDestroy
,
127 &Instance_DidChangeView
,
128 &Instance_DidChangeFocus
,
129 &Instance_HandleDocumentLoad
132 // PPP_Messaging implementation ------------------------------------------------
134 void Messaging_HandleMessage(PP_Instance pp_instance
, PP_Var var
) {
135 Module
* module_singleton
= Module::Get();
136 if (!module_singleton
)
138 Instance
* instance
= module_singleton
->InstanceForPPInstance(pp_instance
);
141 instance
->HandleMessage(Var(PASS_REF
, var
));
144 static PPP_Messaging instance_messaging_interface
= {
145 &Messaging_HandleMessage
148 // Module ----------------------------------------------------------------------
150 Module::Module() : pp_module_(0), get_browser_interface_(NULL
), core_(NULL
) {
158 bool Module::Init() {
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
;
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
;
179 const void* Module::GetBrowserInterface(const char* interface_name
) {
180 return get_browser_interface_(interface_name
);
183 Instance
* Module::InstanceForPPInstance(PP_Instance instance
) {
184 InstanceMap::iterator found
= current_instances_
.find(instance
);
185 if (found
== current_instances_
.end())
187 return found
->second
;
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
);
201 additional_interfaces_
[interface_name
] = vtable
;
204 bool Module::InternalInit(PP_Module mod
,
205 PPB_GetInterface get_browser_interface
) {
207 get_browser_interface_
= get_browser_interface
;
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
));
214 core_
= new Core(core
);