mirror of
https://bitbucket.org/chromiumembedded/cef
synced 2025-06-05 21:39:12 +02:00
- Add new API to retrieve/observe configuration values. - cefclient: Add https://tests/config to inspect configuration values in real time.
264 lines
7.2 KiB
C++
264 lines
7.2 KiB
C++
// Copyright (c) 2022 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 "cef/libcef/browser/prefs/pref_helper.h"
|
|
|
|
#include "base/notreached.h"
|
|
#include "base/strings/stringprintf.h"
|
|
#include "cef/include/cef_preference.h"
|
|
#include "cef/libcef/browser/thread_util.h"
|
|
#include "cef/libcef/common/values_impl.h"
|
|
#include "components/prefs/pref_service.h"
|
|
|
|
namespace pref_helper {
|
|
|
|
namespace {
|
|
|
|
const char* GetTypeString(base::Value::Type type) {
|
|
switch (type) {
|
|
case base::Value::Type::NONE:
|
|
return "NULL";
|
|
case base::Value::Type::BOOLEAN:
|
|
return "BOOLEAN";
|
|
case base::Value::Type::INTEGER:
|
|
return "INTEGER";
|
|
case base::Value::Type::DOUBLE:
|
|
return "DOUBLE";
|
|
case base::Value::Type::STRING:
|
|
return "STRING";
|
|
case base::Value::Type::BINARY:
|
|
return "BINARY";
|
|
case base::Value::Type::DICT:
|
|
return "DICTIONARY";
|
|
case base::Value::Type::LIST:
|
|
return "LIST";
|
|
}
|
|
|
|
DCHECK(false);
|
|
return "UNKNOWN";
|
|
}
|
|
|
|
} // namespace
|
|
|
|
bool HasPreference(PrefService* pref_service, const CefString& name) {
|
|
return (pref_service->FindPreference(std::string_view(name.ToString())) !=
|
|
nullptr);
|
|
}
|
|
|
|
CefRefPtr<CefValue> GetPreference(PrefService* pref_service,
|
|
const CefString& name) {
|
|
const PrefService::Preference* pref =
|
|
pref_service->FindPreference(std::string_view(name.ToString()));
|
|
if (!pref) {
|
|
return nullptr;
|
|
}
|
|
return new CefValueImpl(pref->GetValue()->Clone());
|
|
}
|
|
|
|
CefRefPtr<CefDictionaryValue> GetAllPreferences(PrefService* pref_service,
|
|
bool include_defaults) {
|
|
// Returns a DeepCopy of the value.
|
|
auto values = pref_service->GetPreferenceValues(
|
|
include_defaults ? PrefService::INCLUDE_DEFAULTS
|
|
: PrefService::EXCLUDE_DEFAULTS);
|
|
|
|
// CefDictionaryValueImpl takes ownership of |values| contents.
|
|
return new CefDictionaryValueImpl(std::move(values), /*read_only=*/false);
|
|
}
|
|
|
|
bool CanSetPreference(PrefService* pref_service, const CefString& name) {
|
|
const PrefService::Preference* pref =
|
|
pref_service->FindPreference(std::string_view(name.ToString()));
|
|
return (pref && pref->IsUserModifiable());
|
|
}
|
|
|
|
bool SetPreference(PrefService* pref_service,
|
|
const CefString& name,
|
|
CefRefPtr<CefValue> value,
|
|
CefString& error) {
|
|
// The below validation logic should match PrefService::SetUserPrefValue.
|
|
|
|
const PrefService::Preference* pref =
|
|
pref_service->FindPreference(std::string_view(name.ToString()));
|
|
if (!pref) {
|
|
error = "Trying to modify an unregistered preference";
|
|
return false;
|
|
}
|
|
|
|
if (!pref->IsUserModifiable()) {
|
|
error = "Trying to modify a preference that is not user modifiable";
|
|
return false;
|
|
}
|
|
|
|
if (!value.get()) {
|
|
// Reset the preference to its default value.
|
|
pref_service->ClearPref(std::string_view(name.ToString()));
|
|
return true;
|
|
}
|
|
|
|
if (!value->IsValid()) {
|
|
error = "A valid value is required";
|
|
return false;
|
|
}
|
|
|
|
CefValueImpl* impl = static_cast<CefValueImpl*>(value.get());
|
|
|
|
CefValueImpl::ScopedLockedValue scoped_locked_value(impl);
|
|
base::Value* impl_value = impl->GetValueUnsafe();
|
|
|
|
if (pref->GetType() != impl_value->type()) {
|
|
error = base::StringPrintf(
|
|
"Trying to set a preference of type %s to value of type %s",
|
|
GetTypeString(pref->GetType()), GetTypeString(impl_value->type()));
|
|
return false;
|
|
}
|
|
|
|
// PrefService will make a DeepCopy of |impl_value|.
|
|
pref_service->Set(std::string_view(name.ToString()), *impl_value);
|
|
return true;
|
|
}
|
|
|
|
class RegistrationImpl final : public Registration, public CefRegistration {
|
|
public:
|
|
RegistrationImpl(Registrar* registrar,
|
|
const CefString& name,
|
|
CefRefPtr<CefPreferenceObserver> observer)
|
|
: registrar_(registrar), name_(name), observer_(observer) {
|
|
DCHECK(registrar_);
|
|
DCHECK(observer_);
|
|
}
|
|
|
|
RegistrationImpl(const RegistrationImpl&) = delete;
|
|
RegistrationImpl& operator=(const RegistrationImpl&) = delete;
|
|
|
|
~RegistrationImpl() override {
|
|
CEF_REQUIRE_UIT();
|
|
if (registrar_) {
|
|
registrar_->RemoveObserver(name_.ToString(), this);
|
|
}
|
|
}
|
|
|
|
void Detach() override {
|
|
registrar_ = nullptr;
|
|
observer_ = nullptr;
|
|
}
|
|
|
|
void RunCallback() const override { RunCallback(name_); }
|
|
|
|
void RunCallback(const CefString& name) const override {
|
|
observer_->OnPreferenceChanged(name);
|
|
}
|
|
|
|
private:
|
|
raw_ptr<Registrar> registrar_;
|
|
CefString name_;
|
|
CefRefPtr<CefPreferenceObserver> observer_;
|
|
|
|
IMPLEMENT_REFCOUNTING_DELETE_ON_UIT(RegistrationImpl);
|
|
};
|
|
|
|
Registrar::~Registrar() {
|
|
RemoveAll();
|
|
}
|
|
|
|
void Registrar::Init(PrefService* service) {
|
|
DCHECK(service);
|
|
DCHECK(IsEmpty() || service_ == service);
|
|
service_ = service;
|
|
}
|
|
|
|
void Registrar::Reset() {
|
|
RemoveAll();
|
|
service_ = nullptr;
|
|
}
|
|
|
|
void Registrar::RemoveAll() {
|
|
if (!name_observers_.empty()) {
|
|
for (auto& [name, registrations] : name_observers_) {
|
|
service_->RemovePrefObserver(name, this);
|
|
for (auto& registration : registrations) {
|
|
registration.Detach();
|
|
}
|
|
}
|
|
name_observers_.clear();
|
|
}
|
|
|
|
if (!all_observers_.empty()) {
|
|
service_->RemovePrefObserverAllPrefs(this);
|
|
for (auto& registration : all_observers_) {
|
|
registration.Detach();
|
|
}
|
|
all_observers_.Clear();
|
|
}
|
|
}
|
|
|
|
bool Registrar::IsEmpty() const {
|
|
return name_observers_.empty() && all_observers_.empty();
|
|
}
|
|
|
|
CefRefPtr<CefRegistration> Registrar::AddObserver(
|
|
const CefString& name,
|
|
CefRefPtr<CefPreferenceObserver> observer) {
|
|
CHECK(service_);
|
|
|
|
RegistrationImpl* impl = new RegistrationImpl(this, name, observer);
|
|
|
|
if (name.empty()) {
|
|
if (all_observers_.empty()) {
|
|
service_->AddPrefObserverAllPrefs(this);
|
|
}
|
|
all_observers_.AddObserver(impl);
|
|
} else {
|
|
const std::string& name_str = name.ToString();
|
|
if (!name_observers_.contains(name_str)) {
|
|
service_->AddPrefObserver(name_str, this);
|
|
}
|
|
name_observers_[name_str].AddObserver(impl);
|
|
}
|
|
|
|
return impl;
|
|
}
|
|
|
|
void Registrar::RemoveObserver(std::string_view name,
|
|
Registration* registration) {
|
|
CHECK(service_);
|
|
|
|
if (name.empty()) {
|
|
all_observers_.RemoveObserver(registration);
|
|
if (all_observers_.empty()) {
|
|
service_->RemovePrefObserverAllPrefs(this);
|
|
}
|
|
} else {
|
|
auto it = name_observers_.find(std::string(name));
|
|
DCHECK(it != name_observers_.end());
|
|
it->second.RemoveObserver(registration);
|
|
if (it->second.empty()) {
|
|
name_observers_.erase(it);
|
|
service_->RemovePrefObserver(name, this);
|
|
}
|
|
}
|
|
}
|
|
|
|
void Registrar::OnPreferenceChanged(PrefService* service,
|
|
std::string_view pref_name) {
|
|
std::string pref_name_str(pref_name);
|
|
if (!name_observers_.empty()) {
|
|
auto it = name_observers_.find(pref_name_str);
|
|
if (it != name_observers_.end()) {
|
|
for (Registration& registration : it->second) {
|
|
registration.RunCallback();
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!all_observers_.empty()) {
|
|
CefString name_str(pref_name_str);
|
|
for (Registration& registration : all_observers_) {
|
|
registration.RunCallback(name_str);
|
|
}
|
|
}
|
|
}
|
|
|
|
} // namespace pref_helper
|