cef/libcef/common/values_impl.cc

1479 lines
41 KiB
C++

// Copyright (c) 2012 The Chromium Embedded Framework 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 "libcef/common/values_impl.h"
#include <algorithm>
#include <vector>
#include "base/memory/ptr_util.h"
namespace {
// Removes empty dictionaries from |dict|, potentially nested.
// Does not modify empty lists.
// From chrome/browser/chromeos/extensions/echo_private/echo_private_api.cc
void RemoveEmptyValueDicts(base::Value::Dict& dict) {
auto it = dict.begin();
while (it != dict.end()) {
base::Value& value = it->second;
if (value.is_dict()) {
base::Value::Dict& sub_dict = value.GetDict();
RemoveEmptyValueDicts(sub_dict);
if (sub_dict.empty()) {
it = dict.erase(it);
continue;
}
}
it++;
}
}
} // namespace
// CefValueImpl implementation.
// static
CefRefPtr<CefValue> CefValue::Create() {
return new CefValueImpl(new base::Value());
}
// static
CefRefPtr<CefValue> CefValueImpl::GetOrCreateRefOrCopy(
base::Value* value,
void* parent_value,
bool read_only,
CefValueController* controller) {
DCHECK(value);
if (value->is_blob()) {
return new CefValueImpl(
CefBinaryValueImpl::GetOrCreateRef(value, parent_value, controller));
}
if (value->is_dict()) {
base::DictionaryValue* dict_value =
static_cast<base::DictionaryValue*>(value);
return new CefValueImpl(CefDictionaryValueImpl::GetOrCreateRef(
dict_value, parent_value, read_only, controller));
}
if (value->is_list()) {
base::ListValue* list_value = static_cast<base::ListValue*>(value);
return new CefValueImpl(CefListValueImpl::GetOrCreateRef(
list_value, parent_value, read_only, controller));
}
return new CefValueImpl(new base::Value(value->Clone()));
}
CefValueImpl::CefValueImpl() {}
CefValueImpl::CefValueImpl(base::Value* value) {
SetValue(value);
}
CefValueImpl::CefValueImpl(CefRefPtr<CefBinaryValue> value)
: binary_value_(value) {}
CefValueImpl::CefValueImpl(CefRefPtr<CefDictionaryValue> value)
: dictionary_value_(value) {}
CefValueImpl::CefValueImpl(CefRefPtr<CefListValue> value)
: list_value_(value) {}
CefValueImpl::~CefValueImpl() {}
void CefValueImpl::SetValue(base::Value* value) {
base::AutoLock lock_scope(lock_);
SetValueInternal(value);
}
base::Value* CefValueImpl::CopyOrDetachValue(
CefValueController* new_controller) {
base::AutoLock lock_scope(lock_);
if (binary_value_) {
return static_cast<CefBinaryValueImpl*>(binary_value_.get())
->CopyOrDetachValue(new_controller);
}
if (dictionary_value_) {
return static_cast<CefDictionaryValueImpl*>(dictionary_value_.get())
->CopyOrDetachValue(new_controller);
}
if (list_value_) {
return static_cast<CefListValueImpl*>(list_value_.get())
->CopyOrDetachValue(new_controller);
}
return new base::Value(value_->Clone());
}
void CefValueImpl::SwapValue(base::Value* new_value,
void* new_parent_value,
CefValueController* new_controller) {
base::AutoLock lock_scope(lock_);
if (binary_value_) {
binary_value_ = CefBinaryValueImpl::GetOrCreateRef(
new_value, new_parent_value, new_controller);
} else if (dictionary_value_) {
dictionary_value_ = CefDictionaryValueImpl::GetOrCreateRef(
static_cast<base::DictionaryValue*>(new_value), new_parent_value, false,
new_controller);
} else if (list_value_) {
list_value_ = CefListValueImpl::GetOrCreateRef(
static_cast<base::ListValue*>(new_value), new_parent_value, false,
new_controller);
}
}
bool CefValueImpl::IsValid() {
base::AutoLock lock_scope(lock_);
if (binary_value_)
return binary_value_->IsValid();
if (dictionary_value_)
return dictionary_value_->IsValid();
if (list_value_)
return list_value_->IsValid();
return (value_ != nullptr);
}
bool CefValueImpl::IsOwned() {
base::AutoLock lock_scope(lock_);
if (binary_value_)
return binary_value_->IsOwned();
if (dictionary_value_)
return dictionary_value_->IsOwned();
if (list_value_)
return list_value_->IsOwned();
return false;
}
bool CefValueImpl::IsReadOnly() {
base::AutoLock lock_scope(lock_);
if (binary_value_)
return true;
if (dictionary_value_)
return dictionary_value_->IsReadOnly();
if (list_value_)
return list_value_->IsReadOnly();
return false;
}
bool CefValueImpl::IsSame(CefRefPtr<CefValue> that) {
if (that.get() == this)
return true;
if (!that.get() || that->GetType() != GetType())
return false;
CefValueImpl* impl = static_cast<CefValueImpl*>(that.get());
base::AutoLock lock_scope(lock_);
base::AutoLock lock_scope2(impl->lock_);
if (binary_value_)
return binary_value_->IsSame(impl->binary_value_);
if (dictionary_value_)
return dictionary_value_->IsSame(impl->dictionary_value_);
if (list_value_)
return list_value_->IsSame(impl->list_value_);
// Simple types are never the same.
return false;
}
bool CefValueImpl::IsEqual(CefRefPtr<CefValue> that) {
if (that.get() == this)
return true;
if (!that.get() || that->GetType() != GetType())
return false;
CefValueImpl* impl = static_cast<CefValueImpl*>(that.get());
base::AutoLock lock_scope(lock_);
base::AutoLock lock_scope2(impl->lock_);
if (binary_value_)
return binary_value_->IsEqual(impl->binary_value_);
if (dictionary_value_)
return dictionary_value_->IsEqual(impl->dictionary_value_);
if (list_value_)
return list_value_->IsEqual(impl->list_value_);
if (!value_) // Invalid types are equal.
return true;
return *value_ == *(impl->value_.get());
}
CefRefPtr<CefValue> CefValueImpl::Copy() {
base::AutoLock lock_scope(lock_);
if (binary_value_)
return new CefValueImpl(binary_value_->Copy());
if (dictionary_value_)
return new CefValueImpl(dictionary_value_->Copy(false));
if (list_value_)
return new CefValueImpl(list_value_->Copy());
if (value_)
return new CefValueImpl(new base::Value(value_->Clone()));
return new CefValueImpl();
}
CefValueType CefValueImpl::GetType() {
base::AutoLock lock_scope(lock_);
if (binary_value_)
return VTYPE_BINARY;
if (dictionary_value_)
return VTYPE_DICTIONARY;
if (list_value_)
return VTYPE_LIST;
if (value_) {
switch (value_->type()) {
case base::Value::Type::NONE:
return VTYPE_NULL;
case base::Value::Type::BOOLEAN:
return VTYPE_BOOL;
case base::Value::Type::INTEGER:
return VTYPE_INT;
case base::Value::Type::DOUBLE:
return VTYPE_DOUBLE;
case base::Value::Type::STRING:
return VTYPE_STRING;
default:
NOTREACHED();
break;
}
}
return VTYPE_INVALID;
}
bool CefValueImpl::GetBool() {
base::AutoLock lock_scope(lock_);
bool ret_value = false;
if (value_ && value_->is_bool())
ret_value = value_->GetBool();
return ret_value;
}
int CefValueImpl::GetInt() {
base::AutoLock lock_scope(lock_);
int ret_value = 0;
if (value_ && value_->is_int())
ret_value = value_->GetInt();
return ret_value;
}
double CefValueImpl::GetDouble() {
base::AutoLock lock_scope(lock_);
double ret_value = 0;
if (value_ && value_->is_double())
ret_value = value_->GetDouble();
return ret_value;
}
CefString CefValueImpl::GetString() {
base::AutoLock lock_scope(lock_);
std::string ret_value;
if (value_ && value_->is_string())
ret_value = value_->GetString();
return ret_value;
}
CefRefPtr<CefBinaryValue> CefValueImpl::GetBinary() {
base::AutoLock lock_scope(lock_);
return binary_value_;
}
CefRefPtr<CefDictionaryValue> CefValueImpl::GetDictionary() {
base::AutoLock lock_scope(lock_);
return dictionary_value_;
}
CefRefPtr<CefListValue> CefValueImpl::GetList() {
base::AutoLock lock_scope(lock_);
return list_value_;
}
bool CefValueImpl::SetNull() {
SetValue(new base::Value());
return true;
}
bool CefValueImpl::SetBool(bool value) {
SetValue(new base::Value(value));
return true;
}
bool CefValueImpl::SetInt(int value) {
SetValue(new base::Value(value));
return true;
}
bool CefValueImpl::SetDouble(double value) {
SetValue(new base::Value(value));
return true;
}
bool CefValueImpl::SetString(const CefString& value) {
SetValue(new base::Value(value.ToString()));
return true;
}
bool CefValueImpl::SetBinary(CefRefPtr<CefBinaryValue> value) {
base::AutoLock lock_scope(lock_);
SetValueInternal(nullptr);
binary_value_ = value;
return true;
}
bool CefValueImpl::SetDictionary(CefRefPtr<CefDictionaryValue> value) {
base::AutoLock lock_scope(lock_);
SetValueInternal(nullptr);
dictionary_value_ = value;
return true;
}
bool CefValueImpl::SetList(CefRefPtr<CefListValue> value) {
base::AutoLock lock_scope(lock_);
SetValueInternal(nullptr);
list_value_ = value;
return true;
}
void CefValueImpl::SetValueInternal(base::Value* value) {
lock_.AssertAcquired();
value_.reset(nullptr);
binary_value_ = nullptr;
dictionary_value_ = nullptr;
list_value_ = nullptr;
if (value) {
switch (value->type()) {
case base::Value::Type::BINARY:
binary_value_ = new CefBinaryValueImpl(value, true);
return;
case base::Value::Type::DICTIONARY:
dictionary_value_ = new CefDictionaryValueImpl(
static_cast<base::DictionaryValue*>(value), true, false);
return;
case base::Value::Type::LIST:
list_value_ = new CefListValueImpl(static_cast<base::ListValue*>(value),
true, false);
return;
default:
value_.reset(value);
}
}
}
CefValueController* CefValueImpl::GetValueController() const {
lock_.AssertAcquired();
if (binary_value_) {
return static_cast<CefBinaryValueImpl*>(binary_value_.get())->controller();
} else if (dictionary_value_) {
return static_cast<CefDictionaryValueImpl*>(dictionary_value_.get())
->controller();
} else if (list_value_) {
return static_cast<CefListValueImpl*>(list_value_.get())->controller();
}
return nullptr;
}
void CefValueImpl::AcquireLock() NO_THREAD_SAFETY_ANALYSIS {
lock_.Acquire();
CefValueController* controller = GetValueController();
if (controller)
controller->lock();
}
void CefValueImpl::ReleaseLock() NO_THREAD_SAFETY_ANALYSIS {
CefValueController* controller = GetValueController();
if (controller) {
controller->AssertLockAcquired();
controller->unlock();
}
lock_.Release();
}
base::Value* CefValueImpl::GetValueUnsafe() const {
lock_.AssertAcquired();
if (binary_value_) {
return static_cast<CefBinaryValueImpl*>(binary_value_.get())
->GetValueUnsafe();
} else if (dictionary_value_) {
return static_cast<CefDictionaryValueImpl*>(dictionary_value_.get())
->GetValueUnsafe();
} else if (list_value_) {
return static_cast<CefListValueImpl*>(list_value_.get())->GetValueUnsafe();
}
return value_.get();
}
// CefBinaryValueImpl implementation.
CefRefPtr<CefBinaryValue> CefBinaryValue::Create(const void* data,
size_t data_size) {
DCHECK(data);
DCHECK_GT(data_size, (size_t)0);
if (!data || data_size == 0)
return nullptr;
return new CefBinaryValueImpl(static_cast<char*>(const_cast<void*>(data)),
data_size);
}
// static
CefRefPtr<CefBinaryValue> CefBinaryValueImpl::GetOrCreateRef(
base::Value* value,
void* parent_value,
CefValueController* controller) {
DCHECK(value);
DCHECK(parent_value);
DCHECK(controller);
CefValueController::Object* object = controller->Get(value);
if (object)
return static_cast<CefBinaryValueImpl*>(object);
return new CefBinaryValueImpl(value, parent_value,
CefBinaryValueImpl::kReference, controller);
}
CefBinaryValueImpl::CefBinaryValueImpl(base::Value* value, bool will_delete)
: CefValueBase<CefBinaryValue, base::Value>(
value,
nullptr,
will_delete ? kOwnerWillDelete : kOwnerNoDelete,
true,
nullptr) {}
CefBinaryValueImpl::CefBinaryValueImpl(char* data, size_t data_size)
: CefValueBase<CefBinaryValue, base::Value>(
new base::Value(std::vector<char>(data, data + data_size)),
nullptr,
kOwnerWillDelete,
true,
nullptr) {}
base::Value* CefBinaryValueImpl::CopyValue() {
CEF_VALUE_VERIFY_RETURN(false, nullptr);
return new base::Value(const_value().Clone());
}
base::Value* CefBinaryValueImpl::CopyOrDetachValue(
CefValueController* new_controller) {
base::Value* new_value;
if (!will_delete()) {
// Copy the value.
new_value = CopyValue();
} else {
// Take ownership of the value.
new_value = Detach(new_controller);
}
DCHECK(new_value);
return new_value;
}
bool CefBinaryValueImpl::IsSameValue(const base::Value* that) {
CEF_VALUE_VERIFY_RETURN(false, false);
return (&const_value() == that);
}
bool CefBinaryValueImpl::IsEqualValue(const base::Value* that) {
CEF_VALUE_VERIFY_RETURN(false, false);
return const_value() == *that;
}
base::Value* CefBinaryValueImpl::GetValueUnsafe() {
if (!VerifyAttached())
return nullptr;
controller()->AssertLockAcquired();
return const_cast<base::Value*>(&const_value());
}
bool CefBinaryValueImpl::IsValid() {
return !detached();
}
bool CefBinaryValueImpl::IsOwned() {
return !will_delete();
}
bool CefBinaryValueImpl::IsSame(CefRefPtr<CefBinaryValue> that) {
if (!that.get())
return false;
if (that.get() == this)
return true;
CEF_VALUE_VERIFY_RETURN(false, false);
return static_cast<CefBinaryValueImpl*>(that.get())
->IsSameValue(&const_value());
}
bool CefBinaryValueImpl::IsEqual(CefRefPtr<CefBinaryValue> that) {
if (!that.get())
return false;
if (that.get() == this)
return true;
CEF_VALUE_VERIFY_RETURN(false, false);
return static_cast<CefBinaryValueImpl*>(that.get())
->IsEqualValue(&const_value());
}
CefRefPtr<CefBinaryValue> CefBinaryValueImpl::Copy() {
CEF_VALUE_VERIFY_RETURN(false, nullptr);
return new CefBinaryValueImpl(new base::Value(const_value().Clone()), nullptr,
CefBinaryValueImpl::kOwnerWillDelete, nullptr);
}
size_t CefBinaryValueImpl::GetSize() {
CEF_VALUE_VERIFY_RETURN(false, 0);
return const_value().GetBlob().size();
}
size_t CefBinaryValueImpl::GetData(void* buffer,
size_t buffer_size,
size_t data_offset) {
DCHECK(buffer);
DCHECK_GT(buffer_size, (size_t)0);
if (!buffer || buffer_size == 0)
return 0;
CEF_VALUE_VERIFY_RETURN(false, 0);
size_t size = const_value().GetBlob().size();
DCHECK_LT(data_offset, size);
if (data_offset >= size)
return 0;
size = std::min(buffer_size, size - data_offset);
auto* data = const_value().GetBlob().data();
memcpy(buffer, data + data_offset, size);
return size;
}
CefBinaryValueImpl::CefBinaryValueImpl(base::Value* value,
void* parent_value,
ValueMode value_mode,
CefValueController* controller)
: CefValueBase<CefBinaryValue, base::Value>(value,
parent_value,
value_mode,
true,
controller) {}
// CefDictionaryValueImpl implementation.
// static
CefRefPtr<CefDictionaryValue> CefDictionaryValue::Create() {
return new CefDictionaryValueImpl(new base::DictionaryValue(), true, false);
}
// static
CefRefPtr<CefDictionaryValue> CefDictionaryValueImpl::GetOrCreateRef(
base::DictionaryValue* value,
void* parent_value,
bool read_only,
CefValueController* controller) {
CefValueController::Object* object = controller->Get(value);
if (object)
return static_cast<CefDictionaryValueImpl*>(object);
return new CefDictionaryValueImpl(value, parent_value,
CefDictionaryValueImpl::kReference,
read_only, controller);
}
CefDictionaryValueImpl::CefDictionaryValueImpl(base::DictionaryValue* value,
bool will_delete,
bool read_only)
: CefValueBase<CefDictionaryValue, base::DictionaryValue>(
value,
nullptr,
will_delete ? kOwnerWillDelete : kOwnerNoDelete,
read_only,
nullptr) {}
base::DictionaryValue* CefDictionaryValueImpl::CopyValue() {
CEF_VALUE_VERIFY_RETURN(false, nullptr);
return static_cast<base::DictionaryValue*>(
new base::Value(const_value().Clone()));
}
base::DictionaryValue* CefDictionaryValueImpl::CopyOrDetachValue(
CefValueController* new_controller) {
base::DictionaryValue* new_value;
if (!will_delete()) {
// Copy the value.
new_value = CopyValue();
} else {
// Take ownership of the value.
new_value = Detach(new_controller);
}
DCHECK(new_value);
return new_value;
}
bool CefDictionaryValueImpl::IsSameValue(const base::DictionaryValue* that) {
CEF_VALUE_VERIFY_RETURN(false, false);
return (&const_value() == that);
}
bool CefDictionaryValueImpl::IsEqualValue(const base::DictionaryValue* that) {
CEF_VALUE_VERIFY_RETURN(false, false);
return const_value() == *that;
}
base::DictionaryValue* CefDictionaryValueImpl::GetValueUnsafe() {
if (!VerifyAttached())
return nullptr;
controller()->AssertLockAcquired();
return const_cast<base::DictionaryValue*>(&const_value());
}
bool CefDictionaryValueImpl::IsValid() {
return !detached();
}
bool CefDictionaryValueImpl::IsOwned() {
return !will_delete();
}
bool CefDictionaryValueImpl::IsReadOnly() {
return read_only();
}
bool CefDictionaryValueImpl::IsSame(CefRefPtr<CefDictionaryValue> that) {
if (!that.get())
return false;
if (that.get() == this)
return true;
CEF_VALUE_VERIFY_RETURN(false, false);
return static_cast<CefDictionaryValueImpl*>(that.get())
->IsSameValue(&const_value());
}
bool CefDictionaryValueImpl::IsEqual(CefRefPtr<CefDictionaryValue> that) {
if (!that.get())
return false;
if (that.get() == this)
return true;
CEF_VALUE_VERIFY_RETURN(false, false);
return static_cast<CefDictionaryValueImpl*>(that.get())
->IsEqualValue(&const_value());
}
CefRefPtr<CefDictionaryValue> CefDictionaryValueImpl::Copy(
bool exclude_empty_children) {
CEF_VALUE_VERIFY_RETURN(false, nullptr);
base::DictionaryValue* value = static_cast<base::DictionaryValue*>(
new base::Value(const_value().Clone()));
if (exclude_empty_children) {
RemoveEmptyValueDicts(value->GetDict());
}
return new CefDictionaryValueImpl(
value, nullptr, CefDictionaryValueImpl::kOwnerWillDelete, false, nullptr);
}
size_t CefDictionaryValueImpl::GetSize() {
CEF_VALUE_VERIFY_RETURN(false, 0);
return const_value().DictSize();
}
bool CefDictionaryValueImpl::Clear() {
CEF_VALUE_VERIFY_RETURN(true, false);
// Detach any dependent values.
controller()->RemoveDependencies(mutable_value());
mutable_value()->DictClear();
return true;
}
bool CefDictionaryValueImpl::HasKey(const CefString& key) {
CEF_VALUE_VERIFY_RETURN(false, 0);
return const_value().FindKey(base::StringPiece(key));
}
bool CefDictionaryValueImpl::GetKeys(KeyList& keys) {
CEF_VALUE_VERIFY_RETURN(false, 0);
for (const auto item : const_value().GetDict()) {
keys.push_back(item.first);
}
return true;
}
bool CefDictionaryValueImpl::Remove(const CefString& key) {
CEF_VALUE_VERIFY_RETURN(true, false);
return RemoveInternal(key);
}
CefValueType CefDictionaryValueImpl::GetType(const CefString& key) {
CEF_VALUE_VERIFY_RETURN(false, VTYPE_INVALID);
const base::Value* value = const_value().FindKey(base::StringPiece(key));
if (value) {
switch (value->type()) {
case base::Value::Type::NONE:
return VTYPE_NULL;
case base::Value::Type::BOOLEAN:
return VTYPE_BOOL;
case base::Value::Type::INTEGER:
return VTYPE_INT;
case base::Value::Type::DOUBLE:
return VTYPE_DOUBLE;
case base::Value::Type::STRING:
return VTYPE_STRING;
case base::Value::Type::BINARY:
return VTYPE_BINARY;
case base::Value::Type::DICTIONARY:
return VTYPE_DICTIONARY;
case base::Value::Type::LIST:
return VTYPE_LIST;
}
}
return VTYPE_INVALID;
}
CefRefPtr<CefValue> CefDictionaryValueImpl::GetValue(const CefString& key) {
CEF_VALUE_VERIFY_RETURN(false, nullptr);
const base::Value* value = const_value().FindKey(base::StringPiece(key));
if (value) {
return CefValueImpl::GetOrCreateRefOrCopy(
const_cast<base::Value*>(value),
const_cast<base::DictionaryValue*>(&const_value()), read_only(),
controller());
}
return nullptr;
}
bool CefDictionaryValueImpl::GetBool(const CefString& key) {
CEF_VALUE_VERIFY_RETURN(false, false);
bool ret_value = false;
const base::Value* value = const_value().FindKey(base::StringPiece(key));
if (value && value->is_bool()) {
ret_value = value->GetBool();
}
return ret_value;
}
int CefDictionaryValueImpl::GetInt(const CefString& key) {
CEF_VALUE_VERIFY_RETURN(false, 0);
int ret_value = 0;
const base::Value* value = const_value().FindKey(base::StringPiece(key));
if (value && value->is_int()) {
ret_value = value->GetInt();
}
return ret_value;
}
double CefDictionaryValueImpl::GetDouble(const CefString& key) {
CEF_VALUE_VERIFY_RETURN(false, 0);
double ret_value = 0;
const base::Value* value = const_value().FindKey(base::StringPiece(key));
if (value && value->is_double()) {
ret_value = value->GetDouble();
}
return ret_value;
}
CefString CefDictionaryValueImpl::GetString(const CefString& key) {
CEF_VALUE_VERIFY_RETURN(false, CefString());
std::string ret_value;
const base::Value* value = const_value().FindKey(base::StringPiece(key));
if (value && value->is_string()) {
ret_value = value->GetString();
}
return ret_value;
}
CefRefPtr<CefBinaryValue> CefDictionaryValueImpl::GetBinary(
const CefString& key) {
CEF_VALUE_VERIFY_RETURN(false, nullptr);
const base::Value* value = const_value().FindKey(base::StringPiece(key));
if (value && value->is_blob()) {
base::Value* binary_value = const_cast<base::Value*>(value);
return CefBinaryValueImpl::GetOrCreateRef(
binary_value, const_cast<base::DictionaryValue*>(&const_value()),
controller());
}
return nullptr;
}
CefRefPtr<CefDictionaryValue> CefDictionaryValueImpl::GetDictionary(
const CefString& key) {
CEF_VALUE_VERIFY_RETURN(false, nullptr);
const base::Value* value = const_value().FindKey(base::StringPiece(key));
if (value && value->is_dict()) {
base::DictionaryValue* dict_value =
static_cast<base::DictionaryValue*>(const_cast<base::Value*>(value));
return CefDictionaryValueImpl::GetOrCreateRef(
dict_value, const_cast<base::DictionaryValue*>(&const_value()),
read_only(), controller());
}
return nullptr;
}
CefRefPtr<CefListValue> CefDictionaryValueImpl::GetList(const CefString& key) {
CEF_VALUE_VERIFY_RETURN(false, nullptr);
const base::Value* value = const_value().FindKey(base::StringPiece(key));
if (value && value->is_list()) {
base::ListValue* list_value =
static_cast<base::ListValue*>(const_cast<base::Value*>(value));
return CefListValueImpl::GetOrCreateRef(
list_value, const_cast<base::DictionaryValue*>(&const_value()),
read_only(), controller());
}
return nullptr;
}
bool CefDictionaryValueImpl::SetValue(const CefString& key,
CefRefPtr<CefValue> value) {
CEF_VALUE_VERIFY_RETURN(true, false);
CefValueImpl* impl = static_cast<CefValueImpl*>(value.get());
DCHECK(impl);
base::Value* new_value = impl->CopyOrDetachValue(controller());
base::Value* actual_value = SetInternal(key, new_value);
impl->SwapValue(actual_value, mutable_value(), controller());
return true;
}
bool CefDictionaryValueImpl::SetNull(const CefString& key) {
CEF_VALUE_VERIFY_RETURN(true, false);
SetInternal(key, new base::Value());
return true;
}
bool CefDictionaryValueImpl::SetBool(const CefString& key, bool value) {
CEF_VALUE_VERIFY_RETURN(true, false);
SetInternal(key, new base::Value(value));
return true;
}
bool CefDictionaryValueImpl::SetInt(const CefString& key, int value) {
CEF_VALUE_VERIFY_RETURN(true, false);
SetInternal(key, new base::Value(value));
return true;
}
bool CefDictionaryValueImpl::SetDouble(const CefString& key, double value) {
CEF_VALUE_VERIFY_RETURN(true, false);
SetInternal(key, new base::Value(value));
return true;
}
bool CefDictionaryValueImpl::SetString(const CefString& key,
const CefString& value) {
CEF_VALUE_VERIFY_RETURN(true, false);
SetInternal(key, new base::Value(value.ToString()));
return true;
}
bool CefDictionaryValueImpl::SetBinary(const CefString& key,
CefRefPtr<CefBinaryValue> value) {
CEF_VALUE_VERIFY_RETURN(true, false);
CefBinaryValueImpl* impl = static_cast<CefBinaryValueImpl*>(value.get());
DCHECK(impl);
SetInternal(key, impl->CopyOrDetachValue(controller()));
return true;
}
bool CefDictionaryValueImpl::SetDictionary(
const CefString& key,
CefRefPtr<CefDictionaryValue> value) {
CEF_VALUE_VERIFY_RETURN(true, false);
CefDictionaryValueImpl* impl =
static_cast<CefDictionaryValueImpl*>(value.get());
DCHECK(impl);
SetInternal(key, impl->CopyOrDetachValue(controller()));
return true;
}
bool CefDictionaryValueImpl::SetList(const CefString& key,
CefRefPtr<CefListValue> value) {
CEF_VALUE_VERIFY_RETURN(true, false);
CefListValueImpl* impl = static_cast<CefListValueImpl*>(value.get());
DCHECK(impl);
SetInternal(key, impl->CopyOrDetachValue(controller()));
return true;
}
bool CefDictionaryValueImpl::RemoveInternal(const CefString& key) {
// The ExtractKey() call below which removes the Value from the dictionary
// will return a new Value object with the moved contents of the Value that
// exists in the implementation std::map. Consequently we use FindKey() to
// retrieve the actual Value pointer as it current exists first, for later
// comparison purposes.
const base::Value* actual_value =
const_value().FindKey(base::StringPiece(key));
if (!actual_value)
return false;
// |actual_value| is no longer valid after this call.
absl::optional<base::Value> out_value =
mutable_value()->ExtractKey(base::StringPiece(key));
if (!out_value.has_value()) {
return false;
}
// Remove the value.
controller()->Remove(const_cast<base::Value*>(actual_value), true);
// Only list and dictionary types may have dependencies.
if (out_value->is_list() || out_value->is_dict()) {
controller()->RemoveDependencies(const_cast<base::Value*>(actual_value));
}
return true;
}
base::Value* CefDictionaryValueImpl::SetInternal(const CefString& key,
base::Value* value) {
DCHECK(value);
std::unique_ptr<base::Value> valueObj(value);
RemoveInternal(key);
// base::Value now uses move semantics which means that Set() will move the
// contents of the passed-in base::Value instead of keeping the same object.
// Set() then returns the actual Value pointer as it currently exists.
base::Value* actual_value =
mutable_value()->GetDict().Set(base::StringPiece(key), std::move(*value));
CHECK(actual_value);
// |value| will be deleted when this method returns. Update the controller to
// reference |actual_value| instead.
controller()->Swap(value, actual_value);
return actual_value;
}
CefDictionaryValueImpl::CefDictionaryValueImpl(base::DictionaryValue* value,
void* parent_value,
ValueMode value_mode,
bool read_only,
CefValueController* controller)
: CefValueBase<CefDictionaryValue, base::DictionaryValue>(value,
parent_value,
value_mode,
read_only,
controller) {}
// CefListValueImpl implementation.
// static
CefRefPtr<CefListValue> CefListValue::Create() {
return new CefListValueImpl(new base::ListValue(), true, false);
}
// static
CefRefPtr<CefListValue> CefListValueImpl::GetOrCreateRef(
base::ListValue* value,
void* parent_value,
bool read_only,
CefValueController* controller) {
CefValueController::Object* object = controller->Get(value);
if (object)
return static_cast<CefListValueImpl*>(object);
return new CefListValueImpl(value, parent_value, CefListValueImpl::kReference,
read_only, controller);
}
CefListValueImpl::CefListValueImpl(base::ListValue* value,
bool will_delete,
bool read_only)
: CefValueBase<CefListValue, base::ListValue>(
value,
nullptr,
will_delete ? kOwnerWillDelete : kOwnerNoDelete,
read_only,
nullptr) {}
base::ListValue* CefListValueImpl::CopyValue() {
CEF_VALUE_VERIFY_RETURN(false, nullptr);
return static_cast<base::ListValue*>(new base::Value(const_value().Clone()));
}
base::ListValue* CefListValueImpl::CopyOrDetachValue(
CefValueController* new_controller) {
base::ListValue* new_value;
if (!will_delete()) {
// Copy the value.
new_value = CopyValue();
} else {
// Take ownership of the value.
new_value = Detach(new_controller);
}
DCHECK(new_value);
return new_value;
}
bool CefListValueImpl::IsSameValue(const base::ListValue* that) {
CEF_VALUE_VERIFY_RETURN(false, false);
return (&const_value() == that);
}
bool CefListValueImpl::IsEqualValue(const base::ListValue* that) {
CEF_VALUE_VERIFY_RETURN(false, false);
return const_value() == *that;
}
base::ListValue* CefListValueImpl::GetValueUnsafe() {
if (!VerifyAttached())
return nullptr;
controller()->AssertLockAcquired();
return const_cast<base::ListValue*>(&const_value());
}
bool CefListValueImpl::IsValid() {
return !detached();
}
bool CefListValueImpl::IsOwned() {
return !will_delete();
}
bool CefListValueImpl::IsReadOnly() {
return read_only();
}
bool CefListValueImpl::IsSame(CefRefPtr<CefListValue> that) {
if (!that.get())
return false;
if (that.get() == this)
return true;
CEF_VALUE_VERIFY_RETURN(false, false);
return static_cast<CefListValueImpl*>(that.get())
->IsSameValue(&const_value());
}
bool CefListValueImpl::IsEqual(CefRefPtr<CefListValue> that) {
if (!that.get())
return false;
if (that.get() == this)
return true;
CEF_VALUE_VERIFY_RETURN(false, false);
return static_cast<CefListValueImpl*>(that.get())
->IsEqualValue(&const_value());
}
CefRefPtr<CefListValue> CefListValueImpl::Copy() {
CEF_VALUE_VERIFY_RETURN(false, nullptr);
return new CefListValueImpl(
static_cast<base::ListValue*>(new base::Value(const_value().Clone())),
nullptr, CefListValueImpl::kOwnerWillDelete, false, nullptr);
}
bool CefListValueImpl::SetSize(size_t size) {
CEF_VALUE_VERIFY_RETURN(true, false);
size_t current_size = const_value().GetList().size();
if (size < current_size) {
// Clean up any values above the requested size.
for (size_t i = current_size - 1; i >= size; --i)
RemoveInternal(i);
} else if (size > 0) {
// Expand the list size.
// TODO: This approach seems inefficient. See https://crbug.com/1187066#c17
// for background.
auto& list = mutable_value()->GetList();
while (list.size() < size)
mutable_value()->Append(base::Value());
}
return true;
}
size_t CefListValueImpl::GetSize() {
CEF_VALUE_VERIFY_RETURN(false, 0);
return const_value().GetList().size();
}
bool CefListValueImpl::Clear() {
CEF_VALUE_VERIFY_RETURN(true, false);
// Detach any dependent values.
controller()->RemoveDependencies(mutable_value());
mutable_value()->ClearList();
return true;
}
bool CefListValueImpl::Remove(size_t index) {
CEF_VALUE_VERIFY_RETURN(true, false);
return RemoveInternal(index);
}
CefValueType CefListValueImpl::GetType(size_t index) {
CEF_VALUE_VERIFY_RETURN(false, VTYPE_INVALID);
const auto& list = const_value().GetList();
if (index < list.size()) {
const base::Value& value = list[index];
switch (value.type()) {
case base::Value::Type::NONE:
return VTYPE_NULL;
case base::Value::Type::BOOLEAN:
return VTYPE_BOOL;
case base::Value::Type::INTEGER:
return VTYPE_INT;
case base::Value::Type::DOUBLE:
return VTYPE_DOUBLE;
case base::Value::Type::STRING:
return VTYPE_STRING;
case base::Value::Type::BINARY:
return VTYPE_BINARY;
case base::Value::Type::DICTIONARY:
return VTYPE_DICTIONARY;
case base::Value::Type::LIST:
return VTYPE_LIST;
}
}
return VTYPE_INVALID;
}
CefRefPtr<CefValue> CefListValueImpl::GetValue(size_t index) {
CEF_VALUE_VERIFY_RETURN(false, nullptr);
const auto& list = const_value().GetList();
if (index < list.size()) {
const base::Value& value = list[index];
return CefValueImpl::GetOrCreateRefOrCopy(
const_cast<base::Value*>(&value),
const_cast<base::ListValue*>(&const_value()), read_only(),
controller());
}
return nullptr;
}
bool CefListValueImpl::GetBool(size_t index) {
CEF_VALUE_VERIFY_RETURN(false, false);
bool ret_value = false;
const auto& list = const_value().GetList();
if (index < list.size()) {
const base::Value& value = list[index];
if (value.is_bool()) {
ret_value = value.GetBool();
}
}
return ret_value;
}
int CefListValueImpl::GetInt(size_t index) {
CEF_VALUE_VERIFY_RETURN(false, 0);
int ret_value = 0;
const auto& list = const_value().GetList();
if (index < list.size()) {
const base::Value& value = list[index];
if (value.is_int()) {
ret_value = value.GetInt();
}
}
return ret_value;
}
double CefListValueImpl::GetDouble(size_t index) {
CEF_VALUE_VERIFY_RETURN(false, 0);
double ret_value = 0;
const auto& list = const_value().GetList();
if (index < list.size()) {
const base::Value& value = list[index];
if (value.is_double()) {
ret_value = value.GetDouble();
}
}
return ret_value;
}
CefString CefListValueImpl::GetString(size_t index) {
CEF_VALUE_VERIFY_RETURN(false, CefString());
std::string ret_value;
const auto& list = const_value().GetList();
if (index < list.size()) {
const base::Value& value = list[index];
if (value.is_string()) {
ret_value = value.GetString();
}
}
return ret_value;
}
CefRefPtr<CefBinaryValue> CefListValueImpl::GetBinary(size_t index) {
CEF_VALUE_VERIFY_RETURN(false, nullptr);
const auto& list = const_value().GetList();
if (index < list.size()) {
const base::Value& value = list[index];
if (value.is_blob()) {
base::Value* binary_value = const_cast<base::Value*>(&value);
return CefBinaryValueImpl::GetOrCreateRef(
binary_value, const_cast<base::ListValue*>(&const_value()),
controller());
}
}
return nullptr;
}
CefRefPtr<CefDictionaryValue> CefListValueImpl::GetDictionary(size_t index) {
CEF_VALUE_VERIFY_RETURN(false, nullptr);
const auto& list = const_value().GetList();
if (index < list.size()) {
const base::Value& value = list[index];
if (value.is_dict()) {
base::DictionaryValue* dict_value =
static_cast<base::DictionaryValue*>(const_cast<base::Value*>(&value));
return CefDictionaryValueImpl::GetOrCreateRef(
dict_value, const_cast<base::ListValue*>(&const_value()), read_only(),
controller());
}
}
return nullptr;
}
CefRefPtr<CefListValue> CefListValueImpl::GetList(size_t index) {
CEF_VALUE_VERIFY_RETURN(false, nullptr);
const auto& list = const_value().GetList();
if (index < list.size()) {
const base::Value& value = list[index];
if (value.is_list()) {
base::ListValue* list_value =
static_cast<base::ListValue*>(const_cast<base::Value*>(&value));
return CefListValueImpl::GetOrCreateRef(
list_value, const_cast<base::ListValue*>(&const_value()), read_only(),
controller());
}
}
return nullptr;
}
bool CefListValueImpl::SetValue(size_t index, CefRefPtr<CefValue> value) {
CEF_VALUE_VERIFY_RETURN(true, false);
CefValueImpl* impl = static_cast<CefValueImpl*>(value.get());
DCHECK(impl);
base::Value* new_value = impl->CopyOrDetachValue(controller());
base::Value* actual_value = SetInternal(index, new_value);
impl->SwapValue(actual_value, mutable_value(), controller());
return true;
}
bool CefListValueImpl::SetNull(size_t index) {
CEF_VALUE_VERIFY_RETURN(true, false);
SetInternal(index, new base::Value());
return true;
}
bool CefListValueImpl::SetBool(size_t index, bool value) {
CEF_VALUE_VERIFY_RETURN(true, false);
SetInternal(index, new base::Value(value));
return true;
}
bool CefListValueImpl::SetInt(size_t index, int value) {
CEF_VALUE_VERIFY_RETURN(true, false);
SetInternal(index, new base::Value(value));
return true;
}
bool CefListValueImpl::SetDouble(size_t index, double value) {
CEF_VALUE_VERIFY_RETURN(true, false);
SetInternal(index, new base::Value(value));
return true;
}
bool CefListValueImpl::SetString(size_t index, const CefString& value) {
CEF_VALUE_VERIFY_RETURN(true, false);
SetInternal(index, new base::Value(value.ToString()));
return true;
}
bool CefListValueImpl::SetBinary(size_t index,
CefRefPtr<CefBinaryValue> value) {
CEF_VALUE_VERIFY_RETURN(true, false);
CefBinaryValueImpl* impl = static_cast<CefBinaryValueImpl*>(value.get());
DCHECK(impl);
SetInternal(index, impl->CopyOrDetachValue(controller()));
return true;
}
bool CefListValueImpl::SetDictionary(size_t index,
CefRefPtr<CefDictionaryValue> value) {
CEF_VALUE_VERIFY_RETURN(true, false);
CefDictionaryValueImpl* impl =
static_cast<CefDictionaryValueImpl*>(value.get());
DCHECK(impl);
SetInternal(index, impl->CopyOrDetachValue(controller()));
return true;
}
bool CefListValueImpl::SetList(size_t index, CefRefPtr<CefListValue> value) {
CEF_VALUE_VERIFY_RETURN(true, false);
CefListValueImpl* impl = static_cast<CefListValueImpl*>(value.get());
DCHECK(impl);
SetInternal(index, impl->CopyOrDetachValue(controller()));
return true;
}
bool CefListValueImpl::RemoveInternal(size_t index) {
auto& list = mutable_value()->GetList();
if (index >= list.size())
return false;
// The std::move() call below which removes the Value from the list will
// return a new Value object with the moved contents of the Value that exists
// in the implementation std::vector. Consequently we use operator[] to
// retrieve the actual Value pointer as it current exists first, for later
// comparison purposes.
const base::Value& actual_value = list[index];
// |actual_value| is no longer valid after this call.
auto out_value = std::move(list[index]);
list.erase(list.begin() + index);
// Remove the value.
controller()->Remove(const_cast<base::Value*>(&actual_value), true);
// Only list and dictionary types may have dependencies.
if (out_value.is_list() || out_value.is_dict()) {
controller()->RemoveDependencies(const_cast<base::Value*>(&actual_value));
}
return true;
}
base::Value* CefListValueImpl::SetInternal(size_t index, base::Value* value) {
DCHECK(value);
std::unique_ptr<base::Value> valueObj(value);
auto& list = mutable_value()->GetList();
if (RemoveInternal(index)) {
CHECK_LE(index, list.size());
list.Insert(list.begin() + index, std::move(*value));
} else {
if (index >= list.size()) {
// Expand the list size.
// TODO: This approach seems inefficient. See
// https://crbug.com/1187066#c17 for background.
while (list.size() <= index)
mutable_value()->Append(base::Value());
}
list[index] = std::move(*value);
}
// base::Value now uses move semantics which means that Insert()/Set() will
// move the contents of the passed-in base::Value instead of keeping the same
// object. Consequently we use operator[] to retrieve the actual base::Value
// pointer as it exists in the std::vector.
const base::Value& actual_value = list[index];
// |value| will be deleted when this method returns. Update the controller to
// reference |actual_value| instead.
controller()->Swap(value, const_cast<base::Value*>(&actual_value));
return const_cast<base::Value*>(&actual_value);
}
CefListValueImpl::CefListValueImpl(base::ListValue* value,
void* parent_value,
ValueMode value_mode,
bool read_only,
CefValueController* controller)
: CefValueBase<CefListValue, base::ListValue>(value,
parent_value,
value_mode,
read_only,
controller) {}