Support configuration of preferences during runtime (issue #1709)

- Preferences are now associated with a CefRequestContext instead of
  being stored globally.
- Add methods to CefRequestContext for getting/setting preferences.
This commit is contained in:
Marshall Greenblatt 2015-10-02 19:03:16 -04:00
parent 2328b9be39
commit 5780ea8baa
33 changed files with 1760 additions and 35 deletions

View File

@ -428,6 +428,7 @@
'tests/unittests/os_rendering_unittest.cc',
'tests/unittests/parser_unittest.cc',
'tests/unittests/plugin_unittest.cc',
'tests/unittests/preference_unittest.cc',
'tests/unittests/print_unittest.cc',
'tests/unittests/process_message_unittest.cc',
'tests/unittests/request_context_unittest.cc',
@ -1798,6 +1799,7 @@
'tests/unittests/message_router_unittest.cc',
'tests/unittests/navigation_unittest.cc',
'tests/unittests/plugin_unittest.cc',
'tests/unittests/preference_unittest.cc',
'tests/unittests/process_message_unittest.cc',
'tests/unittests/request_handler_unittest.cc',
'tests/unittests/request_unittest.cc',

View File

@ -171,6 +171,8 @@
'tests/cefclient/browser/osr_dragdrop_events.h',
'tests/cefclient/browser/osr_renderer.h',
'tests/cefclient/browser/osr_renderer.cc',
'tests/cefclient/browser/preferences_test.cc',
'tests/cefclient/browser/preferences_test.h',
'tests/cefclient/browser/resource.h',
'tests/cefclient/browser/resource_util.h',
'tests/cefclient/browser/root_window.cc',
@ -220,6 +222,7 @@
'tests/cefclient/resources/pdf.pdf',
'tests/cefclient/resources/performance.html',
'tests/cefclient/resources/performance2.html',
'tests/cefclient/resources/preferences.html',
'tests/cefclient/resources/transparency.html',
'tests/cefclient/resources/urlrequest.html',
'tests/cefclient/resources/window.html',

View File

@ -40,6 +40,7 @@
#include "include/capi/cef_cookie_capi.h"
#include "include/capi/cef_request_context_handler_capi.h"
#include "include/capi/cef_values_capi.h"
#ifdef __cplusplus
extern "C" {
@ -150,6 +151,54 @@ typedef struct _cef_request_context_t {
///
void (CEF_CALLBACK *purge_plugin_list_cache)(
struct _cef_request_context_t* self, int reload_pages);
///
// Returns true (1) if a preference with the specified |name| exists. This
// function must be called on the browser process UI thread.
///
int (CEF_CALLBACK *has_preference)(struct _cef_request_context_t* self,
const cef_string_t* name);
///
// Returns the value for the preference with the specified |name|. Returns
// NULL if the preference does not exist. The returned object contains a copy
// of the underlying preference value and modifications to the returned object
// will not modify the underlying preference value. This function must be
// called on the browser process UI thread.
///
struct _cef_value_t* (CEF_CALLBACK *get_preference)(
struct _cef_request_context_t* self, const cef_string_t* name);
///
// Returns all preferences as a dictionary. If |include_defaults| is true (1)
// then preferences currently at their default value will be included. The
// returned object contains a copy of the underlying preference values and
// modifications to the returned object will not modify the underlying
// preference values. This function must be called on the browser process UI
// thread.
///
struct _cef_dictionary_value_t* (CEF_CALLBACK *get_all_preferences)(
struct _cef_request_context_t* self, int include_defaults);
///
// Returns true (1) if the preference with the specified |name| can be
// modified using SetPreference. As one example preferences set via the
// command-line usually cannot be modified. This function must be called on
// the browser process UI thread.
///
int (CEF_CALLBACK *can_set_preference)(struct _cef_request_context_t* self,
const cef_string_t* name);
///
// Set the |value| associated with preference |name|. Returns true (1) if the
// value is set successfully and false (0) otherwise. If |value| is NULL the
// preference will be restored to its default value. If setting the preference
// fails then |error| will be populated with a detailed description of the
// problem. This function must be called on the browser process UI thread.
///
int (CEF_CALLBACK *set_preference)(struct _cef_request_context_t* self,
const cef_string_t* name, struct _cef_value_t* value,
cef_string_t* error);
} cef_request_context_t;

View File

@ -40,6 +40,7 @@
#include "include/cef_cookie.h"
#include "include/cef_request_context_handler.h"
#include "include/cef_values.h"
class CefSchemeHandlerFactory;
@ -166,6 +167,56 @@ class CefRequestContext : public virtual CefBase {
///
/*--cef()--*/
virtual void PurgePluginListCache(bool reload_pages) =0;
///
// Returns true if a preference with the specified |name| exists. This method
// must be called on the browser process UI thread.
///
/*--cef()--*/
virtual bool HasPreference(const CefString& name) =0;
///
// Returns the value for the preference with the specified |name|. Returns
// NULL if the preference does not exist. The returned object contains a copy
// of the underlying preference value and modifications to the returned object
// will not modify the underlying preference value. This method must be called
// on the browser process UI thread.
///
/*--cef()--*/
virtual CefRefPtr<CefValue> GetPreference(const CefString& name) =0;
///
// Returns all preferences as a dictionary. If |include_defaults| is true then
// preferences currently at their default value will be included. The returned
// object contains a copy of the underlying preference values and
// modifications to the returned object will not modify the underlying
// preference values. This method must be called on the browser process UI
// thread.
///
/*--cef()--*/
virtual CefRefPtr<CefDictionaryValue> GetAllPreferences(
bool include_defaults) =0;
///
// Returns true if the preference with the specified |name| can be modified
// using SetPreference. As one example preferences set via the command-line
// usually cannot be modified. This method must be called on the browser
// process UI thread.
///
/*--cef()--*/
virtual bool CanSetPreference(const CefString& name) =0;
///
// Set the |value| associated with preference |name|. Returns true if the
// value is set successfully and false otherwise. If |value| is NULL the
// preference will be restored to its default value. If setting the preference
// fails then |error| will be populated with a detailed description of the
// problem. This method must be called on the browser process UI thread.
///
/*--cef(optional_param=value)--*/
virtual bool SetPreference(const CefString& name,
CefRefPtr<CefValue> value,
CefString& error) =0;
};
#endif // CEF_INCLUDE_CEF_REQUEST_CONTEXT_H_

View File

@ -7,7 +7,6 @@
#include <map>
#include "libcef/browser/browser_context_proxy.h"
#include "libcef/browser/content_browser_client.h"
#include "libcef/browser/context.h"
#include "libcef/browser/download_manager_delegate.h"
#include "libcef/browser/permission_manager.h"
@ -20,6 +19,7 @@
#include "base/files/file_util.h"
#include "base/lazy_instance.h"
#include "base/logging.h"
#include "base/prefs/pref_service.h"
#include "base/strings/string_util.h"
#include "base/threading/thread_restrictions.h"
#include "chrome/browser/net/proxy_service_factory.h"
@ -166,6 +166,11 @@ void CefBrowserContextImpl::Initialize() {
CefString(&CefContext::Get()->settings().accept_language_list);
}
// Initialize user preferences.
pref_store_ = new CefBrowserPrefStore();
pref_store_->SetInitializationCompleted();
pref_service_ = pref_store_->CreateService().Pass();
CefBrowserContext::Initialize();
// Initialize proxy configuration tracker.
@ -378,6 +383,5 @@ HostContentSettingsMap* CefBrowserContextImpl::GetHostContentSettingsMap() {
}
PrefService* CefBrowserContextImpl::GetPrefs() {
// TODO(cef): Perhaps use per-context settings.
return CefContentBrowserClient::Get()->pref_service();
return pref_service_.get();
}

View File

@ -8,6 +8,7 @@
#include "libcef/browser/browser_context.h"
#include "libcef/browser/browser_pref_store.h"
#include "libcef/browser/url_request_context_getter_impl.h"
#include "base/files/file_path.h"
@ -111,6 +112,8 @@ class CefBrowserContextImpl : public CefBrowserContext {
typedef std::vector<const CefBrowserContextProxy*> ProxyList;
ProxyList proxy_list_;
scoped_refptr<CefBrowserPrefStore> pref_store_;
scoped_ptr<PrefService> pref_service_;
scoped_ptr<PrefProxyConfigTracker> pref_proxy_config_tracker_;
scoped_ptr<CefDownloadManagerDelegate> download_manager_delegate_;

View File

@ -122,11 +122,6 @@ int CefBrowserMainParts::PreCreateThreads() {
views::CreateDesktopScreen());
#endif
// Initialize user preferences.
pref_store_ = new CefBrowserPrefStore();
pref_store_->SetInitializationCompleted();
pref_service_ = pref_store_->CreateService().Pass();
return 0;
}

View File

@ -6,7 +6,6 @@
#define CEF_LIBCEF_BROWSER_BROWSER_MAIN_H_
#pragma once
#include "libcef/browser/browser_pref_store.h"
#include "libcef/browser/browser_context_impl.h"
#include "libcef/browser/url_request_context_getter_impl.h"
@ -54,7 +53,6 @@ class CefBrowserMainParts : public content::BrowserMainParts {
CefDevToolsDelegate* devtools_delegate() const {
return devtools_delegate_;
}
PrefService* pref_service() const { return pref_service_.get(); }
private:
#if defined(OS_WIN)
@ -65,8 +63,6 @@ class CefBrowserMainParts : public content::BrowserMainParts {
scoped_refptr<CefBrowserContextImpl> global_browser_context_;
CefDevToolsDelegate* devtools_delegate_; // Deletes itself.
scoped_ptr<base::MessageLoop> message_loop_;
scoped_refptr<CefBrowserPrefStore> pref_store_;
scoped_ptr<PrefService> pref_service_;
scoped_ptr<extensions::ExtensionsClient> extensions_client_;
scoped_ptr<extensions::ExtensionsBrowserClient> extensions_browser_client_;

View File

@ -129,6 +129,16 @@ scoped_ptr<PrefService> CefBrowserPrefStore::CreateService() {
registry->RegisterBooleanPref(prefs::kPluginsAllowOutdated, false);
registry->RegisterBooleanPref(prefs::kPluginsAlwaysAuthorize, false);
if (command_line->HasSwitch(switches::kEnablePreferenceTesting)) {
// Register preferences used with unit tests.
registry->RegisterBooleanPref("test.bool", true);
registry->RegisterIntegerPref("test.int", 2);
registry->RegisterDoublePref("test.double", 5.0);
registry->RegisterStringPref("test.string", "default");
registry->RegisterListPref("test.list");
registry->RegisterDictionaryPref("test.dict");
}
return factory.Create(registry.get());
}

View File

@ -1034,10 +1034,6 @@ CefDevToolsDelegate* CefContentBrowserClient::devtools_delegate() const {
return browser_main_parts_->devtools_delegate();
}
PrefService* CefContentBrowserClient::pref_service() const {
return browser_main_parts_->pref_service();
}
// static
SkColor CefContentBrowserClient::GetBaseBackgroundColor(
CefRefPtr<CefBrowserHostImpl> browser) {

View File

@ -29,7 +29,6 @@ class CefBrowserInfo;
class CefBrowserMainParts;
class CefDevToolsDelegate;
class CefResourceDispatcherHostDelegate;
class PrefService;
namespace content {
class PluginServiceFilter;
@ -167,7 +166,6 @@ class CefContentBrowserClient : public content::ContentBrowserClient {
scoped_refptr<CefBrowserContextImpl> browser_context() const;
CefDevToolsDelegate* devtools_delegate() const;
PrefService* pref_service() const;
private:
static SkColor GetBaseBackgroundColor(CefRefPtr<CefBrowserHostImpl> browser);

View File

@ -124,7 +124,7 @@ bool CefExtensionsBrowserClient::AllowCrossRendererResourceLoad(
PrefService* CefExtensionsBrowserClient::GetPrefServiceForContext(
BrowserContext* context) {
return CefBrowserContextImpl::GetForContext(context)->GetPrefs();
return static_cast<CefBrowserContext*>(context)->GetPrefs();
}
void CefExtensionsBrowserClient::GetEarlyExtensionPrefsObservers(

View File

@ -182,8 +182,8 @@ CefPluginInfoMessageFilter::CefPluginInfoMessageFilter(
int render_process_id,
CefBrowserContext* profile)
: BrowserMessageFilter(ExtensionMsgStart),
context_(render_process_id, profile),
browser_context_(profile),
context_(render_process_id, profile),
main_thread_task_runner_(base::ThreadTaskRunnerHandle::Get()),
weak_ptr_factory_(this) {
}

View File

@ -121,8 +121,12 @@ class CefPluginInfoMessageFilter : public content::BrowserMessageFilter {
std::vector<base::string16>* additional_param_values);
#endif
scoped_refptr<CefBrowserContext> browser_context_;
// Members will be destroyed in reverse order of declaration. Due to Context
// depending on the PrefService owned by CefBrowserContext the Context object
// must be destroyed before the CefBrowserContext object.
Context context_;
CefBrowserContext* browser_context_;
scoped_refptr<base::SingleThreadTaskRunner> main_thread_task_runner_;
base::WeakPtrFactory<CefPluginInfoMessageFilter> weak_ptr_factory_;

View File

@ -47,9 +47,12 @@ PrintViewManagerBase::PrintViewManagerBase(content::WebContents* web_contents)
#if !defined(OS_MACOSX)
expecting_first_page_ = true;
#endif // OS_MACOSX
PrefService* pref_service =
static_cast<CefBrowserContext*>(web_contents->GetBrowserContext())->
GetPrefs();
printing_enabled_.Init(
prefs::kPrintingEnabled,
CefContentBrowserClient::Get()->pref_service(),
pref_service,
base::Bind(&PrintViewManagerBase::UpdateScriptedPrintingBlocked,
base::Unretained(this)));
}

View File

@ -9,9 +9,12 @@
#include "libcef/browser/context.h"
#include "libcef/browser/cookie_manager_impl.h"
#include "libcef/browser/thread_util.h"
#include "libcef/common/values_impl.h"
#include "base/atomic_sequence_num.h"
#include "base/logging.h"
#include "base/prefs/pref_service.h"
#include "base/strings/stringprintf.h"
#include "content/public/browser/plugin_service.h"
using content::BrowserThread;
@ -20,6 +23,30 @@ namespace {
base::StaticAtomicSequenceNumber g_next_id;
const char* GetTypeString(base::Value::Type type) {
switch (type) {
case base::Value::TYPE_NULL:
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_DICTIONARY:
return "DICTIONARY";
case base::Value::TYPE_LIST:
return "LIST";
}
NOTREACHED();
return "UNKNOWN";
}
} // namespace
@ -292,6 +319,131 @@ void CefRequestContextImpl::PurgePluginListCache(bool reload_pages) {
this, reload_pages));
}
bool CefRequestContextImpl::HasPreference(const CefString& name) {
// Verify that this method is being called on the UI thread.
if (!CEF_CURRENTLY_ON_UIT()) {
NOTREACHED() << "called on invalid thread";
return false;
}
// Make sure the browser context exists.
EnsureBrowserContext();
PrefService* pref_service = browser_context_->GetPrefs();
return (pref_service->FindPreference(name) != NULL);
}
CefRefPtr<CefValue> CefRequestContextImpl::GetPreference(
const CefString& name) {
// Verify that this method is being called on the UI thread.
if (!CEF_CURRENTLY_ON_UIT()) {
NOTREACHED() << "called on invalid thread";
return NULL;
}
// Make sure the browser context exists.
EnsureBrowserContext();
PrefService* pref_service = browser_context_->GetPrefs();
const PrefService::Preference* pref = pref_service->FindPreference(name);
if (!pref)
return NULL;
return new CefValueImpl(pref->GetValue()->DeepCopy());
}
CefRefPtr<CefDictionaryValue> CefRequestContextImpl::GetAllPreferences(
bool include_defaults) {
// Verify that this method is being called on the UI thread.
if (!CEF_CURRENTLY_ON_UIT()) {
NOTREACHED() << "called on invalid thread";
return NULL;
}
// Make sure the browser context exists.
EnsureBrowserContext();
PrefService* pref_service = browser_context_->GetPrefs();
scoped_ptr<base::DictionaryValue> values;
if (include_defaults)
values = pref_service->GetPreferenceValues();
else
values = pref_service->GetPreferenceValuesOmitDefaults();
// CefDictionaryValueImpl takes ownership of |values|.
return new CefDictionaryValueImpl(values.release(), true, false);
}
bool CefRequestContextImpl::CanSetPreference(const CefString& name) {
// Verify that this method is being called on the UI thread.
if (!CEF_CURRENTLY_ON_UIT()) {
NOTREACHED() << "called on invalid thread";
return false;
}
// Make sure the browser context exists.
EnsureBrowserContext();
PrefService* pref_service = browser_context_->GetPrefs();
const PrefService::Preference* pref = pref_service->FindPreference(name);
return (pref && pref->IsUserModifiable());
}
bool CefRequestContextImpl::SetPreference(const CefString& name,
CefRefPtr<CefValue> value,
CefString& error) {
// Verify that this method is being called on the UI thread.
if (!CEF_CURRENTLY_ON_UIT()) {
NOTREACHED() << "called on invalid thread";
return false;
}
// Make sure the browser context exists.
EnsureBrowserContext();
PrefService* pref_service = browser_context_->GetPrefs();
// The below validation logic should match PrefService::SetUserPrefValue.
const PrefService::Preference* pref = pref_service->FindPreference(name);
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(name);
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->GetType()) {
error = base::StringPrintf(
"Trying to set a preference of type %s to value of type %s",
GetTypeString(pref->GetType()), GetTypeString(impl_value->GetType()));
return false;
}
// PrefService will make a DeepCopy of |impl_value|.
pref_service->Set(name, *impl_value);
return true;
}
CefRequestContextImpl::CefRequestContextImpl(
scoped_refptr<CefBrowserContext> browser_context)
: browser_context_(browser_context),
@ -319,6 +471,12 @@ CefRequestContextImpl::CefRequestContextImpl(
request_context_impl_(NULL) {
}
void CefRequestContextImpl::EnsureBrowserContext() {
GetBrowserContext();
DCHECK(browser_context_.get());
DCHECK(request_context_impl_);
}
void CefRequestContextImpl::GetBrowserContextOnUIThread(
scoped_refptr<base::SingleThreadTaskRunner> task_runner,
const BrowserContextCallback& callback) {
@ -330,9 +488,7 @@ void CefRequestContextImpl::GetBrowserContextOnUIThread(
}
// Make sure the browser context exists.
GetBrowserContext();
DCHECK(browser_context_.get());
DCHECK(request_context_impl_);
EnsureBrowserContext();
if (task_runner->BelongsToCurrentThread()) {
// Execute the callback immediately.

View File

@ -61,6 +61,14 @@ class CefRequestContextImpl : public CefRequestContext {
CefRefPtr<CefSchemeHandlerFactory> factory) override;
bool ClearSchemeHandlerFactories() override;
void PurgePluginListCache(bool reload_pages) override;
bool HasPreference(const CefString& name) override;
CefRefPtr<CefValue> GetPreference(const CefString& name) override;
CefRefPtr<CefDictionaryValue> GetAllPreferences(
bool include_defaults) override;
bool CanSetPreference(const CefString& name) override;
bool SetPreference(const CefString& name,
CefRefPtr<CefValue> value,
CefString& error) override;
const CefRequestContextSettings& settings() const { return settings_; }
@ -74,6 +82,9 @@ class CefRequestContextImpl : public CefRequestContext {
CefRequestContextImpl(CefRefPtr<CefRequestContextImpl> other,
CefRefPtr<CefRequestContextHandler> handler);
// Make sure the browser context exists. Only called on the UI thread.
void EnsureBrowserContext();
void GetBrowserContextOnUIThread(
scoped_refptr<base::SingleThreadTaskRunner> task_runner,
const BrowserContextCallback& callback);

View File

@ -126,4 +126,7 @@ const char kPluginPolicy_Detect[] = "detect";
// Block the content. The user can manually load blocked content.
const char kPluginPolicy_Block[] = "block";
// Expose preferences used only by unit tests.
const char kEnablePreferenceTesting[] = "enable-preference-testing";
} // namespace switches

View File

@ -52,6 +52,7 @@ extern const char kPluginPolicy[];
extern const char kPluginPolicy_Allow[];
extern const char kPluginPolicy_Detect[];
extern const char kPluginPolicy_Block[];
extern const char kEnablePreferenceTesting[];
} // namespace switches

View File

@ -49,6 +49,10 @@ class CefValueImpl : public CefValue {
bool new_read_only,
CefValueController* new_controller);
// Returns a reference to the underlying data. Access must be protected by
// calling AcquireLock/ReleaseLock.
base::Value* GetValueUnsafe() const;
// CefValue methods.
bool IsValid() override;
bool IsOwned() override;
@ -104,10 +108,6 @@ class CefValueImpl : public CefValue {
void AcquireLock();
void ReleaseLock();
// Returns a reference to the underlying data. Access must be protected by
// calling AcquireLock/ReleaseLock.
base::Value* GetValueUnsafe() const;
// Access to all members must be protected by |lock_|.
base::Lock lock_;

View File

@ -11,7 +11,9 @@
//
#include "libcef_dll/cpptoc/cookie_manager_cpptoc.h"
#include "libcef_dll/cpptoc/dictionary_value_cpptoc.h"
#include "libcef_dll/cpptoc/request_context_cpptoc.h"
#include "libcef_dll/cpptoc/value_cpptoc.h"
#include "libcef_dll/ctocpp/completion_callback_ctocpp.h"
#include "libcef_dll/ctocpp/request_context_handler_ctocpp.h"
#include "libcef_dll/ctocpp/scheme_handler_factory_ctocpp.h"
@ -239,6 +241,115 @@ void CEF_CALLBACK request_context_purge_plugin_list_cache(
reload_pages?true:false);
}
int CEF_CALLBACK request_context_has_preference(
struct _cef_request_context_t* self, const cef_string_t* name) {
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
DCHECK(self);
if (!self)
return 0;
// Verify param: name; type: string_byref_const
DCHECK(name);
if (!name)
return 0;
// Execute
bool _retval = CefRequestContextCppToC::Get(self)->HasPreference(
CefString(name));
// Return type: bool
return _retval;
}
struct _cef_value_t* CEF_CALLBACK request_context_get_preference(
struct _cef_request_context_t* self, const cef_string_t* name) {
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
DCHECK(self);
if (!self)
return NULL;
// Verify param: name; type: string_byref_const
DCHECK(name);
if (!name)
return NULL;
// Execute
CefRefPtr<CefValue> _retval = CefRequestContextCppToC::Get(
self)->GetPreference(
CefString(name));
// Return type: refptr_same
return CefValueCppToC::Wrap(_retval);
}
struct _cef_dictionary_value_t* CEF_CALLBACK request_context_get_all_preferences(
struct _cef_request_context_t* self, int include_defaults) {
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
DCHECK(self);
if (!self)
return NULL;
// Execute
CefRefPtr<CefDictionaryValue> _retval = CefRequestContextCppToC::Get(
self)->GetAllPreferences(
include_defaults?true:false);
// Return type: refptr_same
return CefDictionaryValueCppToC::Wrap(_retval);
}
int CEF_CALLBACK request_context_can_set_preference(
struct _cef_request_context_t* self, const cef_string_t* name) {
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
DCHECK(self);
if (!self)
return 0;
// Verify param: name; type: string_byref_const
DCHECK(name);
if (!name)
return 0;
// Execute
bool _retval = CefRequestContextCppToC::Get(self)->CanSetPreference(
CefString(name));
// Return type: bool
return _retval;
}
int CEF_CALLBACK request_context_set_preference(
struct _cef_request_context_t* self, const cef_string_t* name,
struct _cef_value_t* value, cef_string_t* error) {
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
DCHECK(self);
if (!self)
return 0;
// Verify param: name; type: string_byref_const
DCHECK(name);
if (!name)
return 0;
// Verify param: error; type: string_byref
DCHECK(error);
if (!error)
return 0;
// Unverified params: value
// Translate param: error; type: string_byref
CefString errorStr(error);
// Execute
bool _retval = CefRequestContextCppToC::Get(self)->SetPreference(
CefString(name),
CefValueCppToC::Unwrap(value),
errorStr);
// Return type: bool
return _retval;
}
} // namespace
@ -258,6 +369,11 @@ CefRequestContextCppToC::CefRequestContextCppToC() {
request_context_clear_scheme_handler_factories;
GetStruct()->purge_plugin_list_cache =
request_context_purge_plugin_list_cache;
GetStruct()->has_preference = request_context_has_preference;
GetStruct()->get_preference = request_context_get_preference;
GetStruct()->get_all_preferences = request_context_get_all_preferences;
GetStruct()->can_set_preference = request_context_can_set_preference;
GetStruct()->set_preference = request_context_set_preference;
}
template<> CefRefPtr<CefRequestContext> CefCppToC<CefRequestContextCppToC,

View File

@ -14,7 +14,9 @@
#include "libcef_dll/cpptoc/request_context_handler_cpptoc.h"
#include "libcef_dll/cpptoc/scheme_handler_factory_cpptoc.h"
#include "libcef_dll/ctocpp/cookie_manager_ctocpp.h"
#include "libcef_dll/ctocpp/dictionary_value_ctocpp.h"
#include "libcef_dll/ctocpp/request_context_ctocpp.h"
#include "libcef_dll/ctocpp/value_ctocpp.h"
// STATIC METHODS - Body may be edited by hand.
@ -222,6 +224,107 @@ void CefRequestContextCToCpp::PurgePluginListCache(bool reload_pages) {
reload_pages);
}
bool CefRequestContextCToCpp::HasPreference(const CefString& name) {
cef_request_context_t* _struct = GetStruct();
if (CEF_MEMBER_MISSING(_struct, has_preference))
return false;
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
// Verify param: name; type: string_byref_const
DCHECK(!name.empty());
if (name.empty())
return false;
// Execute
int _retval = _struct->has_preference(_struct,
name.GetStruct());
// Return type: bool
return _retval?true:false;
}
CefRefPtr<CefValue> CefRequestContextCToCpp::GetPreference(
const CefString& name) {
cef_request_context_t* _struct = GetStruct();
if (CEF_MEMBER_MISSING(_struct, get_preference))
return NULL;
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
// Verify param: name; type: string_byref_const
DCHECK(!name.empty());
if (name.empty())
return NULL;
// Execute
cef_value_t* _retval = _struct->get_preference(_struct,
name.GetStruct());
// Return type: refptr_same
return CefValueCToCpp::Wrap(_retval);
}
CefRefPtr<CefDictionaryValue> CefRequestContextCToCpp::GetAllPreferences(
bool include_defaults) {
cef_request_context_t* _struct = GetStruct();
if (CEF_MEMBER_MISSING(_struct, get_all_preferences))
return NULL;
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
// Execute
cef_dictionary_value_t* _retval = _struct->get_all_preferences(_struct,
include_defaults);
// Return type: refptr_same
return CefDictionaryValueCToCpp::Wrap(_retval);
}
bool CefRequestContextCToCpp::CanSetPreference(const CefString& name) {
cef_request_context_t* _struct = GetStruct();
if (CEF_MEMBER_MISSING(_struct, can_set_preference))
return false;
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
// Verify param: name; type: string_byref_const
DCHECK(!name.empty());
if (name.empty())
return false;
// Execute
int _retval = _struct->can_set_preference(_struct,
name.GetStruct());
// Return type: bool
return _retval?true:false;
}
bool CefRequestContextCToCpp::SetPreference(const CefString& name,
CefRefPtr<CefValue> value, CefString& error) {
cef_request_context_t* _struct = GetStruct();
if (CEF_MEMBER_MISSING(_struct, set_preference))
return false;
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
// Verify param: name; type: string_byref_const
DCHECK(!name.empty());
if (name.empty())
return false;
// Unverified params: value
// Execute
int _retval = _struct->set_preference(_struct,
name.GetStruct(),
CefValueCToCpp::Unwrap(value),
error.GetWritableStruct());
// Return type: bool
return _retval?true:false;
}
// CONSTRUCTOR - Do not edit by hand.

View File

@ -45,6 +45,13 @@ class CefRequestContextCToCpp
CefRefPtr<CefSchemeHandlerFactory> factory) OVERRIDE;
bool ClearSchemeHandlerFactories() OVERRIDE;
void PurgePluginListCache(bool reload_pages) OVERRIDE;
bool HasPreference(const CefString& name) OVERRIDE;
CefRefPtr<CefValue> GetPreference(const CefString& name) OVERRIDE;
CefRefPtr<CefDictionaryValue> GetAllPreferences(
bool include_defaults) OVERRIDE;
bool CanSetPreference(const CefString& name) OVERRIDE;
bool SetPreference(const CefString& name, CefRefPtr<CefValue> value,
CefString& error) OVERRIDE;
};
#endif // USING_CEF_SHARED

View File

@ -0,0 +1,332 @@
// Copyright (c) 2015 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 "cefclient/browser/preferences_test.h"
#include <sstream>
#include <string>
#include <vector>
#include "include/base/cef_logging.h"
#include "include/cef_command_line.h"
#include "include/cef_parser.h"
namespace client {
namespace preferences_test {
namespace {
const char kTestUrl[] = "http://tests/preferences";
// Application-specific error codes.
const int kMessageFormatError = 1;
const int kPreferenceApplicationError = 1;
// Common to all messages.
const char kNameKey[] = "name";
const char kNameValueGet[] = "preferences_get";
const char kNameValueSet[] = "preferences_set";
const char kNameValueState[] = "preferences_state";
// Used with "preferences_get" messages.
const char kIncludeDefaultsKey[] = "include_defaults";
// Used with "preferences_set" messages.
const char kPreferencesKey[] = "preferences";
// Handle messages in the browser process. Only accessed on the UI thread.
class Handler : public CefMessageRouterBrowserSide::Handler {
public:
typedef std::vector<std::string> NameVector;
Handler() {
CEF_REQUIRE_UI_THREAD();
}
// Called due to cefQuery execution in preferences.html.
bool OnQuery(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
int64 query_id,
const CefString& request,
bool persistent,
CefRefPtr<Callback> callback) OVERRIDE {
CEF_REQUIRE_UI_THREAD();
// Only handle messages from the test URL.
std::string url = frame->GetURL();
if (url.find(kTestUrl) != 0)
return false;
// Parse |request| as a JSON dictionary.
CefRefPtr<CefDictionaryValue> request_dict = ParseJSON(request);
if (!request_dict) {
callback->Failure(kMessageFormatError, "Incorrect message format");
return true;
}
// Verify the "name" key.
if (!VerifyKey(request_dict, kNameKey, VTYPE_STRING, callback))
return true;
const std::string& message_name = request_dict->GetString(kNameKey);
if (message_name == kNameValueGet) {
// JavaScript is requesting a JSON representation of the preferences tree.
// Verify the "include_defaults" key.
if (!VerifyKey(request_dict, kIncludeDefaultsKey, VTYPE_BOOL, callback))
return true;
const bool include_defaults = request_dict->GetBool(kIncludeDefaultsKey);
OnPreferencesGet(browser, include_defaults, callback);
return true;
} else if (message_name == kNameValueSet) {
// JavaScript is requesting that preferences be updated to match the
// specified JSON representation.
// Verify the "preferences" key.
if (!VerifyKey(request_dict, kPreferencesKey, VTYPE_DICTIONARY, callback))
return true;
CefRefPtr<CefDictionaryValue> preferences =
request_dict->GetDictionary(kPreferencesKey);
OnPreferencesSet(browser, preferences, callback);
return true;
} else if (message_name == kNameValueState) {
// JavaScript is requesting global state information.
OnPreferencesState(browser, callback);
return true;
}
return false;
}
private:
// Execute |callback| with the preferences dictionary as a JSON string.
static void OnPreferencesGet(CefRefPtr<CefBrowser> browser,
bool include_defaults,
CefRefPtr<Callback> callback) {
CefRefPtr<CefRequestContext> context =
browser->GetHost()->GetRequestContext();
// Retrieve all preference values.
CefRefPtr<CefDictionaryValue> prefs =
context->GetAllPreferences(include_defaults);
// Serialize the preferences to JSON and return to the JavaScript caller.
callback->Success(GetJSON(prefs));
}
// Set preferences based on the contents of |preferences|. Execute |callback|
// with a descriptive result message.
static void OnPreferencesSet(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefDictionaryValue> preferences,
CefRefPtr<Callback> callback) {
CefRefPtr<CefRequestContext> context =
browser->GetHost()->GetRequestContext();
CefRefPtr<CefValue> value = CefValue::Create();
value->SetDictionary(preferences);
std::string error;
NameVector changed_names;
// Apply preferences. This may result in errors.
const bool success = ApplyPrefs(context, std::string(), value, error,
changed_names);
// Create a message that accurately represents the result.
std::string message;
if (!changed_names.empty()) {
std::stringstream ss;
ss << "Successfully changed " << changed_names.size() <<
" preferences; ";
for (size_t i = 0; i < changed_names.size(); ++i) {
ss << changed_names[i];
if (i < changed_names.size() - 1)
ss << ", ";
}
message = ss.str();
}
if (!success) {
DCHECK(!error.empty());
if (!message.empty())
message += "\n";
message += error;
}
if (changed_names.empty()) {
if (!message.empty())
message += "\n";
message += "No preferences changed.";
}
// Return the message to the JavaScript caller.
if (success)
callback->Success(message);
else
callback->Failure(kPreferenceApplicationError, message);
}
// Execute |callback| with the global state dictionary as a JSON string.
static void OnPreferencesState(CefRefPtr<CefBrowser> browser,
CefRefPtr<Callback> callback) {
CefRefPtr<CefCommandLine> command_line =
CefCommandLine::GetGlobalCommandLine();
CefRefPtr<CefDictionaryValue> dict = CefDictionaryValue::Create();
// If spell checking is disabled via the command-line then it cannot be
// enabled via preferences.
dict->SetBool("spellcheck_disabled",
command_line->HasSwitch("disable-spell-checking"));
// If proxy settings are configured via the command-line then they cannot
// be modified via preferences.
dict->SetBool("proxy_configured",
command_line->HasSwitch("no-proxy-server") ||
command_line->HasSwitch("proxy-auto-detect") ||
command_line->HasSwitch("proxy-pac-url") ||
command_line->HasSwitch("proxy-server"));
// Serialize the state to JSON and return to the JavaScript caller.
callback->Success(GetJSON(dict));
}
// Convert a JSON string to a dictionary value.
static CefRefPtr<CefDictionaryValue> ParseJSON(const CefString& string) {
CefRefPtr<CefValue> value = CefParseJSON(string, JSON_PARSER_RFC);
if (value.get() && value->GetType() == VTYPE_DICTIONARY)
return value->GetDictionary();
return NULL;
}
// Convert a dictionary value to a JSON string.
static CefString GetJSON(CefRefPtr<CefDictionaryValue> dictionary) {
CefRefPtr<CefValue> value = CefValue::Create();
value->SetDictionary(dictionary);
return CefWriteJSON(value, JSON_WRITER_DEFAULT);
}
// Verify that |key| exists in |dictionary| and has type |value_type|. Fails
// |callback| and returns false on failure.
static bool VerifyKey(CefRefPtr<CefDictionaryValue> dictionary,
const char* key,
cef_value_type_t value_type,
CefRefPtr<Callback> callback) {
if (!dictionary->HasKey(key) || dictionary->GetType(key) != value_type) {
callback->Failure(kMessageFormatError,
"Missing or incorrectly formatted message key: " +
std::string(key));
return false;
}
return true;
}
// Apply preferences. Returns true on success. Returns false and sets |error|
// to a descriptive error string on failure. |changed_names| is the list of
// preferences that were successfully changed.
static bool ApplyPrefs(CefRefPtr<CefRequestContext> context,
const std::string& name,
CefRefPtr<CefValue> value,
std::string& error,
NameVector& changed_names) {
if (!name.empty() && context->HasPreference(name)) {
// The preference exists. Set the value.
return SetPref(context, name, value, error, changed_names);
}
if (value->GetType() == VTYPE_DICTIONARY) {
// A dictionary type value that is not an existing preference. Try to set
// each of the elements individually.
CefRefPtr<CefDictionaryValue> dict = value->GetDictionary();
CefDictionaryValue::KeyList keys;
dict->GetKeys(keys);
for (size_t i = 0; i < keys.size(); ++i) {
const std::string& key = keys[i];
const std::string& current_name =
name.empty() ? key : name + "." + key;
if (!ApplyPrefs(context, current_name, dict->GetValue(key), error,
changed_names)) {
return false;
}
}
return true;
}
error = "Trying to create an unregistered preference: " + name;
return false;
}
// Set a specific preference value. Returns true if the value is set
// successfully or has not changed. If the value has changed then |name| will
// be added to |changed_names|. Returns false and sets |error| to a
// descriptive error string on failure.
static bool SetPref(CefRefPtr<CefRequestContext> context,
const std::string& name,
CefRefPtr<CefValue> value,
std::string& error,
NameVector& changed_names) {
CefRefPtr<CefValue> existing_value = context->GetPreference(name);
DCHECK(existing_value);
if (value->GetType() == VTYPE_STRING &&
existing_value->GetType() != VTYPE_STRING) {
// Since |value| is coming from JSON all basic types will be represented
// as strings. Convert to the expected data type.
const std::string& string_val = value->GetString();
switch (existing_value->GetType()) {
case VTYPE_BOOL:
if (string_val == "true" || string_val == "1")
value->SetBool(true);
else if (string_val == "false" || string_val == "0")
value->SetBool(false);
break;
case VTYPE_INT:
value->SetInt(atoi(string_val.c_str()));
break;
case VTYPE_DOUBLE:
value->SetInt(atof(string_val.c_str()));
break;
default:
// Other types cannot be converted.
break;
}
}
// Nothing to do if the value hasn't changed.
if (existing_value->IsEqual(value))
return true;
// Attempt to set the preference.
CefString error_str;
if (!context->SetPreference(name, value, error_str)) {
error = error_str.ToString() + ": " + name;
return false;
}
// The preference was set successfully.
changed_names.push_back(name);
return true;
}
DISALLOW_COPY_AND_ASSIGN(Handler);
};
} // namespace
void CreateMessageHandlers(test_runner::MessageHandlerSet& handlers) {
handlers.insert(new Handler());
}
} // namespace preferences_test
} // namespace client

View File

@ -0,0 +1,20 @@
// Copyright (c) 2015 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.
#ifndef CEF_TESTS_CEFCLIENT_BROWSER_PREFERENCES_TEST_H_
#define CEF_TESTS_CEFCLIENT_BROWSER_PREFERENCES_TEST_H_
#pragma once
#include "cefclient/browser/test_runner.h"
namespace client {
namespace preferences_test {
// Create message handlers. Called from test_runner.cc.
void CreateMessageHandlers(test_runner::MessageHandlerSet& handlers);
} // namespace preferences_test
} // namespace client
#endif // CEF_TESTS_CEFCLIENT_BROWSER_PREFERENCES_TEST_H_

View File

@ -53,10 +53,11 @@
#define IDS_PDF_PDF 1007
#define IDS_PERFORMANCE_HTML 1008
#define IDS_PERFORMANCE2_HTML 1009
#define IDS_TRANSPARENCY_HTML 1010
#define IDS_URLREQUEST_HTML 1011
#define IDS_WINDOW_HTML 1012
#define IDS_XMLHTTPREQUEST_HTML 1013
#define IDS_PREFERENCES_HTML 1010
#define IDS_TRANSPARENCY_HTML 1011
#define IDS_URLREQUEST_HTML 1012
#define IDS_WINDOW_HTML 1013
#define IDS_XMLHTTPREQUEST_HTML 1014
// Next default values for new objects
//

View File

@ -47,6 +47,7 @@ int GetResourceId(const char* resource_name) {
{"pdf.pdf", IDS_PDF_PDF},
{"performance.html", IDS_PERFORMANCE_HTML},
{"performance2.html", IDS_PERFORMANCE2_HTML},
{"preferences.html", IDS_PREFERENCES_HTML},
{"transparency.html", IDS_TRANSPARENCY_HTML},
{"urlrequest.html", IDS_URLREQUEST_HTML},
{"window.html", IDS_WINDOW_HTML},

View File

@ -16,6 +16,7 @@
#include "cefclient/browser/binding_test.h"
#include "cefclient/browser/dialog_test.h"
#include "cefclient/browser/main_context.h"
#include "cefclient/browser/preferences_test.h"
#include "cefclient/browser/resource.h"
#include "cefclient/browser/resource_util.h"
#include "cefclient/browser/root_window_manager.h"
@ -663,6 +664,12 @@ std::string GetErrorString(cef_errorcode_t code) {
}
void SetupResourceManager(CefRefPtr<CefResourceManager> resource_manager) {
if (!CefCurrentlyOn(TID_IO)) {
// Execute on the browser IO thread.
CefPostTask(TID_IO, base::Bind(SetupResourceManager, resource_manager));
return;
}
const std::string& test_origin = kTestOrigin;
// Add the URL filter.
@ -701,11 +708,14 @@ void Alert(CefRefPtr<CefBrowser> browser, const std::string& message) {
void CreateMessageHandlers(MessageHandlerSet& handlers) {
handlers.insert(new PromptHandler);
// Create the binding test handlers.
binding_test::CreateMessageHandlers(handlers);
// Create the dialog test handlers.
dialog_test::CreateMessageHandlers(handlers);
// Create the binding test handlers.
binding_test::CreateMessageHandlers(handlers);
// Create the preferences test handlers.
preferences_test::CreateMessageHandlers(handlers);
// Create the urlrequest test handlers.
urlrequest_test::CreateMessageHandlers(handlers);

View File

@ -21,6 +21,7 @@
<li><a href="http://tests/localstorage">Local Storage</a></li>
<li><a href="http://tests/pdf.pdf">PDF Viewer direct</a></li>
<li><a href="http://tests/pdf">PDF Viewer iframe</a></li>
<li><a href="http://tests/preferences">Preferences</a></li>
<li><a href="http://mrdoob.com/lab/javascript/requestanimationframe/">requestAnimationFrame</a></li>
<li><a href="client://tests/handler.html">Scheme Handler</a></li>
<li><a href="https://www.google.com/intl/en/chrome/demos/speech.html">Speech Input</a> - requires "enable-speech-input" flag</li>

View File

@ -0,0 +1,290 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Preferences Test</title>
<!-- When using the mode "code" it's important to specify charset utf-8 -->
<meta http-equiv="Content-Type" content="text/html;charset=utf-8">
<!-- jsoneditor project from https://github.com/josdejong/jsoneditor/
script hosting from http://cdnjs.com/libraries/jsoneditor -->
<link href="https://cdnjs.cloudflare.com/ajax/libs/jsoneditor/4.2.1/jsoneditor.min.css" rel="stylesheet" type="text/css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jsoneditor/4.2.1/jsoneditor.min.js"></script>
</head>
<body bgcolor="white">
<!-- Header -->
<div id="simple_links">
[ <b>Simple</b> ]
[ <a href="#" onClick="toggleView(); return false;">Advanced</a> ]
</div>
<div id="advanced_links" style="display:none">
[ <a href="#" onClick="toggleView(); return false;">Simple</a> ]
[ <b>Advanced</b> ]
</div>
<!-- Simple view -->
<div id="simple">
<p>
This page supports display and configuration of a few sample preferences.
<table width="100%" style="border: 1px solid #97B0F8">
<tr>
<td>
<input type="checkbox" id="enable_spellchecking"/> Enable spell checking
</td>
</tr>
<tr>
<td>
<br/>
Proxy type:
<select id="proxy_type" onChange="proxyTypeChange()">
<option value="direct">Direct</option>
<option value="auto_detect">Auto-Detect</option>
<option value="pac_script">PAC Script</option>
<option value="fixed_servers">Fixed Servers</option>
<option value="system">System</option>
</select>
<input id="proxy_value" type="text" size="80" disabled/>
</td>
</tr>
</table>
<table border="0" width="100%">
<tr>
<td align="left">
<input type="button" value="Refresh" onClick="refreshSimple()"/>
</td>
<td align="right">
<input type="button" value="Apply Changes" onClick="applySimpleChanges()"/>
</td>
</tr>
</table>
</p>
</div>
<!-- Advanced view -->
<div id="advanced" style="display:none">
<p>
This page displays all preferences organized in a tree structure. Arbitrary changes are
allowed, however <b>changing preferences in arbitrary ways may result in crashes</b>. If you
experience a crash while setting preferences then run a Debug build of CEF/Chromium and watch
for DCHECKs in the Chromium code to figure out what went wrong.
</p>
<div id="jsoneditor" style="width: 100%; height: 100%;"></div>
<table border="0" width="100%">
<tr>
<td align="left">
<input type="button" value="Refresh" onClick="refreshEditor()"/>
<input type="checkbox" id="hide_defaults"/> Show modified preferences only
</td>
<td align="right">
<input type="button" value="Apply Changes" onClick="applyEditorChanges()"/>
</td>
</tr>
</table>
</div>
<script>
// Reference to the JSONEditor.
var editor = null;
// Preferences state information.
var preferences_state = null;
// Toggle between the simple and advanced views.
function toggleView() {
var simple = document.getElementById("simple");
var advanced = document.getElementById("advanced");
var simple_links = document.getElementById("simple_links");
var advanced_links = document.getElementById("advanced_links");
if (simple.style.display == "none") {
// Show the simple view.
simple.style.display = "";
simple_links.style.display = "";
advanced.style.display = "none";
advanced_links.style.display = "none";
// Refresh the simple view contents.
refreshSimple();
} else {
// Show the advanced view.
simple.style.display = "none";
simple_links.style.display = "none";
advanced.style.display = "";
advanced_links.style.display = "";
if (editor == null) {
// Create the editor.
editor = new JSONEditor(document.getElementById("jsoneditor"));
}
// Refesh the editor contents.
refreshEditor();
}
}
// Send a request to C++.
function sendRequest(request, onSuccessCallback) {
// Results in a call to the OnQuery method in preferences_test.cpp.
window.cefQuery({
request: JSON.stringify(request),
onSuccess: onSuccessCallback,
onFailure: function(error_code, error_message) {
alert(error_message + ' (' + error_code + ')');
}
});
}
// Get the preferences and execute |onSuccessCallback| with the resulting
// JSON object.
function getPreferences(include_defaults, onSuccessCallback) {
// Create the request object.
var request = {};
request.name = "preferences_get";
request.include_defaults = include_defaults;
// Send the request to C++.
sendRequest(
request,
function(response) {
onSuccessCallback(JSON.parse(response));
}
);
}
// Set the preferences.
function setPreferences(preferences) {
// Create the request object.
var request = {};
request.name = "preferences_set";
request.preferences = preferences;
// Send the request to C++.
sendRequest(
request,
function(response) {
// Show the informative response message.
alert(response);
}
);
}
// Get the global preference state.
function getPreferenceState() {
// Create the request object.
var request = {};
request.name = "preferences_state";
// Send the request to C++.
sendRequest(
request,
function(response) {
// Populate the global state object.
preferences_state = JSON.parse(response);
// Refresh the simple view contents.
refreshSimple();
}
);
}
// Refresh the editor view contents.
function refreshEditor() {
include_defaults = !document.getElementById("hide_defaults").checked;
getPreferences(include_defaults, function(response) {
// Set the JSON in the editor.
editor.set(response);
});
}
// Apply changes from the editor view.
function applyEditorChanges() {
setPreferences(editor.get());
}
// Refresh the simple view contents.
function refreshSimple() {
getPreferences(true, function(response) {
// Spellcheck settings.
if (preferences_state.spellcheck_disabled) {
// Cannot enable spell checking when disabled via the command-line.
document.getElementById("enable_spellchecking").checked = false;
document.getElementById("enable_spellchecking").disabled = true;
} else {
document.getElementById("enable_spellchecking").checked =
response.browser.enable_spellchecking;
}
// Proxy settings.
document.getElementById("proxy_type").value = response.proxy.mode;
// Some proxy modes have associated values.
if (response.proxy.mode == "pac_script")
proxy_value = response.proxy.pac_url;
else if (response.proxy.mode == "fixed_servers")
proxy_value = response.proxy.server;
else
proxy_value = null;
if (proxy_value != null)
document.getElementById("proxy_value").value = proxy_value;
document.getElementById("proxy_value").disabled = (proxy_value == null);
if (preferences_state.proxy_configured) {
// Cannot modify proxy settings that are configured via the command-
// line.
document.getElementById("proxy_type").disabled = true;
document.getElementById("proxy_value").disabled = true;
}
});
}
// Apply changes from the simple view.
function applySimpleChanges() {
has_preferences = false;
preferences = {};
// Spellcheck settings.
if (!preferences_state.spellcheck_disabled) {
has_preferences = true;
preferences.browser = {};
preferences.browser.enable_spellchecking =
document.getElementById("enable_spellchecking").checked;
}
// Proxy settings.
if (!preferences_state.proxy_configured) {
has_preferences = true;
preferences.proxy = {};
preferences.proxy.mode = document.getElementById("proxy_type").value;
// Some proxy modes have associated values.
if (preferences.proxy.mode == "pac_script") {
preferences.proxy.pac_script =
document.getElementById("proxy_value").value;
} else if (preferences.proxy.mode == "fixed_servers") {
preferences.proxy.server =
document.getElementById("proxy_value").value;
}
}
if (has_preferences)
setPreferences(preferences);
}
// Called when the proxy type is changed.
function proxyTypeChange() {
proxy_type = document.getElementById("proxy_type").value;
document.getElementById("proxy_value").value = "";
// Only enable the value field for the proxy modes that require it.
document.getElementById("proxy_value").disabled =
(proxy_type != "pac_script" && proxy_type != "fixed_servers");
}
// Retrieve global preferences state.
getPreferenceState();
</script>
</body>
</html>

View File

@ -39,6 +39,7 @@ IDS_PDF_HTML BINARY "..\\pdf.html"
IDS_PDF_PDF BINARY "..\\pdf.pdf"
IDS_PERFORMANCE_HTML BINARY "..\\performance.html"
IDS_PERFORMANCE2_HTML BINARY "..\\performance2.html"
IDS_PREFERENCES_HTML BINARY "..\\preferences.html"
IDS_TRANSPARENCY_HTML BINARY "..\\transparency.html"
IDS_URLREQUEST_HTML BINARY "..\\urlrequest.html"
IDS_WINDOW_HTML BINARY "..\\window.html"

View File

@ -24,6 +24,11 @@ void CreateBrowserDelegates(ClientAppBrowser::DelegateSet& delegates) {
ClientAppBrowser::DelegateSet& delegates);
CreatePluginBrowserTests(delegates);
// Bring in the preference tests.
extern void CreatePreferenceBrowserTests(
ClientAppBrowser::DelegateSet& delegates);
CreatePreferenceBrowserTests(delegates);
// Bring in the RequestHandler tests.
extern void CreateRequestHandlerBrowserTests(
ClientAppBrowser::DelegateSet& delegates);

View File

@ -0,0 +1,553 @@
// Copyright (c) 2015 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 this first to avoid type conflicts with CEF headers.
#include "tests/unittests/chromium_includes.h"
#include "base/synchronization/waitable_event.h"
#include "include/base/cef_bind.h"
#include "include/wrapper/cef_closure_task.h"
#include "tests/cefclient/browser/client_app_browser.h"
#include "tests/unittests/test_handler.h"
#include "tests/unittests/test_util.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace {
// Fully qualified preference names.
const char kPrefTest[] = "test";
const char kPrefTestBool[] = "test.bool";
const char kPrefTestInt[] = "test.int";
const char kPrefTestDouble[] = "test.double";
const char kPrefTestString[] = "test.string";
const char kPrefTestList[] = "test.list";
const char kPrefTestDict[] = "test.dict";
const char kPrefTestNoExist[] = "test.noexist";
// Unqualified preference names.
const char kPrefBool[] = "bool";
const char kPrefInt[] = "int";
const char kPrefDouble[] = "double";
const char kPrefString[] = "string";
const char kPrefList[] = "list";
const char kPrefDict[] = "dict";
// Browser-side app delegate.
class PreferenceBrowserTest : public client::ClientAppBrowser::Delegate {
public:
PreferenceBrowserTest() {}
void OnBeforeCommandLineProcessing(
CefRefPtr<client::ClientAppBrowser> app,
CefRefPtr<CefCommandLine> command_line) override {
// Enables testing of preferences.
// See CefBrowserPrefStore::CreateService.
command_line->AppendSwitch("enable-preference-testing");
}
private:
IMPLEMENT_REFCOUNTING(PreferenceBrowserTest);
};
void ValidateReset(CefRefPtr<CefRequestContext> context,
const char* name) {
EXPECT_TRUE(context->HasPreference(name));
EXPECT_TRUE(context->CanSetPreference(name));
CefString error;
EXPECT_TRUE(context->SetPreference(name, NULL, error));
EXPECT_TRUE(error.empty());
}
void ValidateBool(CefRefPtr<CefRequestContext> context,
bool set,
bool expected,
const char* name = kPrefTestBool) {
EXPECT_TRUE(context->HasPreference(name));
EXPECT_TRUE(context->CanSetPreference(name));
CefRefPtr<CefValue> value;
if (set) {
value = CefValue::Create();
value->SetBool(expected);
CefString error;
EXPECT_TRUE(context->SetPreference(name, value, error));
EXPECT_TRUE(error.empty());
}
value = context->GetPreference(name);
EXPECT_TRUE(value.get());
EXPECT_EQ(VTYPE_BOOL, value->GetType());
EXPECT_EQ(expected, value->GetBool());
}
void ValidateInt(CefRefPtr<CefRequestContext> context,
bool set,
int expected,
const char* name = kPrefTestInt) {
EXPECT_TRUE(context->HasPreference(name));
EXPECT_TRUE(context->CanSetPreference(name));
CefRefPtr<CefValue> value;
if (set) {
value = CefValue::Create();
value->SetInt(expected);
CefString error;
EXPECT_TRUE(context->SetPreference(name, value, error));
EXPECT_TRUE(error.empty());
}
value = context->GetPreference(name);
EXPECT_TRUE(value.get());
EXPECT_EQ(VTYPE_INT, value->GetType());
EXPECT_EQ(expected, value->GetInt());
}
void ValidateDouble(CefRefPtr<CefRequestContext> context,
bool set,
double expected,
const char* name = kPrefTestDouble) {
EXPECT_TRUE(context->HasPreference(name));
EXPECT_TRUE(context->CanSetPreference(name));
CefRefPtr<CefValue> value;
if (set) {
value = CefValue::Create();
value->SetDouble(expected);
CefString error;
EXPECT_TRUE(context->SetPreference(name, value, error));
EXPECT_TRUE(error.empty());
}
value = context->GetPreference(name);
EXPECT_TRUE(value.get());
EXPECT_EQ(VTYPE_DOUBLE, value->GetType());
EXPECT_EQ(expected, value->GetDouble());
}
void ValidateString(CefRefPtr<CefRequestContext> context,
bool set,
const std::string& expected,
const char* name = kPrefTestString) {
EXPECT_TRUE(context->HasPreference(name));
EXPECT_TRUE(context->CanSetPreference(name));
CefRefPtr<CefValue> value;
if (set) {
value = CefValue::Create();
value->SetString(expected);
CefString error;
EXPECT_TRUE(context->SetPreference(name, value, error));
EXPECT_TRUE(error.empty());
}
value = context->GetPreference(name);
EXPECT_TRUE(value.get());
EXPECT_EQ(VTYPE_STRING, value->GetType());
EXPECT_STREQ(expected.c_str(), value->GetString().ToString().c_str());
}
void ValidateList(CefRefPtr<CefRequestContext> context,
bool set,
CefRefPtr<CefListValue> expected,
const char* name = kPrefTestList) {
EXPECT_TRUE(context->HasPreference(name));
EXPECT_TRUE(context->CanSetPreference(name));
CefRefPtr<CefValue> value;
if (set) {
value = CefValue::Create();
value->SetList(expected);
CefString error;
EXPECT_TRUE(context->SetPreference(name, value, error));
EXPECT_TRUE(error.empty());
}
value = context->GetPreference(name);
EXPECT_TRUE(value.get());
EXPECT_EQ(VTYPE_LIST, value->GetType());
CefRefPtr<CefListValue> list_val = value->GetList();
EXPECT_TRUE(list_val);
TestListEqual(expected, list_val);
}
void ValidateDict(CefRefPtr<CefRequestContext> context,
bool set,
CefRefPtr<CefDictionaryValue> expected,
const char* name = kPrefTestDict) {
EXPECT_TRUE(context->HasPreference(name));
EXPECT_TRUE(context->CanSetPreference(name));
CefRefPtr<CefValue> value;
if (set) {
value = CefValue::Create();
value->SetDictionary(expected);
CefString error;
EXPECT_TRUE(context->SetPreference(name, value, error));
EXPECT_TRUE(error.empty());
}
value = context->GetPreference(name);
EXPECT_TRUE(value.get());
EXPECT_EQ(VTYPE_DICTIONARY, value->GetType());
CefRefPtr<CefDictionaryValue> dict_val = value->GetDictionary();
EXPECT_TRUE(dict_val);
TestDictionaryEqual(expected, dict_val);
}
void ValidateNoExist(CefRefPtr<CefRequestContext> context,
bool set,
const char* name = kPrefTestNoExist) {
EXPECT_FALSE(context->HasPreference(name));
EXPECT_FALSE(context->CanSetPreference(name));
CefRefPtr<CefValue> value;
if (set) {
value = CefValue::Create();
value->SetBool(false);
CefString error;
EXPECT_FALSE(context->SetPreference(name, value, error));
EXPECT_FALSE(error.empty());
}
value = context->GetPreference(name);
EXPECT_FALSE(value.get());
}
void PopulateRootDefaults(CefRefPtr<CefDictionaryValue> val) {
// Should match the values in CefBrowserPrefStore::CreateService.
val->SetBool(kPrefBool, true);
val->SetInt(kPrefInt, 2);
val->SetDouble(kPrefDouble, 5.0);
val->SetString(kPrefString, "default");
val->SetList(kPrefList, CefListValue::Create());
val->SetDictionary(kPrefDict, CefDictionaryValue::Create());
}
void ValidateRoot(CefRefPtr<CefDictionaryValue> root,
CefRefPtr<CefDictionaryValue> expected,
const char* name = kPrefTest) {
EXPECT_TRUE(root->HasKey(kPrefTest));
EXPECT_EQ(VTYPE_DICTIONARY, root->GetType(kPrefTest));
CefRefPtr<CefDictionaryValue> actual = root->GetDictionary(kPrefTest);
TestDictionaryEqual(expected, actual);
}
// Validate getting default values.
void ValidateDefaults(CefRefPtr<CefRequestContext> context,
bool reset,
base::WaitableEvent* event) {
if (!CefCurrentlyOn(TID_UI)) {
CefPostTask(TID_UI, base::Bind(ValidateDefaults, context, reset, event));
return;
}
if (reset) {
// Reset default values.
ValidateReset(context, kPrefTestBool);
ValidateReset(context, kPrefTestInt);
ValidateReset(context, kPrefTestDouble);
ValidateReset(context, kPrefTestString);
ValidateReset(context, kPrefTestList);
ValidateReset(context, kPrefTestDict);
}
// Test default values.
// Should match the values in CefBrowserPrefStore::CreateService.
ValidateBool(context, false, true);
ValidateInt(context, false, 2);
ValidateDouble(context, false, 5.0);
ValidateString(context, false, "default");
ValidateList(context, false, CefListValue::Create());
ValidateDict(context, false, CefDictionaryValue::Create());
ValidateNoExist(context, false);
// Expected value of the tests root.
CefRefPtr<CefDictionaryValue> expected = CefDictionaryValue::Create();
PopulateRootDefaults(expected);
// Test all preferences including defaults.
ValidateRoot(context->GetAllPreferences(true), expected);
// Test all preferences excluding defaults.
EXPECT_FALSE(context->GetAllPreferences(false)->HasKey(kPrefTest));
event->Signal();
}
void PopulateListValue(CefRefPtr<CefListValue> val) {
// Test list values.
val->SetInt(0, 54);
val->SetString(1, "foobar");
val->SetDouble(2, 99.7643);
}
void PopulateDictValue(CefRefPtr<CefDictionaryValue> val) {
// Test dictionary values.
val->SetString("key1", "some string");
val->SetBool("key2", false);
CefRefPtr<CefListValue> list_val = CefListValue::Create();
PopulateListValue(list_val);
val->SetList("key3", list_val);
}
void PopulateRootSet(CefRefPtr<CefDictionaryValue> val) {
CefRefPtr<CefListValue> list_val = CefListValue::Create();
CefRefPtr<CefDictionaryValue> dict_val = CefDictionaryValue::Create();
PopulateListValue(list_val);
PopulateDictValue(dict_val);
// Should match the values in ValidateSetGet and ValidateGet.
val->SetBool(kPrefBool, true);
val->SetInt(kPrefInt, 65);
val->SetDouble(kPrefDouble, 54.5443);
val->SetString(kPrefString, "My test string");
val->SetList(kPrefList, list_val);
val->SetDictionary(kPrefDict, dict_val);
}
// Validate getting and setting values.
void ValidateSetGet(CefRefPtr<CefRequestContext> context,
base::WaitableEvent* event) {
if (!CefCurrentlyOn(TID_UI)) {
CefPostTask(TID_UI, base::Bind(ValidateSetGet, context, event));
return;
}
CefRefPtr<CefListValue> list_val = CefListValue::Create();
CefRefPtr<CefDictionaryValue> dict_val = CefDictionaryValue::Create();
PopulateListValue(list_val);
PopulateDictValue(dict_val);
// Test setting/getting values.
// Should match the values in PopulateRootSet and ValidateGet.
ValidateBool(context, true, true);
ValidateInt(context, true, 65);
ValidateDouble(context, true, 54.5443);
ValidateString(context, true, "My test string");
ValidateList(context, true, list_val);
ValidateDict(context, true, dict_val);
ValidateNoExist(context, true);
// Expected value of the tests root.
CefRefPtr<CefDictionaryValue> expected = CefDictionaryValue::Create();
PopulateRootSet(expected);
// Validate all preferences including defaults.
ValidateRoot(context->GetAllPreferences(true), expected);
// Validate all preferences excluding defaults.
ValidateRoot(context->GetAllPreferences(false), expected);
event->Signal();
}
// Validate getting values.
void ValidateGet(CefRefPtr<CefRequestContext> context,
base::WaitableEvent* event) {
if (!CefCurrentlyOn(TID_UI)) {
CefPostTask(TID_UI, base::Bind(ValidateGet, context, event));
return;
}
CefRefPtr<CefListValue> list_val = CefListValue::Create();
CefRefPtr<CefDictionaryValue> dict_val = CefDictionaryValue::Create();
PopulateListValue(list_val);
PopulateDictValue(dict_val);
// Test getting values.
// Should match the values in PopulateRootSet and ValidateSetGet.
ValidateBool(context, false, true);
ValidateInt(context, false, 65);
ValidateDouble(context, false, 54.5443);
ValidateString(context, false, "My test string");
ValidateList(context, false, list_val);
ValidateDict(context, false, dict_val);
ValidateNoExist(context, false);
// Expected value of the tests root.
CefRefPtr<CefDictionaryValue> expected = CefDictionaryValue::Create();
PopulateRootSet(expected);
// Validate all preferences including defaults.
ValidateRoot(context->GetAllPreferences(true), expected);
// Validate all preferences excluding defaults.
ValidateRoot(context->GetAllPreferences(false), expected);
event->Signal();
}
// No-op implementation.
class TestRequestContextHandler : public CefRequestContextHandler {
public:
TestRequestContextHandler() {}
IMPLEMENT_REFCOUNTING(TestRequestContextHandler);
};
} // namespace
// Verify default preference values on the global context.
TEST(PreferenceTest, GlobalDefaults) {
base::WaitableEvent event(false, false);
CefRefPtr<CefRequestContext> context = CefRequestContext::GetGlobalContext();
EXPECT_TRUE(context.get());
ValidateDefaults(context, false, &event);
event.Wait();
}
// Verify setting/getting preference values on the global context.
TEST(PreferenceTest, GlobalSetGet) {
base::WaitableEvent event(false, false);
CefRefPtr<CefRequestContext> context = CefRequestContext::GetGlobalContext();
EXPECT_TRUE(context.get());
ValidateSetGet(context, &event);
event.Wait();
// Reset to the default values.
ValidateDefaults(context, true, &event);
event.Wait();
}
// Verify setting/getting preference values on shared global contexts.
TEST(PreferenceTest, GlobalSetGetShared) {
base::WaitableEvent event(false, false);
CefRefPtr<CefRequestContext> context = CefRequestContext::GetGlobalContext();
EXPECT_TRUE(context.get());
// Sharing storage.
CefRefPtr<CefRequestContext> context2 =
CefRequestContext::CreateContext(context, NULL);
EXPECT_TRUE(context2.get());
// Sharing storage.
CefRefPtr<CefRequestContext> context3 =
CefRequestContext::CreateContext(context, new TestRequestContextHandler);
EXPECT_TRUE(context3.get());
// Unassociated context.
CefRequestContextSettings settings;
CefRefPtr<CefRequestContext> context4 =
CefRequestContext::CreateContext(settings, NULL);
EXPECT_TRUE(context.get());
// Set/get the values on the first context.
ValidateSetGet(context, &event);
event.Wait();
// Get the values from the 2nd and 3rd contexts. They should be the same.
ValidateGet(context2, &event);
event.Wait();
ValidateGet(context3, &event);
event.Wait();
// Get the values from the 4th context. They should be at the default.
ValidateDefaults(context4, false, &event);
event.Wait();
// Reset to the default values.
ValidateDefaults(context, true, &event);
event.Wait();
}
// Verify default preference values on a custom context.
TEST(PreferenceTest, CustomDefaults) {
base::WaitableEvent event(false, false);
CefRequestContextSettings settings;
CefRefPtr<CefRequestContext> context =
CefRequestContext::CreateContext(settings, NULL);
EXPECT_TRUE(context.get());
ValidateDefaults(context, false, &event);
event.Wait();
}
// Verify setting/getting preference values on a custom context.
TEST(PreferenceTest, CustomSetGet) {
base::WaitableEvent event(false, false);
CefRequestContextSettings settings;
CefRefPtr<CefRequestContext> context =
CefRequestContext::CreateContext(settings, NULL);
EXPECT_TRUE(context.get());
ValidateSetGet(context, &event);
event.Wait();
// Reset to the default values.
ValidateDefaults(context, true, &event);
event.Wait();
}
// Verify setting/getting preference values on shared custom contexts.
TEST(PreferenceTest, CustomSetGetShared) {
base::WaitableEvent event(false, false);
CefRequestContextSettings settings;
CefRefPtr<CefRequestContext> context =
CefRequestContext::CreateContext(settings, NULL);
EXPECT_TRUE(context.get());
// Sharing storage.
CefRefPtr<CefRequestContext> context2 =
CefRequestContext::CreateContext(context, NULL);
EXPECT_TRUE(context2.get());
// Sharing storage.
CefRefPtr<CefRequestContext> context3 =
CefRequestContext::CreateContext(context, new TestRequestContextHandler);
EXPECT_TRUE(context3.get());
// Unassociated context.
CefRefPtr<CefRequestContext> context4 =
CefRequestContext::CreateContext(settings, NULL);
EXPECT_TRUE(context.get());
// Set/get the values on the first context.
ValidateSetGet(context, &event);
event.Wait();
// Get the values from the 2nd and 3d contexts. They should be the same.
ValidateGet(context2, &event);
event.Wait();
ValidateGet(context3, &event);
event.Wait();
// Get the values from the 4th context. They should be at the default.
ValidateDefaults(context4, false, &event);
event.Wait();
// Reset to the default values.
ValidateDefaults(context, true, &event);
event.Wait();
}
// Entry point for creating preference browser test objects.
// Called from client_app_delegates.cc.
void CreatePreferenceBrowserTests(
client::ClientAppBrowser::DelegateSet& delegates) {
delegates.insert(new PreferenceBrowserTest);
}