blob: 505991d6e58fd4151b94a2b53208cd2dcabe1343 [file] [log] [blame]
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001// 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
41namespace pp {
42
43// PPP_InputEvent implementation -----------------------------------------------
44
45PP_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
56const PPP_InputEvent input_event_interface = {
57 &InputEvent_HandleEvent
58};
59
60// PPP_Instance implementation -------------------------------------------------
61
62PP_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
77void 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
92void 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
103void 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
113PP_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
124static 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
134void 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
144static PPP_Messaging instance_messaging_interface = {
145 &Messaging_HandleMessage
146};
147
148// Module ----------------------------------------------------------------------
149
150Module::Module() : pp_module_(0), get_browser_interface_(NULL), core_(NULL) {
151}
152
153Module::~Module() {
154 delete core_;
155 core_ = NULL;
156}
157
158bool Module::Init() {
159 return true;
160}
161
162const 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
179const void* Module::GetBrowserInterface(const char* interface_name) {
180 return get_browser_interface_(interface_name);
181}
182
183Instance* 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
190void 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
204bool 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