| // 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)); |
| if (!core) |
| return false; |
| core_ = new Core(core); |
| |
| return Init(); |
| } |
| |
| } // namespace pp |