summaryrefslogtreecommitdiffstats
path: root/modules/libpref
diff options
context:
space:
mode:
authorMatt A. Tobin <mattatobin@localhost.localdomain>2018-02-02 04:16:08 -0500
committerMatt A. Tobin <mattatobin@localhost.localdomain>2018-02-02 04:16:08 -0500
commit5f8de423f190bbb79a62f804151bc24824fa32d8 (patch)
tree10027f336435511475e392454359edea8e25895d /modules/libpref
parent49ee0794b5d912db1f95dce6eb52d781dc210db5 (diff)
downloadUXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.gz
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.lz
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.xz
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.zip
Add m-esr52 at 52.6.0
Diffstat (limited to 'modules/libpref')
-rw-r--r--modules/libpref/Preferences.cpp2023
-rw-r--r--modules/libpref/Preferences.h408
-rw-r--r--modules/libpref/greprefs.js12
-rw-r--r--modules/libpref/init/all.js5583
-rw-r--r--modules/libpref/moz.build48
-rw-r--r--modules/libpref/nsIPrefBranch.idl409
-rw-r--r--modules/libpref/nsIPrefBranch2.idl16
-rw-r--r--modules/libpref/nsIPrefBranchInternal.idl17
-rw-r--r--modules/libpref/nsIPrefLocalizedString.idl64
-rw-r--r--modules/libpref/nsIPrefService.idl160
-rw-r--r--modules/libpref/nsIRelativeFilePref.idl69
-rw-r--r--modules/libpref/nsPrefBranch.cpp901
-rw-r--r--modules/libpref/nsPrefBranch.h269
-rw-r--r--modules/libpref/nsPrefsFactory.cpp54
-rw-r--r--modules/libpref/prefapi.cpp1013
-rw-r--r--modules/libpref/prefapi.h258
-rw-r--r--modules/libpref/prefapi_private_data.h40
-rw-r--r--modules/libpref/prefread.cpp657
-rw-r--r--modules/libpref/prefread.h118
-rw-r--r--modules/libpref/test/unit/data/testPref.js6
-rw-r--r--modules/libpref/test/unit/data/testPrefSticky.js2
-rw-r--r--modules/libpref/test/unit/data/testPrefStickyUser.js5
-rw-r--r--modules/libpref/test/unit/extdata/testExt.js2
-rw-r--r--modules/libpref/test/unit/head_libPrefs.js45
-rw-r--r--modules/libpref/test/unit/test_bug345529.js34
-rw-r--r--modules/libpref/test/unit/test_bug506224.js29
-rw-r--r--modules/libpref/test/unit/test_bug577950.js28
-rw-r--r--modules/libpref/test/unit/test_bug790374.js55
-rw-r--r--modules/libpref/test/unit/test_changeType.js63
-rw-r--r--modules/libpref/test/unit/test_dirtyPrefs.js75
-rw-r--r--modules/libpref/test/unit/test_extprefs.js70
-rw-r--r--modules/libpref/test/unit/test_libPrefs.js392
-rw-r--r--modules/libpref/test/unit/test_stickyprefs.js170
-rw-r--r--modules/libpref/test/unit/test_warnings.js69
-rw-r--r--modules/libpref/test/unit/xpcshell.ini18
-rw-r--r--modules/libpref/test/unit_ipc/test_existing_prefs.js21
-rw-r--r--modules/libpref/test/unit_ipc/test_initial_prefs.js18
-rw-r--r--modules/libpref/test/unit_ipc/test_large_pref.js98
-rw-r--r--modules/libpref/test/unit_ipc/test_observed_prefs.js16
-rw-r--r--modules/libpref/test/unit_ipc/test_update_prefs.js38
-rw-r--r--modules/libpref/test/unit_ipc/test_user_default_prefs.js76
-rw-r--r--modules/libpref/test/unit_ipc/xpcshell.ini11
42 files changed, 13460 insertions, 0 deletions
diff --git a/modules/libpref/Preferences.cpp b/modules/libpref/Preferences.cpp
new file mode 100644
index 000000000..f36819236
--- /dev/null
+++ b/modules/libpref/Preferences.cpp
@@ -0,0 +1,2023 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "mozilla/MemoryReporting.h"
+#include "mozilla/dom/ContentChild.h"
+
+#include "mozilla/ArrayUtils.h"
+#include "mozilla/Attributes.h"
+#include "mozilla/HashFunctions.h"
+#include "mozilla/UniquePtrExtensions.h"
+
+#include "nsXULAppAPI.h"
+
+#include "mozilla/Preferences.h"
+#include "nsAppDirectoryServiceDefs.h"
+#include "nsDataHashtable.h"
+#include "nsDirectoryServiceDefs.h"
+#include "nsICategoryManager.h"
+#include "nsCategoryManagerUtils.h"
+#include "nsNetUtil.h"
+#include "nsIFile.h"
+#include "nsIInputStream.h"
+#include "nsIObserverService.h"
+#include "nsIOutputStream.h"
+#include "nsISafeOutputStream.h"
+#include "nsISimpleEnumerator.h"
+#include "nsIStringEnumerator.h"
+#include "nsIZipReader.h"
+#include "nsPrefBranch.h"
+#include "nsXPIDLString.h"
+#include "nsCRT.h"
+#include "nsCOMArray.h"
+#include "nsXPCOMCID.h"
+#include "nsAutoPtr.h"
+#include "nsPrintfCString.h"
+
+#include "nsQuickSort.h"
+#include "PLDHashTable.h"
+
+#include "prefapi.h"
+#include "prefread.h"
+#include "prefapi_private_data.h"
+
+#include "mozilla/Omnijar.h"
+#include "nsZipArchive.h"
+
+#include "nsTArray.h"
+#include "nsRefPtrHashtable.h"
+#include "nsIMemoryReporter.h"
+#include "nsThreadUtils.h"
+
+#ifdef DEBUG
+#define ENSURE_MAIN_PROCESS(message, pref) do { \
+ if (MOZ_UNLIKELY(!XRE_IsParentProcess())) { \
+ nsPrintfCString msg("ENSURE_MAIN_PROCESS failed. %s %s", message, pref); \
+ NS_WARNING(msg.get()); \
+ return NS_ERROR_NOT_AVAILABLE; \
+ } \
+} while (0);
+#else
+#define ENSURE_MAIN_PROCESS(message, pref) \
+ if (MOZ_UNLIKELY(!XRE_IsParentProcess())) { \
+ return NS_ERROR_NOT_AVAILABLE; \
+ }
+#endif
+
+class PrefCallback;
+
+namespace mozilla {
+
+// Definitions
+#define INITIAL_PREF_FILES 10
+static NS_DEFINE_CID(kZipReaderCID, NS_ZIPREADER_CID);
+
+void
+Preferences::DirtyCallback()
+{
+ if (gHashTable && sPreferences && !sPreferences->mDirty) {
+ sPreferences->mDirty = true;
+ }
+}
+
+// Prototypes
+static nsresult openPrefFile(nsIFile* aFile);
+static nsresult pref_InitInitialObjects(void);
+static nsresult pref_LoadPrefsInDirList(const char *listId);
+static nsresult ReadExtensionPrefs(nsIFile *aFile);
+
+static const char kTelemetryPref[] = "toolkit.telemetry.enabled";
+static const char kOldTelemetryPref[] = "toolkit.telemetry.enabledPreRelease";
+static const char kChannelPref[] = "app.update.channel";
+
+static const char kPrefFileHeader[] =
+ "# Mozilla User Preferences"
+ NS_LINEBREAK
+ NS_LINEBREAK
+ "/* Do not edit this file."
+ NS_LINEBREAK
+ " *"
+ NS_LINEBREAK
+ " * If you make changes to this file while the application is running,"
+ NS_LINEBREAK
+ " * the changes will be overwritten when the application exits."
+ NS_LINEBREAK
+ " *"
+ NS_LINEBREAK
+ " * To make a manual change to preferences, you can visit the URL about:config"
+ NS_LINEBREAK
+ " */"
+ NS_LINEBREAK
+ NS_LINEBREAK;
+
+Preferences* Preferences::sPreferences = nullptr;
+nsIPrefBranch* Preferences::sRootBranch = nullptr;
+nsIPrefBranch* Preferences::sDefaultRootBranch = nullptr;
+bool Preferences::sShutdown = false;
+
+class ValueObserverHashKey : public PLDHashEntryHdr {
+public:
+ typedef ValueObserverHashKey* KeyType;
+ typedef const ValueObserverHashKey* KeyTypePointer;
+
+ static const ValueObserverHashKey* KeyToPointer(ValueObserverHashKey *aKey)
+ {
+ return aKey;
+ }
+
+ static PLDHashNumber HashKey(const ValueObserverHashKey *aKey)
+ {
+ PLDHashNumber hash = HashString(aKey->mPrefName);
+ hash = AddToHash(hash, aKey->mMatchKind);
+ return AddToHash(hash, aKey->mCallback);
+ }
+
+ ValueObserverHashKey(const char *aPref, PrefChangedFunc aCallback, Preferences::MatchKind aMatchKind) :
+ mPrefName(aPref), mCallback(aCallback), mMatchKind(aMatchKind) { }
+
+ explicit ValueObserverHashKey(const ValueObserverHashKey *aOther) :
+ mPrefName(aOther->mPrefName),
+ mCallback(aOther->mCallback),
+ mMatchKind(aOther->mMatchKind)
+ { }
+
+ bool KeyEquals(const ValueObserverHashKey *aOther) const
+ {
+ return mCallback == aOther->mCallback &&
+ mPrefName == aOther->mPrefName &&
+ mMatchKind == aOther->mMatchKind;
+ }
+
+ ValueObserverHashKey *GetKey() const
+ {
+ return const_cast<ValueObserverHashKey*>(this);
+ }
+
+ enum { ALLOW_MEMMOVE = true };
+
+ nsCString mPrefName;
+ PrefChangedFunc mCallback;
+ Preferences::MatchKind mMatchKind;
+};
+
+class ValueObserver final : public nsIObserver,
+ public ValueObserverHashKey
+{
+ ~ValueObserver() {
+ Preferences::RemoveObserver(this, mPrefName.get());
+ }
+
+public:
+ NS_DECL_ISUPPORTS
+ NS_DECL_NSIOBSERVER
+
+ ValueObserver(const char *aPref, PrefChangedFunc aCallback, Preferences::MatchKind aMatchKind)
+ : ValueObserverHashKey(aPref, aCallback, aMatchKind) { }
+
+ void AppendClosure(void *aClosure) {
+ mClosures.AppendElement(aClosure);
+ }
+
+ void RemoveClosure(void *aClosure) {
+ mClosures.RemoveElement(aClosure);
+ }
+
+ bool HasNoClosures() {
+ return mClosures.Length() == 0;
+ }
+
+ nsTArray<void*> mClosures;
+};
+
+NS_IMPL_ISUPPORTS(ValueObserver, nsIObserver)
+
+NS_IMETHODIMP
+ValueObserver::Observe(nsISupports *aSubject,
+ const char *aTopic,
+ const char16_t *aData)
+{
+ NS_ASSERTION(!nsCRT::strcmp(aTopic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID),
+ "invalid topic");
+ NS_ConvertUTF16toUTF8 data(aData);
+ if (mMatchKind == Preferences::ExactMatch && !mPrefName.EqualsASCII(data.get())) {
+ return NS_OK;
+ }
+ for (uint32_t i = 0; i < mClosures.Length(); i++) {
+ mCallback(data.get(), mClosures.ElementAt(i));
+ }
+
+ return NS_OK;
+}
+
+struct CacheData {
+ void* cacheLocation;
+ union {
+ bool defaultValueBool;
+ int32_t defaultValueInt;
+ uint32_t defaultValueUint;
+ float defaultValueFloat;
+ };
+};
+
+static nsTArray<nsAutoPtr<CacheData> >* gCacheData = nullptr;
+static nsRefPtrHashtable<ValueObserverHashKey,
+ ValueObserver>* gObserverTable = nullptr;
+
+#ifdef DEBUG
+static bool
+HaveExistingCacheFor(void* aPtr)
+{
+ MOZ_ASSERT(NS_IsMainThread());
+ if (gCacheData) {
+ for (size_t i = 0, count = gCacheData->Length(); i < count; ++i) {
+ if ((*gCacheData)[i]->cacheLocation == aPtr) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+static void
+AssertNotAlreadyCached(const char* aPrefType,
+ const char* aPref,
+ void* aPtr)
+{
+ if (HaveExistingCacheFor(aPtr)) {
+ fprintf_stderr(stderr,
+ "Attempt to add a %s pref cache for preference '%s' at address '%p'"
+ "was made. However, a pref was already cached at this address.\n",
+ aPrefType, aPref, aPtr);
+ MOZ_ASSERT(false, "Should not have an existing pref cache for this address");
+ }
+}
+#endif
+
+static void
+ReportToConsole(const char* aMessage, int aLine, bool aError)
+{
+ nsPrintfCString message("** Preference parsing %s (line %d) = %s **\n",
+ (aError ? "error" : "warning"), aLine, aMessage);
+ nsPrefBranch::ReportToConsole(NS_ConvertUTF8toUTF16(message.get()));
+}
+
+// Although this is a member of Preferences, it measures sPreferences and
+// several other global structures.
+/* static */ int64_t
+Preferences::SizeOfIncludingThisAndOtherStuff(mozilla::MallocSizeOf aMallocSizeOf)
+{
+ NS_ENSURE_TRUE(InitStaticMembers(), 0);
+
+ size_t n = aMallocSizeOf(sPreferences);
+ if (gHashTable) {
+ // pref keys are allocated in a private arena, which we count elsewhere.
+ // pref stringvals are allocated out of the same private arena.
+ n += gHashTable->ShallowSizeOfIncludingThis(aMallocSizeOf);
+ }
+ if (gCacheData) {
+ n += gCacheData->ShallowSizeOfIncludingThis(aMallocSizeOf);
+ for (uint32_t i = 0, count = gCacheData->Length(); i < count; ++i) {
+ n += aMallocSizeOf((*gCacheData)[i]);
+ }
+ }
+ if (gObserverTable) {
+ n += gObserverTable->ShallowSizeOfIncludingThis(aMallocSizeOf);
+ for (auto iter = gObserverTable->Iter(); !iter.Done(); iter.Next()) {
+ n += iter.Key()->mPrefName.SizeOfExcludingThisIfUnshared(aMallocSizeOf);
+ n += iter.Data()->mClosures.ShallowSizeOfExcludingThis(aMallocSizeOf);
+ }
+ }
+ if (sRootBranch) {
+ n += reinterpret_cast<nsPrefBranch*>(sRootBranch)->SizeOfIncludingThis(aMallocSizeOf);
+ }
+ if (sDefaultRootBranch) {
+ n += reinterpret_cast<nsPrefBranch*>(sDefaultRootBranch)->SizeOfIncludingThis(aMallocSizeOf);
+ }
+ n += pref_SizeOfPrivateData(aMallocSizeOf);
+ return n;
+}
+
+class PreferenceServiceReporter final : public nsIMemoryReporter
+{
+ ~PreferenceServiceReporter() {}
+
+public:
+ NS_DECL_ISUPPORTS
+ NS_DECL_NSIMEMORYREPORTER
+
+protected:
+ static const uint32_t kSuspectReferentCount = 1000;
+};
+
+NS_IMPL_ISUPPORTS(PreferenceServiceReporter, nsIMemoryReporter)
+
+MOZ_DEFINE_MALLOC_SIZE_OF(PreferenceServiceMallocSizeOf)
+
+NS_IMETHODIMP
+PreferenceServiceReporter::CollectReports(
+ nsIHandleReportCallback* aHandleReport, nsISupports* aData, bool aAnonymize)
+{
+ MOZ_COLLECT_REPORT(
+ "explicit/preferences", KIND_HEAP, UNITS_BYTES,
+ Preferences::SizeOfIncludingThisAndOtherStuff(PreferenceServiceMallocSizeOf),
+ "Memory used by the preferences system.");
+
+ nsPrefBranch* rootBranch =
+ static_cast<nsPrefBranch*>(Preferences::GetRootBranch());
+ if (!rootBranch) {
+ return NS_OK;
+ }
+
+ size_t numStrong = 0;
+ size_t numWeakAlive = 0;
+ size_t numWeakDead = 0;
+ nsTArray<nsCString> suspectPreferences;
+ // Count of the number of referents for each preference.
+ nsDataHashtable<nsCStringHashKey, uint32_t> prefCounter;
+
+ for (auto iter = rootBranch->mObservers.Iter(); !iter.Done(); iter.Next()) {
+ nsAutoPtr<PrefCallback>& callback = iter.Data();
+ nsPrefBranch* prefBranch = callback->GetPrefBranch();
+ const char* pref = prefBranch->getPrefName(callback->GetDomain().get());
+
+ if (callback->IsWeak()) {
+ nsCOMPtr<nsIObserver> callbackRef = do_QueryReferent(callback->mWeakRef);
+ if (callbackRef) {
+ numWeakAlive++;
+ } else {
+ numWeakDead++;
+ }
+ } else {
+ numStrong++;
+ }
+
+ nsDependentCString prefString(pref);
+ uint32_t oldCount = 0;
+ prefCounter.Get(prefString, &oldCount);
+ uint32_t currentCount = oldCount + 1;
+ prefCounter.Put(prefString, currentCount);
+
+ // Keep track of preferences that have a suspiciously large number of
+ // referents (a symptom of a leak).
+ if (currentCount == kSuspectReferentCount) {
+ suspectPreferences.AppendElement(prefString);
+ }
+ }
+
+ for (uint32_t i = 0; i < suspectPreferences.Length(); i++) {
+ nsCString& suspect = suspectPreferences[i];
+ uint32_t totalReferentCount = 0;
+ prefCounter.Get(suspect, &totalReferentCount);
+
+ nsPrintfCString suspectPath("preference-service-suspect/"
+ "referent(pref=%s)", suspect.get());
+
+ aHandleReport->Callback(
+ /* process = */ EmptyCString(),
+ suspectPath, KIND_OTHER, UNITS_COUNT, totalReferentCount,
+ NS_LITERAL_CSTRING(
+ "A preference with a suspiciously large number referents (symptom of a "
+ "leak)."),
+ aData);
+ }
+
+ MOZ_COLLECT_REPORT(
+ "preference-service/referent/strong", KIND_OTHER, UNITS_COUNT,
+ numStrong,
+ "The number of strong referents held by the preference service.");
+
+ MOZ_COLLECT_REPORT(
+ "preference-service/referent/weak/alive", KIND_OTHER, UNITS_COUNT,
+ numWeakAlive,
+ "The number of weak referents held by the preference service that are "
+ "still alive.");
+
+ MOZ_COLLECT_REPORT(
+ "preference-service/referent/weak/dead", KIND_OTHER, UNITS_COUNT,
+ numWeakDead,
+ "The number of weak referents held by the preference service that are "
+ "dead.");
+
+ return NS_OK;
+}
+
+namespace {
+class AddPreferencesMemoryReporterRunnable : public Runnable
+{
+ NS_IMETHOD Run() override
+ {
+ return RegisterStrongMemoryReporter(new PreferenceServiceReporter());
+ }
+};
+} // namespace
+
+// static
+Preferences*
+Preferences::GetInstanceForService()
+{
+ if (sPreferences) {
+ NS_ADDREF(sPreferences);
+ return sPreferences;
+ }
+
+ NS_ENSURE_TRUE(!sShutdown, nullptr);
+
+ sRootBranch = new nsPrefBranch("", false);
+ NS_ADDREF(sRootBranch);
+ sDefaultRootBranch = new nsPrefBranch("", true);
+ NS_ADDREF(sDefaultRootBranch);
+
+ sPreferences = new Preferences();
+ NS_ADDREF(sPreferences);
+
+ if (NS_FAILED(sPreferences->Init())) {
+ // The singleton instance will delete sRootBranch and sDefaultRootBranch.
+ NS_RELEASE(sPreferences);
+ return nullptr;
+ }
+
+ gCacheData = new nsTArray<nsAutoPtr<CacheData> >();
+
+ gObserverTable = new nsRefPtrHashtable<ValueObserverHashKey, ValueObserver>();
+
+ // Preferences::GetInstanceForService() can be called from GetService(), and
+ // RegisterStrongMemoryReporter calls GetService(nsIMemoryReporter). To
+ // avoid a potential recursive GetService() call, we can't register the
+ // memory reporter here; instead, do it off a runnable.
+ RefPtr<AddPreferencesMemoryReporterRunnable> runnable =
+ new AddPreferencesMemoryReporterRunnable();
+ NS_DispatchToMainThread(runnable);
+
+ NS_ADDREF(sPreferences);
+ return sPreferences;
+}
+
+// static
+bool
+Preferences::IsServiceAvailable()
+{
+ return !!sPreferences;
+}
+
+// static
+bool
+Preferences::InitStaticMembers()
+{
+#ifndef MOZ_B2G
+ MOZ_ASSERT(NS_IsMainThread());
+#endif
+
+ if (!sShutdown && !sPreferences) {
+ nsCOMPtr<nsIPrefService> prefService =
+ do_GetService(NS_PREFSERVICE_CONTRACTID);
+ }
+
+ return sPreferences != nullptr;
+}
+
+// static
+void
+Preferences::Shutdown()
+{
+ if (!sShutdown) {
+ sShutdown = true; // Don't create the singleton instance after here.
+
+ // Don't set sPreferences to nullptr here. The instance may be grabbed by
+ // other modules. The utility methods of Preferences should be available
+ // until the singleton instance actually released.
+ if (sPreferences) {
+ sPreferences->Release();
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+
+/*
+ * Constructor/Destructor
+ */
+
+Preferences::Preferences()
+ : mDirty(false)
+{
+}
+
+Preferences::~Preferences()
+{
+ NS_ASSERTION(sPreferences == this, "Isn't this the singleton instance?");
+
+ delete gObserverTable;
+ gObserverTable = nullptr;
+
+ delete gCacheData;
+ gCacheData = nullptr;
+
+ NS_RELEASE(sRootBranch);
+ NS_RELEASE(sDefaultRootBranch);
+
+ sPreferences = nullptr;
+
+ PREF_Cleanup();
+}
+
+
+/*
+ * nsISupports Implementation
+ */
+
+NS_IMPL_ADDREF(Preferences)
+NS_IMPL_RELEASE(Preferences)
+
+NS_INTERFACE_MAP_BEGIN(Preferences)
+ NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIPrefService)
+ NS_INTERFACE_MAP_ENTRY(nsIPrefService)
+ NS_INTERFACE_MAP_ENTRY(nsIObserver)
+ NS_INTERFACE_MAP_ENTRY(nsIPrefBranch)
+ NS_INTERFACE_MAP_ENTRY(nsIPrefBranch2)
+ NS_INTERFACE_MAP_ENTRY(nsIPrefBranchInternal)
+ NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
+NS_INTERFACE_MAP_END
+
+
+/*
+ * nsIPrefService Implementation
+ */
+
+nsresult
+Preferences::Init()
+{
+ nsresult rv;
+
+ PREF_SetDirtyCallback(&DirtyCallback);
+ PREF_Init();
+
+ rv = pref_InitInitialObjects();
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ using mozilla::dom::ContentChild;
+ if (XRE_IsContentProcess()) {
+ InfallibleTArray<PrefSetting> prefs;
+ ContentChild::GetSingleton()->SendReadPrefsArray(&prefs);
+
+ // Store the array
+ for (uint32_t i = 0; i < prefs.Length(); ++i) {
+ pref_SetPref(prefs[i]);
+ }
+ return NS_OK;
+ }
+
+ nsXPIDLCString lockFileName;
+ /*
+ * The following is a small hack which will allow us to only load the library
+ * which supports the netscape.cfg file if the preference is defined. We
+ * test for the existence of the pref, set in the all.js (mozilla) or
+ * all-ns.js (netscape 6), and if it exists we startup the pref config
+ * category which will do the rest.
+ */
+
+ rv = PREF_CopyCharPref("general.config.filename", getter_Copies(lockFileName), false);
+ if (NS_SUCCEEDED(rv))
+ NS_CreateServicesFromCategory("pref-config-startup",
+ static_cast<nsISupports *>(static_cast<void *>(this)),
+ "pref-config-startup");
+
+ nsCOMPtr<nsIObserverService> observerService =
+ mozilla::services::GetObserverService();
+ if (!observerService)
+ return NS_ERROR_FAILURE;
+
+ rv = observerService->AddObserver(this, "profile-before-change", true);
+
+ observerService->AddObserver(this, "load-extension-defaults", true);
+ observerService->AddObserver(this, "suspend_process_notification", true);
+
+ return(rv);
+}
+
+// static
+nsresult
+Preferences::ResetAndReadUserPrefs()
+{
+ sPreferences->ResetUserPrefs();
+ return sPreferences->ReadUserPrefs(nullptr);
+}
+
+NS_IMETHODIMP
+Preferences::Observe(nsISupports *aSubject, const char *aTopic,
+ const char16_t *someData)
+{
+ if (XRE_IsContentProcess())
+ return NS_ERROR_NOT_AVAILABLE;
+
+ nsresult rv = NS_OK;
+
+ if (!nsCRT::strcmp(aTopic, "profile-before-change")) {
+ rv = SavePrefFile(nullptr);
+ } else if (!strcmp(aTopic, "load-extension-defaults")) {
+ pref_LoadPrefsInDirList(NS_EXT_PREFS_DEFAULTS_DIR_LIST);
+ } else if (!nsCRT::strcmp(aTopic, "reload-default-prefs")) {
+ // Reload the default prefs from file.
+ pref_InitInitialObjects();
+ } else if (!nsCRT::strcmp(aTopic, "suspend_process_notification")) {
+ // Our process is being suspended. The OS may wake our process later,
+ // or it may kill the process. In case our process is going to be killed
+ // from the suspended state, we save preferences before suspending.
+ rv = SavePrefFile(nullptr);
+ }
+ return rv;
+}
+
+
+NS_IMETHODIMP
+Preferences::ReadUserPrefs(nsIFile *aFile)
+{
+ if (XRE_IsContentProcess()) {
+ NS_ERROR("cannot load prefs from content process");
+ return NS_ERROR_NOT_AVAILABLE;
+ }
+
+ nsresult rv;
+
+ if (nullptr == aFile) {
+ rv = UseDefaultPrefFile();
+ // A user pref file is optional.
+ // Ignore all errors related to it, so we retain 'rv' value :-|
+ (void) UseUserPrefFile();
+
+ // Migrate the old prerelease telemetry pref
+ if (!Preferences::GetBool(kOldTelemetryPref, true)) {
+ Preferences::SetBool(kTelemetryPref, false);
+ Preferences::ClearUser(kOldTelemetryPref);
+ }
+
+ NotifyServiceObservers(NS_PREFSERVICE_READ_TOPIC_ID);
+ } else {
+ rv = ReadAndOwnUserPrefFile(aFile);
+ }
+
+ return rv;
+}
+
+NS_IMETHODIMP
+Preferences::ResetPrefs()
+{
+ if (XRE_IsContentProcess()) {
+ NS_ERROR("cannot reset prefs from content process");
+ return NS_ERROR_NOT_AVAILABLE;
+ }
+
+ NotifyServiceObservers(NS_PREFSERVICE_RESET_TOPIC_ID);
+ PREF_CleanupPrefs();
+
+ PREF_Init();
+
+ return pref_InitInitialObjects();
+}
+
+NS_IMETHODIMP
+Preferences::ResetUserPrefs()
+{
+ if (XRE_IsContentProcess()) {
+ NS_ERROR("cannot reset user prefs from content process");
+ return NS_ERROR_NOT_AVAILABLE;
+ }
+
+ PREF_ClearAllUserPrefs();
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+Preferences::SavePrefFile(nsIFile *aFile)
+{
+ if (XRE_IsContentProcess()) {
+ NS_ERROR("cannot save pref file from content process");
+ return NS_ERROR_NOT_AVAILABLE;
+ }
+
+ return SavePrefFileInternal(aFile);
+}
+
+static nsresult
+ReadExtensionPrefs(nsIFile *aFile)
+{
+ nsresult rv;
+ nsCOMPtr<nsIZipReader> reader = do_CreateInstance(kZipReaderCID, &rv);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ rv = reader->Open(aFile);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ nsCOMPtr<nsIUTF8StringEnumerator> files;
+ rv = reader->FindEntries(nsDependentCString("defaults/preferences/*.(J|j)(S|s)$"),
+ getter_AddRefs(files));
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ char buffer[4096];
+
+ bool more;
+ while (NS_SUCCEEDED(rv = files->HasMore(&more)) && more) {
+ nsAutoCString entry;
+ rv = files->GetNext(entry);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ nsCOMPtr<nsIInputStream> stream;
+ rv = reader->GetInputStream(entry, getter_AddRefs(stream));
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ uint64_t avail;
+ uint32_t read;
+
+ PrefParseState ps;
+ PREF_InitParseState(&ps, PREF_ReaderCallback, ReportToConsole, nullptr);
+ while (NS_SUCCEEDED(rv = stream->Available(&avail)) && avail) {
+ rv = stream->Read(buffer, 4096, &read);
+ if (NS_FAILED(rv)) {
+ NS_WARNING("Pref stream read failed");
+ break;
+ }
+
+ PREF_ParseBuf(&ps, buffer, read);
+ }
+ PREF_FinalizeParseState(&ps);
+ }
+ return rv;
+}
+
+void
+Preferences::SetPreference(const PrefSetting& aPref)
+{
+ pref_SetPref(aPref);
+}
+
+void
+Preferences::GetPreference(PrefSetting* aPref)
+{
+ PrefHashEntry *entry = pref_HashTableLookup(aPref->name().get());
+ if (!entry)
+ return;
+
+ if (pref_EntryHasAdvisablySizedValues(entry)) {
+ pref_GetPrefFromEntry(entry, aPref);
+ }
+}
+
+void
+Preferences::GetPreferences(InfallibleTArray<PrefSetting>* aPrefs)
+{
+ aPrefs->SetCapacity(gHashTable->Capacity());
+ for (auto iter = gHashTable->Iter(); !iter.Done(); iter.Next()) {
+ auto entry = static_cast<PrefHashEntry*>(iter.Get());
+
+ if (!pref_EntryHasAdvisablySizedValues(entry)) {
+ continue;
+ }
+
+ dom::PrefSetting *pref = aPrefs->AppendElement();
+ pref_GetPrefFromEntry(entry, pref);
+ }
+}
+
+NS_IMETHODIMP
+Preferences::GetBranch(const char *aPrefRoot, nsIPrefBranch **_retval)
+{
+ nsresult rv;
+
+ if ((nullptr != aPrefRoot) && (*aPrefRoot != '\0')) {
+ // TODO: - cache this stuff and allow consumers to share branches (hold weak references I think)
+ RefPtr<nsPrefBranch> prefBranch = new nsPrefBranch(aPrefRoot, false);
+ prefBranch.forget(_retval);
+ rv = NS_OK;
+ } else {
+ // special case caching the default root
+ nsCOMPtr<nsIPrefBranch> root(sRootBranch);
+ root.forget(_retval);
+ rv = NS_OK;
+ }
+ return rv;
+}
+
+NS_IMETHODIMP
+Preferences::GetDefaultBranch(const char *aPrefRoot, nsIPrefBranch **_retval)
+{
+ if (!aPrefRoot || !aPrefRoot[0]) {
+ nsCOMPtr<nsIPrefBranch> root(sDefaultRootBranch);
+ root.forget(_retval);
+ return NS_OK;
+ }
+
+ // TODO: - cache this stuff and allow consumers to share branches (hold weak references I think)
+ RefPtr<nsPrefBranch> prefBranch = new nsPrefBranch(aPrefRoot, true);
+ if (!prefBranch)
+ return NS_ERROR_OUT_OF_MEMORY;
+
+ prefBranch.forget(_retval);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+Preferences::GetDirty(bool *_retval) {
+ *_retval = mDirty;
+ return NS_OK;
+}
+
+nsresult
+Preferences::NotifyServiceObservers(const char *aTopic)
+{
+ nsCOMPtr<nsIObserverService> observerService =
+ mozilla::services::GetObserverService();
+ if (!observerService)
+ return NS_ERROR_FAILURE;
+
+ nsISupports *subject = (nsISupports *)((nsIPrefService *)this);
+ observerService->NotifyObservers(subject, aTopic, nullptr);
+
+ return NS_OK;
+}
+
+nsresult
+Preferences::UseDefaultPrefFile()
+{
+ nsCOMPtr<nsIFile> aFile;
+ nsresult rv = NS_GetSpecialDirectory(NS_APP_PREFS_50_FILE, getter_AddRefs(aFile));
+
+ if (NS_SUCCEEDED(rv)) {
+ rv = ReadAndOwnUserPrefFile(aFile);
+ // Most likely cause of failure here is that the file didn't
+ // exist, so save a new one. mUserPrefReadFailed will be
+ // used to catch an error in actually reading the file.
+ if (NS_FAILED(rv)) {
+ if (NS_FAILED(SavePrefFileInternal(aFile)))
+ NS_ERROR("Failed to save new shared pref file");
+ else
+ rv = NS_OK;
+ }
+ }
+
+ return rv;
+}
+
+nsresult
+Preferences::UseUserPrefFile()
+{
+ nsresult rv = NS_OK;
+ nsCOMPtr<nsIFile> aFile;
+ nsDependentCString prefsDirProp(NS_APP_PREFS_50_DIR);
+
+ rv = NS_GetSpecialDirectory(prefsDirProp.get(), getter_AddRefs(aFile));
+ if (NS_SUCCEEDED(rv) && aFile) {
+ rv = aFile->AppendNative(NS_LITERAL_CSTRING("user.js"));
+ if (NS_SUCCEEDED(rv)) {
+ bool exists = false;
+ aFile->Exists(&exists);
+ if (exists) {
+ rv = openPrefFile(aFile);
+ } else {
+ rv = NS_ERROR_FILE_NOT_FOUND;
+ }
+ }
+ }
+ return rv;
+}
+
+nsresult
+Preferences::MakeBackupPrefFile(nsIFile *aFile)
+{
+ // Example: this copies "prefs.js" to "Invalidprefs.js" in the same directory.
+ // "Invalidprefs.js" is removed if it exists, prior to making the copy.
+ nsAutoString newFilename;
+ nsresult rv = aFile->GetLeafName(newFilename);
+ NS_ENSURE_SUCCESS(rv, rv);
+ newFilename.Insert(NS_LITERAL_STRING("Invalid"), 0);
+ nsCOMPtr<nsIFile> newFile;
+ rv = aFile->GetParent(getter_AddRefs(newFile));
+ NS_ENSURE_SUCCESS(rv, rv);
+ rv = newFile->Append(newFilename);
+ NS_ENSURE_SUCCESS(rv, rv);
+ bool exists = false;
+ newFile->Exists(&exists);
+ if (exists) {
+ rv = newFile->Remove(false);
+ NS_ENSURE_SUCCESS(rv, rv);
+ }
+ rv = aFile->CopyTo(nullptr, newFilename);
+ NS_ENSURE_SUCCESS(rv, rv);
+ return rv;
+}
+
+nsresult
+Preferences::ReadAndOwnUserPrefFile(nsIFile *aFile)
+{
+ NS_ENSURE_ARG(aFile);
+
+ if (mCurrentFile == aFile)
+ return NS_OK;
+ mCurrentFile = aFile;
+
+ nsresult rv = NS_OK;
+ bool exists = false;
+ mCurrentFile->Exists(&exists);
+ if (exists) {
+ rv = openPrefFile(mCurrentFile);
+ if (NS_FAILED(rv)) {
+ // Save a backup copy of the current (invalid) prefs file, since all prefs
+ // from the error line to the end of the file will be lost (bug 361102).
+ // TODO we should notify the user about it (bug 523725).
+ MakeBackupPrefFile(mCurrentFile);
+ }
+ } else {
+ rv = NS_ERROR_FILE_NOT_FOUND;
+ }
+
+ return rv;
+}
+
+nsresult
+Preferences::SavePrefFileInternal(nsIFile *aFile)
+{
+ if (nullptr == aFile) {
+ // the mDirty flag tells us if we should write to mCurrentFile
+ // we only check this flag when the caller wants to write to the default
+ if (!mDirty) {
+ return NS_OK;
+ }
+
+ // It's possible that we never got a prefs file.
+ nsresult rv = NS_OK;
+ if (mCurrentFile)
+ rv = WritePrefFile(mCurrentFile);
+
+ return rv;
+ } else {
+ return WritePrefFile(aFile);
+ }
+}
+
+nsresult
+Preferences::WritePrefFile(nsIFile* aFile)
+{
+ nsCOMPtr<nsIOutputStream> outStreamSink;
+ nsCOMPtr<nsIOutputStream> outStream;
+ uint32_t writeAmount;
+ nsresult rv;
+
+ if (!gHashTable)
+ return NS_ERROR_NOT_INITIALIZED;
+
+ // execute a "safe" save by saving through a tempfile
+ rv = NS_NewSafeLocalFileOutputStream(getter_AddRefs(outStreamSink),
+ aFile,
+ -1,
+ 0600);
+ if (NS_FAILED(rv))
+ return rv;
+ rv = NS_NewBufferedOutputStream(getter_AddRefs(outStream), outStreamSink, 4096);
+ if (NS_FAILED(rv))
+ return rv;
+
+ // get the lines that we're supposed to be writing to the file
+ uint32_t prefCount;
+ UniquePtr<char*[]> valueArray = pref_savePrefs(gHashTable, &prefCount);
+
+ /* Sort the preferences to make a readable file on disk */
+ NS_QuickSort(valueArray.get(), prefCount, sizeof(char *),
+ pref_CompareStrings, nullptr);
+
+ // write out the file header
+ outStream->Write(kPrefFileHeader, sizeof(kPrefFileHeader) - 1, &writeAmount);
+
+ for (uint32_t valueIdx = 0; valueIdx < prefCount; valueIdx++) {
+ char*& pref = valueArray[valueIdx];
+ MOZ_ASSERT(pref);
+ outStream->Write(pref, strlen(pref), &writeAmount);
+ outStream->Write(NS_LINEBREAK, NS_LINEBREAK_LEN, &writeAmount);
+ free(pref);
+ pref = nullptr;
+ }
+
+ // tell the safe output stream to overwrite the real prefs file
+ // (it'll abort if there were any errors during writing)
+ nsCOMPtr<nsISafeOutputStream> safeStream = do_QueryInterface(outStream);
+ NS_ASSERTION(safeStream, "expected a safe output stream!");
+ if (safeStream) {
+ rv = safeStream->Finish();
+ if (NS_FAILED(rv)) {
+ NS_WARNING("failed to save prefs file! possible data loss");
+ return rv;
+ }
+ }
+
+ mDirty = false;
+ return NS_OK;
+}
+
+static nsresult openPrefFile(nsIFile* aFile)
+{
+ nsCOMPtr<nsIInputStream> inStr;
+
+ nsresult rv = NS_NewLocalFileInputStream(getter_AddRefs(inStr), aFile);
+ if (NS_FAILED(rv))
+ return rv;
+
+ int64_t fileSize64;
+ rv = aFile->GetFileSize(&fileSize64);
+ if (NS_FAILED(rv))
+ return rv;
+ NS_ENSURE_TRUE(fileSize64 <= UINT32_MAX, NS_ERROR_FILE_TOO_BIG);
+
+ uint32_t fileSize = (uint32_t)fileSize64;
+ auto fileBuffer = MakeUniqueFallible<char[]>(fileSize);
+ if (fileBuffer == nullptr)
+ return NS_ERROR_OUT_OF_MEMORY;
+
+ PrefParseState ps;
+ PREF_InitParseState(&ps, PREF_ReaderCallback, ReportToConsole, nullptr);
+
+ // Read is not guaranteed to return a buf the size of fileSize,
+ // but usually will.
+ nsresult rv2 = NS_OK;
+ uint32_t offset = 0;
+ for (;;) {
+ uint32_t amtRead = 0;
+ rv = inStr->Read(fileBuffer.get(), fileSize, &amtRead);
+ if (NS_FAILED(rv) || amtRead == 0)
+ break;
+ if (!PREF_ParseBuf(&ps, fileBuffer.get(), amtRead))
+ rv2 = NS_ERROR_FILE_CORRUPTED;
+ offset += amtRead;
+ if (offset == fileSize) {
+ break;
+ }
+ }
+
+ PREF_FinalizeParseState(&ps);
+
+ return NS_FAILED(rv) ? rv : rv2;
+}
+
+/*
+ * some stuff that gets called from Pref_Init()
+ */
+
+static int
+pref_CompareFileNames(nsIFile* aFile1, nsIFile* aFile2, void* /*unused*/)
+{
+ nsAutoCString filename1, filename2;
+ aFile1->GetNativeLeafName(filename1);
+ aFile2->GetNativeLeafName(filename2);
+
+ return Compare(filename2, filename1);
+}
+
+/**
+ * Load default pref files from a directory. The files in the
+ * directory are sorted reverse-alphabetically; a set of "special file
+ * names" may be specified which are loaded after all the others.
+ */
+static nsresult
+pref_LoadPrefsInDir(nsIFile* aDir, char const *const *aSpecialFiles, uint32_t aSpecialFilesCount)
+{
+ nsresult rv, rv2;
+ bool hasMoreElements;
+
+ nsCOMPtr<nsISimpleEnumerator> dirIterator;
+
+ // this may fail in some normal cases, such as embedders who do not use a GRE
+ rv = aDir->GetDirectoryEntries(getter_AddRefs(dirIterator));
+ if (NS_FAILED(rv)) {
+ // If the directory doesn't exist, then we have no reason to complain. We
+ // loaded everything (and nothing) successfully.
+ if (rv == NS_ERROR_FILE_NOT_FOUND || rv == NS_ERROR_FILE_TARGET_DOES_NOT_EXIST)
+ rv = NS_OK;
+ return rv;
+ }
+
+ rv = dirIterator->HasMoreElements(&hasMoreElements);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ nsCOMArray<nsIFile> prefFiles(INITIAL_PREF_FILES);
+ nsCOMArray<nsIFile> specialFiles(aSpecialFilesCount);
+ nsCOMPtr<nsIFile> prefFile;
+
+ while (hasMoreElements && NS_SUCCEEDED(rv)) {
+ nsAutoCString leafName;
+
+ nsCOMPtr<nsISupports> supports;
+ rv = dirIterator->GetNext(getter_AddRefs(supports));
+ prefFile = do_QueryInterface(supports);
+ if (NS_FAILED(rv)) {
+ break;
+ }
+
+ prefFile->GetNativeLeafName(leafName);
+ NS_ASSERTION(!leafName.IsEmpty(), "Failure in default prefs: directory enumerator returned empty file?");
+
+ // Skip non-js files
+ if (StringEndsWith(leafName, NS_LITERAL_CSTRING(".js"),
+ nsCaseInsensitiveCStringComparator())) {
+ bool shouldParse = true;
+ // separate out special files
+ for (uint32_t i = 0; i < aSpecialFilesCount; ++i) {
+ if (leafName.Equals(nsDependentCString(aSpecialFiles[i]))) {
+ shouldParse = false;
+ // special files should be process in order; we put them into
+ // the array by index; this can make the array sparse
+ specialFiles.ReplaceObjectAt(prefFile, i);
+ }
+ }
+
+ if (shouldParse) {
+ prefFiles.AppendObject(prefFile);
+ }
+ }
+
+ rv = dirIterator->HasMoreElements(&hasMoreElements);
+ }
+
+ if (prefFiles.Count() + specialFiles.Count() == 0) {
+ NS_WARNING("No default pref files found.");
+ if (NS_SUCCEEDED(rv)) {
+ rv = NS_SUCCESS_FILE_DIRECTORY_EMPTY;
+ }
+ return rv;
+ }
+
+ prefFiles.Sort(pref_CompareFileNames, nullptr);
+
+ uint32_t arrayCount = prefFiles.Count();
+ uint32_t i;
+ for (i = 0; i < arrayCount; ++i) {
+ rv2 = openPrefFile(prefFiles[i]);
+ if (NS_FAILED(rv2)) {
+ NS_ERROR("Default pref file not parsed successfully.");
+ rv = rv2;
+ }
+ }
+
+ arrayCount = specialFiles.Count();
+ for (i = 0; i < arrayCount; ++i) {
+ // this may be a sparse array; test before parsing
+ nsIFile* file = specialFiles[i];
+ if (file) {
+ rv2 = openPrefFile(file);
+ if (NS_FAILED(rv2)) {
+ NS_ERROR("Special default pref file not parsed successfully.");
+ rv = rv2;
+ }
+ }
+ }
+
+ return rv;
+}
+
+static nsresult pref_LoadPrefsInDirList(const char *listId)
+{
+ nsresult rv;
+ nsCOMPtr<nsIProperties> dirSvc(do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID, &rv));
+ if (NS_FAILED(rv))
+ return rv;
+
+ nsCOMPtr<nsISimpleEnumerator> list;
+ dirSvc->Get(listId,
+ NS_GET_IID(nsISimpleEnumerator),
+ getter_AddRefs(list));
+ if (!list)
+ return NS_OK;
+
+ bool hasMore;
+ while (NS_SUCCEEDED(list->HasMoreElements(&hasMore)) && hasMore) {
+ nsCOMPtr<nsISupports> elem;
+ list->GetNext(getter_AddRefs(elem));
+ if (!elem)
+ continue;
+
+ nsCOMPtr<nsIFile> path = do_QueryInterface(elem);
+ if (!path)
+ continue;
+
+ nsAutoCString leaf;
+ path->GetNativeLeafName(leaf);
+
+ // Do we care if a file provided by this process fails to load?
+ if (Substring(leaf, leaf.Length() - 4).EqualsLiteral(".xpi"))
+ ReadExtensionPrefs(path);
+ else
+ pref_LoadPrefsInDir(path, nullptr, 0);
+ }
+ return NS_OK;
+}
+
+static nsresult pref_ReadPrefFromJar(nsZipArchive* jarReader, const char *name)
+{
+ nsZipItemPtr<char> manifest(jarReader, name, true);
+ NS_ENSURE_TRUE(manifest.Buffer(), NS_ERROR_NOT_AVAILABLE);
+
+ PrefParseState ps;
+ PREF_InitParseState(&ps, PREF_ReaderCallback, ReportToConsole, nullptr);
+ PREF_ParseBuf(&ps, manifest, manifest.Length());
+ PREF_FinalizeParseState(&ps);
+
+ return NS_OK;
+}
+
+//----------------------------------------------------------------------------------------
+// Initialize default preference JavaScript buffers from
+// appropriate TEXT resources
+//----------------------------------------------------------------------------------------
+static nsresult pref_InitInitialObjects()
+{
+ nsresult rv;
+
+ // In omni.jar case, we load the following prefs:
+ // - jar:$gre/omni.jar!/greprefs.js
+ // - jar:$gre/omni.jar!/defaults/pref/*.js
+ // In non omni.jar case, we load:
+ // - $gre/greprefs.js
+ //
+ // In both cases, we also load:
+ // - $gre/defaults/pref/*.js
+ // This is kept for bug 591866 (channel-prefs.js should not be in omni.jar)
+ // on $app == $gre case ; we load all files instead of channel-prefs.js only
+ // to have the same behaviour as $app != $gre, where this is required as
+ // a supported location for GRE preferences.
+ //
+ // When $app != $gre, we additionally load, in omni.jar case:
+ // - jar:$app/omni.jar!/defaults/preferences/*.js
+ // - $app/defaults/preferences/*.js
+ // and in non omni.jar case:
+ // - $app/defaults/preferences/*.js
+ // When $app == $gre, we additionally load, in omni.jar case:
+ // - jar:$gre/omni.jar!/defaults/preferences/*.js
+ // Thus, in omni.jar case, we always load app-specific default preferences
+ // from omni.jar, whether or not $app == $gre.
+
+ nsZipFind *findPtr;
+ nsAutoPtr<nsZipFind> find;
+ nsTArray<nsCString> prefEntries;
+ const char *entryName;
+ uint16_t entryNameLen;
+
+ RefPtr<nsZipArchive> jarReader = mozilla::Omnijar::GetReader(mozilla::Omnijar::GRE);
+ if (jarReader) {
+ // Load jar:$gre/omni.jar!/greprefs.js
+ rv = pref_ReadPrefFromJar(jarReader, "greprefs.js");
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ // Load jar:$gre/omni.jar!/defaults/pref/*.js
+ rv = jarReader->FindInit("defaults/pref/*.js$", &findPtr);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ find = findPtr;
+ while (NS_SUCCEEDED(find->FindNext(&entryName, &entryNameLen))) {
+ prefEntries.AppendElement(Substring(entryName, entryNameLen));
+ }
+
+ prefEntries.Sort();
+ for (uint32_t i = prefEntries.Length(); i--; ) {
+ rv = pref_ReadPrefFromJar(jarReader, prefEntries[i].get());
+ if (NS_FAILED(rv))
+ NS_WARNING("Error parsing preferences.");
+ }
+ } else {
+ // Load $gre/greprefs.js
+ nsCOMPtr<nsIFile> greprefsFile;
+ rv = NS_GetSpecialDirectory(NS_GRE_DIR, getter_AddRefs(greprefsFile));
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ rv = greprefsFile->AppendNative(NS_LITERAL_CSTRING("greprefs.js"));
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ rv = openPrefFile(greprefsFile);
+ if (NS_FAILED(rv))
+ NS_WARNING("Error parsing GRE default preferences. Is this an old-style embedding app?");
+ }
+
+ // Load $gre/defaults/pref/*.js
+ nsCOMPtr<nsIFile> defaultPrefDir;
+
+ rv = NS_GetSpecialDirectory(NS_APP_PREF_DEFAULTS_50_DIR, getter_AddRefs(defaultPrefDir));
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ /* these pref file names should not be used: we process them after all other application pref files for backwards compatibility */
+ static const char* specialFiles[] = {
+#if defined(XP_MACOSX)
+ "macprefs.js"
+#elif defined(XP_WIN)
+ "winpref.js"
+#elif defined(XP_UNIX)
+ "unix.js"
+#if defined(_AIX)
+ , "aix.js"
+#endif
+#elif defined(XP_BEOS)
+ "beos.js"
+#endif
+ };
+
+ rv = pref_LoadPrefsInDir(defaultPrefDir, specialFiles, ArrayLength(specialFiles));
+ if (NS_FAILED(rv))
+ NS_WARNING("Error parsing application default preferences.");
+
+ // Load jar:$app/omni.jar!/defaults/preferences/*.js
+ // or jar:$gre/omni.jar!/defaults/preferences/*.js.
+ RefPtr<nsZipArchive> appJarReader = mozilla::Omnijar::GetReader(mozilla::Omnijar::APP);
+ // GetReader(mozilla::Omnijar::APP) returns null when $app == $gre, in which
+ // case we look for app-specific default preferences in $gre.
+ if (!appJarReader)
+ appJarReader = mozilla::Omnijar::GetReader(mozilla::Omnijar::GRE);
+ if (appJarReader) {
+ rv = appJarReader->FindInit("defaults/preferences/*.js$", &findPtr);
+ NS_ENSURE_SUCCESS(rv, rv);
+ find = findPtr;
+ prefEntries.Clear();
+ while (NS_SUCCEEDED(find->FindNext(&entryName, &entryNameLen))) {
+ prefEntries.AppendElement(Substring(entryName, entryNameLen));
+ }
+ prefEntries.Sort();
+ for (uint32_t i = prefEntries.Length(); i--; ) {
+ rv = pref_ReadPrefFromJar(appJarReader, prefEntries[i].get());
+ if (NS_FAILED(rv))
+ NS_WARNING("Error parsing preferences.");
+ }
+ }
+
+ rv = pref_LoadPrefsInDirList(NS_APP_PREFS_DEFAULTS_DIR_LIST);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ // Set up the correct default for toolkit.telemetry.enabled.
+ // If this build has MOZ_TELEMETRY_ON_BY_DEFAULT *or* we're on the beta
+ // channel, telemetry is on by default, otherwise not. This is necessary
+ // so that beta users who are testing final release builds don't flipflop
+ // defaults.
+ if (Preferences::GetDefaultType(kTelemetryPref) == nsIPrefBranch::PREF_INVALID) {
+ bool prerelease = false;
+#ifdef MOZ_TELEMETRY_ON_BY_DEFAULT
+ prerelease = true;
+#else
+ if (Preferences::GetDefaultCString(kChannelPref).EqualsLiteral("beta")) {
+ prerelease = true;
+ }
+#endif
+ PREF_SetBoolPref(kTelemetryPref, prerelease, true);
+ }
+
+ NS_CreateServicesFromCategory(NS_PREFSERVICE_APPDEFAULTS_TOPIC_ID,
+ nullptr, NS_PREFSERVICE_APPDEFAULTS_TOPIC_ID);
+
+ nsCOMPtr<nsIObserverService> observerService =
+ mozilla::services::GetObserverService();
+ if (!observerService)
+ return NS_ERROR_FAILURE;
+
+ observerService->NotifyObservers(nullptr, NS_PREFSERVICE_APPDEFAULTS_TOPIC_ID, nullptr);
+
+ return pref_LoadPrefsInDirList(NS_EXT_PREFS_DEFAULTS_DIR_LIST);
+}
+
+
+/******************************************************************************
+ *
+ * static utilities
+ *
+ ******************************************************************************/
+
+// static
+nsresult
+Preferences::GetBool(const char* aPref, bool* aResult)
+{
+ NS_PRECONDITION(aResult, "aResult must not be NULL");
+ NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
+ return PREF_GetBoolPref(aPref, aResult, false);
+}
+
+// static
+nsresult
+Preferences::GetInt(const char* aPref, int32_t* aResult)
+{
+ NS_PRECONDITION(aResult, "aResult must not be NULL");
+ NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
+ return PREF_GetIntPref(aPref, aResult, false);
+}
+
+// static
+nsresult
+Preferences::GetFloat(const char* aPref, float* aResult)
+{
+ NS_PRECONDITION(aResult, "aResult must not be NULL");
+ NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
+ nsAutoCString result;
+ nsresult rv = PREF_CopyCharPref(aPref, getter_Copies(result), false);
+ if (NS_SUCCEEDED(rv)) {
+ *aResult = result.ToFloat(&rv);
+ }
+
+ return rv;
+}
+
+// static
+nsAdoptingCString
+Preferences::GetCString(const char* aPref)
+{
+ nsAdoptingCString result;
+ PREF_CopyCharPref(aPref, getter_Copies(result), false);
+ return result;
+}
+
+// static
+nsAdoptingString
+Preferences::GetString(const char* aPref)
+{
+ nsAdoptingString result;
+ GetString(aPref, &result);
+ return result;
+}
+
+// static
+nsresult
+Preferences::GetCString(const char* aPref, nsACString* aResult)
+{
+ NS_PRECONDITION(aResult, "aResult must not be NULL");
+ NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
+ nsAutoCString result;
+ nsresult rv = PREF_CopyCharPref(aPref, getter_Copies(result), false);
+ if (NS_SUCCEEDED(rv)) {
+ *aResult = result;
+ }
+ return rv;
+}
+
+// static
+nsresult
+Preferences::GetString(const char* aPref, nsAString* aResult)
+{
+ NS_PRECONDITION(aResult, "aResult must not be NULL");
+ NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
+ nsAutoCString result;
+ nsresult rv = PREF_CopyCharPref(aPref, getter_Copies(result), false);
+ if (NS_SUCCEEDED(rv)) {
+ CopyUTF8toUTF16(result, *aResult);
+ }
+ return rv;
+}
+
+// static
+nsAdoptingCString
+Preferences::GetLocalizedCString(const char* aPref)
+{
+ nsAdoptingCString result;
+ GetLocalizedCString(aPref, &result);
+ return result;
+}
+
+// static
+nsAdoptingString
+Preferences::GetLocalizedString(const char* aPref)
+{
+ nsAdoptingString result;
+ GetLocalizedString(aPref, &result);
+ return result;
+}
+
+// static
+nsresult
+Preferences::GetLocalizedCString(const char* aPref, nsACString* aResult)
+{
+ NS_PRECONDITION(aResult, "aResult must not be NULL");
+ nsAutoString result;
+ nsresult rv = GetLocalizedString(aPref, &result);
+ if (NS_SUCCEEDED(rv)) {
+ CopyUTF16toUTF8(result, *aResult);
+ }
+ return rv;
+}
+
+// static
+nsresult
+Preferences::GetLocalizedString(const char* aPref, nsAString* aResult)
+{
+ NS_PRECONDITION(aResult, "aResult must not be NULL");
+ NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
+ nsCOMPtr<nsIPrefLocalizedString> prefLocalString;
+ nsresult rv = sRootBranch->GetComplexValue(aPref,
+ NS_GET_IID(nsIPrefLocalizedString),
+ getter_AddRefs(prefLocalString));
+ if (NS_SUCCEEDED(rv)) {
+ NS_ASSERTION(prefLocalString, "Succeeded but the result is NULL");
+ prefLocalString->GetData(getter_Copies(*aResult));
+ }
+ return rv;
+}
+
+// static
+nsresult
+Preferences::GetComplex(const char* aPref, const nsIID &aType, void** aResult)
+{
+ NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
+ return sRootBranch->GetComplexValue(aPref, aType, aResult);
+}
+
+// static
+nsresult
+Preferences::SetCString(const char* aPref, const char* aValue)
+{
+ ENSURE_MAIN_PROCESS("Cannot SetCString from content process:", aPref);
+ NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
+ return PREF_SetCharPref(aPref, aValue, false);
+}
+
+// static
+nsresult
+Preferences::SetCString(const char* aPref, const nsACString &aValue)
+{
+ ENSURE_MAIN_PROCESS("Cannot SetCString from content process:", aPref);
+ NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
+ return PREF_SetCharPref(aPref, PromiseFlatCString(aValue).get(), false);
+}
+
+// static
+nsresult
+Preferences::SetString(const char* aPref, const char16ptr_t aValue)
+{
+ ENSURE_MAIN_PROCESS("Cannot SetString from content process:", aPref);
+ NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
+ return PREF_SetCharPref(aPref, NS_ConvertUTF16toUTF8(aValue).get(), false);
+}
+
+// static
+nsresult
+Preferences::SetString(const char* aPref, const nsAString &aValue)
+{
+ ENSURE_MAIN_PROCESS("Cannot SetString from content process:", aPref);
+ NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
+ return PREF_SetCharPref(aPref, NS_ConvertUTF16toUTF8(aValue).get(), false);
+}
+
+// static
+nsresult
+Preferences::SetBool(const char* aPref, bool aValue)
+{
+ ENSURE_MAIN_PROCESS("Cannot SetBool from content process:", aPref);
+ NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
+ return PREF_SetBoolPref(aPref, aValue, false);
+}
+
+// static
+nsresult
+Preferences::SetInt(const char* aPref, int32_t aValue)
+{
+ ENSURE_MAIN_PROCESS("Cannot SetInt from content process:", aPref);
+ NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
+ return PREF_SetIntPref(aPref, aValue, false);
+}
+
+// static
+nsresult
+Preferences::SetFloat(const char* aPref, float aValue)
+{
+ return SetCString(aPref, nsPrintfCString("%f", aValue).get());
+}
+
+// static
+nsresult
+Preferences::SetComplex(const char* aPref, const nsIID &aType,
+ nsISupports* aValue)
+{
+ NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
+ return sRootBranch->SetComplexValue(aPref, aType, aValue);
+}
+
+// static
+nsresult
+Preferences::ClearUser(const char* aPref)
+{
+ ENSURE_MAIN_PROCESS("Cannot ClearUser from content process:", aPref);
+ NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
+ return PREF_ClearUserPref(aPref);
+}
+
+// static
+bool
+Preferences::HasUserValue(const char* aPref)
+{
+ NS_ENSURE_TRUE(InitStaticMembers(), false);
+ return PREF_HasUserPref(aPref);
+}
+
+// static
+int32_t
+Preferences::GetType(const char* aPref)
+{
+ NS_ENSURE_TRUE(InitStaticMembers(), nsIPrefBranch::PREF_INVALID);
+ int32_t result;
+ return NS_SUCCEEDED(sRootBranch->GetPrefType(aPref, &result)) ?
+ result : nsIPrefBranch::PREF_INVALID;
+}
+
+// static
+nsresult
+Preferences::AddStrongObserver(nsIObserver* aObserver,
+ const char* aPref)
+{
+ NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
+ return sRootBranch->AddObserver(aPref, aObserver, false);
+}
+
+// static
+nsresult
+Preferences::AddWeakObserver(nsIObserver* aObserver,
+ const char* aPref)
+{
+ NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
+ return sRootBranch->AddObserver(aPref, aObserver, true);
+}
+
+// static
+nsresult
+Preferences::RemoveObserver(nsIObserver* aObserver,
+ const char* aPref)
+{
+ if (!sPreferences && sShutdown) {
+ return NS_OK; // Observers have been released automatically.
+ }
+ NS_ENSURE_TRUE(sPreferences, NS_ERROR_NOT_AVAILABLE);
+ return sRootBranch->RemoveObserver(aPref, aObserver);
+}
+
+// static
+nsresult
+Preferences::AddStrongObservers(nsIObserver* aObserver,
+ const char** aPrefs)
+{
+ for (uint32_t i = 0; aPrefs[i]; i++) {
+ nsresult rv = AddStrongObserver(aObserver, aPrefs[i]);
+ NS_ENSURE_SUCCESS(rv, rv);
+ }
+ return NS_OK;
+}
+
+// static
+nsresult
+Preferences::AddWeakObservers(nsIObserver* aObserver,
+ const char** aPrefs)
+{
+ for (uint32_t i = 0; aPrefs[i]; i++) {
+ nsresult rv = AddWeakObserver(aObserver, aPrefs[i]);
+ NS_ENSURE_SUCCESS(rv, rv);
+ }
+ return NS_OK;
+}
+
+// static
+nsresult
+Preferences::RemoveObservers(nsIObserver* aObserver,
+ const char** aPrefs)
+{
+ if (!sPreferences && sShutdown) {
+ return NS_OK; // Observers have been released automatically.
+ }
+ NS_ENSURE_TRUE(sPreferences, NS_ERROR_NOT_AVAILABLE);
+
+ for (uint32_t i = 0; aPrefs[i]; i++) {
+ nsresult rv = RemoveObserver(aObserver, aPrefs[i]);
+ NS_ENSURE_SUCCESS(rv, rv);
+ }
+ return NS_OK;
+}
+
+// static
+nsresult
+Preferences::RegisterCallback(PrefChangedFunc aCallback,
+ const char* aPref,
+ void* aClosure,
+ MatchKind aMatchKind)
+{
+ NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
+
+ ValueObserverHashKey hashKey(aPref, aCallback, aMatchKind);
+ RefPtr<ValueObserver> observer;
+ gObserverTable->Get(&hashKey, getter_AddRefs(observer));
+ if (observer) {
+ observer->AppendClosure(aClosure);
+ return NS_OK;
+ }
+
+ observer = new ValueObserver(aPref, aCallback, aMatchKind);
+ observer->AppendClosure(aClosure);
+ nsresult rv = AddStrongObserver(observer, aPref);
+ NS_ENSURE_SUCCESS(rv, rv);
+ gObserverTable->Put(observer, observer);
+ return NS_OK;
+}
+
+// static
+nsresult
+Preferences::RegisterCallbackAndCall(PrefChangedFunc aCallback,
+ const char* aPref,
+ void* aClosure,
+ MatchKind aMatchKind)
+{
+ nsresult rv = RegisterCallback(aCallback, aPref, aClosure, aMatchKind);
+ if (NS_SUCCEEDED(rv)) {
+ (*aCallback)(aPref, aClosure);
+ }
+ return rv;
+}
+
+// static
+nsresult
+Preferences::UnregisterCallback(PrefChangedFunc aCallback,
+ const char* aPref,
+ void* aClosure,
+ MatchKind aMatchKind)
+{
+ if (!sPreferences && sShutdown) {
+ return NS_OK; // Observers have been released automatically.
+ }
+ NS_ENSURE_TRUE(sPreferences, NS_ERROR_NOT_AVAILABLE);
+
+ ValueObserverHashKey hashKey(aPref, aCallback, aMatchKind);
+ RefPtr<ValueObserver> observer;
+ gObserverTable->Get(&hashKey, getter_AddRefs(observer));
+ if (!observer) {
+ return NS_OK;
+ }
+
+ observer->RemoveClosure(aClosure);
+ if (observer->HasNoClosures()) {
+ // Delete the callback since its list of closures is empty.
+ gObserverTable->Remove(observer);
+ }
+ return NS_OK;
+}
+
+static void BoolVarChanged(const char* aPref, void* aClosure)
+{
+ CacheData* cache = static_cast<CacheData*>(aClosure);
+ *((bool*)cache->cacheLocation) =
+ Preferences::GetBool(aPref, cache->defaultValueBool);
+}
+
+// static
+nsresult
+Preferences::AddBoolVarCache(bool* aCache,
+ const char* aPref,
+ bool aDefault)
+{
+ NS_ASSERTION(aCache, "aCache must not be NULL");
+#ifdef DEBUG
+ AssertNotAlreadyCached("bool", aPref, aCache);
+#endif
+ *aCache = GetBool(aPref, aDefault);
+ CacheData* data = new CacheData();
+ data->cacheLocation = aCache;
+ data->defaultValueBool = aDefault;
+ gCacheData->AppendElement(data);
+ return RegisterCallback(BoolVarChanged, aPref, data, ExactMatch);
+}
+
+static void IntVarChanged(const char* aPref, void* aClosure)
+{
+ CacheData* cache = static_cast<CacheData*>(aClosure);
+ *((int32_t*)cache->cacheLocation) =
+ Preferences::GetInt(aPref, cache->defaultValueInt);
+}
+
+// static
+nsresult
+Preferences::AddIntVarCache(int32_t* aCache,
+ const char* aPref,
+ int32_t aDefault)
+{
+ NS_ASSERTION(aCache, "aCache must not be NULL");
+#ifdef DEBUG
+ AssertNotAlreadyCached("int", aPref, aCache);
+#endif
+ *aCache = Preferences::GetInt(aPref, aDefault);
+ CacheData* data = new CacheData();
+ data->cacheLocation = aCache;
+ data->defaultValueInt = aDefault;
+ gCacheData->AppendElement(data);
+ return RegisterCallback(IntVarChanged, aPref, data, ExactMatch);
+}
+
+static void UintVarChanged(const char* aPref, void* aClosure)
+{
+ CacheData* cache = static_cast<CacheData*>(aClosure);
+ *((uint32_t*)cache->cacheLocation) =
+ Preferences::GetUint(aPref, cache->defaultValueUint);
+}
+
+// static
+nsresult
+Preferences::AddUintVarCache(uint32_t* aCache,
+ const char* aPref,
+ uint32_t aDefault)
+{
+ NS_ASSERTION(aCache, "aCache must not be NULL");
+#ifdef DEBUG
+ AssertNotAlreadyCached("uint", aPref, aCache);
+#endif
+ *aCache = Preferences::GetUint(aPref, aDefault);
+ CacheData* data = new CacheData();
+ data->cacheLocation = aCache;
+ data->defaultValueUint = aDefault;
+ gCacheData->AppendElement(data);
+ return RegisterCallback(UintVarChanged, aPref, data, ExactMatch);
+}
+
+template <MemoryOrdering Order>
+static void AtomicUintVarChanged(const char* aPref, void* aClosure)
+{
+ CacheData* cache = static_cast<CacheData*>(aClosure);
+ *((Atomic<uint32_t, Order>*)cache->cacheLocation) =
+ Preferences::GetUint(aPref, cache->defaultValueUint);
+}
+
+template <MemoryOrdering Order>
+// static
+nsresult
+Preferences::AddAtomicUintVarCache(Atomic<uint32_t, Order>* aCache,
+ const char* aPref,
+ uint32_t aDefault)
+{
+ NS_ASSERTION(aCache, "aCache must not be NULL");
+#ifdef DEBUG
+ AssertNotAlreadyCached("uint", aPref, aCache);
+#endif
+ *aCache = Preferences::GetUint(aPref, aDefault);
+ CacheData* data = new CacheData();
+ data->cacheLocation = aCache;
+ data->defaultValueUint = aDefault;
+ gCacheData->AppendElement(data);
+ return RegisterCallback(AtomicUintVarChanged<Order>, aPref, data, ExactMatch);
+}
+
+// Since the definition of this template function is not in a header file,
+// we need to explicitly specify the instantiations that are required.
+// Currently only the order=Relaxed variant is needed.
+template
+nsresult Preferences::AddAtomicUintVarCache(Atomic<uint32_t,Relaxed>*,
+ const char*, uint32_t);
+
+static void FloatVarChanged(const char* aPref, void* aClosure)
+{
+ CacheData* cache = static_cast<CacheData*>(aClosure);
+ *((float*)cache->cacheLocation) =
+ Preferences::GetFloat(aPref, cache->defaultValueFloat);
+}
+
+// static
+nsresult
+Preferences::AddFloatVarCache(float* aCache,
+ const char* aPref,
+ float aDefault)
+{
+ NS_ASSERTION(aCache, "aCache must not be NULL");
+#ifdef DEBUG
+ AssertNotAlreadyCached("float", aPref, aCache);
+#endif
+ *aCache = Preferences::GetFloat(aPref, aDefault);
+ CacheData* data = new CacheData();
+ data->cacheLocation = aCache;
+ data->defaultValueFloat = aDefault;
+ gCacheData->AppendElement(data);
+ return RegisterCallback(FloatVarChanged, aPref, data, ExactMatch);
+}
+
+// static
+nsresult
+Preferences::GetDefaultBool(const char* aPref, bool* aResult)
+{
+ NS_PRECONDITION(aResult, "aResult must not be NULL");
+ NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
+ return PREF_GetBoolPref(aPref, aResult, true);
+}
+
+// static
+nsresult
+Preferences::GetDefaultInt(const char* aPref, int32_t* aResult)
+{
+ NS_PRECONDITION(aResult, "aResult must not be NULL");
+ NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
+ return PREF_GetIntPref(aPref, aResult, true);
+}
+
+// static
+nsresult
+Preferences::GetDefaultCString(const char* aPref, nsACString* aResult)
+{
+ NS_PRECONDITION(aResult, "aResult must not be NULL");
+ NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
+ nsAutoCString result;
+ nsresult rv = PREF_CopyCharPref(aPref, getter_Copies(result), true);
+ if (NS_SUCCEEDED(rv)) {
+ *aResult = result;
+ }
+ return rv;
+}
+
+// static
+nsresult
+Preferences::GetDefaultString(const char* aPref, nsAString* aResult)
+{
+ NS_PRECONDITION(aResult, "aResult must not be NULL");
+ NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
+ nsAutoCString result;
+ nsresult rv = PREF_CopyCharPref(aPref, getter_Copies(result), true);
+ if (NS_SUCCEEDED(rv)) {
+ CopyUTF8toUTF16(result, *aResult);
+ }
+ return rv;
+}
+
+// static
+nsresult
+Preferences::GetDefaultLocalizedCString(const char* aPref,
+ nsACString* aResult)
+{
+ nsAutoString result;
+ nsresult rv = GetDefaultLocalizedString(aPref, &result);
+ if (NS_SUCCEEDED(rv)) {
+ CopyUTF16toUTF8(result, *aResult);
+ }
+ return rv;
+}
+
+// static
+nsresult
+Preferences::GetDefaultLocalizedString(const char* aPref,
+ nsAString* aResult)
+{
+ NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
+ nsCOMPtr<nsIPrefLocalizedString> prefLocalString;
+ nsresult rv =
+ sDefaultRootBranch->GetComplexValue(aPref,
+ NS_GET_IID(nsIPrefLocalizedString),
+ getter_AddRefs(prefLocalString));
+ if (NS_SUCCEEDED(rv)) {
+ NS_ASSERTION(prefLocalString, "Succeeded but the result is NULL");
+ prefLocalString->GetData(getter_Copies(*aResult));
+ }
+ return rv;
+}
+
+// static
+nsAdoptingString
+Preferences::GetDefaultString(const char* aPref)
+{
+ nsAdoptingString result;
+ GetDefaultString(aPref, &result);
+ return result;
+}
+
+// static
+nsAdoptingCString
+Preferences::GetDefaultCString(const char* aPref)
+{
+ nsAdoptingCString result;
+ PREF_CopyCharPref(aPref, getter_Copies(result), true);
+ return result;
+}
+
+// static
+nsAdoptingString
+Preferences::GetDefaultLocalizedString(const char* aPref)
+{
+ nsAdoptingString result;
+ GetDefaultLocalizedString(aPref, &result);
+ return result;
+}
+
+// static
+nsAdoptingCString
+Preferences::GetDefaultLocalizedCString(const char* aPref)
+{
+ nsAdoptingCString result;
+ GetDefaultLocalizedCString(aPref, &result);
+ return result;
+}
+
+// static
+nsresult
+Preferences::GetDefaultComplex(const char* aPref, const nsIID &aType,
+ void** aResult)
+{
+ NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
+ return sDefaultRootBranch->GetComplexValue(aPref, aType, aResult);
+}
+
+// static
+int32_t
+Preferences::GetDefaultType(const char* aPref)
+{
+ NS_ENSURE_TRUE(InitStaticMembers(), nsIPrefBranch::PREF_INVALID);
+ int32_t result;
+ return NS_SUCCEEDED(sDefaultRootBranch->GetPrefType(aPref, &result)) ?
+ result : nsIPrefBranch::PREF_INVALID;
+}
+
+} // namespace mozilla
+
+#undef ENSURE_MAIN_PROCESS
diff --git a/modules/libpref/Preferences.h b/modules/libpref/Preferences.h
new file mode 100644
index 000000000..255d2a8d2
--- /dev/null
+++ b/modules/libpref/Preferences.h
@@ -0,0 +1,408 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_Preferences_h
+#define mozilla_Preferences_h
+
+#ifndef MOZILLA_INTERNAL_API
+#error "This header is only usable from within libxul (MOZILLA_INTERNAL_API)."
+#endif
+
+#include "nsIPrefService.h"
+#include "nsIPrefBranch.h"
+#include "nsIPrefBranchInternal.h"
+#include "nsIObserver.h"
+#include "nsCOMPtr.h"
+#include "nsTArray.h"
+#include "nsWeakReference.h"
+#include "mozilla/MemoryReporting.h"
+
+class nsIFile;
+class nsAdoptingString;
+class nsAdoptingCString;
+
+#ifndef have_PrefChangedFunc_typedef
+typedef void (*PrefChangedFunc)(const char *, void *);
+#define have_PrefChangedFunc_typedef
+#endif
+
+namespace mozilla {
+
+namespace dom {
+class PrefSetting;
+} // namespace dom
+
+class Preferences final : public nsIPrefService,
+ public nsIObserver,
+ public nsIPrefBranchInternal,
+ public nsSupportsWeakReference
+{
+public:
+ typedef mozilla::dom::PrefSetting PrefSetting;
+
+ NS_DECL_THREADSAFE_ISUPPORTS
+ NS_DECL_NSIPREFSERVICE
+ NS_FORWARD_NSIPREFBRANCH(sRootBranch->)
+ NS_DECL_NSIOBSERVER
+
+ Preferences();
+
+ nsresult Init();
+
+ /**
+ * Returns true if the Preferences service is available, false otherwise.
+ */
+ static bool IsServiceAvailable();
+
+ /**
+ * Reset loaded user prefs then read them
+ */
+ static nsresult ResetAndReadUserPrefs();
+
+ /**
+ * Returns the singleton instance which is addreffed.
+ */
+ static Preferences* GetInstanceForService();
+
+ /**
+ * Finallizes global members.
+ */
+ static void Shutdown();
+
+ /**
+ * Returns shared pref service instance
+ * NOTE: not addreffed.
+ */
+ static nsIPrefService* GetService()
+ {
+ NS_ENSURE_TRUE(InitStaticMembers(), nullptr);
+ return sPreferences;
+ }
+
+ /**
+ * Returns shared pref branch instance.
+ * NOTE: not addreffed.
+ */
+ static nsIPrefBranch* GetRootBranch()
+ {
+ NS_ENSURE_TRUE(InitStaticMembers(), nullptr);
+ return sRootBranch;
+ }
+
+ /**
+ * Returns shared default pref branch instance.
+ * NOTE: not addreffed.
+ */
+ static nsIPrefBranch* GetDefaultRootBranch()
+ {
+ NS_ENSURE_TRUE(InitStaticMembers(), nullptr);
+ return sDefaultRootBranch;
+ }
+
+ /**
+ * Gets int or bool type pref value with default value if failed to get
+ * the pref.
+ */
+ static bool GetBool(const char* aPref, bool aDefault = false)
+ {
+ bool result = aDefault;
+ GetBool(aPref, &result);
+ return result;
+ }
+
+ static int32_t GetInt(const char* aPref, int32_t aDefault = 0)
+ {
+ int32_t result = aDefault;
+ GetInt(aPref, &result);
+ return result;
+ }
+
+ static uint32_t GetUint(const char* aPref, uint32_t aDefault = 0)
+ {
+ uint32_t result = aDefault;
+ GetUint(aPref, &result);
+ return result;
+ }
+
+ static float GetFloat(const char* aPref, float aDefault = 0)
+ {
+ float result = aDefault;
+ GetFloat(aPref, &result);
+ return result;
+ }
+
+ /**
+ * Gets char type pref value directly. If failed, the get() of result
+ * returns nullptr. Even if succeeded but the result was empty string, the
+ * get() does NOT return nullptr. So, you can check whether the method
+ * succeeded or not by:
+ *
+ * nsAdoptingString value = Prefereces::GetString("foo.bar");
+ * if (!value) {
+ * // failed
+ * }
+ *
+ * Be aware. If you wrote as:
+ *
+ * nsAutoString value = Preferences::GetString("foo.bar");
+ * if (!value.get()) {
+ * // the condition is always FALSE!!
+ * }
+ *
+ * The value.get() doesn't return nullptr. You must use nsAdoptingString
+ * when you need to check whether it was failure or not.
+ */
+ static nsAdoptingCString GetCString(const char* aPref);
+ static nsAdoptingString GetString(const char* aPref);
+ static nsAdoptingCString GetLocalizedCString(const char* aPref);
+ static nsAdoptingString GetLocalizedString(const char* aPref);
+
+ /**
+ * Gets int, float, or bool type pref value with raw return value of
+ * nsIPrefBranch.
+ *
+ * @param aPref A pref name.
+ * @param aResult Must not be nullptr. The value is never modified
+ * when these methods fail.
+ */
+ static nsresult GetBool(const char* aPref, bool* aResult);
+ static nsresult GetInt(const char* aPref, int32_t* aResult);
+ static nsresult GetFloat(const char* aPref, float* aResult);
+ static nsresult GetUint(const char* aPref, uint32_t* aResult)
+ {
+ int32_t result;
+ nsresult rv = GetInt(aPref, &result);
+ if (NS_SUCCEEDED(rv)) {
+ *aResult = static_cast<uint32_t>(result);
+ }
+ return rv;
+ }
+
+ /**
+ * Gets string type pref value with raw return value of nsIPrefBranch.
+ *
+ * @param aPref A pref name.
+ * @param aResult Must not be nullptr. The value is never modified
+ * when these methods fail.
+ */
+ static nsresult GetCString(const char* aPref, nsACString* aResult);
+ static nsresult GetString(const char* aPref, nsAString* aResult);
+ static nsresult GetLocalizedCString(const char* aPref, nsACString* aResult);
+ static nsresult GetLocalizedString(const char* aPref, nsAString* aResult);
+
+ static nsresult GetComplex(const char* aPref, const nsIID &aType,
+ void** aResult);
+
+ /**
+ * Sets various type pref values.
+ */
+ static nsresult SetBool(const char* aPref, bool aValue);
+ static nsresult SetInt(const char* aPref, int32_t aValue);
+ static nsresult SetUint(const char* aPref, uint32_t aValue)
+ {
+ return SetInt(aPref, static_cast<int32_t>(aValue));
+ }
+ static nsresult SetFloat(const char* aPref, float aValue);
+ static nsresult SetCString(const char* aPref, const char* aValue);
+ static nsresult SetCString(const char* aPref, const nsACString &aValue);
+ static nsresult SetString(const char* aPref, const char16ptr_t aValue);
+ static nsresult SetString(const char* aPref, const nsAString &aValue);
+
+ static nsresult SetComplex(const char* aPref, const nsIID &aType,
+ nsISupports* aValue);
+
+ /**
+ * Clears user set pref.
+ */
+ static nsresult ClearUser(const char* aPref);
+
+ /**
+ * Whether the pref has a user value or not.
+ */
+ static bool HasUserValue(const char* aPref);
+
+ /**
+ * Gets the type of the pref.
+ */
+ static int32_t GetType(const char* aPref);
+
+ /**
+ * Adds/Removes the observer for the root pref branch.
+ * The observer is referenced strongly if AddStrongObserver is used. On the
+ * other hand, it is referenced weakly, if AddWeakObserver is used.
+ * See nsIPrefBranch.idl for details.
+ */
+ static nsresult AddStrongObserver(nsIObserver* aObserver, const char* aPref);
+ static nsresult AddWeakObserver(nsIObserver* aObserver, const char* aPref);
+ static nsresult RemoveObserver(nsIObserver* aObserver, const char* aPref);
+
+ /**
+ * Adds/Removes two or more observers for the root pref branch.
+ * Pass to aPrefs an array of const char* whose last item is nullptr.
+ */
+ static nsresult AddStrongObservers(nsIObserver* aObserver,
+ const char** aPrefs);
+ static nsresult AddWeakObservers(nsIObserver* aObserver,
+ const char** aPrefs);
+ static nsresult RemoveObservers(nsIObserver* aObserver,
+ const char** aPrefs);
+
+ /**
+ * Registers/Unregisters the callback function for the aPref.
+ *
+ * Pass ExactMatch for aMatchKind to only get callbacks for
+ * exact matches and not prefixes.
+ */
+ enum MatchKind {
+ PrefixMatch,
+ ExactMatch,
+ };
+ static nsresult RegisterCallback(PrefChangedFunc aCallback,
+ const char* aPref,
+ void* aClosure = nullptr,
+ MatchKind aMatchKind = PrefixMatch);
+ static nsresult UnregisterCallback(PrefChangedFunc aCallback,
+ const char* aPref,
+ void* aClosure = nullptr,
+ MatchKind aMatchKind = PrefixMatch);
+ // Like RegisterCallback, but also calls the callback immediately for
+ // initialization.
+ static nsresult RegisterCallbackAndCall(PrefChangedFunc aCallback,
+ const char* aPref,
+ void* aClosure = nullptr,
+ MatchKind aMatchKind = PrefixMatch);
+
+ /**
+ * Adds the aVariable to cache table. aVariable must be a pointer for a
+ * static variable. The value will be modified when the pref value is
+ * changed but note that even if you modified it, the value isn't assigned to
+ * the pref.
+ */
+ static nsresult AddBoolVarCache(bool* aVariable,
+ const char* aPref,
+ bool aDefault = false);
+ static nsresult AddIntVarCache(int32_t* aVariable,
+ const char* aPref,
+ int32_t aDefault = 0);
+ static nsresult AddUintVarCache(uint32_t* aVariable,
+ const char* aPref,
+ uint32_t aDefault = 0);
+ template <MemoryOrdering Order>
+ static nsresult AddAtomicUintVarCache(Atomic<uint32_t, Order>* aVariable,
+ const char* aPref,
+ uint32_t aDefault = 0);
+ static nsresult AddFloatVarCache(float* aVariable,
+ const char* aPref,
+ float aDefault = 0.0f);
+
+ /**
+ * Gets the default bool, int or uint value of the pref.
+ * The result is raw result of nsIPrefBranch::Get*Pref().
+ * If the pref could have any value, you needed to use these methods.
+ * If not so, you could use below methods.
+ */
+ static nsresult GetDefaultBool(const char* aPref, bool* aResult);
+ static nsresult GetDefaultInt(const char* aPref, int32_t* aResult);
+ static nsresult GetDefaultUint(const char* aPref, uint32_t* aResult)
+ {
+ return GetDefaultInt(aPref, reinterpret_cast<int32_t*>(aResult));
+ }
+
+ /**
+ * Gets the default bool, int or uint value of the pref directly.
+ * You can set an invalid value of the pref to aFailedResult. If these
+ * methods failed to get the default value, they would return the
+ * aFailedResult value.
+ */
+ static bool GetDefaultBool(const char* aPref, bool aFailedResult)
+ {
+ bool result;
+ return NS_SUCCEEDED(GetDefaultBool(aPref, &result)) ? result :
+ aFailedResult;
+ }
+ static int32_t GetDefaultInt(const char* aPref, int32_t aFailedResult)
+ {
+ int32_t result;
+ return NS_SUCCEEDED(GetDefaultInt(aPref, &result)) ? result : aFailedResult;
+ }
+ static uint32_t GetDefaultUint(const char* aPref, uint32_t aFailedResult)
+ {
+ return static_cast<uint32_t>(
+ GetDefaultInt(aPref, static_cast<int32_t>(aFailedResult)));
+ }
+
+ /**
+ * Gets the default value of the char type pref.
+ * If the get() of the result returned nullptr, that meant the value didn't
+ * have default value.
+ *
+ * See the comment at definition at GetString() and GetCString() for more
+ * details of the result.
+ */
+ static nsAdoptingString GetDefaultString(const char* aPref);
+ static nsAdoptingCString GetDefaultCString(const char* aPref);
+ static nsAdoptingString GetDefaultLocalizedString(const char* aPref);
+ static nsAdoptingCString GetDefaultLocalizedCString(const char* aPref);
+
+ static nsresult GetDefaultCString(const char* aPref, nsACString* aResult);
+ static nsresult GetDefaultString(const char* aPref, nsAString* aResult);
+ static nsresult GetDefaultLocalizedCString(const char* aPref,
+ nsACString* aResult);
+ static nsresult GetDefaultLocalizedString(const char* aPref,
+ nsAString* aResult);
+
+ static nsresult GetDefaultComplex(const char* aPref, const nsIID &aType,
+ void** aResult);
+
+ /**
+ * Gets the type of the pref.
+ */
+ static int32_t GetDefaultType(const char* aPref);
+
+ // Used to synchronise preferences between chrome and content processes.
+ static void GetPreferences(InfallibleTArray<PrefSetting>* aPrefs);
+ static void GetPreference(PrefSetting* aPref);
+ static void SetPreference(const PrefSetting& aPref);
+
+ static int64_t SizeOfIncludingThisAndOtherStuff(mozilla::MallocSizeOf aMallocSizeOf);
+
+ static void DirtyCallback();
+
+protected:
+ virtual ~Preferences();
+
+ nsresult NotifyServiceObservers(const char *aSubject);
+ /**
+ * Reads the default pref file or, if that failed, try to save a new one.
+ *
+ * @return NS_OK if either action succeeded,
+ * or the error code related to the read attempt.
+ */
+ nsresult UseDefaultPrefFile();
+ nsresult UseUserPrefFile();
+ nsresult ReadAndOwnUserPrefFile(nsIFile *aFile);
+ nsresult ReadAndOwnSharedUserPrefFile(nsIFile *aFile);
+ nsresult SavePrefFileInternal(nsIFile* aFile);
+ nsresult WritePrefFile(nsIFile* aFile);
+ nsresult MakeBackupPrefFile(nsIFile *aFile);
+
+private:
+ nsCOMPtr<nsIFile> mCurrentFile;
+ bool mDirty;
+
+ static Preferences* sPreferences;
+ static nsIPrefBranch* sRootBranch;
+ static nsIPrefBranch* sDefaultRootBranch;
+ static bool sShutdown;
+
+ /**
+ * Init static members. TRUE if it succeeded. Otherwise, FALSE.
+ */
+ static bool InitStaticMembers();
+};
+
+} // namespace mozilla
+
+#endif // mozilla_Preferences_h
diff --git a/modules/libpref/greprefs.js b/modules/libpref/greprefs.js
new file mode 100644
index 000000000..d59110b6a
--- /dev/null
+++ b/modules/libpref/greprefs.js
@@ -0,0 +1,12 @@
+#include ../../netwerk/base/security-prefs.js
+#include init/all.js
+#ifdef MOZ_DATA_REPORTING
+#include ../../toolkit/components/telemetry/datareporting-prefs.js
+#endif
+#ifdef MOZ_SERVICES_HEALTHREPORT
+#if MOZ_WIDGET_TOOLKIT == android
+#include ../../mobile/android/chrome/content/healthreport-prefs.js
+#else
+#include ../../toolkit/components/telemetry/healthreport-prefs.js
+#endif
+#endif
diff --git a/modules/libpref/init/all.js b/modules/libpref/init/all.js
new file mode 100644
index 000000000..1cb9e1921
--- /dev/null
+++ b/modules/libpref/init/all.js
@@ -0,0 +1,5583 @@
+/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* The prefs in this file are shipped with the GRE and should apply to all
+ * embedding situations. Application-specific preferences belong somewhere else,
+ * for example xpfe/bootstrap/browser-prefs.js
+ *
+ * Platform-specific #ifdefs at the end of this file override the generic
+ * entries at the top.
+ */
+
+/*
+ * SYNTAX HINTS:
+ *
+ * - Dashes are delimiters; use underscores instead.
+ * - The first character after a period must be alphabetic.
+ * - Computed values (e.g. 50 * 1024) don't work.
+ */
+
+pref("keyword.enabled", false);
+pref("general.useragent.locale", "chrome://global/locale/intl.properties");
+pref("general.useragent.compatMode.firefox", false);
+
+// This pref exists only for testing purposes. In order to disable all
+// overrides by default, don't initialize UserAgentOverrides.jsm.
+pref("general.useragent.site_specific_overrides", true);
+
+pref("general.config.obscure_value", 13); // for MCD .cfg files
+
+pref("general.warnOnAboutConfig", true);
+
+// maximum number of dated backups to keep at any time
+pref("browser.bookmarks.max_backups", 5);
+
+// Delete HTTP cache v1 data
+pref("browser.cache.auto_delete_cache_version", 0);
+// Preference for switching the cache backend, can be changed freely at runtime
+// 0 - use the old (Darin's) cache
+// 1 - use the new cache back-end (cache v2)
+pref("browser.cache.use_new_backend", 0);
+pref("browser.cache.use_new_backend_temp", true);
+
+pref("browser.cache.disk.enable", true);
+// Is this the first-time smartsizing has been introduced?
+pref("browser.cache.disk.smart_size.first_run", true);
+// Does the user want smart-sizing?
+pref("browser.cache.disk.smart_size.enabled", true);
+// Which max value should we use for smart-sizing?
+pref("browser.cache.disk.smart_size.use_old_max", true);
+// Size (in KB) explicitly set by the user. Used when smart_size.enabled == false
+pref("browser.cache.disk.capacity", 256000);
+// When smartsizing is disabled we could potentially fill all disk space by
+// cache data when the disk capacity is not set correctly. To avoid that we
+// check the free space every time we write some data to the cache. The free
+// space is checked against two limits. Once the soft limit is reached we start
+// evicting the least useful entries, when we reach the hard limit writing to
+// the entry fails.
+pref("browser.cache.disk.free_space_soft_limit", 5120); // 5MB
+pref("browser.cache.disk.free_space_hard_limit", 1024); // 1MB
+// Max-size (in KB) for entries in disk cache. Set to -1 for no limit.
+// (Note: entries bigger than 1/8 of disk-cache are never cached)
+pref("browser.cache.disk.max_entry_size", 51200); // 50 MB
+pref("browser.cache.memory.enable", true);
+// -1 = determine dynamically, 0 = none, n = memory capacity in kilobytes
+//pref("browser.cache.memory.capacity", -1);
+// Max-size (in KB) for entries in memory cache. Set to -1 for no limit.
+// (Note: entries bigger than than 90% of the mem-cache are never cached)
+pref("browser.cache.memory.max_entry_size", 5120);
+// Memory limit (in kB) for new cache data not yet written to disk. Writes to
+// the cache are buffered and written to disk on background with low priority.
+// With a slow persistent storage these buffers may grow when data is coming
+// fast from the network. When the amount of unwritten data is exceeded, new
+// writes will simply fail. We have two buckets, one for important data
+// (priority) like html, css, fonts and js, and one for other data like images,
+// video, etc.
+// Note: 0 means no limit.
+pref("browser.cache.disk.max_chunks_memory_usage", 10240);
+pref("browser.cache.disk.max_priority_chunks_memory_usage", 10240);
+
+pref("browser.cache.disk_cache_ssl", true);
+// 0 = once-per-session, 1 = each-time, 2 = never, 3 = when-appropriate/automatically
+pref("browser.cache.check_doc_frequency", 3);
+// Limit of recent metadata we keep in memory for faster access, in Kb
+pref("browser.cache.disk.metadata_memory_limit", 250); // 0.25 MB
+// The number of chunks we preload ahead of read. One chunk has currently 256kB.
+pref("browser.cache.disk.preload_chunk_count", 4); // 1 MB of read ahead
+// The half life used to re-compute cache entries frecency in hours.
+pref("browser.cache.frecency_half_life_hours", 6);
+
+// Number of seconds the cache spends writting pending data and closing files
+// after the shutdown has been signalled. Past that time data are never written
+// and files are left open given up to the OS to do the cleanup.
+pref("browser.cache.max_shutdown_io_lag", 2);
+
+pref("browser.cache.offline.enable", true);
+// enable offline apps by default, disable prompt
+pref("offline-apps.allow_by_default", true);
+
+// offline cache capacity in kilobytes
+pref("browser.cache.offline.capacity", 512000);
+
+// the user should be warned if offline app disk usage exceeds this amount
+// (in kilobytes)
+pref("offline-apps.quota.warn", 51200);
+
+// zlib compression level used for cache compression:
+// 0 => disable compression
+// 1 => best speed
+// 9 => best compression
+// cache compression turned off for now - see bug #715198
+pref("browser.cache.compression_level", 0);
+
+// Don't show "Open with" option on download dialog if true.
+pref("browser.download.forbid_open_with", false);
+
+// Whether or not testing features are enabled.
+pref("dom.quotaManager.testing", false);
+
+// Whether or not indexedDB is enabled.
+pref("dom.indexedDB.enabled", true);
+// Whether or not indexedDB experimental features are enabled.
+pref("dom.indexedDB.experimental", false);
+// Enable indexedDB logging.
+pref("dom.indexedDB.logging.enabled", true);
+// Detailed output in log messages.
+pref("dom.indexedDB.logging.details", true);
+// Enable profiler marks for indexedDB events.
+pref("dom.indexedDB.logging.profiler-marks", false);
+
+// Whether or not File Handle is enabled.
+pref("dom.fileHandle.enabled", true);
+
+// Whether window.onappinstalled from "W3C Web Manifest" is enabled
+pref("dom.manifest.onappinstalled", false);
+
+// Whether or not selection events are enabled
+pref("dom.select_events.enabled", true);
+
+// Whether or not selection events on text controls are enabled
+#ifdef NIGHTLY_BUILD
+pref("dom.select_events.textcontrols.enabled", true);
+#else
+pref("dom.select_events.textcontrols.enabled", false);
+#endif
+
+// Whether or not Web Workers are enabled.
+pref("dom.workers.enabled", true);
+
+// The number of workers per domain allowed to run concurrently.
+// We're going for effectively infinite, while preventing abuse.
+pref("dom.workers.maxPerDomain", 512);
+
+pref("dom.serviceWorkers.enabled", false);
+
+// The amount of time (milliseconds) service workers keep running after each event.
+pref("dom.serviceWorkers.idle_timeout", 30000);
+
+// The amount of time (milliseconds) service workers can be kept running using waitUntil promises.
+pref("dom.serviceWorkers.idle_extended_timeout", 300000);
+
+// Enable test for 24 hours update, service workers will always treat last update check time is over 24 hours
+pref("dom.serviceWorkers.testUpdateOverOneDay", false);
+
+// Whether nonzero values can be returned from performance.timing.*
+pref("dom.enable_performance", true);
+
+// Whether resource timing will be gathered and returned by performance.GetEntries*
+pref("dom.enable_resource_timing", true);
+
+// Enable high-resolution timing markers for users
+pref("dom.enable_user_timing", true);
+
+// Enable printing performance marks/measures to log
+pref("dom.performance.enable_user_timing_logging", false);
+
+// Enable notification of performance timing
+pref("dom.performance.enable_notify_performance_timing", false);
+
+// Enable Permission API's .revoke() method
+pref("dom.permissions.revoke.enable", false);
+
+// Enable Performance Observer API
+#ifdef NIGHTLY_BUILD
+pref("dom.enable_performance_observer", true);
+#else
+pref("dom.enable_performance_observer", false);
+#endif
+
+// Enable requestIdleCallback API
+#ifdef NIGHTLY_BUILD
+pref("dom.requestIdleCallback.enabled", true);
+#else
+pref("dom.requestIdleCallback.enabled", false);
+#endif
+
+// Whether the Gamepad API is enabled
+pref("dom.gamepad.enabled", true);
+pref("dom.gamepad.test.enabled", false);
+#ifdef RELEASE_OR_BETA
+pref("dom.gamepad.non_standard_events.enabled", false);
+#else
+pref("dom.gamepad.non_standard_events.enabled", true);
+#endif
+pref("dom.gamepad.extensions.enabled", false);
+
+// Whether the KeyboardEvent.code is enabled
+pref("dom.keyboardevent.code.enabled", true);
+
+// If this is true, TextEventDispatcher dispatches keydown and keyup events
+// even during composition (keypress events are never fired during composition
+// even if this is true).
+pref("dom.keyboardevent.dispatch_during_composition", false);
+
+// Whether URL,Location,Link::GetHash should be percent encoded
+// in setter and percent decoded in getter (old behaviour = true)
+pref("dom.url.encode_decode_hash", true);
+// Whether ::GetHash should do percent decoding (old behaviour = true)
+pref("dom.url.getters_decode_hash", false);
+
+// Whether to run add-on code in different compartments from browser code. This
+// causes a separate compartment for each (addon, global) combination, which may
+// significantly increase the number of compartments in the system.
+pref("dom.compartment_per_addon", true);
+
+// Fastback caching - if this pref is negative, then we calculate the number
+// of content viewers to cache based on the amount of available memory.
+pref("browser.sessionhistory.max_total_viewers", -1);
+
+pref("ui.use_native_colors", true);
+pref("ui.click_hold_context_menus", false);
+// Duration of timeout of incremental search in menus (ms). 0 means infinite.
+pref("ui.menu.incremental_search.timeout", 1000);
+// If true, all popups won't hide automatically on blur
+pref("ui.popup.disable_autohide", false);
+
+pref("browser.display.use_document_fonts", 1); // 0 = never, 1 = quick, 2 = always
+// 0 = default: always, except in high contrast mode
+// 1 = always
+// 2 = never
+pref("browser.display.document_color_use", 0);
+pref("browser.display.use_system_colors", false);
+pref("browser.display.foreground_color", "#000000");
+pref("browser.display.background_color", "#FFFFFF");
+pref("browser.display.force_inline_alttext", false); // true = force ALT text for missing images to be layed out inline
+// 0 = no external leading,
+// 1 = use external leading only when font provides,
+// 2 = add extra leading both internal leading and external leading are zero
+pref("browser.display.normal_lineheight_calc_control", 2);
+// enable showing image placeholders while image is loading or when image is broken
+pref("browser.display.show_image_placeholders", true);
+// if browser.display.show_image_placeholders is true then this controls whether the loading image placeholder and border is shown or not
+pref("browser.display.show_loading_image_placeholder", false);
+// min font device pixel size at which to turn on high quality
+pref("browser.display.auto_quality_min_font_size", 20);
+pref("browser.anchor_color", "#0000EE");
+pref("browser.active_color", "#EE0000");
+pref("browser.visited_color", "#551A8B");
+pref("browser.underline_anchors", true);
+pref("browser.enable_automatic_image_resizing", false);
+pref("browser.enable_click_image_resizing", true);
+
+// See http://dev.w3.org/html5/spec/forms.html#attr-fe-autofocus
+pref("browser.autofocus", true);
+
+// See http://whatwg.org/specs/web-apps/current-work/#ping
+pref("browser.send_pings", false);
+pref("browser.send_pings.max_per_link", 1); // limit the number of pings that are sent per link click
+pref("browser.send_pings.require_same_host", false); // only send pings to the same host if this is true
+
+pref("browser.display.use_focus_colors", false);
+pref("browser.display.focus_background_color", "#117722");
+pref("browser.display.focus_text_color", "#ffffff");
+pref("browser.display.focus_ring_width", 1);
+pref("browser.display.focus_ring_on_anything", false);
+// focus ring border style.
+// 0 = solid border, 1 = dotted border
+pref("browser.display.focus_ring_style", 1);
+
+pref("browser.helperApps.alwaysAsk.force", false);
+pref("browser.helperApps.neverAsk.saveToDisk", "");
+pref("browser.helperApps.neverAsk.openFile", "");
+pref("browser.helperApps.deleteTempFileOnExit", false);
+
+// xxxbsmedberg: where should prefs for the toolkit go?
+pref("browser.chrome.toolbar_tips", true);
+// 0 = Pictures Only, 1 = Text Only, 2 = Pictures and Text
+pref("browser.chrome.toolbar_style", 2);
+// max image size for which it is placed in the tab icon for tabbrowser.
+// if 0, no images are used for tab icons for image documents.
+pref("browser.chrome.image_icons.max_size", 1024);
+
+pref("browser.triple_click_selects_paragraph", true);
+
+// Print/Preview Shrink-To-Fit won't shrink below 20% for text-ish documents.
+pref("print.shrink-to-fit.scale-limit-percent", 20);
+
+// Whether we should display simplify page checkbox on print preview UI
+pref("print.use_simplify_page", false);
+
+// Disable support for MathML
+pref("mathml.disabled", false);
+
+// Enable scale transform for stretchy MathML operators. See bug 414277.
+pref("mathml.scale_stretchy_operators.enabled", true);
+
+// Enabled on nightly only until we fix mochitest failures.
+#ifdef NIGHTLY_BUILD
+pref("media.dormant-on-pause-timeout-ms", 5000);
+#else
+pref("media.dormant-on-pause-timeout-ms", -1);
+#endif
+
+// Media cache size in kilobytes
+pref("media.cache_size", 512000);
+// When a network connection is suspended, don't resume it until the
+// amount of buffered data falls below this threshold (in seconds).
+pref("media.cache_resume_threshold", 999999);
+// Stop reading ahead when our buffered data is this many seconds ahead
+// of the current playback position. This limit can stop us from using arbitrary
+// amounts of network bandwidth prefetching huge videos.
+pref("media.cache_readahead_limit", 999999);
+
+// Master HTML5 media volume scale.
+pref("media.volume_scale", "1.0");
+
+// Timeout for wakelock release
+pref("media.wakelock_timeout", 2000);
+
+// Whether we should play videos opened in a "video document", i.e. videos
+// opened as top-level documents, as opposed to inside a media element.
+pref("media.play-stand-alone", true);
+
+pref("media.hardware-video-decoding.enabled", true);
+pref("media.hardware-video-decoding.force-enabled", false);
+
+#ifdef MOZ_DIRECTSHOW
+pref("media.directshow.enabled", true);
+#endif
+#ifdef MOZ_FMP4
+pref("media.mp4.enabled", true);
+// Specifies whether the PDMFactory can create a test decoder that
+#endif
+// just outputs blank frames/audio instead of actually decoding. The blank
+// decoder works on all platforms.
+pref("media.use-blank-decoder", false);
+#ifdef MOZ_WMF
+pref("media.wmf.enabled", true);
+pref("media.wmf.decoder.thread-count", -1);
+pref("media.wmf.low-latency.enabled", false);
+pref("media.wmf.skip-blacklist", false);
+#ifdef NIGHTLY_BUILD
+pref("media.wmf.vp9.enabled", true);
+#else
+pref("media.wmf.vp9.enabled", false);
+#endif
+pref("media.windows-media-foundation.allow-d3d11-dxva", true);
+pref("media.wmf.disable-d3d11-for-dlls", "igd11dxva64.dll: 20.19.15.4463, 20.19.15.4454, 20.19.15.4444, 20.19.15.4416, 20.19.15.4404, 20.19.15.4390, 20.19.15.4380, 20.19.15.4377, 20.19.15.4364, 20.19.15.4360, 20.19.15.4352, 20.19.15.4331, 20.19.15.4326, 20.19.15.4300; igd10iumd32.dll: 20.19.15.4444, 20.19.15.4424, 20.19.15.4409, 20.19.15.4390, 20.19.15.4380, 20.19.15.4360, 10.18.10.4358, 20.19.15.4331, 20.19.15.4312, 20.19.15.4300, 10.18.15.4281, 10.18.15.4279, 10.18.10.4276, 10.18.15.4268, 10.18.15.4256, 10.18.10.4252, 10.18.15.4248, 10.18.14.4112, 10.18.10.3958, 10.18.10.3496, 10.18.10.3431, 10.18.10.3412, 10.18.10.3355, 9.18.10.3234, 9.18.10.3071, 9.18.10.3055, 9.18.10.3006; igd10umd32.dll: 9.17.10.4229, 9.17.10.3040, 9.17.10.2857, 8.15.10.2274, 8.15.10.2272, 8.15.10.2246, 8.15.10.1840, 8.15.10.1808; igd10umd64.dll: 9.17.10.4229, 9.17.10.2857, 10.18.10.3496; isonyvideoprocessor.dll: 4.1.2247.8090, 4.1.2153.6200; tosqep.dll: 1.2.15.526, 1.1.12.201, 1.0.11.318, 1.0.11.215, 1.0.10.1224; tosqep64.dll: 1.1.12.201, 1.0.11.215; nvwgf2um.dll: 22.21.13.8253, 22.21.13.8233, 22.21.13.8205, 22.21.13.8189, 22.21.13.8178, 22.21.13.8165, 21.21.13.7892, 21.21.13.7878, 21.21.13.7866, 21.21.13.7849, 21.21.13.7654, 21.21.13.7653, 21.21.13.7633, 21.21.13.7619, 21.21.13.7563, 21.21.13.7306, 21.21.13.7290, 21.21.13.7270, 21.21.13.7254, 21.21.13.6939, 21.21.13.6926, 21.21.13.6909, 21.21.13.4201, 21.21.13.4200, 10.18.13.6881, 10.18.13.6839, 10.18.13.6510, 10.18.13.6472, 10.18.13.6143, 10.18.13.5946, 10.18.13.5923, 10.18.13.5921, 10.18.13.5891, 10.18.13.5887, 10.18.13.5582, 10.18.13.5445, 10.18.13.5382, 10.18.13.5362, 9.18.13.4788, 9.18.13.4752, 9.18.13.4725, 9.18.13.4709, 9.18.13.4195, 9.18.13.4192, 9.18.13.4144, 9.18.13.4052, 9.18.13.3788, 9.18.13.3523, 9.18.13.3235, 9.18.13.3165, 9.18.13.2723, 9.18.13.2702, 9.18.13.1422, 9.18.13.1407, 9.18.13.1106, 9.18.13.546; atidxx32.dll: 21.19.151.3, 21.19.142.257, 21.19.137.514, 21.19.137.1, 21.19.134.1, 21.19.128.7, 21.19.128.4, 20.19.0.32837, 20.19.0.32832, 8.17.10.682, 8.17.10.671, 8.17.10.661, 8.17.10.648, 8.17.10.644, 8.17.10.625, 8.17.10.605, 8.17.10.581, 8.17.10.569, 8.17.10.560, 8.17.10.545, 8.17.10.539, 8.17.10.531, 8.17.10.525, 8.17.10.520, 8.17.10.519, 8.17.10.514, 8.17.10.511, 8.17.10.494, 8.17.10.489, 8.17.10.483, 8.17.10.453, 8.17.10.451, 8.17.10.441, 8.17.10.436, 8.17.10.432, 8.17.10.425, 8.17.10.418, 8.17.10.414, 8.17.10.401, 8.17.10.395, 8.17.10.385, 8.17.10.378, 8.17.10.362, 8.17.10.355, 8.17.10.342, 8.17.10.331, 8.17.10.318, 8.17.10.310, 8.17.10.286, 8.17.10.269, 8.17.10.261, 8.17.10.247, 8.17.10.240, 8.15.10.212; atidxx64.dll: 21.19.151.3, 21.19.142.257, 21.19.137.514, 21.19.137.1, 21.19.134.1, 21.19.128.7, 21.19.128.4, 20.19.0.32832, 8.17.10.682, 8.17.10.661, 8.17.10.644, 8.17.10.625; nvumdshim.dll: 10.18.13.6822");
+pref("media.wmf.disable-d3d9-for-dlls", "igdumd64.dll: 8.15.10.2189, 8.15.10.2119, 8.15.10.2104, 8.15.10.2102, 8.771.1.0; atiumd64.dll: 7.14.10.833, 7.14.10.867, 7.14.10.885, 7.14.10.903, 7.14.10.911, 8.14.10.768, 9.14.10.1001, 9.14.10.1017, 9.14.10.1080, 9.14.10.1128, 9.14.10.1162, 9.14.10.1171, 9.14.10.1183, 9.14.10.1197, 9.14.10.945, 9.14.10.972, 9.14.10.984, 9.14.10.996");
+#endif
+#if defined(MOZ_FFMPEG)
+#if defined(XP_MACOSX)
+pref("media.ffmpeg.enabled", false);
+#else
+pref("media.ffmpeg.enabled", true);
+#endif
+pref("media.libavcodec.allow-obsolete", false);
+#endif
+#if defined(MOZ_FFVPX)
+pref("media.ffvpx.enabled", true);
+#endif
+pref("media.gmp.decoder.enabled", false);
+pref("media.gmp.decoder.aac", 0);
+pref("media.gmp.decoder.h264", 0);
+#ifdef MOZ_RAW
+pref("media.raw.enabled", true);
+#endif
+pref("media.ogg.enabled", true);
+pref("media.opus.enabled", true);
+pref("media.wave.enabled", true);
+pref("media.webm.enabled", true);
+
+#ifdef MOZ_APPLEMEDIA
+#ifdef MOZ_WIDGET_UIKIT
+pref("media.mp3.enabled", true);
+#endif
+pref("media.apple.mp3.enabled", true);
+pref("media.apple.mp4.enabled", true);
+#endif
+
+// GMP storage version number. At startup we check the version against
+// media.gmp.storage.version.observed, and if the versions don't match,
+// we clear storage and set media.gmp.storage.version.observed=expected.
+// This provides a mechanism to clear GMP storage when non-compatible
+// changes are made.
+pref("media.gmp.storage.version.expected", 1);
+
+// Filter what triggers user notifications.
+// See DecoderDoctorDocumentWatcher::ReportAnalysis for details.
+pref("media.decoder-doctor.notifications-allowed", "MediaWMFNeeded,MediaWidevineNoWMFNoSilverlight,MediaCannotInitializePulseAudio,MediaCannotPlayNoDecoders,MediaUnsupportedLibavcodec");
+// Whether we report partial failures.
+pref("media.decoder-doctor.verbose", false);
+// Whether DD should consider WMF-disabled a WMF failure, useful for testing.
+pref("media.decoder-doctor.wmf-disabled-is-failure", false);
+
+// Whether to suspend decoding of videos in background tabs.
+#ifdef NIGHTLY_BUILD
+pref("media.suspend-bkgnd-video.enabled", true);
+#else
+pref("media.suspend-bkgnd-video.enabled", false);
+#endif
+// Delay, in ms, from time window goes to background to suspending
+// video decoders. Defaults to 10 seconds.
+pref("media.suspend-bkgnd-video.delay-ms", 10000);
+
+#ifdef MOZ_WEBRTC
+pref("media.navigator.enabled", true);
+pref("media.navigator.video.enabled", true);
+pref("media.navigator.load_adapt", true);
+pref("media.navigator.load_adapt.encoder_only", true);
+pref("media.navigator.load_adapt.measure_interval",1000);
+pref("media.navigator.load_adapt.avg_seconds",3);
+pref("media.navigator.load_adapt.high_load","0.90");
+pref("media.navigator.load_adapt.low_load","0.40");
+pref("media.navigator.video.default_fps",30);
+pref("media.navigator.video.default_minfps",10);
+pref("media.navigator.video.use_remb", true);
+pref("media.navigator.video.use_tmmbr", false);
+pref("media.navigator.audio.use_fec", true);
+pref("media.navigator.video.red_ulpfec_enabled", false);
+
+pref("media.peerconnection.dtmf.enabled", true);
+
+pref("media.webrtc.debug.trace_mask", 0);
+pref("media.webrtc.debug.multi_log", false);
+pref("media.webrtc.debug.aec_log_dir", "");
+pref("media.webrtc.debug.log_file", "");
+pref("media.webrtc.debug.aec_dump_max_size", 4194304); // 4MB
+
+#ifdef MOZ_WIDGET_GONK
+pref("media.navigator.video.default_width", 320);
+pref("media.navigator.video.default_height", 240);
+pref("media.peerconnection.enabled", true);
+pref("media.peerconnection.video.enabled", true);
+pref("media.navigator.video.max_fs", 1200); // 640x480 == 1200mb
+pref("media.navigator.video.max_fr", 30);
+pref("media.navigator.video.h264.level", 12); // 0x42E00C - level 1.2
+pref("media.navigator.video.h264.max_br", 700); // 8x10
+pref("media.navigator.video.h264.max_mbps", 11880); // CIF@30fps
+pref("media.peerconnection.video.h264_enabled", false);
+pref("media.peerconnection.video.vp9_enabled", false);
+pref("media.getusermedia.aec", 4);
+#else
+pref("media.navigator.video.default_width",0); // adaptive default
+pref("media.navigator.video.default_height",0); // adaptive default
+pref("media.peerconnection.enabled", true);
+pref("media.peerconnection.video.enabled", true);
+pref("media.navigator.video.max_fs", 12288); // Enough for 2048x1536
+pref("media.navigator.video.max_fr", 60);
+pref("media.navigator.video.h264.level", 31); // 0x42E01f - level 3.1
+pref("media.navigator.video.h264.max_br", 0);
+pref("media.navigator.video.h264.max_mbps", 0);
+pref("media.peerconnection.video.h264_enabled", false);
+pref("media.peerconnection.video.vp9_enabled", true);
+pref("media.getusermedia.aec", 1);
+pref("media.getusermedia.browser.enabled", true);
+#endif
+// Gonk typically captures at QVGA, and so min resolution is QQVGA or
+// 160x120; 100Kbps is plenty for that.
+// Desktop is typically VGA capture or more; and qm_select will not drop resolution
+// below 1/2 in each dimension (or so), so QVGA (320x200) is the lowest here usually.
+pref("media.peerconnection.video.min_bitrate", 0);
+pref("media.peerconnection.video.start_bitrate", 0);
+pref("media.peerconnection.video.max_bitrate", 0);
+pref("media.peerconnection.video.min_bitrate_estimate", 0);
+pref("media.navigator.audio.fake_frequency", 1000);
+pref("media.navigator.permission.disabled", false);
+pref("media.peerconnection.simulcast", true);
+pref("media.peerconnection.default_iceservers", "[]");
+pref("media.peerconnection.ice.loopback", false); // Set only for testing in offline environments.
+pref("media.peerconnection.ice.tcp", false);
+pref("media.peerconnection.ice.tcp_so_sock_count", 0); // Disable SO gathering
+pref("media.peerconnection.ice.link_local", false); // Set only for testing IPV6 in networks that don't assign IPV6 addresses
+pref("media.peerconnection.ice.force_interface", ""); // Limit to only a single interface
+pref("media.peerconnection.ice.relay_only", false); // Limit candidates to TURN
+pref("media.peerconnection.use_document_iceservers", true);
+pref("media.peerconnection.identity.enabled", true);
+pref("media.peerconnection.identity.timeout", 10000);
+pref("media.peerconnection.ice.stun_client_maximum_transmits", 7);
+pref("media.peerconnection.ice.trickle_grace_period", 5000);
+pref("media.peerconnection.ice.no_host", false);
+pref("media.peerconnection.ice.default_address_only", false);
+pref("media.peerconnection.ice.proxy_only", false);
+
+// These values (aec, agc, and noice) are from media/webrtc/trunk/webrtc/common_types.h
+// kXxxUnchanged = 0, kXxxDefault = 1, and higher values are specific to each
+// setting (for Xxx = Ec, Agc, or Ns). Defaults are all set to kXxxDefault here.
+pref("media.peerconnection.turn.disable", false);
+#if defined(MOZ_WEBRTC_HARDWARE_AEC_NS)
+pref("media.getusermedia.aec_enabled", false);
+pref("media.getusermedia.noise_enabled", false);
+#else
+pref("media.getusermedia.aec_enabled", true);
+pref("media.getusermedia.noise_enabled", true);
+#endif
+pref("media.getusermedia.aec_extended_filter", true);
+pref("media.getusermedia.aec_delay_agnostic", true);
+pref("media.getusermedia.noise", 1);
+pref("media.getusermedia.agc_enabled", false);
+pref("media.getusermedia.agc", 1);
+// capture_delay: Adjustments for OS-specific input delay (lower bound)
+// playout_delay: Adjustments for OS-specific AudioStream+cubeb+output delay (lower bound)
+// full_duplex: enable cubeb full-duplex capture/playback
+#if defined(XP_MACOSX)
+pref("media.peerconnection.capture_delay", 50);
+pref("media.getusermedia.playout_delay", 10);
+pref("media.navigator.audio.full_duplex", false);
+#elif defined(XP_WIN)
+pref("media.peerconnection.capture_delay", 50);
+pref("media.getusermedia.playout_delay", 40);
+pref("media.navigator.audio.full_duplex", false);
+#elif defined(ANDROID)
+pref("media.peerconnection.capture_delay", 100);
+pref("media.getusermedia.playout_delay", 100);
+pref("media.navigator.audio.full_duplex", false);
+// Whether to enable Webrtc Hardware acceleration support
+pref("media.navigator.hardware.vp8_encode.acceleration_enabled", false);
+pref("media.navigator.hardware.vp8_decode.acceleration_enabled", false);
+#elif defined(XP_LINUX)
+pref("media.peerconnection.capture_delay", 70);
+pref("media.getusermedia.playout_delay", 50);
+pref("media.navigator.audio.full_duplex", true);
+#else
+// *BSD, others - merely a guess for now
+pref("media.peerconnection.capture_delay", 50);
+pref("media.getusermedia.playout_delay", 50);
+pref("media.navigator.audio.full_duplex", false);
+#endif
+#endif
+
+pref("dom.webaudio.enabled", true);
+
+#if !defined(ANDROID)
+pref("media.getusermedia.screensharing.enabled", true);
+#endif
+
+#ifdef RELEASE_OR_BETA
+pref("media.getusermedia.screensharing.allowed_domains", "webex.com,*.webex.com,ciscospark.com,*.ciscospark.com,projectsquared.com,*.projectsquared.com,*.room.co,room.co,beta.talky.io,talky.io,*.clearslide.com,appear.in,*.appear.in,tokbox.com,*.tokbox.com,*.sso.francetelecom.fr,*.si.francetelecom.fr,*.sso.infra.ftgroup,*.multimedia-conference.orange-business.com,*.espacecollaboration.orange-business.com,free.gotomeeting.com,g2m.me,*.g2m.me,*.mypurecloud.com,*.mypurecloud.com.au,spreed.me,*.spreed.me,*.spreed.com,air.mozilla.org,*.circuit.com,*.yourcircuit.com,circuit.siemens.com,yourcircuit.siemens.com,circuitsandbox.net,*.unify.com,tandi.circuitsandbox.net,*.ericsson.net,*.cct.ericsson.net,*.opentok.com,*.conf.meetecho.com,meet.jit.si,*.meet.jit.si,web.stage.speakeasyapp.net,web.speakeasyapp.net,*.hipchat.me,*.beta-wspbx.com,*.wspbx.com,*.unifiedcloudit.com,*.smartboxuc.com,*.smartbox-uc.com,*.panterranetworks.com,pexipdemo.com,*.pexipdemo.com,pex.me,*.pex.me,*.rd.pexip.com,1click.io,*.1click.io,*.fuze.com,*.fuzemeeting.com,*.thinkingphones.com,gotomeeting.com,*.gotomeeting.com,gotowebinar.com,*.gotowebinar.com,gototraining.com,*.gototraining.com,citrix.com,*.citrix.com,expertcity.com,*.expertcity.com,citrixonline.com,*.citrixonline.com,g2m.me,*.g2m.me,gotomeet.me,*.gotomeet.me,gotomeet.at,*.gotomeet.at,miriadaxdes.miriadax.net,certificacion.miriadax.net,miriadax.net,*.wire.com,sylaps.com,*.sylaps.com,bluejeans.com,*.bluejeans.com,*.a.bluejeans.com,*.bbcollab.com");
+#else
+ // includes Mozilla's test domain: mozilla.github.io (not intended for release)
+pref("media.getusermedia.screensharing.allowed_domains", "mozilla.github.io,webex.com,*.webex.com,ciscospark.com,*.ciscospark.com,projectsquared.com,*.projectsquared.com,*.room.co,room.co,beta.talky.io,talky.io,*.clearslide.com,appear.in,*.appear.in,tokbox.com,*.tokbox.com,*.sso.francetelecom.fr,*.si.francetelecom.fr,*.sso.infra.ftgroup,*.multimedia-conference.orange-business.com,*.espacecollaboration.orange-business.com,free.gotomeeting.com,g2m.me,*.g2m.me,*.mypurecloud.com,*.mypurecloud.com.au,spreed.me,*.spreed.me,*.spreed.com,air.mozilla.org,*.circuit.com,*.yourcircuit.com,circuit.siemens.com,yourcircuit.siemens.com,circuitsandbox.net,*.unify.com,tandi.circuitsandbox.net,*.ericsson.net,*.cct.ericsson.net,*.opentok.com,*.conf.meetecho.com,meet.jit.si,*.meet.jit.si,web.stage.speakeasyapp.net,web.speakeasyapp.net,*.hipchat.me,*.beta-wspbx.com,*.wspbx.com,*.unifiedcloudit.com,*.smartboxuc.com,*.smartbox-uc.com,*.panterranetworks.com,pexipdemo.com,*.pexipdemo.com,pex.me,*.pex.me,*.rd.pexip.com,1click.io,*.1click.io,*.fuze.com,*.fuzemeeting.com,*.thinkingphones.com,gotomeeting.com,*.gotomeeting.com,gotowebinar.com,*.gotowebinar.com,gototraining.com,*.gototraining.com,citrix.com,*.citrix.com,expertcity.com,*.expertcity.com,citrixonline.com,*.citrixonline.com,g2m.me,*.g2m.me,gotomeet.me,*.gotomeet.me,gotomeet.at,*.gotomeet.at,miriadaxdes.miriadax.net,certificacion.miriadax.net,miriadax.net,*.wire.com,sylaps.com,*.sylaps.com,bluejeans.com,*.bluejeans.com,*.a.bluejeans.com,*.bbcollab.com");
+#endif
+// OS/X 10.6 and XP have screen/window sharing off by default due to various issues - Caveat emptor
+pref("media.getusermedia.screensharing.allow_on_old_platforms", false);
+
+pref("media.getusermedia.audiocapture.enabled", false);
+
+// TextTrack WebVTT Region extension support.
+pref("media.webvtt.regions.enabled", false);
+
+// AudioTrack and VideoTrack support
+pref("media.track.enabled", false);
+
+// Whether to enable MediaSource support.
+pref("media.mediasource.enabled", true);
+
+pref("media.mediasource.mp4.enabled", true);
+
+#if defined(XP_WIN) || defined(XP_MACOSX) || defined(MOZ_WIDGET_GONK) || defined(MOZ_WIDGET_ANDROID)
+pref("media.mediasource.webm.enabled", false);
+#else
+pref("media.mediasource.webm.enabled", true);
+#endif
+pref("media.mediasource.webm.audio.enabled", true);
+
+// Use new MediaFormatReader architecture for plain ogg.
+pref("media.flac.enabled", true);
+pref("media.ogg.flac.enabled", true);
+
+pref("media.benchmark.vp9.threshold", 150);
+pref("media.benchmark.frames", 300);
+pref("media.benchmark.timeout", 1000);
+
+#ifdef MOZ_WEBSPEECH
+pref("media.webspeech.recognition.enable", false);
+pref("media.webspeech.synth.enabled", false);
+#endif
+#ifdef MOZ_WEBM_ENCODER
+pref("media.encoder.webm.enabled", true);
+#endif
+
+// Whether to autostart a media element with an |autoplay| attribute
+pref("media.autoplay.enabled", true);
+
+// The default number of decoded video frames that are enqueued in
+// MediaDecoderReader's mVideoQueue.
+pref("media.video-queue.default-size", 10);
+
+// The maximum number of queued frames to send to the compositor.
+// By default, send all of them.
+pref("media.video-queue.send-to-compositor-size", 9999);
+
+// Whether to disable the video stats to prevent fingerprinting
+pref("media.video_stats.enabled", true);
+
+// Weather we allow AMD switchable graphics
+pref("layers.amd-switchable-gfx.enabled", true);
+
+// Whether to use async panning and zooming
+pref("layers.async-pan-zoom.enabled", true);
+
+// Whether to enable event region building during painting
+pref("layout.event-regions.enabled", false);
+
+// APZ preferences. For documentation/details on what these prefs do, check
+// gfx/layers/apz/src/AsyncPanZoomController.cpp.
+pref("apz.allow_checkerboarding", true);
+pref("apz.allow_immediate_handoff", true);
+pref("apz.allow_zooming", false);
+
+// Whether to lock touch scrolling to one axis at a time
+// 0 = FREE (No locking at all)
+// 1 = STANDARD (Once locked, remain locked until scrolling ends)
+// 2 = STICKY (Allow lock to be broken, with hysteresis)
+pref("apz.axis_lock.mode", 0);
+pref("apz.axis_lock.lock_angle", "0.5235987"); // PI / 6 (30 degrees)
+pref("apz.axis_lock.breakout_threshold", "0.03125"); // 1/32 inches
+pref("apz.axis_lock.breakout_angle", "0.3926991"); // PI / 8 (22.5 degrees)
+pref("apz.axis_lock.direct_pan_angle", "1.047197"); // PI / 3 (60 degrees)
+pref("apz.content_response_timeout", 400);
+pref("apz.drag.enabled", false);
+pref("apz.danger_zone_x", 50);
+pref("apz.danger_zone_y", 100);
+pref("apz.disable_for_scroll_linked_effects", false);
+pref("apz.displayport_expiry_ms", 15000);
+pref("apz.enlarge_displayport_when_clipped", false);
+pref("apz.fling_accel_base_mult", "1.0");
+pref("apz.fling_accel_interval_ms", 500);
+pref("apz.fling_accel_min_velocity", "1.5");
+pref("apz.fling_accel_supplemental_mult", "1.0");
+pref("apz.fling_curve_function_x1", "0.0");
+pref("apz.fling_curve_function_y1", "0.0");
+pref("apz.fling_curve_function_x2", "1.0");
+pref("apz.fling_curve_function_y2", "1.0");
+pref("apz.fling_curve_threshold_inches_per_ms", "-1.0");
+pref("apz.fling_friction", "0.002");
+pref("apz.fling_min_velocity_threshold", "0.5");
+pref("apz.fling_stop_on_tap_threshold", "0.05");
+pref("apz.fling_stopped_threshold", "0.01");
+pref("apz.highlight_checkerboarded_areas", false);
+pref("apz.max_velocity_inches_per_ms", "-1.0");
+pref("apz.max_velocity_queue_size", 5);
+pref("apz.min_skate_speed", "1.0");
+pref("apz.minimap.enabled", false);
+pref("apz.minimap.visibility.enabled", false);
+pref("apz.overscroll.enabled", false);
+pref("apz.overscroll.min_pan_distance_ratio", "1.0");
+pref("apz.overscroll.spring_friction", "0.015");
+pref("apz.overscroll.spring_stiffness", "0.0018");
+pref("apz.overscroll.stop_distance_threshold", "5.0");
+pref("apz.overscroll.stop_velocity_threshold", "0.01");
+pref("apz.overscroll.stretch_factor", "0.35");
+pref("apz.paint_skipping.enabled", true);
+// Fetch displayport updates early from the message queue
+pref("apz.peek_messages.enabled", true);
+
+// Whether to print the APZC tree for debugging
+pref("apz.printtree", false);
+
+#ifdef NIGHTLY_BUILD
+pref("apz.record_checkerboarding", true);
+#else
+pref("apz.record_checkerboarding", false);
+#endif
+pref("apz.test.logging_enabled", false);
+pref("apz.touch_start_tolerance", "0.1");
+pref("apz.touch_move_tolerance", "0.03");
+pref("apz.velocity_bias", "0.0");
+pref("apz.velocity_relevance_time_ms", 150);
+pref("apz.x_skate_highmem_adjust", "0.0");
+pref("apz.y_skate_highmem_adjust", "0.0");
+pref("apz.x_skate_size_multiplier", "1.25");
+pref("apz.y_skate_size_multiplier", "3.5");
+pref("apz.x_stationary_size_multiplier", "1.5");
+pref("apz.y_stationary_size_multiplier", "3.5");
+pref("apz.zoom_animation_duration_ms", 250);
+pref("apz.scale_repaint_delay_ms", 500);
+
+#if defined(MOZ_WIDGET_GONK) || defined(MOZ_WIDGET_ANDROID)
+// Mobile prefs
+pref("apz.allow_zooming", true);
+pref("apz.enlarge_displayport_when_clipped", true);
+pref("apz.y_skate_size_multiplier", "1.5");
+pref("apz.y_stationary_size_multiplier", "1.5");
+#endif
+
+#ifdef XP_MACOSX
+// Whether to run in native HiDPI mode on machines with "Retina"/HiDPI display;
+// <= 0 : hidpi mode disabled, display will just use pixel-based upscaling
+// == 1 : hidpi supported if all screens share the same backingScaleFactor
+// >= 2 : hidpi supported even with mixed backingScaleFactors (somewhat broken)
+pref("gfx.hidpi.enabled", 2);
+#endif
+
+#if !defined(MOZ_WIDGET_GONK) && !defined(MOZ_WIDGET_ANDROID)
+// Use containerless scrolling for now on desktop.
+pref("layout.scroll.root-frame-containers", false);
+#endif
+
+// Whether to enable LayerScope tool and default listening port
+pref("gfx.layerscope.enabled", false);
+pref("gfx.layerscope.port", 23456);
+
+// Log severe performance warnings to the error console and profiles.
+// This should be use to quickly find which slow paths are used by test cases.
+pref("gfx.perf-warnings.enabled", false);
+
+// 0 = Off, 1 = Full, 2 = Tagged Images Only.
+// See eCMSMode in gfx/thebes/gfxPlatform.h
+pref("gfx.color_management.mode", 2);
+pref("gfx.color_management.display_profile", "");
+pref("gfx.color_management.rendering_intent", 0);
+pref("gfx.color_management.enablev4", false);
+
+pref("gfx.downloadable_fonts.enabled", true);
+pref("gfx.downloadable_fonts.fallback_delay", 3000);
+pref("gfx.downloadable_fonts.fallback_delay_short", 100);
+
+// disable downloadable font cache so that behavior is consistently
+// the uncached load behavior across pages (useful for testing reflow problems)
+pref("gfx.downloadable_fonts.disable_cache", false);
+
+pref("gfx.downloadable_fonts.woff2.enabled", true);
+
+#ifdef ANDROID
+pref("gfx.bundled_fonts.enabled", true);
+pref("gfx.bundled_fonts.force-enabled", false);
+#endif
+
+// Do we fire a notification about missing fonts, so the front-end can decide
+// whether to try and do something about it (e.g. download additional fonts)?
+pref("gfx.missing_fonts.notify", false);
+
+// prefs controlling the font (name/cmap) loader that runs shortly after startup
+pref("gfx.font_loader.families_per_slice", 3); // read in info 3 families at a time
+#ifdef XP_WIN
+pref("gfx.font_loader.delay", 120000); // 2 minutes after startup
+pref("gfx.font_loader.interval", 1000); // every 1 second until complete
+#else
+pref("gfx.font_loader.delay", 8000); // 8 secs after startup
+pref("gfx.font_loader.interval", 50); // run every 50 ms
+#endif
+
+// whether to always search all font cmaps during system font fallback
+pref("gfx.font_rendering.fallback.always_use_cmaps", false);
+
+// cache shaped word results
+pref("gfx.font_rendering.wordcache.charlimit", 32);
+
+// cache shaped word results
+pref("gfx.font_rendering.wordcache.maxentries", 10000);
+
+pref("gfx.font_rendering.graphite.enabled", true);
+
+#ifdef XP_WIN
+pref("gfx.font_rendering.directwrite.force-enabled", false);
+pref("gfx.font_rendering.directwrite.use_gdi_table_loading", true);
+#endif
+
+pref("gfx.font_rendering.opentype_svg.enabled", true);
+
+#ifdef XP_WIN
+// comma separated list of backends to use in order of preference
+// e.g., pref("gfx.canvas.azure.backends", "direct2d,skia,cairo");
+pref("gfx.canvas.azure.backends", "direct2d1.1,skia,cairo");
+pref("gfx.content.azure.backends", "direct2d1.1,skia,cairo");
+#else
+#ifdef XP_MACOSX
+pref("gfx.content.azure.backends", "skia");
+pref("gfx.canvas.azure.backends", "skia");
+// Accelerated cg canvas where available (10.7+)
+pref("gfx.canvas.azure.accelerated", true);
+#else
+pref("gfx.canvas.azure.backends", "skia");
+pref("gfx.content.azure.backends", "skia");
+#endif
+#endif
+
+pref("gfx.canvas.skiagl.dynamic-cache", true);
+
+pref("gfx.text.disable-aa", false);
+
+pref("gfx.work-around-driver-bugs", true);
+pref("gfx.prefer-mesa-llvmpipe", false);
+
+pref("gfx.draw-color-bars", false);
+
+pref("gfx.logging.painted-pixel-count.enabled", false);
+pref("gfx.logging.texture-usage.enabled", false);
+pref("gfx.logging.peak-texture-usage.enabled", false);
+
+pref("gfx.ycbcr.accurate-conversion", false);
+
+pref("accessibility.browsewithcaret", false);
+pref("accessibility.warn_on_browsewithcaret", true);
+
+pref("accessibility.browsewithcaret_shortcut.enabled", true);
+
+#ifndef XP_MACOSX
+// Tab focus model bit field:
+// 1 focuses text controls, 2 focuses other form elements, 4 adds links.
+// Most users will want 1, 3, or 7.
+// On OS X, we use Full Keyboard Access system preference,
+// unless accessibility.tabfocus is set by the user.
+pref("accessibility.tabfocus", 7);
+pref("accessibility.tabfocus_applies_to_xul", false);
+#else
+// Only on mac tabfocus is expected to handle UI widgets as well as web content
+pref("accessibility.tabfocus_applies_to_xul", true);
+#endif
+
+// We follow the "Click in the scrollbar to:" system preference on OS X and
+// "gtk-primary-button-warps-slider" property with GTK (since 2.24 / 3.6),
+// unless this preference is explicitly set.
+#if !defined(XP_MACOSX) && !defined(MOZ_WIDGET_GTK)
+pref("ui.scrollToClick", 0);
+#endif
+
+// provide ability to turn on support for canvas focus rings
+pref("canvas.focusring.enabled", true);
+pref("canvas.customfocusring.enabled", false);
+pref("canvas.hitregions.enabled", false);
+pref("canvas.filters.enabled", true);
+// Add support for canvas path objects
+pref("canvas.path.enabled", true);
+pref("canvas.capturestream.enabled", true);
+
+// Disable the ImageBitmap-extensions for now.
+pref("canvas.imagebitmap_extensions.enabled", false);
+
+// We want the ability to forcibly disable platform a11y, because
+// some non-a11y-related components attempt to bring it up. See bug
+// 538530 for details about Windows; we have a pref here that allows it
+// to be disabled for performance and testing resons.
+// See bug 761589 for the crossplatform aspect.
+//
+// This pref is checked only once, and the browser needs a restart to
+// pick up any changes.
+//
+// Values are -1 always on. 1 always off, 0 is auto as some platform perform
+// further checks.
+pref("accessibility.force_disabled", 0);
+
+pref("accessibility.ipc_architecture.enabled", true);
+
+pref("accessibility.AOM.enabled", false);
+
+#ifdef XP_WIN
+// Some accessibility tools poke at windows in the plugin process during setup
+// which can cause hangs. To hack around this set accessibility.delay_plugins
+// to true, you can also try increasing accessibility.delay_plugin_time if your
+// machine is slow and you still experience hangs.
+// See bug 781791.
+pref("accessibility.delay_plugins", false);
+pref("accessibility.delay_plugin_time", 10000);
+#endif
+
+pref("focusmanager.testmode", false);
+
+pref("accessibility.usetexttospeech", "");
+pref("accessibility.usebrailledisplay", "");
+pref("accessibility.accesskeycausesactivation", true);
+pref("accessibility.mouse_focuses_formcontrol", false);
+
+// Type Ahead Find
+pref("accessibility.typeaheadfind", true);
+pref("accessibility.typeaheadfind.autostart", true);
+// casesensitive: controls the find bar's case-sensitivity
+// 0 - "never" (case-insensitive)
+// 1 - "always" (case-sensitive)
+// other - "auto" (case-sensitive for mixed-case input, insensitive otherwise)
+pref("accessibility.typeaheadfind.casesensitive", 0);
+pref("accessibility.typeaheadfind.linksonly", true);
+pref("accessibility.typeaheadfind.startlinksonly", false);
+pref("accessibility.typeaheadfind.timeout", 4000);
+pref("accessibility.typeaheadfind.enabletimeout", true);
+pref("accessibility.typeaheadfind.soundURL", "beep");
+pref("accessibility.typeaheadfind.enablesound", true);
+#ifdef XP_MACOSX
+pref("accessibility.typeaheadfind.prefillwithselection", false);
+#else
+pref("accessibility.typeaheadfind.prefillwithselection", true);
+#endif
+pref("accessibility.typeaheadfind.matchesCountLimit", 1000);
+pref("findbar.highlightAll", false);
+pref("findbar.modalHighlight", false);
+pref("findbar.entireword", false);
+pref("findbar.iteratorTimeout", 100);
+
+// use Mac OS X Appearance panel text smoothing setting when rendering text, disabled by default
+pref("gfx.use_text_smoothing_setting", false);
+
+// Number of characters to consider emphasizing for rich autocomplete results
+pref("toolkit.autocomplete.richBoundaryCutoff", 200);
+
+// Variable controlling logging for osfile.
+pref("toolkit.osfile.log", false);
+
+pref("toolkit.scrollbox.smoothScroll", true);
+pref("toolkit.scrollbox.scrollIncrement", 20);
+pref("toolkit.scrollbox.verticalScrollDistance", 3);
+pref("toolkit.scrollbox.horizontalScrollDistance", 5);
+pref("toolkit.scrollbox.clickToScroll.scrollDelay", 150);
+
+// Telemetry settings.
+// Server to submit telemetry pings to.
+pref("toolkit.telemetry.server", "https://incoming.telemetry.mozilla.org");
+// Telemetry server owner. Please change if you set toolkit.telemetry.server to a different server
+pref("toolkit.telemetry.server_owner", "Mozilla");
+// Information page about telemetry (temporary ; will be about:telemetry in the end)
+pref("toolkit.telemetry.infoURL", "https://www.mozilla.org/legal/privacy/firefox.html#telemetry");
+// Determines whether full SQL strings are returned when they might contain sensitive info
+// i.e. dynamically constructed SQL strings or SQL executed by addons against addon DBs
+pref("toolkit.telemetry.debugSlowSql", false);
+// Whether to use the unified telemetry behavior, requires a restart.
+pref("toolkit.telemetry.unified", true);
+
+// Identity module
+pref("toolkit.identity.enabled", false);
+pref("toolkit.identity.debug", false);
+
+// AsyncShutdown delay before crashing in case of shutdown freeze
+pref("toolkit.asyncshutdown.crash_timeout", 60000);
+// Extra logging for AsyncShutdown barriers and phases
+pref("toolkit.asyncshutdown.log", false);
+
+// Enable deprecation warnings.
+pref("devtools.errorconsole.deprecation_warnings", true);
+
+// Disable debugging chrome
+pref("devtools.chrome.enabled", false);
+
+// Disable remote debugging protocol logging
+pref("devtools.debugger.log", false);
+pref("devtools.debugger.log.verbose", false);
+
+// Disable remote debugging connections
+pref("devtools.debugger.remote-enabled", false);
+
+pref("devtools.debugger.remote-port", 6000);
+pref("devtools.debugger.remote-websocket", false);
+// Force debugger server binding on the loopback interface
+pref("devtools.debugger.force-local", true);
+// Display a prompt when a new connection starts to accept/reject it
+pref("devtools.debugger.prompt-connection", true);
+// Block tools from seeing / interacting with certified apps
+pref("devtools.debugger.forbid-certified-apps", true);
+// List of permissions that a sideloaded app can't ask for
+pref("devtools.apps.forbidden-permissions", "embed-apps");
+
+// DevTools default color unit
+pref("devtools.defaultColorUnit", "authored");
+
+// Used for devtools debugging
+pref("devtools.dump.emit", false);
+
+// Disable device discovery logging
+pref("devtools.discovery.log", false);
+// Whether to scan for DevTools devices via WiFi
+pref("devtools.remote.wifi.scan", true);
+// Whether UI options for controlling device visibility over WiFi are shown
+// N.B.: This does not set whether the device can be discovered via WiFi, only
+// whether the UI control to make such a choice is shown to the user
+pref("devtools.remote.wifi.visible", true);
+// Client must complete TLS handshake within this window (ms)
+pref("devtools.remote.tls-handshake-timeout", 10000);
+
+// URL of the remote JSON catalog used for device simulation
+pref("devtools.devices.url", "https://code.cdn.mozilla.net/devices/devices.json");
+
+// Display the introductory text
+pref("devtools.gcli.hideIntro", false);
+
+// How eager are we to show help: never=1, sometimes=2, always=3
+pref("devtools.gcli.eagerHelper", 2);
+
+// Alias to the script URLs for inject command.
+pref("devtools.gcli.jquerySrc", "https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.1/jquery.min.js");
+pref("devtools.gcli.lodashSrc", "https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.6.1/lodash.min.js");
+pref("devtools.gcli.underscoreSrc", "https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js");
+
+// Set imgur upload client ID
+pref("devtools.gcli.imgurClientID", '0df414e888d7240');
+// Imgur's upload URL
+pref("devtools.gcli.imgurUploadURL", "https://api.imgur.com/3/image");
+
+// GCLI commands directory
+pref("devtools.commands.dir", "");
+
+// Allows setting the performance marks for which telemetry metrics will be recorded.
+pref("devtools.telemetry.supported_performance_marks", "contentInteractive,navigationInteractive,navigationLoaded,visuallyLoaded,fullyLoaded,mediaEnumerated,scanEnd");
+
+// Deprecation warnings after DevTools file migration.
+pref("devtools.migration.warnings", true);
+
+// view source
+pref("view_source.syntax_highlight", true);
+pref("view_source.wrap_long_lines", false);
+pref("view_source.editor.external", false);
+pref("view_source.editor.path", "");
+// allows to add further arguments to the editor; use the %LINE% placeholder
+// for jumping to a specific line (e.g. "/line:%LINE%" or "--goto %LINE%")
+pref("view_source.editor.args", "");
+
+// When true this will word-wrap plain text documents.
+pref("plain_text.wrap_long_lines", false);
+
+// whether or not to draw images while dragging
+pref("nglayout.enable_drag_images", true);
+
+// enable/disable paint flashing --- useful for debugging
+// the first one applies to everything, the second one only to chrome
+pref("nglayout.debug.paint_flashing", false);
+pref("nglayout.debug.paint_flashing_chrome", false);
+
+// enable/disable widget update area flashing --- only supported with
+// BasicLayers (other layer managers always update the entire widget area)
+pref("nglayout.debug.widget_update_flashing", false);
+
+// Enable/disable display list invalidation logging --- useful for debugging.
+pref("nglayout.debug.invalidation", false);
+
+// Whether frame visibility tracking is enabled globally.
+pref("layout.framevisibility.enabled", true);
+
+pref("layout.framevisibility.numscrollportwidths", 0);
+pref("layout.framevisibility.numscrollportheights", 1);
+
+// scrollbar snapping region
+// 0 - off
+// 1 and higher - slider thickness multiple
+pref("slider.snapMultiplier", 0);
+
+// option to choose plug-in finder
+pref("application.use_ns_plugin_finder", false);
+
+// URI fixup prefs
+pref("browser.fixup.alternate.enabled", true);
+pref("browser.fixup.alternate.prefix", "www.");
+pref("browser.fixup.alternate.suffix", ".com");
+pref("browser.fixup.dns_first_for_single_words", false);
+pref("browser.fixup.hide_user_pass", true);
+
+// Location Bar AutoComplete
+pref("browser.urlbar.autocomplete.enabled", true);
+
+// Print header customization
+// Use the following codes:
+// &T - Title
+// &U - Document URL
+// &D - Date/Time
+// &P - Page Number
+// &PT - Page Number "of" Page total
+// Set each header to a string containing zero or one of these codes
+// and the code will be replaced in that string by the corresponding data
+pref("print.print_headerleft", "&T");
+pref("print.print_headercenter", "");
+pref("print.print_headerright", "&U");
+pref("print.print_footerleft", "&PT");
+pref("print.print_footercenter", "");
+pref("print.print_footerright", "&D");
+pref("print.show_print_progress", true);
+
+// xxxbsmedberg: more toolkit prefs
+
+// When this is set to false each window has its own PrintSettings
+// and a change in one window does not affect the others
+pref("print.use_global_printsettings", true);
+
+// Save the Printings after each print job
+pref("print.save_print_settings", true);
+
+// Cache old Presentation when going into Print Preview
+pref("print.always_cache_old_pres", false);
+
+// Enables you to specify the amount of the paper that is to be treated
+// as unwriteable. The print_edge_XXX and print_margin_XXX preferences
+// are treated as offsets that are added to this pref.
+// Default is "-1", which means "use the system default". (If there is
+// no system default, then the -1 is treated as if it were 0.)
+// This is used by both Printing and Print Preview.
+// Units are in 1/100ths of an inch.
+pref("print.print_unwriteable_margin_top", -1);
+pref("print.print_unwriteable_margin_left", -1);
+pref("print.print_unwriteable_margin_right", -1);
+pref("print.print_unwriteable_margin_bottom", -1);
+
+// Enables you to specify the gap from the edge of the paper's
+// unwriteable area to the margin.
+// This is used by both Printing and Print Preview
+// Units are in 1/100ths of an inch.
+pref("print.print_edge_top", 0);
+pref("print.print_edge_left", 0);
+pref("print.print_edge_right", 0);
+pref("print.print_edge_bottom", 0);
+
+// Print via the parent process. This is only used when e10s is enabled.
+#if defined(XP_WIN) || defined(XP_MACOSX)
+pref("print.print_via_parent", true);
+#else
+pref("print.print_via_parent", false);
+#endif
+
+// Pref used by the spellchecker extension to control the
+// maximum number of misspelled words that will be underlined
+// in a document.
+pref("extensions.spellcheck.inline.max-misspellings", 500);
+
+// Prefs used by libeditor. Prefs specific to seamonkey composer
+// belong in comm-central/editor/ui/composer.js
+
+pref("editor.use_custom_colors", false);
+pref("editor.singleLine.pasteNewlines", 2);
+pref("editor.use_css", false);
+pref("editor.css.default_length_unit", "px");
+pref("editor.resizing.preserve_ratio", true);
+pref("editor.positioning.offset", 0);
+
+// Scripts & Windows prefs
+pref("dom.disable_beforeunload", false);
+pref("dom.disable_window_flip", false);
+pref("dom.disable_window_move_resize", false);
+pref("dom.disable_window_status_change", false);
+
+pref("dom.disable_window_open_feature.titlebar", false);
+pref("dom.disable_window_open_feature.close", false);
+pref("dom.disable_window_open_feature.toolbar", false);
+pref("dom.disable_window_open_feature.location", false);
+pref("dom.disable_window_open_feature.personalbar", false);
+pref("dom.disable_window_open_feature.menubar", false);
+pref("dom.disable_window_open_feature.resizable", true);
+pref("dom.disable_window_open_feature.minimizable", false);
+pref("dom.disable_window_open_feature.status", true);
+
+pref("dom.allow_scripts_to_close_windows", false);
+
+pref("dom.require_user_interaction_for_beforeunload", true);
+
+pref("dom.disable_open_during_load", false);
+pref("dom.popup_maximum", 20);
+pref("dom.popup_allowed_events", "change click dblclick mouseup notificationclick reset submit touchend");
+pref("dom.disable_open_click_delay", 1000);
+
+pref("dom.storage.enabled", true);
+pref("dom.storage.default_quota", 5120);
+
+pref("dom.send_after_paint_to_content", false);
+
+// Timeout clamp in ms for timeouts we clamp
+pref("dom.min_timeout_value", 4);
+// And for background windows
+pref("dom.min_background_timeout_value", 1000);
+
+// Don't use new input types
+pref("dom.experimental_forms", false);
+
+// Enable <input type=number>:
+pref("dom.forms.number", true);
+
+// Enable <input type=color> by default. It will be turned off for remaining
+// platforms which don't have a color picker implemented yet.
+pref("dom.forms.color", true);
+
+// Support for input type=date, time, month, week and datetime-local. By
+// default, disabled.
+pref("dom.forms.datetime", false);
+
+// Enable time picker UI. By default, disabled.
+pref("dom.forms.datetime.timepicker", false);
+
+// Support for new @autocomplete values
+pref("dom.forms.autocomplete.experimental", false);
+
+// Enables requestAutocomplete DOM API on forms.
+pref("dom.forms.requestAutocomplete", false);
+
+// Enable Directory API. By default, disabled.
+pref("dom.input.dirpicker", false);
+
+// Enables system messages and activities
+pref("dom.sysmsg.enabled", false);
+
+// Enable pre-installed applications.
+pref("dom.webapps.useCurrentProfile", false);
+
+pref("dom.cycle_collector.incremental", true);
+
+// Parsing perf prefs. For now just mimic what the old code did.
+#ifndef XP_WIN
+pref("content.sink.pending_event_mode", 0);
+#endif
+
+// Disable popups from plugins by default
+// 0 = openAllowed
+// 1 = openControlled
+// 2 = openAbused
+pref("privacy.popups.disable_from_plugins", 2);
+
+// send "do not track" HTTP header, disabled by default
+pref("privacy.donottrackheader.enabled", false);
+// Enforce tracking protection in all modes
+pref("privacy.trackingprotection.enabled", false);
+// Enforce tracking protection in Private Browsing mode
+pref("privacy.trackingprotection.pbmode.enabled", true);
+
+pref("dom.event.contextmenu.enabled", true);
+pref("dom.event.clipboardevents.enabled", true);
+#if defined(XP_WIN) && !defined(RELEASE_OR_BETA) || defined(MOZ_WIDGET_GTK) && !defined(RELEASE_OR_BETA)
+pref("dom.event.highrestimestamp.enabled", true);
+#else
+pref("dom.event.highrestimestamp.enabled", false);
+#endif
+
+pref("dom.webcomponents.enabled", false);
+pref("dom.webcomponents.customelements.enabled", false);
+
+pref("javascript.enabled", true);
+pref("javascript.options.strict", false);
+#ifdef DEBUG
+pref("javascript.options.strict.debug", false);
+#endif
+pref("javascript.options.baselinejit", true);
+pref("javascript.options.ion", true);
+pref("javascript.options.asmjs", true);
+pref("javascript.options.wasm", false);
+pref("javascript.options.wasm_baselinejit", false);
+pref("javascript.options.native_regexp", true);
+pref("javascript.options.parallel_parsing", true);
+#if !defined(RELEASE_OR_BETA) && !defined(ANDROID) && !defined(MOZ_B2G) && !defined(XP_IOS)
+pref("javascript.options.asyncstack", true);
+#else
+pref("javascript.options.asyncstack", false);
+#endif
+pref("javascript.options.throw_on_asmjs_validation_failure", false);
+pref("javascript.options.ion.offthread_compilation", true);
+// This preference instructs the JS engine to discard the
+// source of any privileged JS after compilation. This saves
+// memory, but makes things like Function.prototype.toSource()
+// fail.
+pref("javascript.options.discardSystemSource", false);
+// This preference limits the memory usage of javascript.
+// If you want to change these values for your device,
+// please find Bug 417052 comment 17 and Bug 456721
+// Comment 32 and Bug 613551.
+pref("javascript.options.mem.high_water_mark", 128);
+pref("javascript.options.mem.max", -1);
+pref("javascript.options.mem.gc_per_zone", true);
+pref("javascript.options.mem.gc_incremental", true);
+pref("javascript.options.mem.gc_incremental_slice_ms", 10);
+pref("javascript.options.mem.gc_compacting", true);
+pref("javascript.options.mem.log", false);
+pref("javascript.options.mem.notify", false);
+pref("javascript.options.gc_on_memory_pressure", true);
+pref("javascript.options.compact_on_user_inactive", true);
+#ifdef NIGHTLY_BUILD
+pref("javascript.options.compact_on_user_inactive_delay", 15000); // ms
+#else
+pref("javascript.options.compact_on_user_inactive_delay", 300000); // ms
+#endif
+
+pref("javascript.options.mem.gc_high_frequency_time_limit_ms", 1000);
+pref("javascript.options.mem.gc_high_frequency_low_limit_mb", 100);
+pref("javascript.options.mem.gc_high_frequency_high_limit_mb", 500);
+pref("javascript.options.mem.gc_high_frequency_heap_growth_max", 300);
+pref("javascript.options.mem.gc_high_frequency_heap_growth_min", 150);
+pref("javascript.options.mem.gc_low_frequency_heap_growth", 150);
+pref("javascript.options.mem.gc_dynamic_heap_growth", true);
+pref("javascript.options.mem.gc_dynamic_mark_slice", true);
+pref("javascript.options.mem.gc_refresh_frame_slices_enabled", true);
+pref("javascript.options.mem.gc_allocation_threshold_mb", 30);
+pref("javascript.options.mem.gc_min_empty_chunk_count", 1);
+pref("javascript.options.mem.gc_max_empty_chunk_count", 30);
+
+pref("javascript.options.showInConsole", false);
+
+#ifdef RELEASE_OR_BETA
+// Disabled in Beta and Release for now, see bug 1225406
+pref("javascript.options.shared_memory", false);
+#else
+pref("javascript.options.shared_memory", true);
+#endif
+
+pref("javascript.options.throw_on_debuggee_would_run", false);
+pref("javascript.options.dump_stack_on_debuggee_would_run", false);
+
+// advanced prefs
+pref("advanced.mailftp", false);
+pref("image.animation_mode", "normal");
+
+// Same-origin policy for file URIs, "false" is traditional
+pref("security.fileuri.strict_origin_policy", true);
+
+// If this pref is true, prefs in the logging.config branch will be cleared on
+// startup. This is done so that setting a log-file and log-modules at runtime
+// doesn't persist across restarts leading to huge logfile and low disk space.
+pref("logging.config.clear_on_startup", true);
+
+// If there is ever a security firedrill that requires
+// us to block certian ports global, this is the pref
+// to use. Is is a comma delimited list of port numbers
+// for example:
+// pref("network.security.ports.banned", "1,2,3,4,5");
+// prevents necko connecting to ports 1-5 unless the protocol
+// overrides.
+
+// Allow necko to do A/B testing. Will generally only happen if
+// telemetry is also enabled as otherwise there is no way to report
+// the results
+pref("network.allow-experiments", true);
+
+// Allow the network changed event to get sent when a network topology or
+// setup change is noticed while running.
+pref("network.notify.changed", true);
+
+// Allow network detection of IPv6 related changes (bug 1245059)
+#if defined(XP_WIN)
+pref("network.notify.IPv6", false);
+#else
+pref("network.notify.IPv6", true);
+#endif
+
+// Transmit UDP busy-work to the LAN when anticipating low latency
+// network reads and on wifi to mitigate 802.11 Power Save Polling delays
+pref("network.tickle-wifi.enabled", false);
+pref("network.tickle-wifi.duration", 400);
+pref("network.tickle-wifi.delay", 16);
+
+// Turn off interprocess security checks. Needed to run xpcshell tests.
+pref("network.disable.ipc.security", false);
+
+// Default action for unlisted external protocol handlers
+pref("network.protocol-handler.external-default", true); // OK to load
+pref("network.protocol-handler.warn-external-default", true); // warn before load
+
+// Prevent using external protocol handlers for these schemes
+pref("network.protocol-handler.external.hcp", false);
+pref("network.protocol-handler.external.vbscript", false);
+pref("network.protocol-handler.external.javascript", false);
+pref("network.protocol-handler.external.data", false);
+pref("network.protocol-handler.external.ms-help", false);
+pref("network.protocol-handler.external.shell", false);
+pref("network.protocol-handler.external.vnd.ms.radio", false);
+#ifdef XP_MACOSX
+pref("network.protocol-handler.external.help", false);
+#endif
+pref("network.protocol-handler.external.disk", false);
+pref("network.protocol-handler.external.disks", false);
+pref("network.protocol-handler.external.afp", false);
+pref("network.protocol-handler.external.moz-icon", false);
+
+// Don't allow external protocol handlers for common typos
+pref("network.protocol-handler.external.ttp", false); // http
+pref("network.protocol-handler.external.ttps", false); // https
+pref("network.protocol-handler.external.tps", false); // https
+pref("network.protocol-handler.external.ps", false); // https
+pref("network.protocol-handler.external.ile", false); // file
+pref("network.protocol-handler.external.le", false); // file
+
+// An exposed protocol handler is one that can be used in all contexts. A
+// non-exposed protocol handler is one that can only be used internally by the
+// application. For example, a non-exposed protocol would not be loaded by the
+// application in response to a link click or a X-remote openURL command.
+// Instead, it would be deferred to the system's external protocol handler.
+// Only internal/built-in protocol handlers can be marked as exposed.
+
+// This pref controls the default settings. Per protocol settings can be used
+// to override this value.
+pref("network.protocol-handler.expose-all", true);
+
+// Warning for about:networking page
+pref("network.warnOnAboutNetworking", true);
+
+// Example: make IMAP an exposed protocol
+// pref("network.protocol-handler.expose.imap", true);
+
+// Whether IOService.connectivity and NS_IsOffline depends on connectivity status
+pref("network.manage-offline-status", true);
+// If set to true, IOService.offline depends on IOService.connectivity
+pref("network.offline-mirrors-connectivity", false);
+
+// <http>
+pref("network.http.version", "1.1"); // default
+// pref("network.http.version", "1.0"); // uncomment this out in case of problems
+// pref("network.http.version", "0.9"); // it'll work too if you're crazy
+// keep-alive option is effectively obsolete. Nevertheless it'll work with
+// some older 1.0 servers:
+
+pref("network.http.proxy.version", "1.1"); // default
+// pref("network.http.proxy.version", "1.0"); // uncomment this out in case of problems
+ // (required if using junkbuster proxy)
+
+// this preference can be set to override the socket type used for normal
+// HTTP traffic. an empty value indicates the normal TCP/IP socket type.
+pref("network.http.default-socket-type", "");
+
+// There is a problem with some IIS7 servers that don't close the connection
+// properly after it times out (bug #491541). Default timeout on IIS7 is
+// 120 seconds. We need to reuse or drop the connection within this time.
+// We set the timeout a little shorter to keep a reserve for cases when
+// the packet is lost or delayed on the route.
+pref("network.http.keep-alive.timeout", 115);
+
+// Timeout connections if an initial response is not received after 5 mins.
+pref("network.http.response.timeout", 300);
+
+// Limit the absolute number of http connections.
+// Note: the socket transport service will clamp the number below this if the OS
+// cannot allocate that many FDs
+#ifdef ANDROID
+pref("network.http.max-connections", 256);
+#else
+pref("network.http.max-connections", 900);
+#endif
+
+// If NOT connecting via a proxy, then
+// a new connection will only be attempted if the number of active persistent
+// connections to the server is less then max-persistent-connections-per-server.
+pref("network.http.max-persistent-connections-per-server", 6);
+
+// If connecting via a proxy, then a
+// new connection will only be attempted if the number of active persistent
+// connections to the proxy is less then max-persistent-connections-per-proxy.
+pref("network.http.max-persistent-connections-per-proxy", 32);
+
+// amount of time (in seconds) to suspend pending requests, before spawning a
+// new connection, once the limit on the number of persistent connections per
+// host has been reached. however, a new connection will not be created if
+// max-connections or max-connections-per-server has also been reached.
+pref("network.http.request.max-start-delay", 10);
+
+// If a connection is reset, we will retry it max-attempts times.
+pref("network.http.request.max-attempts", 10);
+
+// Headers
+pref("network.http.accept.default", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
+
+// Prefs allowing granular control of referers
+// 0=don't send any, 1=send only on clicks, 2=send on image requests as well
+pref("network.http.sendRefererHeader", 2);
+// false=real referer, true=spoof referer (use target URI as referer)
+pref("network.http.referer.spoofSource", false);
+// 0=full URI, 1=scheme+host+port+path, 2=scheme+host+port
+pref("network.http.referer.trimmingPolicy", 0);
+// 0=full URI, 1=scheme+host+port+path, 2=scheme+host+port
+pref("network.http.referer.XOriginTrimmingPolicy", 0);
+// 0=always send, 1=send iff base domains match, 2=send iff hosts match
+pref("network.http.referer.XOriginPolicy", 0);
+
+// Controls whether referrer attributes in <a>, <img>, <area>, <iframe>, and <link> are honoured
+pref("network.http.enablePerElementReferrer", true);
+
+// Maximum number of consecutive redirects before aborting.
+pref("network.http.redirection-limit", 20);
+
+// Enable http compression: comment this out in case of problems with 1.1
+// NOTE: support for "compress" has been disabled per bug 196406.
+// NOTE: separate values with comma+space (", "): see bug 576033
+pref("network.http.accept-encoding", "gzip, deflate");
+pref("network.http.accept-encoding.secure", "gzip, deflate, br");
+
+pref("network.http.pipelining" , false);
+pref("network.http.pipelining.ssl" , false); // disable pipelining over SSL
+pref("network.http.pipelining.abtest", false);
+pref("network.http.proxy.pipelining", false);
+
+// Max number of requests in the pipeline
+pref("network.http.pipelining.maxrequests" , 32);
+
+// An optimistic request is one pipelined when policy might allow a new
+// connection instead
+pref("network.http.pipelining.max-optimistic-requests" , 4);
+
+pref("network.http.pipelining.aggressive", false);
+pref("network.http.pipelining.maxsize" , 300000);
+pref("network.http.pipelining.reschedule-on-timeout", true);
+pref("network.http.pipelining.reschedule-timeout", 1500);
+
+// The read-timeout is a ms timer that causes the transaction to be completely
+// restarted without pipelining.
+pref("network.http.pipelining.read-timeout", 30000);
+
+// Prompt for redirects resulting in unsafe HTTP requests
+pref("network.http.prompt-temp-redirect", false);
+
+// If true generate CORRUPTED_CONTENT errors for entities that
+// contain an invalid Assoc-Req response header
+pref("network.http.assoc-req.enforce", false);
+
+// On networks deploying QoS, it is recommended that these be lockpref()'d,
+// since inappropriate marking can easily overwhelm bandwidth reservations
+// for certain services (i.e. EF for VoIP, AF4x for interactive video,
+// AF3x for broadcast/streaming video, etc)
+
+// default value for HTTP
+// in a DSCP environment this should be 40 (0x28, or AF11), per RFC-4594,
+// Section 4.8 "High-Throughput Data Service Class"
+pref("network.http.qos", 0);
+
+// The number of milliseconds after sending a SYN for an HTTP connection,
+// to wait before trying a different connection. 0 means do not use a second
+// connection.
+pref("network.http.connection-retry-timeout", 250);
+
+// The number of seconds after sending initial SYN for an HTTP connection
+// to give up if the OS does not give up first
+pref("network.http.connection-timeout", 90);
+
+// The number of seconds to allow active connections to prove that they have
+// traffic before considered stalled, after a network change has been detected
+// and signalled.
+pref("network.http.network-changed.timeout", 5);
+
+// The maximum number of current global half open sockets allowable
+// when starting a new speculative connection.
+pref("network.http.speculative-parallel-limit", 6);
+
+// Whether or not to block requests for non head js/css items (e.g. media)
+// while those elements load.
+pref("network.http.rendering-critical-requests-prioritization", true);
+
+// Disable IPv6 for backup connections to workaround problems about broken
+// IPv6 connectivity.
+pref("network.http.fast-fallback-to-IPv4", true);
+
+// The maximum amount of time the cache session lock can be held
+// before a new transaction bypasses the cache. In milliseconds.
+#ifdef RELEASE_OR_BETA
+pref("network.http.bypass-cachelock-threshold", 200000);
+#else
+pref("network.http.bypass-cachelock-threshold", 250);
+#endif
+
+// Try and use SPDY when using SSL
+pref("network.http.spdy.enabled", true);
+pref("network.http.spdy.enabled.http2", true);
+pref("network.http.spdy.enabled.deps", true);
+pref("network.http.spdy.enforce-tls-profile", true);
+pref("network.http.spdy.chunk-size", 16000);
+pref("network.http.spdy.timeout", 180);
+pref("network.http.spdy.coalesce-hostnames", true);
+pref("network.http.spdy.persistent-settings", false);
+pref("network.http.spdy.ping-threshold", 58);
+pref("network.http.spdy.ping-timeout", 8);
+pref("network.http.spdy.send-buffer-size", 131072);
+pref("network.http.spdy.allow-push", true);
+pref("network.http.spdy.push-allowance", 131072); // 128KB
+pref("network.http.spdy.pull-allowance", 12582912); // 12MB
+pref("network.http.spdy.default-concurrent", 100);
+pref("network.http.spdy.default-hpack-buffer", 65536); // 64k
+
+// alt-svc allows separation of transport routing from
+// the origin host without using a proxy.
+pref("network.http.altsvc.enabled", true);
+pref("network.http.altsvc.oe", true);
+
+pref("network.http.diagnostics", false);
+
+pref("network.http.pacing.requests.enabled", true);
+pref("network.http.pacing.requests.min-parallelism", 6);
+pref("network.http.pacing.requests.hz", 80);
+pref("network.http.pacing.requests.burst", 10);
+
+// TCP Keepalive config for HTTP connections.
+pref("network.http.tcp_keepalive.short_lived_connections", true);
+// Max time from initial request during which conns are considered short-lived.
+pref("network.http.tcp_keepalive.short_lived_time", 60);
+// Idle time of TCP connection until first keepalive probe sent.
+pref("network.http.tcp_keepalive.short_lived_idle_time", 10);
+
+pref("network.http.tcp_keepalive.long_lived_connections", true);
+pref("network.http.tcp_keepalive.long_lived_idle_time", 600);
+
+pref("network.http.enforce-framing.http1", false); // should be named "strict"
+pref("network.http.enforce-framing.soft", true);
+
+// If it is set to false, headers with empty value will not appear in the header
+// array - behavior as it used to be. If it is true: empty headers coming from
+// the network will exist in header array as empty string. Call SetHeader with
+// an empty value will still delete the header.(Bug 6699259)
+pref("network.http.keep_empty_response_headers_as_empty_string", true);
+
+// Max size, in bytes, for received HTTP response header.
+pref("network.http.max_response_header_size", 393216);
+
+// default values for FTP
+// in a DSCP environment this should be 40 (0x28, or AF11), per RFC-4594,
+// Section 4.8 "High-Throughput Data Service Class", and 80 (0x50, or AF22)
+// per Section 4.7 "Low-Latency Data Service Class".
+pref("network.ftp.data.qos", 0);
+pref("network.ftp.control.qos", 0);
+
+// The max time to spend on xpcom events between two polls in ms.
+pref("network.sts.max_time_for_events_between_two_polls", 100);
+
+// During shutdown we limit PR_Close calls. If time exceeds this pref (in ms)
+// let sockets just leak.
+pref("network.sts.max_time_for_pr_close_during_shutdown", 5000);
+// </http>
+
+// 2147483647 == PR_INT32_MAX == ~2 GB
+pref("network.websocket.max-message-size", 2147483647);
+
+// Should we automatically follow http 3xx redirects during handshake
+pref("network.websocket.auto-follow-http-redirects", false);
+
+// the number of seconds to wait for websocket connection to be opened
+pref("network.websocket.timeout.open", 20);
+
+// the number of seconds to wait for a clean close after sending the client
+// close message
+pref("network.websocket.timeout.close", 20);
+
+// the number of seconds of idle read activity to sustain before sending a
+// ping probe. 0 to disable.
+pref("network.websocket.timeout.ping.request", 0);
+
+// the deadline, expressed in seconds, for some read activity to occur after
+// generating a ping. If no activity happens then an error and unclean close
+// event is sent to the javascript websockets application
+pref("network.websocket.timeout.ping.response", 10);
+
+// Defines whether or not to try to negotiate the permessage compression
+// extension with the websocket server.
+pref("network.websocket.extensions.permessage-deflate", true);
+
+// the maximum number of concurrent websocket sessions. By specification there
+// is never more than one handshake oustanding to an individual host at
+// one time.
+pref("network.websocket.max-connections", 200);
+
+// by default scripts loaded from a https:// origin can only open secure
+// (i.e. wss://) websockets.
+pref("network.websocket.allowInsecureFromHTTPS", false);
+
+// by default we delay websocket reconnects to same host/port if previous
+// connection failed, per RFC 6455 section 7.2.3
+pref("network.websocket.delay-failed-reconnects", true);
+
+// </ws>
+
+// Server-Sent Events
+// Equal to the DEFAULT_RECONNECTION_TIME_VALUE value in nsEventSource.cpp
+pref("dom.server-events.default-reconnection-time", 5000); // in milliseconds
+
+// If false, remote JAR files that are served with a content type other than
+// application/java-archive or application/x-jar will not be opened
+// by the jar channel.
+pref("network.jar.open-unsafe-types", false);
+// If true, loading remote JAR files using the jar: protocol will be prevented.
+#ifdef RELEASE_OR_BETA
+// Keep allowing remote JAR files for IBM iNotes (see bug 1255139) for now.
+pref("network.jar.block-remote-files", false);
+#else
+pref("network.jar.block-remote-files", true);
+#endif
+
+// This preference, if true, causes all UTF-8 domain names to be normalized to
+// punycode. The intention is to allow UTF-8 domain names as input, but never
+// generate them from punycode.
+pref("network.IDN_show_punycode", false);
+
+// If "network.IDN.use_whitelist" is set to true, TLDs with
+// "network.IDN.whitelist.tld" explicitly set to true are treated as
+// IDN-safe. Otherwise, they're treated as unsafe and punycode will be used
+// for displaying them in the UI (e.g. URL bar), unless they conform to one of
+// the profiles specified in
+// http://www.unicode.org/reports/tr36/proposed.html#Security_Levels_and_Alerts
+// If "network.IDN.restriction_profile" is "high", the Highly Restrictive
+// profile is used.
+// If "network.IDN.restriction_profile" is "moderate", the Moderately
+// Restrictive profile is used.
+// In all other cases, the ASCII-Only profile is used.
+// Note that these preferences are referred to ONLY when
+// "network.IDN_show_punycode" is false. In other words, all IDNs will be shown
+// in punycode if "network.IDN_show_punycode" is true.
+pref("network.IDN.restriction_profile", "moderate");
+pref("network.IDN.use_whitelist", false);
+
+// ccTLDs
+pref("network.IDN.whitelist.ac", true);
+pref("network.IDN.whitelist.ar", true);
+pref("network.IDN.whitelist.at", true);
+pref("network.IDN.whitelist.br", true);
+pref("network.IDN.whitelist.ca", true);
+pref("network.IDN.whitelist.ch", true);
+pref("network.IDN.whitelist.cl", true);
+pref("network.IDN.whitelist.cn", true);
+pref("network.IDN.whitelist.de", true);
+pref("network.IDN.whitelist.dk", true);
+pref("network.IDN.whitelist.ee", true);
+pref("network.IDN.whitelist.es", true);
+pref("network.IDN.whitelist.fi", true);
+pref("network.IDN.whitelist.fr", true);
+pref("network.IDN.whitelist.gr", true);
+pref("network.IDN.whitelist.gt", true);
+pref("network.IDN.whitelist.hu", true);
+pref("network.IDN.whitelist.il", true);
+pref("network.IDN.whitelist.io", true);
+pref("network.IDN.whitelist.ir", true);
+pref("network.IDN.whitelist.is", true);
+pref("network.IDN.whitelist.jp", true);
+pref("network.IDN.whitelist.kr", true);
+pref("network.IDN.whitelist.li", true);
+pref("network.IDN.whitelist.lt", true);
+pref("network.IDN.whitelist.lu", true);
+pref("network.IDN.whitelist.lv", true);
+pref("network.IDN.whitelist.no", true);
+pref("network.IDN.whitelist.nu", true);
+pref("network.IDN.whitelist.nz", true);
+pref("network.IDN.whitelist.pl", true);
+pref("network.IDN.whitelist.pm", true);
+pref("network.IDN.whitelist.pr", true);
+pref("network.IDN.whitelist.re", true);
+pref("network.IDN.whitelist.se", true);
+pref("network.IDN.whitelist.sh", true);
+pref("network.IDN.whitelist.si", true);
+pref("network.IDN.whitelist.tf", true);
+pref("network.IDN.whitelist.th", true);
+pref("network.IDN.whitelist.tm", true);
+pref("network.IDN.whitelist.tw", true);
+pref("network.IDN.whitelist.ua", true);
+pref("network.IDN.whitelist.vn", true);
+pref("network.IDN.whitelist.wf", true);
+pref("network.IDN.whitelist.yt", true);
+
+// IDN ccTLDs
+// ae, UAE, .<Emarat>
+pref("network.IDN.whitelist.xn--mgbaam7a8h", true);
+// cn, China, .<China> with variants
+pref("network.IDN.whitelist.xn--fiqz9s", true); // Traditional
+pref("network.IDN.whitelist.xn--fiqs8s", true); // Simplified
+// eg, Egypt, .<Masr>
+pref("network.IDN.whitelist.xn--wgbh1c", true);
+// hk, Hong Kong, .<Hong Kong>
+pref("network.IDN.whitelist.xn--j6w193g", true);
+// ir, Iran, <.Iran> with variants
+pref("network.IDN.whitelist.xn--mgba3a4f16a", true);
+pref("network.IDN.whitelist.xn--mgba3a4fra", true);
+// jo, Jordan, .<Al-Ordon>
+pref("network.IDN.whitelist.xn--mgbayh7gpa", true);
+// lk, Sri Lanka, .<Lanka> and .<Ilangai>
+pref("network.IDN.whitelist.xn--fzc2c9e2c", true);
+pref("network.IDN.whitelist.xn--xkc2al3hye2a", true);
+// qa, Qatar, .<Qatar>
+pref("network.IDN.whitelist.xn--wgbl6a", true);
+// rs, Serbia, .<Srb>
+pref("network.IDN.whitelist.xn--90a3ac", true);
+// ru, Russian Federation, .<RF>
+pref("network.IDN.whitelist.xn--p1ai", true);
+// sa, Saudi Arabia, .<al-Saudiah> with variants
+pref("network.IDN.whitelist.xn--mgberp4a5d4ar", true);
+pref("network.IDN.whitelist.xn--mgberp4a5d4a87g", true);
+pref("network.IDN.whitelist.xn--mgbqly7c0a67fbc", true);
+pref("network.IDN.whitelist.xn--mgbqly7cvafr", true);
+// sy, Syria, .<Souria>
+pref("network.IDN.whitelist.xn--ogbpf8fl", true);
+// th, Thailand, .<Thai>
+pref("network.IDN.whitelist.xn--o3cw4h", true);
+// tw, Taiwan, <.Taiwan> with variants
+pref("network.IDN.whitelist.xn--kpry57d", true); // Traditional
+pref("network.IDN.whitelist.xn--kprw13d", true); // Simplified
+
+// gTLDs
+pref("network.IDN.whitelist.asia", true);
+pref("network.IDN.whitelist.biz", true);
+pref("network.IDN.whitelist.cat", true);
+pref("network.IDN.whitelist.info", true);
+pref("network.IDN.whitelist.museum", true);
+pref("network.IDN.whitelist.org", true);
+pref("network.IDN.whitelist.tel", true);
+
+// NOTE: Before these can be removed, one of bug 414812's tests must be updated
+// or it will likely fail! Please CC jwalden+bmo on the bug associated
+// with removing these so he can provide a patch to make the necessary
+// changes to avoid bustage.
+// ".test" localised TLDs for ICANN's top-level IDN trial
+pref("network.IDN.whitelist.xn--0zwm56d", true);
+pref("network.IDN.whitelist.xn--11b5bs3a9aj6g", true);
+pref("network.IDN.whitelist.xn--80akhbyknj4f", true);
+pref("network.IDN.whitelist.xn--9t4b11yi5a", true);
+pref("network.IDN.whitelist.xn--deba0ad", true);
+pref("network.IDN.whitelist.xn--g6w251d", true);
+pref("network.IDN.whitelist.xn--hgbk6aj7f53bba", true);
+pref("network.IDN.whitelist.xn--hlcj6aya9esc7a", true);
+pref("network.IDN.whitelist.xn--jxalpdlp", true);
+pref("network.IDN.whitelist.xn--kgbechtv", true);
+pref("network.IDN.whitelist.xn--zckzah", true);
+
+// If a domain includes any of the following characters, it may be a spoof
+// attempt and so we always display the domain name as punycode. This would
+// override the settings "network.IDN_show_punycode" and
+// "network.IDN.whitelist.*". (please keep this value in sync with the
+// built-in fallback in intl/uconv/nsTextToSubURI.cpp)
+pref("network.IDN.blacklist_chars", "\u0020\u00A0\u00BC\u00BD\u00BE\u01C3\u02D0\u0337\u0338\u0589\u058A\u05C3\u05F4\u0609\u060A\u066A\u06D4\u0701\u0702\u0703\u0704\u115F\u1160\u1735\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u200B\u200E\u200F\u2010\u2019\u2024\u2027\u2028\u2029\u202A\u202B\u202C\u202D\u202E\u202F\u2039\u203A\u2041\u2044\u2052\u205F\u2153\u2154\u2155\u2156\u2157\u2158\u2159\u215A\u215B\u215C\u215D\u215E\u215F\u2215\u2236\u23AE\u2571\u29F6\u29F8\u2AFB\u2AFD\u2FF0\u2FF1\u2FF2\u2FF3\u2FF4\u2FF5\u2FF6\u2FF7\u2FF8\u2FF9\u2FFA\u2FFB\u3000\u3002\u3014\u3015\u3033\u30A0\u3164\u321D\u321E\u33AE\u33AF\u33C6\u33DF\uA789\uFE14\uFE15\uFE3F\uFE5D\uFE5E\uFEFF\uFF0E\uFF0F\uFF61\uFFA0\uFFF9\uFFFA\uFFFB\uFFFC\uFFFD");
+
+// This preference specifies a list of domains for which DNS lookups will be
+// IPv4 only. Works around broken DNS servers which can't handle IPv6 lookups
+// and/or allows the user to disable IPv6 on a per-domain basis. See bug 68796.
+pref("network.dns.ipv4OnlyDomains", "");
+
+// This preference can be used to turn off IPv6 name lookups. See bug 68796.
+pref("network.dns.disableIPv6", false);
+
+// This is the number of dns cache entries allowed
+pref("network.dnsCacheEntries", 400);
+
+// In the absence of OS TTLs, the DNS cache TTL value
+pref("network.dnsCacheExpiration", 60);
+
+// Get TTL; not supported on all platforms; nop on the unsupported ones.
+pref("network.dns.get-ttl", true);
+
+// The grace period allows the DNS cache to use expired entries, while kicking off
+// a revalidation in the background.
+pref("network.dnsCacheExpirationGracePeriod", 60);
+
+// This preference can be used to turn off DNS prefetch.
+pref("network.dns.disablePrefetch", false);
+
+// This preference controls whether .onion hostnames are
+// rejected before being given to DNS. RFC 7686
+pref("network.dns.blockDotOnion", true);
+
+// These domains are treated as localhost equivalent
+pref("network.dns.localDomains", "");
+
+// Contols whether or not "localhost" should resolve when offline
+pref("network.dns.offline-localhost", true);
+
+// This preference controls whether or not URLs with UTF-8 characters are
+// escaped. Set this preference to TRUE for strict RFC2396 conformance.
+pref("network.standard-url.escape-utf8", true);
+
+// This preference controls whether or not URLs are always encoded and sent as
+// UTF-8.
+pref("network.standard-url.encode-utf8", true);
+
+// The maximum allowed length for a URL - 1MB default
+pref("network.standard-url.max-length", 1048576);
+
+// Idle timeout for ftp control connections - 5 minute default
+pref("network.ftp.idleConnectionTimeout", 300);
+
+// directory listing format
+// 2: HTML
+// 3: XUL directory viewer
+// all other values are treated like 2
+pref("network.dir.format", 2);
+
+// enables the prefetch service (i.e., prefetching of <link rel="next"> URLs).
+pref("network.prefetch-next", true);
+
+// enables the predictive service
+pref("network.predictor.enabled", true);
+pref("network.predictor.enable-hover-on-ssl", false);
+pref("network.predictor.enable-prefetch", false);
+pref("network.predictor.page-degradation.day", 0);
+pref("network.predictor.page-degradation.week", 5);
+pref("network.predictor.page-degradation.month", 10);
+pref("network.predictor.page-degradation.year", 25);
+pref("network.predictor.page-degradation.max", 50);
+pref("network.predictor.subresource-degradation.day", 1);
+pref("network.predictor.subresource-degradation.week", 10);
+pref("network.predictor.subresource-degradation.month", 25);
+pref("network.predictor.subresource-degradation.year", 50);
+pref("network.predictor.subresource-degradation.max", 100);
+pref("network.predictor.prefetch-rolling-load-count", 10);
+pref("network.predictor.prefetch-min-confidence", 100);
+pref("network.predictor.preconnect-min-confidence", 90);
+pref("network.predictor.preresolve-min-confidence", 60);
+pref("network.predictor.redirect-likely-confidence", 75);
+pref("network.predictor.prefetch-force-valid-for", 10);
+pref("network.predictor.max-resources-per-entry", 100);
+pref("network.predictor.max-uri-length", 500);
+pref("network.predictor.cleaned-up", false);
+
+// The following prefs pertain to the negotiate-auth extension (see bug 17578),
+// which provides transparent Kerberos or NTLM authentication using the SPNEGO
+// protocol. Each pref is a comma-separated list of keys, where each key has
+// the format:
+// [scheme "://"] [host [":" port]]
+// For example, "foo.com" would match "http://www.foo.com/bar", etc.
+
+// Force less-secure NTLMv1 when needed (NTLMv2 is the default).
+pref("network.auth.force-generic-ntlm-v1", false);
+
+// This list controls which URIs can use the negotiate-auth protocol. This
+// list should be limited to the servers you know you'll need to login to.
+pref("network.negotiate-auth.trusted-uris", "");
+// This list controls which URIs can support delegation.
+pref("network.negotiate-auth.delegation-uris", "");
+
+// Do not allow SPNEGO by default when challenged by a local server.
+pref("network.negotiate-auth.allow-non-fqdn", false);
+
+// Allow SPNEGO by default when challenged by a proxy server.
+pref("network.negotiate-auth.allow-proxies", true);
+
+// Path to a specific gssapi library
+pref("network.negotiate-auth.gsslib", "");
+
+// Specify if the gss lib comes standard with the OS
+pref("network.negotiate-auth.using-native-gsslib", true);
+
+#ifdef XP_WIN
+
+// Default to using the SSPI intead of GSSAPI on windows
+pref("network.auth.use-sspi", true);
+
+#endif
+
+// Controls which NTLM authentication implementation we default to. True forces
+// the use of our generic (internal) NTLM authentication implementation vs. any
+// native implementation provided by the os. This pref is for diagnosing issues
+// with native NTLM. (See bug 520607 for details.) Using generic NTLM authentication
+// can expose the user to reflection attack vulnerabilities. Do not change this
+// unless you know what you're doing!
+// This pref should be removed 6 months after the release of firefox 3.6.
+pref("network.auth.force-generic-ntlm", false);
+
+// The following prefs are used to enable automatic use of the operating
+// system's NTLM implementation to silently authenticate the user with their
+// Window's domain logon. The trusted-uris pref follows the format of the
+// trusted-uris pref for negotiate authentication.
+pref("network.automatic-ntlm-auth.allow-proxies", true);
+pref("network.automatic-ntlm-auth.allow-non-fqdn", false);
+pref("network.automatic-ntlm-auth.trusted-uris", "");
+
+// The string to return to the server as the 'workstation' that the
+// user is using. Bug 1046421 notes that the previous default, of the
+// system hostname, could be used for user fingerprinting.
+//
+// However, in some network environments where allowedWorkstations is in use
+// to provide a level of host-based access control, it must be set to a string
+// that is listed in allowedWorkstations for the user's account in their
+// AD Domain.
+pref("network.generic-ntlm-auth.workstation", "WORKSTATION");
+
+// Sub-resources HTTP-authentication:
+// 0 - don't allow sub-resources to open HTTP authentication credentials
+// dialogs
+// 1 - allow sub-resources to open HTTP authentication credentials dialogs,
+// but don't allow it for cross-origin sub-resources
+// 2 - allow the cross-origin authentication as well.
+pref("network.auth.subresource-http-auth-allow", 2);
+
+// This preference controls whether to allow sending default credentials (SSO) to
+// NTLM/Negotiate servers allowed in the "trusted uri" list when navigating them
+// in a Private Browsing window.
+// If set to false, Private Browsing windows will not use default credentials and ask
+// for credentials from the user explicitly.
+// If set to true, and a server URL conforms other conditions for sending default
+// credentials, those will be sent automatically in Private Browsing windows.
+//
+// This preference has no effect when the browser is set to "Never Remember History",
+// in that case default credentials will always be used.
+pref("network.auth.private-browsing-sso", false);
+
+pref("permissions.default.image", 1); // 1-Accept, 2-Deny, 3-dontAcceptForeign
+
+pref("network.proxy.type", 5);
+pref("network.proxy.ftp", "");
+pref("network.proxy.ftp_port", 0);
+pref("network.proxy.http", "");
+pref("network.proxy.http_port", 0);
+pref("network.proxy.ssl", "");
+pref("network.proxy.ssl_port", 0);
+pref("network.proxy.socks", "");
+pref("network.proxy.socks_port", 0);
+pref("network.proxy.socks_version", 5);
+pref("network.proxy.socks_remote_dns", false);
+pref("network.proxy.proxy_over_tls", true);
+pref("network.proxy.no_proxies_on", "localhost, 127.0.0.1");
+pref("network.proxy.failover_timeout", 1800); // 30 minutes
+pref("network.online", true); //online/offline
+pref("network.cookie.cookieBehavior", 0); // 0-Accept, 1-dontAcceptForeign, 2-dontAcceptAny, 3-limitForeign
+#ifdef ANDROID
+pref("network.cookie.cookieBehavior", 0); // Keep the old default of accepting all cookies
+#endif
+pref("network.cookie.thirdparty.sessionOnly", false);
+pref("network.cookie.leave-secure-alone", true);
+pref("network.cookie.lifetimePolicy", 0); // 0-accept, 1-dontUse 2-acceptForSession, 3-acceptForNDays
+pref("network.cookie.prefsMigrated", false);
+pref("network.cookie.lifetime.days", 90); // Ignored unless network.cookie.lifetimePolicy is 3.
+
+// The PAC file to load. Ignored unless network.proxy.type is 2.
+pref("network.proxy.autoconfig_url", "");
+// Strip off paths when sending URLs to PAC scripts
+pref("network.proxy.autoconfig_url.include_path", false);
+
+// If we cannot load the PAC file, then try again (doubling from interval_min
+// until we reach interval_max or the PAC file is successfully loaded).
+pref("network.proxy.autoconfig_retry_interval_min", 5); // 5 seconds
+pref("network.proxy.autoconfig_retry_interval_max", 300); // 5 minutes
+
+// Use the HSTS preload list by default
+pref("network.stricttransportsecurity.preloadlist", true);
+
+// Use JS mDNS as a fallback
+pref("network.mdns.use_js_fallback", false);
+
+pref("converter.html2txt.structs", true); // Output structured phrases (strong, em, code, sub, sup, b, i, u)
+pref("converter.html2txt.header_strategy", 1); // 0 = no indention; 1 = indention, increased with header level; 2 = numbering and slight indention
+// Whether we include ruby annotation in the text despite whether it
+// is requested. This was true because we didn't explicitly strip out
+// annotations. Set false by default to provide a better behavior, but
+// we want to be able to pref-off it if user doesn't like it.
+pref("converter.html2txt.always_include_ruby", false);
+
+pref("intl.accept_languages", "chrome://global/locale/intl.properties");
+pref("intl.menuitems.alwaysappendaccesskeys","chrome://global/locale/intl.properties");
+pref("intl.menuitems.insertseparatorbeforeaccesskeys","chrome://global/locale/intl.properties");
+pref("intl.charset.detector", "chrome://global/locale/intl.properties");
+pref("intl.charset.fallback.override", "");
+pref("intl.charset.fallback.tld", true);
+pref("intl.ellipsis", "chrome://global-platform/locale/intl.properties");
+pref("intl.locale.matchOS", false);
+// fallback charset list for Unicode conversion (converting from Unicode)
+// currently used for mail send only to handle symbol characters (e.g Euro, trademark, smartquotes)
+// for ISO-8859-1
+pref("intl.fallbackCharsetList.ISO-8859-1", "windows-1252");
+pref("font.language.group", "chrome://global/locale/intl.properties");
+
+// Android-specific pref to use key-events-only mode for IME-unaware webapps.
+#ifdef MOZ_WIDGET_ANDROID
+pref("intl.ime.hack.on_ime_unaware_apps.fire_key_events_for_composition", true);
+#else
+pref("intl.ime.hack.on_ime_unaware_apps.fire_key_events_for_composition", false);
+#endif
+
+// If you use legacy Chinese IME which puts an ideographic space to composition
+// string as placeholder, this pref might be useful. If this is true and when
+// web contents forcibly commits composition (e.g., moving focus), the
+// ideographic space will be ignored (i.e., commits with empty string).
+pref("intl.ime.remove_placeholder_character_at_commit", false);
+
+// these locales have right-to-left UI
+pref("intl.uidirection.ar", "rtl");
+pref("intl.uidirection.he", "rtl");
+pref("intl.uidirection.fa", "rtl");
+pref("intl.uidirection.ug", "rtl");
+pref("intl.uidirection.ur", "rtl");
+
+// use en-US hyphenation by default for content tagged with plain lang="en"
+pref("intl.hyphenation-alias.en", "en-us");
+// and for other subtags of en-*, if no specific patterns are available
+pref("intl.hyphenation-alias.en-*", "en-us");
+
+pref("intl.hyphenation-alias.af-*", "af");
+pref("intl.hyphenation-alias.bg-*", "bg");
+pref("intl.hyphenation-alias.ca-*", "ca");
+pref("intl.hyphenation-alias.cy-*", "cy");
+pref("intl.hyphenation-alias.da-*", "da");
+pref("intl.hyphenation-alias.eo-*", "eo");
+pref("intl.hyphenation-alias.es-*", "es");
+pref("intl.hyphenation-alias.et-*", "et");
+pref("intl.hyphenation-alias.fi-*", "fi");
+pref("intl.hyphenation-alias.fr-*", "fr");
+pref("intl.hyphenation-alias.gl-*", "gl");
+pref("intl.hyphenation-alias.hr-*", "hr");
+pref("intl.hyphenation-alias.hsb-*", "hsb");
+pref("intl.hyphenation-alias.hu-*", "hu");
+pref("intl.hyphenation-alias.ia-*", "ia");
+pref("intl.hyphenation-alias.is-*", "is");
+pref("intl.hyphenation-alias.it-*", "it");
+pref("intl.hyphenation-alias.kmr-*", "kmr");
+pref("intl.hyphenation-alias.la-*", "la");
+pref("intl.hyphenation-alias.lt-*", "lt");
+pref("intl.hyphenation-alias.mn-*", "mn");
+pref("intl.hyphenation-alias.nl-*", "nl");
+pref("intl.hyphenation-alias.pl-*", "pl");
+pref("intl.hyphenation-alias.pt-*", "pt");
+pref("intl.hyphenation-alias.ru-*", "ru");
+pref("intl.hyphenation-alias.sl-*", "sl");
+pref("intl.hyphenation-alias.sv-*", "sv");
+pref("intl.hyphenation-alias.tr-*", "tr");
+pref("intl.hyphenation-alias.uk-*", "uk");
+
+// use reformed (1996) German patterns by default unless specifically tagged as de-1901
+// (these prefs may soon be obsoleted by better BCP47-based tag matching, but for now...)
+pref("intl.hyphenation-alias.de", "de-1996");
+pref("intl.hyphenation-alias.de-*", "de-1996");
+pref("intl.hyphenation-alias.de-AT-1901", "de-1901");
+pref("intl.hyphenation-alias.de-DE-1901", "de-1901");
+pref("intl.hyphenation-alias.de-CH-*", "de-CH");
+
+// patterns from TeX are tagged as "sh" (Serbo-Croatian) macrolanguage;
+// alias "sr" (Serbian) and "bs" (Bosnian) to those patterns
+// (Croatian has its own separate patterns).
+pref("intl.hyphenation-alias.sr", "sh");
+pref("intl.hyphenation-alias.bs", "sh");
+pref("intl.hyphenation-alias.sh-*", "sh");
+pref("intl.hyphenation-alias.sr-*", "sh");
+pref("intl.hyphenation-alias.bs-*", "sh");
+
+// Norwegian has two forms, Bokmål and Nynorsk, with "no" as a macrolanguage encompassing both.
+// For "no", we'll alias to "nb" (Bokmål) as that is the more widely used written form.
+pref("intl.hyphenation-alias.no", "nb");
+pref("intl.hyphenation-alias.no-*", "nb");
+pref("intl.hyphenation-alias.nb-*", "nb");
+pref("intl.hyphenation-alias.nn-*", "nn");
+
+pref("font.name.serif.x-math", "Latin Modern Math");
+pref("font.name-list.serif.x-math", "Latin Modern Math, XITS Math, Cambria Math, Libertinus Math, DejaVu Math TeX Gyre, TeX Gyre Bonum Math, TeX Gyre Pagella Math, TeX Gyre Schola, TeX Gyre Termes Math, STIX Math, Asana Math, STIXGeneral, DejaVu Serif, DejaVu Sans, serif");
+pref("font.name.sans-serif.x-math", "sans-serif");
+pref("font.name.monospace.x-math", "monospace");
+
+// Some CJK fonts have bad underline offset, their CJK character glyphs are overlapped (or adjoined) to its underline.
+// These fonts are ignored the underline offset, instead of it, the underline is lowered to bottom of its em descent.
+pref("font.blacklist.underline_offset", "FangSong,Gulim,GulimChe,MingLiU,MingLiU-ExtB,MingLiU_HKSCS,MingLiU-HKSCS-ExtB,MS Gothic,MS Mincho,MS PGothic,MS PMincho,MS UI Gothic,PMingLiU,PMingLiU-ExtB,SimHei,SimSun,SimSun-ExtB,Hei,Kai,Apple LiGothic,Apple LiSung,Osaka");
+
+#ifdef MOZ_B2G
+// Whitelist of fonts that ship with B2G that do not include space lookups in
+// default features. This allows us to skip analyzing the GSUB/GPOS tables
+// unless features are explicitly enabled.
+// Use NSPR_LOG_MODULES=fontinit:5 to dump out details of space lookups
+pref("font.whitelist.skip_default_features_space_check", "Fira Sans,Fira Mono");
+#endif
+
+pref("images.dither", "auto");
+pref("security.directory", "");
+
+pref("signed.applets.codebase_principal_support", false);
+pref("security.checkloaduri", true);
+pref("security.xpconnect.plugin.unrestricted", true);
+// security-sensitive dialogs should delay button enabling. In milliseconds.
+pref("security.dialog_enable_delay", 1000);
+pref("security.notification_enable_delay", 500);
+
+pref("security.csp.enable", true);
+pref("security.csp.experimentalEnabled", false);
+pref("security.csp.enableStrictDynamic", true);
+
+// Default Content Security Policy to apply to signed contents.
+pref("security.signed_content.CSP.default", "script-src 'self'; style-src 'self'");
+
+// Mixed content blocking
+pref("security.mixed_content.block_active_content", false);
+pref("security.mixed_content.block_display_content", false);
+
+// Sub-resource integrity
+pref("security.sri.enable", true);
+
+// Block scripts with wrong MIME type such as image/ or video/.
+pref("security.block_script_with_wrong_mime", true);
+
+// Block images of wrong MIME for XCTO: nosniff.
+pref("security.xcto_nosniff_block_images", false);
+
+// OCSP must-staple
+pref("security.ssl.enable_ocsp_must_staple", true);
+
+// Insecure Form Field Warning
+pref("security.insecure_field_warning.contextual.enabled", false);
+
+// Disable pinning checks by default.
+pref("security.cert_pinning.enforcement_level", 0);
+// Do not process hpkp headers rooted by not built in roots by default.
+// This is to prevent accidental pinning from MITM devices and is used
+// for tests.
+pref("security.cert_pinning.process_headers_from_non_builtin_roots", false);
+
+// If set to true, allow view-source URIs to be opened from URIs that share
+// their protocol with the inner URI of the view-source URI
+pref("security.view-source.reachable-from-inner-protocol", false);
+
+// Services security settings
+pref("services.settings.server", "https://firefox.settings.services.mozilla.com/v1");
+
+// Blocklist preferences
+pref("extensions.blocklist.enabled", true);
+// OneCRL freshness checking depends on this value, so if you change it,
+// please also update security.onecrl.maximum_staleness_in_seconds.
+pref("extensions.blocklist.interval", 86400);
+// Required blocklist freshness for OneCRL OCSP bypass
+// (default is 1.25x extensions.blocklist.interval, or 30 hours)
+pref("security.onecrl.maximum_staleness_in_seconds", 108000);
+pref("extensions.blocklist.url", "https://blocklist.addons.mozilla.org/blocklist/3/%APP_ID%/%APP_VERSION%/%PRODUCT%/%BUILD_ID%/%BUILD_TARGET%/%LOCALE%/%CHANNEL%/%OS_VERSION%/%DISTRIBUTION%/%DISTRIBUTION_VERSION%/%PING_COUNT%/%TOTAL_PING_COUNT%/%DAYS_SINCE_LAST_PING%/");
+pref("extensions.blocklist.detailsURL", "https://www.mozilla.com/%LOCALE%/blocklist/");
+pref("extensions.blocklist.itemURL", "https://blocklist.addons.mozilla.org/%LOCALE%/%APP%/blocked/%blockID%");
+// Controls what level the blocklist switches from warning about items to forcibly
+// blocking them.
+pref("extensions.blocklist.level", 2);
+// Blocklist via settings server (Kinto)
+pref("services.blocklist.changes.path", "/buckets/monitor/collections/changes/records");
+pref("services.blocklist.bucket", "blocklists");
+pref("services.blocklist.onecrl.collection", "certificates");
+pref("services.blocklist.onecrl.checked", 0);
+pref("services.blocklist.addons.collection", "addons");
+pref("services.blocklist.addons.checked", 0);
+pref("services.blocklist.plugins.collection", "plugins");
+pref("services.blocklist.plugins.checked", 0);
+pref("services.blocklist.gfx.collection", "gfx");
+pref("services.blocklist.gfx.checked", 0);
+
+// Controls whether signing should be enforced on signature-capable blocklist
+// collections.
+pref("services.blocklist.signing.enforced", true);
+
+// Enable blocklists via the services settings mechanism
+pref("services.blocklist.update_enabled", true);
+
+// Enable certificate blocklist updates via services settings
+pref("security.onecrl.via.amo", false);
+
+
+// Modifier key prefs: default to Windows settings,
+// menu access key = alt, accelerator key = control.
+// Use 17 for Ctrl, 18 for Alt, 224 for Meta, 91 for Win, 0 for none. Mac settings in macprefs.js
+pref("ui.key.accelKey", 17);
+pref("ui.key.menuAccessKey", 18);
+pref("ui.key.generalAccessKey", -1);
+
+// If generalAccessKey is -1, use the following two prefs instead.
+// Use 0 for disabled, 1 for Shift, 2 for Ctrl, 4 for Alt, 8 for Meta, 16 for Win
+// (values can be combined, e.g. 5 for Alt+Shift)
+pref("ui.key.chromeAccess", 4);
+pref("ui.key.contentAccess", 5);
+
+pref("ui.key.menuAccessKeyFocuses", false); // overridden below
+pref("ui.key.saveLink.shift", true); // true = shift, false = meta
+
+// Disable page loading activity cursor by default.
+pref("ui.use_activity_cursor", false);
+
+// Middle-mouse handling
+pref("middlemouse.paste", false);
+pref("middlemouse.openNewWindow", true);
+pref("middlemouse.contentLoadURL", false);
+pref("middlemouse.scrollbarPosition", false);
+
+// Clipboard behavior
+pref("clipboard.autocopy", false);
+
+// Clipboard only supports text/plain
+pref("clipboard.plainTextOnly", false);
+
+#ifdef XP_WIN
+// Setting false you can disable 4th button and/or 5th button of your mouse.
+// 4th button is typically mapped to "Back" and 5th button is typically mapped
+// to "Forward" button.
+pref("mousebutton.4th.enabled", true);
+pref("mousebutton.5th.enabled", true);
+#endif
+
+// mouse wheel scroll transaction period of time (in milliseconds)
+pref("mousewheel.transaction.timeout", 1500);
+// mouse wheel scroll transaction is held even if the mouse cursor is moved.
+pref("mousewheel.transaction.ignoremovedelay", 100);
+
+// prefs for app level mouse wheel scrolling acceleration.
+// number of mousewheel clicks when acceleration starts
+// acceleration can be turned off if pref is set to -1
+pref("mousewheel.acceleration.start", -1);
+// factor to be multiplied for constant acceleration
+pref("mousewheel.acceleration.factor", 10);
+
+// Prefs for override the system mouse wheel scrolling speed on
+// content of the web pages. When
+// "mousewheel.system_scroll_override_on_root_content.enabled" is true and the system
+// scrolling speed isn't customized by the user, the content scrolling
+// speed is multiplied by the following factors. The value will be used as
+// 1/100. E.g., 200 means 2.00.
+// NOTE: Even if "mousewheel.system_scroll_override_on_root_content.enabled" is
+// true, when Gecko detects the user customized the system scrolling speed
+// settings, the override isn't executed.
+pref("mousewheel.system_scroll_override_on_root_content.vertical.factor", 200);
+pref("mousewheel.system_scroll_override_on_root_content.horizontal.factor", 200);
+
+// mousewheel.*.action can specify the action when you use mosue wheel.
+// When no modifier keys are pressed or two or more modifires are pressed,
+// .default is used.
+// 0: Nothing happens
+// 1: Scrolling contents
+// 2: Go back or go forward, in your history
+// 3: Zoom in or out.
+pref("mousewheel.default.action", 1);
+pref("mousewheel.with_alt.action", 2);
+pref("mousewheel.with_control.action", 3);
+pref("mousewheel.with_meta.action", 1); // command key on Mac
+pref("mousewheel.with_shift.action", 1);
+pref("mousewheel.with_win.action", 1);
+
+// mousewheel.*.action.override_x will override the action
+// when the mouse wheel is rotated along the x direction.
+// -1: Don't override the action.
+// 0 to 3: Override the action with the specified value.
+pref("mousewheel.default.action.override_x", -1);
+pref("mousewheel.with_alt.action.override_x", -1);
+pref("mousewheel.with_control.action.override_x", -1);
+pref("mousewheel.with_meta.action.override_x", -1); // command key on Mac
+pref("mousewheel.with_shift.action.override_x", -1);
+pref("mousewheel.with_win.action.override_x", -1);
+
+// mousewheel.*.delta_multiplier_* can specify the value muliplied by the delta
+// value. The values will be used after divided by 100. I.e., 100 means 1.0,
+// -100 means -1.0. If the values were negative, the direction would be
+// reverted. The absolue value must be 100 or larger.
+pref("mousewheel.default.delta_multiplier_x", 100);
+pref("mousewheel.default.delta_multiplier_y", 100);
+pref("mousewheel.default.delta_multiplier_z", 100);
+pref("mousewheel.with_alt.delta_multiplier_x", 100);
+pref("mousewheel.with_alt.delta_multiplier_y", 100);
+pref("mousewheel.with_alt.delta_multiplier_z", 100);
+pref("mousewheel.with_control.delta_multiplier_x", 100);
+pref("mousewheel.with_control.delta_multiplier_y", 100);
+pref("mousewheel.with_control.delta_multiplier_z", 100);
+pref("mousewheel.with_meta.delta_multiplier_x", 100); // command key on Mac
+pref("mousewheel.with_meta.delta_multiplier_y", 100); // command key on Mac
+pref("mousewheel.with_meta.delta_multiplier_z", 100); // command key on Mac
+pref("mousewheel.with_shift.delta_multiplier_x", 100);
+pref("mousewheel.with_shift.delta_multiplier_y", 100);
+pref("mousewheel.with_shift.delta_multiplier_z", 100);
+pref("mousewheel.with_win.delta_multiplier_x", 100);
+pref("mousewheel.with_win.delta_multiplier_y", 100);
+pref("mousewheel.with_win.delta_multiplier_z", 100);
+
+// If line-height is lower than this value (in device pixels), 1 line scroll
+// scrolls this height.
+pref("mousewheel.min_line_scroll_amount", 5);
+
+// These define the smooth scroll behavior (min ms, max ms) for different triggers
+// Some triggers:
+// mouseWheel: Discrete mouse wheel events, Synaptics touchpads on windows (generate wheel events)
+// Lines: Up/Down/Left/Right KB arrows
+// Pages: Page up/down, Space
+// Scrollbars: Clicking scrollbars arrows, clicking scrollbars tracks
+// Note: Currently OS X trackpad and magic mouse don't use our smooth scrolling
+// Note: These are relevant only when "general.smoothScroll" is enabled
+pref("general.smoothScroll.mouseWheel.durationMinMS", 200);
+pref("general.smoothScroll.mouseWheel.durationMaxMS", 400);
+pref("general.smoothScroll.pixels.durationMinMS", 150);
+pref("general.smoothScroll.pixels.durationMaxMS", 150);
+pref("general.smoothScroll.lines.durationMinMS", 150);
+pref("general.smoothScroll.lines.durationMaxMS", 150);
+pref("general.smoothScroll.pages.durationMinMS", 150);
+pref("general.smoothScroll.pages.durationMaxMS", 150);
+pref("general.smoothScroll.scrollbars.durationMinMS", 150);
+pref("general.smoothScroll.scrollbars.durationMaxMS", 150);
+pref("general.smoothScroll.other.durationMinMS", 150);
+pref("general.smoothScroll.other.durationMaxMS", 150);
+// Enable disable smooth scrolling for different triggers (when "general.smoothScroll" is enabled)
+pref("general.smoothScroll.mouseWheel", true);
+pref("general.smoothScroll.pixels", true);
+pref("general.smoothScroll.lines", true);
+pref("general.smoothScroll.pages", true);
+pref("general.smoothScroll.scrollbars", true);
+pref("general.smoothScroll.other", true);
+// To connect consecutive scroll events into a continuous flow, the animation's duration
+// should be longer than scroll events intervals (or else the scroll will stop
+// before the next event arrives - we're guessing next interval by averaging recent
+// intervals).
+// This defines how longer is the duration compared to events interval (percentage)
+pref("general.smoothScroll.durationToIntervalRatio", 200);
+// These two prefs determine the timing function.
+pref("general.smoothScroll.currentVelocityWeighting", "0.25");
+pref("general.smoothScroll.stopDecelerationWeighting", "0.4");
+
+pref("profile.confirm_automigration",true);
+// profile.migration_behavior determines how the profiles root is set
+// 0 - use NS_APP_USER_PROFILES_ROOT_DIR
+// 1 - create one based on the NS4.x profile root
+// 2 - use, if not empty, profile.migration_directory otherwise same as 0
+pref("profile.migration_behavior",0);
+pref("profile.migration_directory", "");
+
+// the amount of time (in seconds) that must elapse
+// before we think your mozilla profile is defunct
+// and you'd benefit from re-migrating from 4.x
+// see bug #137886 for more details
+//
+// if -1, we never think your profile is defunct
+// and users will never see the remigrate UI.
+pref("profile.seconds_until_defunct", -1);
+// We can show it anytime from menus
+pref("profile.manage_only_at_launch", false);
+
+pref("prefs.converted-to-utf8",false);
+
+// ------------------
+// Text Direction
+// ------------------
+// 1 = directionLTRBidi *
+// 2 = directionRTLBidi
+pref("bidi.direction", 1);
+// ------------------
+// Text Type
+// ------------------
+// 1 = charsettexttypeBidi *
+// 2 = logicaltexttypeBidi
+// 3 = visualtexttypeBidi
+pref("bidi.texttype", 1);
+// ------------------
+// Numeral Style
+// ------------------
+// 0 = nominalnumeralBidi *
+// 1 = regularcontextnumeralBidi
+// 2 = hindicontextnumeralBidi
+// 3 = arabicnumeralBidi
+// 4 = hindinumeralBidi
+// 5 = persiancontextnumeralBidi
+// 6 = persiannumeralBidi
+pref("bidi.numeral", 0);
+// Whether delete and backspace should immediately delete characters not
+// visually adjacent to the caret, or adjust the visual position of the caret
+// on the first keypress and delete the character on a second keypress
+pref("bidi.edit.delete_immediately", true);
+
+// Bidi caret movement style:
+// 0 = logical
+// 1 = visual
+// 2 = visual, but logical during selection
+pref("bidi.edit.caret_movement_style", 2);
+
+// Setting this pref to |true| forces Bidi UI menu items and keyboard shortcuts
+// to be exposed, and enables the directional caret hook. By default, only
+// expose it for bidi-associated system locales.
+pref("bidi.browser.ui", false);
+
+// used for double-click word selection behavior. Win will override.
+pref("layout.word_select.eat_space_to_next_word", false);
+pref("layout.word_select.stop_at_punctuation", true);
+
+// controls caret style and word-delete during text selection
+// 0 = use platform default
+// 1 = caret moves and blinks as when there is no selection; word
+// delete deselects the selection and then deletes word
+// 2 = caret moves to selection edge and is not visible during selection;
+// word delete deletes the selection (Mac and Linux default)
+// 3 = caret moves and blinks as when there is no selection; word delete
+// deletes the selection
+// Windows default is 1 for word delete behavior, the rest as for 2.
+pref("layout.selection.caret_style", 0);
+
+// pref to report CSS errors to the error console
+pref("layout.css.report_errors", true);
+
+// Should the :visited selector ever match (otherwise :link matches instead)?
+pref("layout.css.visited_links_enabled", true);
+
+// Override DPI. A value of -1 means use the maximum of 96 and the system DPI.
+// A value of 0 means use the system DPI. A positive value is used as the DPI.
+// This sets the physical size of a device pixel and thus controls the
+// interpretation of physical units such as "pt".
+pref("layout.css.dpi", -1);
+
+// Set the number of device pixels per CSS pixel. A value <= 0 means choose
+// automatically based on user settings for the platform (e.g., "UI scale factor"
+// on Mac). A positive value is used as-is. This effectively controls the size
+// of a CSS "px". This is only used for windows on the screen, not for printing.
+pref("layout.css.devPixelsPerPx", "-1.0");
+
+// Is support for CSS initial-letter property enabled?
+pref("layout.css.initial-letter.enabled", false);
+
+// Is support for mix-blend-mode enabled?
+pref("layout.css.mix-blend-mode.enabled", true);
+
+// Is support for isolation enabled?
+pref("layout.css.isolation.enabled", true);
+
+// Is support for CSS Filters enabled?
+pref("layout.css.filters.enabled", true);
+
+// Set the threshold distance in CSS pixels below which scrolling will snap to
+// an edge, when scroll snapping is set to "proximity".
+pref("layout.css.scroll-snap.proximity-threshold", 200);
+
+// When selecting the snap point for CSS scroll snapping, the velocity of the
+// scroll frame is clamped to this speed, in CSS pixels / s.
+pref("layout.css.scroll-snap.prediction-max-velocity", 2000);
+
+// When selecting the snap point for CSS scroll snapping, the velocity of the
+// scroll frame is integrated over this duration, in seconds. The snap point
+// best suited for this position is selected, enabling the user to perform fling
+// gestures.
+pref("layout.css.scroll-snap.prediction-sensitivity", "0.750");
+
+// Is support for basic shapes in clip-path enabled?
+pref("layout.css.clip-path-shapes.enabled", false);
+
+// Is support for DOMPoint enabled?
+pref("layout.css.DOMPoint.enabled", true);
+
+// Is support for DOMQuad enabled?
+pref("layout.css.DOMQuad.enabled", true);
+
+// Is support for DOMMatrix enabled?
+pref("layout.css.DOMMatrix.enabled", true);
+
+// Is support for GeometryUtils.getBoxQuads enabled?
+#ifdef RELEASE_OR_BETA
+pref("layout.css.getBoxQuads.enabled", false);
+#else
+pref("layout.css.getBoxQuads.enabled", true);
+#endif
+
+// Is support for GeometryUtils.convert*FromNode enabled?
+#ifdef RELEASE_OR_BETA
+pref("layout.css.convertFromNode.enabled", false);
+#else
+pref("layout.css.convertFromNode.enabled", true);
+#endif
+
+// Is support for CSS "text-align: unsafe X" enabled?
+pref("layout.css.text-align-unsafe-value.enabled", false);
+
+// Is support for CSS "float: inline-{start,end}" and
+// "clear: inline-{start,end}" enabled?
+#if defined(MOZ_B2G) || !defined(RELEASE_OR_BETA)
+pref("layout.css.float-logical-values.enabled", true);
+#else
+pref("layout.css.float-logical-values.enabled", false);
+#endif
+
+// Is support for the CSS4 image-orientation property enabled?
+pref("layout.css.image-orientation.enabled", true);
+
+// Is support for the font-display @font-face descriptor enabled?
+pref("layout.css.font-display.enabled", false);
+
+// Are sets of prefixed properties supported?
+pref("layout.css.prefixes.border-image", true);
+pref("layout.css.prefixes.transforms", true);
+pref("layout.css.prefixes.transitions", true);
+pref("layout.css.prefixes.animations", true);
+pref("layout.css.prefixes.box-sizing", true);
+pref("layout.css.prefixes.font-features", true);
+pref("layout.css.prefixes.gradients", true);
+
+// Are webkit-prefixed properties & property-values supported?
+pref("layout.css.prefixes.webkit", true);
+
+// Are "-webkit-{min|max}-device-pixel-ratio" media queries supported?
+// (Note: this pref has no effect if the master 'layout.css.prefixes.webkit'
+// pref is set to false.)
+pref("layout.css.prefixes.device-pixel-ratio-webkit", false);
+
+// Is the CSS Unprefixing Service enabled? (This service emulates support
+// for certain vendor-prefixed properties & values, for sites on a "fixlist".)
+pref("layout.css.unprefixing-service.enabled", true);
+#ifdef NIGHTLY_BUILD
+// Is the CSS Unprefixing Service whitelisted for all domains?
+// (This pref is only honored in Nightly builds and can be removed when
+// Bug 1177263 is fixed.)
+pref("layout.css.unprefixing-service.globally-whitelisted", false);
+#endif
+
+// Is support for the :scope selector enabled?
+pref("layout.css.scope-pseudo.enabled", true);
+
+// Is support for background-blend-mode enabled?
+pref("layout.css.background-blend-mode.enabled", true);
+
+// Is support for background-clip:text enabled?
+pref("layout.css.background-clip-text.enabled", true);
+
+// Is support for CSS text-combine-upright (tate-chu-yoko) enabled?
+pref("layout.css.text-combine-upright.enabled", true);
+// Is support for CSS text-combine-upright: digits 2-4 enabled?
+pref("layout.css.text-combine-upright-digits.enabled", false);
+
+// Is support for object-fit and object-position enabled?
+pref("layout.css.object-fit-and-position.enabled", true);
+
+// Is -moz-osx-font-smoothing enabled?
+// Only supported in OSX builds
+#ifdef XP_MACOSX
+pref("layout.css.osx-font-smoothing.enabled", true);
+#else
+pref("layout.css.osx-font-smoothing.enabled", false);
+#endif
+
+// Is support for the CSS-wide "unset" value enabled?
+pref("layout.css.unset-value.enabled", true);
+
+// Is support for the "all" shorthand enabled?
+pref("layout.css.all-shorthand.enabled", true);
+
+// Is support for CSS variables enabled?
+pref("layout.css.variables.enabled", true);
+
+// Is support for CSS overflow-clip-box enabled for non-UA sheets?
+pref("layout.css.overflow-clip-box.enabled", false);
+
+// Is support for CSS grid enabled?
+pref("layout.css.grid.enabled", true);
+
+// Is support for CSS "grid-template-{columns,rows}: subgrid X" enabled?
+pref("layout.css.grid-template-subgrid-value.enabled", false);
+
+// Is support for CSS contain enabled?
+pref("layout.css.contain.enabled", false);
+
+// Is support for CSS display:contents enabled?
+pref("layout.css.display-contents.enabled", true);
+
+// Is support for CSS box-decoration-break enabled?
+pref("layout.css.box-decoration-break.enabled", true);
+
+// Is layout of CSS outline-style:auto enabled?
+pref("layout.css.outline-style-auto.enabled", false);
+
+// Is CSSOM-View scroll-behavior and its MSD smooth scrolling enabled?
+pref("layout.css.scroll-behavior.enabled", true);
+
+// Is the CSSOM-View scroll-behavior CSS property enabled?
+pref("layout.css.scroll-behavior.property-enabled", true);
+
+// Tuning of the smooth scroll motion used by CSSOM-View scroll-behavior.
+// Spring-constant controls the strength of the simulated MSD
+// (Mass-Spring-Damper)
+pref("layout.css.scroll-behavior.spring-constant", "250.0");
+
+// Tuning of the smooth scroll motion used by CSSOM-View scroll-behavior.
+// Damping-ratio controls the dampening force of the simulated MSD
+// (Mass-Spring-Damper).
+// When below 1.0, the system is under-damped; it may overshoot the target and
+// oscillate.
+// When greater than 1.0, the system is over-damped; it will reach the target at
+// reduced speed without overshooting.
+// When equal to 1.0, the system is critically-damped; it will reach the target
+// at the greatest speed without overshooting.
+pref("layout.css.scroll-behavior.damping-ratio", "1.0");
+
+// Is support for scroll-snap enabled?
+pref("layout.css.scroll-snap.enabled", true);
+
+// Is support for CSS shape-outside enabled?
+pref("layout.css.shape-outside.enabled", false);
+
+// Is support for document.fonts enabled?
+pref("layout.css.font-loading-api.enabled", true);
+
+// Should stray control characters be rendered visibly?
+#ifdef RELEASE_OR_BETA
+pref("layout.css.control-characters.visible", false);
+#else
+pref("layout.css.control-characters.visible", true);
+#endif
+
+// pref for which side vertical scrollbars should be on
+// 0 = end-side in UI direction
+// 1 = end-side in document/content direction
+// 2 = right
+// 3 = left
+pref("layout.scrollbar.side", 0);
+
+// pref to stop overlay scrollbars from fading out, for testing purposes
+pref("layout.testing.overlay-scrollbars.always-visible", false);
+
+// Enable/disable interruptible reflow, which allows reflows to stop
+// before completion (and display the partial results) when user events
+// are pending.
+pref("layout.interruptible-reflow.enabled", true);
+
+// pref to control browser frame rate, in Hz. A value <= 0 means choose
+// automatically based on knowledge of the platform (or 60Hz if no platform-
+// specific information is available).
+pref("layout.frame_rate", -1);
+
+// pref to dump the display list to the log. Useful for debugging drawing.
+pref("layout.display-list.dump", false);
+pref("layout.display-list.dump-content", false);
+
+// pref to control precision of the frame rate timer. When true,
+// we use a "precise" timer, which means each notification fires
+// Nms after the start of the last notification. That means if the
+// processing of the notification is slow, the timer can fire immediately
+// after we've just finished processing the last notification, which might
+// lead to starvation problems.
+// When false, we use a "slack" timer which fires Nms after the *end*
+// of the last notification. This can give less tight frame rates
+// but provides more time for other operations when the browser is
+// heavily loaded.
+pref("layout.frame_rate.precise", false);
+
+// pref to control whether layout warnings that are hit quite often are enabled
+pref("layout.spammy_warnings.enabled", false);
+
+// Should we fragment floats inside CSS column layout?
+pref("layout.float-fragments-inside-column.enabled", true);
+
+// The number of frames times the frame rate is the time required to
+// pass without painting used to guess that we'll not paint again soon
+pref("layout.idle_period.required_quiescent_frames", 2);
+
+// The amount of time (milliseconds) needed between an idle period's
+// end and the start of the next tick to avoid jank.
+pref("layout.idle_period.time_limit", 1);
+
+// Is support for the Web Animations API enabled?
+// Before enabling this by default, make sure also CSSPseudoElement interface
+// has been spec'ed properly, or we should add a separate pref for
+// CSSPseudoElement interface. See Bug 1174575 for further details.
+#ifdef RELEASE_OR_BETA
+pref("dom.animations-api.core.enabled", false);
+#else
+pref("dom.animations-api.core.enabled", true);
+#endif
+
+// Is support for the Element.animate() function (a subset of the Web Animations
+// API) enabled?
+// Note that if dom.animations-api.core.enabled is true, this preference is
+// ignored.
+pref("dom.animations-api.element-animate.enabled", true);
+
+// Pref to throttle offsreen animations
+pref("dom.animations.offscreen-throttling", true);
+
+// pref to permit users to make verified SOAP calls by default
+pref("capability.policy.default.SOAPCall.invokeVerifySourceHeader", "allAccess");
+
+// if true, allow plug-ins to override internal imglib decoder mime types in full-page mode
+pref("plugin.override_internal_types", false);
+
+// See bug 136985. Gives embedders a pref to hook into to show
+// a popup blocker if they choose.
+pref("browser.popups.showPopupBlocker", true);
+
+// Pref to control whether the viewmanager code does double-buffering or not
+// See http://bugzilla.mozilla.org/show_bug.cgi?id=169483 for further details...
+pref("viewmanager.do_doublebuffering", true);
+
+// enable single finger gesture input (win7+ tablets)
+pref("gestures.enable_single_finger_input", true);
+
+pref("editor.resizing.preserve_ratio", true);
+pref("editor.positioning.offset", 0);
+
+pref("dom.use_watchdog", true);
+pref("dom.max_chrome_script_run_time", 20);
+pref("dom.max_script_run_time", 10);
+
+// Stop all scripts in a compartment when the "stop script" dialog is used.
+pref("dom.global_stop_script", true);
+
+// If true, ArchiveReader will be enabled
+pref("dom.archivereader.enabled", false);
+
+// Time (milliseconds) between throttled idle callbacks.
+pref("dom.idle_period.throttled_length", 10000);
+
+// The amount of idle time (milliseconds) reserved for a long idle period
+pref("idle_queue.long_period", 50);
+
+// The minimum amount of time (milliseconds) required for an idle
+// period to be scheduled on the main thread. N.B. that
+// layout.idle_period.time_limit adds padding at the end of the idle
+// period, which makes the point in time that we expect to become busy
+// again be:
+// now + idle_queue.min_period + layout.idle_period.time_limit
+pref("idle_queue.min_period", 3);
+
+// Hang monitor timeout after which we kill the browser, in seconds
+// (0 is disabled)
+// Disabled on all platforms per bug 705748 until the found issues are
+// resolved.
+pref("hangmonitor.timeout", 0);
+
+pref("plugins.load_appdir_plugins", false);
+// If true, plugins will be click to play
+pref("plugins.click_to_play", false);
+#ifdef NIGHTLY_BUILD
+// This only supports one hidden ctp plugin, edit nsPluginArray.cpp if adding a second
+pref("plugins.navigator.hidden_ctp_plugin", "Shockwave Flash");
+#endif
+// The default value for nsIPluginTag.enabledState (STATE_ENABLED = 2)
+pref("plugin.default.state", 2);
+
+// The MIME type that should bind to legacy java-specific invocations like
+// <applet> and <object data="java:foo">. Setting this to a non-java MIME type
+// is undefined behavior.
+pref("plugin.java.mime", "application/x-java-vm");
+
+// How long in minutes we will allow a plugin to work after the user has chosen
+// to allow it "now"
+pref("plugin.sessionPermissionNow.intervalInMinutes", 60);
+// How long in days we will allow a plugin to work after the user has chosen
+// to allow it persistently.
+pref("plugin.persistentPermissionAlways.intervalInDays", 90);
+
+// This pref can take 3 possible string values:
+// "always" - always use favor fallback mode
+// "follow-ctp" - activate if ctp is active for the given
+// plugin object (could be due to a plugin-wide
+// setting or a site-specific setting)
+// "never" - never use favor fallback mode
+pref("plugins.favorfallback.mode", "never");
+
+// A comma-separated list of rules to follow when deciding
+// whether an object has been provided with good fallback content.
+// The valid values can be found at nsObjectLoadingContent::HasGoodFallback.
+pref("plugins.favorfallback.rules", "");
+
+
+// Set IPC timeouts for plugins and tabs, except in leak-checking and
+// dynamic analysis builds. (NS_FREE_PERMANENT_DATA is C++ only, so
+// approximate its definition here.)
+#if !defined(DEBUG) && !defined(MOZ_ASAN) && !defined(MOZ_VALGRIND) && !defined(MOZ_TSAN)
+// How long a plugin is allowed to process a synchronous IPC message
+// before we consider it "hung".
+pref("dom.ipc.plugins.timeoutSecs", 45);
+// How long a plugin process will wait for a response from the parent
+// to a synchronous request before terminating itself. After this
+// point the child assumes the parent is hung. Currently disabled.
+pref("dom.ipc.plugins.parentTimeoutSecs", 0);
+// How long a plugin in e10s is allowed to process a synchronous IPC
+// message before we notify the chrome process of a hang.
+pref("dom.ipc.plugins.contentTimeoutSecs", 10);
+// How long a plugin launch is allowed to take before
+// we consider it failed.
+pref("dom.ipc.plugins.processLaunchTimeoutSecs", 45);
+#ifdef XP_WIN
+// How long a plugin is allowed to process a synchronous IPC message
+// before we display the plugin hang UI
+pref("dom.ipc.plugins.hangUITimeoutSecs", 11);
+// Minimum time that the plugin hang UI will be displayed
+pref("dom.ipc.plugins.hangUIMinDisplaySecs", 10);
+#endif
+// How long a content process can take before closing its IPC channel
+// after shutdown is initiated. If the process exceeds the timeout,
+// we fear the worst and kill it.
+pref("dom.ipc.tabs.shutdownTimeoutSecs", 5);
+#else
+// No timeout in leak-checking builds
+pref("dom.ipc.plugins.timeoutSecs", 0);
+pref("dom.ipc.plugins.contentTimeoutSecs", 0);
+pref("dom.ipc.plugins.processLaunchTimeoutSecs", 0);
+pref("dom.ipc.plugins.parentTimeoutSecs", 0);
+#ifdef XP_WIN
+pref("dom.ipc.plugins.hangUITimeoutSecs", 0);
+pref("dom.ipc.plugins.hangUIMinDisplaySecs", 0);
+#endif
+pref("dom.ipc.tabs.shutdownTimeoutSecs", 0);
+#endif
+
+pref("dom.ipc.plugins.flash.disable-protected-mode", false);
+
+pref("dom.ipc.plugins.flash.subprocess.crashreporter.enabled", true);
+pref("dom.ipc.plugins.reportCrashURL", true);
+
+// How long we wait before unloading an idle plugin process.
+// Defaults to 30 seconds.
+pref("dom.ipc.plugins.unloadTimeoutSecs", 30);
+
+// Asynchronous plugin initialization is on hold.
+pref("dom.ipc.plugins.asyncInit.enabled", false);
+
+#ifdef RELEASE_OR_BETA
+pref("dom.ipc.plugins.asyncdrawing.enabled", false);
+#else
+// Allow the AsyncDrawing mode to be used for plugins in dev channels.
+pref("dom.ipc.plugins.asyncdrawing.enabled", true);
+#endif
+
+pref("dom.ipc.processCount", 1);
+
+// Enable caching of Moz2D Path objects for SVG geometry elements
+pref("svg.path-caching.enabled", true);
+
+// Enable the use of display-lists for SVG hit-testing and painting.
+pref("svg.display-lists.hit-testing.enabled", true);
+pref("svg.display-lists.painting.enabled", true);
+
+// Is support for the SVG 2 paint-order property enabled?
+pref("svg.paint-order.enabled", true);
+
+// Is support for the <marker orient="auto-start-reverse"> feature enabled?
+pref("svg.marker-improvements.enabled", true);
+
+// Is support for the new getBBox method from SVG 2 enabled?
+// See https://svgwg.org/svg2-draft/single-page.html#types-SVGBoundingBoxOptions
+pref("svg.new-getBBox.enabled", false);
+
+#ifdef RELEASE_OR_BETA
+pref("svg.transform-box.enabled", false);
+#else
+pref("svg.transform-box.enabled", true);
+#endif // RELEASE_OR_BETA
+
+// Default font types and sizes by locale
+pref("font.default.ar", "sans-serif");
+pref("font.minimum-size.ar", 0);
+pref("font.size.variable.ar", 16);
+pref("font.size.fixed.ar", 13);
+
+pref("font.default.el", "serif");
+pref("font.minimum-size.el", 0);
+pref("font.size.variable.el", 16);
+pref("font.size.fixed.el", 13);
+
+pref("font.default.he", "sans-serif");
+pref("font.minimum-size.he", 0);
+pref("font.size.variable.he", 16);
+pref("font.size.fixed.he", 13);
+
+pref("font.default.ja", "sans-serif");
+pref("font.minimum-size.ja", 0);
+pref("font.size.variable.ja", 16);
+pref("font.size.fixed.ja", 16);
+
+pref("font.default.ko", "sans-serif");
+pref("font.minimum-size.ko", 0);
+pref("font.size.variable.ko", 16);
+pref("font.size.fixed.ko", 16);
+
+pref("font.default.th", "sans-serif");
+pref("font.minimum-size.th", 0);
+pref("font.size.variable.th", 16);
+pref("font.size.fixed.th", 13);
+
+pref("font.default.x-cyrillic", "serif");
+pref("font.minimum-size.x-cyrillic", 0);
+pref("font.size.variable.x-cyrillic", 16);
+pref("font.size.fixed.x-cyrillic", 13);
+
+pref("font.default.x-devanagari", "serif");
+pref("font.minimum-size.x-devanagari", 0);
+pref("font.size.variable.x-devanagari", 16);
+pref("font.size.fixed.x-devanagari", 13);
+
+pref("font.default.x-tamil", "serif");
+pref("font.minimum-size.x-tamil", 0);
+pref("font.size.variable.x-tamil", 16);
+pref("font.size.fixed.x-tamil", 13);
+
+pref("font.default.x-armn", "serif");
+pref("font.minimum-size.x-armn", 0);
+pref("font.size.variable.x-armn", 16);
+pref("font.size.fixed.x-armn", 13);
+
+pref("font.default.x-beng", "serif");
+pref("font.minimum-size.x-beng", 0);
+pref("font.size.variable.x-beng", 16);
+pref("font.size.fixed.x-beng", 13);
+
+pref("font.default.x-cans", "serif");
+pref("font.minimum-size.x-cans", 0);
+pref("font.size.variable.x-cans", 16);
+pref("font.size.fixed.x-cans", 13);
+
+pref("font.default.x-ethi", "serif");
+pref("font.minimum-size.x-ethi", 0);
+pref("font.size.variable.x-ethi", 16);
+pref("font.size.fixed.x-ethi", 13);
+
+pref("font.default.x-geor", "serif");
+pref("font.minimum-size.x-geor", 0);
+pref("font.size.variable.x-geor", 16);
+pref("font.size.fixed.x-geor", 13);
+
+pref("font.default.x-gujr", "serif");
+pref("font.minimum-size.x-gujr", 0);
+pref("font.size.variable.x-gujr", 16);
+pref("font.size.fixed.x-gujr", 13);
+
+pref("font.default.x-guru", "serif");
+pref("font.minimum-size.x-guru", 0);
+pref("font.size.variable.x-guru", 16);
+pref("font.size.fixed.x-guru", 13);
+
+pref("font.default.x-khmr", "serif");
+pref("font.minimum-size.x-khmr", 0);
+pref("font.size.variable.x-khmr", 16);
+pref("font.size.fixed.x-khmr", 13);
+
+pref("font.default.x-mlym", "serif");
+pref("font.minimum-size.x-mlym", 0);
+pref("font.size.variable.x-mlym", 16);
+pref("font.size.fixed.x-mlym", 13);
+
+pref("font.default.x-orya", "serif");
+pref("font.minimum-size.x-orya", 0);
+pref("font.size.variable.x-orya", 16);
+pref("font.size.fixed.x-orya", 13);
+
+pref("font.default.x-telu", "serif");
+pref("font.minimum-size.x-telu", 0);
+pref("font.size.variable.x-telu", 16);
+pref("font.size.fixed.x-telu", 13);
+
+pref("font.default.x-knda", "serif");
+pref("font.minimum-size.x-knda", 0);
+pref("font.size.variable.x-knda", 16);
+pref("font.size.fixed.x-knda", 13);
+
+pref("font.default.x-sinh", "serif");
+pref("font.minimum-size.x-sinh", 0);
+pref("font.size.variable.x-sinh", 16);
+pref("font.size.fixed.x-sinh", 13);
+
+pref("font.default.x-tibt", "serif");
+pref("font.minimum-size.x-tibt", 0);
+pref("font.size.variable.x-tibt", 16);
+pref("font.size.fixed.x-tibt", 13);
+
+pref("font.default.x-unicode", "serif");
+pref("font.minimum-size.x-unicode", 0);
+pref("font.size.variable.x-unicode", 16);
+pref("font.size.fixed.x-unicode", 13);
+
+pref("font.default.x-western", "serif");
+pref("font.minimum-size.x-western", 0);
+pref("font.size.variable.x-western", 16);
+pref("font.size.fixed.x-western", 13);
+
+pref("font.default.zh-CN", "sans-serif");
+pref("font.minimum-size.zh-CN", 0);
+pref("font.size.variable.zh-CN", 16);
+pref("font.size.fixed.zh-CN", 16);
+
+pref("font.default.zh-HK", "sans-serif");
+pref("font.minimum-size.zh-HK", 0);
+pref("font.size.variable.zh-HK", 16);
+pref("font.size.fixed.zh-HK", 16);
+
+pref("font.default.zh-TW", "sans-serif");
+pref("font.minimum-size.zh-TW", 0);
+pref("font.size.variable.zh-TW", 16);
+pref("font.size.fixed.zh-TW", 16);
+
+// mathml.css sets font-size to "inherit" and font-family to "serif" so only
+// font.name.*.x-math and font.minimum-size.x-math are really relevant.
+pref("font.default.x-math", "serif");
+pref("font.minimum-size.x-math", 0);
+pref("font.size.variable.x-math", 16);
+pref("font.size.fixed.x-math", 13);
+
+/*
+ * A value greater than zero enables font size inflation for
+ * pan-and-zoom UIs, so that the fonts in a block are at least the size
+ * that, if a block's width is scaled to match the device's width, the
+ * fonts in the block are big enough that at most the pref value ems of
+ * text fit in *the width of the device*.
+ *
+ * When both this pref and the next are set, the larger inflation is
+ * used.
+ */
+pref("font.size.inflation.emPerLine", 0);
+/*
+ * A value greater than zero enables font size inflation for
+ * pan-and-zoom UIs, so that if a block's width is scaled to match the
+ * device's width, the fonts in a block are at least the font size
+ * given. The value given is in twips, i.e., 1/20 of a point, or 1/1440
+ * of an inch.
+ *
+ * When both this pref and the previous are set, the larger inflation is
+ * used.
+ */
+pref("font.size.inflation.minTwips", 0);
+/*
+ * In products with multi-mode pan-and-zoom and non-pan-and-zoom UIs,
+ * this pref forces font inflation to always be enabled in all modes.
+ * That is, any heuristics used to detect pan-and-zoom
+ * vs. non-pan-and-zoom modes are disabled and all content is treated
+ * as pan-and-zoom mode wrt font inflation.
+ *
+ * This pref has no effect if font inflation is not enabled through
+ * either of the prefs above. It has no meaning in single-mode UIs.
+ */
+pref("font.size.inflation.forceEnabled", false);
+/*
+ * In products with multi-mode pan-and-zoom and non-pan-and-zoom UIs,
+ * this pref disables font inflation in master-process contexts where
+ * existing heuristics can't be used determine enabled-ness.
+ *
+ * This pref has no effect if font inflation is not enabled through
+ * either of the prefs above. The "forceEnabled" pref above overrides
+ * this pref.
+ */
+pref("font.size.inflation.disabledInMasterProcess", false);
+/*
+ * Since the goal of font size inflation is to avoid having to
+ * repeatedly scroll side to side to read a block of text, and there are
+ * a number of page layouts where a relatively small chunk of text is
+ * better of not being inflated according to the same algorithm we use
+ * for larger chunks of text, we want a threshold for an amount of text
+ * that triggers font size inflation. This preference controls that
+ * threshold.
+ *
+ * It controls the threshold used within an *approximation* of the
+ * number of lines of text we use. In particular, if we assume that
+ * each character (collapsing collapsible whitespace) has a width the
+ * same as the em-size of the font (when, normally, it's actually quite
+ * a bit smaller on average), this preference gives the percentage of a
+ * number of lines of text we'd need to trigger inflation. This means
+ * that a percentage of 100 means that we'd need a number of characters
+ * (we know the font size and the width) equivalent to one line of
+ * square text (which is actually a lot less than a real line of text).
+ *
+ * A value of 0 means there's no character length threshold.
+ */
+pref("font.size.inflation.lineThreshold", 400);
+
+/*
+ * Defines the font size inflation mapping intercept parameter.
+ *
+ * Font size inflation computes a minimum font size, m, based on
+ * other preferences (see font.size.inflation.minTwips and
+ * font.size.inflation.emPerLine, above) and the width of the
+ * frame in which the text resides. Using this minimum, a specified
+ * font size, s, is mapped to an inflated font size, i, using an
+ * equation that varies depending on the value of the font size
+ * inflation mapping intercept parameter, P:
+ *
+ * If the intercept parameter is negative, then the following mapping
+ * function is used:
+ *
+ * i = m + s
+ *
+ * If the intercept parameter is non-negative, then the mapping function
+ * is a function such that its graph meets the graph of i = s at the
+ * point where both i and s are (1 + P/2) * m for values of s that are
+ * large enough. This means that when s=0, i is always equal to m.
+ */
+pref("font.size.inflation.mappingIntercept", 1);
+
+/*
+ * This controls the percentage that fonts will be inflated, if font
+ * size inflation is enabled. Essentially, if we have a specified font
+ * size, s, and an inflated font size, i, this specifies that the ratio
+ * i/s * 100 should never exceed the value of this preference.
+ *
+ * In order for this preference to have any effect, its value must be
+ * greater than 100, since font inflation can never decrease the ratio
+ * i/s.
+ */
+pref("font.size.inflation.maxRatio", 0);
+
+/*
+ * When enabled, the touch.radius and mouse.radius prefs allow events to be dispatched
+ * to nearby elements that are sensitive to the event. See PositionedEventTargeting.cpp.
+ * The 'mm' prefs define a rectangle around the nominal event target point within which
+ * we will search for suitable elements. 'visitedWeight' is a percentage weight;
+ * a value > 100 makes a visited link be treated as further away from the event target
+ * than it really is, while a value < 100 makes a visited link be treated as closer
+ * to the event target than it really is.
+ */
+pref("ui.touch.radius.enabled", false);
+pref("ui.touch.radius.leftmm", 8);
+pref("ui.touch.radius.topmm", 12);
+pref("ui.touch.radius.rightmm", 8);
+pref("ui.touch.radius.bottommm", 4);
+pref("ui.touch.radius.visitedWeight", 120);
+
+pref("ui.mouse.radius.enabled", false);
+pref("ui.mouse.radius.leftmm", 8);
+pref("ui.mouse.radius.topmm", 12);
+pref("ui.mouse.radius.rightmm", 8);
+pref("ui.mouse.radius.bottommm", 4);
+pref("ui.mouse.radius.visitedWeight", 120);
+
+// When true, the ui.mouse.radius.* prefs will only affect simulated mouse events generated by touch input.
+// When false, the prefs will be used for all mouse events.
+pref("ui.mouse.radius.inputSource.touchOnly", true);
+
+#ifdef XP_WIN
+
+pref("font.name.serif.ar", "Times New Roman");
+pref("font.name.sans-serif.ar", "Segoe UI");
+pref("font.name-list.sans-serif.ar", "Segoe UI, Tahoma, Arial");
+pref("font.name.monospace.ar", "Courier New");
+pref("font.name.cursive.ar", "Comic Sans MS");
+
+pref("font.name.serif.el", "Times New Roman");
+pref("font.name.sans-serif.el", "Arial");
+pref("font.name.monospace.el", "Courier New");
+pref("font.name.cursive.el", "Comic Sans MS");
+
+pref("font.name.serif.he", "Narkisim");
+pref("font.name.sans-serif.he", "Arial");
+pref("font.name.monospace.he", "Fixed Miriam Transparent");
+pref("font.name.cursive.he", "Guttman Yad");
+pref("font.name-list.serif.he", "Narkisim, David");
+pref("font.name-list.monospace.he", "Fixed Miriam Transparent, Miriam Fixed, Rod, Courier New");
+pref("font.name-list.cursive.he", "Guttman Yad, Ktav, Arial");
+
+pref("font.name.serif.ja", "MS PMincho");
+pref("font.name.sans-serif.ja", "MS PGothic");
+pref("font.name.monospace.ja", "MS Gothic");
+pref("font.name-list.serif.ja", "MS PMincho, MS Mincho, MS PGothic, MS Gothic,Meiryo");
+pref("font.name-list.sans-serif.ja", "MS PGothic, MS Gothic, MS PMincho, MS Mincho,Meiryo");
+pref("font.name-list.monospace.ja", "MS Gothic, MS Mincho, MS PGothic, MS PMincho,Meiryo");
+
+pref("font.name.serif.ko", "Batang");
+pref("font.name.sans-serif.ko", "Gulim");
+pref("font.name.monospace.ko", "GulimChe");
+pref("font.name.cursive.ko", "Gungsuh");
+
+pref("font.name-list.serif.ko", "Batang, Gulim");
+pref("font.name-list.sans-serif.ko", "Gulim");
+pref("font.name-list.monospace.ko", "GulimChe");
+pref("font.name-list.cursive.ko", "Gungsuh");
+
+pref("font.name.serif.th", "Tahoma");
+pref("font.name.sans-serif.th", "Tahoma");
+pref("font.name.monospace.th", "Tahoma");
+pref("font.name.cursive.th", "Tahoma");
+
+pref("font.name.serif.x-cyrillic", "Times New Roman");
+pref("font.name.sans-serif.x-cyrillic", "Arial");
+pref("font.name.monospace.x-cyrillic", "Courier New");
+pref("font.name.cursive.x-cyrillic", "Comic Sans MS");
+
+pref("font.name.serif.x-unicode", "Times New Roman");
+pref("font.name.sans-serif.x-unicode", "Arial");
+pref("font.name.monospace.x-unicode", "Courier New");
+pref("font.name.cursive.x-unicode", "Comic Sans MS");
+
+pref("font.name.serif.x-western", "Times New Roman");
+pref("font.name.sans-serif.x-western", "Arial");
+pref("font.name.monospace.x-western", "Courier New");
+pref("font.name.cursive.x-western", "Comic Sans MS");
+
+pref("font.name.serif.zh-CN", "SimSun");
+pref("font.name.sans-serif.zh-CN", "Microsoft YaHei");
+pref("font.name.monospace.zh-CN", "SimSun");
+pref("font.name.cursive.zh-CN", "KaiTi");
+pref("font.name-list.serif.zh-CN", "MS Song, SimSun, SimSun-ExtB");
+pref("font.name-list.sans-serif.zh-CN", "Microsoft YaHei, SimHei");
+pref("font.name-list.monospace.zh-CN", "MS Song, SimSun, SimSun-ExtB");
+pref("font.name-list.cursive.zh-CN", "KaiTi, KaiTi_GB2312");
+
+// Per Taiwanese users' demand. They don't want to use TC fonts for
+// rendering Latin letters. (bug 88579)
+pref("font.name.serif.zh-TW", "Times New Roman");
+pref("font.name.sans-serif.zh-TW", "Arial");
+pref("font.name.monospace.zh-TW", "MingLiU");
+pref("font.name.cursive.zh-TW", "DFKai-SB");
+pref("font.name-list.serif.zh-TW", "PMingLiu, MingLiU, MingLiU-ExtB");
+pref("font.name-list.sans-serif.zh-TW", "PMingLiU, MingLiU, MingLiU-ExtB");
+pref("font.name-list.monospace.zh-TW", "MingLiU, MingLiU-ExtB");
+
+// hkscsm3u.ttf (HKSCS-2001) : http://www.microsoft.com/hk/hkscs
+// Hong Kong users have the same demand about glyphs for Latin letters (bug 88579)
+pref("font.name.serif.zh-HK", "Times New Roman");
+pref("font.name.sans-serif.zh-HK", "Arial");
+pref("font.name.monospace.zh-HK", "MingLiu_HKSCS");
+pref("font.name.cursive.zh-HK", "DFKai-SB");
+pref("font.name-list.serif.zh-HK", "MingLiu_HKSCS, Ming(for ISO10646), MingLiU, MingLiU_HKSCS-ExtB");
+pref("font.name-list.sans-serif.zh-HK", "MingLiU_HKSCS, Ming(for ISO10646), MingLiU, MingLiU_HKSCS-ExtB");
+pref("font.name-list.monospace.zh-HK", "MingLiU_HKSCS, Ming(for ISO10646), MingLiU, MingLiU_HKSCS-ExtB");
+
+pref("font.name.serif.x-devanagari", "Kokila");
+pref("font.name.sans-serif.x-devanagari", "Nirmala UI");
+pref("font.name.monospace.x-devanagari", "Mangal");
+pref("font.name-list.serif.x-devanagari", "Kokila, Raghindi");
+pref("font.name-list.sans-serif.x-devanagari", "Nirmala UI, Mangal");
+pref("font.name-list.monospace.x-devanagari", "Mangal, Nirmala UI");
+
+pref("font.name.serif.x-tamil", "Latha");
+pref("font.name.sans-serif.x-tamil", "");
+pref("font.name.monospace.x-tamil", "Latha");
+pref("font.name-list.serif.x-tamil", "Latha");
+pref("font.name-list.monospace.x-tamil", "Latha");
+
+# http://www.alanwood.net/unicode/fonts.html
+
+pref("font.name.serif.x-armn", "Sylfaen");
+pref("font.name.sans-serif.x-armn", "Arial AMU");
+pref("font.name.monospace.x-armn", "Arial AMU");
+pref("font.name-list.serif.x-armn", "Sylfaen");
+pref("font.name-list.monospace.x-armn", "Arial AMU");
+
+pref("font.name.serif.x-beng", "Vrinda");
+pref("font.name.sans-serif.x-beng", "Vrinda");
+pref("font.name.monospace.x-beng", "Mitra Mono");
+pref("font.name-list.serif.x-beng", "Vrinda, Akaash, Likhan, Ekushey Punarbhaba");
+pref("font.name-list.sans-serif.x-beng", "Vrinda, Akaash, Likhan, Ekushey Punarbhaba");
+pref("font.name-list.monospace.x-beng", "Likhan, Mukti Narrow");
+
+pref("font.name.serif.x-cans", "Aboriginal Serif");
+pref("font.name.sans-serif.x-cans", "Aboriginal Sans");
+pref("font.name.monospace.x-cans", "Aboriginal Sans");
+pref("font.name-list.serif.x-cans", "Aboriginal Serif, BJCree Uni");
+pref("font.name-list.monospace.x-cans", "Aboriginal Sans, OskiDakelh, Pigiarniq, Uqammaq");
+
+pref("font.name.serif.x-ethi", "Visual Geez Unicode");
+pref("font.name.sans-serif.x-ethi", "GF Zemen Unicode");
+pref("font.name.cursive.x-ethi", "Visual Geez Unicode Title");
+pref("font.name.monospace.x-ethi", "Ethiopia Jiret");
+pref("font.name-list.serif.x-ethi", "Visual Geez Unicode, Visual Geez Unicode Agazian");
+pref("font.name-list.monospace.x-ethi", "Ethiopia Jiret");
+
+pref("font.name.serif.x-geor", "Sylfaen");
+pref("font.name.sans-serif.x-geor", "BPG Classic 99U");
+pref("font.name.monospace.x-geor", "BPG Classic 99U");
+pref("font.name-list.serif.x-geor", "Sylfaen, BPG Paata Khutsuri U, TITUS Cyberbit Basic");
+pref("font.name-list.monospace.x-geor", "BPG Classic 99U");
+
+pref("font.name.serif.x-gujr", "Shruti");
+pref("font.name.sans-serif.x-gujr", "Shruti");
+pref("font.name.monospace.x-gujr", "Shruti");
+pref("font.name-list.serif.x-gujr", "Shruti");
+pref("font.name-list.monospace.x-gujr", "Shruti");
+
+pref("font.name.serif.x-guru", "Raavi");
+pref("font.name.sans-serif.x-guru", "");
+pref("font.name.monospace.x-guru", "Raavi");
+pref("font.name-list.serif.x-guru", "Raavi, Saab");
+pref("font.name-list.monospace.x-guru", "Raavi, Saab");
+
+pref("font.name.serif.x-khmr", "PhnomPenh OT");
+pref("font.name.sans-serif.x-khmr", "Khmer OS");
+pref("font.name.monospace.x-khmr", "Khmer OS");
+pref("font.name-list.serif.x-khmr", "PhnomPenh OT,.Mondulkiri U GR 1.5, Khmer OS");
+pref("font.name-list.monospace.x-khmr", "Khmer OS, Khmer OS System");
+
+pref("font.name.serif.x-mlym", "Rachana_w01");
+pref("font.name.sans-serif.x-mlym", "Rachana_w01");
+pref("font.name.monospace.x-mlym", "Rachana_w01");
+pref("font.name-list.serif.x-mlym", "AnjaliOldLipi, Kartika, ThoolikaUnicode");
+pref("font.name-list.sans-serif.x-mlym", "AnjaliOldLipi, Kartika, ThoolikaUnicode");
+pref("font.name-list.monospace.x-mlym", "AnjaliOldLipi, Kartika, ThoolikaUnicode");
+
+pref("font.name.serif.x-orya", "ori1Uni");
+pref("font.name.sans-serif.x-orya", "ori1Uni");
+pref("font.name.monospace.x-orya", "ori1Uni");
+pref("font.name-list.serif.x-orya", "Kalinga, ori1Uni");
+pref("font.name-list.sans-serif.x-orya", "Kalinga, ori1Uni");
+pref("font.name-list.monospace.x-orya", "Kalinga, ori1Uni");
+
+pref("font.name.serif.x-telu", "Gautami");
+pref("font.name.sans-serif.x-telu", "Gautami");
+pref("font.name.monospace.x-telu", "Gautami");
+pref("font.name-list.serif.x-telu", "Gautami, Akshar Unicode");
+pref("font.name-list.sans-serif.x-telu", "Gautami, Akshar Unicode");
+pref("font.name-list.monospace.x-telu", "Gautami, Akshar Unicode");
+
+pref("font.name.serif.x-knda", "Tunga");
+pref("font.name.sans-serif.x-knda", "Tunga");
+pref("font.name.monospace.x-knda", "Tunga");
+pref("font.name-list.serif.x-knda", "Tunga, AksharUnicode");
+pref("font.name-list.sans-serif.x-knda", "Tunga, AksharUnicode");
+pref("font.name-list.monospace.x-knda", "Tunga, AksharUnicode");
+
+pref("font.name.serif.x-sinh", "Iskoola Pota");
+pref("font.name.sans-serif.x-sinh", "Iskoola Pota");
+pref("font.name.monospace.x-sinh", "Iskoola Pota");
+pref("font.name-list.serif.x-sinh", "Iskoola Pota, AksharUnicode");
+pref("font.name-list.sans-serif.x-sinh", "Iskoola Pota, AksharUnicode");
+pref("font.name-list.monospace.x-sinh", "Iskoola Pota, AksharUnicode");
+
+pref("font.name.serif.x-tibt", "Tibetan Machine Uni");
+pref("font.name.sans-serif.x-tibt", "Tibetan Machine Uni");
+pref("font.name.monospace.x-tibt", "Tibetan Machine Uni");
+pref("font.name-list.serif.x-tibt", "Tibetan Machine Uni, Jomolhari, Microsoft Himalaya");
+pref("font.name-list.sans-serif.x-tibt", "Tibetan Machine Uni, Jomolhari, Microsoft Himalaya");
+pref("font.name-list.monospace.x-tibt", "Tibetan Machine Uni, Jomolhari, Microsoft Himalaya");
+
+pref("font.minimum-size.th", 10);
+
+pref("font.default.x-devanagari", "sans-serif");
+pref("font.name.serif.x-math", "Latin Modern Math");
+// We have special support for Monotype Symbol on Windows.
+pref("font.name-list.serif.x-math", "Latin Modern Math, XITS Math, Cambria Math, Libertinus Math, DejaVu Math TeX Gyre, TeX Gyre Bonum Math, TeX Gyre Pagella Math, TeX Gyre Schola, TeX Gyre Termes Math, STIX Math, Asana Math, STIXGeneral, DejaVu Serif, DejaVu Sans, Symbol, Times New Roman");
+pref("font.name.sans-serif.x-math", "Arial");
+pref("font.name.monospace.x-math", "Courier New");
+pref("font.name.cursive.x-math", "Comic Sans MS");
+
+// cleartype settings - false implies default system settings
+
+// use cleartype rendering for downloadable fonts (win xp only)
+pref("gfx.font_rendering.cleartype.use_for_downloadable_fonts", true);
+
+// use cleartype rendering for all fonts always (win xp only)
+pref("gfx.font_rendering.cleartype.always_use_for_content", false);
+
+// ClearType tuning parameters for directwrite/d2d.
+//
+// Allows overriding of underlying registry values in:
+// HKCU/Software/Microsoft/Avalon.Graphics/<display> (contrast and level)
+// HKLM/Software/Microsoft/Avalon.Graphics/<display> (gamma, pixel structure)
+// and selection of the ClearType/antialiasing mode.
+//
+// A value of -1 implies use the default value, otherwise value ranges
+// follow registry settings:
+// gamma [1000, 2200] default: based on screen, typically 2200 (== 2.2)
+// enhanced contrast [0, 1000] default: 50
+// cleartype level [0, 100] default: 100
+// pixel structure [0, 2] default: 0 (flat/RGB/BGR)
+// rendering mode [0, 5] default: 0
+// 0 = use default for font & size;
+// 1 = aliased;
+// 2 = GDI Classic;
+// 3 = GDI Natural Widths;
+// 4 = Natural;
+// 5 = Natural Symmetric
+//
+// See:
+// http://msdn.microsoft.com/en-us/library/aa970267.aspx
+// http://msdn.microsoft.com/en-us/library/dd368190%28v=VS.85%29.aspx
+// Note: DirectWrite uses the "Enhanced Contrast Level" value rather than the
+// "Text Contrast Level" value
+
+pref("gfx.font_rendering.cleartype_params.gamma", -1);
+pref("gfx.font_rendering.cleartype_params.enhanced_contrast", -1);
+pref("gfx.font_rendering.cleartype_params.cleartype_level", -1);
+pref("gfx.font_rendering.cleartype_params.pixel_structure", -1);
+pref("gfx.font_rendering.cleartype_params.rendering_mode", -1);
+
+// A comma-separated list of font family names. Fonts in these families will
+// be forced to use "GDI Classic" ClearType mode, provided the value
+// of gfx.font_rendering.cleartype_params.rendering_mode is -1
+// (i.e. a specific rendering_mode has not been explicitly set).
+// Currently we apply this setting to the sans-serif Microsoft "core Web fonts".
+pref("gfx.font_rendering.cleartype_params.force_gdi_classic_for_families",
+ "Arial,Consolas,Courier New,Microsoft Sans Serif,Segoe UI,Tahoma,Trebuchet MS,Verdana");
+// The maximum size at which we will force GDI classic mode using
+// force_gdi_classic_for_families.
+pref("gfx.font_rendering.cleartype_params.force_gdi_classic_max_size", 15);
+
+pref("ui.key.menuAccessKeyFocuses", true);
+
+// override double-click word selection behavior.
+pref("layout.word_select.eat_space_to_next_word", true);
+
+// scrollbar snapping region
+pref("slider.snapMultiplier", 6);
+
+// print_extra_margin enables platforms to specify an extra gap or margin
+// around the content of the page for Print Preview only
+pref("print.print_extra_margin", 90); // twips (90 twips is an eigth of an inch)
+
+// Whether to extend the native dialog with information on printing frames.
+pref("print.extend_native_print_dialog", true);
+
+// Locate plugins by scanning the Adobe Acrobat installation directory with a minimum version
+pref("plugin.scan.Acrobat", "5.0");
+
+// Locate plugins by scanning the Quicktime installation directory with a minimum version
+pref("plugin.scan.Quicktime", "5.0");
+
+// Locate and scan the Window Media Player installation directory for plugins with a minimum version
+pref("plugin.scan.WindowsMediaPlayer", "7.0");
+
+// Locate plugins by the directories specified in the Windows registry for PLIDs
+// Which is currently HKLM\Software\MozillaPlugins\xxxPLIDxxx\Path
+pref("plugin.scan.plid.all", true);
+
+// Whether sending WM_MOUSEWHEEL and WM_MOUSEHWHEEL to plugins on Windows.
+pref("plugin.mousewheel.enabled", true);
+
+// Switch the keyboard layout per window
+pref("intl.keyboard.per_window_layout", false);
+
+#ifdef NS_ENABLE_TSF
+// Enable/Disable TSF support on Vista or later.
+pref("intl.tsf.enable", true);
+
+// Support IMEs implemented with IMM in TSF mode.
+pref("intl.tsf.support_imm", true);
+
+// This is referred only when both "intl.tsf.enable" and "intl.tsf.support_imm"
+// are true. When this is true, default IMC is associated with focused window
+// only when active keyboard layout is a legacy IMM-IME.
+pref("intl.tsf.associate_imc_only_when_imm_ime_is_active", false);
+
+// Enables/Disables hack for specific TIP.
+
+// Whether creates native caret for ATOK or not.
+pref("intl.tsf.hack.atok.create_native_caret", true);
+// Whether use available composition string rect for result of
+// ITfContextView::GetTextExt() even if the specified range is same as the
+// range of composition string but some character rects of them are not
+// available. Note that this is ignored if active ATOK is or older than 2016
+// and create_native_caret is true.
+pref("intl.tsf.hack.atok.do_not_return_no_layout_error_of_composition_string", true);
+// Whether use composition start position for the result of
+// ITfContextView::GetTextExt() if the specified range is larger than
+// composition start offset.
+// For Free ChangJie 2010
+pref("intl.tsf.hack.free_chang_jie.do_not_return_no_layout_error", true);
+// For Microsoft Pinyin and Microsoft Wubi
+pref("intl.tsf.hack.ms_simplified_chinese.do_not_return_no_layout_error", true);
+// For Microsoft ChangJie and Microsoft Quick
+pref("intl.tsf.hack.ms_traditional_chinese.do_not_return_no_layout_error", true);
+// For Easy Changjei
+pref("intl.tsf.hack.easy_changjei.do_not_return_no_layout_error", true);
+// Whether use previous character rect for the result of
+// ITfContextView::GetTextExt() if the specified range is the first character
+// of selected clause of composition string.
+pref("intl.tsf.hack.ms_japanese_ime.do_not_return_no_layout_error_at_first_char", true);
+// Whether default IMC should be associated with focused window when MS-IME
+// for Japanese on Win10 is active. MS-IME for Japanese on Win10 has a crash
+// bug. While restoring default IMC when MS-IME for Japanese is active,
+// it sometimes crashes after Creators Update. This pref avoid the crash.
+pref("intl.tsf.hack.ms_japanese_ime.do_not_associate_imc_on_win10", true);
+// Whether use previous character rect for the result of
+// ITfContextView::GetTextExt() if the specified range is the caret of
+// composition string.
+pref("intl.tsf.hack.ms_japanese_ime.do_not_return_no_layout_error_at_caret", true);
+// Whether hack ITextStoreACP::QueryInsert() or not. The method should return
+// new selection after specified length text is inserted at specified range.
+// However, Microsoft's some Chinese TIPs expect that the result is same as
+// specified range. If following prefs are true, ITextStoreACP::QueryInsert()
+// returns specified range only when one of the TIPs is active.
+// For Microsoft Pinyin and Microsoft Wubi
+pref("intl.tsf.hack.ms_simplified_chinese.query_insert_result", true);
+// For Microsoft ChangJie and Microsoft Quick
+pref("intl.tsf.hack.ms_traditional_chinese.query_insert_result", true);
+#endif
+
+// If composition_font is set, Gecko sets the font to IME. IME may use
+// the fonts on their window like candidate window. If they are empty,
+// Gecko uses the system default font which is set to the IM context.
+// The font name must not start with '@'. When the writing mode is vertical,
+// Gecko inserts '@' to the start of the font name automatically.
+// FYI: Changing these prefs requires to restart.
+pref("intl.imm.composition_font", "");
+
+// Japanist 2003's candidate window is broken if the font is "@System" which
+// is default composition font for vertical writing mode.
+// You can specify font to use on candidate window of Japanist 2003.
+// This value must not start with '@'.
+// FYI: Changing this pref requires to restart.
+pref("intl.imm.composition_font.japanist_2003", "MS PGothic");
+
+// Even if IME claims that they support vertical writing mode but it may not
+// support vertical writing mode for its candidate window. This pref allows
+// to ignore the claim.
+// FYI: Changing this pref requires to restart.
+pref("intl.imm.vertical_writing.always_assume_not_supported", false);
+
+// We cannot retrieve active IME name with IMM32 API if a TIP of TSF is active.
+// This pref can specify active IME name when Japanese TIP is active.
+// For example:
+// Google Japanese Input: "Google 日本語入力 IMM32 モジュール"
+// ATOK 2011: "ATOK 2011" (similarly, e.g., ATOK 2013 is "ATOK 2013")
+pref("intl.imm.japanese.assume_active_tip_name_as", "");
+
+// See bug 448927, on topmost panel, some IMEs are not usable on Windows.
+pref("ui.panel.default_level_parent", false);
+
+pref("mousewheel.system_scroll_override_on_root_content.enabled", true);
+
+// Enable system settings cache for mouse wheel message handling.
+// Note that even if this pref is set to true, Gecko may not cache the system
+// settings if Gecko detects that the cache won't be refreshed properly when
+// the settings are changed.
+pref("mousewheel.system_settings_cache.enabled", true);
+
+// This is a pref to test system settings cache for mouse wheel message
+// handling. If this is set to true, Gecko forcibly use the cache.
+pref("mousewheel.system_settings_cache.force_enabled", false);
+
+// High resolution scrolling with supported mouse drivers on Vista or later.
+pref("mousewheel.enable_pixel_scrolling", true);
+
+// If your mouse drive sends WM_*SCROLL messages when you turn your mouse wheel,
+// set this to true. Then, gecko processes them as mouse wheel messages.
+pref("mousewheel.emulate_at_wm_scroll", false);
+
+// Enables or disabled the TrackPoint hack, -1 is autodetect, 0 is off,
+// and 1 is on. Set this to 1 if TrackPoint scrolling is not working.
+pref("ui.trackpoint_hack.enabled", -1);
+
+// Setting this to a non-empty string overrides the Win32 "window class" used
+// for "normal" windows. Setting this to MozillaUIWindowClass might make
+// some trackpad drivers behave better.
+pref("ui.window_class_override", "");
+
+// Enables or disables the Elantech gesture hacks. -1 is autodetect, 0 is off,
+// and 1 is on. Set this to 1 if three-finger swipe gestures do not cause
+// page back/forward actions, or if pinch-to-zoom does not work.
+pref("ui.elantech_gesture_hacks.enabled", -1);
+
+// Show the Windows on-screen keyboard (osk.exe) when a text field is focused.
+pref("ui.osk.enabled", true);
+// Only show the on-screen keyboard if there are no physical keyboards attached
+// to the device.
+pref("ui.osk.detect_physical_keyboard", true);
+// Path to TabTip.exe on local machine. Cached for performance reasons.
+pref("ui.osk.on_screen_keyboard_path", "");
+// Only try to show the on-screen keyboard on Windows 10 and later. Setting
+// this pref to false will allow the OSK to show on Windows 8 and 8.1.
+pref("ui.osk.require_win10", false);
+// This pref stores the "reason" that the on-screen keyboard was either
+// shown or not shown when focus is moved to an editable text field. It is
+// used to help debug why the keyboard is either not appearing when expected
+// or appearing when it is not expected.
+pref("ui.osk.debug.keyboardDisplayReason", "");
+
+# XP_WIN
+#endif
+
+#ifdef XP_MACOSX
+// Mac specific preference defaults
+pref("browser.drag_out_of_frame_style", 1);
+pref("ui.key.saveLink.shift", false); // true = shift, false = meta
+
+// default fonts (in UTF8 and using canonical names)
+// to determine canonical font names, use a debug build and
+// enable NSPR logging for module fontInfoLog:5
+// canonical names immediately follow '(fontinit) family:' in the log
+
+pref("font.name.serif.ar", "Al Bayan");
+pref("font.name.sans-serif.ar", "Geeza Pro");
+pref("font.name.monospace.ar", "Geeza Pro");
+pref("font.name.cursive.ar", "DecoType Naskh");
+pref("font.name.fantasy.ar", "KufiStandardGK");
+pref("font.name-list.serif.ar", "Al Bayan");
+pref("font.name-list.sans-serif.ar", "Geeza Pro");
+pref("font.name-list.monospace.ar", "Geeza Pro");
+pref("font.name-list.cursive.ar", "DecoType Naskh");
+pref("font.name-list.fantasy.ar", "KufiStandardGK");
+
+pref("font.name.serif.el", "Times");
+pref("font.name.sans-serif.el", "Helvetica");
+pref("font.name.monospace.el", "Courier New");
+pref("font.name.cursive.el", "Lucida Grande");
+pref("font.name.fantasy.el", "Lucida Grande");
+pref("font.name-list.serif.el", "Times,Times New Roman");
+pref("font.name-list.sans-serif.el", "Helvetica,Lucida Grande");
+pref("font.name-list.monospace.el", "Courier New,Lucida Grande");
+pref("font.name-list.cursive.el", "Times,Lucida Grande");
+pref("font.name-list.fantasy.el", "Times,Lucida Grande");
+
+pref("font.name.serif.he", "Times New Roman");
+pref("font.name.sans-serif.he", "Arial");
+pref("font.name.monospace.he", "Courier New");
+pref("font.name.cursive.he", "Times New Roman");
+pref("font.name.fantasy.he", "Times New Roman");
+pref("font.name-list.serif.he", "Times New Roman");
+pref("font.name-list.sans-serif.he", "Arial");
+pref("font.name-list.monospace.he", "Courier New");
+pref("font.name-list.cursive.he", "Times New Roman");
+pref("font.name-list.fantasy.he", "Times New Roman");
+
+pref("font.name.serif.ja", "Hiragino Mincho ProN");
+pref("font.name.sans-serif.ja", "Hiragino Kaku Gothic ProN");
+pref("font.name.monospace.ja", "Osaka-Mono");
+pref("font.name-list.serif.ja", "Hiragino Mincho ProN,Hiragino Mincho Pro");
+pref("font.name-list.sans-serif.ja", "Hiragino Kaku Gothic ProN,Hiragino Kaku Gothic Pro");
+pref("font.name-list.monospace.ja", "Osaka-Mono");
+
+pref("font.name.serif.ko", "AppleMyungjo");
+pref("font.name.sans-serif.ko", "Apple SD Gothic Neo");
+pref("font.name.monospace.ko", "Apple SD Gothic Neo");
+pref("font.name-list.serif.ko", "AppleMyungjo");
+pref("font.name-list.sans-serif.ko", "Apple SD Gothic Neo,AppleGothic");
+pref("font.name-list.monospace.ko", "Apple SD Gothic Neo,AppleGothic");
+
+pref("font.name.serif.th", "Thonburi");
+pref("font.name.sans-serif.th", "Thonburi");
+pref("font.name.monospace.th", "Ayuthaya");
+pref("font.name-list.serif.th", "Thonburi");
+pref("font.name-list.sans-serif.th", "Thonburi");
+pref("font.name-list.monospace.th", "Ayuthaya");
+
+pref("font.name.serif.x-armn", "Mshtakan");
+pref("font.name.sans-serif.x-armn", "Mshtakan");
+pref("font.name.monospace.x-armn", "Mshtakan");
+pref("font.name-list.serif.x-armn", "Mshtakan");
+pref("font.name-list.sans-serif.x-armn", "Mshtakan");
+pref("font.name-list.monospace.x-armn", "Mshtakan");
+
+// SolaimanLipi, Rupali http://ekushey.org/?page/mac_download
+pref("font.name.serif.x-beng", "Bangla MN");
+pref("font.name.sans-serif.x-beng", "Bangla Sangam MN");
+pref("font.name.monospace.x-beng", "Bangla Sangam MN");
+pref("font.name-list.serif.x-beng", "Bangla MN");
+pref("font.name-list.sans-serif.x-beng", "Bangla Sangam MN");
+pref("font.name-list.monospace.x-beng", "Bangla Sangam MN");
+
+pref("font.name.serif.x-cans", "Euphemia UCAS");
+pref("font.name.sans-serif.x-cans", "Euphemia UCAS");
+pref("font.name.monospace.x-cans", "Euphemia UCAS");
+pref("font.name-list.serif.x-cans", "Euphemia UCAS");
+pref("font.name-list.sans-serif.x-cans", "Euphemia UCAS");
+pref("font.name-list.monospace.x-cans", "Euphemia UCAS");
+
+pref("font.name.serif.x-cyrillic", "Times");
+pref("font.name.sans-serif.x-cyrillic", "Helvetica");
+pref("font.name.monospace.x-cyrillic", "Monaco");
+pref("font.name.cursive.x-cyrillic", "Geneva");
+pref("font.name.fantasy.x-cyrillic", "Charcoal CY");
+pref("font.name-list.serif.x-cyrillic", "Times,Times New Roman");
+pref("font.name-list.sans-serif.x-cyrillic", "Helvetica,Arial");
+pref("font.name-list.monospace.x-cyrillic", "Monaco,Courier New");
+pref("font.name-list.cursive.x-cyrillic", "Geneva");
+pref("font.name-list.fantasy.x-cyrillic", "Charcoal CY");
+
+pref("font.name.serif.x-devanagari", "Devanagari MT");
+pref("font.name.sans-serif.x-devanagari", "Devanagari Sangam MN");
+pref("font.name.monospace.x-devanagari", "Devanagari Sangam MN");
+pref("font.name-list.serif.x-devanagari", "Devanagari MT");
+pref("font.name-list.sans-serif.x-devanagari", "Devanagari Sangam MN,Devanagari MT");
+pref("font.name-list.monospace.x-devanagari", "Devanagari Sangam MN,Devanagari MT");
+
+// Abyssinica SIL http://scripts.sil.org/AbyssinicaSIL_Download
+pref("font.name.serif.x-ethi", "Kefa");
+pref("font.name.sans-serif.x-ethi", "Kefa");
+pref("font.name.monospace.x-ethi", "Kefa");
+pref("font.name-list.serif.x-ethi", "Kefa,Abyssinica SIL");
+pref("font.name-list.sans-serif.x-ethi", "Kefa,Abyssinica SIL");
+pref("font.name-list.monospace.x-ethi", "Kefa,Abyssinica SIL");
+
+// no suitable fonts for georgian ship with mac os x
+// however some can be freely downloaded
+// TITUS Cyberbit Basic http://titus.fkidg1.uni-frankfurt.de/unicode/tituut.asp
+// Zuzumbo http://homepage.mac.com/rsiradze/FileSharing91.html
+pref("font.name.serif.x-geor", "TITUS Cyberbit Basic");
+pref("font.name.sans-serif.x-geor", "Zuzumbo");
+pref("font.name.monospace.x-geor", "Zuzumbo");
+pref("font.name-list.serif.x-geor", "TITUS Cyberbit Basic");
+pref("font.name-list.sans-serif.x-geor", "Zuzumbo");
+pref("font.name-list.monospace.x-geor", "Zuzumbo");
+
+pref("font.name.serif.x-gujr", "Gujarati MT");
+pref("font.name.sans-serif.x-gujr", "Gujarati Sangam MN");
+pref("font.name.monospace.x-gujr", "Gujarati Sangam MN");
+pref("font.name-list.serif.x-gujr", "Gujarati MT");
+pref("font.name-list.sans-serif.x-gujr", "Gujarati Sangam MN,Gujarati MT");
+pref("font.name-list.monospace.x-gujr", "Gujarati Sangam MN,Gujarati MT");
+
+pref("font.name.serif.x-guru", "Gurmukhi MT");
+pref("font.name.sans-serif.x-guru", "Gurmukhi MT");
+pref("font.name.monospace.x-guru", "Gurmukhi MT");
+pref("font.name-list.serif.x-guru", "Gurmukhi MT");
+pref("font.name-list.sans-serif.x-guru", "Gurmukhi MT");
+pref("font.name-list.monospace.x-guru", "Gurmukhi MT");
+
+pref("font.name.serif.x-khmr", "Khmer MN");
+pref("font.name.sans-serif.x-khmr", "Khmer Sangam MN");
+pref("font.name.monospace.x-khmr", "Khmer Sangam MN");
+pref("font.name-list.serif.x-khmr", "Khmer MN");
+pref("font.name-list.sans-serif.x-khmr", "Khmer Sangam MN");
+pref("font.name-list.monospace.x-khmr", "Khmer Sangam MN");
+
+pref("font.name.serif.x-mlym", "Malayalam MN");
+pref("font.name.sans-serif.x-mlym", "Malayalam Sangam MN");
+pref("font.name.monospace.x-mlym", "Malayalam Sangam MN");
+pref("font.name-list.serif.x-mlym", "Malayalam MN");
+pref("font.name-list.sans-serif.x-mlym", "Malayalam Sangam MN");
+pref("font.name-list.monospace.x-mlym", "Malayalam Sangam MN");
+
+pref("font.name.serif.x-orya", "Oriya MN");
+pref("font.name.sans-serif.x-orya", "Oriya Sangam MN");
+pref("font.name.monospace.x-orya", "Oriya Sangam MN");
+pref("font.name-list.serif.x-orya", "Oriya MN");
+pref("font.name-list.sans-serif.x-orya", "Oriya Sangam MN");
+pref("font.name-list.monospace.x-orya", "Oriya Sangam MN");
+
+// Pothana http://web.nickshanks.com/typography/telugu/
+pref("font.name.serif.x-telu", "Telugu MN");
+pref("font.name.sans-serif.x-telu", "Telugu Sangam MN");
+pref("font.name.monospace.x-telu", "Telugu Sangam MN");
+pref("font.name-list.serif.x-telu", "Telugu MN,Pothana");
+pref("font.name-list.sans-serif.x-telu", "Telugu Sangam MN,Pothana");
+pref("font.name-list.monospace.x-telu", "Telugu Sangam MN,Pothana");
+
+// Kedage http://web.nickshanks.com/typography/kannada/
+pref("font.name.serif.x-knda", "Kannada MN");
+pref("font.name.sans-serif.x-knda", "Kannada Sangam MN");
+pref("font.name.monospace.x-knda", "Kannada Sangam MN");
+pref("font.name-list.serif.x-knda", "Kannada MN,Kedage");
+pref("font.name-list.sans-serif.x-knda", "Kannada Sangam MN,Kedage");
+pref("font.name-list.monospace.x-knda", "Kannada Sangam MN,Kedage");
+
+pref("font.name.serif.x-sinh", "Sinhala MN");
+pref("font.name.sans-serif.x-sinh", "Sinhala Sangam MN");
+pref("font.name.monospace.x-sinh", "Sinhala Sangam MN");
+pref("font.name-list.serif.x-sinh", "Sinhala MN");
+pref("font.name-list.sans-serif.x-sinh", "Sinhala Sangam MN");
+pref("font.name-list.monospace.x-sinh", "Sinhala Sangam MN");
+
+pref("font.name.serif.x-tamil", "InaiMathi");
+pref("font.name.sans-serif.x-tamil", "InaiMathi");
+pref("font.name.monospace.x-tamil", "InaiMathi");
+pref("font.name-list.serif.x-tamil", "InaiMathi");
+pref("font.name-list.sans-serif.x-tamil", "InaiMathi");
+pref("font.name-list.monospace.x-tamil", "InaiMathi");
+
+// Kailasa ships with mac os x >= 10.5
+pref("font.name.serif.x-tibt", "Kailasa");
+pref("font.name.sans-serif.x-tibt", "Kailasa");
+pref("font.name.monospace.x-tibt", "Kailasa");
+pref("font.name-list.serif.x-tibt", "Kailasa");
+pref("font.name-list.sans-serif.x-tibt", "Kailasa");
+pref("font.name-list.monospace.x-tibt", "Kailasa");
+
+pref("font.name.serif.x-unicode", "Times");
+pref("font.name.sans-serif.x-unicode", "Helvetica");
+pref("font.name.monospace.x-unicode", "Courier");
+pref("font.name.cursive.x-unicode", "Apple Chancery");
+pref("font.name.fantasy.x-unicode", "Papyrus");
+pref("font.name-list.serif.x-unicode", "Times");
+pref("font.name-list.sans-serif.x-unicode", "Helvetica");
+pref("font.name-list.monospace.x-unicode", "Courier");
+pref("font.name-list.cursive.x-unicode", "Apple Chancery");
+pref("font.name-list.fantasy.x-unicode", "Papyrus");
+
+pref("font.name.serif.x-western", "Times");
+pref("font.name.sans-serif.x-western", "Helvetica");
+pref("font.name.monospace.x-western", "Courier");
+pref("font.name.cursive.x-western", "Apple Chancery");
+pref("font.name.fantasy.x-western", "Papyrus");
+pref("font.name-list.serif.x-western", "Times,Times New Roman");
+pref("font.name-list.sans-serif.x-western", "Helvetica,Arial");
+pref("font.name-list.monospace.x-western", "Courier,Courier New");
+pref("font.name-list.cursive.x-western", "Apple Chancery");
+pref("font.name-list.fantasy.x-western", "Papyrus");
+
+pref("font.name.serif.zh-CN", "Times");
+pref("font.name.sans-serif.zh-CN", "Helvetica");
+pref("font.name.monospace.zh-CN", "Courier");
+pref("font.name.cursive.zh-CN", "Kaiti SC");
+pref("font.name-list.serif.zh-CN", "Times,STSong,Heiti SC");
+pref("font.name-list.sans-serif.zh-CN", "Helvetica,PingFang SC,STHeiti,Heiti SC");
+pref("font.name-list.monospace.zh-CN", "Courier,PingFang SC,STHeiti,Heiti SC");
+
+pref("font.name.serif.zh-TW", "Times");
+pref("font.name.sans-serif.zh-TW", "Helvetica");
+pref("font.name.monospace.zh-TW", "Courier");
+pref("font.name.cursive.zh-TW", "Kaiti TC");
+pref("font.name-list.serif.zh-TW", "Times,LiSong Pro,Heiti TC");
+pref("font.name-list.sans-serif.zh-TW", "Helvetica,PingFang TC,Heiti TC,LiHei Pro");
+pref("font.name-list.monospace.zh-TW", "Courier,PingFang TC,Heiti TC,LiHei Pro");
+
+pref("font.name.serif.zh-HK", "Times");
+pref("font.name.sans-serif.zh-HK", "Helvetica");
+pref("font.name.monospace.zh-HK", "Courier");
+pref("font.name.cursive.zh-HK", "Kaiti TC");
+pref("font.name-list.serif.zh-HK", "Times,LiSong Pro,Heiti TC");
+pref("font.name-list.sans-serif.zh-HK", "Helvetica,PingFang TC,Heiti TC,LiHei Pro");
+pref("font.name-list.monospace.zh-HK", "Courier,PingFang TC,Heiti TC,LiHei Pro");
+
+// XP_MACOSX changes to default font sizes
+pref("font.minimum-size.th", 10);
+pref("font.size.variable.zh-CN", 15);
+pref("font.size.variable.zh-HK", 15);
+pref("font.size.variable.zh-TW", 15);
+
+pref("font.name.serif.x-math", "Latin Modern Math");
+// Apple's Symbol is Unicode so use it
+pref("font.name-list.serif.x-math", "Latin Modern Math, XITS Math, Cambria Math, Libertinus Math, DejaVu Math TeX Gyre, TeX Gyre Bonum Math, TeX Gyre Pagella Math, TeX Gyre Schola, TeX Gyre Termes Math, STIX Math, Asana Math, STIXGeneral, DejaVu Serif, DejaVu Sans, Symbol, Times");
+pref("font.name.sans-serif.x-math", "Helvetica");
+pref("font.name.monospace.x-math", "Courier");
+pref("font.name.cursive.x-math", "Apple Chancery");
+pref("font.name.fantasy.x-math", "Papyrus");
+
+// Individual font faces to be treated as independent families,
+// listed as <Postscript name of face:Owning family name>
+pref("font.single-face-list", "Osaka-Mono:Osaka");
+
+// optimization hint for fonts with localized names to be read in at startup, otherwise read in at lookup miss
+// names are canonical family names (typically English names)
+pref("font.preload-names-list", "Hiragino Kaku Gothic ProN,Hiragino Mincho ProN,STSong");
+
+// Override font-weight values for some problematic families Apple ships
+// (see bug 931426).
+// The name here is the font's PostScript name, which can be checked in
+// the Font Book utility or other tools.
+pref("font.weight-override.AppleSDGothicNeo-Thin", 100); // Ensure Thin < UltraLight < Light
+pref("font.weight-override.AppleSDGothicNeo-UltraLight", 200);
+pref("font.weight-override.AppleSDGothicNeo-Light", 300);
+pref("font.weight-override.AppleSDGothicNeo-Heavy", 900); // Ensure Heavy > ExtraBold (800)
+
+pref("font.weight-override.Avenir-Book", 300); // Ensure Book < Roman (400)
+pref("font.weight-override.Avenir-BookOblique", 300);
+pref("font.weight-override.Avenir-MediumOblique", 500); // Harmonize MediumOblique with Medium
+pref("font.weight-override.Avenir-Black", 900); // Ensure Black > Heavy (800)
+pref("font.weight-override.Avenir-BlackOblique", 900);
+
+pref("font.weight-override.AvenirNext-MediumItalic", 500); // Harmonize MediumItalic with Medium
+pref("font.weight-override.AvenirNextCondensed-MediumItalic", 500);
+
+pref("font.weight-override.HelveticaNeue-Light", 300); // Ensure Light > Thin (200)
+pref("font.weight-override.HelveticaNeue-LightItalic", 300);
+pref("font.weight-override.HelveticaNeue-MediumItalic", 500); // Harmonize MediumItalic with Medium
+
+// Override the Windows settings: no menu key, meta accelerator key. ctrl for general access key in HTML/XUL
+// Use 17 for Ctrl, 18 for Option, 224 for Cmd, 0 for none
+pref("ui.key.menuAccessKey", 0);
+pref("ui.key.accelKey", 224);
+// (pinkerton, joki, saari) IE5 for mac uses Control for access keys. The HTML4 spec
+// suggests to use command on mac, but this really sucks (imagine someone having a "q"
+// as an access key and not letting you quit the app!). As a result, we've made a
+// command decision 1 day before tree lockdown to change it to the control key.
+pref("ui.key.generalAccessKey", -1);
+
+// If generalAccessKey is -1, use the following two prefs instead.
+// Use 0 for disabled, 1 for Shift, 2 for Ctrl, 4 for Alt, 8 for Meta (Cmd)
+// (values can be combined, e.g. 3 for Ctrl+Shift)
+pref("ui.key.chromeAccess", 2);
+pref("ui.key.contentAccess", 6);
+
+// print_extra_margin enables platforms to specify an extra gap or margin
+// around the content of the page for Print Preview only
+pref("print.print_extra_margin", 90); // twips (90 twips is an eigth of an inch)
+
+// See bug 404131, topmost <panel> element wins to Dashboard on MacOSX.
+pref("ui.panel.default_level_parent", false);
+
+pref("ui.plugin.cancel_composition_at_input_source_changed", false);
+
+pref("mousewheel.system_scroll_override_on_root_content.enabled", false);
+
+// Macbook touchpad two finger pixel scrolling
+pref("mousewheel.enable_pixel_scrolling", true);
+
+# XP_MACOSX
+#endif
+
+#ifdef ANDROID
+// Handled differently under Mac/Windows
+pref("network.protocol-handler.warn-external.file", false);
+pref("browser.drag_out_of_frame_style", 1);
+
+// Middle-mouse handling
+pref("middlemouse.paste", true);
+pref("middlemouse.contentLoadURL", true);
+pref("middlemouse.openNewWindow", true);
+pref("middlemouse.scrollbarPosition", true);
+
+pref("browser.urlbar.clickSelectsAll", false);
+
+// Tab focus model bit field:
+// 1 focuses text controls, 2 focuses other form elements, 4 adds links.
+// Leave this at the default, 7, to match mozilla1.0-era user expectations.
+// pref("accessibility.tabfocus", 1);
+
+// autocomplete keyboard grab workaround
+pref("autocomplete.grab_during_popup", true);
+pref("autocomplete.ungrab_during_mode_switch", true);
+
+// Default to using the system filepicker if possible, but allow
+// toggling to use the XUL filepicker
+pref("ui.allow_platform_file_picker", true);
+
+pref("helpers.global_mime_types_file", "/etc/mime.types");
+pref("helpers.global_mailcap_file", "/etc/mailcap");
+pref("helpers.private_mime_types_file", "~/.mime.types");
+pref("helpers.private_mailcap_file", "~/.mailcap");
+pref("print.printer_list", ""); // list of printers, separated by spaces
+pref("print.print_reversed", false);
+pref("print.print_color", true);
+pref("print.print_landscape", false);
+pref("print.print_paper_size", 0);
+
+// print_extra_margin enables platforms to specify an extra gap or margin
+// around the content of the page for Print Preview only
+pref("print.print_extra_margin", 0); // twips
+
+/* PostScript print module prefs */
+// pref("print.postscript.enabled", true);
+
+// Setting default_level_parent to true makes the default level for popup
+// windows "top" instead of "parent". On GTK2 platform, this is implemented
+// with override-redirect windows which is the normal way to implement
+// temporary popup windows. Setting this to false would make the default
+// level "parent" which is implemented with managed windows.
+// A problem with using managed windows is that metacity sometimes deactivates
+// the parent window when the managed popup is shown.
+pref("ui.panel.default_level_parent", true);
+
+pref("mousewheel.system_scroll_override_on_root_content.enabled", false);
+
+// Forward downloads with known OMA MIME types to Android's download manager
+// instead of downloading them in the browser.
+pref("browser.download.forward_oma_android_download_manager", false);
+
+# ANDROID
+#endif
+
+#ifndef ANDROID
+#ifndef XP_MACOSX
+#ifdef XP_UNIX
+// Handled differently under Mac/Windows
+pref("network.protocol-handler.warn-external.file", false);
+pref("browser.drag_out_of_frame_style", 1);
+
+// Middle-mouse handling
+pref("middlemouse.paste", true);
+pref("middlemouse.contentLoadURL", true);
+pref("middlemouse.openNewWindow", true);
+pref("middlemouse.scrollbarPosition", true);
+
+// Clipboard behavior
+pref("clipboard.autocopy", true);
+
+pref("browser.urlbar.clickSelectsAll", false);
+
+// Tab focus model bit field:
+// 1 focuses text controls, 2 focuses other form elements, 4 adds links.
+// Leave this at the default, 7, to match mozilla1.0-era user expectations.
+// pref("accessibility.tabfocus", 1);
+
+// autocomplete keyboard grab workaround
+pref("autocomplete.grab_during_popup", true);
+pref("autocomplete.ungrab_during_mode_switch", true);
+
+// Default to using the system filepicker if possible, but allow
+// toggling to use the XUL filepicker
+pref("ui.allow_platform_file_picker", true);
+
+pref("helpers.global_mime_types_file", "/etc/mime.types");
+pref("helpers.global_mailcap_file", "/etc/mailcap");
+pref("helpers.private_mime_types_file", "~/.mime.types");
+pref("helpers.private_mailcap_file", "~/.mailcap");
+pref("print.printer_list", ""); // list of printers, separated by spaces
+pref("print.print_reversed", false);
+pref("print.print_color", true);
+pref("print.print_landscape", false);
+pref("print.print_paper_size", 0);
+
+// print_extra_margin enables platforms to specify an extra gap or margin
+// around the content of the page for Print Preview only
+pref("print.print_extra_margin", 0); // twips
+
+// font names
+
+pref("font.name.serif.ar", "serif");
+pref("font.name.sans-serif.ar", "sans-serif");
+pref("font.name.monospace.ar", "monospace");
+pref("font.size.fixed.ar", 12);
+
+pref("font.name.serif.el", "serif");
+pref("font.name.sans-serif.el", "sans-serif");
+pref("font.name.monospace.el", "monospace");
+pref("font.size.fixed.el", 12);
+
+pref("font.name.serif.he", "serif");
+pref("font.name.sans-serif.he", "sans-serif");
+pref("font.name.monospace.he", "monospace");
+pref("font.size.fixed.he", 12);
+
+pref("font.name.serif.ja", "serif");
+pref("font.name.sans-serif.ja", "sans-serif");
+pref("font.name.monospace.ja", "monospace");
+
+pref("font.name.serif.ko", "serif");
+pref("font.name.sans-serif.ko", "sans-serif");
+pref("font.name.monospace.ko", "monospace");
+
+pref("font.name.serif.th", "serif");
+pref("font.name.sans-serif.th", "sans-serif");
+pref("font.name.monospace.th", "monospace");
+pref("font.minimum-size.th", 13);
+
+pref("font.name.serif.x-armn", "serif");
+pref("font.name.sans-serif.x-armn", "sans-serif");
+pref("font.name.monospace.x-armn", "monospace");
+
+pref("font.name.serif.x-beng", "serif");
+pref("font.name.sans-serif.x-beng", "sans-serif");
+pref("font.name.monospace.x-beng", "monospace");
+
+pref("font.name.serif.x-cans", "serif");
+pref("font.name.sans-serif.x-cans", "sans-serif");
+pref("font.name.monospace.x-cans", "monospace");
+
+pref("font.name.serif.x-cyrillic", "serif");
+pref("font.name.sans-serif.x-cyrillic", "sans-serif");
+pref("font.name.monospace.x-cyrillic", "monospace");
+pref("font.size.fixed.x-cyrillic", 12);
+
+pref("font.name.serif.x-devanagari", "serif");
+pref("font.name.sans-serif.x-devanagari", "sans-serif");
+pref("font.name.monospace.x-devanagari", "monospace");
+
+pref("font.name.serif.x-ethi", "serif");
+pref("font.name.sans-serif.x-ethi", "sans-serif");
+pref("font.name.monospace.x-ethi", "monospace");
+
+pref("font.name.serif.x-geor", "serif");
+pref("font.name.sans-serif.x-geor", "sans-serif");
+pref("font.name.monospace.x-geor", "monospace");
+
+pref("font.name.serif.x-gujr", "serif");
+pref("font.name.sans-serif.x-gujr", "sans-serif");
+pref("font.name.monospace.x-gujr", "monospace");
+
+pref("font.name.serif.x-guru", "serif");
+pref("font.name.sans-serif.x-guru", "sans-serif");
+pref("font.name.monospace.x-guru", "monospace");
+
+pref("font.name.serif.x-khmr", "serif");
+pref("font.name.sans-serif.x-khmr", "sans-serif");
+pref("font.name.monospace.x-khmr", "monospace");
+
+pref("font.name.serif.x-knda", "serif");
+pref("font.name.sans-serif.x-knda", "sans-serif");
+pref("font.name.monospace.x-knda", "monospace");
+
+pref("font.name.serif.x-mlym", "serif");
+pref("font.name.sans-serif.x-mlym", "sans-serif");
+pref("font.name.monospace.x-mlym", "monospace");
+
+pref("font.name.serif.x-orya", "serif");
+pref("font.name.sans-serif.x-orya", "sans-serif");
+pref("font.name.monospace.x-orya", "monospace");
+
+pref("font.name.serif.x-sinh", "serif");
+pref("font.name.sans-serif.x-sinh", "sans-serif");
+pref("font.name.monospace.x-sinh", "monospace");
+
+pref("font.name.serif.x-tamil", "serif");
+pref("font.name.sans-serif.x-tamil", "sans-serif");
+pref("font.name.monospace.x-tamil", "monospace");
+
+pref("font.name.serif.x-telu", "serif");
+pref("font.name.sans-serif.x-telu", "sans-serif");
+pref("font.name.monospace.x-telu", "monospace");
+
+pref("font.name.serif.x-tibt", "serif");
+pref("font.name.sans-serif.x-tibt", "sans-serif");
+pref("font.name.monospace.x-tibt", "monospace");
+
+pref("font.name.serif.x-unicode", "serif");
+pref("font.name.sans-serif.x-unicode", "sans-serif");
+pref("font.name.monospace.x-unicode", "monospace");
+pref("font.size.fixed.x-unicode", 12);
+
+pref("font.name.serif.x-western", "serif");
+pref("font.name.sans-serif.x-western", "sans-serif");
+pref("font.name.monospace.x-western", "monospace");
+pref("font.size.fixed.x-western", 12);
+
+pref("font.name.serif.zh-CN", "serif");
+pref("font.name.sans-serif.zh-CN", "sans-serif");
+pref("font.name.monospace.zh-CN", "monospace");
+
+pref("font.name.serif.zh-HK", "serif");
+pref("font.name.sans-serif.zh-HK", "sans-serif");
+pref("font.name.monospace.zh-HK", "monospace");
+
+pref("font.name.serif.zh-TW", "serif");
+pref("font.name.sans-serif.zh-TW", "sans-serif");
+pref("font.name.monospace.zh-TW", "monospace");
+
+/* PostScript print module prefs */
+// pref("print.postscript.enabled", true);
+
+// On GTK2 platform, we should use topmost window level for the default window
+// level of <panel> element of XUL. GTK2 has only two window types. One is
+// normal top level window, other is popup window. The popup window is always
+// topmost window level, therefore, we are using normal top level window for
+// non-topmost panel, but it is pretty hacky. On some Window Managers, we have
+// 2 problems:
+// 1. The non-topmost panel steals focus from its parent window at showing.
+// 2. The parent of non-topmost panel is not activated when the panel is hidden.
+// So, we have no reasons we should use non-toplevel window for popup.
+pref("ui.panel.default_level_parent", true);
+
+pref("mousewheel.system_scroll_override_on_root_content.enabled", false);
+
+#if MOZ_WIDGET_GTK == 2
+pref("intl.ime.use_simple_context_on_password_field", true);
+#else
+pref("intl.ime.use_simple_context_on_password_field", false);
+#endif
+
+# enable new platform fontlist for linux on GTK platforms
+# temporary pref to allow flipping back to the existing
+# gfxPangoFontGroup/gfxFontconfigUtils code for handling system fonts
+
+#ifdef MOZ_WIDGET_GTK
+pref("gfx.font_rendering.fontconfig.fontlist.enabled", true);
+
+// maximum number of fonts to substitute for a generic
+pref("gfx.font_rendering.fontconfig.max_generic_substitutions", 3);
+#endif
+
+# XP_UNIX
+#endif
+#endif
+#endif
+
+#if defined(ANDROID) || defined(MOZ_B2G)
+
+pref("font.size.fixed.ar", 12);
+
+pref("font.default.el", "sans-serif");
+pref("font.size.fixed.el", 12);
+
+pref("font.size.fixed.he", 12);
+
+pref("font.default.x-cyrillic", "sans-serif");
+pref("font.size.fixed.x-cyrillic", 12);
+
+pref("font.default.x-unicode", "sans-serif");
+pref("font.size.fixed.x-unicode", 12);
+
+pref("font.default.x-western", "sans-serif");
+pref("font.size.fixed.x-western", 12);
+
+# ANDROID || MOZ_B2G
+#endif
+
+#if defined(MOZ_B2G)
+// Gonk, FxOS Simulator, B2G Desktop and Mulet.
+
+// TODO: some entries could probably be cleaned up.
+
+// ar
+
+pref("font.name.serif.el", "Droid Serif"); // not Charis SIL Compact, only has a few Greek chars
+pref("font.name.sans-serif.el", "Fira Sans");
+pref("font.name.monospace.el", "Fira Mono");
+
+pref("font.name.serif.he", "Charis SIL Compact");
+pref("font.name.sans-serif.he", "Fira Sans");
+pref("font.name.monospace.he", "Fira Mono");
+pref("font.name-list.sans-serif.he", "Droid Sans Hebrew, Fira Sans");
+
+pref("font.name.serif.ja", "Charis SIL Compact");
+pref("font.name.sans-serif.ja", "Fira Sans");
+pref("font.name.monospace.ja", "MotoyaLMaru");
+pref("font.name-list.sans-serif.ja", "Fira Sans, MotoyaLMaru, MotoyaLCedar, Droid Sans Japanese");
+pref("font.name-list.monospace.ja", "MotoyaLMaru, MotoyaLCedar, Fira Mono");
+
+pref("font.name.serif.ko", "Charis SIL Compact");
+pref("font.name.sans-serif.ko", "Fira Sans");
+pref("font.name.monospace.ko", "Fira Mono");
+
+pref("font.name.serif.th", "Charis SIL Compact");
+pref("font.name.sans-serif.th", "Fira Sans");
+pref("font.name.monospace.th", "Fira Mono");
+pref("font.name-list.sans-serif.th", "Fira Sans, Noto Sans Thai, Droid Sans Thai");
+
+pref("font.name.serif.x-cyrillic", "Charis SIL Compact");
+pref("font.name.sans-serif.x-cyrillic", "Fira Sans");
+pref("font.name.monospace.x-cyrillic", "Fira Mono");
+
+pref("font.name.serif.x-unicode", "Charis SIL Compact");
+pref("font.name.sans-serif.x-unicode", "Fira Sans");
+pref("font.name.monospace.x-unicode", "Fira Mono");
+
+pref("font.name.serif.x-western", "Charis SIL Compact");
+pref("font.name.sans-serif.x-western", "Fira Sans");
+pref("font.name.monospace.x-western", "Fira Mono");
+
+pref("font.name.serif.zh-CN", "Charis SIL Compact");
+pref("font.name.sans-serif.zh-CN", "Fira Sans");
+pref("font.name.monospace.zh-CN", "Fira Mono");
+pref("font.name-list.sans-serif.zh-CN", "Fira Sans,Droid Sans Fallback");
+
+pref("font.name.serif.zh-HK", "Charis SIL Compact");
+pref("font.name.sans-serif.zh-HK", "Fira Sans");
+pref("font.name.monospace.zh-HK", "Fira Mono");
+pref("font.name-list.sans-serif.zh-HK", "Fira Sans,Droid Sans Fallback");
+
+pref("font.name.serif.zh-TW", "Charis SIL Compact");
+pref("font.name.sans-serif.zh-TW", "Fira Sans");
+pref("font.name.monospace.zh-TW", "Fira Mono");
+pref("font.name-list.sans-serif.zh-TW", "Fira Sans,Droid Sans Fallback");
+
+pref("font.name.serif.x-math", "Latin Modern Math");
+pref("font.name-list.serif.x-math", "Latin Modern Math, XITS Math, Cambria Math, Libertinus Math, DejaVu Math TeX Gyre, TeX Gyre Bonum Math, TeX Gyre Pagella Math, TeX Gyre Schola, TeX Gyre Termes Math, STIX Math, Asana Math, STIXGeneral, DejaVu Serif, DejaVu Sans, Charis SIL Compact");
+pref("font.name.sans-serif.x-math", "Fira Sans");
+pref("font.name.monospace.x-math", "Fira Mono");
+
+#elif defined(ANDROID)
+// We use the bundled fonts for Firefox for Android
+
+// ar
+
+pref("font.name.serif.el", "Droid Serif"); // not Charis SIL Compact, only has a few Greek chars
+pref("font.name.sans-serif.el", "Clear Sans");
+pref("font.name.monospace.el", "Droid Sans Mono");
+pref("font.name-list.serif.el", "Noto Serif");
+pref("font.name-list.sans-serif.el", "Clear Sans, Roboto, Droid Sans");
+
+pref("font.name.serif.he", "Droid Serif");
+pref("font.name.sans-serif.he", "Clear Sans");
+pref("font.name.monospace.he", "Droid Sans Mono");
+pref("font.name-list.serif.he", "Noto Serif");
+pref("font.name-list.sans-serif.he", "Droid Sans Hebrew, Clear Sans, Droid Sans");
+
+pref("font.name.serif.ja", "Charis SIL Compact");
+pref("font.name.sans-serif.ja", "Clear Sans");
+pref("font.name.monospace.ja", "MotoyaLMaru");
+pref("font.name-list.serif.ja", "Noto Serif, Droid Serif");
+pref("font.name-list.sans-serif.ja", "Clear Sans, Roboto, Droid Sans, MotoyaLMaru, MotoyaLCedar, Noto Sans JP, Noto Sans CJK JP, Droid Sans Japanese");
+pref("font.name-list.monospace.ja", "MotoyaLMaru, MotoyaLCedar, Droid Sans Mono CJK JP, Droid Sans Mono");
+
+pref("font.name.serif.ko", "Charis SIL Compact");
+pref("font.name.sans-serif.ko", "Clear Sans");
+pref("font.name.monospace.ko", "Droid Sans Mono");
+pref("font.name-list.serif.ko", "Noto Serif, Droid Serif, HYSerif");
+pref("font.name-list.sans-serif.ko", "SmartGothic, NanumGothic, Noto Sans KR, Noto Sans CJK KR, DroidSansFallback, Droid Sans Fallback");
+pref("font.name-list.monospace.ko", "Noto Sans Mono CJK KR");
+
+pref("font.name.serif.th", "Charis SIL Compact");
+pref("font.name.sans-serif.th", "Clear Sans");
+pref("font.name.monospace.th", "Droid Sans Mono");
+pref("font.name-list.serif.th", "Noto Serif, Droid Serif");
+pref("font.name-list.sans-serif.th", "Droid Sans Thai, Clear Sans, Droid Sans");
+
+pref("font.name.serif.x-cyrillic", "Charis SIL Compact");
+pref("font.name.sans-serif.x-cyrillic", "Clear Sans");
+pref("font.name.monospace.x-cyrillic", "Droid Sans Mono");
+pref("font.name-list.serif.x-cyrillic", "Noto Serif, Droid Serif");
+pref("font.name-list.sans-serif.x-cyrillic", "Clear Sans, Roboto, Droid Sans");
+
+pref("font.name.serif.x-unicode", "Charis SIL Compact");
+pref("font.name.sans-serif.x-unicode", "Clear Sans");
+pref("font.name.monospace.x-unicode", "Droid Sans Mono");
+pref("font.name-list.serif.x-unicode", "Noto Serif, Droid Serif");
+pref("font.name-list.sans-serif.x-unicode", "Clear Sans, Roboto, Droid Sans");
+
+pref("font.name.serif.x-western", "Charis SIL Compact");
+pref("font.name.sans-serif.x-western", "Clear Sans");
+pref("font.name.monospace.x-western", "Droid Sans Mono");
+pref("font.name-list.serif.x-western", "Noto Serif, Droid Serif");
+pref("font.name-list.sans-serif.x-western", "Clear Sans, Roboto, Droid Sans");
+
+pref("font.name.serif.zh-CN", "Charis SIL Compact");
+pref("font.name.sans-serif.zh-CN", "Clear Sans");
+pref("font.name.monospace.zh-CN", "Droid Sans Mono");
+pref("font.name-list.serif.zh-CN", "Noto Serif, Droid Serif, Droid Sans Fallback");
+pref("font.name-list.sans-serif.zh-CN", "Roboto, Droid Sans, Noto Sans SC, Noto Sans CJK SC, Droid Sans Fallback");
+pref("font.name-list.monospace.zh-CN", "Noto Sans Mono CJK SC, Droid Sans Fallback");
+
+pref("font.name.serif.zh-HK", "Charis SIL Compact");
+pref("font.name.sans-serif.zh-HK", "Clear Sans");
+pref("font.name.monospace.zh-HK", "Droid Sans Mono");
+pref("font.name-list.serif.zh-HK", "Noto Serif, Droid Serif, Droid Sans Fallback");
+pref("font.name-list.sans-serif.zh-HK", "Roboto, Droid Sans, Noto Sans TC, Noto Sans SC, Noto Sans CJK TC, Droid Sans Fallback");
+pref("font.name-list.monospace.zh-HK", "Noto Sans Mono CJK TC, Droid Sans Fallback");
+
+pref("font.name.serif.zh-TW", "Charis SIL Compact");
+pref("font.name.sans-serif.zh-TW", "Clear Sans");
+pref("font.name.monospace.zh-TW", "Droid Sans Mono");
+pref("font.name-list.serif.zh-TW", "Noto Serif, Droid Serif, Droid Sans Fallback");
+pref("font.name-list.sans-serif.zh-TW", "Roboto, Droid Sans, Noto Sans TC, Noto Sans SC, Noto Sans CJK TC, Droid Sans Fallback");
+pref("font.name-list.monospace.zh-TW", "Noto Sans Mono CJK TC, Droid Sans Fallback");
+
+pref("font.name.serif.x-math", "Latin Modern Math");
+pref("font.name-list.serif.x-math", "Latin Modern Math, XITS Math, Cambria Math, Libertinus Math, DejaVu Math TeX Gyre, TeX Gyre Bonum Math, TeX Gyre Pagella Math, TeX Gyre Schola, TeX Gyre Termes Math, STIX Math, Asana Math, STIXGeneral, DejaVu Serif, DejaVu Sans, Charis SIL Compact");
+pref("font.name.sans-serif.x-math", "Clear Sans");
+pref("font.name.monospace.x-math", "Droid Sans Mono");
+
+#endif
+
+#if OS_ARCH==AIX
+
+// Override default Japanese fonts
+pref("font.name.serif.ja", "dt-interface system-jisx0208.1983-0");
+pref("font.name.sans-serif.ja", "dt-interface system-jisx0208.1983-0");
+pref("font.name.monospace.ja", "dt-interface user-jisx0208.1983-0");
+
+// Override default Cyrillic fonts
+pref("font.name.serif.x-cyrillic", "dt-interface system-iso8859-5");
+pref("font.name.sans-serif.x-cyrillic", "dt-interface system-iso8859-5");
+pref("font.name.monospace.x-cyrillic", "dt-interface user-iso8859-5");
+
+// Override default Unicode fonts
+pref("font.name.serif.x-unicode", "dt-interface system-ucs2.cjk_japan-0");
+pref("font.name.sans-serif.x-unicode", "dt-interface system-ucs2.cjk_japan-0");
+pref("font.name.monospace.x-unicode", "dt-interface user-ucs2.cjk_japan-0");
+
+# AIX
+#endif
+
+// Login Manager prefs
+pref("signon.rememberSignons", true);
+pref("signon.rememberSignons.visibilityToggle", true);
+pref("signon.autofillForms", true);
+pref("signon.autofillForms.http", false);
+pref("signon.autologin.proxy", false);
+pref("signon.formlessCapture.enabled", true);
+pref("signon.storeWhenAutocompleteOff", true);
+pref("signon.debug", false);
+pref("signon.recipes.path", "chrome://passwordmgr/content/recipes.json");
+pref("signon.schemeUpgrades", false);
+// This temporarily prevents the master password to reprompt for autocomplete.
+pref("signon.masterPasswordReprompt.timeout_ms", 900000); // 15 Minutes
+
+// Satchel (Form Manager) prefs
+pref("browser.formfill.debug", false);
+pref("browser.formfill.enable", true);
+pref("browser.formfill.expire_days", 180);
+pref("browser.formfill.saveHttpsForms", true);
+pref("browser.formfill.agedWeight", 2);
+pref("browser.formfill.bucketSize", 1);
+pref("browser.formfill.maxTimeGroupings", 25);
+pref("browser.formfill.timeGroupingSize", 604800);
+pref("browser.formfill.boundaryWeight", 25);
+pref("browser.formfill.prefixWeight", 5);
+
+// Zoom prefs
+pref("browser.zoom.full", false);
+pref("zoom.minPercent", 30);
+pref("zoom.maxPercent", 300);
+pref("toolkit.zoomManager.zoomValues", ".3,.5,.67,.8,.9,1,1.1,1.2,1.33,1.5,1.7,2,2.4,3");
+
+//
+// Image-related prefs
+//
+
+// The maximum size, in bytes, of the decoded images we cache
+pref("image.cache.size", 5242880);
+
+// A weight, from 0-1000, to place on time when comparing to size.
+// Size is given a weight of 1000 - timeweight.
+pref("image.cache.timeweight", 500);
+
+// Decode all images automatically on load, ignoring our normal heuristics.
+pref("image.decode-immediately.enabled", false);
+
+// Whether we attempt to downscale images during decoding.
+pref("image.downscale-during-decode.enabled", true);
+
+// The default Accept header sent for images loaded over HTTP(S)
+pref("image.http.accept", "*/*");
+
+// The threshold for inferring that changes to an <img> element's |src|
+// attribute by JavaScript represent an animation, in milliseconds. If the |src|
+// attribute is changing more frequently than this value, then we enter a
+// special "animation mode" which is designed to eliminate flicker. Set to 0 to
+// disable.
+pref("image.infer-src-animation.threshold-ms", 2000);
+
+//
+// Image memory management prefs
+//
+
+// Discards inactive image frames and re-decodes them on demand from
+// compressed data.
+pref("image.mem.discardable", true);
+
+// Allows image locking of decoded image data in content processes.
+pref("image.mem.allow_locking_in_content_processes", true);
+
+// Chunk size for calls to the image decoders
+pref("image.mem.decode_bytes_at_a_time", 16384);
+
+// Minimum timeout for expiring unused images from the surface cache, in
+// milliseconds. This controls how long we store cached temporary surfaces.
+pref("image.mem.surfacecache.min_expiration_ms", 60000); // 60s
+
+// Maximum size for the surface cache, in kilobytes.
+pref("image.mem.surfacecache.max_size_kb", 1048576); // 1GB
+
+// The surface cache's size, within the constraints of the maximum size set
+// above, is determined as a fraction of main memory size. The size factor is
+// interpreted as a reciprocal, so a size factor of 4 means to use no more than
+// 1/4 of main memory. The default should be a good balance for most systems.
+pref("image.mem.surfacecache.size_factor", 4);
+
+// How much of the data in the surface cache is discarded when we get a memory
+// pressure notification, as a fraction. The discard factor is interpreted as a
+// reciprocal, so a discard factor of 1 means to discard everything in the
+// surface cache on memory pressure, a discard factor of 2 means to discard half
+// of the data, and so forth. The default should be a good balance for desktop
+// and laptop systems, where we never discard visible images.
+pref("image.mem.surfacecache.discard_factor", 1);
+
+// How many threads we'll use for multithreaded decoding. If < 0, will be
+// automatically determined based on the system's number of cores.
+pref("image.multithreaded_decoding.limit", -1);
+
+// Limit for the canvas image cache. 0 means we don't limit the size of the
+// cache.
+pref("canvas.image.cache.limit", 0);
+
+// WebGL prefs
+#ifdef ANDROID
+// Disable MSAA on mobile.
+pref("gl.msaa-level", 0);
+#else
+pref("gl.msaa-level", 2);
+#endif
+pref("gl.require-hardware", false);
+#ifdef XP_MACOSX
+pref("gl.multithreaded", true);
+#endif
+pref("gl.ignore-dx-interop2-blacklist", false);
+
+pref("webgl.force-enabled", false);
+pref("webgl.disabled", false);
+pref("webgl.disable-angle", false);
+pref("webgl.disable-wgl", false);
+pref("webgl.min_capability_mode", false);
+pref("webgl.disable-extensions", false);
+pref("webgl.msaa-force", false);
+pref("webgl.prefer-16bpp", false);
+pref("webgl.default-no-alpha", false);
+pref("webgl.force-layers-readback", false);
+pref("webgl.lose-context-on-memory-pressure", false);
+pref("webgl.can-lose-context-in-foreground", true);
+pref("webgl.restore-context-when-visible", true);
+pref("webgl.max-warnings-per-context", 32);
+pref("webgl.enable-draft-extensions", false);
+pref("webgl.enable-privileged-extensions", false);
+pref("webgl.bypass-shader-validation", false);
+pref("webgl.disable-fail-if-major-performance-caveat", false);
+pref("webgl.disable-DOM-blit-uploads", false);
+pref("webgl.allow-fb-invalidation", false);
+pref("webgl.webgl2-compat-mode", false);
+
+pref("webgl.enable-webgl2", true);
+
+#ifdef RELEASE_OR_BETA
+// Keep this disabled on Release and Beta for now. (see bug 1171228)
+pref("webgl.enable-debug-renderer-info", false);
+#else
+pref("webgl.enable-debug-renderer-info", true);
+#endif
+
+pref("webgl.renderer-string-override", "");
+pref("webgl.vendor-string-override", "");
+
+#ifdef XP_WIN
+pref("webgl.angle.try-d3d11", true);
+pref("webgl.angle.force-d3d11", false);
+pref("webgl.angle.force-warp", false);
+pref("webgl.dxgl.enabled", true);
+pref("webgl.dxgl.needs-finish", false);
+#endif
+
+pref("gfx.offscreencanvas.enabled", false);
+
+#ifdef MOZ_WIDGET_GONK
+pref("gfx.gralloc.fence-with-readpixels", false);
+#endif
+
+// Stagefright prefs
+pref("stagefright.force-enabled", false);
+pref("stagefright.disabled", false);
+
+// sendbuffer of 0 means use OS default, sendbuffer unset means use
+// gecko default which varies depending on windows version and is OS
+// default on non windows
+// pref("network.tcp.sendbuffer", 0);
+
+// TCP Keepalive
+pref("network.tcp.keepalive.enabled", true);
+// Default idle time before first TCP keepalive probe; same time for interval
+// between successful probes. Can be overridden in socket transport API.
+// Win, Linux and Mac.
+pref("network.tcp.keepalive.idle_time", 600); // seconds; 10 mins
+// Default timeout for retransmission of unack'd keepalive probes.
+// Win and Linux only; not configurable on Mac.
+#if defined(XP_UNIX) && !defined(XP_MACOSX) || defined(XP_WIN)
+pref("network.tcp.keepalive.retry_interval", 1); // seconds
+#endif
+// Default maximum probe retransmissions.
+// Linux only; not configurable on Win and Mac; fixed at 10 and 8 respectively.
+#if defined(XP_UNIX) && !defined(XP_MACOSX)
+pref("network.tcp.keepalive.probe_count", 4);
+#endif
+
+// Whether to disable acceleration for all widgets.
+pref("layers.acceleration.disabled", false);
+// Preference that when switched at runtime will run a series of benchmarks
+// and output the result to stderr.
+pref("layers.bench.enabled", false);
+
+#if defined(XP_WIN) && defined(NIGHTLY_BUILD)
+pref("layers.gpu-process.dev.enabled", true);
+#endif
+
+// Whether to force acceleration on, ignoring blacklists.
+#ifdef ANDROID
+// bug 838603 -- on Android, accidentally blacklisting OpenGL layers
+// means a startup crash for everyone.
+// Temporarily force-enable GL compositing. This is default-disabled
+// deep within the bowels of the widgetry system. Remove me when GL
+// compositing isn't default disabled in widget/android.
+pref("layers.acceleration.force-enabled", true);
+#else
+pref("layers.acceleration.force-enabled", false);
+#endif
+
+pref("layers.acceleration.draw-fps", false);
+
+// Enable DEAA antialiasing for transformed layers in the compositor
+#if !defined(MOZ_WIDGET_GONK) && !defined(MOZ_WIDGET_ANDROID)
+// Desktop prefs
+pref("layers.deaa.enabled", true);
+#else
+// Mobile prefs
+pref("layers.deaa.enabled", false);
+#endif
+
+pref("layers.dump", false);
+#ifdef MOZ_DUMP_PAINTING
+// If we're dumping layers, also dump the texture data
+pref("layers.dump-texture", false);
+pref("layers.dump-decision", false);
+pref("layers.dump-client-layers", false);
+pref("layers.dump-host-layers", false);
+#endif
+pref("layers.draw-borders", false);
+pref("layers.draw-tile-borders", false);
+pref("layers.draw-bigimage-borders", false);
+pref("layers.frame-counter", false);
+pref("layers.enable-tiles", false);
+pref("layers.single-tile.enabled", true);
+pref("layers.low-precision-buffer", false);
+pref("layers.progressive-paint", false);
+pref("layers.tile-width", 256);
+pref("layers.tile-height", 256);
+pref("layers.child-process-shutdown", true);
+// Max number of layers per container. See Overwrite in mobile prefs.
+pref("layers.max-active", -1);
+// If this is set the tile size will only be treated as a suggestion.
+// On B2G we will round this to the stride of the underlying allocation.
+// On any platform we may later use the screen size and ignore
+// tile-width/tile-height entirely. Its recommended to turn this off
+// if you change the tile size.
+pref("layers.tiles.adjust", true);
+
+// Compositor target frame rate. NOTE: If vsync is enabled the compositor
+// frame rate will still be capped.
+// -1 -> default (match layout.frame_rate or 60 FPS)
+// 0 -> full-tilt mode: Recomposite even if not transaction occured.
+pref("layers.offmainthreadcomposition.frame-rate", -1);
+
+#ifdef XP_MACOSX
+pref("layers.enable-tiles", true);
+pref("layers.tile-width", 512);
+pref("layers.tile-height", 512);
+pref("layers.tiles.edge-padding", false);
+#endif
+
+#ifdef MOZ_WIDGET_ANDROID
+pref("layers.tiles.edge-padding", true);
+#endif
+
+// Whether to animate simple opacity and transforms on the compositor
+pref("layers.offmainthreadcomposition.async-animations", true);
+
+// Whether to log information about off main thread animations to stderr
+pref("layers.offmainthreadcomposition.log-animations", false);
+
+pref("layers.bufferrotation.enabled", true);
+
+pref("layers.componentalpha.enabled", true);
+pref("layers.draw-mask-debug", false);
+
+// Use the DT-backend implemented PushLayer
+pref("gfx.content.use-native-pushlayer", false);
+
+pref("gfx.content.always-paint", false);
+
+#ifdef ANDROID
+pref("gfx.apitrace.enabled",false);
+#endif
+
+#ifdef MOZ_X11
+pref("gfx.content.use-native-pushlayer", true);
+#ifdef MOZ_WIDGET_GTK
+pref("gfx.xrender.enabled",false);
+#endif
+#endif
+
+#ifdef XP_WIN
+pref("gfx.content.use-native-pushlayer", true);
+
+// Whether to disable the automatic detection and use of direct2d.
+pref("gfx.direct2d.disabled", false);
+
+// Whether to attempt to enable Direct2D regardless of automatic detection or
+// blacklisting
+pref("gfx.direct2d.force-enabled", false);
+
+pref("layers.prefer-opengl", false);
+pref("layers.prefer-d3d9", false);
+// Disable for now due to bug 1304360
+pref("layers.allow-d3d9-fallback", false);
+#endif
+
+// Copy-on-write canvas
+pref("layers.shared-buffer-provider.enabled", true);
+
+#ifdef XP_WIN
+pref("layers.shared-buffer-provider.enabled", false);
+#endif
+
+#ifdef XP_MACOSX
+// cf. Bug 1324908
+pref("layers.shared-buffer-provider.enabled", false);
+#endif
+
+// Force all possible layers to be always active layers
+pref("layers.force-active", false);
+
+// Never use gralloc surfaces, even when they're available on this
+// platform and are the optimal surface type.
+pref("layers.gralloc.disable", false);
+
+// Enable/Disable the geolocation API for content
+pref("geo.enabled", true);
+
+// Timeout for outbound network geolocation provider XHR
+pref("geo.wifi.xhr.timeout", 60000);
+
+// Enable/Disable the orientation API for content
+pref("device.sensors.enabled", true);
+
+// Enable/Disable the device storage API for content
+pref("device.storage.enabled", false);
+
+// Toggle which thread the HTML5 parser uses for stream parsing
+pref("html5.offmainthread", true);
+// Time in milliseconds between the time a network buffer is seen and the
+// timer firing when the timer hasn't fired previously in this parse in the
+// off-the-main-thread HTML5 parser.
+pref("html5.flushtimer.initialdelay", 120);
+// Time in milliseconds between the time a network buffer is seen and the
+// timer firing when the timer has already fired previously in this parse.
+pref("html5.flushtimer.subsequentdelay", 120);
+
+// Push/Pop/Replace State prefs
+pref("browser.history.maxStateObjectSize", 655360);
+
+pref("browser.meta_refresh_when_inactive.disabled", false);
+
+// XPInstall prefs
+pref("xpinstall.whitelist.required", true);
+// Only Firefox requires add-on signatures
+pref("xpinstall.signatures.required", false);
+pref("extensions.alwaysUnpack", false);
+pref("extensions.minCompatiblePlatformVersion", "2.0");
+pref("extensions.webExtensionsMinPlatformVersion", "42.0a1");
+
+// Other webextensions prefs
+pref("extensions.webextensions.keepStorageOnUninstall", false);
+pref("extensions.webextensions.keepUuidOnUninstall", false);
+
+pref("network.buffer.cache.count", 24);
+pref("network.buffer.cache.size", 32768);
+
+// Desktop Notification
+pref("notification.feature.enabled", false);
+
+// Web Notification
+pref("dom.webnotifications.enabled", true);
+pref("dom.webnotifications.serviceworker.enabled", true);
+pref("dom.webnotifications.requireinteraction.count", 3);
+#ifdef NIGHTLY_BUILD
+pref("dom.webnotifications.requireinteraction.enabled", true);
+#else
+pref("dom.webnotifications.requireinteraction.enabled", false);
+#endif
+
+// Alert animation effect, name is disableSlidingEffect for backwards-compat.
+pref("alerts.disableSlidingEffect", false);
+// Show favicons in web notifications.
+pref("alerts.showFavicons", false);
+
+// DOM full-screen API.
+pref("full-screen-api.enabled", false);
+#ifdef RELEASE_OR_BETA
+pref("full-screen-api.unprefix.enabled", false);
+#else
+pref("full-screen-api.unprefix.enabled", true);
+#endif
+pref("full-screen-api.allow-trusted-requests-only", true);
+pref("full-screen-api.pointer-lock.enabled", true);
+// transition duration of fade-to-black and fade-from-black, unit: ms
+#ifndef MOZ_WIDGET_GTK
+pref("full-screen-api.transition-duration.enter", "200 200");
+pref("full-screen-api.transition-duration.leave", "200 200");
+#else
+pref("full-screen-api.transition-duration.enter", "0 0");
+pref("full-screen-api.transition-duration.leave", "0 0");
+#endif
+// timeout for black screen in fullscreen transition, unit: ms
+pref("full-screen-api.transition.timeout", 1000);
+// time for the warning box stays on the screen before sliding out, unit: ms
+pref("full-screen-api.warning.timeout", 3000);
+// delay for the warning box to show when pointer stays on the top, unit: ms
+pref("full-screen-api.warning.delay", 500);
+
+// DOM pointerlock API
+pref("pointer-lock-api.prefixed.enabled", false);
+// time for the warning box stays on the screen before sliding out, unit: ms
+pref("pointer-lock-api.warning.timeout", 3000);
+
+// DOM idle observers API
+pref("dom.idle-observers-api.enabled", true);
+
+// Time limit, in milliseconds, for EventStateManager::IsHandlingUserInput().
+// Used to detect long running handlers of user-generated events.
+pref("dom.event.handling-user-input-time-limit", 1000);
+
+// Whether we should layerize all animated images (if otherwise possible).
+pref("layout.animated-image-layers.enabled", false);
+
+pref("dom.vibrator.enabled", true);
+pref("dom.vibrator.max_vibrate_ms", 10000);
+pref("dom.vibrator.max_vibrate_list_len", 128);
+
+// Battery API
+pref("dom.battery.enabled", true);
+
+// Push
+
+pref("dom.push.enabled", false);
+
+pref("dom.push.loglevel", "error");
+
+pref("dom.push.serverURL", "wss://push.services.mozilla.com/");
+pref("dom.push.userAgentID", "");
+
+// The maximum number of push messages that a service worker can receive
+// without user interaction.
+pref("dom.push.maxQuotaPerSubscription", 16);
+
+// The maximum number of recent message IDs to store for each push
+// subscription, to avoid duplicates for unacknowledged messages.
+pref("dom.push.maxRecentMessageIDsPerSubscription", 10);
+
+// The delay between receiving a push message and updating the quota for a
+// subscription.
+pref("dom.push.quotaUpdateDelay", 3000); // 3 seconds
+
+// Is the network connection allowed to be up?
+// This preference should be used in UX to enable/disable push.
+pref("dom.push.connection.enabled", true);
+
+// Exponential back-off start is 5 seconds like in HTTP/1.1.
+// Maximum back-off is pingInterval.
+pref("dom.push.retryBaseInterval", 5000);
+
+// Interval at which to ping PushServer to check connection status. In
+// milliseconds. If no reply is received within requestTimeout, the connection
+// is considered closed.
+pref("dom.push.pingInterval", 1800000); // 30 minutes
+
+// How long before we timeout
+pref("dom.push.requestTimeout", 10000);
+
+// WebPush prefs:
+pref("dom.push.http2.reset_retry_count_after_ms", 60000);
+pref("dom.push.http2.maxRetries", 2);
+pref("dom.push.http2.retryInterval", 5000);
+
+// WebNetworkStats
+pref("dom.mozNetworkStats.enabled", false);
+
+// WebSettings
+pref("dom.mozSettings.enabled", false);
+pref("dom.mozPermissionSettings.enabled", false);
+
+// W3C touch events
+// 0 - disabled, 1 - enabled, 2 - autodetect
+// Autodetection is currently only supported on Windows and GTK3
+#if defined(XP_MACOSX)
+pref("dom.w3c_touch_events.enabled", 0);
+#else
+pref("dom.w3c_touch_events.enabled", 2);
+#endif
+
+// W3C draft pointer events
+pref("dom.w3c_pointer_events.enabled", false);
+
+// W3C pointer events draft
+pref("dom.w3c_pointer_events.implicit_capture", false);
+
+// W3C draft ImageCapture API
+pref("dom.imagecapture.enabled", false);
+
+// W3C MediaDevices devicechange event
+pref("media.ondevicechange.enabled", true);
+
+// W3C MediaDevices devicechange fake event
+pref("media.ondevicechange.fakeDeviceChangeEvent.enabled", false);
+
+// W3C touch-action css property (related to touch and pointer events)
+// Note that we turn this on even on platforms/configurations where touch
+// events are not supported (e.g. OS X, or Windows with e10s disabled). For
+// those platforms we don't handle touch events anyway so it's conceptually
+// a no-op.
+pref("layout.css.touch_action.enabled", true);
+
+// Enables some assertions in nsStyleContext that are too expensive
+// for general use, but might be useful to enable for specific tests.
+// This only has an effect in DEBUG-builds.
+pref("layout.css.expensive-style-struct-assertions.enabled", false);
+
+// enable JS dump() function.
+pref("browser.dom.window.dump.enabled", false);
+
+#if defined(MOZ_WIDGET_GONK) || defined(MOZ_WIDGET_ANDROID)
+// Network Information API
+pref("dom.netinfo.enabled", true);
+#else
+pref("dom.netinfo.enabled", false);
+#endif
+
+#ifdef XP_WIN
+// On 32-bit Windows, fire a low-memory notification if we have less than this
+// many mb of virtual address space available.
+pref("memory.low_virtual_memory_threshold_mb", 128);
+
+// On Windows 32-bit, fire a low-memory notification if we have less
+// than this many mb of commit space (physical memory plus page file) left.
+pref("memory.low_commit_space_threshold_mb", 128);
+
+// On Windows 32-bit, fire a low-memory notification if we have less
+// than this many mb of physical memory available on the whole machine.
+pref("memory.low_physical_memory_threshold_mb", 0);
+
+// On Windows 32-bit, don't fire a low-memory notification because of
+// low available physical memory or low commit space more than once every
+// low_memory_notification_interval_ms.
+pref("memory.low_memory_notification_interval_ms", 10000);
+#endif
+
+// How long must we wait before declaring that a window is a "ghost" (i.e., a
+// likely leak)? This should be longer than it usually takes for an eligible
+// window to be collected via the GC/CC.
+pref("memory.ghost_window_timeout_seconds", 60);
+
+// Disable freeing dirty pages when minimizing memory.
+pref("memory.free_dirty_pages", false);
+
+// Disable the Linux-specific, system-wide memory reporter.
+#ifdef XP_LINUX
+pref("memory.system_memory_reporter", false);
+#endif
+
+// Don't dump memory reports on OOM, by default.
+pref("memory.dump_reports_on_oom", false);
+
+// Number of stack frames to capture in createObjectURL for about:memory.
+pref("memory.blob_report.stack_frames", 0);
+
+// comma separated list of domain origins (e.g. https://domain.com) that still
+// need localStorage in the frameworker
+pref("social.whitelist", "https://mozsocial.cliqz.com");
+// comma separated list of domain origins (e.g. https://domain.com) for
+// directory websites (e.g. AMO) that can install providers for other sites
+pref("social.directories", "https://activations.cdn.mozilla.net");
+// remote-install allows any website to activate a provider, with extended UI
+// notifying user of installation. we can later pref off remote install if
+// necessary. This does not affect whitelisted and directory installs.
+pref("social.remote-install.enabled", true);
+pref("social.toast-notifications.enabled", true);
+
+// Disable idle observer fuzz, because only privileged content can access idle
+// observers (bug 780507).
+pref("dom.idle-observers-api.fuzz_time.disabled", true);
+
+// Minimum delay in milliseconds between network activity notifications (0 means
+// no notifications). The delay is the same for both download and upload, though
+// they are handled separately. This pref is only read once at startup:
+// a restart is required to enable a new value.
+pref("network.activity.blipIntervalMilliseconds", 0);
+
+// If true, reuse the same global for everything loaded by the component loader
+// (JS components, JSMs, etc). This saves memory, but makes it possible for
+// the scripts to interfere with each other. A restart is required for this
+// to take effect.
+pref("jsloader.reuseGlobal", false);
+
+// When we're asked to take a screenshot, don't wait more than 2000ms for the
+// event loop to become idle before actually taking the screenshot.
+pref("dom.browserElement.maxScreenshotDelayMS", 2000);
+
+// Whether we should show the placeholder when the element is focused but empty.
+pref("dom.placeholder.show_on_focus", true);
+
+// VR is disabled by default in release and enabled for nightly and aurora
+#ifdef RELEASE_OR_BETA
+pref("dom.vr.enabled", false);
+#else
+pref("dom.vr.enabled", true);
+#endif
+pref("dom.vr.oculus.enabled", true);
+// OSVR device
+pref("dom.vr.osvr.enabled", false);
+// OpenVR device
+pref("dom.vr.openvr.enabled", false);
+// Pose prediction reduces latency effects by returning future predicted HMD
+// poses to callers of the WebVR API. This currently only has an effect for
+// Oculus Rift on SDK 0.8 or greater. It is disabled by default for now due to
+// frame uniformity issues with e10s.
+pref("dom.vr.poseprediction.enabled", false);
+// path to openvr DLL
+pref("gfx.vr.openvr-runtime", "");
+// path to OSVR DLLs
+pref("gfx.vr.osvr.utilLibPath", "");
+pref("gfx.vr.osvr.commonLibPath", "");
+pref("gfx.vr.osvr.clientLibPath", "");
+pref("gfx.vr.osvr.clientKitLibPath", "");
+
+// MMS UA Profile settings
+pref("wap.UAProf.url", "");
+pref("wap.UAProf.tagname", "x-wap-profile");
+
+// MMS version 1.1 = 0x11 (or decimal 17)
+// MMS version 1.3 = 0x13 (or decimal 19)
+// @see OMA-TS-MMS_ENC-V1_3-20110913-A clause 7.3.34
+pref("dom.mms.version", 19);
+
+pref("dom.mms.requestStatusReport", true);
+
+// Retrieval mode for MMS
+// manual: Manual retrieval mode.
+// automatic: Automatic retrieval mode even in roaming.
+// automatic-home: Automatic retrieval mode in home network.
+// never: Never retrieval mode.
+pref("dom.mms.retrieval_mode", "manual");
+
+pref("dom.mms.sendRetryCount", 3);
+pref("dom.mms.sendRetryInterval", "10000,60000,180000");
+
+pref("dom.mms.retrievalRetryCount", 4);
+pref("dom.mms.retrievalRetryIntervals", "60000,300000,600000,1800000");
+// Numeric default service id for MMS API calls with |serviceId| parameter
+// omitted.
+pref("dom.mms.defaultServiceId", 0);
+// Debug enabler for MMS.
+pref("mms.debugging.enabled", false);
+
+// Request read report while sending MMS.
+pref("dom.mms.requestReadReport", true);
+
+// Number of RadioInterface instances to create.
+pref("ril.numRadioInterfaces", 0);
+
+// If the user puts a finger down on an element and we think the user
+// might be executing a pan gesture, how long do we wait before
+// tentatively deciding the gesture is actually a tap and activating
+// the target element?
+pref("ui.touch_activation.delay_ms", 100);
+
+// If the user has clicked an element, how long do we keep the
+// :active state before it is cleared by the mouse sequences
+// fired after a touchstart/touchend.
+pref("ui.touch_activation.duration_ms", 10);
+
+// nsMemoryInfoDumper can watch a fifo in the temp directory and take various
+// actions when the fifo is written to. Disable this in general.
+pref("memory_info_dumper.watch_fifo.enabled", false);
+
+// If minInterval is 0, the check will only happen
+// when the service has a strong suspicion we are in a captive portal
+pref("network.captive-portal-service.minInterval", 60000); // 60 seconds
+pref("network.captive-portal-service.maxInterval", 1500000); // 25 minutes
+// Every 10 checks, the delay is increased by a factor of 5
+pref("network.captive-portal-service.backoffFactor", "5.0");
+pref("network.captive-portal-service.enabled", false);
+
+pref("captivedetect.canonicalURL", "http://detectportal.firefox.com/success.txt");
+pref("captivedetect.canonicalContent", "success\n");
+pref("captivedetect.maxWaitingTime", 5000);
+pref("captivedetect.pollingTime", 3000);
+pref("captivedetect.maxRetryCount", 5);
+
+#ifdef RELEASE_OR_BETA
+pref("dom.forms.inputmode", false);
+#else
+pref("dom.forms.inputmode", true);
+#endif
+
+// InputMethods for soft keyboards in B2G
+pref("dom.mozInputMethod.enabled", false);
+
+pref("dom.flyweb.enabled", false);
+
+// Enable mapped array buffer by default.
+pref("dom.mapped_arraybuffer.enabled", true);
+
+// The tables used for Safebrowsing phishing and malware checks.
+pref("urlclassifier.malwareTable", "goog-malware-shavar,goog-unwanted-shavar,test-malware-simple,test-unwanted-simple");
+
+#ifdef MOZILLA_OFFICIAL
+// In the official build, we are allowed to use google's private
+// phishing list "goog-phish-shavar". See Bug 1288840.
+pref("urlclassifier.phishTable", "goog-phish-shavar,test-phish-simple");
+#else
+pref("urlclassifier.phishTable", "googpub-phish-shavar,test-phish-simple");
+#endif
+
+// Tables for application reputation.
+pref("urlclassifier.downloadBlockTable", "goog-badbinurl-shavar");
+
+#ifdef XP_WIN
+ // Only download the whitelist on Windows, since the whitelist is
+ // only useful for suppressing remote lookups for signed binaries which we can
+ // only verify on Windows (Bug 974579). Other platforms always do remote lookups.
+pref("urlclassifier.downloadAllowTable", "goog-downloadwhite-digest256");
+#else
+pref("urlclassifier.downloadAllowTable", "");
+#endif
+
+pref("urlclassifier.disallow_completions", "test-malware-simple,test-phish-simple,test-unwanted-simple,test-track-simple,test-trackwhite-simple,test-block-simple,goog-downloadwhite-digest256,base-track-digest256,mozstd-trackwhite-digest256,content-track-digest256,mozplugin-block-digest256,mozplugin2-block-digest256");
+
+// The table and update/gethash URLs for Safebrowsing phishing and malware
+// checks.
+pref("urlclassifier.trackingTable", "test-track-simple,base-track-digest256");
+pref("urlclassifier.trackingWhitelistTable", "test-trackwhite-simple,mozstd-trackwhite-digest256");
+
+// The number of random entries to send with a gethash request.
+pref("urlclassifier.gethashnoise", 4);
+
+// Gethash timeout for Safebrowsing.
+pref("urlclassifier.gethash.timeout_ms", 5000);
+
+// If an urlclassifier table has not been updated in this number of seconds,
+// a gethash request will be forced to check that the result is still in
+// the database.
+pref("urlclassifier.max-complete-age", 2700);
+
+// Name of the about: page contributed by safebrowsing to handle display of error
+// pages on phishing/malware hits. (bug 399233)
+pref("urlclassifier.alternate_error_page", "blocked");
+
+// Enable phishing protection
+pref("browser.safebrowsing.phishing.enabled", true);
+
+// Enable malware protection
+pref("browser.safebrowsing.malware.enabled", true);
+
+pref("browser.safebrowsing.downloads.enabled", true);
+pref("browser.safebrowsing.downloads.remote.enabled", true);
+pref("browser.safebrowsing.downloads.remote.timeout_ms", 10000);
+pref("browser.safebrowsing.downloads.remote.url", "https://sb-ssl.google.com/safebrowsing/clientreport/download?key=%GOOGLE_API_KEY%");
+pref("browser.safebrowsing.downloads.remote.block_dangerous", true);
+pref("browser.safebrowsing.downloads.remote.block_dangerous_host", true);
+pref("browser.safebrowsing.downloads.remote.block_potentially_unwanted", true);
+pref("browser.safebrowsing.downloads.remote.block_uncommon", true);
+pref("browser.safebrowsing.debug", false);
+
+// The protocol version we communicate with google server.
+pref("browser.safebrowsing.provider.google.pver", "2.2");
+pref("browser.safebrowsing.provider.google.lists", "goog-badbinurl-shavar,goog-downloadwhite-digest256,goog-phish-shavar,googpub-phish-shavar,goog-malware-shavar,goog-unwanted-shavar");
+pref("browser.safebrowsing.provider.google.updateURL", "https://safebrowsing.google.com/safebrowsing/downloads?client=SAFEBROWSING_ID&appver=%MAJOR_VERSION%&pver=2.2&key=%GOOGLE_API_KEY%");
+pref("browser.safebrowsing.provider.google.gethashURL", "https://safebrowsing.google.com/safebrowsing/gethash?client=SAFEBROWSING_ID&appver=%MAJOR_VERSION%&pver=2.2");
+pref("browser.safebrowsing.provider.google.reportURL", "https://safebrowsing.google.com/safebrowsing/diagnostic?client=%NAME%&hl=%LOCALE%&site=");
+
+// Prefs for v4.
+pref("browser.safebrowsing.provider.google4.pver", "4");
+pref("browser.safebrowsing.provider.google4.lists", "goog-phish-proto,googpub-phish-proto,goog-malware-proto,goog-unwanted-proto");
+pref("browser.safebrowsing.provider.google4.updateURL", "https://safebrowsing.googleapis.com/v4/threatListUpdates:fetch?$ct=application/x-protobuf&key=%GOOGLE_API_KEY%");
+pref("browser.safebrowsing.provider.google4.gethashURL", "https://safebrowsing.googleapis.com/v4/fullHashes:find?$req=%REQUEST_BASE64%&$ct=application/x-protobuf&key=%GOOGLE_API_KEY%");
+pref("browser.safebrowsing.provider.google4.reportURL", "https://safebrowsing.google.com/safebrowsing/diagnostic?client=%NAME%&hl=%LOCALE%&site=");
+
+pref("browser.safebrowsing.reportPhishMistakeURL", "https://%LOCALE%.phish-error.mozilla.com/?hl=%LOCALE%&url=");
+pref("browser.safebrowsing.reportPhishURL", "https://%LOCALE%.phish-report.mozilla.com/?hl=%LOCALE%&url=");
+pref("browser.safebrowsing.reportMalwareMistakeURL", "https://%LOCALE%.malware-error.mozilla.com/?hl=%LOCALE%&url=");
+
+// The table and global pref for blocking plugin content
+pref("browser.safebrowsing.blockedURIs.enabled", true);
+pref("urlclassifier.blockedTable", "test-block-simple,mozplugin-block-digest256");
+
+// The protocol version we communicate with mozilla server.
+pref("browser.safebrowsing.provider.mozilla.pver", "2.2");
+pref("browser.safebrowsing.provider.mozilla.lists", "base-track-digest256,mozstd-trackwhite-digest256,content-track-digest256,mozplugin-block-digest256,mozplugin2-block-digest256");
+pref("browser.safebrowsing.provider.mozilla.updateURL", "https://shavar.services.mozilla.com/downloads?client=SAFEBROWSING_ID&appver=%MAJOR_VERSION%&pver=2.2");
+pref("browser.safebrowsing.provider.mozilla.gethashURL", "https://shavar.services.mozilla.com/gethash?client=SAFEBROWSING_ID&appver=%MAJOR_VERSION%&pver=2.2");
+// Set to a date in the past to force immediate download in new profiles.
+pref("browser.safebrowsing.provider.mozilla.nextupdatetime", "1");
+// Block lists for tracking protection. The name values will be used as the keys
+// to lookup the localized name in preferences.properties.
+pref("browser.safebrowsing.provider.mozilla.lists.base.name", "mozstdName");
+pref("browser.safebrowsing.provider.mozilla.lists.base.description", "mozstdDesc");
+pref("browser.safebrowsing.provider.mozilla.lists.content.name", "mozfullName");
+pref("browser.safebrowsing.provider.mozilla.lists.content.description", "mozfullDesc");
+
+// Allow users to ignore Safe Browsing warnings.
+pref("browser.safebrowsing.allowOverride", true);
+
+#ifdef MOZILLA_OFFICIAL
+// Normally the "client ID" sent in updates is appinfo.name, but for
+// official Firefox releases from Mozilla we use a special identifier.
+pref("browser.safebrowsing.id", "navclient-auto-ffox");
+#else
+pref("browser.safebrowsing.id", "Firefox");
+#endif
+
+// Turn off Spatial navigation by default.
+pref("snav.enabled", false);
+
+// New implementation to unify touch-caret and selection-carets.
+pref("layout.accessiblecaret.enabled", false);
+
+// Enable the accessible caret on platforms/devices
+// that we detect have touch support. Note that this pref is an
+// additional way to enable the accessible carets, rather than
+// overriding the layout.accessiblecaret.enabled pref.
+pref("layout.accessiblecaret.enabled_on_touch", true);
+
+// CSS attributes of the AccessibleCaret in CSS pixels.
+pref("layout.accessiblecaret.width", "34.0");
+pref("layout.accessiblecaret.height", "36.0");
+pref("layout.accessiblecaret.margin-left", "-18.5");
+pref("layout.accessiblecaret.bar.width", "2.0");
+
+// Show no selection bars at the two ends of the selection highlight.
+pref("layout.accessiblecaret.bar.enabled", false);
+
+// Show the caret when long tapping on an empty content.
+pref("layout.accessiblecaret.caret_shown_when_long_tapping_on_empty_content", false);
+
+// Timeout in milliseconds to hide the accessiblecaret under cursor mode while
+// no one touches it. Set the value to 0 to disable this feature.
+pref("layout.accessiblecaret.timeout_ms", 0);
+
+// Simulate long tap to select words on the platforms where APZ is not enabled
+// or long tap events does not fired by APZ.
+pref("layout.accessiblecaret.use_long_tap_injector", false);
+
+// By default, carets become tilt only when they are overlapping.
+pref("layout.accessiblecaret.always_tilt", false);
+
+// By default, carets always show when scrolling (either panning for zooming)
+// the page.
+pref("layout.accessiblecaret.always_show_when_scrolling", true);
+
+// Selection change notifications generated by Javascript hide
+// AccessibleCarets and close UI interaction by default.
+pref("layout.accessiblecaret.allow_script_change_updates", false);
+
+// Allow one caret to be dragged across the other caret without any limitation.
+// This matches the built-in convention for all desktop platforms.
+pref("layout.accessiblecaret.allow_dragging_across_other_caret", true);
+
+// Optionally provide haptic feedback on longPress selection events.
+pref("layout.accessiblecaret.hapticfeedback", false);
+
+// Smart phone-number selection on long-press is not enabled by default.
+pref("layout.accessiblecaret.extend_selection_for_phone_number", false);
+
+// Keep the accessible carets hidden when the user is using mouse input.
+pref("layout.accessiblecaret.hide_carets_for_mouse_input", true);
+
+// Wakelock is disabled by default.
+pref("dom.wakelock.enabled", false);
+
+// The URL of the Firefox Accounts auth server backend
+pref("identity.fxaccounts.auth.uri", "https://api.accounts.firefox.com/v1");
+
+// disable mozsample size for now
+pref("image.mozsamplesize.enabled", false);
+
+pref("beacon.enabled", true);
+
+// Camera prefs
+pref("camera.control.face_detection.enabled", true);
+
+
+// SW Cache API
+pref("dom.caches.enabled", true);
+
+#ifdef MOZ_WIDGET_GONK
+// Empirically, this is the value returned by hal::GetTotalSystemMemory()
+// when Flame's memory is limited to 512MiB. If the camera stack determines
+// it is running on a low memory platform, features that can be reliably
+// supported will be disabled. This threshold can be adjusted to suit other
+// platforms; and set to 0 to disable the low-memory check altogether.
+pref("camera.control.low_memory_thresholdMB", 404);
+#endif
+
+// SystemUpdate API
+pref("dom.system_update.enabled", false);
+pref("dom.system_update.debug", false);
+
+// UDPSocket API
+pref("dom.udpsocket.enabled", false);
+
+// Disable before keyboard events and after keyboard events by default.
+pref("dom.beforeAfterKeyboardEvent.enabled", false);
+
+// Presentation API
+pref("dom.presentation.enabled", false);
+pref("dom.presentation.controller.enabled", false);
+pref("dom.presentation.receiver.enabled", false);
+
+// Presentation Device
+pref("dom.presentation.tcp_server.debug", false);
+pref("dom.presentation.discovery.enabled", false);
+pref("dom.presentation.discovery.legacy.enabled", false);
+pref("dom.presentation.discovery.timeout_ms", 10000);
+pref("dom.presentation.discoverable", false);
+pref("dom.presentation.discoverable.encrypted", true);
+pref("dom.presentation.discoverable.retry_ms", 5000);
+pref("dom.presentation.session_transport.data_channel.enable", false);
+
+#ifdef XP_MACOSX
+#if !defined(RELEASE_OR_BETA) || defined(DEBUG)
+// In non-release builds we crash by default on insecure text input (when a
+// password editor has focus but secure event input isn't enabled). The
+// following pref, when turned on, disables this behavior. See bug 1188425.
+pref("intl.allow-insecure-text-input", false);
+#endif
+#endif // XP_MACOSX
+
+// Enable meta-viewport support in remote APZ-enabled frames.
+pref("dom.meta-viewport.enabled", false);
+
+// MozSettings debugging prefs for each component
+pref("dom.mozSettings.SettingsDB.debug.enabled", false);
+pref("dom.mozSettings.SettingsManager.debug.enabled", false);
+pref("dom.mozSettings.SettingsRequestManager.debug.enabled", false);
+pref("dom.mozSettings.SettingsService.debug.enabled", false);
+
+// MozSettings verbose mode to track everything
+pref("dom.mozSettings.SettingsDB.verbose.enabled", false);
+pref("dom.mozSettings.SettingsManager.verbose.enabled", false);
+pref("dom.mozSettings.SettingsRequestManager.verbose.enabled", false);
+pref("dom.mozSettings.SettingsService.verbose.enabled", false);
+
+// Controlling whether we want to allow forcing some Settings
+// IndexedDB transactions to be opened as readonly or keep everything as
+// readwrite.
+pref("dom.mozSettings.allowForceReadOnly", false);
+
+// The interval at which to check for slow running addons
+#ifdef NIGHTLY_BUILD
+pref("browser.addon-watch.interval", 15000);
+#else
+pref("browser.addon-watch.interval", -1);
+#endif
+pref("browser.addon-watch.ignore", "[\"mochikit@mozilla.org\",\"special-powers@mozilla.org\",\"fxdevtools-adapters@mozilla.org\",\"fx-devtools\"]");
+
+// Search service settings
+pref("browser.search.log", false);
+pref("browser.search.update", true);
+pref("browser.search.update.log", false);
+pref("browser.search.update.interval", 21600);
+pref("browser.search.suggest.enabled", true);
+pref("browser.search.reset.enabled", false);
+pref("browser.search.reset.whitelist", "");
+pref("browser.search.geoSpecificDefaults", false);
+pref("browser.search.geoip.url", "https://location.services.mozilla.com/v1/country?key=%MOZILLA_API_KEY%");
+pref("browser.search.geoip.timeout", 3000);
+
+#ifdef MOZ_OFFICIAL_BRANDING
+// {moz:official} expands to "official"
+pref("browser.search.official", true);
+#endif
+
+#ifndef MOZ_WIDGET_GONK
+// GMPInstallManager prefs
+
+// User-settable override to media.gmp-manager.url for testing purposes.
+//pref("media.gmp-manager.url.override", "");
+
+// Update service URL for GMP install/updates:
+pref("media.gmp-manager.url", "https://aus5.mozilla.org/update/3/GMP/%VERSION%/%BUILD_ID%/%BUILD_TARGET%/%LOCALE%/%CHANNEL%/%OS_VERSION%/%DISTRIBUTION%/%DISTRIBUTION_VERSION%/update.xml");
+
+// When |media.gmp-manager.cert.requireBuiltIn| is true or not specified the
+// final certificate and all certificates the connection is redirected to before
+// the final certificate for the url specified in the |media.gmp-manager.url|
+// preference must be built-in.
+pref("media.gmp-manager.cert.requireBuiltIn", true);
+
+// The |media.gmp-manager.certs.| preference branch contains branches that are
+// sequentially numbered starting at 1 that contain attribute name / value
+// pairs for the certificate used by the server that hosts the update xml file
+// as specified in the |media.gmp-manager.url| preference. When these preferences are
+// present the following conditions apply for a successful update check:
+// 1. the uri scheme must be https
+// 2. the preference name must exist as an attribute name on the certificate and
+// the value for the name must be the same as the value for the attribute name
+// on the certificate.
+// If these conditions aren't met it will be treated the same as when there is
+// no update available. This validation will not be performed when the
+// |media.gmp-manager.url.override| user preference has been set for testing updates or
+// when the |media.gmp-manager.cert.checkAttributes| preference is set to false. Also,
+// the |media.gmp-manager.url.override| preference should ONLY be used for testing.
+// IMPORTANT! app.update.certs.* prefs should also be updated if these
+// are updated.
+pref("media.gmp-manager.cert.checkAttributes", true);
+pref("media.gmp-manager.certs.1.issuerName", "CN=DigiCert SHA2 Secure Server CA,O=DigiCert Inc,C=US");
+pref("media.gmp-manager.certs.1.commonName", "aus5.mozilla.org");
+pref("media.gmp-manager.certs.2.issuerName", "CN=thawte SSL CA - G2,O=\"thawte, Inc.\",C=US");
+pref("media.gmp-manager.certs.2.commonName", "aus5.mozilla.org");
+#endif
+
+// Whether or not to perform reader mode article parsing on page load.
+// If this pref is disabled, we will never show a reader mode icon in the toolbar.
+pref("reader.parse-on-load.enabled", true);
+
+// After what size document we don't bother running Readability on it
+// because it'd slow things down too much
+pref("reader.parse-node-limit", 3000);
+
+// Force-enables reader mode parsing, even on low-memory platforms, where it
+// is disabled by default.
+pref("reader.parse-on-load.force-enabled", false);
+
+// Whether we include full URLs in browser console errors. This is disabled
+// by default because some platforms will persist these, leading to privacy issues.
+pref("reader.errors.includeURLs", false);
+
+// The default relative font size in reader mode (1-9)
+pref("reader.font_size", 5);
+
+// The default relative content width in reader mode (1-9)
+pref("reader.content_width", 3);
+
+// The default relative line height in reader mode (1-9)
+pref("reader.line_height", 4);
+
+// The default color scheme in reader mode (light, dark, sepia, auto)
+// auto = color automatically adjusts according to ambient light level
+// (auto only works on platforms where the 'devicelight' event is enabled)
+pref("reader.color_scheme", "light");
+
+// Color scheme values available in reader mode UI.
+pref("reader.color_scheme.values", "[\"light\",\"dark\",\"sepia\"]");
+
+// The font type in reader (sans-serif, serif)
+pref("reader.font_type", "sans-serif");
+
+// Whether or not the user has interacted with the reader mode toolbar.
+// This is used to show a first-launch tip in reader mode.
+pref("reader.has_used_toolbar", false);
+
+// Whether to use a vertical or horizontal toolbar.
+pref("reader.toolbar.vertical", true);
+
+#if !defined(ANDROID)
+pref("narrate.enabled", true);
+#else
+pref("narrate.enabled", false);
+#endif
+
+pref("narrate.test", false);
+pref("narrate.rate", 0);
+pref("narrate.voice", " { \"default\": \"automatic\" }");
+// Only make voices that match content language available.
+pref("narrate.filter-voices", true);
+
+#if defined(XP_LINUX) && defined(MOZ_GMP_SANDBOX)
+// Whether to allow, on a Linux system that doesn't support the necessary sandboxing
+// features, loading Gecko Media Plugins unsandboxed. However, EME CDMs will not be
+// loaded without sandboxing even if this pref is changed.
+pref("media.gmp.insecure.allow", false);
+#endif
+
+pref("dom.audiochannel.mutedByDefault", false);
+
+// Enable <details> and <summary> tags.
+pref("dom.details_element.enabled", true);
+
+// Secure Element API
+#ifdef MOZ_SECUREELEMENT
+pref("dom.secureelement.enabled", false);
+#endif
+
+// Allow control characters appear in composition string.
+// When this is false, control characters except
+// CHARACTER TABULATION (horizontal tab) are removed from
+// both composition string and data attribute of compositionupdate
+// and compositionend events.
+pref("dom.compositionevent.allow_control_characters", false);
+
+#ifdef MOZ_WIDGET_GONK
+// Bug 1154053: Serialize B2G memory reports; smaller devices are
+// usually overcommitted on memory by using zRAM, so memory reporting
+// causes memory pressure from uncompressing cold heap memory.
+pref("memory.report_concurrency", 1);
+#else
+// Desktop probably doesn't have swapped-out children like that.
+pref("memory.report_concurrency", 10);
+#endif
+
+// Add Mozilla AudioChannel APIs.
+pref("media.useAudioChannelAPI", false);
+
+// Expose Request.context. Currently disabled since the spec is in flux.
+pref("dom.requestcontext.enabled", false);
+
+pref("toolkit.pageThumbs.screenSizeDivisor", 7);
+pref("toolkit.pageThumbs.minWidth", 0);
+pref("toolkit.pageThumbs.minHeight", 0);
+
+pref("webextensions.tests", false);
+
+// 16MB default non-parseable upload limit for requestBody.raw.bytes
+pref("webextensions.webRequest.requestBodyMaxRawBytes", 16777216);
+
+// This functionality is still experimental
+pref("webextensions.storage.sync.enabled", false);
+#ifdef RELEASE_OR_BETA
+pref("webextensions.storage.sync.serverURL", "https://webextensions.settings.services.mozilla.com/v1");
+#else
+pref("webextensions.storage.sync.serverURL", "https://webextensions.dev.mozaws.net/v1");
+#endif
+
+// Allow customization of the fallback directory for file uploads
+pref("dom.input.fallbackUploadDir", "");
+
+// Turn rewriting of youtube embeds on/off
+pref("plugins.rewrite_youtube_embeds", true);
+
+// Don't hide Flash from navigator.plugins when it is click-to-activate
+pref("plugins.navigator_hide_disabled_flash", false);
+
+// Disable browser frames by default
+pref("dom.mozBrowserFramesEnabled", false);
+
+// Is support for 'color-adjust' CSS property enabled?
+pref("layout.css.color-adjust.enabled", true);
+
+pref("dom.audiochannel.audioCompeting", false);
+pref("dom.audiochannel.audioCompeting.allAgents", false);
+
+// Disable Node.rootNode in release builds.
+#ifdef RELEASE_OR_BETA
+pref("dom.node.rootNode.enabled", false);
+#else
+pref("dom.node.rootNode.enabled", true);
+#endif
+
+// Default media volume
+pref("media.default_volume", "1.0");
+
+// Once bug 1276272 is resolved, we will trun this preference to default ON in
+// non-release channels.
+#ifdef RELEASE_OR_BETA
+pref("media.seekToNextFrame.enabled", false);
+#else
+pref("media.seekToNextFrame.enabled", true);
+#endif
+
+// return the maximum number of cores that navigator.hardwareCurrency returns
+pref("dom.maxHardwareConcurrency", 16);
+
+// Shutdown the osfile worker if its no longer needed.
+#if !defined(RELEASE_OR_BETA)
+pref("osfile.reset_worker_delay", 30000);
+#endif
+
+#if !defined(MOZ_WIDGET_GONK) && !defined(MOZ_WIDGET_ANDROID)
+pref("dom.webkitBlink.dirPicker.enabled", true);
+pref("dom.webkitBlink.filesystem.enabled", true);
+#endif
+
+#ifdef NIGHTLY_BUILD
+pref("media.block-autoplay-until-in-foreground", true);
+#else
+pref("media.block-autoplay-until-in-foreground", false);
+#endif
+
+#ifdef MOZ_STYLO
+// Is the Servo-backed style system enabled?
+pref("layout.css.servo.enabled", true);
+#endif
+
+// HSTS Priming
+// If a request is mixed-content, send an HSTS priming request to attempt to
+// see if it is available over HTTPS.
+#ifdef RELEASE_OR_BETA
+// Don't change the order of evaluation of mixed-content and HSTS upgrades in
+// order to be most compatible with current standards
+pref("security.mixed_content.send_hsts_priming", false);
+pref("security.mixed_content.use_hsts", false);
+#else
+// Change the order of evaluation so HSTS upgrades happen before
+// mixed-content blocking
+pref("security.mixed_content.send_hsts_priming", true);
+pref("security.mixed_content.use_hsts", true);
+#endif
+// Approximately 1 week default cache for HSTS priming failures
+pref ("security.mixed_content.hsts_priming_cache_timeout", 10080);
+
+// Disable Storage api in release builds.
+#ifdef NIGHTLY_BUILD
+pref("dom.storageManager.enabled", true);
+#else
+pref("dom.storageManager.enabled", false);
+#endif
+
+// When a user cancels this number of authentication dialogs coming from
+// a single web page in a row, all following authentication dialogs will
+// be blocked (automatically canceled) for that page. The counter resets
+// when the page is reloaded. To turn this feature off, just set the limit to 0.
+pref("prompts.authentication_dialog_abuse_limit", 3);
diff --git a/modules/libpref/moz.build b/modules/libpref/moz.build
new file mode 100644
index 000000000..1c2c13e69
--- /dev/null
+++ b/modules/libpref/moz.build
@@ -0,0 +1,48 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+XPCSHELL_TESTS_MANIFESTS += [
+ 'test/unit/xpcshell.ini',
+ 'test/unit_ipc/xpcshell.ini',
+]
+
+XPIDL_SOURCES += [
+ 'nsIPrefBranch.idl',
+ 'nsIPrefBranch2.idl',
+ 'nsIPrefBranchInternal.idl',
+ 'nsIPrefLocalizedString.idl',
+ 'nsIPrefService.idl',
+ 'nsIRelativeFilePref.idl',
+]
+
+XPIDL_MODULE = 'pref'
+
+EXPORTS.mozilla += [
+ 'Preferences.h',
+]
+
+UNIFIED_SOURCES += [
+ 'nsPrefBranch.cpp',
+ 'nsPrefsFactory.cpp',
+ 'Preferences.cpp',
+ 'prefread.cpp',
+]
+
+# prefapi.cpp cannot be built in unified mode because it uses plarena.h
+SOURCES += [
+ 'prefapi.cpp',
+]
+
+include('/ipc/chromium/chromium-config.mozbuild')
+
+FINAL_LIBRARY = 'xul'
+
+DEFINES['OS_ARCH'] = CONFIG['OS_ARCH']
+DEFINES['MOZ_WIDGET_TOOLKIT'] = CONFIG['MOZ_WIDGET_TOOLKIT']
+
+FINAL_TARGET_PP_FILES += [
+ 'greprefs.js',
+]
diff --git a/modules/libpref/nsIPrefBranch.idl b/modules/libpref/nsIPrefBranch.idl
new file mode 100644
index 000000000..ee0c11ef0
--- /dev/null
+++ b/modules/libpref/nsIPrefBranch.idl
@@ -0,0 +1,409 @@
+/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "nsISupports.idl"
+
+interface nsIObserver;
+
+/**
+ * The nsIPrefBranch interface is used to manipulate the preferences data. This
+ * object may be obtained from the preferences service (nsIPrefService) and
+ * used to get and set default and/or user preferences across the application.
+ *
+ * This object is created with a "root" value which describes the base point in
+ * the preferences "tree" from which this "branch" stems. Preferences are
+ * accessed off of this root by using just the final portion of the preference.
+ * For example, if this object is created with the root "browser.startup.",
+ * the preferences "browser.startup.page", "browser.startup.homepage",
+ * and "browser.startup.homepage_override" can be accessed by simply passing
+ * "page", "homepage", or "homepage_override" to the various Get/Set methods.
+ *
+ * @see nsIPrefService
+ */
+
+[scriptable, uuid(55d25e49-793f-4727-a69f-de8b15f4b985)]
+interface nsIPrefBranch : nsISupports
+{
+
+ /**
+ * Values describing the basic preference types.
+ *
+ * @see getPrefType
+ */
+ const long PREF_INVALID = 0;
+ const long PREF_STRING = 32;
+ const long PREF_INT = 64;
+ const long PREF_BOOL = 128;
+
+ /**
+ * Called to get the root on which this branch is based, such as
+ * "browser.startup."
+ */
+ readonly attribute string root;
+
+ /**
+ * Called to determine the type of a specific preference.
+ *
+ * @param aPrefName The preference to get the type of.
+ *
+ * @return long A value representing the type of the preference. This
+ * value will be PREF_STRING, PREF_INT, or PREF_BOOL.
+ */
+ long getPrefType(in string aPrefName);
+
+ /**
+ * Called to get the state of an individual boolean preference.
+ *
+ * @param aPrefName The boolean preference to get the state of.
+ *
+ * @return boolean The value of the requested boolean preference.
+ *
+ * @see setBoolPref
+ */
+ boolean getBoolPref(in string aPrefName);
+
+ /**
+ * Called to set the state of an individual boolean preference.
+ *
+ * @param aPrefName The boolean preference to set the state of.
+ * @param aValue The boolean value to set the preference to.
+ *
+ * @throws Error if setting failed or the preference has a default
+ value of a type other than boolean.
+ *
+ * @see getBoolPref
+ */
+ void setBoolPref(in string aPrefName, in boolean aValue);
+
+ /**
+ * Called to get the state of an individual floating-point preference.
+ * "Floating point" preferences are really string preferences that
+ * are converted to floating point numbers.
+ *
+ * @param aPrefName The floating point preference to get the state of.
+ *
+ * @return float The value of the requested floating point preference.
+ *
+ * @see setCharPref
+ */
+ float getFloatPref(in string aPrefName);
+
+ /**
+ * Called to get the state of an individual string preference.
+ *
+ * @param aPrefName The string preference to retrieve.
+ *
+ * @return string The value of the requested string preference.
+ *
+ * @see setCharPref
+ */
+ string getCharPref(in string aPrefName);
+
+ /**
+ * Called to set the state of an individual string preference.
+ *
+ * @param aPrefName The string preference to set.
+ * @param aValue The string value to set the preference to.
+ *
+ * @throws Error if setting failed or the preference has a default
+ value of a type other than string.
+ *
+ * @see getCharPref
+ */
+ void setCharPref(in string aPrefName, in string aValue);
+
+ /**
+ * Called to get the state of an individual integer preference.
+ *
+ * @param aPrefName The integer preference to get the value of.
+ *
+ * @return long The value of the requested integer preference.
+ *
+ * @see setIntPref
+ */
+ long getIntPref(in string aPrefName);
+
+ /**
+ * Called to set the state of an individual integer preference.
+ *
+ * @param aPrefName The integer preference to set the value of.
+ * @param aValue The integer value to set the preference to.
+ *
+ * @throws Error if setting failed or the preference has a default
+ value of a type other than integer.
+ *
+ * @see getIntPref
+ */
+ void setIntPref(in string aPrefName, in long aValue);
+
+ /**
+ * Called to get the state of an individual complex preference. A complex
+ * preference is a preference which represents an XPCOM object that can not
+ * be easily represented using a standard boolean, integer or string value.
+ *
+ * @param aPrefName The complex preference to get the value of.
+ * @param aType The XPCOM interface that this complex preference
+ * represents. Interfaces currently supported are:
+ * - nsIFile
+ * - nsISupportsString (UniChar)
+ * - nsIPrefLocalizedString (Localized UniChar)
+ * @param aValue The XPCOM object into which to the complex preference
+ * value should be retrieved.
+ *
+ * @throws Error The value does not exist or is the wrong type.
+ *
+ * @see setComplexValue
+ */
+ void getComplexValue(in string aPrefName, in nsIIDRef aType,
+ [iid_is(aType), retval] out nsQIResult aValue);
+
+ /**
+ * Called to set the state of an individual complex preference. A complex
+ * preference is a preference which represents an XPCOM object that can not
+ * be easily represented using a standard boolean, integer or string value.
+ *
+ * @param aPrefName The complex preference to set the value of.
+ * @param aType The XPCOM interface that this complex preference
+ * represents. Interfaces currently supported are:
+ * - nsIFile
+ * - nsISupportsString (UniChar)
+ * - nsIPrefLocalizedString (Localized UniChar)
+ * @param aValue The XPCOM object from which to set the complex preference
+ * value.
+ *
+ * @throws Error if setting failed or the value is the wrong type.
+ *
+ * @see getComplexValue
+ */
+ void setComplexValue(in string aPrefName, in nsIIDRef aType, in nsISupports aValue);
+
+ /**
+ * Called to clear a user set value from a specific preference. This will, in
+ * effect, reset the value to the default value. If no default value exists
+ * the preference will cease to exist.
+ *
+ * @param aPrefName The preference to be cleared.
+ *
+ * @note
+ * This method does nothing if this object is a default branch.
+ */
+ void clearUserPref(in string aPrefName);
+
+ /**
+ * Called to lock a specific preference. Locking a preference will cause the
+ * preference service to always return the default value regardless of
+ * whether there is a user set value or not.
+ *
+ * @param aPrefName The preference to be locked.
+ *
+ * @note
+ * This method can be called on either a default or user branch but, in
+ * effect, always operates on the default branch.
+ *
+ * @throws Error The preference does not exist or an error occurred.
+ *
+ * @see unlockPref
+ */
+ void lockPref(in string aPrefName);
+
+ /**
+ * Called to check if a specific preference has a user value associated to
+ * it.
+ *
+ * @param aPrefName The preference to be tested.
+ *
+ * @note
+ * This method can be called on either a default or user branch but, in
+ * effect, always operates on the user branch.
+ *
+ * @note
+ * If a preference was manually set to a value that equals the default value,
+ * then the preference no longer has a user set value, i.e. it is
+ * considered reset to its default value.
+ * In particular, this method will return false for such a preference and
+ * the preference will not be saved to a file by nsIPrefService.savePrefFile.
+ *
+ * @return boolean true The preference has a user set value.
+ * false The preference only has a default value.
+ */
+ boolean prefHasUserValue(in string aPrefName);
+
+ /**
+ * Called to check if a specific preference is locked. If a preference is
+ * locked calling its Get method will always return the default value.
+ *
+ * @param aPrefName The preference to be tested.
+ *
+ * @note
+ * This method can be called on either a default or user branch but, in
+ * effect, always operates on the default branch.
+ *
+ * @return boolean true The preference is locked.
+ * false The preference is not locked.
+ *
+ * @see lockPref
+ * @see unlockPref
+ */
+ boolean prefIsLocked(in string aPrefName);
+
+ /**
+ * Called to unlock a specific preference. Unlocking a previously locked
+ * preference allows the preference service to once again return the user set
+ * value of the preference.
+ *
+ * @param aPrefName The preference to be unlocked.
+ *
+ * @note
+ * This method can be called on either a default or user branch but, in
+ * effect, always operates on the default branch.
+ *
+ * @throws Error The preference does not exist or an error occurred.
+ *
+ * @see lockPref
+ */
+ void unlockPref(in string aPrefName);
+
+
+ /**
+ * Called to remove all of the preferences referenced by this branch.
+ *
+ * @param aStartingAt The point on the branch at which to start the deleting
+ * preferences. Pass in "" to remove all preferences
+ * referenced by this branch.
+ *
+ * @note
+ * This method can be called on either a default or user branch but, in
+ * effect, always operates on both.
+ *
+ * @throws Error The preference(s) do not exist or an error occurred.
+ */
+ void deleteBranch(in string aStartingAt);
+
+ /**
+ * Returns an array of strings representing the child preferences of the
+ * root of this branch.
+ *
+ * @param aStartingAt The point on the branch at which to start enumerating
+ * the child preferences. Pass in "" to enumerate all
+ * preferences referenced by this branch.
+ * @param aCount Receives the number of elements in the array.
+ * @param aChildArray Receives the array of child preferences.
+ *
+ * @note
+ * This method can be called on either a default or user branch but, in
+ * effect, always operates on both.
+ *
+ * @throws Error The preference(s) do not exist or an error occurred.
+ */
+ void getChildList(in string aStartingAt,
+ [optional] out unsigned long aCount,
+ [array, size_is(aCount), retval] out string aChildArray);
+
+ /**
+ * Called to reset all of the preferences referenced by this branch to their
+ * default values.
+ *
+ * @param aStartingAt The point on the branch at which to start the resetting
+ * preferences to their default values. Pass in "" to
+ * reset all preferences referenced by this branch.
+ *
+ * @note
+ * This method can be called on either a default or user branch but, in
+ * effect, always operates on the user branch.
+ *
+ * @throws Error The preference(s) do not exist or an error occurred.
+ */
+ void resetBranch(in string aStartingAt);
+
+ /**
+ * Add a preference change observer. On preference changes, the following
+ * arguments will be passed to the nsIObserver.observe() method:
+ * aSubject - The nsIPrefBranch object (this)
+ * aTopic - The string defined by NS_PREFBRANCH_PREFCHANGE_TOPIC_ID
+ * aData - The name of the preference which has changed, relative to
+ * the |root| of the aSubject branch.
+ *
+ * aSubject.get*Pref(aData) will get the new value of the modified
+ * preference. For example, if your observer is registered with
+ * addObserver("bar.", ...) on a branch with root "foo.", modifying
+ * the preference "foo.bar.baz" will trigger the observer, and aData
+ * parameter will be "bar.baz".
+ *
+ * @param aDomain The preference on which to listen for changes. This can
+ * be the name of an entire branch to observe.
+ * e.g. Holding the "root" prefbranch and calling
+ * addObserver("foo.bar.", ...) will observe changes to
+ * foo.bar.baz and foo.bar.bzip
+ * @param aObserver The object to be notified if the preference changes.
+ * @param aHoldWeak true Hold a weak reference to |aObserver|. The object
+ * must implement the nsISupportsWeakReference
+ * interface or this will fail.
+ * false Hold a strong reference to |aObserver|.
+ *
+ * @note
+ * Registering as a preference observer can open an object to potential
+ * cyclical references which will cause memory leaks. These cycles generally
+ * occur because an object both registers itself as an observer (causing the
+ * branch to hold a reference to the observer) and holds a reference to the
+ * branch object for the purpose of getting/setting preference values. There
+ * are 3 approaches which have been implemented in an attempt to avoid these
+ * situations.
+ * 1) The nsPrefBranch object supports nsISupportsWeakReference. Any consumer
+ * may hold a weak reference to it instead of a strong one.
+ * 2) The nsPrefBranch object listens for xpcom-shutdown and frees all of the
+ * objects currently in its observer list. This ensures that long lived
+ * objects (services for example) will be freed correctly.
+ * 3) The observer can request to be held as a weak reference when it is
+ * registered. This insures that shorter lived objects (say one tied to an
+ * open window) will not fall into the cyclical reference trap.
+ *
+ * @note
+ * The list of registered observers may be changed during the dispatch of
+ * nsPref:changed notification. However, the observers are not guaranteed
+ * to be notified in any particular order, so you can't be sure whether the
+ * added/removed observer will be called during the notification when it
+ * is added/removed.
+ *
+ * @note
+ * It is possible to change preferences during the notification.
+ *
+ * @note
+ * It is not safe to change observers during this callback in Gecko
+ * releases before 1.9. If you want a safe way to remove a pref observer,
+ * please use an nsITimer.
+ *
+ * @see nsIObserver
+ * @see removeObserver
+ */
+ void addObserver(in string aDomain, in nsIObserver aObserver,
+ in boolean aHoldWeak);
+
+ /**
+ * Remove a preference change observer.
+ *
+ * @param aDomain The preference which is being observed for changes.
+ * @param aObserver An observer previously registered with addObserver().
+ *
+ * @note
+ * Note that you must call removeObserver() on the same nsIPrefBranch
+ * instance on which you called addObserver() in order to remove aObserver;
+ * otherwise, the observer will not be removed.
+ *
+ * @see nsIObserver
+ * @see addObserver
+ */
+ void removeObserver(in string aDomain, in nsIObserver aObserver);
+};
+
+
+%{C++
+
+#define NS_PREFBRANCH_CONTRACTID "@mozilla.org/preferencesbranch;1"
+/**
+ * Notification sent when a preference changes.
+ */
+#define NS_PREFBRANCH_PREFCHANGE_TOPIC_ID "nsPref:changed"
+
+%}
diff --git a/modules/libpref/nsIPrefBranch2.idl b/modules/libpref/nsIPrefBranch2.idl
new file mode 100644
index 000000000..f1087c92d
--- /dev/null
+++ b/modules/libpref/nsIPrefBranch2.idl
@@ -0,0 +1,16 @@
+/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "nsIPrefBranch.idl"
+
+/**
+ * An empty interface to provide backwards compatibility for existing code.
+ *
+ * @see nsIPrefBranch
+ */
+[scriptable, uuid(8892016d-07f7-4530-b5c1-d73dfcde4a1c)]
+interface nsIPrefBranch2 : nsIPrefBranch
+{
+};
diff --git a/modules/libpref/nsIPrefBranchInternal.idl b/modules/libpref/nsIPrefBranchInternal.idl
new file mode 100644
index 000000000..476e6a59f
--- /dev/null
+++ b/modules/libpref/nsIPrefBranchInternal.idl
@@ -0,0 +1,17 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "nsIPrefBranch2.idl"
+
+/**
+ * An empty interface to provide backwards compatibility for existing code that
+ * bsmedberg didn't want to break all at once. Don't use me!
+ *
+ * @status NON-FROZEN interface WHICH WILL PROBABLY GO AWAY.
+ */
+
+[scriptable, uuid(355bd1e9-248a-438b-809d-e0db1b287882)]
+interface nsIPrefBranchInternal : nsIPrefBranch2
+{
+};
diff --git a/modules/libpref/nsIPrefLocalizedString.idl b/modules/libpref/nsIPrefLocalizedString.idl
new file mode 100644
index 000000000..f99d60f6f
--- /dev/null
+++ b/modules/libpref/nsIPrefLocalizedString.idl
@@ -0,0 +1,64 @@
+/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "nsISupports.idl"
+
+/**
+ * The nsIPrefLocalizedString interface is simply a wrapper interface for
+ * nsISupportsString so the preferences service can have a unique identifier
+ * to distinguish between requests for normal wide strings (nsISupportsString)
+ * and "localized" wide strings, which get their default values from properites
+ * files.
+ *
+ * @see nsIPrefBranch
+ * @see nsISupportsString
+ */
+
+[scriptable, uuid(ae419e24-1dd1-11b2-b39a-d3e5e7073802)]
+interface nsIPrefLocalizedString : nsISupports
+{
+ /**
+ * Provides access to string data stored in this property.
+ *
+ * @throws Error An error occurred.
+ */
+ attribute wstring data;
+
+ /**
+ * Used to retrieve the contents of this object into a wide string.
+ *
+ * @return wstring The string containing the data stored within this object.
+ */
+ wstring toString();
+
+ /**
+ * Used to set the contents of this object.
+ *
+ * @param length The length of the string. This value should not include
+ * space for the null terminator, nor should it account for the
+ * size of a character. It should only be the number of
+ * characters for which there is space in the string.
+ * @param data The string data to be stored.
+ *
+ * @note
+ * This makes a copy of the string argument passed in.
+ */
+ void setDataWithLength(in unsigned long length,
+ [size_is(length)] in wstring data);
+};
+
+%{C++
+
+#define NS_PREFLOCALIZEDSTRING_CID \
+ { /* {064d9cee-1dd2-11b2-83e3-d25ab0193c26} */ \
+ 0x064d9cee, \
+ 0x1dd2, \
+ 0x11b2, \
+ { 0x83, 0xe3, 0xd2, 0x5a, 0xb0, 0x19, 0x3c, 0x26 } \
+ }
+
+#define NS_PREFLOCALIZEDSTRING_CONTRACTID "@mozilla.org/pref-localizedstring;1"
+
+%}
diff --git a/modules/libpref/nsIPrefService.idl b/modules/libpref/nsIPrefService.idl
new file mode 100644
index 000000000..0db401996
--- /dev/null
+++ b/modules/libpref/nsIPrefService.idl
@@ -0,0 +1,160 @@
+/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "nsISupports.idl"
+#include "nsIPrefBranch.idl"
+
+%{C++
+struct PrefTuple;
+#include "nsTArrayForwardDeclare.h"
+%}
+
+[ptr] native nsPreferencesArrayPtr(nsTArray<PrefTuple>);
+[ptr] native nsPreferencePtr(PrefTuple);
+[ptr] native nsPreferencePtrConst(const PrefTuple);
+
+interface nsIFile;
+
+/**
+ * The nsIPrefService interface is the main entry point into the back end
+ * preferences management library. The preference service is directly
+ * responsible for the management of the preferences files and also facilitates
+ * access to the preference branch object which allows the direct manipulation
+ * of the preferences themselves.
+ *
+ * @see nsIPrefBranch
+ */
+
+[scriptable, uuid(1f84fd56-3956-40df-b86a-1ea01402ee96)]
+interface nsIPrefService : nsISupports
+{
+ /**
+ * Called to read in the preferences specified in a user preference file.
+ *
+ * @param aFile The file to be read.
+ *
+ * @note
+ * If nullptr is passed in for the aFile parameter the default preferences
+ * file(s) [prefs.js, user.js] will be read and processed.
+ *
+ * @throws Error File failed to read or contained invalid data.
+ *
+ * @see savePrefFile
+ * @see nsIFile
+ */
+ void readUserPrefs(in nsIFile aFile);
+
+ /**
+ * Called to completely flush and re-initialize the preferences system.
+ *
+ * @throws Error The preference service failed to restart correctly.
+ */
+ void resetPrefs();
+
+ /**
+ * Called to reset all preferences with user set values back to the
+ * application default values.
+ */
+ void resetUserPrefs();
+
+ /**
+ * Called to write current preferences state to a file.
+ *
+ * @param aFile The file to be written.
+ *
+ * @note
+ * If nullptr is passed in for the aFile parameter the preference data is
+ * written out to the current preferences file (usually prefs.js.)
+ *
+ * @throws Error File failed to write.
+ *
+ * @see readUserPrefs
+ * @see nsIFile
+ */
+ void savePrefFile(in nsIFile aFile);
+
+ /**
+ * Call to get a Preferences "Branch" which accesses user preference data.
+ * Using a Set method on this object will always create or set a user
+ * preference value. When using a Get method a user set value will be
+ * returned if one exists, otherwise a default value will be returned.
+ *
+ * @param aPrefRoot The preference "root" on which to base this "branch".
+ * For example, if the root "browser.startup." is used, the
+ * branch will be able to easily access the preferences
+ * "browser.startup.page", "browser.startup.homepage", or
+ * "browser.startup.homepage_override" by simply requesting
+ * "page", "homepage", or "homepage_override". nullptr or ""
+ * may be used to access to the entire preference "tree".
+ *
+ * @return nsIPrefBranch The object representing the requested branch.
+ *
+ * @see getDefaultBranch
+ */
+ nsIPrefBranch getBranch(in string aPrefRoot);
+
+ /**
+ * Call to get a Preferences "Branch" which accesses only the default
+ * preference data. Using a Set method on this object will always create or
+ * set a default preference value. When using a Get method a default value
+ * will always be returned.
+ *
+ * @param aPrefRoot The preference "root" on which to base this "branch".
+ * For example, if the root "browser.startup." is used, the
+ * branch will be able to easily access the preferences
+ * "browser.startup.page", "browser.startup.homepage", or
+ * "browser.startup.homepage_override" by simply requesting
+ * "page", "homepage", or "homepage_override". nullptr or ""
+ * may be used to access to the entire preference "tree".
+ *
+ * @note
+ * Few consumers will want to create default branch objects. Many of the
+ * branch methods do nothing on a default branch because the operations only
+ * make sense when applied to user set preferences.
+ *
+ * @return nsIPrefBranch The object representing the requested default branch.
+ *
+ * @see getBranch
+ */
+ nsIPrefBranch getDefaultBranch(in string aPrefRoot);
+
+ /**
+ * The preference service is 'dirty' if there are changes to user preferences
+ * that have not been written to disk
+ */
+ readonly attribute boolean dirty;
+};
+
+%{C++
+
+#define NS_PREFSERVICE_CID \
+ { /* {1cd91b88-1dd2-11b2-92e1-ed22ed298000} */ \
+ 0x91ca2441, \
+ 0x050f, \
+ 0x4f7c, \
+ { 0x9d, 0xf8, 0x75, 0xb4, 0x0e, 0xa4, 0x01, 0x56 } \
+ }
+
+#define NS_PREFSERVICE_CONTRACTID "@mozilla.org/preferences-service;1"
+
+/**
+ * Notification sent before reading the default user preferences files.
+ */
+#define NS_PREFSERVICE_READ_TOPIC_ID "prefservice:before-read-userprefs"
+
+/**
+ * Notification sent when resetPrefs has been called, but before the actual
+ * reset process occurs.
+ */
+#define NS_PREFSERVICE_RESET_TOPIC_ID "prefservice:before-reset"
+
+/**
+ * Notification sent when after reading app-provided default
+ * preferences, but before user profile override defaults or extension
+ * defaults are loaded.
+ */
+#define NS_PREFSERVICE_APPDEFAULTS_TOPIC_ID "prefservice:after-app-defaults"
+
+%}
diff --git a/modules/libpref/nsIRelativeFilePref.idl b/modules/libpref/nsIRelativeFilePref.idl
new file mode 100644
index 000000000..4b86e3755
--- /dev/null
+++ b/modules/libpref/nsIRelativeFilePref.idl
@@ -0,0 +1,69 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "nsISupports.idl"
+interface nsIFile;
+
+/**
+ * The nsIRelativeFilePref interface is a wrapper for an nsIFile and
+ * and a directory service key. When used as a pref value, it stores a
+ * relative path to the file from the location pointed to by the directory
+ * service key. The path has the same syntax across all platforms.
+ *
+ * @see nsIPrefBranch::getComplexValue
+ * @see nsIPrefBranch::setComplexValue
+ *
+ */
+
+[scriptable, uuid(2f977d4e-5485-11d4-87e2-0010a4e75ef2)]
+interface nsIRelativeFilePref : nsISupports
+{
+ /**
+ * file
+ *
+ * The file whose location is stored or retrieved.
+ */
+ attribute nsIFile file;
+
+ /**
+ * relativeToKey
+ *
+ * A directory service key for the directory
+ * from which the file path is relative.
+ */
+ attribute ACString relativeToKey;
+
+};
+
+%{C++
+
+#define NS_RELATIVEFILEPREF_CID \
+ { /* {2f977d4f-5485-11d4-87e2-0010a4e75ef2} */ \
+ 0x2f977d4f, \
+ 0x5485, \
+ 0x11d4, \
+ { 0x87, 0xe2, 0x00, 0x10, 0xa4, 0xe7, 0x5e, 0xf2 } \
+ }
+
+#define NS_RELATIVEFILEPREF_CONTRACTID "@mozilla.org/pref-relativefile;1"
+
+#include "nsComponentManagerUtils.h"
+
+inline nsresult
+NS_NewRelativeFilePref(nsIFile* aFile, const nsACString& relativeToKey, nsIRelativeFilePref** result)
+{
+ nsresult rv;
+ nsCOMPtr<nsIRelativeFilePref> local(do_CreateInstance(NS_RELATIVEFILEPREF_CONTRACTID, &rv));
+ if (NS_FAILED(rv)) return rv;
+
+ (void)local->SetFile(aFile);
+ (void)local->SetRelativeToKey(relativeToKey);
+
+ *result = local;
+ NS_ADDREF(*result);
+ return NS_OK;
+}
+
+%}
diff --git a/modules/libpref/nsPrefBranch.cpp b/modules/libpref/nsPrefBranch.cpp
new file mode 100644
index 000000000..2fd4992c8
--- /dev/null
+++ b/modules/libpref/nsPrefBranch.cpp
@@ -0,0 +1,901 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "mozilla/dom/ContentChild.h"
+#include "nsXULAppAPI.h"
+
+#include "nsPrefBranch.h"
+#include "nsILocalFile.h" // nsILocalFile used for backwards compatibility
+#include "nsIObserverService.h"
+#include "nsXPCOM.h"
+#include "nsISupportsPrimitives.h"
+#include "nsIDirectoryService.h"
+#include "nsString.h"
+#include "nsReadableUtils.h"
+#include "nsXPIDLString.h"
+#include "nsPrintfCString.h"
+#include "nsIStringBundle.h"
+#include "prefapi.h"
+#include "PLDHashTable.h"
+
+#include "nsCRT.h"
+#include "mozilla/Services.h"
+
+#include "prefapi_private_data.h"
+
+#ifdef MOZ_CRASHREPORTER
+#include "nsICrashReporter.h"
+#endif
+
+#include "nsIConsoleService.h"
+
+#ifdef DEBUG
+#define ENSURE_MAIN_PROCESS(message, pref) do { \
+ if (GetContentChild()) { \
+ nsPrintfCString msg("ENSURE_MAIN_PROCESS failed. %s %s", message, pref); \
+ NS_ERROR(msg.get()); \
+ return NS_ERROR_NOT_AVAILABLE; \
+ } \
+} while (0);
+#else
+#define ENSURE_MAIN_PROCESS(message, pref) \
+ if (GetContentChild()) { \
+ return NS_ERROR_NOT_AVAILABLE; \
+ }
+#endif
+
+using mozilla::dom::ContentChild;
+
+static ContentChild*
+GetContentChild()
+{
+ if (XRE_IsContentProcess()) {
+ ContentChild* cpc = ContentChild::GetSingleton();
+ if (!cpc) {
+ NS_RUNTIMEABORT("Content Protocol is NULL! We're going to crash!");
+ }
+ return cpc;
+ }
+ return nullptr;
+}
+
+/*
+ * Constructor/Destructor
+ */
+
+nsPrefBranch::nsPrefBranch(const char *aPrefRoot, bool aDefaultBranch)
+{
+ mPrefRoot = aPrefRoot;
+ mPrefRootLength = mPrefRoot.Length();
+ mIsDefault = aDefaultBranch;
+ mFreeingObserverList = false;
+
+ nsCOMPtr<nsIObserverService> observerService =
+ mozilla::services::GetObserverService();
+ if (observerService) {
+ ++mRefCnt; // Our refcnt must be > 0 when we call this, or we'll get deleted!
+ // add weak so we don't have to clean up at shutdown
+ observerService->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, true);
+ --mRefCnt;
+ }
+}
+
+nsPrefBranch::~nsPrefBranch()
+{
+ freeObserverList();
+
+ nsCOMPtr<nsIObserverService> observerService =
+ mozilla::services::GetObserverService();
+ if (observerService)
+ observerService->RemoveObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID);
+}
+
+
+/*
+ * nsISupports Implementation
+ */
+
+NS_IMPL_ADDREF(nsPrefBranch)
+NS_IMPL_RELEASE(nsPrefBranch)
+
+NS_INTERFACE_MAP_BEGIN(nsPrefBranch)
+ NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIPrefBranch)
+ NS_INTERFACE_MAP_ENTRY(nsIPrefBranch)
+ NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIPrefBranch2, !mIsDefault)
+ NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIPrefBranchInternal, !mIsDefault)
+ NS_INTERFACE_MAP_ENTRY(nsIObserver)
+ NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
+NS_INTERFACE_MAP_END
+
+
+/*
+ * nsIPrefBranch Implementation
+ */
+
+NS_IMETHODIMP nsPrefBranch::GetRoot(char **aRoot)
+{
+ NS_ENSURE_ARG_POINTER(aRoot);
+ mPrefRoot.Truncate(mPrefRootLength);
+ *aRoot = ToNewCString(mPrefRoot);
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsPrefBranch::GetPrefType(const char *aPrefName, int32_t *_retval)
+{
+ NS_ENSURE_ARG(aPrefName);
+ const char *pref = getPrefName(aPrefName);
+ switch (PREF_GetPrefType(pref)) {
+ case PrefType::String:
+ *_retval = PREF_STRING;
+ break;
+ case PrefType::Int:
+ *_retval = PREF_INT;
+ break;
+ case PrefType::Bool:
+ *_retval = PREF_BOOL;
+ break;
+ case PrefType::Invalid:
+ default:
+ *_retval = PREF_INVALID;
+ break;
+ }
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsPrefBranch::GetBoolPref(const char *aPrefName, bool *_retval)
+{
+ NS_ENSURE_ARG(aPrefName);
+ const char *pref = getPrefName(aPrefName);
+ return PREF_GetBoolPref(pref, _retval, mIsDefault);
+}
+
+NS_IMETHODIMP nsPrefBranch::SetBoolPref(const char *aPrefName, bool aValue)
+{
+ ENSURE_MAIN_PROCESS("Cannot SetBoolPref from content process:", aPrefName);
+ NS_ENSURE_ARG(aPrefName);
+ const char *pref = getPrefName(aPrefName);
+ return PREF_SetBoolPref(pref, aValue, mIsDefault);
+}
+
+NS_IMETHODIMP nsPrefBranch::GetFloatPref(const char *aPrefName, float *_retval)
+{
+ NS_ENSURE_ARG(aPrefName);
+ const char *pref = getPrefName(aPrefName);
+ nsAutoCString stringVal;
+ nsresult rv = GetCharPref(pref, getter_Copies(stringVal));
+ if (NS_SUCCEEDED(rv)) {
+ *_retval = stringVal.ToFloat(&rv);
+ }
+
+ return rv;
+}
+
+NS_IMETHODIMP nsPrefBranch::GetCharPref(const char *aPrefName, char **_retval)
+{
+ NS_ENSURE_ARG(aPrefName);
+ const char *pref = getPrefName(aPrefName);
+ return PREF_CopyCharPref(pref, _retval, mIsDefault);
+}
+
+NS_IMETHODIMP nsPrefBranch::SetCharPref(const char *aPrefName, const char *aValue)
+{
+ nsresult rv = CheckSanityOfStringLength(aPrefName, aValue);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ return SetCharPrefInternal(aPrefName, aValue);
+}
+
+nsresult nsPrefBranch::SetCharPrefInternal(const char *aPrefName, const char *aValue)
+
+{
+ ENSURE_MAIN_PROCESS("Cannot SetCharPref from content process:", aPrefName);
+ NS_ENSURE_ARG(aPrefName);
+ NS_ENSURE_ARG(aValue);
+ const char *pref = getPrefName(aPrefName);
+ return PREF_SetCharPref(pref, aValue, mIsDefault);
+}
+
+NS_IMETHODIMP nsPrefBranch::GetIntPref(const char *aPrefName, int32_t *_retval)
+{
+ NS_ENSURE_ARG(aPrefName);
+ const char *pref = getPrefName(aPrefName);
+ return PREF_GetIntPref(pref, _retval, mIsDefault);
+}
+
+NS_IMETHODIMP nsPrefBranch::SetIntPref(const char *aPrefName, int32_t aValue)
+{
+ ENSURE_MAIN_PROCESS("Cannot SetIntPref from content process:", aPrefName);
+ NS_ENSURE_ARG(aPrefName);
+ const char *pref = getPrefName(aPrefName);
+ return PREF_SetIntPref(pref, aValue, mIsDefault);
+}
+
+NS_IMETHODIMP nsPrefBranch::GetComplexValue(const char *aPrefName, const nsIID & aType, void **_retval)
+{
+ NS_ENSURE_ARG(aPrefName);
+
+ nsresult rv;
+ nsXPIDLCString utf8String;
+
+ // we have to do this one first because it's different than all the rest
+ if (aType.Equals(NS_GET_IID(nsIPrefLocalizedString))) {
+ nsCOMPtr<nsIPrefLocalizedString> theString(do_CreateInstance(NS_PREFLOCALIZEDSTRING_CONTRACTID, &rv));
+ if (NS_FAILED(rv)) return rv;
+
+ const char *pref = getPrefName(aPrefName);
+ bool bNeedDefault = false;
+
+ if (mIsDefault) {
+ bNeedDefault = true;
+ } else {
+ // if there is no user (or locked) value
+ if (!PREF_HasUserPref(pref) && !PREF_PrefIsLocked(pref)) {
+ bNeedDefault = true;
+ }
+ }
+
+ // if we need to fetch the default value, do that instead, otherwise use the
+ // value we pulled in at the top of this function
+ if (bNeedDefault) {
+ nsXPIDLString utf16String;
+ rv = GetDefaultFromPropertiesFile(pref, getter_Copies(utf16String));
+ if (NS_SUCCEEDED(rv)) {
+ theString->SetData(utf16String.get());
+ }
+ } else {
+ rv = GetCharPref(aPrefName, getter_Copies(utf8String));
+ if (NS_SUCCEEDED(rv)) {
+ theString->SetData(NS_ConvertUTF8toUTF16(utf8String).get());
+ }
+ }
+
+ if (NS_SUCCEEDED(rv)) {
+ theString.forget(reinterpret_cast<nsIPrefLocalizedString**>(_retval));
+ }
+
+ return rv;
+ }
+
+ // if we can't get the pref, there's no point in being here
+ rv = GetCharPref(aPrefName, getter_Copies(utf8String));
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+
+ // also check nsILocalFile, for backwards compatibility
+ if (aType.Equals(NS_GET_IID(nsIFile)) || aType.Equals(NS_GET_IID(nsILocalFile))) {
+ if (GetContentChild()) {
+ NS_ERROR("cannot get nsIFile pref from content process");
+ return NS_ERROR_NOT_AVAILABLE;
+ }
+
+ nsCOMPtr<nsIFile> file(do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv));
+
+ if (NS_SUCCEEDED(rv)) {
+ rv = file->SetPersistentDescriptor(utf8String);
+ if (NS_SUCCEEDED(rv)) {
+ file.forget(reinterpret_cast<nsIFile**>(_retval));
+ return NS_OK;
+ }
+ }
+ return rv;
+ }
+
+ if (aType.Equals(NS_GET_IID(nsIRelativeFilePref))) {
+ if (GetContentChild()) {
+ NS_ERROR("cannot get nsIRelativeFilePref from content process");
+ return NS_ERROR_NOT_AVAILABLE;
+ }
+
+ nsACString::const_iterator keyBegin, strEnd;
+ utf8String.BeginReading(keyBegin);
+ utf8String.EndReading(strEnd);
+
+ // The pref has the format: [fromKey]a/b/c
+ if (*keyBegin++ != '[')
+ return NS_ERROR_FAILURE;
+ nsACString::const_iterator keyEnd(keyBegin);
+ if (!FindCharInReadable(']', keyEnd, strEnd))
+ return NS_ERROR_FAILURE;
+ nsAutoCString key(Substring(keyBegin, keyEnd));
+
+ nsCOMPtr<nsIFile> fromFile;
+ nsCOMPtr<nsIProperties> directoryService(do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID, &rv));
+ if (NS_FAILED(rv))
+ return rv;
+ rv = directoryService->Get(key.get(), NS_GET_IID(nsIFile), getter_AddRefs(fromFile));
+ if (NS_FAILED(rv))
+ return rv;
+
+ nsCOMPtr<nsIFile> theFile;
+ rv = NS_NewNativeLocalFile(EmptyCString(), true, getter_AddRefs(theFile));
+ if (NS_FAILED(rv))
+ return rv;
+ rv = theFile->SetRelativeDescriptor(fromFile, Substring(++keyEnd, strEnd));
+ if (NS_FAILED(rv))
+ return rv;
+ nsCOMPtr<nsIRelativeFilePref> relativePref;
+ rv = NS_NewRelativeFilePref(theFile, key, getter_AddRefs(relativePref));
+ if (NS_FAILED(rv))
+ return rv;
+
+ relativePref.forget(reinterpret_cast<nsIRelativeFilePref**>(_retval));
+ return NS_OK;
+ }
+
+ if (aType.Equals(NS_GET_IID(nsISupportsString))) {
+ nsCOMPtr<nsISupportsString> theString(do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID, &rv));
+
+ if (NS_SUCCEEDED(rv)) {
+ // Debugging to see why we end up with very long strings here with
+ // some addons, see bug 836263.
+ nsAutoString wdata;
+ if (!AppendUTF8toUTF16(utf8String, wdata, mozilla::fallible)) {
+#ifdef MOZ_CRASHREPORTER
+ nsCOMPtr<nsICrashReporter> cr =
+ do_GetService("@mozilla.org/toolkit/crash-reporter;1");
+ if (cr) {
+ cr->AnnotateCrashReport(NS_LITERAL_CSTRING("bug836263-size"),
+ nsPrintfCString("%x", utf8String.Length()));
+ cr->RegisterAppMemory(uint64_t(utf8String.BeginReading()),
+ std::min(0x1000U, utf8String.Length()));
+ }
+#endif
+ NS_RUNTIMEABORT("bug836263");
+ }
+ theString->SetData(wdata);
+ theString.forget(reinterpret_cast<nsISupportsString**>(_retval));
+ }
+ return rv;
+ }
+
+ NS_WARNING("nsPrefBranch::GetComplexValue - Unsupported interface type");
+ return NS_NOINTERFACE;
+}
+
+nsresult nsPrefBranch::CheckSanityOfStringLength(const char* aPrefName, const char* aValue) {
+ if (!aValue) {
+ return NS_OK;
+ }
+ return CheckSanityOfStringLength(aPrefName, strlen(aValue));
+}
+
+nsresult nsPrefBranch::CheckSanityOfStringLength(const char* aPrefName, const nsAString& aValue) {
+ return CheckSanityOfStringLength(aPrefName, aValue.Length());
+}
+
+nsresult nsPrefBranch::CheckSanityOfStringLength(const char* aPrefName, const uint32_t aLength) {
+ if (aLength > MAX_PREF_LENGTH) {
+ return NS_ERROR_ILLEGAL_VALUE;
+ }
+ if (aLength <= MAX_ADVISABLE_PREF_LENGTH) {
+ return NS_OK;
+ }
+ nsresult rv;
+ nsCOMPtr<nsIConsoleService> console = do_GetService("@mozilla.org/consoleservice;1", &rv);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ nsAutoCString message(nsPrintfCString("Warning: attempting to write %d bytes to preference %s. This is bad "
+ "for general performance and memory usage. Such an amount of data "
+ "should rather be written to an external file. This preference will "
+ "not be sent to any content processes.",
+ aLength,
+ getPrefName(aPrefName)));
+ rv = console->LogStringMessage(NS_ConvertUTF8toUTF16(message).get());
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ return NS_OK;
+}
+
+/*static*/
+void nsPrefBranch::ReportToConsole(const nsAString& aMessage)
+{
+ nsresult rv;
+ nsCOMPtr<nsIConsoleService> console = do_GetService("@mozilla.org/consoleservice;1", &rv);
+ if (NS_FAILED(rv)) {
+ return;
+ }
+ nsAutoString message(aMessage);
+ console->LogStringMessage(message.get());
+}
+
+NS_IMETHODIMP nsPrefBranch::SetComplexValue(const char *aPrefName, const nsIID & aType, nsISupports *aValue)
+{
+ ENSURE_MAIN_PROCESS("Cannot SetComplexValue from content process:", aPrefName);
+ NS_ENSURE_ARG(aPrefName);
+
+ nsresult rv = NS_NOINTERFACE;
+
+ // also check nsILocalFile, for backwards compatibility
+ if (aType.Equals(NS_GET_IID(nsIFile)) || aType.Equals(NS_GET_IID(nsILocalFile))) {
+ nsCOMPtr<nsIFile> file = do_QueryInterface(aValue);
+ if (!file)
+ return NS_NOINTERFACE;
+ nsAutoCString descriptorString;
+
+ rv = file->GetPersistentDescriptor(descriptorString);
+ if (NS_SUCCEEDED(rv)) {
+ rv = SetCharPrefInternal(aPrefName, descriptorString.get());
+ }
+ return rv;
+ }
+
+ if (aType.Equals(NS_GET_IID(nsIRelativeFilePref))) {
+ nsCOMPtr<nsIRelativeFilePref> relFilePref = do_QueryInterface(aValue);
+ if (!relFilePref)
+ return NS_NOINTERFACE;
+
+ nsCOMPtr<nsIFile> file;
+ relFilePref->GetFile(getter_AddRefs(file));
+ if (!file)
+ return NS_NOINTERFACE;
+ nsAutoCString relativeToKey;
+ (void) relFilePref->GetRelativeToKey(relativeToKey);
+
+ nsCOMPtr<nsIFile> relativeToFile;
+ nsCOMPtr<nsIProperties> directoryService(do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID, &rv));
+ if (NS_FAILED(rv))
+ return rv;
+ rv = directoryService->Get(relativeToKey.get(), NS_GET_IID(nsIFile), getter_AddRefs(relativeToFile));
+ if (NS_FAILED(rv))
+ return rv;
+
+ nsAutoCString relDescriptor;
+ rv = file->GetRelativeDescriptor(relativeToFile, relDescriptor);
+ if (NS_FAILED(rv))
+ return rv;
+
+ nsAutoCString descriptorString;
+ descriptorString.Append('[');
+ descriptorString.Append(relativeToKey);
+ descriptorString.Append(']');
+ descriptorString.Append(relDescriptor);
+ return SetCharPrefInternal(aPrefName, descriptorString.get());
+ }
+
+ if (aType.Equals(NS_GET_IID(nsISupportsString))) {
+ nsCOMPtr<nsISupportsString> theString = do_QueryInterface(aValue);
+
+ if (theString) {
+ nsString wideString;
+
+ rv = theString->GetData(wideString);
+ if (NS_SUCCEEDED(rv)) {
+ // Check sanity of string length before any lengthy conversion
+ rv = CheckSanityOfStringLength(aPrefName, wideString);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = SetCharPrefInternal(aPrefName, NS_ConvertUTF16toUTF8(wideString).get());
+ }
+ }
+ return rv;
+ }
+
+ if (aType.Equals(NS_GET_IID(nsIPrefLocalizedString))) {
+ nsCOMPtr<nsIPrefLocalizedString> theString = do_QueryInterface(aValue);
+
+ if (theString) {
+ nsXPIDLString wideString;
+
+ rv = theString->GetData(getter_Copies(wideString));
+ if (NS_SUCCEEDED(rv)) {
+ // Check sanity of string length before any lengthy conversion
+ rv = CheckSanityOfStringLength(aPrefName, wideString);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = SetCharPrefInternal(aPrefName, NS_ConvertUTF16toUTF8(wideString).get());
+ }
+ }
+ return rv;
+ }
+
+ NS_WARNING("nsPrefBranch::SetComplexValue - Unsupported interface type");
+ return NS_NOINTERFACE;
+}
+
+NS_IMETHODIMP nsPrefBranch::ClearUserPref(const char *aPrefName)
+{
+ ENSURE_MAIN_PROCESS("Cannot ClearUserPref from content process:", aPrefName);
+ NS_ENSURE_ARG(aPrefName);
+ const char *pref = getPrefName(aPrefName);
+ return PREF_ClearUserPref(pref);
+}
+
+NS_IMETHODIMP nsPrefBranch::PrefHasUserValue(const char *aPrefName, bool *_retval)
+{
+ NS_ENSURE_ARG_POINTER(_retval);
+ NS_ENSURE_ARG(aPrefName);
+ const char *pref = getPrefName(aPrefName);
+ *_retval = PREF_HasUserPref(pref);
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsPrefBranch::LockPref(const char *aPrefName)
+{
+ ENSURE_MAIN_PROCESS("Cannot LockPref from content process:", aPrefName);
+ NS_ENSURE_ARG(aPrefName);
+ const char *pref = getPrefName(aPrefName);
+ return PREF_LockPref(pref, true);
+}
+
+NS_IMETHODIMP nsPrefBranch::PrefIsLocked(const char *aPrefName, bool *_retval)
+{
+ ENSURE_MAIN_PROCESS("Cannot check PrefIsLocked from content process:", aPrefName);
+ NS_ENSURE_ARG_POINTER(_retval);
+ NS_ENSURE_ARG(aPrefName);
+ const char *pref = getPrefName(aPrefName);
+ *_retval = PREF_PrefIsLocked(pref);
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsPrefBranch::UnlockPref(const char *aPrefName)
+{
+ ENSURE_MAIN_PROCESS("Cannot UnlockPref from content process:", aPrefName);
+ NS_ENSURE_ARG(aPrefName);
+ const char *pref = getPrefName(aPrefName);
+ return PREF_LockPref(pref, false);
+}
+
+NS_IMETHODIMP nsPrefBranch::ResetBranch(const char *aStartingAt)
+{
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP nsPrefBranch::DeleteBranch(const char *aStartingAt)
+{
+ ENSURE_MAIN_PROCESS("Cannot DeleteBranch from content process:", aStartingAt);
+ NS_ENSURE_ARG(aStartingAt);
+ const char *pref = getPrefName(aStartingAt);
+ return PREF_DeleteBranch(pref);
+}
+
+NS_IMETHODIMP nsPrefBranch::GetChildList(const char *aStartingAt, uint32_t *aCount, char ***aChildArray)
+{
+ char **outArray;
+ int32_t numPrefs;
+ int32_t dwIndex;
+ AutoTArray<nsCString, 32> prefArray;
+
+ NS_ENSURE_ARG(aStartingAt);
+ NS_ENSURE_ARG_POINTER(aCount);
+ NS_ENSURE_ARG_POINTER(aChildArray);
+
+ *aChildArray = nullptr;
+ *aCount = 0;
+
+ // this will contain a list of all the pref name strings
+ // allocate on the stack for speed
+
+ const char* parent = getPrefName(aStartingAt);
+ size_t parentLen = strlen(parent);
+ for (auto iter = gHashTable->Iter(); !iter.Done(); iter.Next()) {
+ auto entry = static_cast<PrefHashEntry*>(iter.Get());
+ if (strncmp(entry->key, parent, parentLen) == 0) {
+ prefArray.AppendElement(entry->key);
+ }
+ }
+
+ // now that we've built up the list, run the callback on
+ // all the matching elements
+ numPrefs = prefArray.Length();
+
+ if (numPrefs) {
+ outArray = (char **)moz_xmalloc(numPrefs * sizeof(char *));
+ if (!outArray)
+ return NS_ERROR_OUT_OF_MEMORY;
+
+ for (dwIndex = 0; dwIndex < numPrefs; ++dwIndex) {
+ // we need to lop off mPrefRoot in case the user is planning to pass this
+ // back to us because if they do we are going to add mPrefRoot again.
+ const nsCString& element = prefArray[dwIndex];
+ outArray[dwIndex] = (char *)nsMemory::Clone(
+ element.get() + mPrefRootLength, element.Length() - mPrefRootLength + 1);
+
+ if (!outArray[dwIndex]) {
+ // we ran out of memory... this is annoying
+ NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(dwIndex, outArray);
+ return NS_ERROR_OUT_OF_MEMORY;
+ }
+ }
+ *aChildArray = outArray;
+ }
+ *aCount = numPrefs;
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsPrefBranch::AddObserver(const char *aDomain, nsIObserver *aObserver, bool aHoldWeak)
+{
+ PrefCallback *pCallback;
+ const char *pref;
+
+ NS_ENSURE_ARG(aDomain);
+ NS_ENSURE_ARG(aObserver);
+
+ // hold a weak reference to the observer if so requested
+ if (aHoldWeak) {
+ nsCOMPtr<nsISupportsWeakReference> weakRefFactory = do_QueryInterface(aObserver);
+ if (!weakRefFactory) {
+ // the caller didn't give us a object that supports weak reference... tell them
+ return NS_ERROR_INVALID_ARG;
+ }
+
+ // Construct a PrefCallback with a weak reference to the observer.
+ pCallback = new PrefCallback(aDomain, weakRefFactory, this);
+
+ } else {
+ // Construct a PrefCallback with a strong reference to the observer.
+ pCallback = new PrefCallback(aDomain, aObserver, this);
+ }
+
+ if (mObservers.Get(pCallback)) {
+ NS_WARNING("Ignoring duplicate observer.");
+ delete pCallback;
+ return NS_OK;
+ }
+
+ mObservers.Put(pCallback, pCallback);
+
+ // We must pass a fully qualified preference name to the callback
+ // aDomain == nullptr is the only possible failure, and we trapped it with
+ // NS_ENSURE_ARG above.
+ pref = getPrefName(aDomain);
+ PREF_RegisterCallback(pref, NotifyObserver, pCallback);
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsPrefBranch::RemoveObserver(const char *aDomain, nsIObserver *aObserver)
+{
+ NS_ENSURE_ARG(aDomain);
+ NS_ENSURE_ARG(aObserver);
+
+ nsresult rv = NS_OK;
+
+ // If we're in the middle of a call to freeObserverList, don't process this
+ // RemoveObserver call -- the observer in question will be removed soon, if
+ // it hasn't been already.
+ //
+ // It's important that we don't touch mObservers in any way -- even a Get()
+ // which returns null might cause the hashtable to resize itself, which will
+ // break the iteration in freeObserverList.
+ if (mFreeingObserverList)
+ return NS_OK;
+
+ // Remove the relevant PrefCallback from mObservers and get an owning
+ // pointer to it. Unregister the callback first, and then let the owning
+ // pointer go out of scope and destroy the callback.
+ PrefCallback key(aDomain, aObserver, this);
+ nsAutoPtr<PrefCallback> pCallback;
+ mObservers.RemoveAndForget(&key, pCallback);
+ if (pCallback) {
+ // aDomain == nullptr is the only possible failure, trapped above
+ const char *pref = getPrefName(aDomain);
+ rv = PREF_UnregisterCallback(pref, NotifyObserver, pCallback);
+ }
+
+ return rv;
+}
+
+NS_IMETHODIMP nsPrefBranch::Observe(nsISupports *aSubject, const char *aTopic, const char16_t *someData)
+{
+ // watch for xpcom shutdown and free our observers to eliminate any cyclic references
+ if (!nsCRT::strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID)) {
+ freeObserverList();
+ }
+ return NS_OK;
+}
+
+/* static */
+void nsPrefBranch::NotifyObserver(const char *newpref, void *data)
+{
+ PrefCallback *pCallback = (PrefCallback *)data;
+
+ nsCOMPtr<nsIObserver> observer = pCallback->GetObserver();
+ if (!observer) {
+ // The observer has expired. Let's remove this callback.
+ pCallback->GetPrefBranch()->RemoveExpiredCallback(pCallback);
+ return;
+ }
+
+ // remove any root this string may contain so as to not confuse the observer
+ // by passing them something other than what they passed us as a topic
+ uint32_t len = pCallback->GetPrefBranch()->GetRootLength();
+ nsAutoCString suffix(newpref + len);
+
+ observer->Observe(static_cast<nsIPrefBranch *>(pCallback->GetPrefBranch()),
+ NS_PREFBRANCH_PREFCHANGE_TOPIC_ID,
+ NS_ConvertASCIItoUTF16(suffix).get());
+}
+
+size_t
+nsPrefBranch::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf)
+{
+ size_t n = aMallocSizeOf(this);
+ n += mPrefRoot.SizeOfExcludingThisIfUnshared(aMallocSizeOf);
+ n += mObservers.ShallowSizeOfExcludingThis(aMallocSizeOf);
+ return n;
+}
+
+void nsPrefBranch::freeObserverList(void)
+{
+ // We need to prevent anyone from modifying mObservers while we're iterating
+ // over it. In particular, some clients will call RemoveObserver() when
+ // they're removed and destructed via the iterator; we set
+ // mFreeingObserverList to keep those calls from touching mObservers.
+ mFreeingObserverList = true;
+ for (auto iter = mObservers.Iter(); !iter.Done(); iter.Next()) {
+ nsAutoPtr<PrefCallback>& callback = iter.Data();
+ nsPrefBranch *prefBranch = callback->GetPrefBranch();
+ const char *pref = prefBranch->getPrefName(callback->GetDomain().get());
+ PREF_UnregisterCallback(pref, nsPrefBranch::NotifyObserver, callback);
+ iter.Remove();
+ }
+ mFreeingObserverList = false;
+}
+
+void
+nsPrefBranch::RemoveExpiredCallback(PrefCallback *aCallback)
+{
+ NS_PRECONDITION(aCallback->IsExpired(), "Callback should be expired.");
+ mObservers.Remove(aCallback);
+}
+
+nsresult nsPrefBranch::GetDefaultFromPropertiesFile(const char *aPrefName, char16_t **return_buf)
+{
+ nsresult rv;
+
+ // the default value contains a URL to a .properties file
+
+ nsXPIDLCString propertyFileURL;
+ rv = PREF_CopyCharPref(aPrefName, getter_Copies(propertyFileURL), true);
+ if (NS_FAILED(rv))
+ return rv;
+
+ nsCOMPtr<nsIStringBundleService> bundleService =
+ mozilla::services::GetStringBundleService();
+ if (!bundleService)
+ return NS_ERROR_FAILURE;
+
+ nsCOMPtr<nsIStringBundle> bundle;
+ rv = bundleService->CreateBundle(propertyFileURL,
+ getter_AddRefs(bundle));
+ if (NS_FAILED(rv))
+ return rv;
+
+ // string names are in unicode
+ nsAutoString stringId;
+ stringId.AssignASCII(aPrefName);
+
+ return bundle->GetStringFromName(stringId.get(), return_buf);
+}
+
+const char *nsPrefBranch::getPrefName(const char *aPrefName)
+{
+ NS_ASSERTION(aPrefName, "null pref name!");
+
+ // for speed, avoid strcpy if we can:
+ if (mPrefRoot.IsEmpty())
+ return aPrefName;
+
+ // isn't there a better way to do this? this is really kind of gross.
+ mPrefRoot.Truncate(mPrefRootLength);
+ mPrefRoot.Append(aPrefName);
+ return mPrefRoot.get();
+}
+
+//----------------------------------------------------------------------------
+// nsPrefLocalizedString
+//----------------------------------------------------------------------------
+
+nsPrefLocalizedString::nsPrefLocalizedString()
+{
+}
+
+nsPrefLocalizedString::~nsPrefLocalizedString()
+{
+}
+
+
+/*
+ * nsISupports Implementation
+ */
+
+NS_IMPL_ADDREF(nsPrefLocalizedString)
+NS_IMPL_RELEASE(nsPrefLocalizedString)
+
+NS_INTERFACE_MAP_BEGIN(nsPrefLocalizedString)
+ NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIPrefLocalizedString)
+ NS_INTERFACE_MAP_ENTRY(nsIPrefLocalizedString)
+ NS_INTERFACE_MAP_ENTRY(nsISupportsString)
+NS_INTERFACE_MAP_END
+
+nsresult nsPrefLocalizedString::Init()
+{
+ nsresult rv;
+ mUnicodeString = do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID, &rv);
+
+ return rv;
+}
+
+NS_IMETHODIMP
+nsPrefLocalizedString::GetData(char16_t **_retval)
+{
+ nsAutoString data;
+
+ nsresult rv = GetData(data);
+ if (NS_FAILED(rv))
+ return rv;
+
+ *_retval = ToNewUnicode(data);
+ if (!*_retval)
+ return NS_ERROR_OUT_OF_MEMORY;
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsPrefLocalizedString::SetData(const char16_t *aData)
+{
+ if (!aData)
+ return SetData(EmptyString());
+ return SetData(nsDependentString(aData));
+}
+
+NS_IMETHODIMP
+nsPrefLocalizedString::SetDataWithLength(uint32_t aLength,
+ const char16_t *aData)
+{
+ if (!aData)
+ return SetData(EmptyString());
+ return SetData(Substring(aData, aLength));
+}
+
+//----------------------------------------------------------------------------
+// nsRelativeFilePref
+//----------------------------------------------------------------------------
+
+NS_IMPL_ISUPPORTS(nsRelativeFilePref, nsIRelativeFilePref)
+
+nsRelativeFilePref::nsRelativeFilePref()
+{
+}
+
+nsRelativeFilePref::~nsRelativeFilePref()
+{
+}
+
+NS_IMETHODIMP nsRelativeFilePref::GetFile(nsIFile **aFile)
+{
+ NS_ENSURE_ARG_POINTER(aFile);
+ *aFile = mFile;
+ NS_IF_ADDREF(*aFile);
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsRelativeFilePref::SetFile(nsIFile *aFile)
+{
+ mFile = aFile;
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsRelativeFilePref::GetRelativeToKey(nsACString& aRelativeToKey)
+{
+ aRelativeToKey.Assign(mRelativeToKey);
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsRelativeFilePref::SetRelativeToKey(const nsACString& aRelativeToKey)
+{
+ mRelativeToKey.Assign(aRelativeToKey);
+ return NS_OK;
+}
+
+#undef ENSURE_MAIN_PROCESS
diff --git a/modules/libpref/nsPrefBranch.h b/modules/libpref/nsPrefBranch.h
new file mode 100644
index 000000000..37cf5c2c4
--- /dev/null
+++ b/modules/libpref/nsPrefBranch.h
@@ -0,0 +1,269 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef nsPrefBranch_h
+#define nsPrefBranch_h
+
+#include "nsCOMPtr.h"
+#include "nsIObserver.h"
+#include "nsIPrefBranch.h"
+#include "nsIPrefBranchInternal.h"
+#include "nsIPrefLocalizedString.h"
+#include "nsXPCOM.h"
+#include "nsISupportsPrimitives.h"
+#include "nsIRelativeFilePref.h"
+#include "nsIFile.h"
+#include "nsString.h"
+#include "nsTArray.h"
+#include "nsWeakReference.h"
+#include "nsClassHashtable.h"
+#include "nsCRT.h"
+#include "nsISupportsImpl.h"
+#include "mozilla/HashFunctions.h"
+#include "mozilla/MemoryReporting.h"
+
+namespace mozilla {
+class PreferenceServiceReporter;
+} // namespace mozilla
+
+class nsPrefBranch;
+
+class PrefCallback : public PLDHashEntryHdr {
+ friend class mozilla::PreferenceServiceReporter;
+
+ public:
+ typedef PrefCallback* KeyType;
+ typedef const PrefCallback* KeyTypePointer;
+
+ static const PrefCallback* KeyToPointer(PrefCallback *aKey)
+ {
+ return aKey;
+ }
+
+ static PLDHashNumber HashKey(const PrefCallback *aKey)
+ {
+ uint32_t hash = mozilla::HashString(aKey->mDomain);
+ return mozilla::AddToHash(hash, aKey->mCanonical);
+ }
+
+
+ public:
+ // Create a PrefCallback with a strong reference to its observer.
+ PrefCallback(const char *aDomain, nsIObserver *aObserver,
+ nsPrefBranch *aBranch)
+ : mDomain(aDomain),
+ mBranch(aBranch),
+ mWeakRef(nullptr),
+ mStrongRef(aObserver)
+ {
+ MOZ_COUNT_CTOR(PrefCallback);
+ nsCOMPtr<nsISupports> canonical = do_QueryInterface(aObserver);
+ mCanonical = canonical;
+ }
+
+ // Create a PrefCallback with a weak reference to its observer.
+ PrefCallback(const char *aDomain,
+ nsISupportsWeakReference *aObserver,
+ nsPrefBranch *aBranch)
+ : mDomain(aDomain),
+ mBranch(aBranch),
+ mWeakRef(do_GetWeakReference(aObserver)),
+ mStrongRef(nullptr)
+ {
+ MOZ_COUNT_CTOR(PrefCallback);
+ nsCOMPtr<nsISupports> canonical = do_QueryInterface(aObserver);
+ mCanonical = canonical;
+ }
+
+ // Copy constructor needs to be explicit or the linker complains.
+ explicit PrefCallback(const PrefCallback *&aCopy)
+ : mDomain(aCopy->mDomain),
+ mBranch(aCopy->mBranch),
+ mWeakRef(aCopy->mWeakRef),
+ mStrongRef(aCopy->mStrongRef),
+ mCanonical(aCopy->mCanonical)
+ {
+ MOZ_COUNT_CTOR(PrefCallback);
+ }
+
+ ~PrefCallback()
+ {
+ MOZ_COUNT_DTOR(PrefCallback);
+ }
+
+ bool KeyEquals(const PrefCallback *aKey) const
+ {
+ // We want to be able to look up a weakly-referencing PrefCallback after
+ // its observer has died so we can remove it from the table. Once the
+ // callback's observer dies, its canonical pointer is stale -- in
+ // particular, we may have allocated a new observer in the same spot in
+ // memory! So we can't just compare canonical pointers to determine
+ // whether aKey refers to the same observer as this.
+ //
+ // Our workaround is based on the way we use this hashtable: When we ask
+ // the hashtable to remove a PrefCallback whose weak reference has
+ // expired, we use as the key for removal the same object as was inserted
+ // into the hashtable. Thus we can say that if one of the keys' weak
+ // references has expired, the two keys are equal iff they're the same
+ // object.
+
+ if (IsExpired() || aKey->IsExpired())
+ return this == aKey;
+
+ if (mCanonical != aKey->mCanonical)
+ return false;
+
+ return mDomain.Equals(aKey->mDomain);
+ }
+
+ PrefCallback *GetKey() const
+ {
+ return const_cast<PrefCallback*>(this);
+ }
+
+ // Get a reference to the callback's observer, or null if the observer was
+ // weakly referenced and has been destroyed.
+ already_AddRefed<nsIObserver> GetObserver() const
+ {
+ if (!IsWeak()) {
+ nsCOMPtr<nsIObserver> copy = mStrongRef;
+ return copy.forget();
+ }
+
+ nsCOMPtr<nsIObserver> observer = do_QueryReferent(mWeakRef);
+ return observer.forget();
+ }
+
+ const nsCString& GetDomain() const
+ {
+ return mDomain;
+ }
+
+ nsPrefBranch* GetPrefBranch() const
+ {
+ return mBranch;
+ }
+
+ // Has this callback's weak reference died?
+ bool IsExpired() const
+ {
+ if (!IsWeak())
+ return false;
+
+ nsCOMPtr<nsIObserver> observer(do_QueryReferent(mWeakRef));
+ return !observer;
+ }
+
+ enum { ALLOW_MEMMOVE = true };
+
+ private:
+ nsCString mDomain;
+ nsPrefBranch *mBranch;
+
+ // Exactly one of mWeakRef and mStrongRef should be non-null.
+ nsWeakPtr mWeakRef;
+ nsCOMPtr<nsIObserver> mStrongRef;
+
+ // We need a canonical nsISupports pointer, per bug 578392.
+ nsISupports *mCanonical;
+
+ bool IsWeak() const
+ {
+ return !!mWeakRef;
+ }
+};
+
+class nsPrefBranch final : public nsIPrefBranchInternal,
+ public nsIObserver,
+ public nsSupportsWeakReference
+{
+ friend class mozilla::PreferenceServiceReporter;
+public:
+ NS_DECL_ISUPPORTS
+ NS_DECL_NSIPREFBRANCH
+ NS_DECL_NSIPREFBRANCH2
+ NS_DECL_NSIOBSERVER
+
+ nsPrefBranch(const char *aPrefRoot, bool aDefaultBranch);
+
+ int32_t GetRootLength() { return mPrefRootLength; }
+
+ nsresult RemoveObserverFromMap(const char *aDomain, nsISupports *aObserver);
+
+ static void NotifyObserver(const char *newpref, void *data);
+
+ size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf);
+
+ static void ReportToConsole(const nsAString& aMessage);
+
+protected:
+ virtual ~nsPrefBranch();
+
+ nsPrefBranch() /* disallow use of this constructer */
+ : mPrefRootLength(0)
+ , mIsDefault(false)
+ , mFreeingObserverList(false)
+ {}
+
+ nsresult GetDefaultFromPropertiesFile(const char *aPrefName, char16_t **return_buf);
+ // As SetCharPref, but without any check on the length of |aValue|
+ nsresult SetCharPrefInternal(const char *aPrefName, const char *aValue);
+ // Reject strings that are more than 1Mb, warn if strings are more than 16kb
+ nsresult CheckSanityOfStringLength(const char* aPrefName, const nsAString& aValue);
+ nsresult CheckSanityOfStringLength(const char* aPrefName, const char* aValue);
+ nsresult CheckSanityOfStringLength(const char* aPrefName, const uint32_t aLength);
+ void RemoveExpiredCallback(PrefCallback *aCallback);
+ const char *getPrefName(const char *aPrefName);
+ void freeObserverList(void);
+
+private:
+ int32_t mPrefRootLength;
+ nsCString mPrefRoot;
+ bool mIsDefault;
+
+ bool mFreeingObserverList;
+ nsClassHashtable<PrefCallback, PrefCallback> mObservers;
+};
+
+
+class nsPrefLocalizedString final : public nsIPrefLocalizedString,
+ public nsISupportsString
+{
+public:
+ nsPrefLocalizedString();
+
+ NS_DECL_ISUPPORTS
+ NS_FORWARD_NSISUPPORTSSTRING(mUnicodeString->)
+ NS_FORWARD_NSISUPPORTSPRIMITIVE(mUnicodeString->)
+
+ nsresult Init();
+
+private:
+ virtual ~nsPrefLocalizedString();
+
+ NS_IMETHOD GetData(char16_t**) override;
+ NS_IMETHOD SetData(const char16_t* aData) override;
+ NS_IMETHOD SetDataWithLength(uint32_t aLength, const char16_t *aData) override;
+
+ nsCOMPtr<nsISupportsString> mUnicodeString;
+};
+
+
+class nsRelativeFilePref : public nsIRelativeFilePref
+{
+public:
+ NS_DECL_ISUPPORTS
+ NS_DECL_NSIRELATIVEFILEPREF
+
+ nsRelativeFilePref();
+
+private:
+ virtual ~nsRelativeFilePref();
+
+ nsCOMPtr<nsIFile> mFile;
+ nsCString mRelativeToKey;
+};
+
+#endif
diff --git a/modules/libpref/nsPrefsFactory.cpp b/modules/libpref/nsPrefsFactory.cpp
new file mode 100644
index 000000000..35a9885b9
--- /dev/null
+++ b/modules/libpref/nsPrefsFactory.cpp
@@ -0,0 +1,54 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "mozilla/ModuleUtils.h"
+#include "mozilla/Preferences.h"
+#include "nsPrefBranch.h"
+#include "prefapi.h"
+
+using namespace mozilla;
+
+NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(Preferences,
+ Preferences::GetInstanceForService)
+NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsPrefLocalizedString, Init)
+NS_GENERIC_FACTORY_CONSTRUCTOR(nsRelativeFilePref)
+
+static NS_DEFINE_CID(kPrefServiceCID, NS_PREFSERVICE_CID);
+static NS_DEFINE_CID(kPrefLocalizedStringCID, NS_PREFLOCALIZEDSTRING_CID);
+static NS_DEFINE_CID(kRelativeFilePrefCID, NS_RELATIVEFILEPREF_CID);
+
+static mozilla::Module::CIDEntry kPrefCIDs[] = {
+ { &kPrefServiceCID, true, nullptr, PreferencesConstructor },
+ { &kPrefLocalizedStringCID, false, nullptr, nsPrefLocalizedStringConstructor },
+ { &kRelativeFilePrefCID, false, nullptr, nsRelativeFilePrefConstructor },
+ { nullptr }
+};
+
+static mozilla::Module::ContractIDEntry kPrefContracts[] = {
+ { NS_PREFSERVICE_CONTRACTID, &kPrefServiceCID },
+ { NS_PREFLOCALIZEDSTRING_CONTRACTID, &kPrefLocalizedStringCID },
+ { NS_RELATIVEFILEPREF_CONTRACTID, &kRelativeFilePrefCID },
+ // compatibility for extension that uses old service
+ { "@mozilla.org/preferences;1", &kPrefServiceCID },
+ { nullptr }
+};
+
+static void
+UnloadPrefsModule()
+{
+ Preferences::Shutdown();
+}
+
+static const mozilla::Module kPrefModule = {
+ mozilla::Module::kVersion,
+ kPrefCIDs,
+ kPrefContracts,
+ nullptr,
+ nullptr,
+ nullptr,
+ UnloadPrefsModule
+};
+
+NSMODULE_DEFN(nsPrefModule) = &kPrefModule;
diff --git a/modules/libpref/prefapi.cpp b/modules/libpref/prefapi.cpp
new file mode 100644
index 000000000..046a69419
--- /dev/null
+++ b/modules/libpref/prefapi.cpp
@@ -0,0 +1,1013 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include <string>
+#include <vector>
+
+#include "base/basictypes.h"
+
+#include "prefapi.h"
+#include "prefapi_private_data.h"
+#include "prefread.h"
+#include "MainThreadUtils.h"
+#include "nsReadableUtils.h"
+#include "nsCRT.h"
+
+#define PL_ARENA_CONST_ALIGN_MASK 3
+#include "plarena.h"
+
+#ifdef _WIN32
+ #include "windows.h"
+#endif /* _WIN32 */
+
+#include "plstr.h"
+#include "PLDHashTable.h"
+#include "plbase64.h"
+#include "mozilla/Logging.h"
+#include "prprf.h"
+#include "mozilla/MemoryReporting.h"
+#include "mozilla/dom/PContent.h"
+#include "nsQuickSort.h"
+#include "nsString.h"
+#include "nsPrintfCString.h"
+#include "prlink.h"
+
+using namespace mozilla;
+
+static void
+clearPrefEntry(PLDHashTable *table, PLDHashEntryHdr *entry)
+{
+ PrefHashEntry *pref = static_cast<PrefHashEntry *>(entry);
+ if (pref->prefFlags.IsTypeString())
+ {
+ if (pref->defaultPref.stringVal)
+ PL_strfree(pref->defaultPref.stringVal);
+ if (pref->userPref.stringVal)
+ PL_strfree(pref->userPref.stringVal);
+ }
+ // don't need to free this as it's allocated in memory owned by
+ // gPrefNameArena
+ pref->key = nullptr;
+ memset(entry, 0, table->EntrySize());
+}
+
+static bool
+matchPrefEntry(const PLDHashEntryHdr* entry, const void* key)
+{
+ const PrefHashEntry *prefEntry =
+ static_cast<const PrefHashEntry*>(entry);
+
+ if (prefEntry->key == key) return true;
+
+ if (!prefEntry->key || !key) return false;
+
+ const char *otherKey = reinterpret_cast<const char*>(key);
+ return (strcmp(prefEntry->key, otherKey) == 0);
+}
+
+PLDHashTable* gHashTable;
+static PLArenaPool gPrefNameArena;
+
+static struct CallbackNode* gCallbacks = nullptr;
+static bool gIsAnyPrefLocked = false;
+// These are only used during the call to pref_DoCallback
+static bool gCallbacksInProgress = false;
+static bool gShouldCleanupDeadNodes = false;
+
+
+static PLDHashTableOps pref_HashTableOps = {
+ PLDHashTable::HashStringKey,
+ matchPrefEntry,
+ PLDHashTable::MoveEntryStub,
+ clearPrefEntry,
+ nullptr,
+};
+
+// PR_ALIGN_OF_WORD is only defined on some platforms. ALIGN_OF_WORD has
+// already been defined to PR_ALIGN_OF_WORD everywhere
+#ifndef PR_ALIGN_OF_WORD
+#define PR_ALIGN_OF_WORD PR_ALIGN_OF_POINTER
+#endif
+
+// making PrefName arena 8k for nice allocation
+#define PREFNAME_ARENA_SIZE 8192
+
+#define WORD_ALIGN_MASK (PR_ALIGN_OF_WORD - 1)
+
+// sanity checking
+#if (PR_ALIGN_OF_WORD & WORD_ALIGN_MASK) != 0
+#error "PR_ALIGN_OF_WORD must be a power of 2!"
+#endif
+
+// equivalent to strdup() - does no error checking,
+// we're assuming we're only called with a valid pointer
+static char *ArenaStrDup(const char* str, PLArenaPool* aArena)
+{
+ void* mem;
+ uint32_t len = strlen(str);
+ PL_ARENA_ALLOCATE(mem, aArena, len+1);
+ if (mem)
+ memcpy(mem, str, len+1);
+ return static_cast<char*>(mem);
+}
+
+static PrefsDirtyFunc gDirtyCallback = nullptr;
+
+inline void MakeDirtyCallback()
+{
+ // Right now the callback function is always set, so we don't need
+ // to complicate the code to cover the scenario where we set the callback
+ // after we've already tried to make it dirty. If this assert triggers
+ // we will add that code.
+ MOZ_ASSERT(gDirtyCallback);
+ if (gDirtyCallback) {
+ gDirtyCallback();
+ }
+}
+
+void PREF_SetDirtyCallback(PrefsDirtyFunc aFunc)
+{
+ gDirtyCallback = aFunc;
+}
+
+/*---------------------------------------------------------------------------*/
+
+static bool pref_ValueChanged(PrefValue oldValue, PrefValue newValue, PrefType type);
+/* -- Privates */
+struct CallbackNode {
+ char* domain;
+ // If someone attempts to remove the node from the callback list while
+ // pref_DoCallback is running, |func| is set to nullptr. Such nodes will
+ // be removed at the end of pref_DoCallback.
+ PrefChangedFunc func;
+ void* data;
+ struct CallbackNode* next;
+};
+
+/* -- Prototypes */
+static nsresult pref_DoCallback(const char* changed_pref);
+
+enum {
+ kPrefSetDefault = 1,
+ kPrefForceSet = 2,
+ kPrefStickyDefault = 4,
+};
+static nsresult pref_HashPref(const char *key, PrefValue value, PrefType type, uint32_t flags);
+
+#define PREF_HASHTABLE_INITIAL_LENGTH 1024
+
+void PREF_Init()
+{
+ if (!gHashTable) {
+ gHashTable = new PLDHashTable(&pref_HashTableOps,
+ sizeof(PrefHashEntry),
+ PREF_HASHTABLE_INITIAL_LENGTH);
+
+ PL_INIT_ARENA_POOL(&gPrefNameArena, "PrefNameArena",
+ PREFNAME_ARENA_SIZE);
+ }
+}
+
+/* Frees the callback list. */
+void PREF_Cleanup()
+{
+ NS_ASSERTION(!gCallbacksInProgress,
+ "PREF_Cleanup was called while gCallbacksInProgress is true!");
+ struct CallbackNode* node = gCallbacks;
+ struct CallbackNode* next_node;
+
+ while (node)
+ {
+ next_node = node->next;
+ PL_strfree(node->domain);
+ free(node);
+ node = next_node;
+ }
+ gCallbacks = nullptr;
+
+ PREF_CleanupPrefs();
+}
+
+/* Frees up all the objects except the callback list. */
+void PREF_CleanupPrefs()
+{
+ if (gHashTable) {
+ delete gHashTable;
+ gHashTable = nullptr;
+ PL_FinishArenaPool(&gPrefNameArena);
+ }
+}
+
+// note that this appends to aResult, and does not assign!
+static void str_escape(const char * original, nsAFlatCString& aResult)
+{
+ /* JavaScript does not allow quotes, slashes, or line terminators inside
+ * strings so we must escape them. ECMAScript defines four line
+ * terminators, but we're only worrying about \r and \n here. We currently
+ * feed our pref script to the JS interpreter as Latin-1 so we won't
+ * encounter \u2028 (line separator) or \u2029 (paragraph separator).
+ *
+ * WARNING: There are hints that we may be moving to storing prefs
+ * as utf8. If we ever feed them to the JS compiler as UTF8 then
+ * we'll have to worry about the multibyte sequences that would be
+ * interpreted as \u2028 and \u2029
+ */
+ const char *p;
+
+ if (original == nullptr)
+ return;
+
+ /* Paranoid worst case all slashes will free quickly */
+ for (p=original; *p; ++p)
+ {
+ switch (*p)
+ {
+ case '\n':
+ aResult.AppendLiteral("\\n");
+ break;
+
+ case '\r':
+ aResult.AppendLiteral("\\r");
+ break;
+
+ case '\\':
+ aResult.AppendLiteral("\\\\");
+ break;
+
+ case '\"':
+ aResult.AppendLiteral("\\\"");
+ break;
+
+ default:
+ aResult.Append(*p);
+ break;
+ }
+ }
+}
+
+/*
+** External calls
+*/
+nsresult
+PREF_SetCharPref(const char *pref_name, const char *value, bool set_default)
+{
+ if ((uint32_t)strlen(value) > MAX_PREF_LENGTH) {
+ return NS_ERROR_ILLEGAL_VALUE;
+ }
+
+ PrefValue pref;
+ pref.stringVal = (char*)value;
+
+ return pref_HashPref(pref_name, pref, PrefType::String, set_default ? kPrefSetDefault : 0);
+}
+
+nsresult
+PREF_SetIntPref(const char *pref_name, int32_t value, bool set_default)
+{
+ PrefValue pref;
+ pref.intVal = value;
+
+ return pref_HashPref(pref_name, pref, PrefType::Int, set_default ? kPrefSetDefault : 0);
+}
+
+nsresult
+PREF_SetBoolPref(const char *pref_name, bool value, bool set_default)
+{
+ PrefValue pref;
+ pref.boolVal = value;
+
+ return pref_HashPref(pref_name, pref, PrefType::Bool, set_default ? kPrefSetDefault : 0);
+}
+
+enum WhichValue { DEFAULT_VALUE, USER_VALUE };
+static nsresult
+SetPrefValue(const char* aPrefName, const dom::PrefValue& aValue,
+ WhichValue aWhich)
+{
+ bool setDefault = (aWhich == DEFAULT_VALUE);
+ switch (aValue.type()) {
+ case dom::PrefValue::TnsCString:
+ return PREF_SetCharPref(aPrefName, aValue.get_nsCString().get(),
+ setDefault);
+ case dom::PrefValue::Tint32_t:
+ return PREF_SetIntPref(aPrefName, aValue.get_int32_t(),
+ setDefault);
+ case dom::PrefValue::Tbool:
+ return PREF_SetBoolPref(aPrefName, aValue.get_bool(),
+ setDefault);
+ default:
+ MOZ_CRASH();
+ }
+}
+
+nsresult
+pref_SetPref(const dom::PrefSetting& aPref)
+{
+ const char* prefName = aPref.name().get();
+ const dom::MaybePrefValue& defaultValue = aPref.defaultValue();
+ const dom::MaybePrefValue& userValue = aPref.userValue();
+
+ nsresult rv;
+ if (defaultValue.type() == dom::MaybePrefValue::TPrefValue) {
+ rv = SetPrefValue(prefName, defaultValue.get_PrefValue(), DEFAULT_VALUE);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ }
+
+ if (userValue.type() == dom::MaybePrefValue::TPrefValue) {
+ rv = SetPrefValue(prefName, userValue.get_PrefValue(), USER_VALUE);
+ } else {
+ rv = PREF_ClearUserPref(prefName);
+ }
+
+ // NB: we should never try to clear a default value, that doesn't
+ // make sense
+
+ return rv;
+}
+
+UniquePtr<char*[]>
+pref_savePrefs(PLDHashTable* aTable, uint32_t* aPrefCount)
+{
+ // This function allocates the entries in the savedPrefs array it returns.
+ // It is the callers responsibility to go through the array and free
+ // all of them. The aPrefCount entries will be non-null. Any end padding
+ // is an implementation detail and may change.
+ MOZ_ASSERT(aPrefCount);
+ auto savedPrefs = MakeUnique<char*[]>(aTable->EntryCount());
+
+ // This is not necessary, but leaving it in for now
+ memset(savedPrefs.get(), 0, aTable->EntryCount() * sizeof(char*));
+
+ int32_t j = 0;
+ for (auto iter = aTable->Iter(); !iter.Done(); iter.Next()) {
+ auto pref = static_cast<PrefHashEntry*>(iter.Get());
+
+ nsAutoCString prefValue;
+ nsAutoCString prefPrefix;
+ prefPrefix.AssignLiteral("user_pref(\"");
+
+ // where we're getting our pref from
+ PrefValue* sourcePref;
+
+ if (pref->prefFlags.HasUserValue() &&
+ (pref_ValueChanged(pref->defaultPref,
+ pref->userPref,
+ pref->prefFlags.GetPrefType()) ||
+ !(pref->prefFlags.HasDefault()) ||
+ pref->prefFlags.HasStickyDefault())) {
+ sourcePref = &pref->userPref;
+ } else {
+ // do not save default prefs that haven't changed
+ continue;
+ }
+
+ // strings are in quotes!
+ if (pref->prefFlags.IsTypeString()) {
+ prefValue = '\"';
+ str_escape(sourcePref->stringVal, prefValue);
+ prefValue += '\"';
+
+ } else if (pref->prefFlags.IsTypeInt()) {
+ prefValue.AppendInt(sourcePref->intVal);
+
+ } else if (pref->prefFlags.IsTypeBool()) {
+ prefValue = (sourcePref->boolVal) ? "true" : "false";
+ }
+
+ nsAutoCString prefName;
+ str_escape(pref->key, prefName);
+
+ savedPrefs[j++] = ToNewCString(prefPrefix +
+ prefName +
+ NS_LITERAL_CSTRING("\", ") +
+ prefValue +
+ NS_LITERAL_CSTRING(");"));
+ }
+ *aPrefCount = j;
+
+ return savedPrefs;
+}
+
+bool
+pref_EntryHasAdvisablySizedValues(PrefHashEntry* aHashEntry)
+{
+ if (aHashEntry->prefFlags.GetPrefType() != PrefType::String) {
+ return true;
+ }
+
+ char* stringVal;
+ if (aHashEntry->prefFlags.HasDefault()) {
+ stringVal = aHashEntry->defaultPref.stringVal;
+ if (strlen(stringVal) > MAX_ADVISABLE_PREF_LENGTH) {
+ return false;
+ }
+ }
+
+ if (aHashEntry->prefFlags.HasUserValue()) {
+ stringVal = aHashEntry->userPref.stringVal;
+ if (strlen(stringVal) > MAX_ADVISABLE_PREF_LENGTH) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+static void
+GetPrefValueFromEntry(PrefHashEntry *aHashEntry, dom::PrefSetting* aPref,
+ WhichValue aWhich)
+{
+ PrefValue* value;
+ dom::PrefValue* settingValue;
+ if (aWhich == USER_VALUE) {
+ value = &aHashEntry->userPref;
+ aPref->userValue() = dom::PrefValue();
+ settingValue = &aPref->userValue().get_PrefValue();
+ } else {
+ value = &aHashEntry->defaultPref;
+ aPref->defaultValue() = dom::PrefValue();
+ settingValue = &aPref->defaultValue().get_PrefValue();
+ }
+
+ switch (aHashEntry->prefFlags.GetPrefType()) {
+ case PrefType::String:
+ *settingValue = nsDependentCString(value->stringVal);
+ return;
+ case PrefType::Int:
+ *settingValue = value->intVal;
+ return;
+ case PrefType::Bool:
+ *settingValue = !!value->boolVal;
+ return;
+ default:
+ MOZ_CRASH();
+ }
+}
+
+void
+pref_GetPrefFromEntry(PrefHashEntry *aHashEntry, dom::PrefSetting* aPref)
+{
+ aPref->name() = aHashEntry->key;
+ if (aHashEntry->prefFlags.HasDefault()) {
+ GetPrefValueFromEntry(aHashEntry, aPref, DEFAULT_VALUE);
+ } else {
+ aPref->defaultValue() = null_t();
+ }
+ if (aHashEntry->prefFlags.HasUserValue()) {
+ GetPrefValueFromEntry(aHashEntry, aPref, USER_VALUE);
+ } else {
+ aPref->userValue() = null_t();
+ }
+
+ MOZ_ASSERT(aPref->defaultValue().type() == dom::MaybePrefValue::Tnull_t ||
+ aPref->userValue().type() == dom::MaybePrefValue::Tnull_t ||
+ (aPref->defaultValue().get_PrefValue().type() ==
+ aPref->userValue().get_PrefValue().type()));
+}
+
+
+int
+pref_CompareStrings(const void *v1, const void *v2, void *unused)
+{
+ char *s1 = *(char**) v1;
+ char *s2 = *(char**) v2;
+
+ if (!s1)
+ {
+ if (!s2)
+ return 0;
+ else
+ return -1;
+ }
+ else if (!s2)
+ return 1;
+ else
+ return strcmp(s1, s2);
+}
+
+bool PREF_HasUserPref(const char *pref_name)
+{
+ if (!gHashTable)
+ return false;
+
+ PrefHashEntry *pref = pref_HashTableLookup(pref_name);
+ return pref && pref->prefFlags.HasUserValue();
+}
+
+nsresult
+PREF_CopyCharPref(const char *pref_name, char ** return_buffer, bool get_default)
+{
+ if (!gHashTable)
+ return NS_ERROR_NOT_INITIALIZED;
+
+ nsresult rv = NS_ERROR_UNEXPECTED;
+ char* stringVal;
+ PrefHashEntry* pref = pref_HashTableLookup(pref_name);
+
+ if (pref && (pref->prefFlags.IsTypeString())) {
+ if (get_default || pref->prefFlags.IsLocked() || !pref->prefFlags.HasUserValue()) {
+ stringVal = pref->defaultPref.stringVal;
+ } else {
+ stringVal = pref->userPref.stringVal;
+ }
+
+ if (stringVal) {
+ *return_buffer = NS_strdup(stringVal);
+ rv = NS_OK;
+ }
+ }
+ return rv;
+}
+
+nsresult PREF_GetIntPref(const char *pref_name,int32_t * return_int, bool get_default)
+{
+ if (!gHashTable)
+ return NS_ERROR_NOT_INITIALIZED;
+
+ nsresult rv = NS_ERROR_UNEXPECTED;
+ PrefHashEntry* pref = pref_HashTableLookup(pref_name);
+ if (pref && (pref->prefFlags.IsTypeInt())) {
+ if (get_default || pref->prefFlags.IsLocked() || !pref->prefFlags.HasUserValue()) {
+ int32_t tempInt = pref->defaultPref.intVal;
+ /* check to see if we even had a default */
+ if (!pref->prefFlags.HasDefault()) {
+ return NS_ERROR_UNEXPECTED;
+ }
+ *return_int = tempInt;
+ } else {
+ *return_int = pref->userPref.intVal;
+ }
+ rv = NS_OK;
+ }
+ return rv;
+}
+
+nsresult PREF_GetBoolPref(const char *pref_name, bool * return_value, bool get_default)
+{
+ if (!gHashTable)
+ return NS_ERROR_NOT_INITIALIZED;
+
+ nsresult rv = NS_ERROR_UNEXPECTED;
+ PrefHashEntry* pref = pref_HashTableLookup(pref_name);
+ //NS_ASSERTION(pref, pref_name);
+ if (pref && (pref->prefFlags.IsTypeBool())) {
+ if (get_default || pref->prefFlags.IsLocked() || !pref->prefFlags.HasUserValue()) {
+ bool tempBool = pref->defaultPref.boolVal;
+ /* check to see if we even had a default */
+ if (pref->prefFlags.HasDefault()) {
+ *return_value = tempBool;
+ rv = NS_OK;
+ }
+ } else {
+ *return_value = pref->userPref.boolVal;
+ rv = NS_OK;
+ }
+ }
+ return rv;
+}
+
+nsresult
+PREF_DeleteBranch(const char *branch_name)
+{
+#ifndef MOZ_B2G
+ MOZ_ASSERT(NS_IsMainThread());
+#endif
+
+ int len = (int)strlen(branch_name);
+
+ if (!gHashTable)
+ return NS_ERROR_NOT_INITIALIZED;
+
+ /* The following check insures that if the branch name already has a "."
+ * at the end, we don't end up with a "..". This fixes an incompatibility
+ * between nsIPref, which needs the period added, and nsIPrefBranch which
+ * does not. When nsIPref goes away this function should be fixed to
+ * never add the period at all.
+ */
+ nsAutoCString branch_dot(branch_name);
+ if ((len > 1) && branch_name[len - 1] != '.')
+ branch_dot += '.';
+
+ /* Delete a branch. Used for deleting mime types */
+ const char *to_delete = branch_dot.get();
+ MOZ_ASSERT(to_delete);
+ len = strlen(to_delete);
+ for (auto iter = gHashTable->Iter(); !iter.Done(); iter.Next()) {
+ auto entry = static_cast<PrefHashEntry*>(iter.Get());
+
+ /* note if we're deleting "ldap" then we want to delete "ldap.xxx"
+ and "ldap" (if such a leaf node exists) but not "ldap_1.xxx" */
+ if (PL_strncmp(entry->key, to_delete, (uint32_t) len) == 0 ||
+ (len-1 == (int)strlen(entry->key) &&
+ PL_strncmp(entry->key, to_delete, (uint32_t)(len-1)) == 0)) {
+ iter.Remove();
+ }
+ }
+
+ MakeDirtyCallback();
+ return NS_OK;
+}
+
+
+nsresult
+PREF_ClearUserPref(const char *pref_name)
+{
+ if (!gHashTable)
+ return NS_ERROR_NOT_INITIALIZED;
+
+ PrefHashEntry* pref = pref_HashTableLookup(pref_name);
+ if (pref && pref->prefFlags.HasUserValue()) {
+ pref->prefFlags.SetHasUserValue(false);
+
+ if (!pref->prefFlags.HasDefault()) {
+ gHashTable->RemoveEntry(pref);
+ }
+
+ pref_DoCallback(pref_name);
+ MakeDirtyCallback();
+ }
+ return NS_OK;
+}
+
+nsresult
+PREF_ClearAllUserPrefs()
+{
+#ifndef MOZ_B2G
+ MOZ_ASSERT(NS_IsMainThread());
+#endif
+
+ if (!gHashTable)
+ return NS_ERROR_NOT_INITIALIZED;
+
+ std::vector<std::string> prefStrings;
+ for (auto iter = gHashTable->Iter(); !iter.Done(); iter.Next()) {
+ auto pref = static_cast<PrefHashEntry*>(iter.Get());
+
+ if (pref->prefFlags.HasUserValue()) {
+ prefStrings.push_back(std::string(pref->key));
+
+ pref->prefFlags.SetHasUserValue(false);
+ if (!pref->prefFlags.HasDefault()) {
+ iter.Remove();
+ }
+ }
+ }
+
+ for (std::string& prefString : prefStrings) {
+ pref_DoCallback(prefString.c_str());
+ }
+
+ MakeDirtyCallback();
+ return NS_OK;
+}
+
+nsresult PREF_LockPref(const char *key, bool lockit)
+{
+ if (!gHashTable)
+ return NS_ERROR_NOT_INITIALIZED;
+
+ PrefHashEntry* pref = pref_HashTableLookup(key);
+ if (!pref)
+ return NS_ERROR_UNEXPECTED;
+
+ if (lockit) {
+ if (!pref->prefFlags.IsLocked()) {
+ pref->prefFlags.SetLocked(true);
+ gIsAnyPrefLocked = true;
+ pref_DoCallback(key);
+ }
+ } else {
+ if (pref->prefFlags.IsLocked()) {
+ pref->prefFlags.SetLocked(false);
+ pref_DoCallback(key);
+ }
+ }
+ return NS_OK;
+}
+
+/*
+ * Hash table functions
+ */
+static bool pref_ValueChanged(PrefValue oldValue, PrefValue newValue, PrefType type)
+{
+ bool changed = true;
+ switch(type) {
+ case PrefType::String:
+ if (oldValue.stringVal && newValue.stringVal) {
+ changed = (strcmp(oldValue.stringVal, newValue.stringVal) != 0);
+ }
+ break;
+ case PrefType::Int:
+ changed = oldValue.intVal != newValue.intVal;
+ break;
+ case PrefType::Bool:
+ changed = oldValue.boolVal != newValue.boolVal;
+ break;
+ case PrefType::Invalid:
+ default:
+ changed = false;
+ break;
+ }
+ return changed;
+}
+
+/*
+ * Overwrite the type and value of an existing preference. Caller must
+ * ensure that they are not changing the type of a preference that has
+ * a default value.
+ */
+static PrefTypeFlags pref_SetValue(PrefValue* existingValue, PrefTypeFlags flags,
+ PrefValue newValue, PrefType newType)
+{
+ if (flags.IsTypeString() && existingValue->stringVal) {
+ PL_strfree(existingValue->stringVal);
+ }
+ flags.SetPrefType(newType);
+ if (flags.IsTypeString()) {
+ MOZ_ASSERT(newValue.stringVal);
+ existingValue->stringVal = newValue.stringVal ? PL_strdup(newValue.stringVal) : nullptr;
+ }
+ else {
+ *existingValue = newValue;
+ }
+ return flags;
+}
+
+PrefHashEntry* pref_HashTableLookup(const char *key)
+{
+#ifndef MOZ_B2G
+ MOZ_ASSERT(NS_IsMainThread());
+#endif
+
+ return static_cast<PrefHashEntry*>(gHashTable->Search(key));
+}
+
+nsresult pref_HashPref(const char *key, PrefValue value, PrefType type, uint32_t flags)
+{
+#ifndef MOZ_B2G
+ MOZ_ASSERT(NS_IsMainThread());
+#endif
+
+ if (!gHashTable)
+ return NS_ERROR_OUT_OF_MEMORY;
+
+ auto pref = static_cast<PrefHashEntry*>(gHashTable->Add(key, fallible));
+ if (!pref)
+ return NS_ERROR_OUT_OF_MEMORY;
+
+ // new entry, better initialize
+ if (!pref->key) {
+
+ // initialize the pref entry
+ pref->prefFlags.Reset().SetPrefType(type);
+ pref->key = ArenaStrDup(key, &gPrefNameArena);
+ memset(&pref->defaultPref, 0, sizeof(pref->defaultPref));
+ memset(&pref->userPref, 0, sizeof(pref->userPref));
+ } else if (pref->prefFlags.HasDefault() && !pref->prefFlags.IsPrefType(type)) {
+ NS_WARNING(nsPrintfCString("Trying to overwrite value of default pref %s with the wrong type!", key).get());
+ return NS_ERROR_UNEXPECTED;
+ }
+
+ bool valueChanged = false;
+ if (flags & kPrefSetDefault) {
+ if (!pref->prefFlags.IsLocked()) {
+ /* ?? change of semantics? */
+ if (pref_ValueChanged(pref->defaultPref, value, type) ||
+ !pref->prefFlags.HasDefault()) {
+ pref->prefFlags = pref_SetValue(&pref->defaultPref, pref->prefFlags, value, type).SetHasDefault(true);
+ if (flags & kPrefStickyDefault) {
+ pref->prefFlags.SetHasStickyDefault(true);
+ }
+ if (!pref->prefFlags.HasUserValue()) {
+ valueChanged = true;
+ }
+ }
+ // What if we change the default to be the same as the user value?
+ // Should we clear the user value?
+ }
+ } else {
+ /* If new value is same as the default value and it's not a "sticky"
+ pref, then un-set the user value.
+ Otherwise, set the user value only if it has changed */
+ if ((pref->prefFlags.HasDefault()) &&
+ !(pref->prefFlags.HasStickyDefault()) &&
+ !pref_ValueChanged(pref->defaultPref, value, type) &&
+ !(flags & kPrefForceSet)) {
+ if (pref->prefFlags.HasUserValue()) {
+ /* XXX should we free a user-set string value if there is one? */
+ pref->prefFlags.SetHasUserValue(false);
+ if (!pref->prefFlags.IsLocked()) {
+ MakeDirtyCallback();
+ valueChanged = true;
+ }
+ }
+ } else if (!pref->prefFlags.HasUserValue() ||
+ !pref->prefFlags.IsPrefType(type) ||
+ pref_ValueChanged(pref->userPref, value, type) ) {
+ pref->prefFlags = pref_SetValue(&pref->userPref, pref->prefFlags, value, type).SetHasUserValue(true);
+ if (!pref->prefFlags.IsLocked()) {
+ MakeDirtyCallback();
+ valueChanged = true;
+ }
+ }
+ }
+
+ if (valueChanged) {
+ return pref_DoCallback(key);
+ }
+ return NS_OK;
+}
+
+size_t
+pref_SizeOfPrivateData(MallocSizeOf aMallocSizeOf)
+{
+ size_t n = PL_SizeOfArenaPoolExcludingPool(&gPrefNameArena, aMallocSizeOf);
+ for (struct CallbackNode* node = gCallbacks; node; node = node->next) {
+ n += aMallocSizeOf(node);
+ n += aMallocSizeOf(node->domain);
+ }
+ return n;
+}
+
+PrefType
+PREF_GetPrefType(const char *pref_name)
+{
+ if (gHashTable) {
+ PrefHashEntry* pref = pref_HashTableLookup(pref_name);
+ if (pref) {
+ return pref->prefFlags.GetPrefType();
+ }
+ }
+ return PrefType::Invalid;
+}
+
+/* -- */
+
+bool
+PREF_PrefIsLocked(const char *pref_name)
+{
+ bool result = false;
+ if (gIsAnyPrefLocked && gHashTable) {
+ PrefHashEntry* pref = pref_HashTableLookup(pref_name);
+ if (pref && pref->prefFlags.IsLocked()) {
+ result = true;
+ }
+ }
+
+ return result;
+}
+
+/* Adds a node to the beginning of the callback list. */
+void
+PREF_RegisterCallback(const char *pref_node,
+ PrefChangedFunc callback,
+ void * instance_data)
+{
+ NS_PRECONDITION(pref_node, "pref_node must not be nullptr");
+ NS_PRECONDITION(callback, "callback must not be nullptr");
+
+ struct CallbackNode* node = (struct CallbackNode*) malloc(sizeof(struct CallbackNode));
+ if (node)
+ {
+ node->domain = PL_strdup(pref_node);
+ node->func = callback;
+ node->data = instance_data;
+ node->next = gCallbacks;
+ gCallbacks = node;
+ }
+ return;
+}
+
+/* Removes |node| from gCallbacks list.
+ Returns the node after the deleted one. */
+struct CallbackNode*
+pref_RemoveCallbackNode(struct CallbackNode* node,
+ struct CallbackNode* prev_node)
+{
+ NS_PRECONDITION(!prev_node || prev_node->next == node, "invalid params");
+ NS_PRECONDITION(prev_node || gCallbacks == node, "invalid params");
+
+ NS_ASSERTION(!gCallbacksInProgress,
+ "modifying the callback list while gCallbacksInProgress is true");
+
+ struct CallbackNode* next_node = node->next;
+ if (prev_node)
+ prev_node->next = next_node;
+ else
+ gCallbacks = next_node;
+ PL_strfree(node->domain);
+ free(node);
+ return next_node;
+}
+
+/* Deletes a node from the callback list or marks it for deletion. */
+nsresult
+PREF_UnregisterCallback(const char *pref_node,
+ PrefChangedFunc callback,
+ void * instance_data)
+{
+ nsresult rv = NS_ERROR_FAILURE;
+ struct CallbackNode* node = gCallbacks;
+ struct CallbackNode* prev_node = nullptr;
+
+ while (node != nullptr)
+ {
+ if ( node->func == callback &&
+ node->data == instance_data &&
+ strcmp(node->domain, pref_node) == 0)
+ {
+ if (gCallbacksInProgress)
+ {
+ // postpone the node removal until after
+ // gCallbacks enumeration is finished.
+ node->func = nullptr;
+ gShouldCleanupDeadNodes = true;
+ prev_node = node;
+ node = node->next;
+ }
+ else
+ {
+ node = pref_RemoveCallbackNode(node, prev_node);
+ }
+ rv = NS_OK;
+ }
+ else
+ {
+ prev_node = node;
+ node = node->next;
+ }
+ }
+ return rv;
+}
+
+static nsresult pref_DoCallback(const char* changed_pref)
+{
+ nsresult rv = NS_OK;
+ struct CallbackNode* node;
+
+ bool reentered = gCallbacksInProgress;
+ gCallbacksInProgress = true;
+ // Nodes must not be deleted while gCallbacksInProgress is true.
+ // Nodes that need to be deleted are marked for deletion by nulling
+ // out the |func| pointer. We release them at the end of this function
+ // if we haven't reentered.
+
+ for (node = gCallbacks; node != nullptr; node = node->next)
+ {
+ if ( node->func &&
+ PL_strncmp(changed_pref,
+ node->domain,
+ strlen(node->domain)) == 0 )
+ {
+ (*node->func) (changed_pref, node->data);
+ }
+ }
+
+ gCallbacksInProgress = reentered;
+
+ if (gShouldCleanupDeadNodes && !gCallbacksInProgress)
+ {
+ struct CallbackNode* prev_node = nullptr;
+ node = gCallbacks;
+
+ while (node != nullptr)
+ {
+ if (!node->func)
+ {
+ node = pref_RemoveCallbackNode(node, prev_node);
+ }
+ else
+ {
+ prev_node = node;
+ node = node->next;
+ }
+ }
+ gShouldCleanupDeadNodes = false;
+ }
+
+ return rv;
+}
+
+void PREF_ReaderCallback(void *closure,
+ const char *pref,
+ PrefValue value,
+ PrefType type,
+ bool isDefault,
+ bool isStickyDefault)
+
+{
+ uint32_t flags = 0;
+ if (isDefault) {
+ flags |= kPrefSetDefault;
+ if (isStickyDefault) {
+ flags |= kPrefStickyDefault;
+ }
+ } else {
+ flags |= kPrefForceSet;
+ }
+ pref_HashPref(pref, value, type, flags);
+}
diff --git a/modules/libpref/prefapi.h b/modules/libpref/prefapi.h
new file mode 100644
index 000000000..9ef014ada
--- /dev/null
+++ b/modules/libpref/prefapi.h
@@ -0,0 +1,258 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+// <pre>
+*/
+#ifndef PREFAPI_H
+#define PREFAPI_H
+
+#include "nscore.h"
+#include "PLDHashTable.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// 1 MB should be enough for everyone.
+static const uint32_t MAX_PREF_LENGTH = 1 * 1024 * 1024;
+// Actually, 4kb should be enough for everyone.
+static const uint32_t MAX_ADVISABLE_PREF_LENGTH = 4 * 1024;
+
+typedef union
+{
+ char* stringVal;
+ int32_t intVal;
+ bool boolVal;
+} PrefValue;
+
+/*
+// <font color=blue>
+// The Init function initializes the preference context and creates
+// the preference hashtable.
+// </font>
+*/
+void PREF_Init();
+
+/*
+// Cleanup should be called at program exit to free the
+// list of registered callbacks.
+*/
+void PREF_Cleanup();
+void PREF_CleanupPrefs();
+
+/*
+// <font color=blue>
+// Preference flags, including the native type of the preference. Changing any of these
+// values will require modifying the code inside of PrefTypeFlags class.
+// </font>
+*/
+
+enum class PrefType {
+ Invalid = 0,
+ String = 1,
+ Int = 2,
+ Bool = 3,
+};
+
+// Keep the type of the preference, as well as the flags guiding its behaviour.
+class PrefTypeFlags
+{
+public:
+ PrefTypeFlags() : mValue(AsInt(PrefType::Invalid)) {}
+ explicit PrefTypeFlags(PrefType aType) : mValue(AsInt(aType)) {}
+ PrefTypeFlags& Reset() { mValue = AsInt(PrefType::Invalid); return *this; }
+
+ bool IsTypeValid() const { return !IsPrefType(PrefType::Invalid); }
+ bool IsTypeString() const { return IsPrefType(PrefType::String); }
+ bool IsTypeInt() const { return IsPrefType(PrefType::Int); }
+ bool IsTypeBool() const { return IsPrefType(PrefType::Bool); }
+ bool IsPrefType(PrefType type) const { return GetPrefType() == type; }
+
+ PrefTypeFlags& SetPrefType(PrefType aType) {
+ mValue = mValue - AsInt(GetPrefType()) + AsInt(aType);
+ return *this;
+ }
+ PrefType GetPrefType() const {
+ return (PrefType)(mValue & (AsInt(PrefType::String) |
+ AsInt(PrefType::Int) |
+ AsInt(PrefType::Bool)));
+ }
+
+ bool HasDefault() const { return mValue & PREF_FLAG_HAS_DEFAULT; }
+ PrefTypeFlags& SetHasDefault(bool aSetOrUnset) { return SetFlag(PREF_FLAG_HAS_DEFAULT, aSetOrUnset); }
+
+ bool HasStickyDefault() const { return mValue & PREF_FLAG_STICKY_DEFAULT; }
+ PrefTypeFlags& SetHasStickyDefault(bool aSetOrUnset) { return SetFlag(PREF_FLAG_STICKY_DEFAULT, aSetOrUnset); }
+
+ bool IsLocked() const { return mValue & PREF_FLAG_LOCKED; }
+ PrefTypeFlags& SetLocked(bool aSetOrUnset) { return SetFlag(PREF_FLAG_LOCKED, aSetOrUnset); }
+
+ bool HasUserValue() const { return mValue & PREF_FLAG_USERSET; }
+ PrefTypeFlags& SetHasUserValue(bool aSetOrUnset) { return SetFlag(PREF_FLAG_USERSET, aSetOrUnset); }
+
+private:
+ static uint16_t AsInt(PrefType aType) { return (uint16_t)aType; }
+
+ PrefTypeFlags& SetFlag(uint16_t aFlag, bool aSetOrUnset) {
+ mValue = aSetOrUnset ? mValue | aFlag : mValue & ~aFlag;
+ return *this;
+ }
+
+ // Pack both the value of type (PrefType) and flags into the same int. This is why
+ // the flag enum starts at 4, as PrefType occupies the bottom two bits.
+ enum {
+ PREF_FLAG_LOCKED = 4,
+ PREF_FLAG_USERSET = 8,
+ PREF_FLAG_CONFIG = 16,
+ PREF_FLAG_REMOTE = 32,
+ PREF_FLAG_LILOCAL = 64,
+ PREF_FLAG_HAS_DEFAULT = 128,
+ PREF_FLAG_STICKY_DEFAULT = 256,
+ };
+ uint16_t mValue;
+};
+
+struct PrefHashEntry : PLDHashEntryHdr
+{
+ PrefTypeFlags prefFlags; // This field goes first to minimize struct size on 64-bit.
+ const char *key;
+ PrefValue defaultPref;
+ PrefValue userPref;
+};
+
+/*
+// <font color=blue>
+// Set the various types of preferences. These functions take a dotted
+// notation of the preference name (e.g. "browser.startup.homepage").
+// Note that this will cause the preference to be saved to the file if
+// it is different from the default. In other words, these are used
+// to set the _user_ preferences.
+//
+// If set_default is set to true however, it sets the default value.
+// This will only affect the program behavior if the user does not have a value
+// saved over it for the particular preference. In addition, these will never
+// be saved out to disk.
+//
+// Each set returns PREF_VALUECHANGED if the user value changed
+// (triggering a callback), or PREF_NOERROR if the value was unchanged.
+// </font>
+*/
+nsresult PREF_SetCharPref(const char *pref,const char* value, bool set_default = false);
+nsresult PREF_SetIntPref(const char *pref,int32_t value, bool set_default = false);
+nsresult PREF_SetBoolPref(const char *pref,bool value, bool set_default = false);
+
+bool PREF_HasUserPref(const char* pref_name);
+
+/*
+// <font color=blue>
+// Get the various types of preferences. These functions take a dotted
+// notation of the preference name (e.g. "browser.startup.homepage")
+//
+// They also take a pointer to fill in with the return value and return an
+// error value. At the moment, this is simply an int but it may
+// be converted to an enum once the global error strategy is worked out.
+//
+// They will perform conversion if the type doesn't match what was requested.
+// (if it is reasonably possible)
+// </font>
+*/
+nsresult PREF_GetIntPref(const char *pref,
+ int32_t * return_int, bool get_default);
+nsresult PREF_GetBoolPref(const char *pref, bool * return_val, bool get_default);
+/*
+// <font color=blue>
+// These functions are similar to the above "Get" version with the significant
+// difference that the preference module will alloc the memory (e.g. XP_STRDUP) and
+// the caller will need to be responsible for freeing it...
+// </font>
+*/
+nsresult PREF_CopyCharPref(const char *pref, char ** return_buf, bool get_default);
+/*
+// <font color=blue>
+// bool function that returns whether or not the preference is locked and therefore
+// cannot be changed.
+// </font>
+*/
+bool PREF_PrefIsLocked(const char *pref_name);
+
+/*
+// <font color=blue>
+// Function that sets whether or not the preference is locked and therefore
+// cannot be changed.
+// </font>
+*/
+nsresult PREF_LockPref(const char *key, bool lockIt);
+
+PrefType PREF_GetPrefType(const char *pref_name);
+
+/*
+ * Delete a branch of the tree
+ */
+nsresult PREF_DeleteBranch(const char *branch_name);
+
+/*
+ * Clears the given pref (reverts it to its default value)
+ */
+nsresult PREF_ClearUserPref(const char *pref_name);
+
+/*
+ * Clears all user prefs
+ */
+nsresult PREF_ClearAllUserPrefs();
+
+
+/*
+// <font color=blue>
+// The callback function will get passed the pref_node which triggered the call
+// and the void * instance_data which was passed to the register callback function.
+// Return a non-zero result (nsresult) to pass an error up to the caller.
+// </font>
+*/
+/* Temporarily conditionally compile PrefChangedFunc typedef.
+** During migration from old libpref to nsIPref we need it in
+** both header files. Eventually prefapi.h will become a private
+** file. The two types need to be in sync for now. Certain
+** compilers were having problems with multiple definitions.
+*/
+#ifndef have_PrefChangedFunc_typedef
+typedef void (*PrefChangedFunc) (const char *, void *);
+#define have_PrefChangedFunc_typedef
+#endif
+
+/*
+// <font color=blue>
+// Register a callback. This takes a node in the preference tree and will
+// call the callback function if anything below that node is modified.
+// Unregister returns PREF_NOERROR if a callback was found that
+// matched all the parameters; otherwise it returns PREF_ERROR.
+// </font>
+*/
+void PREF_RegisterCallback(const char* domain,
+ PrefChangedFunc callback, void* instance_data );
+nsresult PREF_UnregisterCallback(const char* domain,
+ PrefChangedFunc callback, void* instance_data );
+
+/*
+ * Used by nsPrefService as the callback function of the 'pref' parser
+ */
+void PREF_ReaderCallback( void *closure,
+ const char *pref,
+ PrefValue value,
+ PrefType type,
+ bool isDefault,
+ bool isStickyDefault);
+
+
+/*
+ * Callback whenever we change a preference
+ */
+typedef void (*PrefsDirtyFunc) ();
+void PREF_SetDirtyCallback(PrefsDirtyFunc);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/modules/libpref/prefapi_private_data.h b/modules/libpref/prefapi_private_data.h
new file mode 100644
index 000000000..f1fa68fdc
--- /dev/null
+++ b/modules/libpref/prefapi_private_data.h
@@ -0,0 +1,40 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* Data shared between prefapi.c and nsPref.cpp */
+
+#ifndef prefapi_private_data_h
+#define prefapi_private_data_h
+
+#include "mozilla/MemoryReporting.h"
+#include "mozilla/UniquePtr.h"
+
+extern PLDHashTable* gHashTable;
+
+namespace mozilla {
+namespace dom {
+class PrefSetting;
+} // namespace dom
+} // namespace mozilla
+
+mozilla::UniquePtr<char*[]>
+pref_savePrefs(PLDHashTable* aTable, uint32_t* aPrefCount);
+
+nsresult
+pref_SetPref(const mozilla::dom::PrefSetting& aPref);
+
+int pref_CompareStrings(const void *v1, const void *v2, void* unused);
+PrefHashEntry* pref_HashTableLookup(const char *key);
+
+bool
+pref_EntryHasAdvisablySizedValues(PrefHashEntry* aHashEntry);
+
+void pref_GetPrefFromEntry(PrefHashEntry *aHashEntry,
+ mozilla::dom::PrefSetting* aPref);
+
+size_t
+pref_SizeOfPrivateData(mozilla::MallocSizeOf aMallocSizeOf);
+
+#endif
diff --git a/modules/libpref/prefread.cpp b/modules/libpref/prefread.cpp
new file mode 100644
index 000000000..605dcaac6
--- /dev/null
+++ b/modules/libpref/prefread.cpp
@@ -0,0 +1,657 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include "prefread.h"
+#include "nsString.h"
+#include "nsUTF8Utils.h"
+
+#ifdef TEST_PREFREAD
+#include <stdio.h>
+#define NS_WARNING(_s) printf(">>> " _s "!\n")
+#define NS_NOTREACHED(_s) NS_WARNING(_s)
+#else
+#include "nsDebug.h" // for NS_WARNING
+#endif
+
+/* pref parser states */
+enum {
+ PREF_PARSE_INIT,
+ PREF_PARSE_MATCH_STRING,
+ PREF_PARSE_UNTIL_NAME,
+ PREF_PARSE_QUOTED_STRING,
+ PREF_PARSE_UNTIL_COMMA,
+ PREF_PARSE_UNTIL_VALUE,
+ PREF_PARSE_INT_VALUE,
+ PREF_PARSE_COMMENT_MAYBE_START,
+ PREF_PARSE_COMMENT_BLOCK,
+ PREF_PARSE_COMMENT_BLOCK_MAYBE_END,
+ PREF_PARSE_ESC_SEQUENCE,
+ PREF_PARSE_HEX_ESCAPE,
+ PREF_PARSE_UTF16_LOW_SURROGATE,
+ PREF_PARSE_UNTIL_OPEN_PAREN,
+ PREF_PARSE_UNTIL_CLOSE_PAREN,
+ PREF_PARSE_UNTIL_SEMICOLON,
+ PREF_PARSE_UNTIL_EOL
+};
+
+#define UTF16_ESC_NUM_DIGITS 4
+#define HEX_ESC_NUM_DIGITS 2
+#define BITS_PER_HEX_DIGIT 4
+
+static const char kUserPref[] = "user_pref";
+static const char kPref[] = "pref";
+static const char kPrefSticky[] = "sticky_pref";
+static const char kTrue[] = "true";
+static const char kFalse[] = "false";
+
+/**
+ * pref_GrowBuf
+ *
+ * this function will increase the size of the buffer owned
+ * by the given pref parse state. We currently use a simple
+ * doubling algorithm, but the only hard requirement is that
+ * it increase the buffer by at least the size of the ps->esctmp
+ * buffer used for escape processing (currently 6 bytes).
+ *
+ * this buffer is used to store partial pref lines. it is
+ * freed when the parse state is destroyed.
+ *
+ * @param ps
+ * parse state instance
+ *
+ * this function updates all pointers that reference an
+ * address within lb since realloc may relocate the buffer.
+ *
+ * @return false if insufficient memory.
+ */
+static bool
+pref_GrowBuf(PrefParseState *ps)
+{
+ int bufLen, curPos, valPos;
+
+ bufLen = ps->lbend - ps->lb;
+ curPos = ps->lbcur - ps->lb;
+ valPos = ps->vb - ps->lb;
+
+ if (bufLen == 0)
+ bufLen = 128; /* default buffer size */
+ else
+ bufLen <<= 1; /* double buffer size */
+
+#ifdef TEST_PREFREAD
+ fprintf(stderr, ">>> realloc(%d)\n", bufLen);
+#endif
+
+ ps->lb = (char*) realloc(ps->lb, bufLen);
+ if (!ps->lb)
+ return false;
+
+ ps->lbcur = ps->lb + curPos;
+ ps->lbend = ps->lb + bufLen;
+ ps->vb = ps->lb + valPos;
+
+ return true;
+}
+
+/**
+ * Report an error or a warning. If not specified, just dump to stderr.
+ */
+static void
+pref_ReportParseProblem(PrefParseState& ps, const char* aMessage, int aLine, bool aError)
+{
+ if (ps.reporter) {
+ ps.reporter(aMessage, aLine, aError);
+ } else {
+ printf_stderr("**** Preference parsing %s (line %d) = %s **\n",
+ (aError ? "error" : "warning"), aLine, aMessage);
+ }
+}
+
+/**
+ * pref_DoCallback
+ *
+ * this function is called when a complete pref name-value pair has
+ * been extracted from the input data.
+ *
+ * @param ps
+ * parse state instance
+ *
+ * @return false to indicate a fatal error.
+ */
+static bool
+pref_DoCallback(PrefParseState *ps)
+{
+ PrefValue value;
+
+ switch (ps->vtype) {
+ case PrefType::String:
+ value.stringVal = ps->vb;
+ break;
+ case PrefType::Int:
+ if ((ps->vb[0] == '-' || ps->vb[0] == '+') && ps->vb[1] == '\0') {
+ pref_ReportParseProblem(*ps, "invalid integer value", 0, true);
+ NS_WARNING("malformed integer value");
+ return false;
+ }
+ value.intVal = atoi(ps->vb);
+ break;
+ case PrefType::Bool:
+ value.boolVal = (ps->vb == kTrue);
+ break;
+ default:
+ break;
+ }
+ (*ps->reader)(ps->closure, ps->lb, value, ps->vtype, ps->fdefault,
+ ps->fstickydefault);
+ return true;
+}
+
+void
+PREF_InitParseState(PrefParseState *ps, PrefReader reader,
+ PrefParseErrorReporter reporter, void *closure)
+{
+ memset(ps, 0, sizeof(*ps));
+ ps->reader = reader;
+ ps->closure = closure;
+ ps->reporter = reporter;
+}
+
+void
+PREF_FinalizeParseState(PrefParseState *ps)
+{
+ if (ps->lb)
+ free(ps->lb);
+}
+
+/**
+ * Pseudo-BNF
+ * ----------
+ * function = LJUNK function-name JUNK function-args
+ * function-name = "user_pref" | "pref" | "sticky_pref"
+ * function-args = "(" JUNK pref-name JUNK "," JUNK pref-value JUNK ")" JUNK ";"
+ * pref-name = quoted-string
+ * pref-value = quoted-string | "true" | "false" | integer-value
+ * JUNK = *(WS | comment-block | comment-line)
+ * LJUNK = *(WS | comment-block | comment-line | bcomment-line)
+ * WS = SP | HT | LF | VT | FF | CR
+ * SP = <US-ASCII SP, space (32)>
+ * HT = <US-ASCII HT, horizontal-tab (9)>
+ * LF = <US-ASCII LF, linefeed (10)>
+ * VT = <US-ASCII HT, vertical-tab (11)>
+ * FF = <US-ASCII FF, form-feed (12)>
+ * CR = <US-ASCII CR, carriage return (13)>
+ * comment-block = <C/C++ style comment block>
+ * comment-line = <C++ style comment line>
+ * bcomment-line = <bourne-shell style comment line>
+ */
+bool
+PREF_ParseBuf(PrefParseState *ps, const char *buf, int bufLen)
+{
+ const char *end;
+ char c;
+ char udigit;
+ int state;
+
+ // The line number is currently only used for the error/warning reporting.
+ int lineNum = 0;
+
+ state = ps->state;
+ for (end = buf + bufLen; buf != end; ++buf) {
+ c = *buf;
+ if (c == '\r' || c == '\n' || c == 0x1A) {
+ lineNum ++;
+ }
+
+ switch (state) {
+ /* initial state */
+ case PREF_PARSE_INIT:
+ if (ps->lbcur != ps->lb) { /* reset state */
+ ps->lbcur = ps->lb;
+ ps->vb = nullptr;
+ ps->vtype = PrefType::Invalid;
+ ps->fdefault = false;
+ ps->fstickydefault = false;
+ }
+ switch (c) {
+ case '/': /* begin comment block or line? */
+ state = PREF_PARSE_COMMENT_MAYBE_START;
+ break;
+ case '#': /* accept shell style comments */
+ state = PREF_PARSE_UNTIL_EOL;
+ break;
+ case 'u': /* indicating user_pref */
+ case 's': /* indicating sticky_pref */
+ case 'p': /* indicating pref */
+ if (c == 'u') {
+ ps->smatch = kUserPref;
+ } else if (c == 's') {
+ ps->smatch = kPrefSticky;
+ } else {
+ ps->smatch = kPref;
+ }
+ ps->sindex = 1;
+ ps->nextstate = PREF_PARSE_UNTIL_OPEN_PAREN;
+ state = PREF_PARSE_MATCH_STRING;
+ break;
+ /* else skip char */
+ }
+ break;
+
+ /* string matching */
+ case PREF_PARSE_MATCH_STRING:
+ if (c == ps->smatch[ps->sindex++]) {
+ /* if we've matched all characters, then move to next state. */
+ if (ps->smatch[ps->sindex] == '\0') {
+ state = ps->nextstate;
+ ps->nextstate = PREF_PARSE_INIT; /* reset next state */
+ }
+ /* else wait for next char */
+ }
+ else {
+ pref_ReportParseProblem(*ps, "non-matching string", lineNum, true);
+ NS_WARNING("malformed pref file");
+ return false;
+ }
+ break;
+
+ /* quoted string parsing */
+ case PREF_PARSE_QUOTED_STRING:
+ /* we assume that the initial quote has already been consumed */
+ if (ps->lbcur == ps->lbend && !pref_GrowBuf(ps))
+ return false; /* out of memory */
+ if (c == '\\')
+ state = PREF_PARSE_ESC_SEQUENCE;
+ else if (c == ps->quotechar) {
+ *ps->lbcur++ = '\0';
+ state = ps->nextstate;
+ ps->nextstate = PREF_PARSE_INIT; /* reset next state */
+ }
+ else
+ *ps->lbcur++ = c;
+ break;
+
+ /* name parsing */
+ case PREF_PARSE_UNTIL_NAME:
+ if (c == '\"' || c == '\'') {
+ ps->fdefault = (ps->smatch == kPref || ps->smatch == kPrefSticky);
+ ps->fstickydefault = (ps->smatch == kPrefSticky);
+ ps->quotechar = c;
+ ps->nextstate = PREF_PARSE_UNTIL_COMMA; /* return here when done */
+ state = PREF_PARSE_QUOTED_STRING;
+ }
+ else if (c == '/') { /* allow embedded comment */
+ ps->nextstate = state; /* return here when done with comment */
+ state = PREF_PARSE_COMMENT_MAYBE_START;
+ }
+ else if (!isspace(c)) {
+ pref_ReportParseProblem(*ps, "need space, comment or quote", lineNum, true);
+ NS_WARNING("malformed pref file");
+ return false;
+ }
+ break;
+
+ /* parse until we find a comma separating name and value */
+ case PREF_PARSE_UNTIL_COMMA:
+ if (c == ',') {
+ ps->vb = ps->lbcur;
+ state = PREF_PARSE_UNTIL_VALUE;
+ }
+ else if (c == '/') { /* allow embedded comment */
+ ps->nextstate = state; /* return here when done with comment */
+ state = PREF_PARSE_COMMENT_MAYBE_START;
+ }
+ else if (!isspace(c)) {
+ pref_ReportParseProblem(*ps, "need space, comment or comma", lineNum, true);
+ NS_WARNING("malformed pref file");
+ return false;
+ }
+ break;
+
+ /* value parsing */
+ case PREF_PARSE_UNTIL_VALUE:
+ /* the pref value type is unknown. so, we scan for the first
+ * character of the value, and determine the type from that. */
+ if (c == '\"' || c == '\'') {
+ ps->vtype = PrefType::String;
+ ps->quotechar = c;
+ ps->nextstate = PREF_PARSE_UNTIL_CLOSE_PAREN;
+ state = PREF_PARSE_QUOTED_STRING;
+ }
+ else if (c == 't' || c == 'f') {
+ ps->vb = (char *) (c == 't' ? kTrue : kFalse);
+ ps->vtype = PrefType::Bool;
+ ps->smatch = ps->vb;
+ ps->sindex = 1;
+ ps->nextstate = PREF_PARSE_UNTIL_CLOSE_PAREN;
+ state = PREF_PARSE_MATCH_STRING;
+ }
+ else if (isdigit(c) || (c == '-') || (c == '+')) {
+ ps->vtype = PrefType::Int;
+ /* write c to line buffer... */
+ if (ps->lbcur == ps->lbend && !pref_GrowBuf(ps))
+ return false; /* out of memory */
+ *ps->lbcur++ = c;
+ state = PREF_PARSE_INT_VALUE;
+ }
+ else if (c == '/') { /* allow embedded comment */
+ ps->nextstate = state; /* return here when done with comment */
+ state = PREF_PARSE_COMMENT_MAYBE_START;
+ }
+ else if (!isspace(c)) {
+ pref_ReportParseProblem(*ps, "need value, comment or space", lineNum, true);
+ NS_WARNING("malformed pref file");
+ return false;
+ }
+ break;
+ case PREF_PARSE_INT_VALUE:
+ /* grow line buffer if necessary... */
+ if (ps->lbcur == ps->lbend && !pref_GrowBuf(ps))
+ return false; /* out of memory */
+ if (isdigit(c))
+ *ps->lbcur++ = c;
+ else {
+ *ps->lbcur++ = '\0'; /* stomp null terminator; we are done. */
+ if (c == ')')
+ state = PREF_PARSE_UNTIL_SEMICOLON;
+ else if (c == '/') { /* allow embedded comment */
+ ps->nextstate = PREF_PARSE_UNTIL_CLOSE_PAREN;
+ state = PREF_PARSE_COMMENT_MAYBE_START;
+ }
+ else if (isspace(c))
+ state = PREF_PARSE_UNTIL_CLOSE_PAREN;
+ else {
+ pref_ReportParseProblem(*ps, "while parsing integer", lineNum, true);
+ NS_WARNING("malformed pref file");
+ return false;
+ }
+ }
+ break;
+
+ /* comment parsing */
+ case PREF_PARSE_COMMENT_MAYBE_START:
+ switch (c) {
+ case '*': /* comment block */
+ state = PREF_PARSE_COMMENT_BLOCK;
+ break;
+ case '/': /* comment line */
+ state = PREF_PARSE_UNTIL_EOL;
+ break;
+ default:
+ /* pref file is malformed */
+ pref_ReportParseProblem(*ps, "while parsing comment", lineNum, true);
+ NS_WARNING("malformed pref file");
+ return false;
+ }
+ break;
+ case PREF_PARSE_COMMENT_BLOCK:
+ if (c == '*')
+ state = PREF_PARSE_COMMENT_BLOCK_MAYBE_END;
+ break;
+ case PREF_PARSE_COMMENT_BLOCK_MAYBE_END:
+ switch (c) {
+ case '/':
+ state = ps->nextstate;
+ ps->nextstate = PREF_PARSE_INIT;
+ break;
+ case '*': /* stay in this state */
+ break;
+ default:
+ state = PREF_PARSE_COMMENT_BLOCK;
+ }
+ break;
+
+ /* string escape sequence parsing */
+ case PREF_PARSE_ESC_SEQUENCE:
+ /* not necessary to resize buffer here since we should be writing
+ * only one character and the resize check would have been done
+ * for us in the previous state */
+ switch (c) {
+ case '\"':
+ case '\'':
+ case '\\':
+ break;
+ case 'r':
+ c = '\r';
+ break;
+ case 'n':
+ c = '\n';
+ break;
+ case 'x': /* hex escape -- always interpreted as Latin-1 */
+ case 'u': /* UTF16 escape */
+ ps->esctmp[0] = c;
+ ps->esclen = 1;
+ ps->utf16[0] = ps->utf16[1] = 0;
+ ps->sindex = (c == 'x' ) ?
+ HEX_ESC_NUM_DIGITS :
+ UTF16_ESC_NUM_DIGITS;
+ state = PREF_PARSE_HEX_ESCAPE;
+ continue;
+ default:
+ pref_ReportParseProblem(*ps, "preserving unexpected JS escape sequence",
+ lineNum, false);
+ NS_WARNING("preserving unexpected JS escape sequence");
+ /* Invalid escape sequence so we do have to write more than
+ * one character. Grow line buffer if necessary... */
+ if ((ps->lbcur+1) == ps->lbend && !pref_GrowBuf(ps))
+ return false; /* out of memory */
+ *ps->lbcur++ = '\\'; /* preserve the escape sequence */
+ break;
+ }
+ *ps->lbcur++ = c;
+ state = PREF_PARSE_QUOTED_STRING;
+ break;
+
+ /* parsing a hex (\xHH) or utf16 escape (\uHHHH) */
+ case PREF_PARSE_HEX_ESCAPE:
+ if ( c >= '0' && c <= '9' )
+ udigit = (c - '0');
+ else if ( c >= 'A' && c <= 'F' )
+ udigit = (c - 'A') + 10;
+ else if ( c >= 'a' && c <= 'f' )
+ udigit = (c - 'a') + 10;
+ else {
+ /* bad escape sequence found, write out broken escape as-is */
+ pref_ReportParseProblem(*ps, "preserving invalid or incomplete hex escape",
+ lineNum, false);
+ NS_WARNING("preserving invalid or incomplete hex escape");
+ *ps->lbcur++ = '\\'; /* original escape slash */
+ if ((ps->lbcur + ps->esclen) >= ps->lbend && !pref_GrowBuf(ps))
+ return false;
+ for (int i = 0; i < ps->esclen; ++i)
+ *ps->lbcur++ = ps->esctmp[i];
+
+ /* push the non-hex character back for re-parsing. */
+ /* (++buf at the top of the loop keeps this safe) */
+ --buf;
+ state = PREF_PARSE_QUOTED_STRING;
+ continue;
+ }
+
+ /* have a digit */
+ ps->esctmp[ps->esclen++] = c; /* preserve it */
+ ps->utf16[1] <<= BITS_PER_HEX_DIGIT;
+ ps->utf16[1] |= udigit;
+ ps->sindex--;
+ if (ps->sindex == 0) {
+ /* have the full escape. Convert to UTF8 */
+ int utf16len = 0;
+ if (ps->utf16[0]) {
+ /* already have a high surrogate, this is a two char seq */
+ utf16len = 2;
+ }
+ else if (0xD800 == (0xFC00 & ps->utf16[1])) {
+ /* a high surrogate, can't convert until we have the low */
+ ps->utf16[0] = ps->utf16[1];
+ ps->utf16[1] = 0;
+ state = PREF_PARSE_UTF16_LOW_SURROGATE;
+ break;
+ }
+ else {
+ /* a single utf16 character */
+ ps->utf16[0] = ps->utf16[1];
+ utf16len = 1;
+ }
+
+ /* actual conversion */
+ /* make sure there's room, 6 bytes is max utf8 len (in */
+ /* theory; 4 bytes covers the actual utf16 range) */
+ if (ps->lbcur+6 >= ps->lbend && !pref_GrowBuf(ps))
+ return false;
+
+ ConvertUTF16toUTF8 converter(ps->lbcur);
+ converter.write(ps->utf16, utf16len);
+ ps->lbcur += converter.Size();
+ state = PREF_PARSE_QUOTED_STRING;
+ }
+ break;
+
+ /* looking for beginning of utf16 low surrogate */
+ case PREF_PARSE_UTF16_LOW_SURROGATE:
+ if (ps->sindex == 0 && c == '\\') {
+ ++ps->sindex;
+ }
+ else if (ps->sindex == 1 && c == 'u') {
+ /* escape sequence is correct, now parse hex */
+ ps->sindex = UTF16_ESC_NUM_DIGITS;
+ ps->esctmp[0] = 'u';
+ ps->esclen = 1;
+ state = PREF_PARSE_HEX_ESCAPE;
+ }
+ else {
+ /* didn't find expected low surrogate. Ignore high surrogate
+ * (it would just get converted to nothing anyway) and start
+ * over with this character */
+ --buf;
+ if (ps->sindex == 1)
+ state = PREF_PARSE_ESC_SEQUENCE;
+ else
+ state = PREF_PARSE_QUOTED_STRING;
+ continue;
+ }
+ break;
+
+ /* function open and close parsing */
+ case PREF_PARSE_UNTIL_OPEN_PAREN:
+ /* tolerate only whitespace and embedded comments */
+ if (c == '(')
+ state = PREF_PARSE_UNTIL_NAME;
+ else if (c == '/') {
+ ps->nextstate = state; /* return here when done with comment */
+ state = PREF_PARSE_COMMENT_MAYBE_START;
+ }
+ else if (!isspace(c)) {
+ pref_ReportParseProblem(*ps, "need space, comment or open parentheses",
+ lineNum, true);
+ NS_WARNING("malformed pref file");
+ return false;
+ }
+ break;
+ case PREF_PARSE_UNTIL_CLOSE_PAREN:
+ /* tolerate only whitespace and embedded comments */
+ if (c == ')') {
+ state = PREF_PARSE_UNTIL_SEMICOLON;
+ } else if (c == '/') {
+ ps->nextstate = state; /* return here when done with comment */
+ state = PREF_PARSE_COMMENT_MAYBE_START;
+ } else if (!isspace(c)) {
+ pref_ReportParseProblem(*ps, "need space, comment or closing parentheses",
+ lineNum, true);
+ NS_WARNING("malformed pref file");
+ return false;
+ }
+ break;
+
+ /* function terminator ';' parsing */
+ case PREF_PARSE_UNTIL_SEMICOLON:
+ /* tolerate only whitespace and embedded comments */
+ if (c == ';') {
+ if (!pref_DoCallback(ps))
+ return false;
+ state = PREF_PARSE_INIT;
+ }
+ else if (c == '/') {
+ ps->nextstate = state; /* return here when done with comment */
+ state = PREF_PARSE_COMMENT_MAYBE_START;
+ }
+ else if (!isspace(c)) {
+ pref_ReportParseProblem(*ps, "need space, comment or semicolon",
+ lineNum, true);
+ NS_WARNING("malformed pref file");
+ return false;
+ }
+ break;
+
+ /* eol parsing */
+ case PREF_PARSE_UNTIL_EOL:
+ /* need to handle mac, unix, or dos line endings.
+ * PREF_PARSE_INIT will eat the next \n in case
+ * we have \r\n. */
+ if (c == '\r' || c == '\n' || c == 0x1A) {
+ state = ps->nextstate;
+ ps->nextstate = PREF_PARSE_INIT; /* reset next state */
+ }
+ break;
+ }
+ }
+ ps->state = state;
+ return true;
+}
+
+#ifdef TEST_PREFREAD
+
+static void
+pref_reader(void *closure,
+ const char *pref,
+ PrefValue val,
+ PrefType type,
+ bool defPref)
+{
+ printf("%spref(\"%s\", ", defPref ? "" : "user_", pref);
+ switch (type) {
+ case PREF_STRING:
+ printf("\"%s\");\n", val.stringVal);
+ break;
+ case PREF_INT:
+ printf("%i);\n", val.intVal);
+ break;
+ case PREF_BOOL:
+ printf("%s);\n", val.boolVal == false ? "false" : "true");
+ break;
+ }
+}
+
+int
+main(int argc, char **argv)
+{
+ PrefParseState ps;
+ char buf[4096]; /* i/o buffer */
+ FILE *fp;
+ int n;
+
+ if (argc == 1) {
+ printf("usage: prefread file.js\n");
+ return -1;
+ }
+
+ fp = fopen(argv[1], "r");
+ if (!fp) {
+ printf("failed to open file\n");
+ return -1;
+ }
+
+ PREF_InitParseState(&ps, pref_reader, nullptr, nullptr);
+
+ while ((n = fread(buf, 1, sizeof(buf), fp)) > 0)
+ PREF_ParseBuf(&ps, buf, n);
+
+ PREF_FinalizeParseState(&ps);
+
+ fclose(fp);
+ return 0;
+}
+
+#endif /* TEST_PREFREAD */
diff --git a/modules/libpref/prefread.h b/modules/libpref/prefread.h
new file mode 100644
index 000000000..2a09b30b6
--- /dev/null
+++ b/modules/libpref/prefread.h
@@ -0,0 +1,118 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef prefread_h__
+#define prefread_h__
+
+#include "prefapi.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Callback function used to notify consumer of preference name value pairs.
+ * The pref name and value must be copied by the implementor of the callback
+ * if they are needed beyond the scope of the callback function.
+ *
+ * @param closure
+ * user data passed to PREF_InitParseState
+ * @param pref
+ * preference name
+ * @param val
+ * preference value
+ * @param type
+ * preference type (PREF_STRING, PREF_INT, or PREF_BOOL)
+ * @param defPref
+ * preference type (true: default, false: user preference)
+ * @param stickyPref
+ * default preference marked as a "sticky" pref
+ */
+typedef void (*PrefReader)(void *closure,
+ const char *pref,
+ PrefValue val,
+ PrefType type,
+ bool defPref,
+ bool stickyPref);
+
+/**
+ * Report any errors or warnings we encounter during parsing.
+ */
+typedef void (*PrefParseErrorReporter)(const char* message, int line, bool error);
+
+/* structure fields are private */
+typedef struct PrefParseState {
+ PrefReader reader;
+ PrefParseErrorReporter reporter;
+ void *closure;
+ int state; /* PREF_PARSE_... */
+ int nextstate; /* sometimes used... */
+ const char *smatch; /* string to match */
+ int sindex; /* next char of smatch to check */
+ /* also, counter in \u parsing */
+ char16_t utf16[2]; /* parsing UTF16 (\u) escape */
+ int esclen; /* length in esctmp */
+ char esctmp[6]; /* raw escape to put back if err */
+ char quotechar; /* char delimiter for quotations */
+ char *lb; /* line buffer (only allocation) */
+ char *lbcur; /* line buffer cursor */
+ char *lbend; /* line buffer end */
+ char *vb; /* value buffer (ptr into lb) */
+ PrefType vtype; /* PREF_STRING,INT,BOOL */
+ bool fdefault; /* true if (default) pref */
+ bool fstickydefault; /* true if (sticky) pref */
+} PrefParseState;
+
+/**
+ * PREF_InitParseState
+ *
+ * Called to initialize a PrefParseState instance.
+ *
+ * @param ps
+ * PrefParseState instance.
+ * @param reader
+ * PrefReader callback function, which will be called once for each
+ * preference name value pair extracted.
+ * @param reporter
+ * PrefParseErrorReporter callback function, which will be called if we
+ * encounter any errors (stop) or warnings (continue) during parsing.
+ * @param closure
+ * PrefReader closure.
+ */
+void PREF_InitParseState(PrefParseState *ps, PrefReader reader,
+ PrefParseErrorReporter reporter, void *closure);
+
+/**
+ * PREF_FinalizeParseState
+ *
+ * Called to release any memory in use by the PrefParseState instance.
+ *
+ * @param ps
+ * PrefParseState instance.
+ */
+void PREF_FinalizeParseState(PrefParseState *ps);
+
+/**
+ * PREF_ParseBuf
+ *
+ * Called to parse a buffer containing some portion of a preference file. This
+ * function may be called repeatedly as new data is made available. The
+ * PrefReader callback function passed PREF_InitParseState will be called as
+ * preference name value pairs are extracted from the data.
+ *
+ * @param ps
+ * PrefParseState instance. Must have been initialized.
+ * @param buf
+ * Raw buffer containing data to be parsed.
+ * @param bufLen
+ * Length of buffer.
+ *
+ * @return false if buffer contains malformed content.
+ */
+bool PREF_ParseBuf(PrefParseState *ps, const char *buf, int bufLen);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* prefread_h__ */
diff --git a/modules/libpref/test/unit/data/testPref.js b/modules/libpref/test/unit/data/testPref.js
new file mode 100644
index 000000000..0864e7ce8
--- /dev/null
+++ b/modules/libpref/test/unit/data/testPref.js
@@ -0,0 +1,6 @@
+user_pref("testPref.bool1", true);
+user_pref("testPref.bool2", false);
+user_pref("testPref.int1", 23);
+user_pref("testPref.int2", -1236);
+user_pref("testPref.char1", "_testPref");
+user_pref("testPref.char2", "älskar"); \ No newline at end of file
diff --git a/modules/libpref/test/unit/data/testPrefSticky.js b/modules/libpref/test/unit/data/testPrefSticky.js
new file mode 100644
index 000000000..69b3165fb
--- /dev/null
+++ b/modules/libpref/test/unit/data/testPrefSticky.js
@@ -0,0 +1,2 @@
+pref("testPref.unsticky.bool", true);
+sticky_pref("testPref.sticky.bool", false);
diff --git a/modules/libpref/test/unit/data/testPrefStickyUser.js b/modules/libpref/test/unit/data/testPrefStickyUser.js
new file mode 100644
index 000000000..0ea090681
--- /dev/null
+++ b/modules/libpref/test/unit/data/testPrefStickyUser.js
@@ -0,0 +1,5 @@
+// testPrefSticky.js defined this pref as a sticky_pref(). Once a sticky
+// pref has been changed, it's written as a user_pref().
+// So this test file reflects that scenario.
+// Note the default in testPrefSticky.js is also false.
+user_pref("testPref.sticky.bool", false);
diff --git a/modules/libpref/test/unit/extdata/testExt.js b/modules/libpref/test/unit/extdata/testExt.js
new file mode 100644
index 000000000..17c684969
--- /dev/null
+++ b/modules/libpref/test/unit/extdata/testExt.js
@@ -0,0 +1,2 @@
+pref("testPref.bool2", true);
+pref("testExtPref.bool", true);
diff --git a/modules/libpref/test/unit/head_libPrefs.js b/modules/libpref/test/unit/head_libPrefs.js
new file mode 100644
index 000000000..b5e763419
--- /dev/null
+++ b/modules/libpref/test/unit/head_libPrefs.js
@@ -0,0 +1,45 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+const NS_APP_USER_PROFILE_50_DIR = "ProfD";
+
+var Ci = Components.interfaces;
+var Cc = Components.classes;
+var Cr = Components.results;
+var Cu = Components.utils;
+
+function do_check_throws(f, result, stack)
+{
+ if (!stack)
+ stack = Components.stack.caller;
+
+ try {
+ f();
+ } catch (exc) {
+ if (exc.result == result)
+ return;
+ do_throw("expected result " + result + ", caught " + exc, stack);
+ }
+ do_throw("expected result " + result + ", none thrown", stack);
+}
+
+var dirSvc = Cc["@mozilla.org/file/directory_service;1"].getService(Ci.nsIProperties);
+
+// Register current test directory as provider for the profile directory.
+var provider = {
+ getFile: function(prop, persistent) {
+ persistent.value = true;
+ if (prop == NS_APP_USER_PROFILE_50_DIR)
+ return dirSvc.get("CurProcD", Ci.nsIFile);
+ throw Components.Exception("Tried to get test directory '" + prop + "'", Cr.NS_ERROR_FAILURE);
+ },
+ QueryInterface: function(iid) {
+ if (iid.equals(Ci.nsIDirectoryServiceProvider) ||
+ iid.equals(Ci.nsISupports)) {
+ return this;
+ }
+ throw Cr.NS_ERROR_NO_INTERFACE;
+ }
+};
+dirSvc.QueryInterface(Ci.nsIDirectoryService).registerProvider(provider);
diff --git a/modules/libpref/test/unit/test_bug345529.js b/modules/libpref/test/unit/test_bug345529.js
new file mode 100644
index 000000000..2e4616a6b
--- /dev/null
+++ b/modules/libpref/test/unit/test_bug345529.js
@@ -0,0 +1,34 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/licenses/publicdomain/ */
+
+// Regression test for bug 345529 - crash removing an observer during an
+// nsPref:changed notification.
+function run_test() {
+ const Cc = Components.classes;
+ const Ci = Components.interfaces;
+ const PREF_NAME = "testPref";
+
+ var prefs = Cc["@mozilla.org/preferences-service;1"]
+ .getService(Ci.nsIPrefBranch);
+ var observer = {
+ QueryInterface: function QueryInterface(aIID) {
+ if (aIID.equals(Ci.nsIObserver) ||
+ aIID.equals(Ci.nsISupports))
+ return this;
+ throw Components.results.NS_NOINTERFACE;
+ },
+
+ observe: function observe(aSubject, aTopic, aState) {
+ prefs.removeObserver(PREF_NAME, observer);
+ }
+ }
+ prefs.addObserver(PREF_NAME, observer, false);
+
+ prefs.setCharPref(PREF_NAME, "test0")
+ // This second call isn't needed on a clean profile: it makes sure
+ // the observer gets called even if the pref already had the value
+ // "test0" before this test.
+ prefs.setCharPref(PREF_NAME, "test1")
+
+ do_check_true(true);
+}
diff --git a/modules/libpref/test/unit/test_bug506224.js b/modules/libpref/test/unit/test_bug506224.js
new file mode 100644
index 000000000..3fb723974
--- /dev/null
+++ b/modules/libpref/test/unit/test_bug506224.js
@@ -0,0 +1,29 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/licenses/publicdomain/ */
+
+function run_test() {
+ const Cc = Components.classes;
+ const Ci = Components.interfaces;
+ const PREF_NAME = "testPref";
+
+ var ps = Cc["@mozilla.org/preferences-service;1"]
+ .getService(Ci.nsIPrefService);
+ var prefs = ps.getDefaultBranch(null);
+ var userprefs = ps.getBranch(null);
+
+ prefs.setCharPref(PREF_NAME, "test0");
+ prefs.lockPref(PREF_NAME);
+ do_check_eq("test0", userprefs.getCharPref(PREF_NAME));
+ do_check_eq(false, userprefs.prefHasUserValue(PREF_NAME));
+
+ var file = do_get_profile();
+ file.append("prefs.js");
+ ps.savePrefFile(file);
+
+ prefs.unlockPref(PREF_NAME);
+ prefs.setCharPref(PREF_NAME, "test1");
+ ps.readUserPrefs(file);
+
+ do_check_eq("test1", userprefs.getCharPref(PREF_NAME));
+ do_check_eq(false, userprefs.prefHasUserValue(PREF_NAME));
+}
diff --git a/modules/libpref/test/unit/test_bug577950.js b/modules/libpref/test/unit/test_bug577950.js
new file mode 100644
index 000000000..b4f28e902
--- /dev/null
+++ b/modules/libpref/test/unit/test_bug577950.js
@@ -0,0 +1,28 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+function run_test() {
+ var ps = Cc["@mozilla.org/preferences-service;1"].
+ getService(Ci.nsIPrefService);
+
+ var pb = Cc["@mozilla.org/preferences-service;1"].
+ getService(Ci.nsIPrefBranch);
+
+ var observer = {
+ QueryInterface: function QueryInterface(aIID) {
+ if (aIID.equals(Ci.nsIObserver) ||
+ aIID.equals(Ci.nsISupports))
+ return this;
+ throw Components.results.NS_NOINTERFACE;
+ },
+
+ observe: function observe(aSubject, aTopic, aState) {
+ // Don't do anything.
+ }
+ }
+
+ /* Set the same pref twice. This shouldn't leak. */
+ pb.addObserver("UserPref.nonexistent.setIntPref", observer, false);
+ pb.addObserver("UserPref.nonexistent.setIntPref", observer, false);
+}
diff --git a/modules/libpref/test/unit/test_bug790374.js b/modules/libpref/test/unit/test_bug790374.js
new file mode 100644
index 000000000..64ca620ed
--- /dev/null
+++ b/modules/libpref/test/unit/test_bug790374.js
@@ -0,0 +1,55 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/licenses/publicdomain/ */
+
+function run_test() {
+ const Cc = Components.classes;
+ const Ci = Components.interfaces;
+ const Cr = Components.results;
+ const PREF_NAME = "testPref";
+
+ var ps = Cc["@mozilla.org/preferences-service;1"]
+ .getService(Ci.nsIPrefService);
+ var prefs = ps.getDefaultBranch(null);
+ var userprefs = ps.getBranch(null);
+
+ /* First, test to make sure we can parse a float from a string properly. */
+ prefs.setCharPref(PREF_NAME, "9.674");
+ prefs.lockPref(PREF_NAME);
+ var myFloat = 9.674;
+ var fudge = 0.001;
+ var floatPref = userprefs.getFloatPref(PREF_NAME);
+ do_check_true(myFloat+fudge >= floatPref);
+ do_check_true(myFloat-fudge <= floatPref);
+
+ /* Now test some failure conditions. */
+ prefs.unlockPref(PREF_NAME);
+ prefs.setCharPref(PREF_NAME, "");
+ prefs.lockPref(PREF_NAME);
+ do_check_throws(function() {
+ userprefs.getFloatPref(PREF_NAME);
+ }, Cr.NS_ERROR_ILLEGAL_VALUE);
+
+ prefs.unlockPref(PREF_NAME);
+ prefs.setCharPref(PREF_NAME, "18.0a1");
+ prefs.lockPref(PREF_NAME);
+
+ do_check_throws(function() {
+ userprefs.getFloatPref(PREF_NAME);
+ }, Cr.NS_ERROR_ILLEGAL_VALUE);
+
+ prefs.unlockPref(PREF_NAME);
+ prefs.setCharPref(PREF_NAME, "09.25.2012");
+ prefs.lockPref(PREF_NAME);
+
+ do_check_throws(function() {
+ userprefs.getFloatPref(PREF_NAME);
+ }, Cr.NS_ERROR_ILLEGAL_VALUE);
+
+ prefs.unlockPref(PREF_NAME);
+ prefs.setCharPref(PREF_NAME, "aString");
+ prefs.lockPref(PREF_NAME);
+
+ do_check_throws(function() {
+ userprefs.getFloatPref(PREF_NAME);
+ }, Cr.NS_ERROR_ILLEGAL_VALUE);
+}
diff --git a/modules/libpref/test/unit/test_changeType.js b/modules/libpref/test/unit/test_changeType.js
new file mode 100644
index 000000000..573d561a4
--- /dev/null
+++ b/modules/libpref/test/unit/test_changeType.js
@@ -0,0 +1,63 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* Tests for changing the type of a preference (bug 985998) */
+
+const PREF_INVALID = 0;
+const PREF_BOOL = 128;
+const PREF_INT = 64;
+const PREF_STRING = 32;
+
+function run_test() {
+
+ var ps = Cc["@mozilla.org/preferences-service;1"].
+ getService(Ci.nsIPrefService);
+
+ let defaultBranch = ps.getDefaultBranch("");
+ let userBranch = ps.getBranch("");
+
+ //**************************************************************************//
+ // Can't change the type of prefs that have default values
+
+ defaultBranch.setBoolPref("TypeTest.existing.bool", true);
+ defaultBranch.setIntPref("TypeTest.existing.int", 23);
+ defaultBranch.setCharPref("TypeTest.existing.char", "hey");
+
+ // The user branch reads back the expected default
+ do_check_eq(userBranch.getBoolPref("TypeTest.existing.bool"), true);
+ do_check_eq(userBranch.getIntPref("TypeTest.existing.int"), 23);
+ do_check_eq(userBranch.getCharPref("TypeTest.existing.char"), "hey");
+
+ // All the combinations of attempted type changes
+ do_check_throws(function() {
+ userBranch.setCharPref("TypeTest.existing.bool", "boo"); }, Cr.NS_ERROR_UNEXPECTED);
+ do_check_throws(function() {
+ userBranch.setIntPref("TypeTest.existing.bool", 5); }, Cr.NS_ERROR_UNEXPECTED);
+ do_check_throws(function() {
+ userBranch.setCharPref("TypeTest.existing.int", "boo"); }, Cr.NS_ERROR_UNEXPECTED);
+ do_check_throws(function() {
+ userBranch.setBoolPref("TypeTest.existing.int", true); }, Cr.NS_ERROR_UNEXPECTED);
+ do_check_throws(function() {
+ userBranch.setBoolPref("TypeTest.existing.char", true); }, Cr.NS_ERROR_UNEXPECTED);
+ do_check_throws(function() {
+ userBranch.setIntPref("TypeTest.existing.char", 6); }, Cr.NS_ERROR_UNEXPECTED);
+
+
+ //**************************************************************************//
+ // Prefs that don't have default values can mutate
+ let pref = "TypeTest.user";
+ userBranch.setBoolPref(pref, true);
+ userBranch.setCharPref(pref, "yay");
+ do_check_eq(userBranch.getCharPref(pref), "yay");
+ userBranch.setIntPref(pref, 7);
+ do_check_eq(userBranch.getIntPref(pref), 7);
+ userBranch.setBoolPref(pref, false);
+ do_check_eq(userBranch.getBoolPref(pref), false);
+ userBranch.setIntPref(pref, 8);
+ do_check_eq(userBranch.getIntPref(pref), 8);
+ userBranch.setCharPref(pref, "whee");
+ do_check_eq(userBranch.getCharPref(pref), "whee");
+ userBranch.setBoolPref(pref, true);
+ do_check_eq(userBranch.getBoolPref(pref), true);
+}
diff --git a/modules/libpref/test/unit/test_dirtyPrefs.js b/modules/libpref/test/unit/test_dirtyPrefs.js
new file mode 100644
index 000000000..361171616
--- /dev/null
+++ b/modules/libpref/test/unit/test_dirtyPrefs.js
@@ -0,0 +1,75 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* Tests for handling of the preferences 'dirty' flag (bug 985998) */
+
+const PREF_INVALID = 0;
+const PREF_BOOL = 128;
+const PREF_INT = 64;
+const PREF_STRING = 32;
+
+function run_test() {
+
+ var ps = Cc["@mozilla.org/preferences-service;1"].
+ getService(Ci.nsIPrefService);
+
+ let defaultBranch = ps.getDefaultBranch("");
+ let userBranch = ps.getBranch("");
+
+ let prefFile = do_get_profile();
+ prefFile.append("prefs.js");
+
+ //**************************************************************************//
+ // prefs are not dirty after a write
+ ps.savePrefFile(prefFile);
+ do_check_false(ps.dirty);
+
+ // set a new a user value, we should become dirty
+ userBranch.setBoolPref("DirtyTest.new.bool", true);
+ do_check_true(ps.dirty);
+ ps.savePrefFile(prefFile);
+ // Overwrite a pref with the same value => not dirty
+ userBranch.setBoolPref("DirtyTest.new.bool", true);
+ do_check_false(ps.dirty);
+
+ // Repeat for the other two types
+ userBranch.setIntPref("DirtyTest.new.int", 1);
+ do_check_true(ps.dirty);
+ ps.savePrefFile(prefFile);
+ // Overwrite a pref with the same value => not dirty
+ userBranch.setIntPref("DirtyTest.new.int", 1);
+ do_check_false(ps.dirty);
+
+ userBranch.setCharPref("DirtyTest.new.char", "oop");
+ do_check_true(ps.dirty);
+ ps.savePrefFile(prefFile);
+ // Overwrite a pref with the same value => not dirty
+ userBranch.setCharPref("DirtyTest.new.char", "oop");
+ do_check_false(ps.dirty);
+
+ // change *type* of a user value -> dirty
+ userBranch.setBoolPref("DirtyTest.new.char", false);
+ do_check_true(ps.dirty);
+ ps.savePrefFile(prefFile);
+
+ // Set a default pref => not dirty (defaults don't go into prefs.js)
+ defaultBranch.setBoolPref("DirtyTest.existing.bool", true);
+ do_check_false(ps.dirty);
+ // Fail to change type of a pref with default value -> not dirty
+ do_check_throws(function() {
+ userBranch.setCharPref("DirtyTest.existing.bool", "boo"); }, Cr.NS_ERROR_UNEXPECTED);
+ do_check_false(ps.dirty);
+
+ // Set user value same as default, not dirty
+ userBranch.setBoolPref("DirtyTest.existing.bool", true);
+ do_check_false(ps.dirty);
+ // User value different from default, dirty
+ userBranch.setBoolPref("DirtyTest.existing.bool", false);
+ do_check_true(ps.dirty);
+ ps.savePrefFile(prefFile);
+ // Back to default value, dirty again
+ userBranch.setBoolPref("DirtyTest.existing.bool", true);
+ do_check_true(ps.dirty);
+ ps.savePrefFile(prefFile);
+}
diff --git a/modules/libpref/test/unit/test_extprefs.js b/modules/libpref/test/unit/test_extprefs.js
new file mode 100644
index 000000000..37f8de167
--- /dev/null
+++ b/modules/libpref/test/unit/test_extprefs.js
@@ -0,0 +1,70 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/licenses/publicdomain/ */
+
+Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
+Components.utils.import("resource://gre/modules/Services.jsm");
+
+// The profile directory is already set up in the head_ files.
+
+function arrayenumerator(a)
+{
+ return {
+ i_: 0,
+ QueryInterface: XPCOMUtils.generateQI([Ci.nsISimpleEnumerator]),
+ hasMoreElements: function ae_hasMoreElements() {
+ return this.i_ < a.length;
+ },
+ getNext: function ae_getNext() {
+ return a[this.i_++];
+ }
+ };
+}
+
+function run_test() {
+ var ps = Cc["@mozilla.org/preferences-service;1"].
+ getService(Ci.nsIPrefService).QueryInterface(Ci.nsIPrefBranch);
+
+ var extprefs = [do_get_file("extdata")];
+
+ var extProvider = {
+ QueryInterface: XPCOMUtils.generateQI([Ci.nsIDirectoryServiceProvider,
+ Ci.nsIDirectoryServiceProvider2]),
+ getFile: function ep_getFile() {
+ throw Cr.NS_ERROR_FAILURE;
+ },
+
+ getFiles: function ep_getFiles(key) {
+ if (key != "ExtPrefDL")
+ throw Cr.NS_ERROR_FAILURE;
+
+ return arrayenumerator(extprefs);
+ }
+ };
+
+ let prefFile = do_get_file("data/testPref.js");
+
+ do_check_throws(function() {
+ ps.getBoolPref("testExtPref.bool");
+ }, Cr.NS_ERROR_UNEXPECTED);
+ do_check_throws(function() {
+ ps.getBoolPref("testPref.bool1");
+ }, Cr.NS_ERROR_UNEXPECTED);
+
+ ps.readUserPrefs(prefFile);
+
+ do_check_true(ps.getBoolPref("testPref.bool1"));
+ ps.setBoolPref("testPref.bool1", false);
+ do_check_false(ps.getBoolPref("testPref.bool1"));
+
+ dirSvc.registerProvider(extProvider);
+ Services.obs.notifyObservers(null, "load-extension-defaults", null);
+
+ // The extension default should be available.
+ do_check_true(ps.getBoolPref("testExtPref.bool"));
+
+ // The extension default should not override existing user prefs
+ do_check_false(ps.getBoolPref("testPref.bool2"));
+
+ // The extension default should not modify existing set values
+ do_check_false(ps.getBoolPref("testPref.bool1"));
+}
diff --git a/modules/libpref/test/unit/test_libPrefs.js b/modules/libpref/test/unit/test_libPrefs.js
new file mode 100644
index 000000000..be9c629e0
--- /dev/null
+++ b/modules/libpref/test/unit/test_libPrefs.js
@@ -0,0 +1,392 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+const PREF_INVALID = 0;
+const PREF_BOOL = 128;
+const PREF_INT = 64;
+const PREF_STRING = 32;
+
+const MAX_PREF_LENGTH = 1 * 1024 * 1024;
+
+function makeList(a)
+{
+ var o = {};
+ for(var i=0; i<a.length; i++)
+ {
+ o[a[i]] = '';
+ }
+ return o;
+}
+
+function run_test() {
+
+ var ps = Cc["@mozilla.org/preferences-service;1"].
+ getService(Ci.nsIPrefService);
+
+ var pb2= Cc["@mozilla.org/preferences-service;1"].
+ getService(Ci.nsIPrefBranch);
+
+ var pb = Cc["@mozilla.org/preferences-service;1"].
+ getService(Ci.nsIPrefBranch);
+
+ //**************************************************************************//
+ // Nullsafety
+
+ do_check_throws(function() {
+ pb.getPrefType(null); }, Cr.NS_ERROR_INVALID_ARG);
+ do_check_throws(function() {
+ pb.getBoolPref(null); }, Cr.NS_ERROR_INVALID_ARG);
+ do_check_throws(function() {
+ pb.setBoolPref(null, false); }, Cr.NS_ERROR_INVALID_ARG);
+ do_check_throws(function() {
+ pb.getIntPref(null); }, Cr.NS_ERROR_INVALID_ARG);
+ do_check_throws(function() {
+ pb.setIntPref(null, 0); }, Cr.NS_ERROR_INVALID_ARG);
+ do_check_throws(function() {
+ pb.getCharPref(null); }, Cr.NS_ERROR_INVALID_ARG);
+ do_check_throws(function() {
+ pb.setCharPref(null, null); }, Cr.NS_ERROR_INVALID_ARG);
+ do_check_throws(function() {
+ pb.getComplexValue(null, Components.interfaces.nsISupportsString); }, Cr.NS_ERROR_INVALID_ARG);
+ do_check_throws(function() {
+ pb.setComplexValue(null, Components.interfaces.nsISupportsString, pb); }, Cr.NS_ERROR_INVALID_ARG);
+ do_check_throws(function() {
+ pb.clearUserPref(null); }, Cr.NS_ERROR_INVALID_ARG);
+ do_check_throws(function() {
+ pb.prefHasUserValue(null); }, Cr.NS_ERROR_INVALID_ARG);
+ do_check_throws(function() {
+ pb.lockPref(null); }, Cr.NS_ERROR_INVALID_ARG);
+ do_check_throws(function() {
+ pb.prefIsLocked(null); }, Cr.NS_ERROR_INVALID_ARG);
+ do_check_throws(function() {
+ pb.unlockPref(null); }, Cr.NS_ERROR_INVALID_ARG);
+ do_check_throws(function() {
+ pb.deleteBranch(null); }, Cr.NS_ERROR_INVALID_ARG);
+ do_check_throws(function() {
+ pb.getChildList(null); }, Cr.NS_ERROR_INVALID_ARG);
+
+ //**************************************************************************//
+ // Nonexisting user preferences
+
+ do_check_eq(pb.prefHasUserValue("UserPref.nonexistent.hasUserValue"), false);
+ pb.clearUserPref("UserPref.nonexistent.clearUserPref"); // shouldn't throw
+ do_check_eq(pb.getPrefType("UserPref.nonexistent.getPrefType"), PREF_INVALID);
+ do_check_eq(pb.root, "");
+
+ // bool...
+ do_check_throws(function() {
+ pb.getBoolPref("UserPref.nonexistent.getBoolPref");}, Cr.NS_ERROR_UNEXPECTED);
+ pb.setBoolPref("UserPref.nonexistent.setBoolPref", false);
+ do_check_eq(pb.getBoolPref("UserPref.nonexistent.setBoolPref"), false);
+
+ // int...
+ do_check_throws(function() {
+ pb.getIntPref("UserPref.nonexistent.getIntPref");}, Cr.NS_ERROR_UNEXPECTED);
+ pb.setIntPref("UserPref.nonexistent.setIntPref", 5);
+ do_check_eq(pb.getIntPref("UserPref.nonexistent.setIntPref"), 5);
+
+ // char
+ do_check_throws(function() {
+ pb.getCharPref("UserPref.nonexistent.getCharPref");}, Cr.NS_ERROR_UNEXPECTED);
+ pb.setCharPref("UserPref.nonexistent.setCharPref", "_test");
+ do_check_eq(pb.getCharPref("UserPref.nonexistent.setCharPref"), "_test");
+
+ //**************************************************************************//
+ // Existing user Prefs and data integrity test (round-trip match)
+
+ pb.setBoolPref("UserPref.existing.bool", true);
+ pb.setIntPref("UserPref.existing.int", 23);
+ pb.setCharPref("UserPref.existing.char", "hey");
+
+ // getPref should return the pref value
+ do_check_eq(pb.getBoolPref("UserPref.existing.bool"), true);
+ do_check_eq(pb.getIntPref("UserPref.existing.int"), 23);
+ do_check_eq(pb.getCharPref("UserPref.existing.char"), "hey");
+
+ // setPref should not complain and should change the value of the pref
+ pb.setBoolPref("UserPref.existing.bool", false);
+ do_check_eq(pb.getBoolPref("UserPref.existing.bool"), false);
+ pb.setIntPref("UserPref.existing.int", 24);
+ do_check_eq(pb.getIntPref("UserPref.existing.int"), 24);
+ pb.setCharPref("UserPref.existing.char", "hej då!");
+ do_check_eq(pb.getCharPref("UserPref.existing.char"), "hej då!");
+
+ // prefHasUserValue should return true now
+ do_check_true(pb.prefHasUserValue("UserPref.existing.bool"));
+ do_check_true(pb.prefHasUserValue("UserPref.existing.int"));
+ do_check_true(pb.prefHasUserValue("UserPref.existing.char"));
+
+ // clearUserPref should remove the pref
+ pb.clearUserPref("UserPref.existing.bool");
+ do_check_false(pb.prefHasUserValue("UserPref.existing.bool"));
+ pb.clearUserPref("UserPref.existing.int");
+ do_check_false(pb.prefHasUserValue("UserPref.existing.int"));
+ pb.clearUserPref("UserPref.existing.char");
+ do_check_false(pb.prefHasUserValue("UserPref.existing.char"));
+
+ //**************************************************************************//
+ // Large value test
+
+ let largeStr = new Array(MAX_PREF_LENGTH + 1).join('x');
+ pb.setCharPref("UserPref.large.char", largeStr);
+ largeStr += 'x';
+ do_check_throws(function() {
+ pb.setCharPref("UserPref.large.char", largeStr); }, Cr.NS_ERROR_ILLEGAL_VALUE);
+
+ //**************************************************************************//
+ // getPrefType test
+
+ // bool...
+ pb.setBoolPref("UserPref.getPrefType.bool", true);
+ do_check_eq(pb.getPrefType("UserPref.getPrefType.bool"), PREF_BOOL);
+
+ // int...
+ pb.setIntPref("UserPref.getPrefType.int", -234);
+ do_check_eq(pb.getPrefType("UserPref.getPrefType.int"), PREF_INT);
+
+ // char...
+ pb.setCharPref("UserPref.getPrefType.char", "testing1..2");
+ do_check_eq(pb.getPrefType("UserPref.getPrefType.char"), PREF_STRING);
+
+ //**************************************************************************//
+ // getBranch tests
+
+ do_check_eq(ps.root, "");
+
+ // bool ...
+ pb.setBoolPref("UserPref.root.boolPref", true);
+ let pb_1 = ps.getBranch("UserPref.root.");
+ do_check_eq(pb_1.getBoolPref("boolPref"), true);
+ let pb_2 = ps.getBranch("UserPref.root.boolPref");
+ do_check_eq(pb_2.getBoolPref(""), true);
+ pb_2.setBoolPref(".anotherPref", false);
+ let pb_3 = ps.getBranch("UserPref.root.boolPre");
+ do_check_eq(pb_3.getBoolPref("f.anotherPref"), false);
+
+ // int ...
+ pb.setIntPref("UserPref.root.intPref", 23);
+ pb_1 = ps.getBranch("UserPref.root.");
+ do_check_eq(pb_1.getIntPref("intPref"), 23);
+ pb_2 = ps.getBranch("UserPref.root.intPref");
+ do_check_eq(pb_2.getIntPref(""), 23);
+ pb_2.setIntPref(".anotherPref", 69);
+ pb_3 = ps.getBranch("UserPref.root.intPre");
+ do_check_eq(pb_3.getIntPref("f.anotherPref"), 69);
+
+ // char...
+ pb.setCharPref("UserPref.root.charPref", "_char");
+ pb_1 = ps.getBranch("UserPref.root.");
+ do_check_eq(pb_1.getCharPref("charPref"), "_char");
+ pb_2 = ps.getBranch("UserPref.root.charPref");
+ do_check_eq(pb_2.getCharPref(""), "_char");
+ pb_2.setCharPref(".anotherPref", "_another");
+ pb_3 = ps.getBranch("UserPref.root.charPre");
+ do_check_eq(pb_3.getCharPref("f.anotherPref"), "_another");
+
+ //**************************************************************************//
+ // getChildlist tests
+
+ // get an already set prefBranch
+ pb1 = ps.getBranch("UserPref.root.");
+ let prefList = pb1.getChildList("");
+ do_check_eq(prefList.length, 6);
+
+ // check for specific prefs in the array : the order is not important
+ do_check_true("boolPref" in makeList(prefList));
+ do_check_true("intPref" in makeList(prefList));
+ do_check_true("charPref" in makeList(prefList));
+ do_check_true("boolPref.anotherPref" in makeList(prefList));
+ do_check_true("intPref.anotherPref" in makeList(prefList));
+ do_check_true("charPref.anotherPref" in makeList(prefList));
+
+ //**************************************************************************//
+ // Default branch tests
+
+ // bool...
+ pb1 = ps.getDefaultBranch("");
+ pb1.setBoolPref("DefaultPref.bool", true);
+ do_check_eq(pb1.getBoolPref("DefaultPref.bool"), true);
+ do_check_false(pb1.prefHasUserValue("DefaultPref.bool"));
+ ps.setBoolPref("DefaultPref.bool", false);
+ do_check_true(pb1.prefHasUserValue("DefaultPref.bool"));
+ do_check_eq(ps.getBoolPref("DefaultPref.bool"), false);
+
+ // int...
+ pb1 = ps.getDefaultBranch("");
+ pb1.setIntPref("DefaultPref.int", 100);
+ do_check_eq(pb1.getIntPref("DefaultPref.int"), 100);
+ do_check_false(pb1.prefHasUserValue("DefaultPref.int"));
+ ps.setIntPref("DefaultPref.int", 50);
+ do_check_true(pb1.prefHasUserValue("DefaultPref.int"));
+ do_check_eq(ps.getIntPref("DefaultPref.int"), 50);
+
+ // char...
+ pb1 = ps.getDefaultBranch("");
+ pb1.setCharPref("DefaultPref.char", "_default");
+ do_check_eq(pb1.getCharPref("DefaultPref.char"), "_default");
+ do_check_false(pb1.prefHasUserValue("DefaultPref.char"));
+ ps.setCharPref("DefaultPref.char", "_user");
+ do_check_true(pb1.prefHasUserValue("DefaultPref.char"));
+ do_check_eq(ps.getCharPref("DefaultPref.char"), "_user");
+
+ //**************************************************************************//
+ // pref Locking/Unlocking tests
+
+ // locking and unlocking a nonexistent pref should throw
+ do_check_throws(function() {
+ ps.lockPref("DefaultPref.nonexistent");}, Cr.NS_ERROR_UNEXPECTED);
+ do_check_throws(function() {
+ ps.unlockPref("DefaultPref.nonexistent");}, Cr.NS_ERROR_UNEXPECTED);
+
+ // getting a locked pref branch should return the "default" value
+ do_check_false(ps.prefIsLocked("DefaultPref.char"));
+ ps.lockPref("DefaultPref.char");
+ do_check_eq(ps.getCharPref("DefaultPref.char"), "_default");
+ do_check_true(ps.prefIsLocked("DefaultPref.char"));
+
+ // getting an unlocked pref branch should return the "user" value
+ ps.unlockPref("DefaultPref.char");
+ do_check_eq(ps.getCharPref("DefaultPref.char"), "_user");
+ do_check_false(ps.prefIsLocked("DefaultPref.char"));
+
+ // setting the "default" value to a user pref branch should
+ // make prefHasUserValue return false (documented behavior)
+ ps.setCharPref("DefaultPref.char", "_default");
+ do_check_false(pb1.prefHasUserValue("DefaultPref.char"));
+
+ // unlocking and locking multiple times shouldn't throw
+ ps.unlockPref("DefaultPref.char");
+ ps.lockPref("DefaultPref.char");
+ ps.lockPref("DefaultPref.char");
+
+ //**************************************************************************//
+ // resetBranch test
+
+ // NOT IMPLEMENTED YET in module/libpref. So we're not testing !
+ // uncomment the following if resetBranch ever gets implemented.
+ /*ps.resetBranch("DefaultPref");
+ do_check_eq(ps.getBoolPref("DefaultPref.bool"), true);
+ do_check_eq(ps.getIntPref("DefaultPref.int"), 100);
+ do_check_eq(ps.getCharPref("DefaultPref.char"), "_default");*/
+
+ //**************************************************************************//
+ // deleteBranch tests
+
+ // TODO : Really, this should throw!, by documentation.
+ // do_check_throws(function() {
+ // ps.deleteBranch("UserPref.nonexistent.deleteBranch");}, Cr.NS_ERROR_UNEXPECTED);
+
+ ps.deleteBranch("DefaultPref");
+ pb = ps.getBranch("DefaultPref");
+ pb1 = ps.getDefaultBranch("DefaultPref");
+
+ // getting prefs on deleted user branches should throw
+ do_check_throws(function() {
+ pb.getBoolPref("DefaultPref.bool");}, Cr.NS_ERROR_UNEXPECTED);
+ do_check_throws(function() {
+ pb.getIntPref("DefaultPref.int");}, Cr.NS_ERROR_UNEXPECTED);
+ do_check_throws(function() {
+ pb.getCharPref("DefaultPref.char");}, Cr.NS_ERROR_UNEXPECTED);
+
+ // getting prefs on deleted default branches should throw
+ do_check_throws(function() {
+ pb1.getBoolPref("DefaultPref.bool");}, Cr.NS_ERROR_UNEXPECTED);
+ do_check_throws(function() {
+ pb1.getIntPref("DefaultPref.int");}, Cr.NS_ERROR_UNEXPECTED);
+ do_check_throws(function() {
+ pb1.getCharPref("DefaultPref.char");}, Cr.NS_ERROR_UNEXPECTED);
+
+ //**************************************************************************//
+ // savePrefFile & readPrefFile tests
+
+ // set some prefs
+ ps.setBoolPref("ReadPref.bool", true);
+ ps.setIntPref("ReadPref.int", 230);
+ ps.setCharPref("ReadPref.char", "hello");
+
+ // save those prefs in a file
+ let savePrefFile = do_get_cwd();
+ savePrefFile.append("data");
+ savePrefFile.append("savePref.js");
+ if (savePrefFile.exists())
+ savePrefFile.remove(false);
+ savePrefFile.create(Ci.nsIFile.NORMAL_FILE_TYPE, 0o666);
+ ps.savePrefFile(savePrefFile);
+ ps.resetPrefs();
+
+ // load a preexisting pref file
+ let prefFile = do_get_file("data/testPref.js");
+ ps.readUserPrefs(prefFile);
+
+ // former prefs should have been replaced/lost
+ do_check_throws(function() {
+ do_check_eq(pb.getBoolPref("ReadPref.bool"));}, Cr.NS_ERROR_UNEXPECTED);
+ do_check_throws(function() {
+ do_check_eq(pb.getIntPref("ReadPref.int"));}, Cr.NS_ERROR_UNEXPECTED);
+ do_check_throws(function() {
+ do_check_eq(pb.getCharPref("ReadPref.char"));}, Cr.NS_ERROR_UNEXPECTED);
+
+ // loaded prefs should read ok.
+ pb = ps.getBranch("testPref.");
+ do_check_eq(pb.getBoolPref("bool1"), true);
+ do_check_eq(pb.getBoolPref("bool2"), false);
+ do_check_eq(pb.getIntPref("int1"), 23);
+ do_check_eq(pb.getIntPref("int2"), -1236);
+ do_check_eq(pb.getCharPref("char1"), "_testPref");
+ do_check_eq(pb.getCharPref("char2"), "älskar");
+
+ // loading our former savePrefFile should allow us to read former prefs
+ ps.readUserPrefs(savePrefFile);
+ // cleanup the file now we don't need it
+ savePrefFile.remove(false);
+ do_check_eq(ps.getBoolPref("ReadPref.bool"), true);
+ do_check_eq(ps.getIntPref("ReadPref.int"), 230);
+ do_check_eq(ps.getCharPref("ReadPref.char"), "hello");
+
+ // ... and still be able to access "prior-to-readUserPrefs" preferences
+ do_check_eq(pb.getBoolPref("bool1"), true);
+ do_check_eq(pb.getBoolPref("bool2"), false);
+ do_check_eq(pb.getIntPref("int1"), 23);
+
+ //**************************************************************************//
+ // preference Observers
+
+ // an observer...
+ var observer = {
+ QueryInterface: function QueryInterface(aIID) {
+ if (aIID.equals(Ci.nsIObserver) ||
+ aIID.equals(Ci.nsISupports))
+ return this;
+ throw Components.results.NS_NOINTERFACE;
+ },
+
+ observe: function observe(aSubject, aTopic, aState) {
+ do_check_eq(aTopic, "nsPref:changed");
+ do_check_eq(aState, "ReadPref.int");
+ do_check_eq(ps.getIntPref(aState), 76);
+ ps.removeObserver("ReadPref.int", this);
+
+ // notification received, we may go on...
+ do_test_finished();
+ }
+ }
+
+ pb2.addObserver("ReadPref.int", observer, false);
+ ps.setIntPref("ReadPref.int", 76);
+
+ // test will continue upon notification...
+ do_test_pending();
+
+ // removed observer should not fire
+ pb2.removeObserver("ReadPref.int", observer);
+ ps.setIntPref("ReadPref.int", 32);
+
+ // let's test observers once more with a non-root prefbranch
+ pb2.getBranch("ReadPref.");
+ pb2.addObserver("int", observer, false);
+ ps.setIntPref("ReadPref.int", 76);
+
+ // test will complete upon notification...
+ do_test_pending();
+}
diff --git a/modules/libpref/test/unit/test_stickyprefs.js b/modules/libpref/test/unit/test_stickyprefs.js
new file mode 100644
index 000000000..c2c5a7c4b
--- /dev/null
+++ b/modules/libpref/test/unit/test_stickyprefs.js
@@ -0,0 +1,170 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/licenses/publicdomain/ */
+
+Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
+Components.utils.import("resource://gre/modules/Services.jsm");
+
+const ps = Services.prefs;
+
+// Once we fetch the profile directory the xpcshell test harness will send
+// a profile-before-change notification at shutdown. This causes the prefs
+// service to flush the prefs file - and the prefs file it uses ends up being
+// testPrefSticky*.js in the test dir. This upsets things in confusing ways :)
+// We avoid this by ensuring our "temp" prefs.js is the current prefs file.
+do_get_profile();
+do_register_cleanup(saveAndReload);
+
+// A little helper to reset the service and load some pref files
+function resetAndLoad(filenames) {
+ ps.resetPrefs();
+ for (let filename of filenames) {
+ ps.readUserPrefs(do_get_file(filename));
+ }
+}
+
+// A little helper that saves the current state to a file in the profile
+// dir, then resets the service and re-reads the file it just saved.
+// Used to test what gets actually written - things the pref service decided
+// not to write don't exist at all after this call.
+function saveAndReload() {
+ let file = do_get_profile();
+ file.append("prefs.js");
+ ps.savePrefFile(file);
+
+ // Now reset the pref service and re-read what we saved.
+ ps.resetPrefs();
+ ps.readUserPrefs(file);
+}
+
+function run_test() {
+ run_next_test();
+}
+
+// A sticky pref should not be written if the value is unchanged.
+add_test(function notWrittenWhenUnchanged() {
+ resetAndLoad(["data/testPrefSticky.js"]);
+ Assert.strictEqual(ps.getBoolPref("testPref.unsticky.bool"), true);
+ Assert.strictEqual(ps.getBoolPref("testPref.sticky.bool"), false);
+
+ // write prefs - but we haven't changed the sticky one, so it shouldn't be written.
+ saveAndReload();
+ // sticky should not have been written to the new file.
+ try {
+ ps.getBoolPref("testPref.sticky.bool");
+ Assert.ok(false, "expected failure reading this pref");
+ } catch (ex) {
+ Assert.ok(ex, "exception reading regular pref");
+ }
+ run_next_test();
+});
+
+// Loading a sticky_pref then a user_pref for the same pref means it should
+// always be written.
+add_test(function writtenOnceLoadedWithoutChange() {
+ // Load the same pref file *as well as* a pref file that has a user_pref for
+ // our sticky with the default value. It should be re-written without us
+ // touching it.
+ resetAndLoad(["data/testPrefSticky.js", "data/testPrefStickyUser.js"]);
+ // reset and re-read what we just wrote - it should be written.
+ saveAndReload();
+ Assert.strictEqual(ps.getBoolPref("testPref.sticky.bool"), false,
+ "user_pref was written with default value");
+ run_next_test();
+});
+
+// If a sticky pref is explicicitly changed, even to the default, it is written.
+add_test(function writtenOnceLoadedWithChangeNonDefault() {
+ // Load the same pref file *as well as* a pref file that has a user_pref for
+ // our sticky - then change the pref. It should be written.
+ resetAndLoad(["data/testPrefSticky.js", "data/testPrefStickyUser.js"]);
+ // Set a new val and check we wrote it.
+ ps.setBoolPref("testPref.sticky.bool", false);
+ saveAndReload();
+ Assert.strictEqual(ps.getBoolPref("testPref.sticky.bool"), false,
+ "user_pref was written with custom value");
+ run_next_test();
+});
+
+// If a sticky pref is changed to the non-default value, it is written.
+add_test(function writtenOnceLoadedWithChangeNonDefault() {
+ // Load the same pref file *as well as* a pref file that has a user_pref for
+ // our sticky - then change the pref. It should be written.
+ resetAndLoad(["data/testPrefSticky.js", "data/testPrefStickyUser.js"]);
+ // Set a new val and check we wrote it.
+ ps.setBoolPref("testPref.sticky.bool", true);
+ saveAndReload();
+ Assert.strictEqual(ps.getBoolPref("testPref.sticky.bool"), true,
+ "user_pref was written with custom value");
+ run_next_test();
+});
+
+// Test that prefHasUserValue always returns true whenever there is a sticky
+// value, even when that value matches the default. This is mainly for
+// about:config semantics - prefs with a sticky value always remain bold and
+// always offer "reset" (which fully resets and drops the sticky value as if
+// the pref had never changed.)
+add_test(function hasUserValue() {
+ // sticky pref without user value.
+ resetAndLoad(["data/testPrefSticky.js"]);
+ Assert.strictEqual(ps.getBoolPref("testPref.sticky.bool"), false);
+ Assert.ok(!ps.prefHasUserValue("testPref.sticky.bool"),
+ "should not initially reflect a user value");
+
+ ps.setBoolPref("testPref.sticky.bool", false);
+ Assert.ok(ps.prefHasUserValue("testPref.sticky.bool"),
+ "should reflect a user value after set to default");
+
+ ps.setBoolPref("testPref.sticky.bool", true);
+ Assert.ok(ps.prefHasUserValue("testPref.sticky.bool"),
+ "should reflect a user value after change to non-default");
+
+ ps.clearUserPref("testPref.sticky.bool");
+ Assert.ok(!ps.prefHasUserValue("testPref.sticky.bool"),
+ "should reset to no user value");
+ ps.setBoolPref("testPref.sticky.bool", false, "expected default");
+
+ // And make sure the pref immediately reflects a user value after load.
+ resetAndLoad(["data/testPrefSticky.js", "data/testPrefStickyUser.js"]);
+ Assert.strictEqual(ps.getBoolPref("testPref.sticky.bool"), false);
+ Assert.ok(ps.prefHasUserValue("testPref.sticky.bool"),
+ "should have a user value when loaded value is the default");
+ run_next_test();
+});
+
+// Test that clearUserPref removes the "sticky" value.
+add_test(function clearUserPref() {
+ // load things such that we have a sticky value which is the same as the
+ // default.
+ resetAndLoad(["data/testPrefSticky.js", "data/testPrefStickyUser.js"]);
+ ps.clearUserPref("testPref.sticky.bool");
+
+ // Once we save prefs the sticky pref should no longer be written.
+ saveAndReload();
+ try {
+ ps.getBoolPref("testPref.sticky.bool");
+ Assert.ok(false, "expected failure reading this pref");
+ } catch (ex) {
+ Assert.ok(ex, "pref doesn't have a sticky value");
+ }
+ run_next_test();
+});
+
+// Test that a pref observer gets a notification fired when a sticky pref
+// has it's value changed to the same value as the default. The reason for
+// this behaviour is that later we might have other code that cares about a
+// pref being sticky (IOW, we notify due to the "state" of the pref changing
+// even if the value has not)
+add_test(function observerFires() {
+ // load things so there's no sticky value.
+ resetAndLoad(["data/testPrefSticky.js"]);
+
+ function observe(subject, topic, data) {
+ Assert.equal(data, "testPref.sticky.bool");
+ ps.removeObserver("testPref.sticky.bool", observe);
+ run_next_test();
+ }
+ ps.addObserver("testPref.sticky.bool", observe, false);
+
+ ps.setBoolPref("testPref.sticky.bool", ps.getBoolPref("testPref.sticky.bool"));
+ // and the observer will fire triggering the next text.
+});
diff --git a/modules/libpref/test/unit/test_warnings.js b/modules/libpref/test/unit/test_warnings.js
new file mode 100644
index 000000000..856e117b7
--- /dev/null
+++ b/modules/libpref/test/unit/test_warnings.js
@@ -0,0 +1,69 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+Cu.import("resource://gre/modules/Promise.jsm");
+
+var cs = Cc["@mozilla.org/consoleservice;1"].
+ getService(Ci.nsIConsoleService);
+var ps = Cc["@mozilla.org/preferences-service;1"].
+ getService(Ci.nsIPrefService);
+
+function makeBuffer(length) {
+ return new Array(length + 1).join('x');
+}
+
+/**
+ * @resolves |true| if execution proceeded without warning,
+ * |false| if there was a warning.
+ */
+function checkWarning(pref, buffer) {
+ let deferred = Promise.defer();
+ let complete = false;
+ let listener = {
+ observe: function(event) {
+ let message = event.message;
+ if (!(message.startsWith("Warning: attempting to write")
+ && message.includes(pref))) {
+ return;
+ }
+ if (complete) {
+ return;
+ }
+ complete = true;
+ do_print("Warning while setting " + pref);
+ cs.unregisterListener(listener);
+ deferred.resolve(true);
+ }
+ };
+ do_timeout(1000, function() {
+ if (complete) {
+ return;
+ }
+ complete = true;
+ do_print("No warning while setting " + pref);
+ cs.unregisterListener(listener);
+ deferred.resolve(false);
+ });
+ cs.registerListener(listener);
+ ps.setCharPref(pref, buffer);
+ return deferred.promise;
+}
+
+function run_test() {
+ run_next_test();
+}
+
+add_task(function() {
+ // Simple change, shouldn't cause a warning
+ do_print("Checking that a simple change doesn't cause a warning");
+ let buf = makeBuffer(100);
+ let warned = yield checkWarning("string.accept", buf);
+ do_check_false(warned);
+
+ // Large change, should cause a warning
+ do_print("Checking that a large change causes a warning");
+ buf = makeBuffer(32 * 1024);
+ warned = yield checkWarning("string.warn", buf);
+ do_check_true(warned);
+});
diff --git a/modules/libpref/test/unit/xpcshell.ini b/modules/libpref/test/unit/xpcshell.ini
new file mode 100644
index 000000000..74c56907a
--- /dev/null
+++ b/modules/libpref/test/unit/xpcshell.ini
@@ -0,0 +1,18 @@
+[DEFAULT]
+head = head_libPrefs.js
+tail =
+support-files =
+ data/testPref.js
+ extdata/testExt.js
+
+[test_warnings.js]
+[test_bug345529.js]
+[test_bug506224.js]
+[test_bug577950.js]
+[test_bug790374.js]
+[test_stickyprefs.js]
+support-files = data/testPrefSticky.js data/testPrefStickyUser.js
+[test_changeType.js]
+[test_dirtyPrefs.js]
+[test_extprefs.js]
+[test_libPrefs.js]
diff --git a/modules/libpref/test/unit_ipc/test_existing_prefs.js b/modules/libpref/test/unit_ipc/test_existing_prefs.js
new file mode 100644
index 000000000..4c51c4d67
--- /dev/null
+++ b/modules/libpref/test/unit_ipc/test_existing_prefs.js
@@ -0,0 +1,21 @@
+var Ci = Components.interfaces;
+var Cc = Components.classes;
+
+function isParentProcess() {
+ let appInfo = Cc["@mozilla.org/xre/app-info;1"];
+ return (!appInfo || appInfo.getService(Ci.nsIXULRuntime).processType == Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT);
+}
+
+function run_test() {
+ if (isParentProcess() == false) {
+
+ do_load_child_test_harness();
+
+ var pb = Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefBranch);
+ pb.setBoolPref("Test.IPC.bool.new", true);
+ pb.setIntPref("Test.IPC.int.new", 23);
+ pb.setCharPref("Test.IPC.char.new", "hey");
+
+ run_test_in_child("test_observed_prefs.js");
+ }
+} \ No newline at end of file
diff --git a/modules/libpref/test/unit_ipc/test_initial_prefs.js b/modules/libpref/test/unit_ipc/test_initial_prefs.js
new file mode 100644
index 000000000..62b36c694
--- /dev/null
+++ b/modules/libpref/test/unit_ipc/test_initial_prefs.js
@@ -0,0 +1,18 @@
+var Ci = Components.interfaces;
+var Cc = Components.classes;
+
+function isParentProcess() {
+ let appInfo = Cc["@mozilla.org/xre/app-info;1"];
+ return (!appInfo || appInfo.getService(Ci.nsIXULRuntime).processType == Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT);
+}
+
+function run_test() {
+ if (isParentProcess() == false) {
+ var pb = Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefBranch);
+ pb.setBoolPref("Test.IPC.bool", true);
+ pb.setIntPref("Test.IPC.int", 23);
+ pb.setCharPref("Test.IPC.char", "hey");
+
+ run_test_in_child("test_existing_prefs.JS");
+ }
+} \ No newline at end of file
diff --git a/modules/libpref/test/unit_ipc/test_large_pref.js b/modules/libpref/test/unit_ipc/test_large_pref.js
new file mode 100644
index 000000000..c3c937b43
--- /dev/null
+++ b/modules/libpref/test/unit_ipc/test_large_pref.js
@@ -0,0 +1,98 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+// Large preferences should not be set in the child process.
+// Non-string preferences are not tested here, because their behavior
+// should not be affected by this filtering.
+
+var Ci = Components.interfaces;
+var Cc = Components.classes;
+
+function isParentProcess() {
+ let appInfo = Cc["@mozilla.org/xre/app-info;1"];
+ return (!appInfo || appInfo.getService(Ci.nsIXULRuntime).processType == Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT);
+}
+
+function makeBuffer(length) {
+ let string = "x";
+ while (string.length < length) {
+ string = string + string;
+ }
+ if (string.length > length) {
+ string = string.substring(length - string.length);
+ }
+ return string;
+}
+
+// from prefapi.h
+const MAX_ADVISABLE_PREF_LENGTH = 4 * 1024;
+
+const largeString = makeBuffer(MAX_ADVISABLE_PREF_LENGTH + 1);
+const smallString = makeBuffer(4);
+
+const testValues = [
+ {name: "None", value: undefined},
+ {name: "Small", value: smallString},
+ {name: "Large", value: largeString},
+];
+
+function prefName(def, user) {
+ return "Test.IPC.default" + def.name + "User" + user.name;
+}
+
+function expectedPrefValue(def, user) {
+ if (user.value) {
+ return user.value;
+ }
+ return def.value;
+}
+
+function run_test() {
+ let pb = Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefBranch);
+ let ps = Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefService);
+ let defaultBranch = ps.getDefaultBranch("");
+
+ let isParent = isParentProcess();
+ if (isParent) {
+ // Set all combinations of none, small and large, for default and user prefs.
+ for (let def of testValues) {
+ for (let user of testValues) {
+ let currPref = prefName(def, user);
+ if (def.value) {
+ defaultBranch.setCharPref(currPref, def.value);
+ }
+ if (user.value) {
+ pb.setCharPref(currPref, user.value);
+ }
+ }
+ }
+
+ run_test_in_child("test_large_pref.js");
+ }
+
+ // Check that each preference is set or not set, as appropriate.
+ for (let def of testValues) {
+ for (let user of testValues) {
+ if (!def.value && !user.value) {
+ continue;
+ }
+ let pref_name = prefName(def, user);
+ if (isParent || (def.name != "Large" && user.name != "Large")) {
+ do_check_eq(pb.getCharPref(pref_name), expectedPrefValue(def, user));
+ } else {
+ // This is the child, and either the default or user value is
+ // large, so the preference should not be set.
+ let prefExists;
+ try {
+ pb.getCharPref(pref_name);
+ prefExists = true;
+ } catch(e) {
+ prefExists = false;
+ }
+ ok(!prefExists,
+ "Pref " + pref_name + " should not be set in the child");
+ }
+ }
+ }
+}
diff --git a/modules/libpref/test/unit_ipc/test_observed_prefs.js b/modules/libpref/test/unit_ipc/test_observed_prefs.js
new file mode 100644
index 000000000..c18f7f0fe
--- /dev/null
+++ b/modules/libpref/test/unit_ipc/test_observed_prefs.js
@@ -0,0 +1,16 @@
+var Ci = Components.interfaces;
+var Cc = Components.classes;
+
+function isParentProcess() {
+ let appInfo = Cc["@mozilla.org/xre/app-info;1"];
+ return (!appInfo || appInfo.getService(Ci.nsIXULRuntime).processType == Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT);
+}
+
+function run_test() {
+ if (isParentProcess() == false) {
+ var pb = Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefBranch);
+ do_check_eq(pb.getBoolPref("Test.IPC.bool.new"), true);
+ do_check_eq(pb.getIntPref("Test.IPC.int.new"), 23);
+ do_check_eq(pb.getCharPref("Test.IPC.char.new"), "hey");
+ }
+} \ No newline at end of file
diff --git a/modules/libpref/test/unit_ipc/test_update_prefs.js b/modules/libpref/test/unit_ipc/test_update_prefs.js
new file mode 100644
index 000000000..7e1b0dcd7
--- /dev/null
+++ b/modules/libpref/test/unit_ipc/test_update_prefs.js
@@ -0,0 +1,38 @@
+var Ci = Components.interfaces;
+var Cc = Components.classes;
+
+function isParentProcess() {
+ let appInfo = Cc["@mozilla.org/xre/app-info;1"];
+ return (!appInfo || appInfo.getService(Ci.nsIXULRuntime).processType == Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT);
+}
+
+function run_test() {
+ if (isParentProcess()) {
+
+ do_load_child_test_harness();
+
+ var pb = Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefBranch);
+
+ // these prefs are set after the child has been created.
+ pb.setBoolPref("Test.IPC.bool.new", true);
+ pb.setIntPref("Test.IPC.int.new", 23);
+ pb.setCharPref("Test.IPC.char.new", "hey");
+
+ run_test_in_child("test_observed_prefs.js", testPrefClear);
+ }
+}
+
+function testPrefClear() {
+ var pb = Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefBranch);
+ pb.clearUserPref("Test.IPC.bool.new");
+
+ sendCommand(
+'var pb = Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefBranch);\n'+
+'pb.prefHasUserValue("Test.IPC.bool.new");\n',
+ checkWasCleared);
+}
+
+function checkWasCleared(existsStr) {
+ do_check_eq(existsStr, "false");
+ do_test_finished();
+} \ No newline at end of file
diff --git a/modules/libpref/test/unit_ipc/test_user_default_prefs.js b/modules/libpref/test/unit_ipc/test_user_default_prefs.js
new file mode 100644
index 000000000..3b8ca28c6
--- /dev/null
+++ b/modules/libpref/test/unit_ipc/test_user_default_prefs.js
@@ -0,0 +1,76 @@
+var Ci = Components.interfaces;
+var Cc = Components.classes;
+
+var pb = Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefBranch);
+
+// This pref is chosen somewhat arbitrarily --- we just need one
+// that's guaranteed to have a default value.
+const kPrefName = 'intl.accept_languages'; // of type char, which we
+ // assume below
+var initialValue = null;
+
+function check_child_pref_info_eq(continuation) {
+ sendCommand(
+ 'var pb = Components.classes["@mozilla.org/preferences-service;1"].getService(Components.interfaces.nsIPrefBranch);\n'+
+ // Returns concatenation "[value],[isUser]"
+ 'pb.getCharPref("'+ kPrefName +'")+ "," +'+
+ 'pb.prefHasUserValue("'+ kPrefName +'");',
+ function (info) {
+ let [ value, isUser ] = info.split(',');
+ do_check_eq(pb.getCharPref(kPrefName), value);
+ do_check_eq(pb.prefHasUserValue(kPrefName), isUser == "true");
+ continuation();
+ });
+}
+
+function run_test() {
+ // We finish in clean_up()
+ do_test_pending();
+
+ try {
+ if (pb.getCharPref('dom.ipc.processPrelaunch.enabled')) {
+ dump('WARNING: Content process may already have launched, so this test may not be meaningful.');
+ }
+ } catch(e) { }
+
+ initialValue = pb.getCharPref(kPrefName);
+
+ test_user_setting();
+}
+
+function test_user_setting() {
+ // We rely on setting this before the content process starts up.
+ // When it starts up, it should recognize this as a user pref, not
+ // a default pref.
+ pb.setCharPref(kPrefName, 'i-imaginarylanguage');
+ // NB: processing of the value-change notification in the child
+ // process triggered by the above set happens-before the remaining
+ // code here
+ check_child_pref_info_eq(function () {
+ do_check_eq(pb.prefHasUserValue(kPrefName), true);
+
+ test_cleared_is_default();
+ });
+}
+
+function test_cleared_is_default() {
+ pb.clearUserPref(kPrefName);
+ // NB: processing of the value-change notification in the child
+ // process triggered by the above set happens-before the remaining
+ // code here
+ check_child_pref_info_eq(function () {
+ do_check_eq(pb.prefHasUserValue(kPrefName), false);
+
+ clean_up();
+ });
+}
+
+function clean_up() {
+ pb.setCharPref(kPrefName, initialValue);
+ // NB: processing of the value-change notification in the child
+ // process triggered by the above set happens-before the remaining
+ // code here
+ check_child_pref_info_eq(function () {
+ do_test_finished();
+ });
+} \ No newline at end of file
diff --git a/modules/libpref/test/unit_ipc/xpcshell.ini b/modules/libpref/test/unit_ipc/xpcshell.ini
new file mode 100644
index 000000000..319276e68
--- /dev/null
+++ b/modules/libpref/test/unit_ipc/xpcshell.ini
@@ -0,0 +1,11 @@
+[DEFAULT]
+head =
+tail =
+skip-if = toolkit == 'android'
+
+[test_existing_prefs.js]
+[test_initial_prefs.js]
+[test_large_pref.js]
+[test_observed_prefs.js]
+[test_update_prefs.js]
+[test_user_default_prefs.js]