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