|  | // 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 |