| // Copyright 2014 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 "fake_ppapi/fake_var_manager.h" |
| #include "gtest/gtest.h" |
| #include "sdk_util/auto_lock.h" |
| |
| FakeVarManager::FakeVarManager() : debug(false), next_id_(1) {} |
| |
| FakeVarManager::~FakeVarManager() { |
| // The ref counts for all vars should be zero. |
| for (VarMap::const_iterator iter = var_map_.begin(); iter != var_map_.end(); |
| ++iter) { |
| const FakeVarData& var_data = iter->second; |
| EXPECT_EQ(0, var_data.ref_count) << "Non-zero refcount on " |
| << Describe(var_data); |
| } |
| } |
| |
| FakeVarData* FakeVarManager::CreateVarData() { |
| AUTO_LOCK(lock_); |
| Id id = next_id_++; |
| FakeVarData data; |
| data.id = id; |
| data.ref_count = 1; |
| var_map_[id] = data; |
| return &var_map_[id]; |
| } |
| |
| void FakeVarManager::AddRef(PP_Var var) { |
| AUTO_LOCK(lock_); |
| // From ppb_var.h: |
| // AddRef() adds a reference to the given var. If this is not a refcounted |
| // object, this function will do nothing so you can always call it no matter |
| // what the type. |
| |
| FakeVarData* var_data = GetVarData_Locked(var); |
| if (!var_data) |
| return; |
| |
| EXPECT_GT(var_data->ref_count, 0) |
| << "AddRefing freed " << Describe(*var_data); |
| var_data->ref_count++; |
| if (debug) |
| printf("AddRef of %s [new refcount=%d]\n", |
| Describe(*var_data).c_str(), |
| var_data->ref_count); |
| } |
| |
| std::string FakeVarManager::Describe(const FakeVarData& var_data) { |
| std::stringstream rtn; |
| switch (var_data.type) { |
| case PP_VARTYPE_STRING: |
| rtn << "String with id " << var_data.id << |
| " with value \"" << var_data.string_value << "\""; |
| break; |
| case PP_VARTYPE_ARRAY: |
| rtn << "Array of size " << var_data.array_value.size() |
| << " with id " << var_data.id; |
| break; |
| case PP_VARTYPE_ARRAY_BUFFER: |
| rtn << "ArrayBuffer of size " << var_data.buffer_value.length |
| << " with id " << var_data.id; |
| break; |
| case PP_VARTYPE_DICTIONARY: |
| rtn << "Dictionary of size " << var_data.dict_value.size() << " with id " |
| << var_data.id; |
| break; |
| default: |
| rtn << "resource of type " << var_data.type |
| << " with id " << var_data.id; |
| break; |
| } |
| return rtn.str(); |
| } |
| |
| void FakeVarManager::DestroyVarData_Locked(FakeVarData* var_data) { |
| // Release each PP_Var in the array |
| |
| switch (var_data->type) { |
| case PP_VARTYPE_ARRAY: { |
| FakeArrayType& vector = var_data->array_value; |
| for (FakeArrayType::iterator it = vector.begin(); |
| it != vector.end(); ++it) { |
| Release_Locked(*it); |
| } |
| vector.clear(); |
| break; |
| } |
| case PP_VARTYPE_ARRAY_BUFFER: { |
| free(var_data->buffer_value.ptr); |
| var_data->buffer_value.ptr = NULL; |
| var_data->buffer_value.length = 0; |
| break; |
| } |
| case PP_VARTYPE_DICTIONARY: { |
| FakeDictType& dict = var_data->dict_value; |
| for (FakeDictType::iterator it = dict.begin(); |
| it != dict.end(); it++) { |
| Release_Locked(it->second); |
| } |
| dict.clear(); |
| break; |
| } |
| default: |
| break; |
| } |
| } |
| |
| FakeVarData* FakeVarManager::GetVarData(PP_Var var) { |
| AUTO_LOCK(lock_); |
| return GetVarData_Locked(var); |
| } |
| |
| FakeVarData* FakeVarManager::GetVarData_Locked(PP_Var var) { |
| switch (var.type) { |
| // These types don't have any var data as their data |
| // is stored directly in the var's value union. |
| case PP_VARTYPE_UNDEFINED: |
| case PP_VARTYPE_NULL: |
| case PP_VARTYPE_BOOL: |
| case PP_VARTYPE_INT32: |
| case PP_VARTYPE_DOUBLE: |
| return NULL; |
| default: |
| break; |
| } |
| |
| VarMap::iterator iter = var_map_.find(var.value.as_id); |
| if (iter == var_map_.end()) |
| return NULL; |
| FakeVarData* var_data = &iter->second; |
| EXPECT_GT(var_data->ref_count, 0) |
| << "Accessing freed " << Describe(*var_data); |
| return var_data; |
| } |
| |
| void FakeVarManager::Release(PP_Var var) { |
| AUTO_LOCK(lock_); |
| Release_Locked(var); |
| } |
| |
| void FakeVarManager::Release_Locked(PP_Var var) { |
| // From ppb_var.h: |
| // Release() removes a reference to given var, deleting it if the internal |
| // reference count becomes 0. If the given var is not a refcounted object, |
| // this function will do nothing so you can always call it no matter what |
| // the type. |
| FakeVarData* var_data = GetVarData_Locked(var); |
| if (!var_data) { |
| if (debug) |
| printf("Releasing simple var\n"); |
| return; |
| } |
| |
| EXPECT_GT(var_data->ref_count, 0) |
| << "Releasing freed " << Describe(*var_data); |
| |
| var_data->ref_count--; |
| if (debug) |
| printf("Released %s [new refcount=%d]\n", |
| Describe(*var_data).c_str(), |
| var_data->ref_count); |
| |
| if (var_data->ref_count == 0) |
| DestroyVarData_Locked(var_data); |
| } |