blob: 220609dcc03cdd5678b7cddda1e3f280690e8e37 [file] [log] [blame]
// Copyright (c) 2010 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 difference 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_instance.h"
#include "ppapi/cpp/common.h"
#include "ppapi/cpp/url_loader.h"
#include "ppapi/cpp/instance.h"
#include "ppapi/cpp/rect.h"
#include "ppapi/cpp/resource.h"
#include "ppapi/cpp/var.h"
namespace pp {
// 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 BoolToPPBool(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,
const PP_Rect* position,
const PP_Rect* clip) {
Module* module_singleton = Module::Get();
if (!module_singleton)
return;
Instance* instance = module_singleton->InstanceForPPInstance(pp_instance);
if (!instance)
return;
instance->DidChangeView(*position, *clip);
}
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(PPBoolToBool(has_focus));
}
PP_Bool Instance_HandleInputEvent(PP_Instance pp_instance,
const PP_InputEvent* event) {
Module* module_singleton = Module::Get();
if (!module_singleton)
return PP_FALSE;
Instance* instance = module_singleton->InstanceForPPInstance(pp_instance);
if (!instance)
return PP_FALSE;
return BoolToPPBool(instance->HandleInputEvent(*event));
}
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 BoolToPPBool(
instance->HandleDocumentLoad(URLLoader(pp_url_loader)));
}
PP_Var Instance_GetInstanceObject(PP_Instance pp_instance) {
Module* module_singleton = Module::Get();
if (!module_singleton)
return Var().Detach();
Instance* instance = module_singleton->InstanceForPPInstance(pp_instance);
if (!instance)
return Var().Detach();
return instance->GetInstanceObject().Detach();
}
static PPP_Instance instance_interface = {
&Instance_DidCreate,
&Instance_DidDestroy,
&Instance_DidChangeView,
&Instance_DidChangeFocus,
&Instance_HandleInputEvent,
&Instance_HandleDocumentLoad,
&Instance_GetInstanceObject
};
// 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_INSTANCE_INTERFACE) == 0)
return &instance_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