| // Copyright (c) 2012 The Chromium Authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style license that can be | |
| // found in the LICENSE file. | |
| // Note that the single accessor, Module::Get(), is not actually implemented | |
| // in this file. This is an intentional hook that allows users of ppapi's | |
| // C++ wrapper objects to provide different semantics for how the singleton | |
| // object is accessed. | |
| // | |
| // In general, users of ppapi will also link in ppp_entrypoints.cc, which | |
| // provides a simple default implementation of Module::Get(). | |
| // | |
| // A notable exception where the default ppp_entrypoints will not work is | |
| // when implementing "internal plugins" that are statically linked into the | |
| // browser. In this case, the process may actually have multiple Modules | |
| // loaded at once making a traditional "singleton" unworkable. To get around | |
| // this, the users of ppapi need to get creative about how to properly | |
| // implement the Module::Get() so that ppapi's C++ wrappers can find the | |
| // right Module object. One example solution is to use thread local storage | |
| // to change the Module* returned based on which thread is invoking the | |
| // function. Leaving Module::Get() unimplemented provides a hook for | |
| // implementing such behavior. | |
| #include "ppapi/cpp/module.h" | |
| #include <string.h> | |
| #include "ppapi/c/pp_instance.h" | |
| #include "ppapi/c/pp_var.h" | |
| #include "ppapi/c/ppp_input_event.h" | |
| #include "ppapi/c/ppp_instance.h" | |
| #include "ppapi/c/ppp_messaging.h" | |
| #include "ppapi/cpp/input_event.h" | |
| #include "ppapi/cpp/instance.h" | |
| #include "ppapi/cpp/rect.h" | |
| #include "ppapi/cpp/resource.h" | |
| #include "ppapi/cpp/url_loader.h" | |
| #include "ppapi/cpp/var.h" | |
| #include "ppapi/cpp/view.h" | |
| namespace pp { | |
| // PPP_InputEvent implementation ----------------------------------------------- | |
| PP_Bool InputEvent_HandleEvent(PP_Instance pp_instance, PP_Resource resource) { | |
| Module* module_singleton = Module::Get(); | |
| if (!module_singleton) | |
| return PP_FALSE; | |
| Instance* instance = module_singleton->InstanceForPPInstance(pp_instance); | |
| if (!instance) | |
| return PP_FALSE; | |
| return PP_FromBool(instance->HandleInputEvent(InputEvent(resource))); | |
| } | |
| const PPP_InputEvent input_event_interface = { | |
| &InputEvent_HandleEvent | |
| }; | |
| // PPP_Instance implementation ------------------------------------------------- | |
| PP_Bool Instance_DidCreate(PP_Instance pp_instance, | |
| uint32_t argc, | |
| const char* argn[], | |
| const char* argv[]) { | |
| Module* module_singleton = Module::Get(); | |
| if (!module_singleton) | |
| return PP_FALSE; | |
| Instance* instance = module_singleton->CreateInstance(pp_instance); | |
| if (!instance) | |
| return PP_FALSE; | |
| module_singleton->current_instances_[pp_instance] = instance; | |
| return PP_FromBool(instance->Init(argc, argn, argv)); | |
| } | |
| void Instance_DidDestroy(PP_Instance instance) { | |
| Module* module_singleton = Module::Get(); | |
| if (!module_singleton) | |
| return; | |
| Module::InstanceMap::iterator found = | |
| module_singleton->current_instances_.find(instance); | |
| if (found == module_singleton->current_instances_.end()) | |
| return; | |
| // Remove it from the map before deleting to try to catch reentrancy. | |
| Instance* obj = found->second; | |
| module_singleton->current_instances_.erase(found); | |
| delete obj; | |
| } | |
| void Instance_DidChangeView(PP_Instance pp_instance, | |
| PP_Resource view_resource) { | |
| Module* module_singleton = Module::Get(); | |
| if (!module_singleton) | |
| return; | |
| Instance* instance = module_singleton->InstanceForPPInstance(pp_instance); | |
| if (!instance) | |
| return; | |
| instance->DidChangeView(View(view_resource)); | |
| } | |
| void Instance_DidChangeFocus(PP_Instance pp_instance, PP_Bool has_focus) { | |
| Module* module_singleton = Module::Get(); | |
| if (!module_singleton) | |
| return; | |
| Instance* instance = module_singleton->InstanceForPPInstance(pp_instance); | |
| if (!instance) | |
| return; | |
| instance->DidChangeFocus(PP_ToBool(has_focus)); | |
| } | |
| PP_Bool Instance_HandleDocumentLoad(PP_Instance pp_instance, | |
| PP_Resource pp_url_loader) { | |
| Module* module_singleton = Module::Get(); | |
| if (!module_singleton) | |
| return PP_FALSE; | |
| Instance* instance = module_singleton->InstanceForPPInstance(pp_instance); | |
| if (!instance) | |
| return PP_FALSE; | |
| return PP_FromBool(instance->HandleDocumentLoad(URLLoader(pp_url_loader))); | |
| } | |
| static PPP_Instance instance_interface = { | |
| &Instance_DidCreate, | |
| &Instance_DidDestroy, | |
| &Instance_DidChangeView, | |
| &Instance_DidChangeFocus, | |
| &Instance_HandleDocumentLoad | |
| }; | |
| // PPP_Messaging implementation ------------------------------------------------ | |
| void Messaging_HandleMessage(PP_Instance pp_instance, PP_Var var) { | |
| Module* module_singleton = Module::Get(); | |
| if (!module_singleton) | |
| return; | |
| Instance* instance = module_singleton->InstanceForPPInstance(pp_instance); | |
| if (!instance) | |
| return; | |
| instance->HandleMessage(Var(PASS_REF, var)); | |
| } | |
| static PPP_Messaging instance_messaging_interface = { | |
| &Messaging_HandleMessage | |
| }; | |
| // Module ---------------------------------------------------------------------- | |
| Module::Module() : pp_module_(0), get_browser_interface_(NULL), core_(NULL) { | |
| } | |
| Module::~Module() { | |
| delete core_; | |
| core_ = NULL; | |
| } | |
| bool Module::Init() { | |
| return true; | |
| } | |
| const void* Module::GetPluginInterface(const char* interface_name) { | |
| if (strcmp(interface_name, PPP_INPUT_EVENT_INTERFACE) == 0) | |
| return &input_event_interface; | |
| if (strcmp(interface_name, PPP_INSTANCE_INTERFACE) == 0) | |
| return &instance_interface; | |
| if (strcmp(interface_name, PPP_MESSAGING_INTERFACE) == 0) | |
| return &instance_messaging_interface; | |
| // Now see if anything was dynamically registered. | |
| InterfaceMap::const_iterator found = additional_interfaces_.find( | |
| std::string(interface_name)); | |
| if (found != additional_interfaces_.end()) | |
| return found->second; | |
| return NULL; | |
| } | |
| const void* Module::GetBrowserInterface(const char* interface_name) { | |
| return get_browser_interface_(interface_name); | |
| } | |
| Instance* Module::InstanceForPPInstance(PP_Instance instance) { | |
| InstanceMap::iterator found = current_instances_.find(instance); | |
| if (found == current_instances_.end()) | |
| return NULL; | |
| return found->second; | |
| } | |
| void Module::AddPluginInterface(const std::string& interface_name, | |
| const void* vtable) { | |
| // Verify that we're not trying to register an interface that's already | |
| // handled, and if it is, that we're re-registering with the same vtable. | |
| // Calling GetPluginInterface rather than looking it up in the map allows | |
| // us to also catch "internal" ones in addition to just previously added ones. | |
| const void* existing_interface = GetPluginInterface(interface_name.c_str()); | |
| if (existing_interface) { | |
| PP_DCHECK(vtable == existing_interface); | |
| return; | |
| } | |
| additional_interfaces_[interface_name] = vtable; | |
| } | |
| bool Module::InternalInit(PP_Module mod, | |
| PPB_GetInterface get_browser_interface) { | |
| pp_module_ = mod; | |
| get_browser_interface_ = get_browser_interface; | |
| // Get the core interface which we require to run. | |
| const PPB_Core* core = reinterpret_cast<const PPB_Core*>( | |
| GetBrowserInterface(PPB_CORE_INTERFACE_1_0)); | |
| if (!core) | |
| return false; | |
| core_ = new Core(core); | |
| return Init(); | |
| } | |
| } // namespace pp |