#include "ppapi/proxy/plugin_var_tracker.h"
#include "base/memory/ref_counted.h"
#include "base/memory/singleton.h"
#include "ppapi/c/dev/ppp_class_deprecated.h"
#include "ppapi/c/ppb_var.h"
#include "ppapi/proxy/plugin_array_buffer_var.h"
#include "ppapi/proxy/plugin_dispatcher.h"
#include "ppapi/proxy/ppapi_messages.h"
#include "ppapi/proxy/proxy_object_var.h"
#include "ppapi/shared_impl/api_id.h"
#include "ppapi/shared_impl/var.h"
namespace ppapi {
namespace proxy {
PluginVarTracker::HostVar::HostVar(PluginDispatcher* d, int32 i)
: dispatcher(d),
host_object_id(i) {
}
bool PluginVarTracker::HostVar::operator<(const HostVar& other) const {
if (dispatcher < other.dispatcher)
return true;
if (other.dispatcher < dispatcher)
return false;
return host_object_id < other.host_object_id;
}
PluginVarTracker::PluginVarTracker() {
}
PluginVarTracker::~PluginVarTracker() {
}
PP_Var PluginVarTracker::ReceiveObjectPassRef(const PP_Var& host_var,
PluginDispatcher* dispatcher) {
DCHECK(CalledOnValidThread());
DCHECK(host_var.type == PP_VARTYPE_OBJECT);
scoped_refptr<ProxyObjectVar> object(
FindOrMakePluginVarFromHostVar(host_var, dispatcher));
PP_Var ret = GetOrCreateObjectVarID(object.get());
VarInfo& info = GetLiveVar(ret)->second;
if (info.ref_count > 0) {
SendReleaseObjectMsg(*object);
}
info.ref_count++;
return ret;
}
PP_Var PluginVarTracker::TrackObjectWithNoReference(
const PP_Var& host_var,
PluginDispatcher* dispatcher) {
DCHECK(CalledOnValidThread());
DCHECK(host_var.type == PP_VARTYPE_OBJECT);
scoped_refptr<ProxyObjectVar> object(
FindOrMakePluginVarFromHostVar(host_var, dispatcher));
PP_Var ret = GetOrCreateObjectVarID(object.get());
VarInfo& info = GetLiveVar(ret)->second;
info.track_with_no_reference_count++;
return ret;
}
void PluginVarTracker::StopTrackingObjectWithNoReference(
const PP_Var& plugin_var) {
DCHECK(CalledOnValidThread());
DCHECK(plugin_var.type == PP_VARTYPE_OBJECT);
VarMap::iterator found = GetLiveVar(plugin_var);
if (found == live_vars_.end()) {
NOTREACHED();
return;
}
DCHECK(found->second.track_with_no_reference_count > 0);
found->second.track_with_no_reference_count--;
DeleteObjectInfoIfNecessary(found);
}
PP_Var PluginVarTracker::GetHostObject(const PP_Var& plugin_object) const {
DCHECK(CalledOnValidThread());
if (plugin_object.type != PP_VARTYPE_OBJECT) {
NOTREACHED();
return PP_MakeUndefined();
}
Var* var = GetVar(plugin_object);
ProxyObjectVar* object = var->AsProxyObjectVar();
if (!object) {
NOTREACHED();
return PP_MakeUndefined();
}
PP_Var ret = { PP_VARTYPE_OBJECT };
ret.value.as_id = object->host_var_id();
return ret;
}
PluginDispatcher* PluginVarTracker::DispatcherForPluginObject(
const PP_Var& plugin_object) const {
DCHECK(CalledOnValidThread());
if (plugin_object.type != PP_VARTYPE_OBJECT)
return NULL;
VarMap::const_iterator found = GetLiveVar(plugin_object);
if (found == live_vars_.end())
return NULL;
ProxyObjectVar* object = found->second.var->AsProxyObjectVar();
if (!object)
return NULL;
return object->dispatcher();
}
void PluginVarTracker::ReleaseHostObject(PluginDispatcher* dispatcher,
const PP_Var& host_object) {
DCHECK(CalledOnValidThread());
DCHECK(host_object.type == PP_VARTYPE_OBJECT);
HostVarToPluginVarMap::iterator found = host_var_to_plugin_var_.find(
HostVar(dispatcher, static_cast<int32>(host_object.value.as_id)));
if (found == host_var_to_plugin_var_.end()) {
NOTREACHED();
return;
}
ReleaseVar(found->second);
}
void PluginVarTracker::DidDeleteInstance(PP_Instance instance) {
std::vector<void*> user_data_to_delete;
for (UserDataToPluginImplementedVarMap::const_iterator i =
user_data_to_plugin_.begin();
i != user_data_to_plugin_.end();
++i) {
if (i->second.instance == instance)
user_data_to_delete.push_back(i->first);
}
for (size_t i = 0; i < user_data_to_delete.size(); i++) {
UserDataToPluginImplementedVarMap::iterator found =
user_data_to_plugin_.find(user_data_to_delete[i]);
if (found == user_data_to_plugin_.end())
continue;
if (!found->second.plugin_object_id) {
found->second.ppp_class->Deallocate(found->first);
user_data_to_plugin_.erase(found);
} else {
found->second.instance = 0;
}
}
}
ArrayBufferVar* PluginVarTracker::CreateArrayBuffer(uint32 size_in_bytes) {
return new PluginArrayBufferVar(size_in_bytes);
}
void PluginVarTracker::PluginImplementedObjectCreated(
PP_Instance instance,
const PP_Var& created_var,
const PPP_Class_Deprecated* ppp_class,
void* ppp_class_data) {
PluginImplementedVar p;
p.ppp_class = ppp_class;
p.instance = instance;
p.plugin_object_id = created_var.value.as_id;
user_data_to_plugin_[ppp_class_data] = p;
ProxyObjectVar* object = GetVar(created_var)->AsProxyObjectVar();
object->set_user_data(ppp_class_data);
}
void PluginVarTracker::PluginImplementedObjectDestroyed(void* user_data) {
UserDataToPluginImplementedVarMap::iterator found =
user_data_to_plugin_.find(user_data);
if (found == user_data_to_plugin_.end()) {
NOTREACHED();
return;
}
user_data_to_plugin_.erase(found);
}
bool PluginVarTracker::IsPluginImplementedObjectAlive(void* user_data) {
return user_data_to_plugin_.find(user_data) != user_data_to_plugin_.end();
}
bool PluginVarTracker::ValidatePluginObjectCall(
const PPP_Class_Deprecated* ppp_class,
void* user_data) {
UserDataToPluginImplementedVarMap::iterator found =
user_data_to_plugin_.find(user_data);
if (found == user_data_to_plugin_.end())
return false;
return found->second.ppp_class == ppp_class;
}
int32 PluginVarTracker::AddVarInternal(Var* var, AddVarRefMode mode) {
int32 new_id = VarTracker::AddVarInternal(var, mode);
ProxyObjectVar* proxy_object = var->AsProxyObjectVar();
if (proxy_object) {
HostVar host_var(proxy_object->dispatcher(), proxy_object->host_var_id());
DCHECK(host_var_to_plugin_var_.find(host_var) ==
host_var_to_plugin_var_.end());
host_var_to_plugin_var_[host_var] = new_id;
}
return new_id;
}
void PluginVarTracker::TrackedObjectGettingOneRef(VarMap::const_iterator iter) {
ProxyObjectVar* object = iter->second.var->AsProxyObjectVar();
if (!object) {
NOTREACHED();
return;
}
DCHECK(iter->second.ref_count == 0);
SendAddRefObjectMsg(*object);
}
void PluginVarTracker::ObjectGettingZeroRef(VarMap::iterator iter) {
ProxyObjectVar* object = iter->second.var->AsProxyObjectVar();
if (!object) {
NOTREACHED();
return;
}
DCHECK(iter->second.ref_count == 0);
SendReleaseObjectMsg(*object);
UserDataToPluginImplementedVarMap::iterator found =
user_data_to_plugin_.find(object->user_data());
if (found != user_data_to_plugin_.end()) {
if (found->second.instance == 0) {
found->second.ppp_class->Deallocate(found->first);
user_data_to_plugin_.erase(found);
} else {
found->second.plugin_object_id = 0;
}
}
VarTracker::ObjectGettingZeroRef(iter);
}
bool PluginVarTracker::DeleteObjectInfoIfNecessary(VarMap::iterator iter) {
ProxyObjectVar* object = iter->second.var->AsProxyObjectVar();
HostVar host_var(object->dispatcher(), object->host_var_id());
if (!VarTracker::DeleteObjectInfoIfNecessary(iter))
return false;
DCHECK(host_var_to_plugin_var_.find(host_var) !=
host_var_to_plugin_var_.end());
host_var_to_plugin_var_.erase(host_var);
return true;
}
PP_Var PluginVarTracker::GetOrCreateObjectVarID(ProxyObjectVar* object) {
int32 var_id = object->GetExistingVarID();
if (!var_id) {
var_id = AddVarInternal(object, ADD_VAR_CREATE_WITH_NO_REFERENCE);
object->AssignVarID(var_id);
}
PP_Var ret = { PP_VARTYPE_OBJECT };
ret.value.as_id = var_id;
return ret;
}
void PluginVarTracker::SendAddRefObjectMsg(
const ProxyObjectVar& proxy_object) {
int unused;
proxy_object.dispatcher()->Send(new PpapiHostMsg_PPBVar_AddRefObject(
API_ID_PPB_VAR_DEPRECATED, proxy_object.host_var_id(), &unused));
}
void PluginVarTracker::SendReleaseObjectMsg(
const ProxyObjectVar& proxy_object) {
proxy_object.dispatcher()->Send(new PpapiHostMsg_PPBVar_ReleaseObject(
API_ID_PPB_VAR_DEPRECATED, proxy_object.host_var_id()));
}
scoped_refptr<ProxyObjectVar> PluginVarTracker::FindOrMakePluginVarFromHostVar(
const PP_Var& var,
PluginDispatcher* dispatcher) {
DCHECK(var.type == PP_VARTYPE_OBJECT);
HostVar host_var(dispatcher, var.value.as_id);
HostVarToPluginVarMap::iterator found =
host_var_to_plugin_var_.find(host_var);
if (found == host_var_to_plugin_var_.end()) {
return scoped_refptr<ProxyObjectVar>(
new ProxyObjectVar(dispatcher, static_cast<int32>(var.value.as_id)));
}
VarMap::iterator ret = live_vars_.find(found->second);
DCHECK(ret != live_vars_.end());
DCHECK(ret->second.var->AsProxyObjectVar());
return scoped_refptr<ProxyObjectVar>(ret->second.var->AsProxyObjectVar());
}
}
}