// 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.
#include "content/renderer/pepper/host_var_tracker.h"
#include "base/logging.h"
#include "content/renderer/pepper/host_array_buffer_var.h"
#include "content/renderer/pepper/host_resource_var.h"
#include "content/renderer/pepper/npobject_var.h"
#include "content/renderer/pepper/pepper_plugin_instance_impl.h"
#include "ppapi/c/pp_var.h"
using ppapi::ArrayBufferVar;
using ppapi::NPObjectVar;
namespace content {
HostVarTracker::HostVarTracker()
: VarTracker(SINGLE_THREADED),
last_shared_memory_map_id_(0) {
}
HostVarTracker::~HostVarTracker() {
}
ArrayBufferVar* HostVarTracker::CreateArrayBuffer(uint32 size_in_bytes) {
return new HostArrayBufferVar(size_in_bytes);
}
ArrayBufferVar* HostVarTracker::CreateShmArrayBuffer(
uint32 size_in_bytes,
base::SharedMemoryHandle handle) {
return new HostArrayBufferVar(size_in_bytes, handle);
}
void HostVarTracker::AddNPObjectVar(NPObjectVar* object_var) {
CheckThreadingPreconditions();
InstanceMap::iterator found_instance = instance_map_.find(
object_var->pp_instance());
if (found_instance == instance_map_.end()) {
// Lazily create the instance map.
DCHECK(object_var->pp_instance() != 0);
found_instance = instance_map_.insert(std::make_pair(
object_var->pp_instance(),
linked_ptr<NPObjectToNPObjectVarMap>(new NPObjectToNPObjectVarMap))).
first;
}
NPObjectToNPObjectVarMap* np_object_map = found_instance->second.get();
DCHECK(np_object_map->find(object_var->np_object()) ==
np_object_map->end()) << "NPObjectVar already in map";
np_object_map->insert(std::make_pair(object_var->np_object(), object_var));
}
void HostVarTracker::RemoveNPObjectVar(NPObjectVar* object_var) {
CheckThreadingPreconditions();
InstanceMap::iterator found_instance = instance_map_.find(
object_var->pp_instance());
if (found_instance == instance_map_.end()) {
NOTREACHED() << "NPObjectVar has invalid instance.";
return;
}
NPObjectToNPObjectVarMap* np_object_map = found_instance->second.get();
NPObjectToNPObjectVarMap::iterator found_object =
np_object_map->find(object_var->np_object());
if (found_object == np_object_map->end()) {
NOTREACHED() << "NPObjectVar not registered.";
return;
}
if (found_object->second != object_var) {
NOTREACHED() << "NPObjectVar doesn't match.";
return;
}
np_object_map->erase(found_object);
}
NPObjectVar* HostVarTracker::NPObjectVarForNPObject(PP_Instance instance,
NPObject* np_object) {
CheckThreadingPreconditions();
InstanceMap::iterator found_instance = instance_map_.find(instance);
if (found_instance == instance_map_.end())
return NULL; // No such instance.
NPObjectToNPObjectVarMap* np_object_map = found_instance->second.get();
NPObjectToNPObjectVarMap::iterator found_object =
np_object_map->find(np_object);
if (found_object == np_object_map->end())
return NULL; // No such object.
return found_object->second;
}
int HostVarTracker::GetLiveNPObjectVarsForInstance(PP_Instance instance) const {
CheckThreadingPreconditions();
InstanceMap::const_iterator found = instance_map_.find(instance);
if (found == instance_map_.end())
return 0;
return static_cast<int>(found->second->size());
}
PP_Var HostVarTracker::MakeResourcePPVarFromMessage(
PP_Instance instance,
const IPC::Message& creation_message,
int pending_renderer_id,
int pending_browser_id) {
// On the host side, the creation message is ignored when creating a resource.
// Therefore, a call to this function indicates a null resource. Return the
// resource 0.
return MakeResourcePPVar(0);
}
ppapi::ResourceVar* HostVarTracker::MakeResourceVar(PP_Resource pp_resource) {
return new HostResourceVar(pp_resource);
}
void HostVarTracker::DidDeleteInstance(PP_Instance instance) {
CheckThreadingPreconditions();
InstanceMap::iterator found_instance = instance_map_.find(instance);
if (found_instance == instance_map_.end())
return; // Nothing to do.
NPObjectToNPObjectVarMap* np_object_map = found_instance->second.get();
// Force delete all var references. ForceReleaseNPObject() will cause
// this object, and potentially others it references, to be removed from
// |np_object_map|.
while (!np_object_map->empty()) {
ForceReleaseNPObject(np_object_map->begin()->second);
}
// Remove the record for this instance since it should be empty.
DCHECK(np_object_map->empty());
instance_map_.erase(found_instance);
}
void HostVarTracker::ForceReleaseNPObject(ppapi::NPObjectVar* object_var) {
object_var->InstanceDeleted();
VarMap::iterator iter = live_vars_.find(object_var->GetExistingVarID());
if (iter == live_vars_.end()) {
NOTREACHED();
return;
}
iter->second.ref_count = 0;
DCHECK(iter->second.track_with_no_reference_count == 0);
DeleteObjectInfoIfNecessary(iter);
}
int HostVarTracker::TrackSharedMemoryHandle(PP_Instance instance,
base::SharedMemoryHandle handle,
uint32 size_in_bytes) {
SharedMemoryMapEntry entry;
entry.instance = instance;
entry.handle = handle;
entry.size_in_bytes = size_in_bytes;
// Find a free id for our map.
while (shared_memory_map_.find(last_shared_memory_map_id_) !=
shared_memory_map_.end()) {
++last_shared_memory_map_id_;
}
shared_memory_map_[last_shared_memory_map_id_] = entry;
return last_shared_memory_map_id_;
}
bool HostVarTracker::StopTrackingSharedMemoryHandle(
int id,
PP_Instance instance,
base::SharedMemoryHandle* handle,
uint32* size_in_bytes) {
SharedMemoryMap::iterator it = shared_memory_map_.find(id);
if (it == shared_memory_map_.end())
return false;
if (it->second.instance != instance)
return false;
*handle = it->second.handle;
*size_in_bytes = it->second.size_in_bytes;
shared_memory_map_.erase(it);
return true;
}
} // namespace content