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